Mercurial > parpg-core
diff src/parpg/objects/action.py @ 0:1fd2201f5c36
Initial commit of parpg-core.
author | M. George Hansen <technopolitica@gmail.com> |
---|---|
date | Sat, 14 May 2011 01:12:35 -0700 |
parents | |
children | d60f1dab8469 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/parpg/objects/action.py Sat May 14 01:12:35 2011 -0700 @@ -0,0 +1,548 @@ +# This file is part of PARPG. + +# PARPG is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# PARPG is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with PARPG. If not, see <http://www.gnu.org/licenses/>. + +#exceptions + +import logging + +logger = logging.getLogger('action') + +from parpg.gui import drag_drop_data as data_drag + +class NoSuchQuestException(Exception): + """NoQuestException is used when there is no active quest with the id""" + pass + +#classes + +class Action(object): + """Base Action class, to define the structure""" + + + def __init__(self, controller, commands = None): + """Basic action constructor + @param controller: A reference to the GameSceneController. + @type controller: parpg.GameSceneController + @param commands: Special commands that are executed + @type commands: Dictionary + """ + self.commands = commands or () + self.controller = controller + self.model = controller.model + + def execute(self): + """To be overwritten""" + #Check if there are special commands and execute them + for command_data in self.commands: + command = command_data["Command"] + if command == "SetQuestVariable": + quest_id = command_data["ID"] + variable = command_data["Variable"] + value = command_data["Value"] + quest_engine = self.model.game_state.quest_engine + if quest_engine.hasQuest(quest_id): + quest_engine[quest_id].setValue(variable, value) + else: + raise NoSuchQuestException + elif command == "ResetMouseCursor": + self.controller.resetMouseCursor() + elif command == "StopDragging": + data_drag.dragging = False + +class ChangeMapAction(Action): + """A change map scheduled""" + def __init__(self, controller, target_map_name, target_pos, commands=None): + """Initiates a change of the position of the character + possibly flagging a new map to be loaded. + @param controller: A reference to the GameSceneController. + @type controller: parpg.GameSceneController + @param commands: Special commands that are executed + @type commands: Dictionary + @type view: class derived from parpg.ViewBase + @param view: The view + @type target_map_name: String + @param target_map_name: Target map id + @type target_pos: Tuple + @param target_pos: (X, Y) coordinates on the target map. + @return: None""" + super(ChangeMapAction, self).__init__(controller, commands) + self.view = controller.view + self.target_pos = target_pos + self.target_map_name = target_map_name + + def execute(self): + """Executes the map change.""" + self.model.changeMap(self.target_map_name, + self.target_pos) + super(ChangeMapAction, self).execute() + +class OpenAction(Action): + """Open a container""" + def __init__(self, controller, container, commands=None): + """ + @param controller: A reference to the GameSceneController. + @type controller: parpg.GameSceneController + @param commands: Special commands that are executed + @type commands: Dictionary + @type view: class derived from parpg.ViewBase + @param view: The view + @param container: A reference to the container + """ + super(OpenAction, self).__init__(controller, commands) + self.view = controller.view + self.container = container + def execute(self): + """Open the box.""" + self.view.hud.createBoxGUI(self.container.name, \ + self.container) + super(OpenAction, self).execute() + + +class OpenBoxAction(OpenAction): + """Open a box. Needs to be more generic, but will do for now.""" + def __init__(self, controller, container, commands = None): + """ + @param controller: A reference to the GameSceneController. + @type controller: parpg.GameSceneController + @param commands: Special commands that are executed + @type commands: Dictionary + @type view: class derived from parpg.ViewBase + @param view: The view + @param container: A reference to the container + """ + super(OpenBoxAction, self).__init__(controller, commands) + self.view = controller.view + self.container = container + + def execute(self): + """Open the box.""" + try: + self.container.open() + super(OpenBoxAction, self).execute() + + except ValueError: + self.view.hud.createExamineBox(self.container.name, \ + "The container is locked") + +class UnlockBoxAction(Action): + """Unlocks a box. Needs to be more generic, but will do for now.""" + def __init__(self, controller, container, commands = None): + """ + @param controller: A reference to the GameSceneController. + @type controller: parpg.GameSceneController + @param commands: Special commands that are executed + @type commands: Dictionary + @param container: A reference to the container + """ + super(UnlockBoxAction, self).__init__(controller, commands) + self.container = container + + def execute(self): + """Open the box.""" + self.container.unlock() + super(UnlockBoxAction, self).execute() + +class LockBoxAction(Action): + """Locks a box. Needs to be more generic, but will do for now.""" + def __init__(self, controller, container, commands = None): + """ + @param controller: A reference to the GameSceneController. + @type controller: parpg.GameSceneController + @param commands: Special commands that are executed + @type commands: Dictionary + @param container: A reference to the container + """ + super(LockBoxAction, self).__init__(controller, commands) + self.container = container + + def execute(self): + """Lock the box.""" + self.container.lock() + super(LockBoxAction, self).execute() + + +class ExamineAction(Action): + """Examine an object.""" + def __init__(self, controller, examine_id, examine_name, examine_desc=None, commands=None): + """ + @param controller: A reference to the GameSceneController. + @type controller: parpg.GameSceneController + @param examine_id: An object id + @type examine_id: integer + @param examine_name: An object name + @type examine_name: string + @param examine_desc: A description of the object that will be displayed. + @type examine_desc: string + @param commands: Special commands that are executed + @type commands: Dictionary + @type view: class derived from parpg.ViewBase + @param view: The view + + """ + super(ExamineAction, self).__init__(controller, commands) + self.view = controller.view + self.examine_id = examine_id + self.examine_name = examine_name + if examine_desc is not None: + self.examine_desc = examine_desc + else: + self.examine_desc = "No Description" + + def execute(self): + """Display the text.""" + action_text = self.examine_desc + self.view.hud.addAction(unicode(action_text)) + logger.debug(action_text) + #this code will cut the line up into smaller lines that will be displayed + place = 25 + while place <= len(action_text): + if action_text[place] == ' ': + action_text = action_text[:place] +'\n'+action_text[place:] + place += 26 #plus 1 character to offset the new line + else: place += 1 + self.view.displayObjectText(self.examine_id, unicode(action_text), time=3000) + +class ExamineItemAction(Action): + """Examine an item.""" + def __init__(self, controller, examine_name, examine_desc, commands = None): + """ + @param controller: A reference to the GameSceneController. + @type controller: parpg.GameSceneController + @param commands: Special commands that are executed + @type commands: Dictionary + @type view: class derived from parpg.ViewBase + @param view: The view + @type examine_name: String + @param examine_name: Name of the object to be examined. + @type examine_name: String + @param examine_name: Description of the object to be examined. + """ + super(ExamineItemAction, self).__init__(controller, commands) + self.view = controller.view + self.examine_name = examine_name + self.examine_desc = examine_desc + + def execute(self): + """Display the text.""" + action_text = unicode(self.examine_desc) + self.view.hud.addAction(action_text) + logger.debug(action_text) + +class ReadAction(Action): + """Read a text.""" + def __init__(self, controller, text_name, text, commands = None): + """ + @param controller: A reference to the GameSceneController. + @type controller: parpg.GameSceneController + @param commands: Special commands that are executed + @type commands: Dictionary + @param view: The view + @type view: class derived from parpg.ViewBase + @param text_name: Name of the object containing the text + @type text_name: String + @param text: Text to be displayied + @type text: String + """ + super(ReadAction, self).__init__(controller, commands) + self.view = controller.view + self.text_name = text_name + self.text = text + + def execute(self): + """Examine the box.""" + action_text = unicode('\n'.join(["You read " + self.text_name + ".", + self.text])) + self.view.hud.addAction(action_text) + logger.debug(action_text) + super(ReadAction, self).execute() + +class TalkAction(Action): + """An action to represent starting a dialogue""" + def __init__(self, controller, npc, commands = None): + """ + @param controller: A reference to the GameSceneController. + @type controller: parpg.GameSceneController + @param commands: Special commands that are executed + @type commands: Dictionary + @type view: class derived from parpg.ViewBase + @param view: The view + @type npc: NonPlayerCharacter + @param npc: NPC to interact with. + """ + super(TalkAction, self).__init__(controller, commands) + self.view = controller.view + self.npc = npc + + def execute(self): + """Talk with the NPC when close enough, otherwise move closer. + @return: None""" + from parpg.dialoguecontroller import DialogueController + + player_char = self.model.game_state.player_character + npc_coordinates = self.npc.getLocation().getLayerCoordinates() + pc_coordinates = player_char.behaviour.agent.\ + getLocation().getLayerCoordinates() + + distance_squared = (npc_coordinates.x - pc_coordinates.x) *\ + (npc_coordinates.x - pc_coordinates.x) +\ + (npc_coordinates.y - pc_coordinates.y) *\ + (npc_coordinates.y - pc_coordinates.y) + + # If we are too far away, we approach the NPC again + if distance_squared > 2: + player_char.approach([self.npc.getLocation(). + getLayerCoordinates().x, + self.npc.getLocation(). + getLayerCoordinates().y], + TalkAction(self.controller, + self.npc, self.commands)) + else: + player_char.behaviour.agent.act('stand', self.npc.getLocation()) + + if self.npc.dialogue is not None: + dialogue_controller = DialogueController(self.controller.engine, + self.view, + self.model, + self.controller.application) + self.controller.application.pushController(dialogue_controller) + dialogue_controller.startTalk(self.npc) + else: + self.npc.behaviour.agent.say("Leave me alone!", 1000) + + self.model.game_state.player_character.behaviour.idle() + self.model.game_state.player_character.nextAction = None + super(TalkAction, self).execute() + +class UseAction(Action): + """Action for carryable items. It executes special commands that can be only + used on carryable utens""" + + + def __init__(self, controller, item, commands = None): + """ + @param controller: A reference to the GameSceneController. + @type controller: parpg.GameSceneController + @param item: Item on which the action is called + @type item: CarryableItem + @param commands: Special commands that are executed + @type commands: Dictionary + """ + super(UseAction, self).__init__(controller, commands) + self.view = controller.view + self.item = item + + def execute(self): + #Check if there are special commands and execute them + for command_data in self.commands: + command = command_data["Command"] + if command == "ReplaceItem": + object_id = command_data["ID"] + object_type = command_data["ObjectType"] + container = self.item.in_container + inst_dict = {} + inst_dict["ID"] = object_id + inst_dict["object_type"] = object_type + new_item = self.model.createContainerObject(inst_dict) + container.replaceItem(self.item, new_item) + self.view.hud.inventory.updateInventoryButtons() + super(UseAction, self).execute() + +class PickUpAction(Action): + """Action for picking up items from a map""" + + def __init__(self, controller, map_item, commands = None): + super(PickUpAction, self).__init__(controller, commands) + self.map_item = map_item + self.view = controller.view + + def execute(self): + real_item = self.map_item.item + self.model.deleteObject(self.map_item.ID) + self.model.game_state.player_character.\ + inventory.placeItem(real_item) + self.view.hud.inventory.updateInventoryButtons() + super(PickUpAction, self).execute() + +class DropItemAction(Action): + """Action for dropping an items on a map""" + def __init__(self, controller, item, commands = None): + super(DropItemAction, self).__init__(controller, commands) + self.item = item + + def execute(self): + map_name = self.model.game_state.current_map_name + map_item_values = {} + map_item_values["ViewName"] = self.item.name + map_item_values["ObjectType"] = "MapItem" + map_item_values["ItemType"] = self.item.item_type + map_item_values["Map"] = map_name + coords = self.model.game_state.player_character.\ + getLocation().getExactLayerCoordinates() + map_item_values["Position"] = (coords.x, coords.y) + map_item_values["Rotation"] = 0 + map_item_values["item"] = self.item + agent = {} + agent[self.item.ID] = map_item_values + self.model.addAgent("All", agent) + self.model.placeAgents() + super(DropItemAction, self).execute() + +class DropItemFromContainerAction(DropItemAction): + """Action for dropping an items from the Inventory to a map""" + + def __init__(self, controller, item, container_gui, commands = None): + super(DropItemFromContainerAction, self).__init__(controller, item, commands) + self.container_gui = container_gui + + def execute(self): + super(DropItemFromContainerAction, self).execute() + self.item.in_container.takeItem(self.item) + self.container_gui.updateImages() + +class BrewBeerAction(Action): + """Action for brewing beer in a pot""" + def __init__(self, controller, pot, commands = None): + super(BrewBeerAction, self).__init__(controller, commands) + self.pot = pot + self.view = controller.view + + def execute(self): + """Brew the beer""" + has_water = False + has_yeast = False + has_fruit = False + has_wood = False + has_bottle = False + player_character = self.model.game_state.player_character + for item in self.pot.items.itervalues(): + if item.item_type == "Questionable water": + if has_water: + self.view.hud.addAction(unicode(\ + "Please put only 1 water in the pot")) + return + has_water = True + water_type = 1 + water = item + elif item.item_type == "Pure water": + if has_water: + self.view.hud.addAction(unicode(\ + "Please put only 1 water in the pot")) + return + has_water = True + water_type = 2 + water = item + elif item.item_type == "Grain": + if has_fruit: + self.view.hud.addAction(unicode(\ + "Please put only 1 fruit in the pot")) + return + has_fruit = True + fruit_type = 3 + fruit = item + elif item.item_type == "Wild potato": + if has_fruit: + self.view.hud.addAction(unicode(\ + "Please put only 1 fruit in the pot")) + return + has_fruit = True + fruit_type = 2 + fruit = item + elif item.item_type == "Rotten yam": + if has_fruit: + self.view.hud.addAction(unicode(\ + "Please put only 1 fruit in the pot")) + return + has_fruit = True + fruit_type = 1 + fruit = item + elif item.item_type == "Yeast": + if has_yeast: + self.view.hud.addAction(unicode(\ + "Please put only 1 yeast in the pot")) + return + has_yeast = True + yeast = item + else: + self.view.hud.addAction(unicode("Item " + item.name + \ + " is not needed for brewing beer")) + self.view.hud.addAction(unicode(\ + "Please put only ingredients for the beer in the pot.\ + Things like bottles and wood have to be in your inventory")) + return + wood = player_character.hasItem("Wood") + if wood: + has_wood = True + bottle = player_character.hasItem("Empty beer bottle") + if bottle: + has_bottle = True + if has_water and has_fruit and has_wood and has_bottle: + self.pot.removeItem(water) + self.pot.removeItem(fruit) + if has_yeast: + self.pot.removeItem(yeast) + player_character.inventory.removeItem(wood) + inst_dict = {} + inst_dict["ID"] = "Beer" + inst_dict["object_type"] = "Beer" + new_item = self.model.createContainerObject(inst_dict) + player_character.inventory.placeItem(new_item) + self.view.hud.inventory.updateInventoryButtons() + beer_quality = 0 + if water_type == 1: + if fruit_type == 1: + beer_quality = -1 + elif fruit_type == 2: + beer_quality = 2 + elif fruit_type == 3: + beer_quality = 3 + if water_type == 2: + if fruit_type == 1: + beer_quality = 1 + elif fruit_type == 2: + beer_quality = 3 + elif fruit_type == 3: + beer_quality = 4 + if beer_quality > 0 and has_yeast: + beer_quality += 1 + self.model.game_state.quest_engine.quests["beer"].\ + setValue("beer_quality", beer_quality) + else: + self.view.hud.addAction(unicode( + """For brewing beer you need at least: + In the pot: + Fruit (like grain, potato, yam) + Water + Optionally: + Good quality yeast. + Wild yeast will be used if none present. + In the inventory: + Wood + Empty bottle""")) + super(BrewBeerAction, self).execute() + +ACTIONS = {"ChangeMap":ChangeMapAction, + "Open":OpenAction, + "OpenBox":OpenBoxAction, + "Unlock":UnlockBoxAction, + "Lock":LockBoxAction, + "ExamineItem":ExamineItemAction, + "Examine":ExamineAction, + "Look":ExamineItemAction, + "Read":ReadAction, + "Talk":TalkAction, + "Use":UseAction, + "PickUp":PickUpAction, + "DropFromInventory":DropItemFromContainerAction, + "BrewBeer":BrewBeerAction}