comparison entities/action.py @ 148:2241722311bf

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 objects/action.py@46570c1ee4ca
children 79d6b17b80a3
comparison
equal deleted inserted replaced
147:bb29d81d7ce6 148:2241722311bf
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 #exceptions
17
18 import logging
19
20 logger = logging.getLogger('action')
21
22 from parpg.gui import drag_drop_data as data_drag
23 from parpg.dialoguecontroller import DialogueController
24 from parpg.components import container, lockable
25
26
27 class NoSuchQuestException(Exception):
28 """NoQuestException is used when there is no active quest with the id"""
29 pass
30
31 #classes
32
33 class Action(object):
34 """Base Action class, to define the structure"""
35
36
37 def __init__(self, controller, commands = None):
38 """Basic action constructor
39 @param controller: A reference to the GameSceneController.
40 @type controller: parpg.GameSceneController
41 @param commands: Special commands that are executed
42 @type commands: Dictionary
43 """
44 self.commands = commands or ()
45 self.controller = controller
46 self.model = controller.model
47
48 def execute(self):
49 """To be overwritten"""
50 #Check if there are special commands and execute them
51 for command_data in self.commands:
52 command = command_data["Command"]
53 if command == "SetQuestVariable":
54 quest_id = command_data["ID"]
55 variable = command_data["Variable"]
56 value = command_data["Value"]
57 quest_engine = self.model.game_state.quest_engine
58 if quest_engine.hasQuest(quest_id):
59 quest_engine[quest_id].setValue(variable, value)
60 else:
61 raise NoSuchQuestException
62 elif command == "ResetMouseCursor":
63 self.controller.resetMouseCursor()
64 elif command == "StopDragging":
65 data_drag.dragging = False
66
67 class ChangeMapAction(Action):
68 """A change map scheduled"""
69 def __init__(self, controller, target_map_name, target_pos, commands=None):
70 """Initiates a change of the position of the character
71 possibly flagging a new map to be loaded.
72 @param controller: A reference to the GameSceneController.
73 @type controller: parpg.GameSceneController
74 @param commands: Special commands that are executed
75 @type commands: Dictionary
76 @type view: class derived from parpg.ViewBase
77 @param view: The view
78 @type target_map_name: String
79 @param target_map_name: Target map id
80 @type target_pos: Tuple
81 @param target_pos: (X, Y) coordinates on the target map.
82 @return: None"""
83 super(ChangeMapAction, self).__init__(controller, commands)
84 self.view = controller.view
85 self.target_pos = target_pos
86 self.target_map_name = target_map_name
87
88 def execute(self):
89 """Executes the map change."""
90 self.model.changeMap(self.target_map_name,
91 self.target_pos)
92 super(ChangeMapAction, self).execute()
93
94 class OpenAction(Action):
95 """Open an lockable"""
96 def __init__(self, controller, lockable, commands=None):
97 """
98 @param controller: A reference to the GameSceneController.
99 @type controller: parpg.GameSceneController
100 @param commands: Special commands that are executed
101 @type commands: Dictionary
102 @type view: class derived from parpg.ViewBase
103 @param view: The view
104 @param lockable: A reference to the lockable
105 """
106 Action.__init__(self, controller, commands)
107 self.view = controller.view
108 self.lockable = lockable
109
110 def execute(self):
111 """Open the lockable."""
112 try:
113 lockable.open(self.lockable.lockable)
114 self.lockable.fifeagent.behaviour.animate("open")
115 self.lockable.fifeagent.behaviour.queue_animation("opened",
116 repeating=True)
117 except lockable.LockedError:
118 self.view.hud.createExamineBox(self.lockable.description.view_name,
119 "Locked")
120 Action.execute(self)
121
122 class CloseAction(Action):
123 """Close an lockable"""
124 def __init__(self, controller, lockable, commands=None):
125 """
126 @param controller: A reference to the GameSceneController.
127 @type controller: parpg.GameSceneController
128 @param commands: Special commands that are executed
129 @type commands: Dictionary
130 @type view: class derived from parpg.ViewBase
131 @param view: The view
132 @param lockable: A reference to the lockable
133 """
134 Action.__init__(self, controller, commands)
135 self.lockable = lockable
136
137 def execute(self):
138 """Close the lockable."""
139 lockable.close(self.lockable.lockable)
140 self.lockable.fifeagent.behaviour.animate("close")
141 self.lockable.fifeagent.behaviour.queue_animation("closed",
142 repeating=True)
143 Action.execute(self)
144
145 class UnlockAction(Action):
146 """Unlocks a lockable."""
147 def __init__(self, controller, lockable, commands = None):
148 """
149 @param controller: A reference to the GameSceneController.
150 @type controller: parpg.GameSceneController
151 @param commands: Special commands that are executed
152 @type commands: Dictionary
153 @param lockable: A reference to the lockable
154 """
155 Action.__init__(self, controller, commands)
156 self.lockable = lockable
157
158 def execute(self):
159 """Open the box."""
160 lockable.unlock(self.lockable.lockable)
161 Action.execute(self)
162
163 class LockAction(Action):
164 """Locks a lockable."""
165 def __init__(self, controller, lockable, commands = None):
166 """
167 @param controller: A reference to the GameSceneController.
168 @type controller: parpg.GameSceneController
169 @param commands: Special commands that are executed
170 @type commands: Dictionary
171 @param lockable: A reference to the lockable
172 """
173 Action.__init__(self, controller, commands)
174 self.lockable = lockable
175 self.view = controller.view
176
177 def execute(self):
178 """Lock the box."""
179 try:
180 lockable.lock(self.lockable.lockable)
181 except lockable.OpenError:
182 self.view.hud.createExamineBox(self.lockable.description.view_name,
183 "Is open")
184
185 Action.execute(self)
186
187
188 class ExamineAction(Action):
189 """Examine an object."""
190 def __init__(self, controller, examine_id, examine_name, examine_desc=None, commands=None):
191 """
192 @param controller: A reference to the GameSceneController.
193 @type controller: parpg.GameSceneController
194 @param examine_id: An object id
195 @type examine_id: integer
196 @param examine_name: An object name
197 @type examine_name: string
198 @param examine_desc: A description of the object that will be displayed.
199 @type examine_desc: string
200 @param commands: Special commands that are executed
201 @type commands: Dictionary
202 """
203 super(ExamineAction, self).__init__(controller, commands)
204 self.view = controller.view
205 self.examine_id = examine_id
206 self.examine_name = examine_name
207 if examine_desc is not None:
208 self.examine_desc = examine_desc
209 else:
210 self.examine_desc = "No Description"
211
212 def execute(self):
213 """Display the text."""
214 action_text = self.examine_desc
215 self.view.hud.addAction(unicode(action_text))
216 logger.debug(action_text)
217 #this code will cut the line up into smaller lines that will be displayed
218 place = 25
219 while place < len(action_text):
220 if action_text[place] == ' ':
221 action_text = action_text[:place] +'\n'+action_text[place:]
222 place += 26 #plus 1 character to offset the new line
223 else: place += 1
224 self.view.displayObjectText(self.examine_id, unicode(action_text), time=3000)
225 Action.execute(self)
226
227 class ExamineItemAction(Action):
228 """Examine an item."""
229 def __init__(self, controller, examine_name, examine_desc, commands = None):
230 """
231 @param controller: A reference to the GameSceneController.
232 @type controller: parpg.GameSceneController
233 @param commands: Special commands that are executed
234 @type commands: Dictionary
235 @type view: class derived from parpg.ViewBase
236 @param view: The view
237 @type examine_name: String
238 @param examine_name: Name of the object to be examined.
239 @type examine_name: String
240 @param examine_name: Description of the object to be examined.
241 """
242 super(ExamineItemAction, self).__init__(controller, commands)
243 self.view = controller.view
244 self.examine_name = examine_name
245 self.examine_desc = examine_desc
246
247 def execute(self):
248 """Display the text."""
249 action_text = unicode(self.examine_desc)
250 self.view.hud.addAction(action_text)
251 logger.debug(action_text)
252 Action.execute(self)
253
254 class ExamineContentsAction(Action):
255 """Examine the contens of an container"""
256 def __init__(self, controller, container, commands=None):
257 """
258 @param controller: A reference to the GameSceneController.
259 @type controller: parpg.GameSceneController
260 @param container: The container
261 @type container: parpg.entities.General
262 @param commands: Special commands that are executed
263 @type commands: Dictionary
264 """
265 Action.__init__(self, controller, commands)
266 self.view = controller.view
267 self.container = container
268
269 def execute(self):
270 """Examine the contents"""
271 self.view.hud.createBoxGUI(self.container.description.view_name,
272 self.container.container)
273 Action.execute(self)
274
275 class ReadAction(Action):
276 """Read a text."""
277 def __init__(self, controller, text_name, text, commands = None):
278 """
279 @param controller: A reference to the GameSceneController.
280 @type controller: parpg.GameSceneController
281 @param commands: Special commands that are executed
282 @type commands: Dictionary
283 @param view: The view
284 @type view: class derived from parpg.ViewBase
285 @param text_name: Name of the object containing the text
286 @type text_name: String
287 @param text: Text to be displayied
288 @type text: String
289 """
290 super(ReadAction, self).__init__(controller, commands)
291 self.view = controller.view
292 self.text_name = text_name
293 self.text = text
294
295 def execute(self):
296 """Examine the box."""
297 action_text = unicode('\n'.join(["You read " + self.text_name + ".",
298 self.text]))
299 self.view.hud.addAction(action_text)
300 logger.debug(action_text)
301 super(ReadAction, self).execute()
302
303 class TalkAction(Action):
304 """An action to represent starting a dialogue"""
305 def __init__(self, controller, npc, commands = None):
306 """
307 @param controller: A reference to the GameSceneController.
308 @type controller: parpg.GameSceneController
309 @param commands: Special commands that are executed
310 @type commands: Dictionary
311 @type view: class derived from parpg.ViewBase
312 @param view: The view
313 @type npc: NonPlayerCharacter
314 @param npc: NPC to interact with.
315 """
316 super(TalkAction, self).__init__(controller, commands)
317 self.view = controller.view
318 self.npc = npc
319
320 def execute(self):
321 """Talk with the NPC when close enough, otherwise move closer.
322 @return: None"""
323 player_char = self.model.game_state.\
324 getObjectById("PlayerCharacter").fifeagent
325 npc_coordinates = self.npc.fifeagent.behaviour.getLocation().\
326 getLayerCoordinates()
327 pc_coordinates = player_char.behaviour.agent.\
328 getLocation().getLayerCoordinates()
329
330 distance_squared = (npc_coordinates.x - pc_coordinates.x) *\
331 (npc_coordinates.x - pc_coordinates.x) +\
332 (npc_coordinates.y - pc_coordinates.y) *\
333 (npc_coordinates.y - pc_coordinates.y)
334
335 # If we are too far away, we approach the NPC again
336 if distance_squared > 2:
337 player_char.behaviour.approach(
338 [npc_coordinates.x, npc_coordinates.y],
339 TalkAction(self.controller,
340 self.npc,
341 self.commands
342 )
343 )
344 else:
345 player_char.behaviour.agent.act(
346 'stand',
347 self.npc.fifeagent.behaviour.getLocation()
348 )
349
350 if self.npc.dialogue.dialogue is not None:
351 dialogue_controller = DialogueController(
352 self.controller.engine,
353 self.view,
354 self.model,
355 self.controller.application
356 )
357 self.controller.application.manager.push_mode(
358 dialogue_controller
359 )
360 dialogue_controller.startTalk(self.npc)
361 else:
362 self.npc.fifeagent.behaviour.agent.say("Leave me alone!", 1000)
363
364 self.model.game_state.getObjectById("PlayerCharacter").\
365 fifeagent.behaviour.idle()
366 self.model.game_state.getObjectById("PlayerCharacter").\
367 fifeagent.behaviour.nextAction = None
368 super(TalkAction, self).execute()
369
370 class UseAction(Action):
371 """Action for carryable items. It executes special commands that can be only
372 used on carryable utens"""
373
374
375 def __init__(self, controller, item, commands = None):
376 """
377 @param controller: A reference to the GameSceneController.
378 @type controller: parpg.GameSceneController
379 @param item: Item on which the action is called
380 @type item: CarryableItem
381 @param commands: Special commands that are executed
382 @type commands: Dictionary
383 """
384 super(UseAction, self).__init__(controller, commands)
385 self.view = controller.view
386 self.item = item
387
388 def execute(self):
389 #Check if there are special commands and execute them
390 for command_data in self.commands:
391 command = command_data["Command"]
392 if command == "ReplaceItem":
393 object_id = command_data["ID"]
394 object_type = command_data["ObjectType"]
395 containable = self.item.containable
396 new_item = self.model.createItemByType(object_type,
397 object_id,
398 self.item.world)
399 container.put_item(containable.container,
400 new_item.containable,
401 containable.slot)
402 self.model.deleteObject(self.item.general.identifier)
403 self.item.delete()
404 self.view.hud.inventory.updateImages()
405 super(UseAction, self).execute()
406
407 class PickUpAction(Action):
408 """Action for picking up items from a map"""
409
410 def __init__(self, controller, item, commands = None):
411 super(PickUpAction, self).__init__(controller, commands)
412 self.item = item
413 self.view = controller.view
414
415 def execute(self):
416 real_item = self.item.containable
417 self.item.fifeagent = None
418 player = self.model.game_state.getObjectById("PlayerCharacter")
419 self.model.moveObject(self.item.general.identifier, None)
420 self.model.updateObjectDB(self.item.world)
421 container.put_item(player.container, real_item)
422 super(PickUpAction, self).execute()
423
424 class DropItemAction(Action):
425 """Action for dropping an items on a map"""
426 def __init__(self, controller, item, commands = None):
427 super(DropItemAction, self).__init__(controller, commands)
428 self.item = item
429
430 def execute(self):
431 map_name = self.model.game_state.current_map_name
432 identifier = self.item.entity.general.identifier
433 agent_values = self.model.items[identifier]
434 coords = (self.model.game_state.getObjectById("PlayerCharacter").
435 fifeagent.behaviour.getLocation().getExactLayerCoordinates()
436 )
437 agent_values["Position"] = (coords.x, coords.y)
438 agent_values["Rotation"] = 0
439 agent_values["Map"] = map_name
440 self.model.deleteObject(identifier)
441 self.model.addAgent(self.model.ALL_AGENTS_KEY,
442 {identifier: agent_values})
443 self.model.placeAgents(self.item.entity.world)
444 self.model.updateObjectDB(self.item.entity.world)
445 super(DropItemAction, self).execute()
446
447 class DropItemFromContainerAction(DropItemAction):
448 """Action for dropping an items from the Inventory to a map"""
449
450 def __init__(self, controller, item, container_gui, commands = None):
451 super(DropItemFromContainerAction, self).__init__(controller, item, commands)
452 self.container_gui = container_gui
453
454 def execute(self):
455 super(DropItemFromContainerAction, self).execute()
456 container.remove_item(self.item.container, self.item.slot)
457 self.container_gui.updateImages()
458
459 class BrewBeerAction(Action):
460 """Action for brewing beer in a pot"""
461 def __init__(self, controller, pot, commands = None):
462 super(BrewBeerAction, self).__init__(controller, commands)
463 self.pot = pot.container
464 self.view = controller.view
465
466 def execute(self):
467 """Brew the beer"""
468 has_water = False
469 has_yeast = False
470 has_fruit = False
471 has_wood = False
472 has_bottle = False
473 player_character = (self.model.game_state.
474 getObjectById("PlayerCharacter").container)
475 for item in self.pot.children:
476 if not item:
477 continue
478 if item.item_type == "Questionable water":
479 if has_water:
480 self.view.hud.addAction(unicode(\
481 "Please put only 1 water in the pot"))
482 return
483 has_water = True
484 water_type = 1
485 water = item
486 elif item.item_type == "Pure water":
487 if has_water:
488 self.view.hud.addAction(unicode(\
489 "Please put only 1 water in the pot"))
490 return
491 has_water = True
492 water_type = 2
493 water = item
494 elif item.item_type == "Grain":
495 if has_fruit:
496 self.view.hud.addAction(unicode(\
497 "Please put only 1 fruit in the pot"))
498 return
499 has_fruit = True
500 fruit_type = 3
501 fruit = item
502 elif item.item_type == "Wild potato":
503 if has_fruit:
504 self.view.hud.addAction(unicode(\
505 "Please put only 1 fruit in the pot"))
506 return
507 has_fruit = True
508 fruit_type = 2
509 fruit = item
510 elif item.item_type == "Rotten yam":
511 if has_fruit:
512 self.view.hud.addAction(unicode(\
513 "Please put only 1 fruit in the pot"))
514 return
515 has_fruit = True
516 fruit_type = 1
517 fruit = item
518 elif item.item_type == "Yeast":
519 if has_yeast:
520 self.view.hud.addAction(unicode(\
521 "Please put only 1 yeast in the pot"))
522 return
523 has_yeast = True
524 yeast = item
525 else:
526 self.view.hud.addAction(unicode(
527 "Item " + (item.entity.description.view_name) +
528 " is not needed for brewing beer"))
529 self.view.hud.addAction(unicode(\
530 "Please put only ingredients for the beer in the pot.\
531 Things like bottles and wood have to be in your inventory"))
532 return
533 wood = container.get_item(player_character, "Wood")
534 if wood:
535 has_wood = True
536 bottle = container.get_item(player_character, "Empty beer bottle")
537 if bottle:
538 has_bottle = True
539 if has_water and has_fruit and has_wood and has_bottle:
540 container.remove_item(self.pot, water.slot)
541 container.remove_item(self.pot, fruit.slot)
542 if has_yeast:
543 container.remove_item(self.pot, yeast.slot)
544 container.remove_item(player_character, wood.slot)
545 new_item = (self.model.createItemByType("Beer", "Beer",
546 self.pot.entity.world)
547 )
548 container.put_item(player_character, new_item.containable)
549 self.view.hud.inventory.updateImages()
550 beer_quality = 0
551 if water_type == 1:
552 if fruit_type == 1:
553 beer_quality = -1
554 elif fruit_type == 2:
555 beer_quality = 2
556 elif fruit_type == 3:
557 beer_quality = 3
558 if water_type == 2:
559 if fruit_type == 1:
560 beer_quality = 1
561 elif fruit_type == 2:
562 beer_quality = 3
563 elif fruit_type == 3:
564 beer_quality = 4
565 if beer_quality > 0 and has_yeast:
566 beer_quality += 1
567 self.model.game_state.quest_engine.quests["beer"].\
568 setValue("beer_quality", beer_quality)
569 else:
570 self.view.hud.addAction(unicode(
571 """For brewing beer you need at least:
572 In the pot:
573 Fruit (like grain, potato, yam)
574 Water
575 Optionally:
576 Good quality yeast.
577 Wild yeast will be used if none present.
578 In the inventory:
579 Wood
580 Empty bottle"""))
581 super(BrewBeerAction, self).execute()
582
583 ACTIONS = {"ChangeMap":ChangeMapAction,
584 "Open":OpenAction,
585 "Close":CloseAction,
586 "Unlock":UnlockAction,
587 "Lock":LockAction,
588 "ExamineItem":ExamineItemAction,
589 "Examine":ExamineAction,
590 "Look":ExamineItemAction,
591 "Read":ReadAction,
592 "Talk":TalkAction,
593 "Use":UseAction,
594 "PickUp":PickUpAction,
595 "DropFromInventory":DropItemFromContainerAction,
596 "BrewBeer":BrewBeerAction,
597 "ExamineContents": ExamineContentsAction,
598 }