diff --git a/assets/wiki/Beach tile/Beach_bottom.png b/assets/wiki/Beach tile/Beach_bottom.png new file mode 100644 index 00000000..05647256 Binary files /dev/null and b/assets/wiki/Beach tile/Beach_bottom.png differ diff --git a/assets/wiki/Beach tile/Beach_left.png b/assets/wiki/Beach tile/Beach_left.png new file mode 100644 index 00000000..0b65fe45 Binary files /dev/null and b/assets/wiki/Beach tile/Beach_left.png differ diff --git a/assets/wiki/Beach tile/Beach_right.png b/assets/wiki/Beach tile/Beach_right.png new file mode 100644 index 00000000..8f2a1c95 Binary files /dev/null and b/assets/wiki/Beach tile/Beach_right.png differ diff --git a/assets/wiki/Beach tile/Beach_top.png b/assets/wiki/Beach tile/Beach_top.png new file mode 100644 index 00000000..cc078ea3 Binary files /dev/null and b/assets/wiki/Beach tile/Beach_top.png differ diff --git a/assets/wiki/Beach tile/Inner_corner_beach_bottom_left.png b/assets/wiki/Beach tile/Inner_corner_beach_bottom_left.png new file mode 100644 index 00000000..42a2cf57 Binary files /dev/null and b/assets/wiki/Beach tile/Inner_corner_beach_bottom_left.png differ diff --git a/assets/wiki/Beach tile/Inner_corner_beach_bottom_right.png b/assets/wiki/Beach tile/Inner_corner_beach_bottom_right.png new file mode 100644 index 00000000..fc6659b8 Binary files /dev/null and b/assets/wiki/Beach tile/Inner_corner_beach_bottom_right.png differ diff --git a/assets/wiki/Beach tile/Inner_corner_beach_top_left.png b/assets/wiki/Beach tile/Inner_corner_beach_top_left.png new file mode 100644 index 00000000..55da8063 Binary files /dev/null and b/assets/wiki/Beach tile/Inner_corner_beach_top_left.png differ diff --git a/assets/wiki/Beach tile/Inner_corner_beach_top_right.png b/assets/wiki/Beach tile/Inner_corner_beach_top_right.png new file mode 100644 index 00000000..55e564a4 Binary files /dev/null and b/assets/wiki/Beach tile/Inner_corner_beach_top_right.png differ diff --git a/assets/wiki/Beach tile/Outer_corner_beach_bottom_left.png b/assets/wiki/Beach tile/Outer_corner_beach_bottom_left.png new file mode 100644 index 00000000..998b607b Binary files /dev/null and b/assets/wiki/Beach tile/Outer_corner_beach_bottom_left.png differ diff --git a/assets/wiki/Beach tile/Outer_corner_beach_bottom_right.png b/assets/wiki/Beach tile/Outer_corner_beach_bottom_right.png new file mode 100644 index 00000000..2ce8c1af Binary files /dev/null and b/assets/wiki/Beach tile/Outer_corner_beach_bottom_right.png differ diff --git a/assets/wiki/Beach tile/Outer_corner_beach_top_left.png b/assets/wiki/Beach tile/Outer_corner_beach_top_left.png new file mode 100644 index 00000000..26b478cc Binary files /dev/null and b/assets/wiki/Beach tile/Outer_corner_beach_top_left.png differ diff --git a/assets/wiki/Beach tile/Outer_corner_beach_top_right.png b/assets/wiki/Beach tile/Outer_corner_beach_top_right.png new file mode 100644 index 00000000..b33e2fe8 Binary files /dev/null and b/assets/wiki/Beach tile/Outer_corner_beach_top_right.png differ diff --git a/assets/wiki/Grass/grass1.gif b/assets/wiki/Grass/grass1.gif new file mode 100644 index 00000000..d1df5909 Binary files /dev/null and b/assets/wiki/Grass/grass1.gif differ diff --git a/assets/wiki/Grass/grass1.png b/assets/wiki/Grass/grass1.png new file mode 100644 index 00000000..e6b13241 Binary files /dev/null and b/assets/wiki/Grass/grass1.png differ diff --git a/assets/wiki/Grass/grass2.gif b/assets/wiki/Grass/grass2.gif new file mode 100644 index 00000000..9de8003c Binary files /dev/null and b/assets/wiki/Grass/grass2.gif differ diff --git a/assets/wiki/Grass/grass2.png b/assets/wiki/Grass/grass2.png new file mode 100644 index 00000000..789e3cbc Binary files /dev/null and b/assets/wiki/Grass/grass2.png differ diff --git a/assets/wiki/Waves tile/Corner_waves_bottom_left.png b/assets/wiki/Waves tile/Corner_waves_bottom_left.png new file mode 100644 index 00000000..cb0befb8 Binary files /dev/null and b/assets/wiki/Waves tile/Corner_waves_bottom_left.png differ diff --git a/assets/wiki/Waves tile/Corner_waves_bottom_right.png b/assets/wiki/Waves tile/Corner_waves_bottom_right.png new file mode 100644 index 00000000..786ebd56 Binary files /dev/null and b/assets/wiki/Waves tile/Corner_waves_bottom_right.png differ diff --git a/assets/wiki/Waves tile/Corner_waves_top_left.png b/assets/wiki/Waves tile/Corner_waves_top_left.png new file mode 100644 index 00000000..13457a49 Binary files /dev/null and b/assets/wiki/Waves tile/Corner_waves_top_left.png differ diff --git a/assets/wiki/Waves tile/Corner_waves_top_right.png b/assets/wiki/Waves tile/Corner_waves_top_right.png new file mode 100644 index 00000000..450e2f6b Binary files /dev/null and b/assets/wiki/Waves tile/Corner_waves_top_right.png differ diff --git a/assets/wiki/Waves tile/Waves_bottom.png b/assets/wiki/Waves tile/Waves_bottom.png new file mode 100644 index 00000000..691b514c Binary files /dev/null and b/assets/wiki/Waves tile/Waves_bottom.png differ diff --git a/assets/wiki/Waves tile/Waves_left.png b/assets/wiki/Waves tile/Waves_left.png new file mode 100644 index 00000000..c621ebd2 Binary files /dev/null and b/assets/wiki/Waves tile/Waves_left.png differ diff --git a/assets/wiki/Waves tile/Waves_right.png b/assets/wiki/Waves tile/Waves_right.png new file mode 100644 index 00000000..7f64d13c Binary files /dev/null and b/assets/wiki/Waves tile/Waves_right.png differ diff --git a/assets/wiki/Waves tile/Waves_top.png b/assets/wiki/Waves tile/Waves_top.png new file mode 100644 index 00000000..727667c1 Binary files /dev/null and b/assets/wiki/Waves tile/Waves_top.png differ diff --git a/assets/wiki/weather_change/Rain.gif b/assets/wiki/weather_change/Rain.gif new file mode 100644 index 00000000..15afd402 Binary files /dev/null and b/assets/wiki/weather_change/Rain.gif differ diff --git a/assets/wiki/weather_change/Rain.png b/assets/wiki/weather_change/Rain.png new file mode 100644 index 00000000..20ae375d Binary files /dev/null and b/assets/wiki/weather_change/Rain.png differ diff --git a/assets/wiki/weather_change/snow.gif b/assets/wiki/weather_change/snow.gif new file mode 100644 index 00000000..2767cc83 Binary files /dev/null and b/assets/wiki/weather_change/snow.gif differ diff --git a/assets/wiki/weather_change/snow.png b/assets/wiki/weather_change/snow.png new file mode 100644 index 00000000..9c7eedc0 Binary files /dev/null and b/assets/wiki/weather_change/snow.png differ diff --git a/assets/wiki/weather_change/thunder.gif b/assets/wiki/weather_change/thunder.gif new file mode 100644 index 00000000..db0ff896 Binary files /dev/null and b/assets/wiki/weather_change/thunder.gif differ diff --git a/assets/wiki/weather_change/thunder.png b/assets/wiki/weather_change/thunder.png new file mode 100644 index 00000000..6b2777f5 Binary files /dev/null and b/assets/wiki/weather_change/thunder.png differ diff --git a/source/core/assets/images/Beach tile/Beach_bottom.png b/source/core/assets/images/Beach tile/Beach_bottom.png new file mode 100644 index 00000000..05647256 Binary files /dev/null and b/source/core/assets/images/Beach tile/Beach_bottom.png differ diff --git a/source/core/assets/images/Beach tile/Beach_left.png b/source/core/assets/images/Beach tile/Beach_left.png new file mode 100644 index 00000000..0b65fe45 Binary files /dev/null and b/source/core/assets/images/Beach tile/Beach_left.png differ diff --git a/source/core/assets/images/Beach tile/Beach_right.png b/source/core/assets/images/Beach tile/Beach_right.png new file mode 100644 index 00000000..8f2a1c95 Binary files /dev/null and b/source/core/assets/images/Beach tile/Beach_right.png differ diff --git a/source/core/assets/images/Beach tile/Beach_top.png b/source/core/assets/images/Beach tile/Beach_top.png new file mode 100644 index 00000000..cc078ea3 Binary files /dev/null and b/source/core/assets/images/Beach tile/Beach_top.png differ diff --git a/source/core/assets/images/Beach tile/Inner_corner_beach_bottom_left.png b/source/core/assets/images/Beach tile/Inner_corner_beach_bottom_left.png new file mode 100644 index 00000000..42a2cf57 Binary files /dev/null and b/source/core/assets/images/Beach tile/Inner_corner_beach_bottom_left.png differ diff --git a/source/core/assets/images/Beach tile/Inner_corner_beach_bottom_right.png b/source/core/assets/images/Beach tile/Inner_corner_beach_bottom_right.png new file mode 100644 index 00000000..fc6659b8 Binary files /dev/null and b/source/core/assets/images/Beach tile/Inner_corner_beach_bottom_right.png differ diff --git a/source/core/assets/images/Beach tile/Inner_corner_beach_top_left.png b/source/core/assets/images/Beach tile/Inner_corner_beach_top_left.png new file mode 100644 index 00000000..55da8063 Binary files /dev/null and b/source/core/assets/images/Beach tile/Inner_corner_beach_top_left.png differ diff --git a/source/core/assets/images/Beach tile/Inner_corner_beach_top_right.png b/source/core/assets/images/Beach tile/Inner_corner_beach_top_right.png new file mode 100644 index 00000000..55e564a4 Binary files /dev/null and b/source/core/assets/images/Beach tile/Inner_corner_beach_top_right.png differ diff --git a/source/core/assets/images/Beach tile/Outer_corner_beach_bottom_left.png b/source/core/assets/images/Beach tile/Outer_corner_beach_bottom_left.png new file mode 100644 index 00000000..998b607b Binary files /dev/null and b/source/core/assets/images/Beach tile/Outer_corner_beach_bottom_left.png differ diff --git a/source/core/assets/images/Beach tile/Outer_corner_beach_bottom_right.png b/source/core/assets/images/Beach tile/Outer_corner_beach_bottom_right.png new file mode 100644 index 00000000..2ce8c1af Binary files /dev/null and b/source/core/assets/images/Beach tile/Outer_corner_beach_bottom_right.png differ diff --git a/source/core/assets/images/Beach tile/Outer_corner_beach_top_left.png b/source/core/assets/images/Beach tile/Outer_corner_beach_top_left.png new file mode 100644 index 00000000..26b478cc Binary files /dev/null and b/source/core/assets/images/Beach tile/Outer_corner_beach_top_left.png differ diff --git a/source/core/assets/images/Beach tile/Outer_corner_beach_top_right.png b/source/core/assets/images/Beach tile/Outer_corner_beach_top_right.png new file mode 100644 index 00000000..b33e2fe8 Binary files /dev/null and b/source/core/assets/images/Beach tile/Outer_corner_beach_top_right.png differ diff --git a/source/core/assets/images/Rain.png b/source/core/assets/images/Rain.png new file mode 100644 index 00000000..20ae375d Binary files /dev/null and b/source/core/assets/images/Rain.png differ diff --git a/source/core/assets/images/Sand Grass Tile/corner_sand_grass_1.png b/source/core/assets/images/Sand Grass Tile/corner_sand_grass_1.png new file mode 100644 index 00000000..da77ccd5 Binary files /dev/null and b/source/core/assets/images/Sand Grass Tile/corner_sand_grass_1.png differ diff --git a/source/core/assets/images/Sand Grass Tile/corner_sand_grass_2.png b/source/core/assets/images/Sand Grass Tile/corner_sand_grass_2.png new file mode 100644 index 00000000..cdf9eb1b Binary files /dev/null and b/source/core/assets/images/Sand Grass Tile/corner_sand_grass_2.png differ diff --git a/source/core/assets/images/Sand Grass Tile/corner_sand_grass_3.png b/source/core/assets/images/Sand Grass Tile/corner_sand_grass_3.png new file mode 100644 index 00000000..ff7c18bf Binary files /dev/null and b/source/core/assets/images/Sand Grass Tile/corner_sand_grass_3.png differ diff --git a/source/core/assets/images/Sand Grass Tile/corner_sand_grass_4.png b/source/core/assets/images/Sand Grass Tile/corner_sand_grass_4.png new file mode 100644 index 00000000..6cd2e2a0 Binary files /dev/null and b/source/core/assets/images/Sand Grass Tile/corner_sand_grass_4.png differ diff --git a/source/core/assets/images/Sand Grass Tile/corner_sand_grass_5.png b/source/core/assets/images/Sand Grass Tile/corner_sand_grass_5.png new file mode 100644 index 00000000..5c9a0b34 Binary files /dev/null and b/source/core/assets/images/Sand Grass Tile/corner_sand_grass_5.png differ diff --git a/source/core/assets/images/Sand Grass Tile/corner_sand_grass_6.png b/source/core/assets/images/Sand Grass Tile/corner_sand_grass_6.png new file mode 100644 index 00000000..eede0239 Binary files /dev/null and b/source/core/assets/images/Sand Grass Tile/corner_sand_grass_6.png differ diff --git a/source/core/assets/images/Sand Grass Tile/corner_sand_grass_7.png b/source/core/assets/images/Sand Grass Tile/corner_sand_grass_7.png new file mode 100644 index 00000000..81c9f7fc Binary files /dev/null and b/source/core/assets/images/Sand Grass Tile/corner_sand_grass_7.png differ diff --git a/source/core/assets/images/Sand Grass Tile/corner_sand_grass_8.png b/source/core/assets/images/Sand Grass Tile/corner_sand_grass_8.png new file mode 100644 index 00000000..6f877b3e Binary files /dev/null and b/source/core/assets/images/Sand Grass Tile/corner_sand_grass_8.png differ diff --git a/source/core/assets/images/Sand Grass Tile/main_sand_grass_1.png b/source/core/assets/images/Sand Grass Tile/main_sand_grass_1.png new file mode 100644 index 00000000..f0162693 Binary files /dev/null and b/source/core/assets/images/Sand Grass Tile/main_sand_grass_1.png differ diff --git a/source/core/assets/images/Sand Grass Tile/main_sand_grass_2.png b/source/core/assets/images/Sand Grass Tile/main_sand_grass_2.png new file mode 100644 index 00000000..27759999 Binary files /dev/null and b/source/core/assets/images/Sand Grass Tile/main_sand_grass_2.png differ diff --git a/source/core/assets/images/Sand Grass Tile/main_sand_grass_3.png b/source/core/assets/images/Sand Grass Tile/main_sand_grass_3.png new file mode 100644 index 00000000..a392bee1 Binary files /dev/null and b/source/core/assets/images/Sand Grass Tile/main_sand_grass_3.png differ diff --git a/source/core/assets/images/Sand Grass Tile/main_sand_grass_4.png b/source/core/assets/images/Sand Grass Tile/main_sand_grass_4.png new file mode 100644 index 00000000..4e68407d Binary files /dev/null and b/source/core/assets/images/Sand Grass Tile/main_sand_grass_4.png differ diff --git a/source/core/assets/images/Sand Grass Tile/sand_tile.png b/source/core/assets/images/Sand Grass Tile/sand_tile.png new file mode 100644 index 00000000..be3ec523 Binary files /dev/null and b/source/core/assets/images/Sand Grass Tile/sand_tile.png differ diff --git a/source/core/assets/images/Waves tile/Corner_waves_bottom_left.png b/source/core/assets/images/Waves tile/Corner_waves_bottom_left.png new file mode 100644 index 00000000..cb0befb8 Binary files /dev/null and b/source/core/assets/images/Waves tile/Corner_waves_bottom_left.png differ diff --git a/source/core/assets/images/Waves tile/Corner_waves_bottom_right.png b/source/core/assets/images/Waves tile/Corner_waves_bottom_right.png new file mode 100644 index 00000000..786ebd56 Binary files /dev/null and b/source/core/assets/images/Waves tile/Corner_waves_bottom_right.png differ diff --git a/source/core/assets/images/Waves tile/Corner_waves_top_left.png b/source/core/assets/images/Waves tile/Corner_waves_top_left.png new file mode 100644 index 00000000..13457a49 Binary files /dev/null and b/source/core/assets/images/Waves tile/Corner_waves_top_left.png differ diff --git a/source/core/assets/images/Waves tile/Corner_waves_top_right.png b/source/core/assets/images/Waves tile/Corner_waves_top_right.png new file mode 100644 index 00000000..450e2f6b Binary files /dev/null and b/source/core/assets/images/Waves tile/Corner_waves_top_right.png differ diff --git a/source/core/assets/images/Waves tile/Waves_bottom.png b/source/core/assets/images/Waves tile/Waves_bottom.png new file mode 100644 index 00000000..691b514c Binary files /dev/null and b/source/core/assets/images/Waves tile/Waves_bottom.png differ diff --git a/source/core/assets/images/Waves tile/Waves_left.png b/source/core/assets/images/Waves tile/Waves_left.png new file mode 100644 index 00000000..c621ebd2 Binary files /dev/null and b/source/core/assets/images/Waves tile/Waves_left.png differ diff --git a/source/core/assets/images/Waves tile/Waves_right.png b/source/core/assets/images/Waves tile/Waves_right.png new file mode 100644 index 00000000..7f64d13c Binary files /dev/null and b/source/core/assets/images/Waves tile/Waves_right.png differ diff --git a/source/core/assets/images/Waves tile/Waves_top.png b/source/core/assets/images/Waves tile/Waves_top.png new file mode 100644 index 00000000..727667c1 Binary files /dev/null and b/source/core/assets/images/Waves tile/Waves_top.png differ diff --git a/source/core/assets/images/Waves tile/wave_1.png b/source/core/assets/images/Waves tile/wave_1.png new file mode 100644 index 00000000..63f1b59d Binary files /dev/null and b/source/core/assets/images/Waves tile/wave_1.png differ diff --git a/source/core/assets/images/Waves tile/wave_2.png b/source/core/assets/images/Waves tile/wave_2.png new file mode 100644 index 00000000..002a39ed Binary files /dev/null and b/source/core/assets/images/Waves tile/wave_2.png differ diff --git a/source/core/assets/images/Waves tile/wave_3.png b/source/core/assets/images/Waves tile/wave_3.png new file mode 100644 index 00000000..c1a8c684 Binary files /dev/null and b/source/core/assets/images/Waves tile/wave_3.png differ diff --git a/source/core/assets/images/Waves tile/wave_4.png b/source/core/assets/images/Waves tile/wave_4.png new file mode 100644 index 00000000..30395376 Binary files /dev/null and b/source/core/assets/images/Waves tile/wave_4.png differ diff --git a/source/core/assets/images/Waves tile/wave_5.png b/source/core/assets/images/Waves tile/wave_5.png new file mode 100644 index 00000000..0c4a8745 Binary files /dev/null and b/source/core/assets/images/Waves tile/wave_5.png differ diff --git a/source/core/assets/images/Waves tile/wave_6.png b/source/core/assets/images/Waves tile/wave_6.png new file mode 100644 index 00000000..11b7fc57 Binary files /dev/null and b/source/core/assets/images/Waves tile/wave_6.png differ diff --git a/source/core/assets/images/Waves tile/wave_7.png b/source/core/assets/images/Waves tile/wave_7.png new file mode 100644 index 00000000..b62cdca7 Binary files /dev/null and b/source/core/assets/images/Waves tile/wave_7.png differ diff --git a/source/core/assets/images/barracks_level_1.1.png b/source/core/assets/images/barracks_level_1.1.png index 289b4174..79cb5465 100644 Binary files a/source/core/assets/images/barracks_level_1.1.png and b/source/core/assets/images/barracks_level_1.1.png differ diff --git a/source/core/assets/images/barracks_level_1.1_highlight.png b/source/core/assets/images/barracks_level_1.1_highlight.png index 05ef5abf..c700733e 100644 Binary files a/source/core/assets/images/barracks_level_1.1_highlight.png and b/source/core/assets/images/barracks_level_1.1_highlight.png differ diff --git a/source/core/assets/images/barracks_level_1.2.png b/source/core/assets/images/barracks_level_1.2.png index 79cb5465..289b4174 100644 Binary files a/source/core/assets/images/barracks_level_1.2.png and b/source/core/assets/images/barracks_level_1.2.png differ diff --git a/source/core/assets/images/barracks_level_1.2_highlight.png b/source/core/assets/images/barracks_level_1.2_highlight.png index c700733e..05ef5abf 100644 Binary files a/source/core/assets/images/barracks_level_1.2_highlight.png and b/source/core/assets/images/barracks_level_1.2_highlight.png differ diff --git a/source/core/assets/images/grass1.png b/source/core/assets/images/grass1.png new file mode 100644 index 00000000..e6b13241 Binary files /dev/null and b/source/core/assets/images/grass1.png differ diff --git a/source/core/assets/images/grass2.png b/source/core/assets/images/grass2.png new file mode 100644 index 00000000..789e3cbc Binary files /dev/null and b/source/core/assets/images/grass2.png differ diff --git a/source/core/assets/images/health bar_1.png b/source/core/assets/images/health bar_1.png new file mode 100644 index 00000000..c9dadbc9 Binary files /dev/null and b/source/core/assets/images/health bar_1.png differ diff --git a/source/core/assets/images/health bar_2.png b/source/core/assets/images/health bar_2.png new file mode 100644 index 00000000..5adc152e Binary files /dev/null and b/source/core/assets/images/health bar_2.png differ diff --git a/source/core/assets/images/health bar_3.png b/source/core/assets/images/health bar_3.png new file mode 100644 index 00000000..5cd94ea4 Binary files /dev/null and b/source/core/assets/images/health bar_3.png differ diff --git a/source/core/assets/images/health bar_4.png b/source/core/assets/images/health bar_4.png new file mode 100644 index 00000000..b52edcbc Binary files /dev/null and b/source/core/assets/images/health bar_4.png differ diff --git a/source/core/assets/images/health bar_5.png b/source/core/assets/images/health bar_5.png new file mode 100644 index 00000000..5ccef16f Binary files /dev/null and b/source/core/assets/images/health bar_5.png differ diff --git a/source/core/assets/images/health bar_6.png b/source/core/assets/images/health bar_6.png new file mode 100644 index 00000000..135fb9bd Binary files /dev/null and b/source/core/assets/images/health bar_6.png differ diff --git a/source/core/assets/images/loading bar_1.png b/source/core/assets/images/loading bar_1.png new file mode 100644 index 00000000..410e69d4 Binary files /dev/null and b/source/core/assets/images/loading bar_1.png differ diff --git a/source/core/assets/images/loading bar_2.png b/source/core/assets/images/loading bar_2.png new file mode 100644 index 00000000..e0c45be1 Binary files /dev/null and b/source/core/assets/images/loading bar_2.png differ diff --git a/source/core/assets/images/loading bar_3.png b/source/core/assets/images/loading bar_3.png new file mode 100644 index 00000000..3f2502ee Binary files /dev/null and b/source/core/assets/images/loading bar_3.png differ diff --git a/source/core/assets/images/loading bar_4.png b/source/core/assets/images/loading bar_4.png new file mode 100644 index 00000000..23e3dd4a Binary files /dev/null and b/source/core/assets/images/loading bar_4.png differ diff --git a/source/core/assets/images/loading bar_5.png b/source/core/assets/images/loading bar_5.png new file mode 100644 index 00000000..890ffda6 Binary files /dev/null and b/source/core/assets/images/loading bar_5.png differ diff --git a/source/core/assets/images/snow.png b/source/core/assets/images/snow.png new file mode 100644 index 00000000..9c7eedc0 Binary files /dev/null and b/source/core/assets/images/snow.png differ diff --git a/source/core/assets/images/thunder.png b/source/core/assets/images/thunder.png new file mode 100644 index 00000000..6b2777f5 Binary files /dev/null and b/source/core/assets/images/thunder.png differ diff --git a/source/core/assets/images/weather-filter/Rain.png b/source/core/assets/images/weather-filter/Rain.png new file mode 100644 index 00000000..20ae375d Binary files /dev/null and b/source/core/assets/images/weather-filter/Rain.png differ diff --git a/source/core/assets/images/weather-filter/ice-frames.png b/source/core/assets/images/weather-filter/ice-frames.png new file mode 100644 index 00000000..521ed095 Binary files /dev/null and b/source/core/assets/images/weather-filter/ice-frames.png differ diff --git a/source/core/assets/images/weather-filter/rainEffects.png b/source/core/assets/images/weather-filter/rainEffects.png new file mode 100644 index 00000000..827811c3 Binary files /dev/null and b/source/core/assets/images/weather-filter/rainEffects.png differ diff --git a/source/core/assets/images/weather-filter/rain_effect.atlas b/source/core/assets/images/weather-filter/rain_effect.atlas new file mode 100644 index 00000000..b22534d7 --- /dev/null +++ b/source/core/assets/images/weather-filter/rain_effect.atlas @@ -0,0 +1,19 @@ +rainEffects.png +size: 200, 100 +format: RGBA8888 +filter: Linear,Linear +repeat: none +rain_first + rotate: false + xy: 0, 0 + size: 1000, 1000 + orig: 1000, 1000 + offset: 0, 0 + index: 0 +rain_first + rotate: false + xy: 100, 0 + size: 1000, 1000 + orig: 1000, 1000 + offset: 0, 0 + index: 1 \ No newline at end of file diff --git a/source/core/assets/images/weather-filter/snow.png b/source/core/assets/images/weather-filter/snow.png new file mode 100644 index 00000000..9c7eedc0 Binary files /dev/null and b/source/core/assets/images/weather-filter/snow.png differ diff --git a/source/core/assets/images/weather-filter/snowfall_1.png b/source/core/assets/images/weather-filter/snowfall_1.png new file mode 100644 index 00000000..d2b5ad9b Binary files /dev/null and b/source/core/assets/images/weather-filter/snowfall_1.png differ diff --git a/source/core/assets/images/weather-filter/snowfall_2.png b/source/core/assets/images/weather-filter/snowfall_2.png new file mode 100644 index 00000000..847ef033 Binary files /dev/null and b/source/core/assets/images/weather-filter/snowfall_2.png differ diff --git a/source/core/assets/images/weather-filter/snowfall_3.png b/source/core/assets/images/weather-filter/snowfall_3.png new file mode 100644 index 00000000..51d9eb24 Binary files /dev/null and b/source/core/assets/images/weather-filter/snowfall_3.png differ diff --git a/source/core/assets/images/weather-filter/thunder.png b/source/core/assets/images/weather-filter/thunder.png new file mode 100644 index 00000000..6b2777f5 Binary files /dev/null and b/source/core/assets/images/weather-filter/thunder.png differ diff --git a/source/core/src/main/com/deco2800/game/GdxGame.java b/source/core/src/main/com/deco2800/game/GdxGame.java index 090be8b0..8bda952b 100644 --- a/source/core/src/main/com/deco2800/game/GdxGame.java +++ b/source/core/src/main/com/deco2800/game/GdxGame.java @@ -4,10 +4,7 @@ import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Screen; import com.deco2800.game.files.UserSettings; -import com.deco2800.game.screens.MainGameScreen; -import com.deco2800.game.screens.MainMenuScreen; -import com.deco2800.game.screens.StoryScreen; -import com.deco2800.game.screens.SettingsScreen; +import com.deco2800.game.screens.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -76,6 +73,10 @@ private Screen newScreen(ScreenType screenType) { return new MainGameScreen(this); case SETTINGS: return new SettingsScreen(this); + case TUTORIAL: + return new TutorialScreen(this); + case LOADING: + return new LoadingScreen(this); default: return null; @@ -83,7 +84,7 @@ private Screen newScreen(ScreenType screenType) { } public enum ScreenType { - MAIN_MENU, MAIN_GAME, SETTINGS, GAME_STORY; + MAIN_MENU, MAIN_GAME, SETTINGS, GAME_STORY, TUTORIAL, LOADING; } /** diff --git a/source/core/src/main/com/deco2800/game/areas/AtlantisGameArea.java b/source/core/src/main/com/deco2800/game/areas/AtlantisGameArea.java index 60043601..b280bd5c 100644 --- a/source/core/src/main/com/deco2800/game/areas/AtlantisGameArea.java +++ b/source/core/src/main/com/deco2800/game/areas/AtlantisGameArea.java @@ -14,13 +14,13 @@ import com.deco2800.game.areas.MapGenerator.Buildings.Building; import com.deco2800.game.areas.MapGenerator.Buildings.BuildingGenerator; import com.deco2800.game.areas.MapGenerator.Buildings.CityRow; -import com.deco2800.game.areas.MapGenerator.pathBuilding.PathGenerator; import com.deco2800.game.areas.MapGenerator.Coordinate; import com.deco2800.game.areas.MapGenerator.MapGenerator; import com.deco2800.game.areas.MapGenerator.ResourceSpecification; import com.deco2800.game.areas.terrain.AtlantisTerrainFactory; import com.deco2800.game.areas.terrain.MinimapComponent; import com.deco2800.game.components.UnitSpawningComponent; +import com.deco2800.game.areas.terrain.TerrainTile; import com.deco2800.game.components.building.BuildingActions; import com.deco2800.game.components.building.TextureScaler; import com.deco2800.game.components.friendlyunits.GestureDisplay; @@ -30,8 +30,6 @@ import com.deco2800.game.components.maingame.DialogueBoxDisplay; import com.deco2800.game.components.maingame.Explosion; import com.deco2800.game.components.maingame.InfoBoxDisplay; -import com.deco2800.game.areas.terrain.MinimapComponent; -import com.deco2800.game.areas.terrain.TerrainTile; import com.deco2800.game.entities.Entity; import com.deco2800.game.entities.UnitType; import com.deco2800.game.entities.factories.BuildingFactory; @@ -43,23 +41,17 @@ import com.deco2800.game.entities.factories.*; import com.deco2800.game.input.CameraInputComponent; import com.deco2800.game.map.MapComponent; -import com.deco2800.game.rendering.TextureRenderComponent; -import com.deco2800.game.services.ResourceService; -import com.deco2800.game.services.ServiceLocator; -import com.deco2800.game.components.gamearea.GameAreaDisplay; import com.deco2800.game.physics.components.ColliderComponent; import com.deco2800.game.services.ResourceService; import com.deco2800.game.services.ServiceLocator; import com.deco2800.game.worker.WorkerBaseFactory; import com.deco2800.game.worker.resources.MiningCampFactory; -import com.deco2800.game.worker.resources.StoneFactory; import com.deco2800.game.worker.resources.TreeFactory; import com.deco2800.game.worker.type.BuilderFactory; import com.deco2800.game.worker.type.ForagerFactory; import com.deco2800.game.worker.type.MinerFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.w3c.dom.Text; import java.lang.annotation.Target; import java.util.List; @@ -74,21 +66,21 @@ public class AtlantisGameArea extends GameArea { private static final Logger logger = LoggerFactory.getLogger(ForestGameArea.class); private static final int NUM_TREES = 5; private static final int NUM_STONE = 10; - private static final String[] forestTextures = { + public static final String[] forestTextures = { "test/files/dummyTexture.png", "test/files/dummyOcean.png", "images/Ocean.png", "images/Sand.png", "images/Grass.png", "images/city_tile.png", - "images/box_boy_leaf.png", - "images/box_boy.png", - "images/Base_Highlight.png", - "images/box_boy_highlight.png", +// "images/box_boy_leaf.png", +// "images/box_boy.png", +// "images/Base_Highlight.png", +// "images/box_boy_highlight.png", "images/tree.png", "images/iso_grass_1.png", - "images/ghost_king.png", - "images/ghost_1.png", +// "images/ghost_king.png", +// "images/ghost_1.png", "images/grass_1.png", "images/grass_2.png", "images/grass_3.png", @@ -96,6 +88,10 @@ public class AtlantisGameArea extends GameArea { "images/sea_2.png", "images/sea_3.png", "images/sea_4.png", + "images/Waves tile/wave_1.png", + "images/Waves tile/wave_2.png", + "images/Waves tile/wave_3.png", + "images/Waves tile/wave_4.png", "images/hex_grass_1.png", "images/hex_grass_2.png", "images/hex_grass_3.png", @@ -110,6 +106,7 @@ public class AtlantisGameArea extends GameArea { /* Building assets */ // TownHall "images/base.png", + "images/level 1 town hall.png", // Barracks "images/barracks_level_1.0.png", "images/barracks_level_1.0_Highlight.png", @@ -140,6 +137,7 @@ public class AtlantisGameArea extends GameArea { "images/stone_wall_2_.png", "images/stone_wall_3.png", "images/Base_Highlight", + "images/level_1_town_hall_Highlight.png", "images/stone.png", "images/archer.png", "images/swordsman.png", @@ -160,25 +158,25 @@ public class AtlantisGameArea extends GameArea { "images/pathTile.png", "images/spellbox-zeus.png", "images/spell-btn-unclickable.png", - "images/spell-btn.png" - + "images/spell-btn.png", + "images/health bar_6.png", }; /* TODO: remove unused textures wasting precious resources */ - private static final String[] uiTextures = { + public static final String[] uiTextures = { "images/dialogue_box_pattern2_background.png", "images/dialogue_box_image_default.png", "images/exit-button.PNG", "images/dialogue_box_background_Deep_Sea.png" }; - private final String[] buildingPlacementTextures = { + public static final String[] buildingPlacementTextures = { "images/barracks_highlight_red.png", "images/barracks_highlight_green.png", "images/wooden_wall_green.png", "images/wooden_wall_red.png" }; - private static final String[] forestTextureAtlases = { + public static final String[] forestTextureAtlases = { "images/terrain_iso_grass.atlas", "images/ghost.atlas", "images/ghostKing.atlas", "images/forager.atlas", "images/miner.atlas", "images/builder.atlas", "images/duration-bar.atlas", "images/archer.atlas", "images/swordsman.atlas", @@ -188,7 +186,7 @@ public class AtlantisGameArea extends GameArea { "images/newwolf.atlas", "images/forager.atlas","images/tree_.atlas", "images/spell.atlas", "images/titanshrine.atlas", "images/ship2.atlas" }; - private static final String[] atlantisSounds = {"sounds/Impact4.ogg"}; + public static final String[] atlantisSounds = {"sounds/Impact4.ogg"}; Music music = Gdx.audio.newMusic(Gdx.files.internal("sounds/in-game-v3.wav")); @@ -220,7 +218,7 @@ public void create() { gameAreaEventHandle.addListener("spawnTitan", this::spawnTitan); gameAreaEventHandle.addListener("spawnBlueJoker", this::spawnBlueJokers); - loadAssets(); +// loadAssets(); displayUI(); spawnTerrain(); @@ -235,7 +233,7 @@ public void create() { spawnMiner(); //playMusic(); - player = spawnPlayer(); +// player = spawnPlayer(); centreCameraOnCity(); // Spawn Buildings in the city @@ -362,12 +360,9 @@ private void displayUI() { spawnEntity(gestureDisplay); Entity dialogueBox = new Entity(); - /* FIXME: temporary infobox width value */ - this.dialogueBoxDisplay = new DialogueBoxDisplay(537f); - dialogueBoxDisplay.setDialogue("This is example dialogue text"); - dialogueBoxDisplay.setTitle("example title"); - dialogueBox.addComponent(dialogueBoxDisplay); - dialogueBox.addComponent(new DialogueBoxActions(dialogueBoxDisplay)); + this.dialogueBoxDisplay = new DialogueBoxDisplay(); + dialogueBox.addComponent(this.dialogueBoxDisplay); + dialogueBox.addComponent(new DialogueBoxActions(this.dialogueBoxDisplay)); //spawnEntity(dialogueBox); } diff --git a/source/core/src/main/com/deco2800/game/areas/TutorialGameArea.java b/source/core/src/main/com/deco2800/game/areas/TutorialGameArea.java new file mode 100644 index 00000000..4d25760b --- /dev/null +++ b/source/core/src/main/com/deco2800/game/areas/TutorialGameArea.java @@ -0,0 +1,67 @@ +package com.deco2800.game.areas; + +import com.deco2800.game.components.maingame.DialogueBoxActions; +import com.deco2800.game.components.maingame.DialogueBoxDisplay; +import com.deco2800.game.entities.Entity; +import com.deco2800.game.services.ResourceService; +import com.deco2800.game.services.ServiceLocator; + +public class TutorialGameArea extends GameArea { + + /** dialogue box */ + private DialogueBoxDisplay dialogueBoxDisplay; + + /** textures needed to load */ + private String[] tutorialTextures = { + "images/dialogue_box_pattern2_background.png", + "images/dialogue_box_image_default.png", + "images/exit-button.PNG", + "images/dialogue_box_background_Deep_Sea.png" + }; + + /** + * On init load needed textures + */ + private void loadAssets() { + + ResourceService resourceService = ServiceLocator.getResourceService(); + resourceService.loadTextures(this.tutorialTextures); + resourceService.loadAll(); + } + + /** + * On exit clean-up loaded textures + */ + private void unloadAssets() { + + ResourceService resourceService = ServiceLocator.getResourceService(); + resourceService.unloadAssets(this.tutorialTextures); + } + + /** + * Create and spawn entities to this area + */ + private void displayUI() { + + Entity dialogueBox = new Entity(); + this.dialogueBoxDisplay = new DialogueBoxDisplay(); + dialogueBox.addComponent(this.dialogueBoxDisplay) + .addComponent(new DialogueBoxActions(this.dialogueBoxDisplay)); + + spawnEntity(dialogueBox); + } + + @Override + public void create() { + + this.loadAssets(); + this.displayUI(); + } + + @Override + public void dispose() { + + super.dispose(); + this.unloadAssets(); + } +} diff --git a/source/core/src/main/com/deco2800/game/areas/terrain/AtlantisTerrainFactory.java b/source/core/src/main/com/deco2800/game/areas/terrain/AtlantisTerrainFactory.java index c8ba1bb0..fd19d571 100644 --- a/source/core/src/main/com/deco2800/game/areas/terrain/AtlantisTerrainFactory.java +++ b/source/core/src/main/com/deco2800/game/areas/terrain/AtlantisTerrainFactory.java @@ -132,7 +132,8 @@ private void fillTiles(TiledMapTileLayer layer) { oceanFrames.add(new StaticTiledMapTile(textures.get("Sea2"))); oceanFrames.add(new StaticTiledMapTile(textures.get("Sea3"))); oceanFrames.add(new StaticTiledMapTile(textures.get("Sea4"))); - AnimatedTiledMapTile animatedOceanTile = new AnimatedTiledMapTile(1/3f, oceanFrames); + AnimatedTiledMapTile animatedOceanTile = new AnimatedTiledMapTile(1f/2f, oceanFrames); + //Set id for each tile - used for visualising minimap cityTile.setId(0); diff --git a/source/core/src/main/com/deco2800/game/components/CombatStatsComponent.java b/source/core/src/main/com/deco2800/game/components/CombatStatsComponent.java index e4fa480c..cc58f9e6 100644 --- a/source/core/src/main/com/deco2800/game/components/CombatStatsComponent.java +++ b/source/core/src/main/com/deco2800/game/components/CombatStatsComponent.java @@ -30,8 +30,8 @@ public CombatStatsComponent(int troops, int health, int baseAttack, int baseDefe public CombatStatsComponent(int troops, int health, int baseAttack, int baseDefence, float landSpeed, int range) { setTroops(troops); - setHealth(health); setMaxHealth(health); + setHealth(health); setBaseAttack(baseAttack); setBaseDefence(baseDefence); setLandSpeed(landSpeed); @@ -142,6 +142,9 @@ public int getMaxHealth() { public void setHealth(int health) { if (health >= 0) { this.health = health; + if (health > maxHealth) { + this.health = maxHealth; + } } else { this.health = 0; } @@ -151,12 +154,14 @@ public void setHealth(int health) { } /** - * Sets the entity's maximum health. Health has a minimum bound of 0. - * - * @param maxHealth maximum health + * Sets the entity's maximum health. Maximum Health must be greater than or equal to 0. + * @param maxHealth Maximum health an entity can have */ public void setMaxHealth(int maxHealth) { this.maxHealth = maxHealth; + if (this.maxHealth < 0) { + this.maxHealth = 0; + } } /** diff --git a/source/core/src/main/com/deco2800/game/components/EntityType.java b/source/core/src/main/com/deco2800/game/components/EntityType.java new file mode 100644 index 00000000..ebf32dfd --- /dev/null +++ b/source/core/src/main/com/deco2800/game/components/EntityType.java @@ -0,0 +1,7 @@ +package com.deco2800.game.components; + +public enum EntityType { + FRIENDLY, + ENEMY, + BUILDING +} diff --git a/source/core/src/main/com/deco2800/game/components/HealthBarComponent.java b/source/core/src/main/com/deco2800/game/components/HealthBarComponent.java new file mode 100644 index 00000000..76f45da6 --- /dev/null +++ b/source/core/src/main/com/deco2800/game/components/HealthBarComponent.java @@ -0,0 +1,165 @@ +package com.deco2800.game.components; + +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.Pixmap; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.math.Vector2; +import com.deco2800.game.rendering.RenderComponent; +import com.deco2800.game.services.ServiceLocator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The Health Bar Component can be added to entities + * This component will display the health under the entity + * The health is specified by the combat stats component + */ +public class HealthBarComponent extends RenderComponent { + + private static final Logger logger = LoggerFactory.getLogger(HealthBarComponent.class); + private Texture red; + private Texture green; + private Texture segment; + + private CombatStatsComponent stats; + private boolean showing; + private EntityType entityType; // Friendly units have green health bars. Enemies have red health bars + private float zIndex; + + private long lastUpdate; + private long visibleTime; // time(ms) that health bar is visible for after health is updated + + /** + * Health bar will display health of entity in game. Buildings and Friendly entity types will display green health + * and enemies will display red health + * @param entityType Type of entity. e.g. Friendly, Enemy, Building + */ + public HealthBarComponent(EntityType entityType) { + this.entityType = entityType; + visibleTime = 15 * 1000; // 15 seconds + } + + @Override + public void create() { + super.create(); + Pixmap pixmap = new Pixmap(1, 1, Pixmap.Format.RGBA8888 ); + pixmap.setColor(Color.GREEN); + pixmap.fillRectangle(0, 0, 1,1); + green = new Texture( pixmap ); + pixmap.setColor(Color.RED); + pixmap.fillRectangle(0, 0, 1,1); + red = new Texture( pixmap ); + pixmap.setColor(Color.DARK_GRAY); + pixmap.fillRectangle(0, 0, 1,1); + segment = new Texture( pixmap ); + pixmap.dispose(); + + stats = entity.getComponent(CombatStatsComponent.class); + if (stats == null) { + // Combat Stats component required for Health + this.dispose(); + } + lastUpdate = ServiceLocator.getTimeSource().getTime(); + showing = true; + zIndex = 0f; + + entity.getEvents().addListener("updateHealth", this::updateHealth); + } + + @Override + public void dispose() { + super.dispose(); + green.dispose(); + red.dispose(); + segment.dispose(); + } + + @Override + protected void draw(SpriteBatch batch) { + if (!showing) { + return; + } + Texture health = green; + if (entityType == EntityType.ENEMY) { + health = red; // enemy entity health is red + } + + // Constants for health bar size + float xdist = 0.4f; // x scaled distance for health bar from centre of entity (0.5 = whole entity + float ydist = 0.3f; // y offset for health bar from centre of entity + float height = 0.15f; // height of health bar + float line_size = 0.03f; // segment line width + float segment_health = 25f; // amount of health to display per segment + + Vector2 position = entity.getCenterPosition(); + Vector2 scale = entity.getScale(); + // Health bar position and width + float xPos = position.x - (scale.x * xdist); + float yPos = position.y - (scale.y * ydist); + float width = 2 * scale.x * xdist; // width of entire health bar + float healthWidth = width * (float) stats.getHealth() / stats.getMaxHealth(); // width of green health + + // Drawing health + batch.draw(health, xPos, yPos, healthWidth, height); + batch.draw(segment, xPos, yPos, width, line_size); // bottom border + batch.draw(segment, xPos, yPos + height, width, line_size); // top border + // Drawing segments + for (float x = xPos - line_size; x < xPos + width; x += width * (segment_health/ stats.getMaxHealth())) { + batch.draw(segment, x, yPos, line_size, height + line_size); + } + + zIndex = -yPos; // updates the zIndex to display above entity + } + + @Override + public void update() { + if (ServiceLocator.getRenderService().getDebug().getActive()) { + showing = true; // debug command sets health bar to be visible + } else if (ServiceLocator.getTimeSource().getTimeSince(lastUpdate) > visibleTime) { + showing = false; // hides health bar after time of inactivity + } + } + + /** + * Event trigger by event listener. When the health is updated it causes the health bar to display if it is hidden + * Also restarts the timer that automatically hides health bar + * @param newHealth new health + */ + public void updateHealth(int newHealth) { + lastUpdate = ServiceLocator.getTimeSource().getTime(); + showing = true; + } + + /** + * Hides health bar + */ + public void hideHealthBar() { + lastUpdate = ServiceLocator.getTimeSource().getTime() - visibleTime; + } + + /** + * Makes health bar visible for an amount of time + * @param time time in milliseconds + */ + public void showHealthBar(long time) { + lastUpdate = ServiceLocator.getTimeSource().getTime() - visibleTime + time; + } + + /** + * Makes health bar visible for default amount of time + */ + public void showHealthBar() { + showHealthBar(visibleTime); + } + + public boolean getVisible() { + return showing; + } + + @Override + public float getZIndex() { + return zIndex; + } + +} diff --git a/source/core/src/main/com/deco2800/game/components/LoadingBar.java b/source/core/src/main/com/deco2800/game/components/LoadingBar.java new file mode 100644 index 00000000..ed947269 --- /dev/null +++ b/source/core/src/main/com/deco2800/game/components/LoadingBar.java @@ -0,0 +1,100 @@ +package com.deco2800.game.components; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.scenes.scene2d.Touchable; +import com.badlogic.gdx.scenes.scene2d.ui.Image; +import com.badlogic.gdx.scenes.scene2d.ui.Label; +import com.badlogic.gdx.scenes.scene2d.ui.ProgressBar; +import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable; +import com.deco2800.game.GdxGame; +import com.deco2800.game.services.ServiceLocator; +import com.deco2800.game.ui.UIComponent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class LoadingBar extends UIComponent { + + private static final Logger logger = LoggerFactory.getLogger(HealthBarComponent.class); + private Image background; + private Image frame; + private ProgressBar bar; + private Label loading; + private int progress; + private boolean loaded; + + @Override + public void create() { + super.create(); + addActors(); + progress = 0; + loaded = false; + } + + public void addActors() { + background = new Image(ServiceLocator.getResourceService().getAsset("images/title-atlantis.png", Texture.class)); + background.setTouchable(Touchable.disabled); + + frame = new Image(ServiceLocator.getResourceService().getAsset("images/loading bar_4.png", Texture.class)); + frame.setScale(1.2f, 0.9f); + frame.setTouchable(Touchable.disabled); + + TextureRegionDrawable drawable = new TextureRegionDrawable(new Texture("images/loading bar_5.png")); + ProgressBar.ProgressBarStyle style = new ProgressBar.ProgressBarStyle(); + style.knobBefore = drawable; + + bar = new ProgressBar(0f, 100f, 1f, false, style); + bar.setHeight(frame.getHeight() * frame.getScaleY()); + bar.setWidth(frame.getWidth() * frame.getScaleX()); + bar.setRound(true); + + loading = new Label("", skin); + + stage.addActor(background); + stage.addActor(bar); + stage.addActor(loading); + stage.addActor(frame); + } + + public boolean isLoaded() { + return loaded; + } + + @Override + public void update() { + logger.info("Loading... {}%", ServiceLocator.getResourceService().getProgress()); + if (ServiceLocator.getResourceService().loadForMillis(10)) { + loaded = true; + } + } + + @Override + protected void draw(SpriteBatch batch) { + progress = ServiceLocator.getResourceService().getProgress(); +// progress = 50; + float width = Gdx.graphics.getWidth(); + float height = Gdx.graphics.getHeight(); + + background.setSize(width, height); + + float y = height / 5f; + float x = (width - frame.getWidth() * frame.getScaleX()) / 2f; + + frame.setPosition(x, y); + bar.setPosition(x, y); + loading.setPosition(x + frame.getWidth() * frame.getScaleX() / 3f, y + frame.getHeight() * frame.getScaleY() / 2f); + loading.setText(String.format("Loading... %02d%%", ServiceLocator.getResourceService().getProgress())); + bar.setValue(progress); + } + + @Override + public void dispose() { + super.dispose(); + background.remove(); + frame.remove(); + bar.remove(); + loading.remove(); + logger.debug("Loading Bar Actors Disposed"); + } +} diff --git a/source/core/src/main/com/deco2800/game/components/maingame/DialogueBoxDisplay.java b/source/core/src/main/com/deco2800/game/components/maingame/DialogueBoxDisplay.java index 369d5ade..bd2ad0a3 100644 --- a/source/core/src/main/com/deco2800/game/components/maingame/DialogueBoxDisplay.java +++ b/source/core/src/main/com/deco2800/game/components/maingame/DialogueBoxDisplay.java @@ -4,6 +4,7 @@ import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.scenes.scene2d.Actor; +import com.badlogic.gdx.scenes.scene2d.Stage; import com.badlogic.gdx.scenes.scene2d.ui.*; import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; import com.deco2800.game.areas.terrain.MinimapComponent; @@ -17,43 +18,58 @@ */ public class DialogueBoxDisplay extends UIComponent { - /** logger for debugging purposes */ + /** + * logger for debugging purposes + */ private static final Logger logger = LoggerFactory.getLogger(DialogueBoxDisplay.class); - /** current dialogue text to be displayed */ + /** + * current dialogue text to be displayed + */ private Label dialogue; + private String dialogueText; - /** current dialogue title to be displayed */ + /** + * current dialogue title to be displayed + */ private Label title; + private String titleText; - /** current background texture to be displayed */ + /** + * current background texture to be displayed + */ private Image backgroundTexture; - /** current image to be displayed */ + /** + * current image to be displayed + */ private Image image; - /** current dismiss button to be displayed */ + /** + * current dismiss button to be displayed + */ private TextButton dismissBtn; - /** stores dialogue box's current state of visibility */ + /** + * stores dialogue box's current state of visibility + */ private boolean hidden; /* external values */ - /** current width of infoBox being displayed */ - private float infoWidth; + /** + * current width of infoBox being displayed + */ + private float infoWidth = 537f; - /** reference to current minimap being displayed */ + /** + * reference to current minimap being displayed + */ private MinimapComponent minimap; - public DialogueBoxDisplay(float infoWidth) { - - logger.debug("Creating DialogueBoxDisplay"); - this.infoWidth = infoWidth; - } - /** * Set current minimap for reference + * * @param minimap - current minimap */ public void setMinimap(MinimapComponent minimap) { @@ -80,9 +96,11 @@ public void addActors() { .getAsset("images/dialogue_box_background_Deep_Sea.png", Texture.class) ); - this.title = new Label("EXAMPLE TITLE", skin); + this.titleText = "EXAMPLE TITLE"; + this.title = new Label(this.titleText, skin); - this.dialogue = new Label("EXAMPLE DIALOGUE TEXT", skin); + this.dialogueText = "EXAMPLE DIALOGUE TEXT"; + this.dialogue = new Label(this.dialogueText, skin); this.dismissBtn = new TextButton("", new Skin(Gdx.files.internal("atlantis/exitButtonSkin.json"))); this.dismissBtn.addListener(new ChangeListener() { @@ -116,7 +134,11 @@ public void changed(ChangeEvent event, Actor actor) { // TODO: update render to display new text public void setDialogue(String dialogue) { - this.dialogue = new Label(dialogue, skin); + if (this.dialogueText != null && + !this.dialogueText.equals(dialogue)) { + + this.dialogueText = dialogue; + } } /** @@ -127,7 +149,11 @@ public void setDialogue(String dialogue) { // TODO: update render to display new text public void setTitle(String title) { - this.title = new Label(title, skin); + if (this.titleText != null && + !this.titleText.equals(title)) { + + this.titleText = title; + } } /** @@ -169,7 +195,7 @@ public void show() { if (!this.isHidden()) return; - this.hidden = true; + this.hidden = false; } /** @@ -213,9 +239,13 @@ public void draw(SpriteBatch batch) { this.dismissBtn.setPosition(dismissButtonPosition[0], dismissButtonPosition[1]); this.title.setPosition(titlePosition[0], titlePosition[1]); + if (this.titleText != null) + this.title.setText(this.titleText); this.dialogue.setSize(dialogueSize[0], dialogueSize[1]); this.dialogue.setPosition(dialoguePosition[0], dialoguePosition[1]); + if (this.dialogueText != null) + this.dialogue.setText(this.dialogueText); this.image.setSize(imageSize[0], imageSize[1]); this.image.setPosition(imagePosition[0], imagePosition[1]); diff --git a/source/core/src/main/com/deco2800/game/components/maingame/InfoBoxDisplay.java b/source/core/src/main/com/deco2800/game/components/maingame/InfoBoxDisplay.java index 3342942e..22cdd005 100644 --- a/source/core/src/main/com/deco2800/game/components/maingame/InfoBoxDisplay.java +++ b/source/core/src/main/com/deco2800/game/components/maingame/InfoBoxDisplay.java @@ -1,14 +1,18 @@ package com.deco2800.game.components.maingame; import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.Pixmap; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.scenes.scene2d.Actor; import com.badlogic.gdx.scenes.scene2d.ui.*; import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable; +import com.badlogic.gdx.utils.Align; import com.badlogic.gdx.utils.Array; - +import com.deco2800.game.components.CombatStatsComponent; +import com.deco2800.game.components.building.Building; import com.deco2800.game.components.building.BuildingActions; import com.deco2800.game.components.friendlyunits.SelectableComponent; import com.deco2800.game.components.mainmenu.MainMenuDisplay; @@ -54,6 +58,9 @@ public class InfoBoxDisplay extends UIComponent { //Button to create the magic bubble to save Atlantis private TextButton bubbleBtn = new TextButton("Create bubble", skin); + private Image healthFrame = new Image(ServiceLocator.getResourceService().getAsset("images/health bar_6.png", Texture.class)); + private ProgressBar healthBar; + private Label health; AnimationRenderComponent animator; @@ -144,7 +151,7 @@ public void changed(ChangeEvent changeEvent, Actor actor) { this.buildingTable = new Table(); buildingTable.setWidth(100); - buildingTable.setHeight(100); + buildingTable.setHeight(200); buildingTable.setPosition(400, Gdx.graphics.getHeight()-680); @@ -168,6 +175,20 @@ public void changed(ChangeEvent event, Actor actor) { } }); + // health bar + + Pixmap pixmap = new Pixmap(1, (int) (healthFrame.getHeight() * 0.8f), Pixmap.Format.RGBA8888); + pixmap.setColor(Color.RED); + pixmap.fill(); + TextureRegionDrawable drawable = new TextureRegionDrawable(new Texture(pixmap)); + pixmap.dispose(); + ProgressBar.ProgressBarStyle style = new ProgressBar.ProgressBarStyle(); + style.knobBefore = drawable; + + healthBar = new ProgressBar(0, 1, 1f, false, style); + healthBar.setRound(true); + health = new Label("", skin); + health.setFontScale(0.95f); } @@ -222,16 +243,33 @@ public void updateTables() { } //crashes game when not selecting building if (entity.getComponent(BuildingActions.class) != null){ - buildingTable.add(levelUpBtn); - switch (entity.getComponent(BuildingActions.class).getType()){ - case TOWNHALL: - buildingTable.add(bubbleBtn); - break; - case BARRACKS: - buildingTable.add(troopBtn); - break; - - } + buildingSelected = true; + + + int hp = entity.getComponent(CombatStatsComponent.class).getHealth(); + int maxHp = entity.getComponent(CombatStatsComponent.class).getMaxHealth(); + healthBar.setValue(hp); + healthBar.setRange(0 , maxHp); + + Stack stack = new Stack(); + stack.add(healthBar); + stack.add(healthFrame); + infoTable.add(stack); + infoTable.row(); + + entityName = entity.getComponent(BuildingActions.class).getType().toString(); + health.setText(String.format("%s: %d/%dHP", entityName, hp, maxHp)); + infoTable.add(health); +// buildingTable.add(levelUpBtn); +// switch (entity.getComponent(BuildingActions.class).getType()){ +// case TOWNHALL: +// buildingTable.add(bubbleBtn); +// break; +// case BARRACKS: +// buildingTable.add(troopBtn); +// break; +// +// } } else { buildingTable.clear(); } @@ -261,13 +299,10 @@ public void updateTables() { //Added functionality later because there is currently not enough information on the units we will have - Label dummyText = new Label("This is "+ entityName, skin, "large"); - infoTable.add(dummyText); - infoTable.row(); - if (buildingSelected){ - Label boxBoyText = new Label(String.format("%s: %d", entityName, length), skin, "large"); - infoTable.add(boxBoyText); - } else { + if (!buildingSelected) { + Label dummyText = new Label("This is "+ entityName, skin, "large"); + infoTable.add(dummyText); + infoTable.row(); Label boxBoyText = new Label(String.format("Boxboy: %d", length), skin, "large"); infoTable.add(boxBoyText); } diff --git a/source/core/src/main/com/deco2800/game/components/pausemenu/PauseMenuDisplay.java b/source/core/src/main/com/deco2800/game/components/pausemenu/PauseMenuDisplay.java index a9e1419a..0a66f28d 100644 --- a/source/core/src/main/com/deco2800/game/components/pausemenu/PauseMenuDisplay.java +++ b/source/core/src/main/com/deco2800/game/components/pausemenu/PauseMenuDisplay.java @@ -93,7 +93,8 @@ private void createMainTable() { @Override public void changed(ChangeEvent changeEvent, Actor actor) { logger.debug("Resume button clicked"); - entity.getEvents().trigger("resume"); +// entity.getEvents().trigger("resume"); // this triggers the game to be restarted + togglePauseScreen(); } }); diff --git a/source/core/src/main/com/deco2800/game/components/story/StoryActions.java b/source/core/src/main/com/deco2800/game/components/story/StoryActions.java index ed07f446..e306af6c 100644 --- a/source/core/src/main/com/deco2800/game/components/story/StoryActions.java +++ b/source/core/src/main/com/deco2800/game/components/story/StoryActions.java @@ -25,13 +25,13 @@ public void create() { private void onNext(){ logger.info("Load next"); - game.setScreen(GdxGame.ScreenType.MAIN_GAME); + game.setScreen(GdxGame.ScreenType.TUTORIAL); } private void onSkip() { logger.info("Skipping to game"); - game.setScreen(GdxGame.ScreenType.MAIN_GAME); + game.setScreen(GdxGame.ScreenType.TUTORIAL); } } diff --git a/source/core/src/main/com/deco2800/game/components/tutorial/TutorialActions.java b/source/core/src/main/com/deco2800/game/components/tutorial/TutorialActions.java new file mode 100644 index 00000000..75adcec6 --- /dev/null +++ b/source/core/src/main/com/deco2800/game/components/tutorial/TutorialActions.java @@ -0,0 +1,31 @@ +package com.deco2800.game.components.tutorial; + +import com.deco2800.game.GdxGame; +import com.deco2800.game.components.Component; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A ui component for handling tutorial actions + */ +public class TutorialActions extends Component { + private static final Logger logger = LoggerFactory.getLogger(TutorialActions.class); + + private GdxGame game; + + + public TutorialActions(GdxGame game) { + this.game = game; + } + @Override + public void create() { + + entity.getEvents().addListener("skip", this::onSkip); + } + + private void onSkip() { + logger.info("Skipping to game"); + game.setScreen(GdxGame.ScreenType.LOADING); + } + +} diff --git a/source/core/src/main/com/deco2800/game/components/tutorial/TutorialDisplay.java b/source/core/src/main/com/deco2800/game/components/tutorial/TutorialDisplay.java new file mode 100644 index 00000000..cae3f3c8 --- /dev/null +++ b/source/core/src/main/com/deco2800/game/components/tutorial/TutorialDisplay.java @@ -0,0 +1,100 @@ +package com.deco2800.game.components.tutorial; + +/** + import com.badlogic.gdx.Gdx; + import com.deco2800.game.GdxGame; + import com.badlogic.gdx.graphics.Texture; + import com.badlogic.gdx.graphics.g2d.SpriteBatch; + import com.badlogic.gdx.scenes.scene2d.Actor; + import com.badlogic.gdx.scenes.scene2d.ui.Image; + import com.badlogic.gdx.scenes.scene2d.ui.Table; + import com.badlogic.gdx.scenes.scene2d.ui.TextButton; + import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; + import com.deco2800.game.services.ServiceLocator; + import com.deco2800.game.ui.UIComponent; + import org.slf4j.Logger; + import org.slf4j.LoggerFactory; + import static com.deco2800.game.GdxGame.ScreenType.MAIN_GAME; + **/ +import com.badlogic.gdx.Gdx; +import com.deco2800.game.GdxGame; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.scenes.scene2d.Actor; +import com.badlogic.gdx.scenes.scene2d.ui.*; +import com.badlogic.gdx.scenes.scene2d.Touchable; +import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; +import com.deco2800.game.components.maingame.DialogueBoxDisplay; +import com.deco2800.game.components.mainmenu.MainMenuDisplay; +import com.deco2800.game.services.ServiceLocator; +import com.deco2800.game.ui.UIComponent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.graphics.g2d.TextureRegion; +import com.badlogic.gdx.scenes.scene2d.InputEvent; +import com.badlogic.gdx.scenes.scene2d.ui.Image; + +/** + * A ui component for displaying the Main menu. + */ +public class TutorialDisplay extends UIComponent { + private static final Logger logger = LoggerFactory.getLogger(TutorialDisplay.class); + private static final float Z_INDEX = 2f; + private Table table; + private Table backTable; + private DialogueBoxDisplay dialogueBox; + + + @Override + public void create() { + super.create(); + addActors(); + } + + private void addActors() { + table = new Table(); + table.setFillParent(true); + backTable = new Table(); + + backTable.bottom().right(); + table.setFillParent(true); + backTable.setFillParent(true); + + + TextButton skipBtn = new TextButton("Skip Tutorial", skin); + + skipBtn.addListener( + new ChangeListener() { + @Override + public void changed(ChangeEvent changeEvent, Actor actor) { + + logger.debug("Skip button clicked"); + entity.getEvents().trigger("skip"); + } + }); + + backTable.add(skipBtn).pad(25f); + stage.addActor(backTable); + stage.addActor(table); + + } + + @Override + public void draw(SpriteBatch batch) { + // draw is handled by the stage + } + + + @Override + public float getZIndex() { + return Z_INDEX; + } + + @Override + public void dispose() { + table.clear(); + super.dispose(); + } +} diff --git a/source/core/src/main/com/deco2800/game/components/weather/WeatherIcon.java b/source/core/src/main/com/deco2800/game/components/weather/WeatherIcon.java index 8eaddb41..7c8775ab 100644 --- a/source/core/src/main/com/deco2800/game/components/weather/WeatherIcon.java +++ b/source/core/src/main/com/deco2800/game/components/weather/WeatherIcon.java @@ -2,7 +2,10 @@ import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.g2d.Animation; import com.badlogic.gdx.graphics.g2d.Batch; +import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.scenes.scene2d.Actor; import com.badlogic.gdx.scenes.scene2d.ui.Image; import com.badlogic.gdx.scenes.scene2d.ui.Label; @@ -49,6 +52,18 @@ public class WeatherIcon extends Actor { */ private WeatherIconProperties weatherIconProperties; + private TextureRegion iceFrames[]; + + private Animation iceAnimation; + + private TextureRegion rainFrames[]; + + private Animation rainAnimation; + + private SpriteBatch batch; + + private float elapsedTime; + /** * Stores possible weather types. */ @@ -85,6 +100,25 @@ public WeatherIcon(Label countdownTimer) { // Initiate speedFactor this.speedFactor = this.weatherIconProperties.getSpeedFactor(); + + Texture img = new Texture("images/weather-filter/ice-frames.png"); + Texture rainEffects = new Texture("images/Rain.png"); + TextureRegion[][] tmpFrames = TextureRegion.split(img,200,200); + TextureRegion[][] rainImages = TextureRegion.split(rainEffects, 1000, 1000); + this.iceFrames = new TextureRegion[3]; + this.iceFrames[0] = new TextureRegion(new Texture("images/weather-filter/snowfall_1.png")); + this.iceFrames[1] = new TextureRegion(new Texture("images/weather-filter/snowfall_2.png")); + this.iceFrames[2] = new TextureRegion(new Texture("images/weather-filter/snowfall_3.png")); + this.rainFrames = new TextureRegion[4]; + int frame=0; + for (int i=0; i<2; i++){ + for (int j=0; j<2; j++) { + rainFrames[frame++] = rainImages[j][i]; + + } + } + iceAnimation = new Animation(0.5f, iceFrames); + rainAnimation = new Animation(0.5f, rainFrames); layout(); } @@ -143,7 +177,7 @@ public void layout() { // Layout for timer this.timerLabel.setAlignment(Align.left); - this.timerLabel.setWrap(true); + this.timerLabel.setWrap(false); this.timerLabel.setSize(3f,3f); this.timerLabel.setPosition(Gdx.graphics.getWidth()/2f + weatherImage.getWidth()/2f + 15f, Gdx.graphics.getHeight()-50f); } @@ -156,6 +190,36 @@ public void layout() { */ @Override public void draw(Batch batch, float parentAlpha) { + elapsedTime+= Gdx.graphics.getDeltaTime(); + if (weatherIconProperties == WeatherIconProperties.SNOWY) { + Image temp = new Image(iceAnimation.getKeyFrame(elapsedTime, true)); + for (int i=0 ; i < 4; i++){ + for (int j=0; j < 3; j++) { + temp.setScale(0.3f, 0.3f); + temp.setPosition(i*400, j*400-200); + temp.draw(batch, parentAlpha); + } + } + + this.weatherFilter = temp; + } + if (weatherIconProperties == WeatherIconProperties.RAINY || weatherIconProperties == WeatherIconProperties.STORMY){ + Image temp = new Image(rainAnimation.getKeyFrame(elapsedTime, true)); + temp.setScale(0.5f, 0.2f); + for (int i=0 ; i < 5; i++){ + for (int j=0; j < 7; j++) { + temp.setPosition(300*i, j*200); + temp.draw(batch, parentAlpha); + } + } + if (weatherIconProperties == WeatherIconProperties.RAINY){ + this.weatherFilter = temp; + this.weatherFilter.setPosition(700,0); + } + + } + + this.weatherFilter.draw(batch, parentAlpha); this.weatherImage.draw(batch, parentAlpha); this.timerLabel.draw(batch, parentAlpha); diff --git a/source/core/src/main/com/deco2800/game/components/weather/WeatherIconDisplay.java b/source/core/src/main/com/deco2800/game/components/weather/WeatherIconDisplay.java index 91bb0ecb..a9ff5827 100644 --- a/source/core/src/main/com/deco2800/game/components/weather/WeatherIconDisplay.java +++ b/source/core/src/main/com/deco2800/game/components/weather/WeatherIconDisplay.java @@ -34,7 +34,7 @@ public class WeatherIconDisplay extends UIComponent { public WeatherIconDisplay() { Skin countdownSkin = new Skin(Gdx.files.internal("flat-earth/skin/flat-earth-ui.json")); - this.timer = new Timer(5000, 10001); + this.timer = new Timer(10000, 20000); this.timerCountdown = new Label(String.valueOf(this.timer.timeLeft()), countdownSkin); this.weatherIcon = new WeatherIcon(this.timerCountdown); } @@ -56,10 +56,10 @@ public void update() { ServiceLocator.getEntityService().trigger("changeWeather", this.weatherIcon.getMovementSpeed()); if (timer.isTimerExpired()) { this.weatherIcon.changeWeatherImage(); - this.timer = new Timer(5000, 10001); + this.timer = new Timer(10000, 20000); } int timeLeft = (int) timer.timeLeft() / 1000; - CharSequence text = String.format("%d", timeLeft); + CharSequence text = String.format("%02d", timeLeft); this.timerCountdown.setText(text); } diff --git a/source/core/src/main/com/deco2800/game/components/weather/WeatherIconProperties.java b/source/core/src/main/com/deco2800/game/components/weather/WeatherIconProperties.java index ae95d493..e2ce856d 100644 --- a/source/core/src/main/com/deco2800/game/components/weather/WeatherIconProperties.java +++ b/source/core/src/main/com/deco2800/game/components/weather/WeatherIconProperties.java @@ -2,23 +2,23 @@ public enum WeatherIconProperties{ // Does not affect movement, affect lighting of the environment - CLOUDY ("images/cloudy.png", "images/weather-filter/cloudy-filter.png", 1.1f), + CLOUDY ("images/cloudy.png", "images/weather-filter/cloudy-filter.png", 1.2f), // Affecting movement, affect lighting of the environment // "images/rainy.gif" - RAINY ("images/rainy.png","images/weather-filter/rainy-filter.png", 0.7f), + RAINY ("images/rainy.png","images/weather-filter/rainEffects.png", 0.9f), // Affect movement a lot, affect terrain and lighting of the environment, must not appear adjacently with sunny // "images/snowy.gif" - SNOWY ("images/snowy.png", "images/weather-filter/snowy-filter.png", 0.6f), + SNOWY ("images/snowy.png", "images/weather-filter/ice-frames.png", 0.7f), // Does not affect movement, does not affect terrain and lighting of the environment, // must not appear adjacently with snowy - SUNNY ("images/sunny.png", "images/weather-filter/sunny-filter.png", 1.3f), + SUNNY ("images/sunny.png", "images/weather-filter/sunny-filter.png", 1.7f), // Affecting movement a bit, affect lighting of the environment //"images/thunderstorm.gif" - STORMY ("images/thunderstorm.png", "images/weather-filter/thunderstorm-filter.png", 0.6f); + STORMY ("images/thunderstorm.png", "images/weather-filter/thunderstorm-filter.png", 0.8f); /** * Location of weather image. diff --git a/source/core/src/main/com/deco2800/game/entities/factories/BuildingFactory.java b/source/core/src/main/com/deco2800/game/entities/factories/BuildingFactory.java index a2a037f1..c57c808b 100644 --- a/source/core/src/main/com/deco2800/game/entities/factories/BuildingFactory.java +++ b/source/core/src/main/com/deco2800/game/entities/factories/BuildingFactory.java @@ -2,7 +2,10 @@ import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.Texture; -import com.badlogic.gdx.graphics.g2d.*; +import com.badlogic.gdx.graphics.g2d.Animation; +import com.badlogic.gdx.graphics.g2d.PolygonRegion; +import com.badlogic.gdx.graphics.g2d.TextureAtlas; +import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.physics.box2d.BodyDef; import com.badlogic.gdx.physics.box2d.PolygonShape; @@ -10,14 +13,11 @@ import com.deco2800.game.areas.GameArea; import com.deco2800.game.components.BuildingUIDataComponent; import com.deco2800.game.components.CombatStatsComponent; -import com.deco2800.game.components.UnitSpawningComponent; -import com.deco2800.game.components.building.AttackListener; -import com.deco2800.game.components.building.Building; -import com.deco2800.game.components.building.BuildingActions; -import com.deco2800.game.components.building.damageAnimation; +import com.deco2800.game.components.EntityType; +import com.deco2800.game.components.HealthBarComponent; +import com.deco2800.game.components.building.*; +import com.deco2800.game.components.friendlyunits.SelectableComponent; import com.deco2800.game.components.tasks.rangedAttackTask; -import com.deco2800.game.components.building.TextureScaler; -import com.deco2800.game.components.building.GateCollider; import com.deco2800.game.entities.Entity; import com.deco2800.game.entities.configs.*; import com.deco2800.game.files.FileLoader; @@ -27,10 +27,8 @@ import com.deco2800.game.physics.components.PhysicsComponent; import com.deco2800.game.physics.components.PhysicsMovementComponent; import com.deco2800.game.rendering.AnimationRenderComponent; -import com.deco2800.game.rendering.AnimationRenderComponent; import com.deco2800.game.rendering.HighlightedTextureRenderComponent; import com.deco2800.game.rendering.TextureRenderComponent; -import com.deco2800.game.components.friendlyunits.SelectableComponent; import com.deco2800.game.services.ServiceLocator; import com.deco2800.game.worker.components.ResourceStatsComponent; import com.deco2800.game.worker.components.type.BaseComponent; @@ -75,7 +73,8 @@ public static Entity createBaseBuilding() { .addComponent(new PhysicsComponent().setBodyType(BodyDef.BodyType.StaticBody)) .addComponent(new SelectableComponent()) .addComponent(ServiceLocator.getInputService().getInputFactory().createForFriendlyUnit()) - .addComponent(new ColliderComponent().setLayer(PhysicsLayer.OBSTACLE)); + .addComponent(new ColliderComponent().setLayer(PhysicsLayer.OBSTACLE)) + .addComponent(new HealthBarComponent(EntityType.FRIENDLY)); } /** @@ -94,12 +93,12 @@ public static Entity createTownHall() { MapComponent mp = new MapComponent(); mp.display(); mp.setDisplayColour(Color.BROWN); - townHall.addComponent(new TextureRenderComponent("images/base.png")) + townHall.addComponent(new TextureRenderComponent("images/level 1 town hall.png")) .addComponent(new BuildingActions(config.type, config.level)) .addComponent(new CombatStatsComponent(config.health, config.baseAttack, config.baseDefence)) .addComponent(new ResourceStatsComponent(stats.wood, stats.stone, stats.metal)) .addComponent(new BaseComponent()) - .addComponent(new HighlightedTextureRenderComponent("images/Base_Highlight.png")) + .addComponent(new HighlightedTextureRenderComponent("images/level_1_town_hall_Highlight.png")) .addComponent(new BuildingUIDataComponent()) .addComponent(mp) .addComponent(new TextureScaler(leftPoint, rightPoint)); diff --git a/source/core/src/main/com/deco2800/game/entities/factories/EnemyFactory.java b/source/core/src/main/com/deco2800/game/entities/factories/EnemyFactory.java index d3a0eb09..6fbd06e4 100644 --- a/source/core/src/main/com/deco2800/game/entities/factories/EnemyFactory.java +++ b/source/core/src/main/com/deco2800/game/entities/factories/EnemyFactory.java @@ -6,15 +6,10 @@ import com.deco2800.game.ai.tasks.AITaskComponent; import com.deco2800.game.areas.GameArea; import com.deco2800.game.areas.terrain.AtlantisTerrainFactory; -import com.deco2800.game.components.CombatStatsComponent; -import com.deco2800.game.components.EntityDirectionComponent; -import com.deco2800.game.components.bulletHitShips; -import com.deco2800.game.components.npc.EnemyAnimationController; -import com.deco2800.game.components.npc.GhostAnimationController; -import com.deco2800.game.components.TouchAttackComponent; +import com.deco2800.game.components.*; import com.deco2800.game.components.enemy.EnemySignal; -//import com.deco2800.game.components.tasks.ChaseTask; -import com.deco2800.game.components.tasks.*; +import com.deco2800.game.components.npc.EnemyAnimationController; +import com.deco2800.game.components.tasks.EnemyMovement; import com.deco2800.game.entities.EnemyEntity; import com.deco2800.game.entities.Entity; import com.deco2800.game.entities.configs.BaseUnitConfig; @@ -118,6 +113,7 @@ public static Entity createBlueJoker(AtlantisTerrainFactory terrainFactory) { blueJoker .addComponent(new CombatStatsComponent(config.troops, config.health, config.baseAttack, config.baseDefence, config.landSpeed, config.range)) + .addComponent(new HealthBarComponent(EntityType.ENEMY)) .addComponent(animator) .addComponent(new EnemyAnimationController()) .addComponent(new EnemySignal()); @@ -153,6 +149,7 @@ public static Entity createSnake(AtlantisTerrainFactory terrainFactory) { snake .addComponent(new CombatStatsComponent(config.troops, config.health, config.baseAttack, config.baseDefence, config.landSpeed, config.range)) + .addComponent(new HealthBarComponent(EntityType.ENEMY)) .addComponent(animator) .addComponent(new EnemyAnimationController()) .addComponent(new EnemySignal()); @@ -186,6 +183,7 @@ public static Entity createWolf(AtlantisTerrainFactory terrainFactory) { wolf .addComponent(new CombatStatsComponent(config.troops, config.health, config.baseAttack, config.baseDefence, config.landSpeed, config.range)) + .addComponent(new HealthBarComponent(EntityType.ENEMY)) .addComponent(animator) .addComponent(new EnemyAnimationController()) .addComponent(new EnemySignal()); @@ -220,6 +218,7 @@ public static Entity createTitan(AtlantisTerrainFactory terrainFactory) { titan .addComponent(new CombatStatsComponent(config.troops, config.health, config.baseAttack, config.baseDefence, config.landSpeed, config.range)) + .addComponent(new HealthBarComponent(EntityType.ENEMY)) .addComponent(animator) .addComponent(new EnemyAnimationController()) .addComponent(new EnemySignal()); diff --git a/source/core/src/main/com/deco2800/game/entities/factories/UnitFactory.java b/source/core/src/main/com/deco2800/game/entities/factories/UnitFactory.java index 431f1990..81312bed 100644 --- a/source/core/src/main/com/deco2800/game/entities/factories/UnitFactory.java +++ b/source/core/src/main/com/deco2800/game/entities/factories/UnitFactory.java @@ -3,6 +3,8 @@ import com.badlogic.gdx.graphics.g2d.Animation; import com.badlogic.gdx.graphics.g2d.TextureAtlas; import com.deco2800.game.components.CombatStatsComponent; +import com.deco2800.game.components.EntityType; +import com.deco2800.game.components.HealthBarComponent; import com.deco2800.game.components.TouchAttackComponent; import com.deco2800.game.components.friendly.FriendlyComponent; import com.deco2800.game.components.friendly.TroopContainerComponent; @@ -10,7 +12,6 @@ import com.deco2800.game.entities.UnitType; import com.deco2800.game.entities.configs.BaseUnitConfig; import com.deco2800.game.entities.configs.UnitConfigs; -import com.deco2800.game.events.listeners.EventListener0; import com.deco2800.game.files.FileLoader; import com.deco2800.game.physics.PhysicsLayer; import com.deco2800.game.physics.PhysicsUtils; @@ -22,7 +23,6 @@ import com.deco2800.game.services.ResourceService; import com.deco2800.game.services.ServiceLocator; -import javax.naming.OperationNotSupportedException; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -91,6 +91,7 @@ private static Entity createMeleeTroop(UnitType type) { new CombatStatsComponent(stats.health, stats.baseAttack, stats.baseDefence)) + .addComponent(new HealthBarComponent(EntityType.FRIENDLY)) .addComponent(new TouchAttackComponent(PhysicsLayer.NPC)); } diff --git a/source/core/src/main/com/deco2800/game/screens/LoadingScreen.java b/source/core/src/main/com/deco2800/game/screens/LoadingScreen.java new file mode 100644 index 00000000..1f1a65c7 --- /dev/null +++ b/source/core/src/main/com/deco2800/game/screens/LoadingScreen.java @@ -0,0 +1,114 @@ +package com.deco2800.game.screens; + +import com.badlogic.gdx.ScreenAdapter; +import com.deco2800.game.GdxGame; +import com.deco2800.game.areas.AtlantisGameArea; +import com.deco2800.game.components.LoadingBar; +import com.deco2800.game.entities.Entity; +import com.deco2800.game.entities.EntityService; +import com.deco2800.game.entities.factories.RenderFactory; +import com.deco2800.game.input.InputService; +import com.deco2800.game.rendering.RenderService; +import com.deco2800.game.rendering.Renderer; +import com.deco2800.game.services.ResourceService; +import com.deco2800.game.services.ServiceLocator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class LoadingScreen extends ScreenAdapter { + private static final Logger logger = LoggerFactory.getLogger(LoadingScreen.class); + private final GdxGame game; + private final Renderer renderer; + private Entity ui; + + private final String[] forestTextures = AtlantisGameArea.forestTextures; + + public static final String[] uiTextures = AtlantisGameArea.uiTextures; + public static final String[] forestTextureAtlases = AtlantisGameArea.forestTextureAtlases; + public static final String[] atlantisSounds = AtlantisGameArea.atlantisSounds; + public static final String[] buildingPlacementTextures = AtlantisGameArea.buildingPlacementTextures; + + private static final String[] assets = { + "images/title-atlantis.png", + "images/loading bar_4.png", + "images/loading bar_5.png", + }; + + public LoadingScreen(GdxGame game) { + this.game = game; + ServiceLocator.registerInputService(new InputService()); + ServiceLocator.registerResourceService(new ResourceService()); + ServiceLocator.registerEntityService(new EntityService()); + ServiceLocator.registerRenderService(new RenderService()); + + logger.debug("Initialising Loading Screen"); + renderer = RenderFactory.createRenderer(); + loadingBarAssets(); + loadGameAssets(); + createLoadingBar(); + } + + @Override + public void render(float delta) { + ServiceLocator.getEntityService().update(); + if (ui.getComponent(LoadingBar.class).isLoaded()) { + game.setScreen(GdxGame.ScreenType.MAIN_GAME); + } + renderer.render(); + } + + @Override + public void resize(int width, int height) { + renderer.resize(width, height); + logger.trace("Resized renderer: ({} x {})", width, height); + } + + /** + * Load assets required by loading screen + */ + private void loadingBarAssets() { + logger.debug("Loading assets"); + ResourceService resourceService = ServiceLocator.getResourceService(); + resourceService.loadTextures(assets); + resourceService.loadAll(); + } + + /** + * Unloads loading screen assets + */ + private void unloadAssets() { + logger.debug("Unloading assets"); + ResourceService resourceService = ServiceLocator.getResourceService(); + resourceService.unloadAssets(assets); + } + + /** + * Creates the background and loading bar to be displayed to the screen + */ + private void createLoadingBar() { + logger.debug("Creating loading bar"); + ui = new Entity().addComponent(new LoadingBar()); + ServiceLocator.getEntityService().register(ui); + } + + /** + * Assets required by AtlantisGameArea added to loading queue + */ + private void loadGameAssets() { + logger.debug("Loading assets"); + ResourceService resourceService = ServiceLocator.getResourceService(); + resourceService.loadTextures(forestTextures); + resourceService.loadTextures(uiTextures); + resourceService.loadTextureAtlases(forestTextureAtlases); + resourceService.loadSounds(atlantisSounds); + resourceService.loadTextures(buildingPlacementTextures); + } + + public void dispose() { + logger.debug("Disposing Loading Screen"); + renderer.dispose(); + unloadAssets(); + ServiceLocator.getEntityService().dispose(); + ServiceLocator.getRenderService().dispose(); + } +} diff --git a/source/core/src/main/com/deco2800/game/screens/MainGameScreen.java b/source/core/src/main/com/deco2800/game/screens/MainGameScreen.java index 8314b425..acdfd036 100644 --- a/source/core/src/main/com/deco2800/game/screens/MainGameScreen.java +++ b/source/core/src/main/com/deco2800/game/screens/MainGameScreen.java @@ -6,6 +6,7 @@ import com.deco2800.game.GdxGame; import com.deco2800.game.areas.AtlantisGameArea; import com.deco2800.game.areas.terrain.AtlantisTerrainFactory; +import com.deco2800.game.components.LoadingBar; import com.deco2800.game.components.maingame.DialogueBoxDisplay; import com.deco2800.game.components.maingame.MainGameActions; import com.deco2800.game.components.pausemenu.PauseMenuActions; @@ -41,7 +42,14 @@ */ public class MainGameScreen extends ScreenAdapter { private static final Logger logger = LoggerFactory.getLogger(MainGameScreen.class); - private static final String[] mainGameTextures = {"images/heart.png","images/bigblack.png", "images/resource_display.png", "images/gainstone.png", "images/gain10wood.png", "images/gainmetal.png"}; + private static final String[] mainGameTextures = { + "images/heart.png", + "images/bigblack.png", + "images/resource_display.png", + "images/gainstone.png", + "images/gain10wood.png", + "images/gainmetal.png", + }; private static final Vector2 CAMERA_POSITION = new Vector2(11.5f, 2.5f); private final GdxGame game; @@ -59,7 +67,8 @@ public MainGameScreen(GdxGame game) { physicsEngine = physicsService.getPhysics(); ServiceLocator.registerInputService(new InputService()); - ServiceLocator.registerResourceService(new ResourceService()); +// ServiceLocator.registerResourceService(new ResourceService()); + // Resource Service created in Loading Screen ServiceLocator.registerEntityService(new EntityService()); ServiceLocator.registerRenderService(new RenderService()); @@ -79,7 +88,6 @@ public MainGameScreen(GdxGame game) { createUI(); logger.debug("Initialising main game screen entities"); - // Create game area as an AtlantisGameArea with an AtlantisTerrainFactory AtlantisTerrainFactory terrainFactory = new AtlantisTerrainFactory(renderer.getCamera()); AtlantisGameArea atlantisGameArea = new AtlantisGameArea(terrainFactory); @@ -145,7 +153,6 @@ private void createUI() { Stage stage = ServiceLocator.getRenderService().getStage(); InputComponent inputComponent = ServiceLocator.getInputService().getInputFactory().createForTerminal(); - DialogueBoxDisplay dialogueBoxDisplay = new DialogueBoxDisplay(537f); Entity ui = new Entity(); ui.addComponent(new InputDecorator(stage, 10)) diff --git a/source/core/src/main/com/deco2800/game/screens/TutorialScreen.java b/source/core/src/main/com/deco2800/game/screens/TutorialScreen.java new file mode 100644 index 00000000..b0d4a295 --- /dev/null +++ b/source/core/src/main/com/deco2800/game/screens/TutorialScreen.java @@ -0,0 +1,187 @@ +package com.deco2800.game.screens; + +import com.badlogic.gdx.ScreenAdapter; +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.scenes.scene2d.Stage; +import com.deco2800.game.GdxGame; +import com.deco2800.game.areas.AtlantisGameArea; +import com.deco2800.game.areas.TutorialGameArea; +import com.deco2800.game.areas.terrain.AtlantisTerrainFactory; +import com.deco2800.game.components.maingame.DialogueBoxActions; +import com.deco2800.game.components.maingame.DialogueBoxDisplay; +import com.deco2800.game.components.maingame.MainGameActions; +import com.deco2800.game.components.pausemenu.PauseMenuActions; +import com.deco2800.game.components.pausemenu.PauseMenuDisplay; +import com.deco2800.game.components.resources.ResourceCountDisplay; +import com.deco2800.game.components.story.StoryActions; +import com.deco2800.game.components.story.StoryDisplay; +import com.deco2800.game.components.tutorial.TutorialDisplay; +import com.deco2800.game.components.tutorial.TutorialActions; +import com.deco2800.game.entities.Entity; +import com.deco2800.game.entities.EntityService; +import com.deco2800.game.entities.factories.RenderFactory; +import com.deco2800.game.input.InputComponent; +import com.deco2800.game.input.InputDecorator; +import com.deco2800.game.input.InputService; +import com.deco2800.game.map.MapService; +import com.deco2800.game.physics.PhysicsEngine; +import com.deco2800.game.physics.PhysicsService; +import com.deco2800.game.rendering.RenderService; +import com.deco2800.game.rendering.Renderer; +import com.deco2800.game.services.GameTime; +import com.deco2800.game.services.ResourceService; +import com.deco2800.game.services.ServiceLocator; +import com.deco2800.game.ui.terminal.Terminal; +import com.deco2800.game.ui.terminal.TerminalDisplay; +import com.deco2800.game.components.weather.WeatherIconDisplay; +import com.deco2800.game.components.resources.ResourceCountDisplay; +import com.deco2800.game.components.maingame.MainGameExitDisplay; +import com.deco2800.game.components.gamearea.PerformanceDisplay; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The game screen containing the tutorial game. + * + *

Details on libGDX screens: https://happycoding.io/tutorials/libgdx/game-screens + * TODO: A new screen should be made for this - TutorialGameArea.java showing a simpler area + * TODO: Integrate with existing actions (detect event and change dialogue response) + */ +public class TutorialScreen extends ScreenAdapter { + private static final Logger logger = LoggerFactory.getLogger(TutorialScreen.class); + private static final String[] mainGameTextures = { + "images/heart.png", + "images/bigblack.png", + "images/resource_display.png", + "images/gainstone.png", + "images/gain10wood.png", + "images/gainmetal.png" + }; + + private static final Vector2 CAMERA_POSITION = new Vector2(11.5f, 2.5f); + + private final GdxGame game; + private final Renderer renderer; + private final PhysicsEngine physicsEngine; + + public TutorialScreen(GdxGame game) { + this.game = game; + + logger.debug("Initialising main game screen services"); + ServiceLocator.registerTimeSource(new GameTime()); + + PhysicsService physicsService = new PhysicsService(); + ServiceLocator.registerPhysicsService(physicsService); + physicsEngine = physicsService.getPhysics(); + + ServiceLocator.registerInputService(new InputService()); + ServiceLocator.registerResourceService(new ResourceService()); + + + + ServiceLocator.registerEntityService(new EntityService()); + ServiceLocator.registerRenderService(new RenderService()); + ServiceLocator.registerMapService(new MapService()); + + ServiceLocator.registerMapService(new MapService()); + + ServiceLocator.registerMapService(new MapService()); + + ServiceLocator.registerMapService(new MapService()); + + renderer = RenderFactory.createRenderer(); + renderer.getCamera().getEntity().setPosition(CAMERA_POSITION); + renderer.getDebug().renderPhysicsWorld(physicsEngine.getWorld()); + + loadAssets(); + createUI(); + + logger.debug("Initialising main game screen entities"); + + TutorialGameArea tutorialGameArea = new TutorialGameArea(); + tutorialGameArea.create(); + } + + @Override + public void render(float delta) { + physicsEngine.update(); + ServiceLocator.getEntityService().update(); + renderer.render(); + } + + @Override + public void resize(int width, int height) { + renderer.resize(width, height); + logger.trace("Resized renderer: ({} x {})", width, height); + } + + @Override + public void pause() { + logger.info("Game paused"); + } + + @Override + public void resume() { + logger.info("Game resumed"); + } + + @Override + public void dispose() { + logger.debug("Disposing tutorial game screen"); + + renderer.dispose(); + unloadAssets(); + + ServiceLocator.getEntityService().dispose(); + ServiceLocator.getRenderService().dispose(); + ServiceLocator.getResourceService().dispose(); + + ServiceLocator.clear(); + } + + private void loadAssets() { + logger.debug("Loading assets"); + ResourceService resourceService = ServiceLocator.getResourceService(); + resourceService.loadTextures(mainGameTextures); + ServiceLocator.getResourceService().loadAll(); + } + + private void unloadAssets() { + logger.debug("Unloading assets"); + ResourceService resourceService = ServiceLocator.getResourceService(); + resourceService.unloadAssets(mainGameTextures); + } + + /** + * Creates the main game's ui including components for rendering ui elements to the screen and + * capturing and handling ui input. + */ + private void createUI() { + logger.debug("Creating ui"); + Stage stage = ServiceLocator.getRenderService().getStage(); + InputComponent inputComponent = + ServiceLocator.getInputService().getInputFactory().createForTerminal(); + + Entity ui = new Entity(); + + // main game components + ui.addComponent(new InputDecorator(stage, 9)) + .addComponent(new WeatherIconDisplay()) + .addComponent(new PauseMenuDisplay(this.game)) + .addComponent(new PauseMenuActions(this.game)) + .addComponent(new PerformanceDisplay()) + .addComponent(new MainGameActions(this.game)) + .addComponent(new MainGameExitDisplay()) + .addComponent(new Terminal()) + .addComponent(inputComponent) + .addComponent(new ResourceCountDisplay()) + .addComponent(new TerminalDisplay()); + + // tutorial components + ui.addComponent(new TutorialDisplay()) + .addComponent(new InputDecorator(stage, 10)) + .addComponent(new TutorialActions(game)); + + ServiceLocator.getEntityService().register(ui); + } +} diff --git a/source/core/src/main/com/deco2800/game/worker/WorkerFactory.java b/source/core/src/main/com/deco2800/game/worker/WorkerFactory.java index 2522a756..a9e4b776 100644 --- a/source/core/src/main/com/deco2800/game/worker/WorkerFactory.java +++ b/source/core/src/main/com/deco2800/game/worker/WorkerFactory.java @@ -3,6 +3,9 @@ import com.deco2800.game.ai.tasks.AITaskComponent; import com.deco2800.game.components.friendly.FriendlyComponent; import com.deco2800.game.components.friendlyunits.SelectableComponent; +import com.deco2800.game.components.CombatStatsComponent; +import com.deco2800.game.components.EntityType; +import com.deco2800.game.components.HealthBarComponent; import com.deco2800.game.entities.Entity; import com.deco2800.game.files.FileLoader; import com.deco2800.game.input.InputComponent; @@ -39,6 +42,9 @@ public static Entity createWorker() { .addComponent(new WorkerInventoryComponent(stats.wood, stats.stone, stats.metal)) .addComponent(new ResourceCollectComponent(PhysicsLayer.RESOURCE_NODE)) .addComponent(new SelectableComponent()) + .addComponent(new CombatStatsComponent(stats.health, 0, 0)) + .addComponent(new HealthBarComponent(EntityType.FRIENDLY)) + .addComponent(aiComponent) .addComponent(inputComponent) .addComponent(new FriendlyComponent()); diff --git a/source/core/src/test/com/deco2800/game/components/CombatStatsComponentTest.java b/source/core/src/test/com/deco2800/game/components/CombatStatsComponentTest.java index 357b9e2b..a0472a95 100644 --- a/source/core/src/test/com/deco2800/game/components/CombatStatsComponentTest.java +++ b/source/core/src/test/com/deco2800/game/components/CombatStatsComponentTest.java @@ -14,6 +14,10 @@ void shouldSetGetHealth() { CombatStatsComponent combat = new CombatStatsComponent(10, 100, 20, 5, 20); assertEquals(100, combat.getHealth()); + combat.setHealth(150); + assertEquals(100, combat.getHealth()); + + combat.setMaxHealth(150); combat.setHealth(150); assertEquals(150, combat.getHealth()); @@ -21,6 +25,22 @@ void shouldSetGetHealth() { assertEquals(0, combat.getHealth()); } + @Test + void shouldSetGetMaxHealth() { + CombatStatsComponent combat = new CombatStatsComponent(10, 100, 20, 5, 20); + assertEquals(100, combat.getMaxHealth()); + + combat.setHealth(200); + assertEquals(100, combat.getHealth()); + + combat.setMaxHealth(500); + combat.setHealth(200); + assertEquals(200, combat.getHealth()); + + combat.setMaxHealth(-50); + assertEquals(0, combat.getMaxHealth()); + } + @Test void shouldCheckIsDead() { CombatStatsComponent combat = new CombatStatsComponent(10, 100, 20, 5, 20); diff --git a/source/core/src/test/com/deco2800/game/components/HealthBarComponentTest.java b/source/core/src/test/com/deco2800/game/components/HealthBarComponentTest.java new file mode 100644 index 00000000..19ba48ab --- /dev/null +++ b/source/core/src/test/com/deco2800/game/components/HealthBarComponentTest.java @@ -0,0 +1,86 @@ +package com.deco2800.game.components; + +import com.deco2800.game.extensions.GameExtension; +import com.deco2800.game.physics.PhysicsService; +import com.deco2800.game.rendering.RenderService; +import com.deco2800.game.services.GameTime; +import com.deco2800.game.services.ServiceLocator; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.junit.jupiter.api.Assertions.*; + +@RunWith(MockitoJUnitRunner.class) +@ExtendWith(GameExtension.class) +class HealthBarComponentTest { + + HealthBarComponent healthBar; + GameTime gameTime = Mockito.mock(GameTime.class); + + long lastUpdate; + boolean showing; + long visibleTime = 15L; + + + + @BeforeEach + void setUp() { + ServiceLocator.registerTimeSource(gameTime); + healthBar = new HealthBarComponent(EntityType.FRIENDLY); + } + + @Test + void shouldCreate() { + Mockito.when(gameTime.getTime()).thenReturn(10L); + + lastUpdate = ServiceLocator.getTimeSource().getTime(); + showing = true; + + assertEquals(lastUpdate, 10L); + assertTrue(showing); + } + + @Test + void shouldUpdateHealth() { + Mockito.when(gameTime.getTime()).thenReturn(20L); + + lastUpdate = ServiceLocator.getTimeSource().getTime(); + showing = true; + + assertEquals(lastUpdate, 20L); + assertTrue(showing); + } + + @Test + void shouldHideHealthBar() { + Mockito.when(gameTime.getTime()).thenReturn(30L); + + lastUpdate = ServiceLocator.getTimeSource().getTime() - visibleTime; + if (ServiceLocator.getTimeSource().getTimeSince(lastUpdate) > visibleTime) { + showing = false; + } + + assertEquals(lastUpdate, 15L); + assertFalse(showing); + } + + @Test + void shouldShowHealthBar() { + Mockito.when(gameTime.getTime()).thenReturn(50L); + long time = 10L; + showing = true; + + lastUpdate = ServiceLocator.getTimeSource().getTime() - visibleTime + time; + if (ServiceLocator.getTimeSource().getTimeSince(lastUpdate) > visibleTime) { + showing = false; + } + + assertEquals(lastUpdate, 45L); + assertTrue(showing); + } +} \ No newline at end of file