diff src/parpg/entities/action.py @ 178:487fba82abff

Moved the action module into the entities package. Removed the objects package.
author KarstenBock@gmx.net
date Sun, 09 Oct 2011 21:02:48 +0200
parents src/parpg/objects/action.py@c50a7adeae85
children 61d158ce6bc3
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/parpg/entities/action.py	Sun Oct 09 21:02:48 2011 +0200
@@ -0,0 +1,598 @@
+#   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
+from parpg.dialoguecontroller import DialogueController
+from parpg.components import container, lockable
+
+
+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 an lockable"""
+    def __init__(self, controller, lockable, 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 lockable: A reference to the lockable
+        """
+        Action.__init__(self, controller, commands)
+        self.view = controller.view
+        self.lockable = lockable
+    
+    def execute(self):
+        """Open the lockable."""
+        try:
+            lockable.open(self.lockable.lockable)
+            self.lockable.fifeagent.behaviour.animate("open")
+            self.lockable.fifeagent.behaviour.queue_animation("opened", 
+                                                              repeating=True)
+        except lockable.LockedError:
+            self.view.hud.createExamineBox(self.lockable.description.view_name,
+                                           "Locked")            
+        Action.execute(self)
+
+class CloseAction(Action):
+    """Close an lockable"""
+    def __init__(self, controller, lockable, 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 lockable: A reference to the lockable
+        """
+        Action.__init__(self, controller, commands)
+        self.lockable = lockable
+    
+    def execute(self):
+        """Close the lockable."""
+        lockable.close(self.lockable.lockable)
+        self.lockable.fifeagent.behaviour.animate("close")
+        self.lockable.fifeagent.behaviour.queue_animation("closed", 
+                                                          repeating=True)
+        Action.execute(self)
+        
+class UnlockAction(Action):
+    """Unlocks a lockable."""
+    def __init__(self, controller, lockable, commands = None):
+        """
+        @param controller: A reference to the GameSceneController.
+        @type controller: parpg.GameSceneController
+        @param commands: Special commands that are executed
+        @type commands: Dictionary 
+        @param lockable: A reference to the lockable
+        """
+        Action.__init__(self, controller, commands)
+        self.lockable = lockable
+    
+    def execute(self):
+        """Open the box."""
+        lockable.unlock(self.lockable.lockable)
+        Action.execute(self)
+        
+class LockAction(Action):
+    """Locks a lockable."""
+    def __init__(self, controller, lockable, commands = None):
+        """
+        @param controller: A reference to the GameSceneController.
+        @type controller: parpg.GameSceneController
+        @param commands: Special commands that are executed
+        @type commands: Dictionary 
+        @param lockable: A reference to the lockable
+        """
+        Action.__init__(self, controller, commands)
+        self.lockable = lockable
+        self.view = controller.view
+        
+    def execute(self):
+        """Lock the box."""
+        try:
+            lockable.lock(self.lockable.lockable)
+        except lockable.OpenError:
+            self.view.hud.createExamineBox(self.lockable.description.view_name,
+                                           "Is open")            
+            
+        Action.execute(self)
+
+
+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 
+        """
+        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)
+        Action.execute(self)
+
+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)
+        Action.execute(self)
+
+class ExamineContentsAction(Action):
+    """Examine the contens of an container"""
+    def __init__(self, controller, container, commands=None):
+        """
+        @param controller: A reference to the GameSceneController.
+        @type controller: parpg.GameSceneController
+        @param container: The container
+        @type container: parpg.entities.General
+        @param commands: Special commands that are executed
+        @type commands: Dictionary         
+        """
+        Action.__init__(self, controller, commands)
+        self.view = controller.view
+        self.container = container
+        
+    def execute(self):
+        """Examine the contents"""
+        self.view.hud.createBoxGUI(self.container.description.view_name,
+                                   self.container.container)
+        Action.execute(self)
+
+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"""
+        player_char = self.model.game_state.\
+                    getObjectById("PlayerCharacter").fifeagent
+        npc_coordinates = self.npc.fifeagent.behaviour.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.behaviour.approach(
+                [npc_coordinates.x, npc_coordinates.y],
+                        TalkAction(self.controller, 
+                                   self.npc, 
+                                   self.commands
+                                   )
+            )        
+        else:
+            player_char.behaviour.agent.act(
+                'stand', 
+                self.npc.fifeagent.behaviour.getLocation()
+            )
+    
+            if self.npc.dialogue.dialogue is not None:
+                dialogue_controller = DialogueController(
+                    self.controller.engine,
+                    self.view,
+                    self.model,
+                    self.controller.application
+                )
+                self.controller.application.manager.push_mode(
+                    dialogue_controller
+                )
+                dialogue_controller.startTalk(self.npc)
+            else:
+                self.npc.fifeagent.behaviour.agent.say("Leave me alone!", 1000)
+                
+            self.model.game_state.getObjectById("PlayerCharacter").\
+                fifeagent.behaviour.idle()
+            self.model.game_state.getObjectById("PlayerCharacter").\
+                fifeagent.behaviour.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"]
+                containable = self.item.containable
+                new_item = self.model.createItemByType(object_type, 
+                                                       object_id, 
+                                                       self.item.world)
+                container.put_item(containable.container, 
+                                   new_item.containable,
+                                   containable.slot)
+                self.model.deleteObject(self.item.general.identifier)
+                self.item.delete()
+                self.view.hud.inventory.updateImages()
+        super(UseAction, self).execute()
+
+class PickUpAction(Action):
+    """Action for picking up items from a map"""
+
+    def __init__(self, controller, item, commands = None):
+        super(PickUpAction, self).__init__(controller, commands)
+        self.item = item
+        self.view = controller.view
+        
+    def execute(self):
+        real_item = self.item.containable
+        self.item.fifeagent = None
+        player = self.model.game_state.getObjectById("PlayerCharacter")
+        self.model.moveObject(self.item.general.identifier, None)
+        self.model.updateObjectDB(self.item.world)
+        container.put_item(player.container, real_item)
+        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
+        identifier = self.item.entity.general.identifier
+        agent_values = self.model.items[identifier]
+        coords = (self.model.game_state.getObjectById("PlayerCharacter").
+                  fifeagent.behaviour.getLocation().getExactLayerCoordinates()
+                  )
+        agent_values["Position"] = (coords.x, coords.y)
+        agent_values["Rotation"] = 0
+        agent_values["Map"] = map_name
+        self.model.deleteObject(identifier)
+        self.model.addAgent(self.model.ALL_AGENTS_KEY, 
+                            {identifier: agent_values})
+        self.model.placeAgents(self.item.entity.world)
+        self.model.updateObjectDB(self.item.entity.world)
+        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()
+        container.remove_item(self.item.container, self.item.slot)
+        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.container
+        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.
+                            getObjectById("PlayerCharacter").container)
+        for item in self.pot.children:
+            if not item:
+                continue
+            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.entity.description.view_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 = container.get_item(player_character, "Wood")
+        if wood:
+            has_wood = True        
+        bottle = container.get_item(player_character, "Empty beer bottle")
+        if bottle:
+            has_bottle = True        
+        if has_water and has_fruit and has_wood and has_bottle:
+            container.remove_item(self.pot, water.slot)
+            container.remove_item(self.pot, fruit.slot)
+            if has_yeast:
+                container.remove_item(self.pot, yeast.slot)
+            container.remove_item(player_character, wood.slot)
+            new_item = (self.model.createItemByType("Beer", "Beer", 
+                                                    self.pot.entity.world)
+                        )
+            container.put_item(player_character, new_item.containable)
+            self.view.hud.inventory.updateImages()
+            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,
+           "Close":CloseAction,
+           "Unlock":UnlockAction,
+           "Lock":LockAction,
+           "ExamineItem":ExamineItemAction,
+           "Examine":ExamineAction,
+           "Look":ExamineItemAction,
+           "Read":ReadAction,
+           "Talk":TalkAction,
+           "Use":UseAction,
+           "PickUp":PickUpAction,
+           "DropFromInventory":DropItemFromContainerAction,
+           "BrewBeer":BrewBeerAction,
+           "ExamineContents": ExamineContentsAction,
+           }