Don't re-initialize when re-entering.
[koperkapel.git] / koperkapel / scenes / roach_management.py
index 0d10e21f5078e1f8b23a0fecc61dcbbf09811a00..c0e82107a93ec56ed08059e8dba3a89bbaa56b3c 100644 (file)
@@ -4,8 +4,8 @@ from pgzero.constants import keys, mouse
 from pgzero.actor import Actor
 from ..actors.buttons import ImageButton
 from ..constants import WIDTH, HEIGHT
 from pgzero.actor import Actor
 from ..actors.buttons import ImageButton
 from ..constants import WIDTH, HEIGHT
-from ..roaches import big_roaches
-from ..serums import big_serums, SERUMS
+from ..roaches import big_roaches, roach_by_name
+from ..serums import big_serums, roach_is_serumless, SERUMS
 from ..vehicles.base import Vehicle
 from .base import Scene, ChangeSceneEvent
 
 from ..vehicles.base import Vehicle
 from .base import Scene, ChangeSceneEvent
 
@@ -17,6 +17,7 @@ VEHICLE_MID_X = WIDTH * 3 // 8
 VEHICLE_MID_Y = HEIGHT * 1 // 2
 BUTTON_INSET = (20, 20)
 SERUM_OFFSET = (0, 20)
 VEHICLE_MID_Y = HEIGHT * 1 // 2
 BUTTON_INSET = (20, 20)
 SERUM_OFFSET = (0, 20)
+ROACH_PAD_OFFSET = (0, 20)
 
 
 def inset_button(pos, d):
 
 
 def inset_button(pos, d):
@@ -28,51 +29,56 @@ def inset_button(pos, d):
 class RoachesScene(Scene):
     """ Roach management scene. """
 
 class RoachesScene(Scene):
     """ Roach management scene. """
 
-    def __init__(self):
+    def __init__(self, level_scene=None):
         super().__init__()
         super().__init__()
+        self._level_scene = level_scene
+        self._vehicle = None
+        self._seat_pos = 0
+        self._outside_roach = None
         self._outside_roach_pos = 0
         self._inventory_pos = 0
         self._inventory_item = None
         self._outside_roach_pos = 0
         self._inventory_pos = 0
         self._inventory_item = None
-        self._selected_seat = None
-        self._roaches = self.actors.add_layer("roaches", level=10)
-        self._inventory = self.actors.add_layer("inventory", level=10)
-        self._pads = self.actors.add_layer("pads", level=5)
-        self._seats = self.actors.add_layer("seats", level=5)
-        self._buttons = self.actors.add_layer("buttons", level=6)
+        self._roach_layer = self.actors.add_layer("roaches", level=10)
+        self._inventory_layer = self.actors.add_layer("inventory", level=10)
+        self._pad_layer = self.actors.add_layer("pads", level=5)
+        self._seat_layer = self.actors.add_layer("seats", level=5)
+        self._button_layer = self.actors.add_layer("buttons", level=6)
         self._init_pads()
         self._init_buttons()
         self._init_serums()
 
     def enter(self, world):
         self._init_pads()
         self._init_buttons()
         self._init_serums()
 
     def enter(self, world):
-        self._vehicle = Vehicle.by_type(world.vehicles.current)
+        self._vehicle = Vehicle.current(world)
+        self._update_calls = []
         self._init_bg()
         self._init_seats()
         self._init_bg()
         self._init_seats()
-        self._init_roaches(world.roaches)
+        self._init_roaches(world)
         self._update_inventory(world)
 
     def _init_bg(self):
         self._update_inventory(world)
 
     def _init_bg(self):
+        self.actors.default.clear()
         self.actors.default.add(self._vehicle.roach_management_overlay())
 
     def _init_seats(self):
         self.actors.default.add(self._vehicle.roach_management_overlay())
 
     def _init_seats(self):
+        self._seat_layer.clear()
         for seat in self._vehicle.seats:
         for seat in self._vehicle.seats:
