source: trunk/game/scripts/dialogueactions.py @ 680

Revision 680, 12.9 KB checked in by technomage, 9 years ago (diff)

Patch by Technomage

  • Updated/wrote code documentation for the core dialogue subsystem modules dialogue.py, dialogueengine.py, dialogueactions.py, and dialogueparsers.py.
  • Updated/created flowcharts and UML diagrams explaining the new DialogueEngine? and how it functions.
  • Made a few minor changes to the dialoguegui.py module to make the class logger less visible.
  • Removed the "this is a sample dialogue file" crud from the old_man.yaml test dialogue file.
  • Property svn:mime-type set to text/plain
Line 
1#!/usr/bin/env python
2#
3#   This file is part of PARPG.
4#
5#   PARPG is free software: you can redistribute it and/or modify
6#   it under the terms of the GNU General Public License as published by
7#   the Free Software Foundation, either version 3 of the License, or
8#   (at your option) any later version.
9#
10#   PARPG is distributed in the hope that it will be useful,
11#   but WITHOUT ANY WARRANTY; without even the implied warranty of
12#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13#   GNU General Public License for more details.
14#
15#   You should have received a copy of the GNU General Public License
16#   along with PARPG.  If not, see <http://www.gnu.org/licenses/>.
17"""
18Provides classes used to implement dialogue logic and allow dialogues to have
19external effects on the game state.
20"""
21import logging
22
23def setup_logging():
24    """Set various logging parameters for this module."""
25    module_logger = logging.getLogger('dialogueaction')
26    if __debug__:
27        module_logger.setLevel(logging.DEBUG)
28setup_logging()
29
30class DialogueAction(object):
31    """
32    Abstract base class for subclasses that represent dialogue actions embedded
33    within a DialogueSection or DialogueResponse.
34   
35    Subclasses must define the keyword class variable and implement both the
36    __init__ and __call__ methods.
37   
38    @cvar keyword: keyword used by the L{DialogueParser} to recognize the
39        L{DialogueAction} in serialized L{Dialogues<Dialogues>}.
40    @type keyword: basestring
41    """
42    logger = logging.getLogger('dialogueaction.DialogueAction')
43    registered_actions = {}
44   
45    @classmethod
46    def registerAction(cls, dialogue_action_type):
47        """
48        Register a L{DialogueAction} subclass for easy reference.
49       
50        @param dialogue_action_type: dialogue action to register.
51        @type dialogue_action_type: L{DialogueAction} subclass
52        """
53        cls.registered_actions[dialogue_action_type.keyword] = \
54            dialogue_action_type
55   
56    def __init__(self, *args, **kwargs):
57        """
58        Initialize a new L{DialogueAction} instance.
59       
60        @param args: positional arguments passed by the L{DialogueParser} after
61            reading a serialized L{Dialogue}.
62        @type args: list of objects
63        @param kwargs: keyword arguments passed by the L{DialogueParser} after
64            reading a serialized L{Dialogue}.
65        @type kwargs: dict of objects
66        """
67        if (not hasattr(type(self), 'keyword')):
68            raise AttributeError('DialogueAction subclasses must define the '
69                                 'keyword class variable.')
70        self.arguments = (args, kwargs)
71   
72    def __call__(self, game_state):
73        """
74        Execute the L{DialogueAction}.
75       
76        @param game_state: variables and functions that make up the current
77            game state.
78        @type game_state: dict of objects
79        """
80        raise NotImplementedError('subclasses of DialogueAction must '
81                                  'override __call__')
82
83
84class MeetAction(DialogueAction):
85    """
86    L{DialogueAction} that adds an NPC to the list of NPCs known by the player.
87    """
88    keyword = 'meet'
89   
90    def __init__(self, *args, **kwargs):
91        """
92        Initialize a new L{MeetAction} instance.
93       
94        @param args: positional arguments.
95        @type args: list of objects
96        @param npc_id: identifier of the NPC that the player has met.
97        @type npc_id: basestring
98        @param kwargs: keyword arguments (not used).
99        @type kwargs: dict of objects
100        """
101        DialogueAction.__init__(self, *args, **kwargs)
102        self.npc_id = args[0]
103   
104    def __call__(self, game_state):
105        """
106        Add an NPC to the list of NPCs known by the player.
107       
108        @param game_state: variables and functions that make up the current
109            game state.
110        @type game_state: dict of objects
111        """
112        npc_id = self.npc_id
113        # NOTE Technomage 2010-11-13: This print statement seems overly
114        #     verbose, so I'm logging it as an INFO message instead.
115#        print("You've met {0}!".format(npc_id))
116        self.logger.info("You've met {0}!".format(npc_id))
117        game_state['pc'].meet(npc_id)
118DialogueAction.registerAction(MeetAction)
119
120
121class InventoryAction(DialogueAction):
122    """
123    Abstract base class for L{DialogueActions<DialogueAction>} used to
124    manipulate the NPC's and the player's inventory.
125    """
126    def __init__(self, *args, **kwargs):
127        """
128        Initialize a new L{InventoryAction} instance.
129       
130        @param args: positional arguments.
131        @type args: list of objects
132        @param item_types: item types that should be manipulated.
133        @type item_types: list of basestrings
134        @param kwargs: keyword arguments.
135        @type kwargs: dict of objects
136        """
137        DialogueAction.__init__(self, *args, **kwargs)
138        self.item_types = args
139
140
141class TakeStuffAction(InventoryAction):
142    """
143    L{InventoryAction} used to move items from the NPC's inventory to the
144    player's inventory.
145    """
146    keyword = 'take_stuff'
147   
148    def __call__(self, game_state):
149        """
150        Move items from the NPC's inventory to the player's inventory.
151       
152        @param game_state: variables and functions that make up the current
153            game state.
154        @type game_state: dict of objects
155        """
156        item_types = self.item_types
157        for item_type in item_types:
158            item = game_state['npc'].inventory.findItem(item_type=item_type)
159            if (item):
160                game_state['npc'].give(item, game_state['pc'])
161                print("{0} gave you the {1}".format(game_state['npc'].name,
162                                                    item_type))
163            else:
164                print("{0} doesn't have the {1}".format(game_state['npc'].name,
165                                                        item_type))
166DialogueAction.registerAction(TakeStuffAction)
167
168
169class GiveStuffAction(InventoryAction):
170    """
171    L{InventoryAction} used to move items from the player's inventory to the
172    NPC's inventory.
173    """
174    keyword = 'give_stuff'
175   
176    def __call__(self, game_state):
177        """
178        Move items from the player's inventory to the NPC's inventory.
179       
180        @param game_state: variables and functions that make up the current
181            game state.
182        @type game_state: dict of objects
183        """
184        item_types = self.item_types
185        for item_type in item_types:
186            item = game_state['npc'].inventory.findItem(item_type = item_type)
187            if (item):
188                game_state['pc'].give(item, game_state['npc'])
189                print("You give the {0} to {1}".format(item_type,
190                                                       game_state['npc'].name))
191            else:
192                print("You don't have the {0}".format(item_type))
193DialogueAction.registerAction(GiveStuffAction)
194
195
196class QuestAction(DialogueAction):
197    """
198    Abstract base class for quest-related L{DialogueActions<DialogueAction>}.
199    """
200    def __init__(self, *args, **kwargs):
201        """
202        Initialize a new L{QuestAction} instance.
203       
204        @param args: positional arguments.
205        @type args: list of objects
206        @param quest_id: ID of the quest to manipulate.
207        @type quest_id: basestring
208        @param kwargs: keyword arguments (not used).
209        @type kwargs: dict of objects
210        """
211        DialogueAction.__init__(self, *args, **kwargs)
212        self.quest_id = kwargs['quest'] if 'quest' in kwargs else args[0]
213
214
215class StartQuestAction(QuestAction):
216    """L{QuestAction} used to activate a quest."""
217    keyword = 'start_quest'
218   
219    def __call__(self, game_state):
220        """
221        Activate a quest.
222       
223        @param game_state: variables and functions that make up the current
224            game state.
225        @type game_state: dict of objects
226        """
227        quest_id = self.quest_id
228        print("You've picked up the \"{0}\" quest!".format(quest_id))
229        game_state['quest'].activateQuest(quest_id)
230DialogueAction.registerAction(StartQuestAction)
231
232
233class CompleteQuestAction(QuestAction):
234    """
235    L{QuestAction} used to mark a quest as successfully finished/completed.
236    """
237    keyword = 'complete_quest'
238   
239    def __call__(self, game_state):
240        """
241        Successfully complete a quest.
242       
243        @param game_state: variables and functions that make up the current
244            game state.
245        @type game_state: dict of objects
246        """
247        quest_id = self.quest_id
248        print("You've finished the \"{0}\" quest".format(quest_id))
249        game_state['quest'].finishQuest(quest_id)
250DialogueAction.registerAction(CompleteQuestAction)
251
252
253class FailQuestAction(QuestAction):
254    """L{QuestAction} used to fail an active quest."""
255    keyword = 'fail_quest'
256   
257    def __call__(self, game_state):
258        """
259        Fail an active quest.
260       
261        @param game_state: variables and functions that make up the current
262            game state.
263        @type game_state: dict of objects
264        """
265        quest_id = self.quest_id
266        print("You've failed the \"{0}\" quest".format(quest_id))
267        game_state['quest'].failQuest(quest_id)
268DialogueAction.registerAction(FailQuestAction)
269
270
271class RestartQuestAction(QuestAction):
272    """L{QuestAction} used to restart an active quest."""
273    keyword = 'restart_quest'
274   
275    def __call__(self, game_state):
276        """
277        Restart an active quest.
278       
279        @param game_state: variables and functions that make up the current
280            game state.
281        @type game_state: dict of objects
282        """
283        quest_id = self.quest_id
284        print("You've restarted the \"{0}\" quest".format(quest_id))
285        game_state['quest'].restartQuest(quest_id)
286DialogueAction.registerAction(RestartQuestAction)
287
288
289class QuestVariableAction(QuestAction):
290    """
291    Base class for L{QuestActions<QuestAction>} that modify quest
292    variables.
293    """
294    def __init__(self, *args, **kwargs):
295        """
296        Initialize a new L{QuestVariableAction} instance.
297       
298        @param args: positional arguments (not used).
299        @type args: list of objects
300        @param kwargs: keyword arguments.
301        @type kwargs: dict of objects
302        @keyword quest: ID of the quest whose variable should be modified.
303        @type quest: basestring
304        @keyword variable: name of the quest variable to modify.
305        @type variable: basestring
306        @keyword value: new value that should be used to modify the quest
307            variable.
308        @type value: object
309        """
310        QuestAction.__init__(self, *args, **kwargs)
311        self.variable_name = kwargs['variable']
312        self.value = kwargs['value']
313
314
315class IncreaseQuestVariableAction(QuestVariableAction):
316    """
317    L{QuestVariableAction} used to increase the value of a quest variable by a
318    set amount.
319    """
320    keyword = 'increase_quest_variable'
321   
322    def __call__(self, game_state):
323        """
324        Increase a quest variable by a set amount.
325       
326        @param game_state: variables and functions that make up the current
327            game state.
328        @type game_state: dict of objects
329        """
330        quest_id = self.quest_id
331        variable_name = self.variable_name
332        value = self.value
333        print('Increased {0} by {1}'.format(variable_name, value))
334        game_state['quest'][quest_id].increaseValue(variable_name, value)
335DialogueAction.registerAction(IncreaseQuestVariableAction)
336
337
338class DecreaseQuestVariableAction(QuestVariableAction):
339    """
340    L{QuestVariableAction} used to decrease the value of a quest variable by a
341    set amount.
342    """
343    keyword = 'decrease_quest_variable'
344   
345    def __call__(self, game_state):
346        """
347        Decrease a quest variable by a set amount.
348       
349        @param game_state: variables and functions that make up the current
350            game state.
351        @type game_state: dict of objects
352        """
353        quest_id = self.quest_id
354        variable_name = self.variable_name
355        value = self.value
356        print('Decreased {0} by {1}'.format(variable_name, value))
357        game_state['quest'][quest_id].decreaseValue(variable_name, value)
358DialogueAction.registerAction(DecreaseQuestVariableAction)
359
360
361class SetQuestVariableAction(QuestVariableAction):
362    """
363    L{QuestVariableAction} used to set the value of a quest variable.
364    """
365    keyword = 'set_quest_variable'
366   
367    def __call__(self, game_state):
368        """
369        Set the value of a quest variable.
370       
371        @param game_state: variables and functions that make up the current
372            game state.
373        @type game_state: dict of objects
374        """
375        quest_id = self.quest_id
376        variable_name = self.variable_name
377        value = self.value
378        print('Set {0} to {1}'.format(variable_name, value))
379        game_state['quest'][quest_id].setValue(variable_name, value)
380DialogueAction.registerAction(SetQuestVariableAction)
Note: See TracBrowser for help on using the repository browser.