Very statis hud.
[koperkapel.git] / koperkapel / scenes / level.py
index 5db95bb2d3070debfb893439a05e489486455e9b..e5de740eac91189febeffd4503ec29193cc3162c 100644 (file)
@@ -7,18 +7,45 @@ from ..loaders.levelloader import levels
 from .base import (
     Scene, ChangeSceneEvent, MoveViewportEvent, WorldEvent, defer_to_update)
 from ..constants import TILE_SIZE, WIDTH, HEIGHT
-from ..gamelib.items import clone_old_item
+from ..gamelib.items import clone_old_item, create_new_item
+from ..hud import HudActor
 from ..roaches import build_roach
 from ..vehicles.base import Vehicle
 from ..weapons import weapon_by_name
 
 
+class PlayerStats:
+    def __init__(self, world):
+        roaches = world.roaches
+        self.health = sum(r.health for r in roaches)
+        self.smart = self._count_attr("smart", roaches)
+        self.fast = self._count_attr("fast", roaches)
+        self.strong = self._count_attr("strong", roaches)
+
+    def __str__(self):
+        return "<PlayerStats health=%d smart=%d fast=%d strong=%d>" % (
+            self.health, self.smart, self.fast, self.strong)
+
+    def __eq__(self, other):
+        if not isinstance(other, PlayerStats):
+            return NotImplemented
+        return all(
+            (self.health == other.health, self.smart == other.smart,
+             self.fast == other.fast, self.strong == other.strong))
+
+    def _count_attr(self, attr, roaches):
+        attrs = [r[attr] for r in roaches]
+        attrs = [a for a in attrs if a]
+        return len(attrs)
+
+
 class BaseLevelScene(Scene):
     """ Level scene. """
 
     def __init__(self):
         super().__init__()
         self._level = None
+        self._stats = None
 
     def enter(self, world):
         self._level = levels.load(world.level.name)
@@ -93,12 +120,16 @@ class GameLevelScene(BaseLevelScene):
             for generator in self._generators:
                 generator.unpause()
             return
+        self._update_player_stats(world)
         super().enter(world)
         self._roaches = self.actors.add_layer("roaches", level=10)
         self._friends = self.actors.add_layer("friendly roaches", level=9)
         self._items = self.actors.add_layer("items", level=9)
         self._generators = self.actors.add_layer("enemy generators", level=8)
-        self._enemies = self.actors.add_layer("enemies", level=7)
+        self._enemies = self.actors.add_layer("enemies", level=11)
+        self._hud = self.actors.add_layer("hud", level=12)
+        self._hud.add(HudActor(
+            self._stats, anchor=("right", "bottom"), pos=(WIDTH, HEIGHT)))
         self._vehicle = Vehicle.current(world)
         self._mode = 'walk'
         self._angle = 0  # up
@@ -195,19 +226,41 @@ class GameLevelScene(BaseLevelScene):
             self._level.remove_enemy(enemy)
             self._enemies.remove(enemy)
 
-    def _fire_bullet(self, bullet, pos, dp):
+    def _fire_bullet(self, bullet, pos, dp, angle):
         if len(self._bullets) >= 10:
             return
         bullet.game_pos = pos
+        bullet.game_dp = dp
+        bullet.dt = 0
+        bullet.level_layer = self._level_layer
+        bullet.angle = angle
         self._bullets.add(bullet)
 
+    def _check_for_bullet_hits(self):
+        for bullet in list(self._bullets):
+            for enemy in list(self._enemies):
+                if enemy.collidepoint(bullet.pos):
+                    self._hit_enemy(enemy, bullet.weapon)
+                    self._bullets.remove(bullet)
+
+    def _update_bullet(self, bullet, dt):
+        bullet.dt += dt
+        if bullet.dt > 0.1:
+            bullet.dt = 0
+            bullet.game_pos = pos = (
+                bullet.game_pos[0] + bullet.game_dp[0],
+                bullet.game_pos[1] + bullet.game_dp[1])
+            if not self._level.can_bullet(pos[0], pos[1], bullet.level_layer):
+                self._bullets.remove(bullet)
+
     @defer_to_update
     def _fire_weapon(self, world):
         weapon = weapon_by_name(world.weapons.current)
         weapon.play_sound()
         if weapon.bullet_range > 0:
             self._fire_bullet(
-                weapon.assemble_bullet(), self._player_pos, self._angle_dp)
+                weapon.assemble_bullet(), self._player_pos, self._angle_dp,
+                self._angle)
         else:
             # melee
             pos, dp = self._player_pos, self._angle_dp
@@ -218,8 +271,25 @@ class GameLevelScene(BaseLevelScene):
 
     @defer_to_update
     def _change_vehicle(self, world):
-        vehicle = Vehicle.random()
-        world.vehicles.current = vehicle
+        x, y = self._player_pos
+
+        old_vehicle = world.vehicles.current
+
+        item = self._level.item_at(x, y)
+
+        if item and item.item_type == "vehicle":
+            world.vehicles.current = item.item_data["vehicle"]
+            self._level.remove_item(item)
+            self._items.remove(item)
+        else:
+            world.vehicles.current = "walking"
+
+        if old_vehicle != "walking":
+            dropped_vehicle = create_new_item(
+                "vehicle", (x, y), vehicle=old_vehicle)
+            self._level.items.append(dropped_vehicle)
+            self._items.add(dropped_vehicle)
+
         self._vehicle_changed()
 
     def update(self, world, engine, dt):
@@ -235,15 +305,22 @@ class GameLevelScene(BaseLevelScene):
         for enemy in self._enemies:
             enemy.pos = self.calc_offset(
                 enemy.game_pos[0] * TILE_SIZE, enemy.game_pos[1] * TILE_SIZE)
-        for bullet in self._bullets:
+        for bullet in list(self._bullets):
+            self._update_bullet(bullet, dt)
             bullet.pos = self.calc_offset(
                 bullet.game_pos[0] * TILE_SIZE + (TILE_SIZE // 2),
                 bullet.game_pos[1] * TILE_SIZE + (TILE_SIZE // 2))
+        self._check_for_bullet_hits()
+        self._update_player_stats(world)
+        self._hud[0].stats = self._stats
         more = self._check_held_keys(dt)
         if more:
             events.extend(more)
         return events
 
+    def _update_player_stats(self, world):
+        self._stats = PlayerStats(world)
+
     def _check_enemies(self):
         if len(self._level.enemies) != len(self._enemies):
             # New nemy has spawned
@@ -302,9 +379,10 @@ class GameLevelScene(BaseLevelScene):
             self._add_roach()
         elif self._level.item_at(x, y):
             item = self._level.item_at(x, y)
-            self._level.remove_item(item)
-            self._items.remove(item)
-            self._gain_item(item)
+            if item.item_type != "vehicle":
+                self._level.remove_item(item)
+                self._items.remove(item)
+                self._gain_item(item)
         elif self._level.is_exit(x, y):
             next_level = self._level.get_exit_level()
             return [
@@ -323,8 +401,11 @@ class GameLevelScene(BaseLevelScene):
     def on_key_down(self, key, mod, unicode):
         x, y = self._player_pos
         if key in (keys.DOWN, keys.UP, keys.LEFT, keys.RIGHT):
+            firing = (keys.X in self._held_keys)
             self._held_keys.clear()
             self._held_keys.add(key)
+            if firing:
+                self._held_keys.add(keys.X)
             # We do this so pressing the key has an instant effect, and can
             # then be held
             self._last_key_down = self._key_rate + 0.01