-            seat_actor = self._seats.add(seat.actor())
+            seat_actor = self._seat_layer.add(seat.actor())
             seat_actor.pos = (
                 seat.vehicle_pos[0] + VEHICLE_MID_X,
                 seat.vehicle_pos[1] + VEHICLE_MID_Y)
             seat_actor.pos = (
                 seat.vehicle_pos[0] + VEHICLE_MID_X,
                 seat.vehicle_pos[1] + VEHICLE_MID_Y)
+        self._seat_layer[self._seat_pos].selected = True
 
 
-    def _init_roaches(self, roaches):
-        for i, roach in enumerate(roaches):
-            roach_actor = self._roaches.add(big_roaches.assemble(roach))
-            # TODO: less hacky seat assignment
-            if i < len(self._seats):
-                roach_actor.pos = self._seats[i].pos
+    def _init_roaches(self, world):
+        self._roach_actors = {}
+        for roach in world.roaches:
+            self._roach_actors[roach.name] = big_roaches.assemble(roach)
 
     def _init_serums(self):
         self._serum_actors = {
             serum: big_serums.assemble(serum) for serum in SERUMS}
 
     def _update_inventory(self, world):
 
     def _init_serums(self):
         self._serum_actors = {
             serum: big_serums.assemble(serum) for serum in SERUMS}
 
     def _update_inventory(self, world):
-        self._inventory.clear()
+        self._inventory_layer.clear()
         serums = world.serums
         if not serums:
             return
         serums = world.serums
         if not serums:
             return
@@ -82,23 +88,48 @@ class RoachesScene(Scene):
         serum_actor.pos = (
             inv_pad_centre[0] + SERUM_OFFSET[0],
             inv_pad_centre[1] + SERUM_OFFSET[1])
         serum_actor.pos = (
             inv_pad_centre[0] + SERUM_OFFSET[0],
             inv_pad_centre[1] + SERUM_OFFSET[1])
-        self._inventory.add(serum_actor)
+        self._inventory_layer.add(serum_actor)
+
+    def _update_roaches(self, world):
+        self._roach_layer.clear()
+        seating = self._vehicle.seating(world)
+        self._outside_roaches = []
+        for roach in world.roaches:
+            seat_pos = seating.get(roach.name)
+            if seat_pos is not None:
+                roach_actor = self._roach_actors[roach.name]
+                roach_actor.pos = self._seat_layer[seat_pos].pos
+                self._roach_layer.add(roach_actor)
+            else:
+                self._outside_roaches.append(roach.name)
+        if self._outside_roaches:
+            self._outside_roach_pos %= len(self._outside_roaches)
+            roach_actor = self._roach_actors[
+                self._outside_roaches[self._outside_roach_pos]]
+            roach_pad_center = self._roach_pad.center
+            roach_actor.pos = (
+                roach_pad_center[0] + ROACH_PAD_OFFSET[0],
+                roach_pad_center[1] + ROACH_PAD_OFFSET[1])
+            self._roach_layer.add(roach_actor)
+        else:
+            self._outside_roach_pos = 0
 
     def _init_pads(self):
 
     def _init_pads(self):
-        self._roach_pad = self._pads.add(
+        self._roach_pad = self._pad_layer.add(
             Actor("roach_management/roach_pad", anchor=("left", "bottom")))
         self._roach_pad.pos = (TOOLBAR_LEFT_X, TOOLBAR_MID_Y)
             Actor("roach_management/roach_pad", anchor=("left", "bottom")))
         self._roach_pad.pos = (TOOLBAR_LEFT_X, TOOLBAR_MID_Y)
-        self._inventory_pad = self._pads.add(
+        self._inventory_pad = self._pad_layer.add(
             Actor("roach_management/inventory_pad", anchor=("left", "top")))
         self._inventory_pad.pos = (TOOLBAR_LEFT_X, TOOLBAR_MID_Y)
 
     def _add_button(self, name, anchor, inset, pos, action):
             Actor("roach_management/inventory_pad", anchor=("left", "top")))
         self._inventory_pad.pos = (TOOLBAR_LEFT_X, TOOLBAR_MID_Y)
 
     def _add_button(self, name, anchor, inset, pos, action):
