changeset 346:282113d86d75

Save door and lever state.
author Jeremy Thurgood <firxen@gmail.com>
date Fri, 06 Sep 2013 15:14:27 +0200
parents 4708e86a9a3c
children dced49dd9864
files data/levels/level1 nagslang/game_object.py nagslang/level.py nagslang/screens/menu.py nagslang/world.py
diffstat 5 files changed, 65 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/data/levels/level1	Fri Sep 06 13:42:42 2013 +0200
+++ b/data/levels/level1	Fri Sep 06 15:14:27 2013 +0200
@@ -34,7 +34,7 @@
   name: both_switches
 - args:
   - [620, 220]
-  - door_switch
+  - switch_door
   classname: FloorLight
   name: door_light
 - args:
--- a/nagslang/game_object.py	Fri Sep 06 13:42:42 2013 +0200
+++ b/nagslang/game_object.py	Fri Sep 06 15:14:27 2013 +0200
@@ -127,6 +127,16 @@
             self.interactible.set_game_object(self)
         self.remove = False  # If true, will be removed from drawables
 
+    def set_stored_state_dict(self, stored_state):
+        """Override this to set up whatever state storage you want.
+
+        The `stored_state` dict passed in contains whatever saved state we
+        might have for this object. If the return value of this method
+        evaluates to `True`, the contents of the `stored_state` dict will be
+        saved, otherwise it will be discarded.
+        """
+        pass
+
     def get_space(self):
         return self.physicser.get_space()
 
@@ -270,21 +280,44 @@
         self.shape.sensor = True
         self.destination = destination
         self.dest_pos = tuple(dest_pos)
-        puzzler = None
-        action = environment.Action(self._post_door_event)
-        if key_state is not None:
-            puzzler = puzzle.StateProxyPuzzler(key_state)
-            action.condition = environment.PuzzleStateCondition(puzzler)
+        self._key_state = key_state
         super(Door, self).__init__(
             SingleShapePhysicser(space, self.shape),
-            render.ImageRenderer(resources.get_image('objects', 'door.png')),
-            puzzler,
-            interactible=environment.Interactible(action),
+            render.ImageStateRenderer({
+                True: resources.get_image('objects', 'door.png'),
+                # TODO: Locked door image.
+                False: resources.get_image('objects', 'door.png'),
+            }),
+            puzzle.ParentAttrPuzzler('is_open'),
+            interactible=environment.Interactible(
+                environment.Action(
+                    self._post_door_event,
+                    environment.FunctionCondition(lambda p: self.is_open))),
         )
 
+    @property
+    def is_open(self):
+        return self._stored_state['is_open']
+
     def _post_door_event(self, protagonist):
         DoorEvent.post(self.destination, self.dest_pos)
 
+    def set_stored_state_dict(self, stored_state):
+        self._stored_state = stored_state
+        if self._key_state is not None:
+            # We're lockable, so we start locked and want to save our state.
+            self._stored_state.setdefault('is_open', False)
+            return True
+        # Not lockable, so we're always open and don't bother saving state.
+        self._stored_state['is_open'] = True
+        return False
+
+    def update(self, dt):
+        if not self.is_open:
+            self._stored_state['is_open'] = self.puzzler.glue.get_state_of(
+                self._key_state)
+        super(Door, self).update(dt)
+
     @classmethod
     def requires(cls):
         return [("name", "string"), ("position", "coordinates"),
@@ -331,7 +364,6 @@
         body = make_body(None, None, position)
         self.shape = pymunk.Circle(body, 20)
         self.shape.sensor = True
-        self.toggle_on = False
         super(ToggleSwitch, self).__init__(
             SingleShapePhysicser(space, self.shape),
             render.ImageStateRenderer({
@@ -344,8 +376,18 @@
                 environment.Action(self._toggle)),
         )
 
+    @property
+    def toggle_on(self):
+        return self._stored_state['toggle_on']
+
     def _toggle(self, protagonist):
-        self.toggle_on = not self.toggle_on
+        self._stored_state['toggle_on'] = not self.toggle_on
+
+    def set_stored_state_dict(self, stored_state):
+        self._stored_state = stored_state
+        # We start in the "off" position.
+        self._stored_state.setdefault('toggle_on', False)
+        return True
 
     @classmethod
     def requires(cls):
--- a/nagslang/level.py	Fri Sep 06 13:42:42 2013 +0200
+++ b/nagslang/level.py	Fri Sep 06 15:14:27 2013 +0200
@@ -30,6 +30,7 @@
         self.polygons = {}
         self.lines = []
         self.world = world
+        self.world.level_state.setdefault(name, {})
         self.basetile = 'tiles/floor.png'
         self._tile_image = None
         self._surface = None
@@ -93,6 +94,14 @@
             gobj = cls(*args)
         elif issubclass(cls, go.GameObject):
             gobj = cls(space, *args)
+            level_state = self.world.level_state[self.name]
+            stored_state = level_state.get(name, {})
+            should_save = bool(gobj.set_stored_state_dict(stored_state))
+            if should_save:
+                if name is None:
+                    raise Exception(
+                        "Unnamed game object wants to save state:" % (gobj,))
+                level_state[name] = stored_state
             self.drawables.append(gobj)
             if gobj.overlay:
                 self.overlay_drawables.append(gobj.overlay)
--- a/nagslang/screens/menu.py	Fri Sep 06 13:42:42 2013 +0200
+++ b/nagslang/screens/menu.py	Fri Sep 06 15:14:27 2013 +0200
@@ -47,7 +47,7 @@
 
     def play(self):
         level_name, pos = self.world.level
-        self.world.protagonist.set_position(pos)
+        self.world.protagonist.set_position(tuple(pos))
         ScreenChange.post(level_name)
 
     def restart(self):
--- a/nagslang/world.py	Fri Sep 06 13:42:42 2013 +0200
+++ b/nagslang/world.py	Fri Sep 06 15:14:27 2013 +0200
@@ -26,6 +26,7 @@
         starting_position = (350, 300)
         self.protagonist = Protagonist(pymunk.Space(), self, starting_position)
         self.level = (first_level, starting_position)
+        self.level_state = {}
 
     def _save_location(self):
         app = 'nagslang'
@@ -46,7 +47,7 @@
             if hasattr(value, '__name__'):
                 continue
             # Hack until we save protagonist state
-            if hasattr(value, 'update'):
+            if hasattr(value, 'update') and not isinstance(value, dict):
                 continue
             data[attr] = value