diff src/parpg/dialogueactions.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 2e307c4f78e3
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/parpg/dialogueactions.py	Sat May 14 01:12:35 2011 -0700
@@ -0,0 +1,373 @@
+#   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/>.
+"""
+Provides classes used to implement dialogue logic and allow dialogues to have
+external effects on the game state.
+"""
+import logging
+
+logger = logging.getLogger('dialogueaction')
+
+class DialogueAction(object):
+    """
+    Abstract base class for subclasses that represent dialogue actions embedded
+    within a DialogueSection or DialogueResponse.
+    
+    Subclasses must define the keyword class variable and implement both the
+    __init__ and __call__ methods.
+    
+    @cvar keyword: keyword used by the L{DialogueParser} to recognize the
+        L{DialogueAction} in serialized L{Dialogues<Dialogues>}.
+    @type keyword: basestring
+    """
+    logger = logging.getLogger('dialogueaction.DialogueAction')
+    registered_actions = {}
+    
+    @classmethod
+    def registerAction(cls, dialogue_action_type):
+        """
+        Register a L{DialogueAction} subclass for easy reference.
+        
+        @param dialogue_action_type: dialogue action to register.
+        @type dialogue_action_type: L{DialogueAction} subclass
+        """
+        cls.registered_actions[dialogue_action_type.keyword] = \
+            dialogue_action_type
+    
+    def __init__(self, *args, **kwargs):
+        """
+        Initialize a new L{DialogueAction} instance.
+        
+        @param args: positional arguments passed by the L{DialogueParser} after
+            reading a serialized L{Dialogue}.
+        @type args: list of objects
+        @param kwargs: keyword arguments passed by the L{DialogueParser} after
+            reading a serialized L{Dialogue}.
+        @type kwargs: dict of objects
+        """
+        if (not hasattr(type(self), 'keyword')):
+            raise AttributeError('DialogueAction subclasses must define the '
+                                 'keyword class variable.')
+        self.arguments = (args, kwargs)
+    
+    def __call__(self, game_state):
+        """
+        Execute the L{DialogueAction}.
+        
+        @param game_state: variables and functions that make up the current
+            game state.
+        @type game_state: dict of objects
+        """
+        raise NotImplementedError('subclasses of DialogueAction must '
+                                  'override __call__')
+
+
+class MeetAction(DialogueAction):
+    """
+    L{DialogueAction} that adds an NPC to the list of NPCs known by the player.
+    """
+    keyword = 'meet'
+    
+    def __init__(self, *args, **kwargs):
+        """
+        Initialize a new L{MeetAction} instance.
+        
+        @param args: positional arguments.
+        @type args: list of objects
+        @param npc_id: identifier of the NPC that the player has met.
+        @type npc_id: basestring
+        @param kwargs: keyword arguments (not used).
+        @type kwargs: dict of objects
+        """
+        DialogueAction.__init__(self, *args, **kwargs)
+        self.npc_id = args[0]
+    
+    def __call__(self, game_state):
+        """
+        Add an NPC to the list of NPCs known by the player.
+        
+        @param game_state: variables and functions that make up the current
+            game state.
+        @type game_state: dict of objects
+        """
+        npc_id = self.npc_id
+        # NOTE Technomage 2010-11-13: This print statement seems overly
+        #     verbose, so I'm logging it as an INFO message instead.
+#        print("You've met {0}!".format(npc_id))
+        self.logger.info("You've met {0}!".format(npc_id))
+        game_state['pc'].meet(npc_id)
+DialogueAction.registerAction(MeetAction)
+
+
+class InventoryAction(DialogueAction):
+    """
+    Abstract base class for L{DialogueActions<DialogueAction>} used to
+    manipulate the NPC's and the player's inventory.
+    """
+    def __init__(self, *args, **kwargs):
+        """
+        Initialize a new L{InventoryAction} instance.
+        
+        @param args: positional arguments.
+        @type args: list of objects
+        @param item_types: item types that should be manipulated.
+        @type item_types: list of basestrings
+        @param kwargs: keyword arguments.
+        @type kwargs: dict of objects
+        """
+        DialogueAction.__init__(self, *args, **kwargs)
+        self.item_types = args
+
+
+class TakeStuffAction(InventoryAction):
+    """
+    L{InventoryAction} used to move items from the NPC's inventory to the
+    player's inventory.
+    """
+    keyword = 'take_stuff'
+    
+    def __call__(self, game_state):
+        """
+        Move items from the NPC's inventory to the player's inventory.
+        
+        @param game_state: variables and functions that make up the current
+            game state.
+        @type game_state: dict of objects
+        """
+        item_types = self.item_types
+        for item_type in item_types:
+            item = game_state['npc'].inventory.findItem(item_type=item_type)
+            if (item):
+                game_state['npc'].give(item, game_state['pc'])
+                print("{0} gave you the {1}".format(game_state['npc'].name,
+                                                    item_type))
+            else:
+                print("{0} doesn't have the {1}".format(game_state['npc'].name,
+                                                        item_type))
+DialogueAction.registerAction(TakeStuffAction)
+
+
+class GiveStuffAction(InventoryAction):
+    """
+    L{InventoryAction} used to move items from the player's inventory to the
+    NPC's inventory.
+    """
+    keyword = 'give_stuff'
+    
+    def __call__(self, game_state):
+        """
+        Move items from the player's inventory to the NPC's inventory.
+        
+        @param game_state: variables and functions that make up the current
+            game state.
+        @type game_state: dict of objects
+        """
+        item_types = self.item_types
+        for item_type in item_types:
+            item = game_state['npc'].inventory.findItem(item_type = item_type)
+            if (item):
+                game_state['pc'].give(item, game_state['npc'])
+                print("You give the {0} to {1}".format(item_type,
+                                                       game_state['npc'].name))
+            else:
+                print("You don't have the {0}".format(item_type))
+DialogueAction.registerAction(GiveStuffAction)
+
+
+class QuestAction(DialogueAction):
+    """
+    Abstract base class for quest-related L{DialogueActions<DialogueAction>}.
+    """
+    def __init__(self, *args, **kwargs):
+        """
+        Initialize a new L{QuestAction} instance.
+        
+        @param args: positional arguments.
+        @type args: list of objects
+        @param quest_id: ID of the quest to manipulate.
+        @type quest_id: basestring
+        @param kwargs: keyword arguments (not used).
+        @type kwargs: dict of objects
+        """
+        DialogueAction.__init__(self, *args, **kwargs)
+        self.quest_id = kwargs['quest'] if 'quest' in kwargs else args[0]
+
+
+class StartQuestAction(QuestAction):
+    """L{QuestAction} used to activate a quest."""
+    keyword = 'start_quest'
+    
+    def __call__(self, game_state):
+        """
+        Activate a quest.
+        
+        @param game_state: variables and functions that make up the current
+            game state.
+        @type game_state: dict of objects
+        """
+        quest_id = self.quest_id
+        print("You've picked up the \"{0}\" quest!".format(quest_id))
+        game_state['quest'].activateQuest(quest_id)
+DialogueAction.registerAction(StartQuestAction)
+
+
+class CompleteQuestAction(QuestAction):
+    """
+    L{QuestAction} used to mark a quest as successfully finished/completed.
+    """
+    keyword = 'complete_quest'
+    
+    def __call__(self, game_state):
+        """
+        Successfully complete a quest.
+        
+        @param game_state: variables and functions that make up the current
+            game state.
+        @type game_state: dict of objects
+        """
+        quest_id = self.quest_id
+        print("You've finished the \"{0}\" quest".format(quest_id))
+        game_state['quest'].finishQuest(quest_id)
+DialogueAction.registerAction(CompleteQuestAction)
+
+
+class FailQuestAction(QuestAction):
+    """L{QuestAction} used to fail an active quest."""
+    keyword = 'fail_quest'
+    
+    def __call__(self, game_state):
+        """
+        Fail an active quest.
+        
+        @param game_state: variables and functions that make up the current
+            game state.
+        @type game_state: dict of objects
+        """
+        quest_id = self.quest_id
+        print("You've failed the \"{0}\" quest".format(quest_id))
+        game_state['quest'].failQuest(quest_id)
+DialogueAction.registerAction(FailQuestAction)
+
+
+class RestartQuestAction(QuestAction):
+    """L{QuestAction} used to restart an active quest."""
+    keyword = 'restart_quest'
+    
+    def __call__(self, game_state):
+        """
+        Restart an active quest.
+        
+        @param game_state: variables and functions that make up the current
+            game state.
+        @type game_state: dict of objects
+        """
+        quest_id = self.quest_id
+        print("You've restarted the \"{0}\" quest".format(quest_id))
+        game_state['quest'].restartQuest(quest_id)
+DialogueAction.registerAction(RestartQuestAction)
+
+
+class QuestVariableAction(QuestAction):
+    """
+    Base class for L{QuestActions<QuestAction>} that modify quest
+    variables.
+    """
+    def __init__(self, *args, **kwargs):
+        """
+        Initialize a new L{QuestVariableAction} instance.
+        
+        @param args: positional arguments (not used).
+        @type args: list of objects
+        @param kwargs: keyword arguments.
+        @type kwargs: dict of objects
+        @keyword quest: ID of the quest whose variable should be modified.
+        @type quest: basestring
+        @keyword variable: name of the quest variable to modify.
+        @type variable: basestring
+        @keyword value: new value that should be used to modify the quest
+            variable.
+        @type value: object
+        """
+        QuestAction.__init__(self, *args, **kwargs)
+        self.variable_name = kwargs['variable']
+        self.value = kwargs['value']
+
+
+class IncreaseQuestVariableAction(QuestVariableAction):
+    """
+    L{QuestVariableAction} used to increase the value of a quest variable by a
+    set amount.
+    """
+    keyword = 'increase_quest_variable'
+    
+    def __call__(self, game_state):
+        """
+        Increase a quest variable by a set amount.
+        
+        @param game_state: variables and functions that make up the current
+            game state.
+        @type game_state: dict of objects
+        """
+        quest_id = self.quest_id
+        variable_name = self.variable_name
+        value = self.value
+        print('Increased {0} by {1}'.format(variable_name, value))
+        game_state['quest'][quest_id].increaseValue(variable_name, value)
+DialogueAction.registerAction(IncreaseQuestVariableAction)
+
+
+class DecreaseQuestVariableAction(QuestVariableAction):
+    """
+    L{QuestVariableAction} used to decrease the value of a quest variable by a
+    set amount.
+    """
+    keyword = 'decrease_quest_variable'
+    
+    def __call__(self, game_state):
+        """
+        Decrease a quest variable by a set amount.
+        
+        @param game_state: variables and functions that make up the current
+            game state.
+        @type game_state: dict of objects
+        """
+        quest_id = self.quest_id
+        variable_name = self.variable_name
+        value = self.value
+        print('Decreased {0} by {1}'.format(variable_name, value))
+        game_state['quest'][quest_id].decreaseValue(variable_name, value)
+DialogueAction.registerAction(DecreaseQuestVariableAction)
+
+
+class SetQuestVariableAction(QuestVariableAction):
+    """
+    L{QuestVariableAction} used to set the value of a quest variable.
+    """
+    keyword = 'set_quest_variable'
+    
+    def __call__(self, game_state):
+        """
+        Set the value of a quest variable.
+        
+        @param game_state: variables and functions that make up the current
+            game state.
+        @type game_state: dict of objects
+        """
+        quest_id = self.quest_id
+        variable_name = self.variable_name
+        value = self.value
+        print('Set {0} to {1}'.format(variable_name, value))
+        game_state['quest'][quest_id].setValue(variable_name, value)
+DialogueAction.registerAction(SetQuestVariableAction)