-        button = self._buttons.add(
+        button = self._button_layer.add(
             ImageButton(name, anchor=anchor, action=action))
         button.pos = inset_button(pos, inset)
         return button
 
     def _init_buttons(self):
             ImageButton(name, anchor=anchor, action=action))
         button.pos = inset_button(pos, inset)
         return button
 
     def _init_buttons(self):
+        self._button_layer.clear()
         self._add_button(
             "roach_management/left_button", ("left", "bottom"), (1, -1),
             self._roach_pad.bottomleft, self._roach_left)
         self._add_button(
             "roach_management/left_button", ("left", "bottom"), (1, -1),
             self._roach_pad.bottomleft, self._roach_left)
@@ -131,20 +162,76 @@ class RoachesScene(Scene):
     def _inventory_right(self):
         self._inventory_pos += 1
 
     def _inventory_right(self):
         self._inventory_pos += 1
 
-    def _eject_roach(self):
-        print("Eject roach.")
+    def _select_seat(self, seat_pos):
+        self._seat_layer[self._seat_pos].selected = False
+        self._seat_pos = seat_pos
+        self._seat_layer[self._seat_pos].selected = True
 
 
-    def update(self, world, dt):
+    def _eject_roach(self, world=None):
+        if world is None:
+            self._update_calls.append(self._eject_roach)
+            return
+        self._vehicle.seat_roach(world, None, self._seat_pos)
+
+    def _click_roach_pad(self, world=None):
+        if world is None:
+            self._update_calls.append(self._click_roach_pad)
+            return
+        if self._outside_roaches:
+            roach = self._outside_roaches[self._outside_roach_pos]
+            self._vehicle.seat_roach(world, roach, self._seat_pos)
+
+    def _click_inventory_pad(self, world=None):
+        if world is None:
+            self._update_calls.append(self._click_inventory_pad)
+            return
+        roach_name = self._vehicle.roach_at(world, self._seat_pos)
+        if roach_name is None:
+            return
+        roach = roach_by_name(world, roach_name)
+        if roach is None:
+            return
+        serums = list(world.serums)
+        if self._inventory_pos >= len(serums):
+            return
+        serum = serums.pop(self._inventory_pos)
+        if roach_is_serumless(roach):
+            roach[serum] = True
+            world.serums = serums
+            self._update_calls.append((self._update_roach_actor, roach_name))
+
+    def _update_roach_actor(self, world, roach_name):
+        roach = roach_by_name(world, roach_name)
+        self._roach_actors[roach_name] = big_roaches.assemble(roach)
+
+    def update(self, world, engine, dt):
+        update_calls, self._update_calls = self._update_calls, []
+        while update_calls:
+            f, args = update_calls.pop(), ()
+            if type(f) is tuple:
+                f, args = f[0], f[1:]
+            f(world, *args)
+        events = world.pop_events()
         self._update_inventory(world)
         self._update_inventory(world)
+        self._update_roaches(world)
+        return events
 
     def on_key_down(self, key, mod, unicode):
 
     def on_key_down(self, key, mod, unicode):
-        if key == keys.ESCAPE:
-            from .menu import MenuScene
-            return [ChangeSceneEvent(MenuScene())]
+        if key in (keys.ESCAPE, keys.Z):
+            if self._level_scene is None:
+                from .menu import MenuScene
+                return [ChangeSceneEvent(MenuScene())]
+            return [ChangeSceneEvent(self._level_scene)]
 
     def on_mouse_down(self, pos, button):
         if button == mouse.LEFT:
             for actor in self.actors.buttons:
                 if actor.collidepoint(pos):
 
     def on_mouse_down(self, pos, button):
         if button == mouse.LEFT:
             for actor in self.actors.buttons:
                 if actor.collidepoint(pos):
-                    actor.action()
-                    break
+                    return actor.action()
+            for i, actor in enumerate(self.actors.seats):
+                if actor.collidepoint(pos):
+                    return self._select_seat(i)
+            if self._roach_pad.collidepoint(pos):
+                return self._click_roach_pad()
+            if self._inventory_pad.collidepoint(pos):
+                return self._click_inventory_pad()