# HG changeset patch # User Neil Muller # Date 1329047819 -7200 # Node ID c77d6aa29bee20d9f11453e809163bc1c8530f14 # Parent 335db68e0db4122c2fe09e5fc8faf13fda446532 Some code to kinda demonstrate the ever so cunning state handling plan diff -r 335db68e0db4 -r c77d6aa29bee gamelib/main.py --- a/gamelib/main.py Sun Feb 12 13:11:53 2012 +0200 +++ b/gamelib/main.py Sun Feb 12 13:56:59 2012 +0200 @@ -2,6 +2,7 @@ from menu import MenuScreen from endscreen import EndScreen +from ss_state import SSState from pyntnclick.main import GameDescription @@ -16,6 +17,9 @@ } START_SCREEN = 'menu' + def __init__(self): + super(SuspendedSentence, self).__init__(SSState) + def main(): ss = SuspendedSentence() diff -r 335db68e0db4 -r c77d6aa29bee gamelib/scenes/bridge.py --- a/gamelib/scenes/bridge.py Sun Feb 12 13:11:53 2012 +0200 +++ b/gamelib/scenes/bridge.py Sun Feb 12 13:56:59 2012 +0200 @@ -330,19 +330,21 @@ return "The sign reads 'Warning: Authorized Techinicians Only'." def interact_without(self): - if self.scene.get_data('ai status') == 'online': + ai_status = self.state.get_jim_state() + if ai_status == 'online': return self.interact_default(None) elif self.scene.get_data('ai panel') == 'closed': return Result("You are unable to open the panel with your" " bare hands.") elif self.scene.get_data('ai panel') == 'open': self.scene.set_data('ai panel', 'broken') - self.scene.set_data('ai status', 'dead') + self.state.break_ai() self.set_interact('broken') return Result("You unplug various important-looking wires.") def interact_with_machete(self, item): - if self.scene.get_data('ai status') == 'online': + ai_status = self.state.get_jim_state() + if ai_status == 'online': return self.interact_default(item) elif self.scene.get_data('ai panel') == 'closed': self.scene.set_data('ai panel', 'open') @@ -350,13 +352,13 @@ return Result("Using the machete, you lever the panel off.") elif self.scene.get_data('ai panel') == 'open': self.scene.set_data('ai panel', 'broken') - self.scene.set_data('ai status', 'dead') + self.state.break_ai() self.set_interact('broken') return Result("You smash various delicate components with" " the machete.") def interact_default(self, item): - if self.scene.get_data('ai status') == 'online': + if self.state.get_jim_state() == 'online': return (Result('You feel a shock from the panel.'), make_jim_dialog("Prisoner %s. Please step away from the" " panel. You are not an authorized" diff -r 335db68e0db4 -r c77d6aa29bee gamelib/scenes/game_widgets.py --- a/gamelib/scenes/game_widgets.py Sun Feb 12 13:11:53 2012 +0200 +++ b/gamelib/scenes/game_widgets.py Sun Feb 12 13:56:59 2012 +0200 @@ -28,9 +28,9 @@ return self.interact_without() -def make_jim_dialog(mesg, state): +def make_jim_dialog(mesg, game): "Utility helper function" - if state.scenes['bridge'].get_data('ai status') == 'online': + if game.data.get_jim_state() == 'online': return Result(mesg, style='JIM') else: return None @@ -45,7 +45,7 @@ } def get_description(self): - status = self.game.scenes['bridge'].get_data('ai status') + status = self.state.get_jim_state() if status == 'online': return "A security camera watches over the room" elif status == 'looping': @@ -55,19 +55,19 @@ return "The security camera is powered down" def is_interactive(self, tool=None): - return self.game.scenes['bridge'].get_data('ai status') == 'online' + return self.state.get_jim_state() == 'online' def interact_with_escher_poster(self, item): # Order matters here, because of helper function - if self.game.scenes['bridge'].get_data('ai status') == 'online': + if self.state.get_jim_state() == 'online': ai_response = make_jim_dialog("3D scene reconstruction failed." " Critical error. Entering emergency shutdown.", self.game) - self.game.scenes['bridge'].set_data('ai status', 'looping') + self.game.data.loop_ai() return ai_response def animate(self): - ai_status = self.game.scenes['bridge'].get_data('ai status') + ai_status = self.state.get_jim_state() if ai_status != self.get_data('status'): self.set_data('status', ai_status) self.set_interact(ai_status) diff -r 335db68e0db4 -r c77d6aa29bee gamelib/ss_state.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gamelib/ss_state.py Sun Feb 12 13:56:59 2012 +0200 @@ -0,0 +1,16 @@ +"""The Custom state object for Suspended Sentence""" + +from pyntnclick.state import GameState + +class SSState(GameState): + + def get_jim_state(self): + """Check JIM's health""" + return self['bridge']['ai status'] + + def loop_ai(self): + """Make JIM loopy""" + self['bridge']['ai status'] = 'looping' + + def break_ai(self): + self['bridge']['ai status'] = 'dead' diff -r 335db68e0db4 -r c77d6aa29bee pyntnclick/main.py --- a/pyntnclick/main.py Sun Feb 12 13:11:53 2012 +0200 +++ b/pyntnclick/main.py Sun Feb 12 13:56:59 2012 +0200 @@ -49,7 +49,7 @@ # resource module RESOURCE_MODULE = "Resources" - def __init__(self): + def __init__(self, custom_data_cls=None): if self.INITIAL_SCENE is None: raise GameDescriptionError("A game must have an initial scene.") if not self.SCENE_LIST: @@ -62,6 +62,7 @@ self._scene_list = self.SCENE_LIST self._resource_module = self.RESOURCE_MODULE self._debug_rects = False + self._custom_data_cls = custom_data_cls self._screens = self.SCREENS.copy() self._screens['game'] = GameScreen self.resource = Resources(self._resource_module) @@ -72,6 +73,8 @@ def initial_state(self): """Create a copy of the initial game state.""" initial_state = state.Game(self) + if self._custom_data_cls: + initial_state.set_custom_data(self._custom_data_cls()) initial_state.set_debug_rects(self._debug_rects) for scene in self._scene_list: initial_state.load_scenes(scene) diff -r 335db68e0db4 -r c77d6aa29bee pyntnclick/state.py --- a/pyntnclick/state.py Sun Feb 12 13:11:53 2012 +0200 +++ b/pyntnclick/state.py Sun Feb 12 13:56:59 2012 +0200 @@ -7,7 +7,7 @@ from pygame.color import Color -def frame_rect(surface, color, rect, thick = 1): +def frame_rect(surface, color, rect, thick=1): # FIXME: Stolen from albow surface.fill(color, (rect.left, rect.top, rect.width, thick)) surface.fill(color, (rect.left, rect.bottom - thick, rect.width, thick)) @@ -59,6 +59,35 @@ res.process(scene_widget) +class GameState(dict): + """This holds the serializable game state. + + Games wanting to do fancier stuff with the state should + sub-class this and feed the subclass into + GameDescription via the custom_data parameter.""" + + def get_all_gizmo_data(self, state_key): + """Get all state for a gizmo - returns a dict""" + return self[state_key] + + def get_data(self, state_key, data_key): + """Get a single entry""" + return self[state_key].get(data_key, None) + + def set_data(self, state_key, data_key, value): + """Set a single value""" + self[state_key][data_key] = value + + def initialize_state(self, state_key, initial_data): + """Initialize a gizmo entry""" + if state_key not in self: + self[state_key] = {} + if initial_data: + # deep copy of INITIAL_DATA allows lists, sets and + # other mutable types to safely be used in INITIAL_DATA + self[state_key].update(copy.deepcopy(initial_data)) + + class Game(object): """Complete game state. @@ -81,7 +110,7 @@ # currently selected tool (item) self.tool = None # Global game data - self.data = {} + self.data = GameState() # current scene self.current_scene = None # current detail view @@ -97,6 +126,9 @@ # debug rects self.debug_rects = False + def set_custom_data(self, data_object): + self.data = data_object + def set_debug_rects(self, value=True): self.debug_rects = value @@ -251,21 +283,15 @@ def set_state(self, state): """Set the state object and initialize if needed""" self.state = state - if self.state_key not in self.state: - self.state[self.state_key] = {} - if self.INITIAL_DATA: - # deep copy of INITIAL_DATA allows lists, sets and - # other mutable types to safely be used in INITIAL_DATA - self.state[self.state_key].update( - copy.deepcopy(self.INITIAL_DATA)) + self.state.initialize_state(self.state_key, self.INITIAL_DATA) def set_data(self, key, value): if self.state: - self.state[self.state_key][key] = value + self.state.set_data(self.state_key, key, value) def get_data(self, key): if self.state: - return self.state[self.state_key].get(key, None) + return self.state.get_data(self.state_key, key) class Scene(StatefulGizmo):