# HG changeset patch # User Jeremy Thurgood # Date 1359317979 -7200 # Node ID eed75a1d50c4086f9382740057295b4378d2e9b5 # Parent 8f94fbf05ab9b70967051069798659ce2e4a0715 Better Item handling. diff -r 8f94fbf05ab9 -r eed75a1d50c4 gamelib/scenes/bridge.py --- a/gamelib/scenes/bridge.py Sun Jan 27 22:09:34 2013 +0200 +++ b/gamelib/scenes/bridge.py Sun Jan 27 22:19:39 2013 +0200 @@ -42,8 +42,9 @@ def setup(self): self.background_playlist = None - self.add_item(Superconductor('superconductor')) - self.add_item(Stethoscope('stethoscope')) + self.add_item_factory(Superconductor) + self.add_item_factory(TapedSuperconductor) + self.add_item_factory(Stethoscope) self.add_thing(ToMap()) self.add_thing(MonitorCamera()) self.add_thing(MassageChair()) @@ -173,6 +174,7 @@ class Stethoscope(Item): "Used for cracking safes. Found on the doctor on the chair" + NAME = 'stethoscope' INVENTORY_IMAGE = 'stethoscope.png' CURSOR = CursorSprite('stethoscope.png') @@ -203,6 +205,7 @@ class TapedSuperconductor(Item): "Used for connecting high-powered parts of the ship up" + NAME = 'taped_superconductor' INVENTORY_IMAGE = 'superconductor_taped.png' CURSOR = CursorSprite('superconductor_taped_cursor.png') @@ -210,13 +213,12 @@ class Superconductor(Item): "Used for connecting high-powered parts of the ship up" + NAME = 'superconductor' INVENTORY_IMAGE = 'superconductor_fixed.png' CURSOR = CursorSprite('superconductor_fixed.png') def interact_with_duct_tape(self, item): - taped_superconductor = TapedSuperconductor('taped_superconductor') - self.game.add_item(taped_superconductor) - self.game.replace_inventory_item(self.name, taped_superconductor.name) + self.game.replace_inventory_item(self.name, 'taped_superconductor') return Result(_("You rip off a piece of duct tape and stick it on the" " superconductor. It almost sticks to itself, but you" " successfully avoid disaster.")) diff -r 8f94fbf05ab9 -r eed75a1d50c4 gamelib/scenes/crew_quarters.py --- a/gamelib/scenes/crew_quarters.py Sun Jan 27 22:09:34 2013 +0200 +++ b/gamelib/scenes/crew_quarters.py Sun Jan 27 22:19:39 2013 +0200 @@ -22,9 +22,10 @@ self.add_thing(ToMap()) self.add_thing(Safe()) self.add_thing(FishbowlThing()) - self.add_item(Fishbowl('fishbowl')) - self.add_item(DuctTape('duct_tape')) - self.add_item(EscherPoster('escher_poster')) + self.add_item_factory(Fishbowl) + self.add_item_factory(DuctTape) + self.add_item_factory(EscherPoster) + self.add_item_factory(FishbowlHelmet) self.add_thing(PosterThing()) self.add_thing(MonitorCamera()) self.add_thing(GenericDescThing('crew.plant', 1, @@ -154,9 +155,7 @@ NAME = "fishbowl" def interact_with_duct_tape(self, item): - helmet = FishbowlHelmet('helmet') - self.game.add_item(helmet) - self.game.replace_inventory_item(self.name, helmet.name) + self.game.replace_inventory_item(self.name, 'helmet') return Result(_("You duct tape the edges of the helmet. The seal is" " crude, but it will serve as a workable helmet if" " needed.")) @@ -173,6 +172,7 @@ class DuctTape(Item): "A bowl. Sans fish." + NAME = 'duct_tape' INVENTORY_IMAGE = 'duct_tape.png' CURSOR = CursorSprite('duct_tape.png') diff -r 8f94fbf05ab9 -r eed75a1d50c4 gamelib/scenes/cryo.py --- a/gamelib/scenes/cryo.py Sun Jan 27 22:09:34 2013 +0200 +++ b/gamelib/scenes/cryo.py Sun Jan 27 22:19:39 2013 +0200 @@ -34,7 +34,9 @@ ] def setup(self): - self.add_item(TitaniumLeg("titanium_leg")) + self.add_item_factory(TitaniumLeg) + self.add_item_factory(TubeFragment) + self.add_item_factory(FullBottle) self.add_thing(CryoUnitAlpha()) self.add_thing(CryoRoomDoor()) self.add_thing(CryoComputer()) @@ -165,9 +167,7 @@ def interact_with_machete(self, item): if self.get_data('fixed'): self.set_data('fixed', False) - pipe = TubeFragment('tube_fragment') - self.game.add_item(pipe) - self.game.add_inventory_item(pipe.name) + self.game.add_inventory_item('tube_fragment') self.set_interact() responses = [Result(_("It takes more effort than one would expect," " but eventually the pipe is separated from" @@ -226,9 +226,11 @@ class TubeFragment(CloneableItem): "Obtained after cutting down a cryo room pipe." + NAME = "tube_fragment" INVENTORY_IMAGE = "tube_fragment.png" CURSOR = CursorSprite('tube_fragment_cursor.png') TOOL_NAME = "tube_fragment" + MAX_COUNT = 3 class CryoPipeLeft(CryoPipeBase): @@ -264,6 +266,7 @@ class TitaniumLeg(Item): "Titanium leg, found on a piratical corpse." + NAME = 'titanium_leg' INVENTORY_IMAGE = "titanium_femur.png" CURSOR = CursorSprite('titanium_femur_cursor.png', 13, 5) @@ -463,6 +466,7 @@ class FullBottle(Item): + NAME = 'full_detergent_bottle' INVENTORY_IMAGE = 'bottle_full.png' CURSOR = CursorSprite('bottle_full_cursor.png', 27, 7) @@ -489,9 +493,7 @@ return Result(_("It's gooey")) def interact_with_detergent_bottle(self, item): - full = FullBottle('full_detergent_bottle') - self.game.add_item(full) - self.game.replace_inventory_item(item.name, full.name) + self.game.replace_inventory_item(item.name, 'full_detergent_bottle') return Result(_("You scoop up some coolant and fill the bottle.")) diff -r 8f94fbf05ab9 -r eed75a1d50c4 gamelib/scenes/engine.py --- a/gamelib/scenes/engine.py Sun Jan 27 22:09:34 2013 +0200 +++ b/gamelib/scenes/engine.py Sun Jan 27 22:19:39 2013 +0200 @@ -22,7 +22,7 @@ } def setup(self): - self.add_item(CanOpener('canopener')) + self.add_item_factory(CanOpener) self.add_thing(CanOpenerThing()) self.add_thing(SuperconductorSocket()) self.add_thing(PowerLines()) @@ -160,6 +160,7 @@ class CanOpener(Item): + NAME = 'canopener' INVENTORY_IMAGE = 'can_opener.png' CURSOR = CursorSprite('can_opener_cursor.png') diff -r 8f94fbf05ab9 -r eed75a1d50c4 gamelib/scenes/machine.py --- a/gamelib/scenes/machine.py Sun Jan 27 22:09:34 2013 +0200 +++ b/gamelib/scenes/machine.py Sun Jan 27 22:19:39 2013 +0200 @@ -22,11 +22,11 @@ self.add_thing(LaserWelderPowerLights()) self.add_thing(Grinder()) self.add_thing(ManualThing()) - self.add_item(TitaniumMachete('machete')) - self.add_item(CryoPipesOne('cryo_pipes_one')) - self.add_item(CryoPipesTwo('cryo_pipes_two')) - self.add_item(CryoPipesThree('cryo_pipes_three')) - self.add_item(Manual('manual')) + self.add_item_factory(TitaniumMachete) + self.add_item_factory(CryoPipesOne) + self.add_item_factory(CryoPipesTwo) + self.add_item_factory(CryoPipesThree) + self.add_item_factory(Manual) self.add_thing(GenericDescThing('machine.wires', 2, _("Wires run to all the machines in the room"), ( @@ -181,19 +181,19 @@ else: welder_slot.set_data("contents", []) welder_slot.set_interact() - if self.game.is_in_inventory("cryo_pipes_one"): - self.game.replace_inventory_item("cryo_pipes_one", + if self.game.is_in_inventory("cryo_pipes_one:"): + self.game.replace_inventory_item("cryo_pipes_one:", "cryo_pipes_two") return Result(_("With high-precision spitzensparken, you weld" " together a second pipe. You bundle the two" " pipes together."), soundfile='laser.ogg') - elif self.game.is_in_inventory("cryo_pipes_two"): - self.game.replace_inventory_item("cryo_pipes_two", + elif self.game.is_in_inventory("cryo_pipes_two:"): + self.game.replace_inventory_item("cryo_pipes_two:", "cryo_pipes_three") return Result(_("With high-precision spitzensparken, you" " create yet another pipe. You store it with" " the other two."), soundfile='laser.ogg') - elif self.game.is_in_inventory("cryo_pipes_three"): + elif self.game.is_in_inventory("cryo_pipes_three:"): # just for safety return None else: @@ -223,6 +223,7 @@ class CryoPipesOne(Item): "A single cryo pipe (made from a tube fragment and can)." + NAME = 'cryo_pipes_one' INVENTORY_IMAGE = "cryo_pipes_one.png" CURSOR = CursorSprite('cryo_pipes_one_cursor.png') TOOL_NAME = "cryo_pipes_one" @@ -231,6 +232,7 @@ class CryoPipesTwo(Item): "Two cryo pipes (each made from a tube fragment and can)." + NAME = 'cryo_pipes_two' INVENTORY_IMAGE = "cryo_pipes_two.png" CURSOR = CursorSprite('cryo_pipes_two_cursor.png') TOOL_NAME = "cryo_pipes_two" @@ -239,6 +241,7 @@ class CryoPipesThree(Item): "Three cryo pipes (each made from a tube fragment and can)." + NAME = 'cryo_pipes_three' INVENTORY_IMAGE = "cryo_pipes_three.png" CURSOR = CursorSprite('cryo_pipes_three_cursor.png') TOOL_NAME = "cryo_pipes_three" @@ -273,6 +276,7 @@ class TitaniumMachete(Item): "Titanium machete, formerly a leg." + NAME = 'machete' INVENTORY_IMAGE = "machete.png" CURSOR = CursorSprite('machete_cursor.png', 23, 1) @@ -298,6 +302,7 @@ class Manual(Item): "A ship instruction manual." + NAME = 'manual' INVENTORY_IMAGE = "manual.png" CURSOR = None diff -r 8f94fbf05ab9 -r eed75a1d50c4 gamelib/scenes/map.py --- a/gamelib/scenes/map.py Sun Jan 27 22:09:34 2013 +0200 +++ b/gamelib/scenes/map.py Sun Jan 27 22:19:39 2013 +0200 @@ -125,7 +125,7 @@ INITIAL = 'door' def interact(self, item): - if not self.game.is_in_inventory('helmet'): + if not self.game.is_in_inventory('helmet:'): return Result(_('The airlock refuses to open. The automated' ' voice says: "Hull breach beyond this door. Personnel' ' must be equipped for vacuum before entry."')) diff -r 8f94fbf05ab9 -r eed75a1d50c4 gamelib/scenes/mess.py --- a/gamelib/scenes/mess.py Sun Jan 27 22:09:34 2013 +0200 +++ b/gamelib/scenes/mess.py Sun Jan 27 22:19:39 2013 +0200 @@ -28,7 +28,10 @@ self.add_thing(ToMap()) self.add_thing(DetergentThing()) self.add_thing(Boomslang()) - self.add_item(DetergentBottle('detergent_bottle')) + self.add_item_factory(DetergentBottle) + self.add_item_factory(EmptyCan) + self.add_item_factory(FullCan) + self.add_item_factory(DentedCan) # Flavour items # extra cans on shelf self.add_thing(GenericDescThing('mess.cans', 1, @@ -48,6 +51,8 @@ class BaseCan(CloneableItem): """Base class for the cans""" + MAX_COUNT = 3 + def interact_with_full_can(self, item): return Result(_("You bang the cans together. It sounds like two" " cans being banged together."), @@ -63,9 +68,7 @@ return Result(_("You'd mangle it beyond usefulness.")) def interact_with_canopener(self, item): - empty = EmptyCan('empty_can') - self.game.add_item(empty) - self.game.replace_inventory_item(self.name, empty.name) + self.game.replace_inventory_item(self.name, 'empty_can') return Result(_("You open both ends of the can, discarding the" " hideous contents.")) @@ -73,6 +76,7 @@ class EmptyCan(BaseCan): "After emptying the full can." + NAME = 'empty_can' INVENTORY_IMAGE = "empty_can.png" CURSOR = CursorSprite('empty_can_cursor.png') @@ -87,13 +91,12 @@ class FullCan(BaseCan): "Found on the shelf." + NAME = 'full_can' INVENTORY_IMAGE = "full_can.png" CURSOR = CursorSprite('full_can_cursor.png') def interact_with_titanium_leg(self, item): - dented = DentedCan("dented_can") - self.game.add_item(dented) - self.game.replace_inventory_item(self.name, dented.name) + self.game.replace_inventory_item(self.name, 'dented_can') return Result(_("You club the can with the femur. The can gets dented," " but doesn't open."), soundfile="can_hit.ogg") @@ -101,6 +104,7 @@ class DentedCan(BaseCan): "A can banged on with the femur" + NAME = 'dented_can' INVENTORY_IMAGE = "dented_can.png" CURSOR = CursorSprite('dented_can_cursor.png') @@ -136,9 +140,7 @@ def interact_without(self): starting_cans = self.get_data('cans_available') if starting_cans > 0: - can = FullCan("full_can") - self.game.add_item(can) - self.game.add_inventory_item(can.name) + self.game.add_inventory_item('full_can') self.set_data('cans_available', starting_cans - 1) self.set_interact() if starting_cans == 1: @@ -324,6 +326,7 @@ class DetergentBottle(Item): + NAME = 'detergent_bottle' INVENTORY_IMAGE = 'bottle_empty.png' CURSOR = CursorSprite('bottle_empty_cursor.png', 27, 7) diff -r 8f94fbf05ab9 -r eed75a1d50c4 gamelib/tests/test_scene_interactions_cryo.py --- a/gamelib/tests/test_scene_interactions_cryo.py Sun Jan 27 22:09:34 2013 +0200 +++ b/gamelib/tests/test_scene_interactions_cryo.py Sun Jan 27 22:19:39 2013 +0200 @@ -23,10 +23,10 @@ self.state.add_inventory_item('titanium_leg') self.assert_game_data('door', 'shut', 'cryo.door') - self.interact_thing('cryo.door', 'titanium_leg') + self.interact_thing('cryo.door', 'titanium_leg:') self.assert_game_data('door', 'shut', 'cryo.door') - self.assert_inventory_item('titanium_leg', True) + self.assert_inventory_item('titanium_leg:', True) def test_cryo_door_ajar_hand(self): "The door is ajar and we touch it with the hand. No change." @@ -43,10 +43,10 @@ self.state.add_inventory_item('titanium_leg') self.set_game_data('door', 'ajar', 'cryo.door') - self.interact_thing('cryo.door', 'titanium_leg') + self.interact_thing('cryo.door', 'titanium_leg:') self.assert_game_data('door', 'open', 'cryo.door') - self.assert_inventory_item('titanium_leg', True) + self.assert_inventory_item('titanium_leg:', True) def test_cryo_door_open_hand(self): "The door is open and we touch it with the hand. We go to the map." @@ -64,7 +64,7 @@ self.state.add_inventory_item('titanium_leg') self.set_game_data('door', 'open', 'cryo.door') - self.interact_thing('cryo.door', 'titanium_leg') + self.interact_thing('cryo.door', 'titanium_leg:') self.assert_game_data('door', 'open', 'cryo.door') self.assert_current_scene('cryo') @@ -74,12 +74,12 @@ self.interact_thing('cryo.unit.1') self.assert_game_data('contains_titanium_leg', True, 'cryo.unit.1') - self.assert_inventory_item('titanium_leg', False) + self.assert_inventory_item('titanium_leg:', False) self.assert_detail_thing('cryo.titanium_leg', True) self.interact_thing('cryo.titanium_leg', detail='cryo_detail') - self.assert_inventory_item('titanium_leg', True) + self.assert_inventory_item('titanium_leg:', True) self.assert_detail_thing('cryo.titanium_leg', False) self.assert_game_data('contains_titanium_leg', False, 'cryo.unit.1') @@ -128,26 +128,26 @@ self.assert_game_data('fixed', True, 'cryo.pipe.left') self.assert_game_data('fixed', True, 'cryo.pipe.right.top') self.assert_game_data('fixed', True, 'cryo.pipe.right.bottom') - self.assert_item_exists('cryo_pipe.0', False) - self.assert_item_exists('cryo_pipe.1', False) - self.assert_item_exists('cryo_pipe.2', False) + self.assert_item_exists('cryo_pipe:0', False) + self.assert_item_exists('cryo_pipe:1', False) + self.assert_item_exists('cryo_pipe:2', False) self.assertNotEquals( - None, self.interact_thing('cryo.pipe.left', 'machete')) + None, self.interact_thing('cryo.pipe.left', 'machete:')) self.assertNotEquals( - None, self.interact_thing('cryo.pipe.right.top', 'machete')) + None, self.interact_thing('cryo.pipe.right.top', 'machete:')) self.assertNotEquals( - None, self.interact_thing('cryo.pipe.right.bottom', 'machete')) + None, self.interact_thing('cryo.pipe.right.bottom', 'machete:')) self.assert_game_data('fixed', False, 'cryo.pipe.left') self.assert_game_data('fixed', False, 'cryo.pipe.right.top') self.assert_game_data('fixed', False, 'cryo.pipe.right.bottom') - self.assert_item_exists('tube_fragment.0') - self.assert_item_exists('tube_fragment.1') - self.assert_item_exists('tube_fragment.2') - self.assert_inventory_item('tube_fragment.0', True) - self.assert_inventory_item('tube_fragment.1', True) - self.assert_inventory_item('tube_fragment.2', True) + self.assert_item_exists('tube_fragment:0') + self.assert_item_exists('tube_fragment:1') + self.assert_item_exists('tube_fragment:2') + self.assert_inventory_item('tube_fragment:0', True) + self.assert_inventory_item('tube_fragment:1', True) + self.assert_inventory_item('tube_fragment:2', True) def test_pipes_chopped_machete(self): "Touch the chopped cryopipes with the machete. No change." @@ -158,11 +158,11 @@ self.set_game_data('fixed', False, 'cryo.pipe.right.bottom') self.assertEquals( - None, self.interact_thing('cryo.pipe.left', 'machete')) + None, self.interact_thing('cryo.pipe.left', 'machete:')) self.assertEquals( - None, self.interact_thing('cryo.pipe.right.top', 'machete')) + None, self.interact_thing('cryo.pipe.right.top', 'machete:')) self.assertEquals( - None, self.interact_thing('cryo.pipe.right.bottom', 'machete')) + None, self.interact_thing('cryo.pipe.right.bottom', 'machete:')) self.assert_game_data('fixed', False, 'cryo.pipe.left') self.assert_game_data('fixed', False, 'cryo.pipe.right.top') diff -r 8f94fbf05ab9 -r eed75a1d50c4 gamelib/tests/test_walkthrough.py --- a/gamelib/tests/test_walkthrough.py Sun Jan 27 22:09:34 2013 +0200 +++ b/gamelib/tests/test_walkthrough.py Sun Jan 27 22:19:39 2013 +0200 @@ -31,13 +31,13 @@ self.assert_detail_thing('cryo.titanium_leg') self.interact_thing('cryo.titanium_leg', detail='cryo_detail') self.assert_detail_thing('cryo.titanium_leg', False) - self.assert_inventory_item('titanium_leg') + self.assert_inventory_item('titanium_leg:') self.close_detail() # Open the door the rest of the way. - self.interact_thing('cryo.door', 'titanium_leg') + self.interact_thing('cryo.door', 'titanium_leg:') self.assert_game_data('door', 'open', 'cryo.door') - self.assert_inventory_item('titanium_leg') + self.assert_inventory_item('titanium_leg:') # Go to the mess. self.move_to('mess') @@ -48,54 +48,54 @@ # Get the cans. self.assert_game_data('cans_available', 3, 'mess.cans') self.interact_thing('mess.cans') - self.assert_inventory_item('full_can.0') + self.assert_inventory_item('full_can:0') self.assert_game_data('cans_available', 2, 'mess.cans') self.interact_thing('mess.cans') - self.assert_inventory_item('full_can.1') + self.assert_inventory_item('full_can:1') self.assert_game_data('cans_available', 1, 'mess.cans') self.interact_thing('mess.cans') - self.assert_inventory_item('full_can.2') + self.assert_inventory_item('full_can:2') self.assert_scene_thing('mess.cans', False) # Bash one of the cans. - self.assert_item_exists('dented_can.0', False) - self.interact_item('full_can.1', 'titanium_leg') - self.assert_inventory_item('dented_can.0') - self.assert_inventory_item('full_can.1', False) + self.assert_item_exists('dented_can:0', False) + self.interact_item('full_can:1', 'titanium_leg:') + self.assert_inventory_item('dented_can:0') + self.assert_inventory_item('full_can:1', False) # Go to the machine room. self.move_to('machine') # Sharpen leg into machete. - self.interact_thing('machine.grinder', 'titanium_leg') + self.interact_thing('machine.grinder', 'titanium_leg:') self.assert_inventory_item('titanium_leg', False) - self.assert_inventory_item('machete') + self.assert_inventory_item('machete:') # Go to the cryo room. self.move_to('cryo') # Chop up some pipes. self.assert_game_data('fixed', True, 'cryo.pipe.left') - self.interact_thing('cryo.pipe.left', 'machete') + self.interact_thing('cryo.pipe.left', 'machete:') self.assert_game_data('fixed', False, 'cryo.pipe.left') - self.assert_inventory_item('tube_fragment.0') + self.assert_inventory_item('tube_fragment:0') self.assert_game_data('fixed', True, 'cryo.pipe.right.top') - self.interact_thing('cryo.pipe.right.top', 'machete') + self.interact_thing('cryo.pipe.right.top', 'machete:') self.assert_game_data('fixed', False, 'cryo.pipe.right.top') - self.assert_inventory_item('tube_fragment.1') + self.assert_inventory_item('tube_fragment:1') self.assert_game_data('fixed', True, 'cryo.pipe.right.bottom') - self.interact_thing('cryo.pipe.right.bottom', 'machete') + self.interact_thing('cryo.pipe.right.bottom', 'machete:') self.assert_game_data('fixed', False, 'cryo.pipe.right.bottom') - self.assert_inventory_item('tube_fragment.2') + self.assert_inventory_item('tube_fragment:2') # Go to the mess. self.move_to('mess') # Clear the broccoli. self.assert_game_data('status', 'blocked', 'mess.tubes') - self.interact_thing('mess.tubes', 'machete') + self.interact_thing('mess.tubes', 'machete:') self.assert_game_data('status', 'broken', 'mess.tubes') # Go to the bridge. @@ -106,13 +106,13 @@ # Get the stethoscope. self.interact_thing('bridge.stethoscope') - self.assert_inventory_item('stethoscope') + self.assert_inventory_item('stethoscope:') self.assert_scene_thing('bridge.stethoscope', False) # Get the superconductor. self.interact_thing('bridge.massagechair_base') self.interact_thing('bridge.superconductor', detail='chair_detail') - self.assert_inventory_item('superconductor') + self.assert_inventory_item('superconductor:') self.assert_detail_thing('bridge.superconductor', False) self.close_detail() @@ -121,29 +121,29 @@ # Get the poster. self.interact_thing('crew.poster') - self.assert_inventory_item('escher_poster') + self.assert_inventory_item('escher_poster:') self.assert_scene_thing('crew.poster', False) # Get the fishbowl. self.assert_game_data('has_bowl', True, 'crew.fishbowl') self.interact_thing('crew.fishbowl') self.assert_game_data('has_bowl', False, 'crew.fishbowl') - self.assert_inventory_item('fishbowl') + self.assert_inventory_item('fishbowl:') # Crack the safe. self.assert_game_data('is_cracked', False, 'crew.safe') - self.interact_thing('crew.safe', 'stethoscope') + self.interact_thing('crew.safe', 'stethoscope:') self.assert_game_data('is_cracked', True, 'crew.safe') # Get the duct tape. self.assert_game_data('has_tape', True, 'crew.safe') self.interact_thing('crew.safe') self.assert_game_data('has_tape', False, 'crew.safe') - self.assert_inventory_item('duct_tape') + self.assert_inventory_item('duct_tape:') # Make the helmet. - self.interact_item('fishbowl', 'duct_tape') - self.assert_inventory_item('helmet') + self.interact_item('fishbowl:', 'duct_tape:') + self.assert_inventory_item('helmet:') self.assert_inventory_item('fishbowl', False) # Go to the engine room. @@ -154,69 +154,69 @@ # Get the can opener. self.interact_thing('engine.canopener') - self.assert_inventory_item('canopener') + self.assert_inventory_item('canopener:') self.assert_scene_thing('engine.canopener', False) # Open the cans. - self.interact_item('full_can.2', 'canopener') - self.assert_inventory_item('full_can.2', False) - self.assert_inventory_item('empty_can.0') + self.interact_item('full_can:2', 'canopener:') + self.assert_inventory_item('full_can:2', False) + self.assert_inventory_item('empty_can:0') - self.interact_item('full_can.0', 'canopener') - self.assert_inventory_item('full_can.0', False) - self.assert_inventory_item('empty_can.1') + self.interact_item('full_can:0', 'canopener:') + self.assert_inventory_item('full_can:0', False) + self.assert_inventory_item('empty_can:1') - self.interact_item('dented_can.0', 'canopener') - self.assert_inventory_item('dented_can.0', False) - self.assert_inventory_item('empty_can.2') + self.interact_item('dented_can:0', 'canopener:') + self.assert_inventory_item('dented_can:0', False) + self.assert_inventory_item('empty_can:2') # Go to the machine room. self.move_to('machine') # Weld pipes and cans. self.assert_game_data('contents', [], 'machine.welder.slot') - self.interact_thing('machine.welder.slot', 'tube_fragment.0') - self.assert_inventory_item('tube_fragment.0', False) + self.interact_thing('machine.welder.slot', 'tube_fragment:0') + self.assert_inventory_item('tube_fragment:0', False) self.assert_game_data('contents', ['tube'], 'machine.welder.slot') - self.interact_thing('machine.welder.slot', 'empty_can.1') - self.assert_inventory_item('empty_can.1', False) + self.interact_thing('machine.welder.slot', 'empty_can:1') + self.assert_inventory_item('empty_can:1', False) self.assert_game_data( 'contents', ['tube', 'can'], 'machine.welder.slot') self.interact_thing('machine.welder.button') self.assert_game_data('contents', [], 'machine.welder.slot') - self.assert_inventory_item('cryo_pipes_one') + self.assert_inventory_item('cryo_pipes_one:') self.assert_game_data('contents', [], 'machine.welder.slot') - self.interact_thing('machine.welder.slot', 'tube_fragment.2') - self.assert_inventory_item('tube_fragment.2', False) + self.interact_thing('machine.welder.slot', 'tube_fragment:2') + self.assert_inventory_item('tube_fragment:2', False) self.assert_game_data('contents', ['tube'], 'machine.welder.slot') - self.interact_thing('machine.welder.slot', 'empty_can.2') - self.assert_inventory_item('empty_can.2', False) + self.interact_thing('machine.welder.slot', 'empty_can:2') + self.assert_inventory_item('empty_can:2', False) self.assert_game_data( 'contents', ['tube', 'can'], 'machine.welder.slot') self.interact_thing('machine.welder.button') self.assert_game_data('contents', [], 'machine.welder.slot') self.assert_inventory_item('cryo_pipes_one', False) - self.assert_inventory_item('cryo_pipes_two') + self.assert_inventory_item('cryo_pipes_two:') self.assert_game_data('contents', [], 'machine.welder.slot') - self.interact_thing('machine.welder.slot', 'tube_fragment.1') - self.assert_inventory_item('tube_fragment.1', False) + self.interact_thing('machine.welder.slot', 'tube_fragment:1') + self.assert_inventory_item('tube_fragment:1', False) self.assert_game_data('contents', ['tube'], 'machine.welder.slot') - self.interact_thing('machine.welder.slot', 'empty_can.0') - self.assert_inventory_item('empty_can.0', False) + self.interact_thing('machine.welder.slot', 'empty_can:0') + self.assert_inventory_item('empty_can:0', False) self.assert_game_data( 'contents', ['tube', 'can'], 'machine.welder.slot') self.interact_thing('machine.welder.button') self.assert_game_data('contents', [], 'machine.welder.slot') self.assert_inventory_item('cryo_pipes_two', False) - self.assert_inventory_item('cryo_pipes_three') + self.assert_inventory_item('cryo_pipes_three:') # Go to the mess. self.move_to('mess') # Replace the tubes. - self.interact_thing('mess.tubes', 'cryo_pipes_three') + self.interact_thing('mess.tubes', 'cryo_pipes_three:') self.assert_inventory_item('cryo_pipes_three', False) self.assert_game_data('status', 'replaced', 'mess.tubes') @@ -224,7 +224,7 @@ self.assert_game_data('life support status', 'replaced') # Tape up the tubes. - self.interact_thing('mess.tubes', 'duct_tape') + self.interact_thing('mess.tubes', 'duct_tape:') self.assert_game_data('status', 'fixed', 'mess.tubes') # Check that life support is fixed @@ -232,45 +232,45 @@ # Get the detergent bottle. self.interact_thing('mess.detergent') - self.assert_inventory_item('detergent_bottle') + self.assert_inventory_item('detergent_bottle:') # Go to the cryo room. self.move_to('cryo') # Fill the detergent bottle. - self.interact_thing('cryo.pool', 'detergent_bottle') + self.interact_thing('cryo.pool', 'detergent_bottle:') self.assert_inventory_item('detergent_bottle', False) - self.assert_inventory_item('full_detergent_bottle') + self.assert_inventory_item('full_detergent_bottle:') # Go to the engine room. self.move_to('engine') # Patch the cracked pipe. self.assert_game_data('fixed', False, 'engine.cracked_pipe') - self.interact_thing('engine.cracked_pipe', 'duct_tape') + self.interact_thing('engine.cracked_pipe', 'duct_tape:') self.assert_game_data('fixed', True, 'engine.cracked_pipe') # Fill the cryofluid receptacles. self.assert_game_data('filled', False, 'engine.cryo_containers') self.interact_thing( - 'engine.cryo_container_receptacle', 'full_detergent_bottle') + 'engine.cryo_container_receptacle', 'full_detergent_bottle:') self.assert_game_data('filled', True, 'engine.cryo_containers') self.assert_inventory_item('full_detergent_bottle', False) # Remove the burned-out superconductor. self.assert_game_data('present', True, 'engine.superconductor') self.assert_game_data('working', False, 'engine.superconductor') - self.interact_thing('engine.superconductor', 'machete') + self.interact_thing('engine.superconductor', 'machete:') self.assert_game_data('present', False, 'engine.superconductor') self.assert_game_data('working', False, 'engine.superconductor') # Tape up new superconductor. - self.interact_item('superconductor', 'duct_tape') + self.interact_item('superconductor:', 'duct_tape:') self.assert_inventory_item('superconductor', False) - self.assert_inventory_item('taped_superconductor') + self.assert_inventory_item('taped_superconductor:') # Install superconductor. - self.interact_thing('engine.superconductor', 'taped_superconductor') + self.interact_thing('engine.superconductor', 'taped_superconductor:') self.assert_inventory_item('taped_superconductor', False) self.assert_game_data('present', True, 'engine.superconductor') self.assert_game_data('working', True, 'engine.superconductor') @@ -282,16 +282,16 @@ self.move_to('bridge') # Show JIM the poster. - self.interact_thing('bridge.camera', 'escher_poster') + self.interact_thing('bridge.camera', 'escher_poster:') self.assert_game_data('ai status', 'looping') # Get at JIM. self.assert_game_data('ai panel', 'closed') - self.interact_thing('jim_panel', 'machete') + self.interact_thing('jim_panel', 'machete:') self.assert_game_data('ai panel', 'open') # Break JIM. - self.interact_thing('jim_panel', 'machete') + self.interact_thing('jim_panel', 'machete:') self.assert_game_data('ai panel', 'broken') # Check that we've turned off JIM. diff -r 8f94fbf05ab9 -r eed75a1d50c4 pyntnclick/gamescreen.py --- a/pyntnclick/gamescreen.py Sun Jan 27 22:09:34 2013 +0200 +++ b/pyntnclick/gamescreen.py Sun Jan 27 22:19:39 2013 +0200 @@ -124,7 +124,7 @@ @property def slot_items(self): item_names = self.game.inventory()[self.inv_offset:][:len(self.slots)] - return [self.game.items[name] for name in item_names] + return [self.game.get_item(name) for name in item_names] def mouse_down(self, event, widget): if event.button != 1: diff -r 8f94fbf05ab9 -r eed75a1d50c4 pyntnclick/state.py --- a/pyntnclick/state.py Sun Jan 27 22:09:34 2013 +0200 +++ b/pyntnclick/state.py Sun Jan 27 22:19:39 2013 +0200 @@ -49,7 +49,11 @@ def __init__(self, state_dict=None): if state_dict is None: - state_dict = {'inventories': {'main': []}, 'current_scene': None} + state_dict = { + 'inventories': {'main': []}, + 'item_factories': {}, + 'current_scene': None, + } self._game_state = copy.deepcopy(state_dict) def __getitem__(self, key): @@ -61,10 +65,6 @@ def export_data(self): return copy.deepcopy(self._game_state) - 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) @@ -73,14 +73,18 @@ """Set a single value""" self[state_key][data_key] = value + def _initialize_state(self, state_dict, state_key, initial_data): + if state_key not in self._game_state: + state_dict[state_key] = copy.deepcopy(initial_data) + def initialize_state(self, state_key, initial_data): """Initialize a gizmo entry""" - if state_key not in self._game_state: - self._game_state[state_key] = {} - if initial_data: - # deep copy of INITIAL_DATA allows lists, dicts and other - # mutable types to safely be used in INITIAL_DATA - self._game_state[state_key].update(copy.deepcopy(initial_data)) + self._initialize_state(self._game_state, state_key, initial_data) + + def initialize_item_factory_state(self, state_key, initial_data): + """Initialize an item factory entry""" + self._initialize_state( + self._game_state['item_factories'], state_key, initial_data) def inventory(self, name='main'): return self['inventories'][name] @@ -125,8 +129,8 @@ self.scenes = {} # map of detail view name -> DetailView object self.detail_views = {} - # map of item name -> Item object - self.items = {} + # map of item prefix -> ItemFactory object + self.item_factories = {} # list of item objects in inventory self.current_inventory = 'main' # currently selected tool (item) @@ -142,6 +146,16 @@ return self.scenes[scene_name] return None + def get_item(self, item_name): + base_name, _, _suffix = item_name.partition(':') + factory = self.item_factories[base_name] + return factory.get_item(item_name) + + def create_item(self, base_name): + assert ":" not in base_name + factory = self.item_factories[base_name] + return factory.create_item() + def inventory(self, name=None): if name is None: name = self.current_inventory @@ -161,9 +175,13 @@ detail_view.set_game(self) self.detail_views[detail_view.name] = detail_view - def add_item(self, item): - item.set_game(self) - self.items[item.name] = item + def add_item_factory(self, item_class): + name = item_class.NAME + assert name not in self.item_factories, ( + "Factory for %s already added." % (name,)) + factory = item_class.ITEM_FACTORY(item_class) + factory.set_game(self) + self.item_factories[name] = factory def load_scenes(self, modname): mod = __import__('%s.%s' % (self.gd.SCENE_MODULE, modname), @@ -187,8 +205,9 @@ def _update_inventory(self): ScreenEvent.post('game', 'inventory', None) - def add_inventory_item(self, name): - self.inventory().append(name) + def add_inventory_item(self, item_name): + item = self.create_item(item_name) + self.inventory().append(item.name) self._update_inventory() def is_in_inventory(self, name): @@ -197,7 +216,7 @@ def remove_inventory_item(self, name): self.inventory().remove(name) # Unselect tool if it's removed - if self.tool == self.items[name]: + if self.tool == self.get_item(name): self.set_tool(None) self._update_inventory() @@ -205,9 +224,10 @@ """Try to replace an item in the inventory with a new one""" try: index = self.inventory().index(old_item_name) - self.inventory()[index] = new_item_name - if self.tool == self.items[old_item_name]: - self.set_tool(self.items[new_item_name]) + new_item = self.create_item(new_item_name) + self.inventory()[index] = new_item.name + if self.tool == self.get_item(old_item_name): + self.set_tool(new_item) except ValueError: return False self._update_inventory() @@ -302,8 +322,8 @@ self.current_thing = None self._background = None - def add_item(self, item): - self.game.add_item(item) + def add_item_factory(self, item_factory): + self.game.add_item_factory(item_factory) def add_thing(self, thing): thing.set_game(self.game) @@ -546,13 +566,48 @@ rect.inflate(1, 1), 1) +class ItemFactory(StatefulGizmo): + INITIAL_DATA = { + 'created': [], + } + + def __init__(self, item_class): + super(ItemFactory, self).__init__() + self.item_class = item_class + assert self.item_class.NAME is not None, ( + "%s has no NAME set" % (self.item_class,)) + self.state_key = self.item_class.NAME + '_factory' + self.items = {} + + def get_item(self, item_name): + assert item_name in self.get_data('created'), ( + "Object %s has not been created" % (item_name,)) + if item_name not in self.items: + item = self.item_class(item_name) + item.set_game(self.game) + self.items[item_name] = item + return self.items[item_name] + + def get_item_suffix(self): + return '' + + def create_item(self): + item_name = '%s:%s' % (self.item_class.NAME, self.get_item_suffix()) + created_list = self.get_data('created') + assert item_name not in created_list, ( + "Already created object %s" % (item_name,)) + created_list.append(item_name) + self.set_data('created', created_list) + return self.get_item(item_name) + + class Item(GameDeveloperGizmo, InteractiveMixin): """Base class for inventory items.""" # image for inventory INVENTORY_IMAGE = None - # name of item + # Base name of item NAME = None # name for interactions (i.e. def interact_with_) @@ -561,12 +616,14 @@ # set to instance of CursorSprite CURSOR = None + ITEM_FACTORY = ItemFactory + def __init__(self, name=None): GameDeveloperGizmo.__init__(self) self.name = self.NAME if name is not None: self.name = name - self.tool_name = name + self.tool_name = self.NAME if self.TOOL_NAME is not None: self.tool_name = self.TOOL_NAME self.inventory_image = None @@ -589,15 +646,15 @@ return False -class CloneableItem(Item): - _counter = 0 +class ClonableItemFactory(ItemFactory): + def get_item_suffix(self): + # Works as long as we never remove anything from our 'created' list. + count = len(self.get_data('created')) + assert self.item_class.MAX_COUNT is not None + assert count <= self.item_class.MAX_COUNT + return str(count) - @classmethod - def _get_new_id(cls): - cls._counter += 1 - return cls._counter - 1 - def __init__(self, name=None): - super(CloneableItem, self).__init__(name) - my_count = self._get_new_id() - self.name = "%s.%s" % (self.name, my_count) +class CloneableItem(Item): + ITEM_FACTORY = ClonableItemFactory + MAX_COUNT = None diff -r 8f94fbf05ab9 -r eed75a1d50c4 pyntnclick/tests/game_logic_utils.py --- a/pyntnclick/tests/game_logic_utils.py Sun Jan 27 22:09:34 2013 +0200 +++ b/pyntnclick/tests/game_logic_utils.py Sun Jan 27 22:19:39 2013 +0200 @@ -37,11 +37,6 @@ self.scene_stack.pop() self.assertTrue(len(self.scene_stack) > 0) - def tearDown(self): - for item in self.state.items.values(): - if isinstance(item, pyntnclick.state.CloneableItem): - type(item)._counter = 0 - def clear_event_queue(self): # Since we aren't handling events, we may overflow the pygame # event buffer if we're generating a lot of events @@ -80,7 +75,11 @@ self.assertEquals(in_detail, thing in self.scene_stack[-1].things) def assert_item_exists(self, item, exists=True): - self.assertEquals(exists, item in self.state.items) + try: + self.state.get_item(item) + self.assertTrue(exists) + except: + self.assertFalse(exists) def assert_current_scene(self, scene): self.assertEquals(scene, self.state.get_current_scene().name) @@ -99,7 +98,7 @@ item_obj = None if item is not None: self.assert_inventory_item(item) - item_obj = self.state.items[item] + item_obj = self.state.get_item(item) thing_container = self.scene_stack[-1] if detail is not None: self.assertEqual(detail, thing_container.name) @@ -108,7 +107,7 @@ def interact_item(self, target_item, item): self.assert_inventory_item(target_item) - item_obj = self.state.items[item] - target_obj = self.state.items[target_item] + item_obj = self.state.get_item(item) + target_obj = self.state.get_item(target_item) result = target_obj.interact(item_obj) return self.handle_result(result)