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