source: trunk/game/scripts/objects/action.py @ 618

Revision 618, 21.1 KB checked in by beliar, 9 years ago (diff)

Patch by Beliar.

  • Added messages to ignore to pylintrc
  • Fixed error when marking a quest as finished/failed
  • It is now possible to brew the beer required for a quest. For now this does not need any special requirements, like having the quest active or read the pamphlet, but to make the best quality beer you need an ingredient you can only get if you have the quest and read the pamphlet. Most ingredients can be found if you look around on the maps. This makes the "Beer" quest finishable!
  • Property svn:eol-style set to native
Line 
1#!/usr/bin/env python
2#   This file is part of PARPG.
3
4#   PARPG is free software: you can redistribute it and/or modify
5#   it under the terms of the GNU General Public License as published by
6#   the Free Software Foundation, either version 3 of the License, or
7#   (at your option) any later version.
8
9#   PARPG is distributed in the hope that it will be useful,
10#   but WITHOUT ANY WARRANTY; without even the implied warranty of
11#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12#   GNU General Public License for more details.
13
14#   You should have received a copy of the GNU General Public License
15#   along with PARPG.  If not, see <http://www.gnu.org/licenses/>.
16
17#exceptions
18
19from scripts.gui import drag_drop_data as data_drag
20
21class NoSuchQuestException(Exception):
22    """NoQuestException is used when there is no active quest with the id"""
23    pass
24
25#classes
26
27class Action(object):
28    """Base Action class, to define the structure"""
29
30
31    def __init__(self, controller, commands = None):
32        """Basic action constructor
33        @param controller: A reference to the GameSceneController.
34        @type controller: scripts.GameSceneController
35        @param commands: Special commands that are executed
36        @type commands: Dictionary
37        """
38        self.commands = commands or ()
39        self.controller = controller
40        self.model = controller.model
41   
42    def execute(self):
43        """To be overwritten"""       
44        #Check if there are special commands and execute them
45        for command_data in self.commands:
46            command = command_data["Command"]
47            if command == "SetQuestVariable":
48                quest_id = command_data["ID"]
49                variable = command_data["Variable"]
50                value = command_data["Value"]
51                quest_engine = self.model.game_state.quest_engine
52                if quest_engine.hasQuest(quest_id):
53                    quest_engine[quest_id].setValue(variable, value)
54                else:
55                    raise NoSuchQuestException
56            elif command == "ResetMouseCursor":
57                self.controller.resetMouseCursor()
58            elif command == "StopDragging":
59                data_drag.dragging = False
60               
61class ChangeMapAction(Action):
62    """A change map scheduled"""
63    def __init__(self, controller, target_map_name, target_pos, commands = None):
64        """Initiates a change of the position of the character
65        possibly flagging a new map to be loaded.
66        @param controller: A reference to the GameSceneController.
67        @type controller: scripts.GameSceneController
68        @param commands: Special commands that are executed
69        @type commands: Dictionary
70        @type view: class derived from scripts.ViewBase
71        @param view: The view
72        @type target_map_name: String
73        @param target_map_name: Target map id
74        @type target_pos: Tuple
75        @param target_pos: (X, Y) coordinates on the target map.
76        @return: None"""
77        super(ChangeMapAction, self).__init__(controller, commands)
78        self.view = controller.view
79        self.target_pos = target_pos
80        self.target_map_name = target_map_name
81
82    def execute(self):
83        """Executes the map change."""
84        self.model.changeMap(self.target_map_name,
85                              self.target_pos)
86        super(ChangeMapAction, self).execute()
87
88class OpenAction(Action):
89    """Open a container"""
90    def __init__(self, controller, container, commands = None):
91        """
92        @param controller: A reference to the GameSceneController.
93        @type controller: scripts.GameSceneController
94        @param commands: Special commands that are executed
95        @type commands: Dictionary
96        @type view: class derived from scripts.ViewBase
97        @param view: The view
98        @param container: A reference to the container
99        """
100        super(OpenAction, self).__init__(controller, commands)
101        self.view = controller.view
102        self.container = container
103    def execute(self):
104        """Open the box."""
105        self.view.hud.createBoxGUI(self.container.name, \
106                                              self.container)
107        super(OpenAction, self).execute()
108       
109       
110class OpenBoxAction(OpenAction):
111    """Open a box. Needs to be more generic, but will do for now."""
112    def __init__(self, controller, container, commands = None):
113        """
114        @param controller: A reference to the GameSceneController.
115        @type controller: scripts.GameSceneController
116        @param commands: Special commands that are executed
117        @type commands: Dictionary
118        @type view: class derived from scripts.ViewBase
119        @param view: The view
120        @param container: A reference to the container
121        """
122        super(OpenBoxAction, self).__init__(controller, commands)
123        self.view = controller.view
124        self.container = container
125       
126    def execute(self):
127        """Open the box."""
128        try:
129            self.container.open()
130            super(OpenBoxAction, self).execute()
131
132        except ValueError:
133            self.view.hud.createExamineBox(self.container.name, \
134                                                  "The container is locked")
135       
136class UnlockBoxAction(Action):
137    """Unlocks a box. Needs to be more generic, but will do for now."""
138    def __init__(self, controller, container, commands = None):
139        """
140        @param controller: A reference to the GameSceneController.
141        @type controller: scripts.GameSceneController
142        @param commands: Special commands that are executed
143        @type commands: Dictionary
144        @param container: A reference to the container
145        """
146        super(UnlockBoxAction, self).__init__(controller, commands)
147        self.container = container
148   
149    def execute(self):
150        """Open the box."""
151        self.container.unlock()
152        super(UnlockBoxAction, self).execute()
153       
154class LockBoxAction(Action):
155    """Locks a box. Needs to be more generic, but will do for now."""
156    def __init__(self, controller, container, commands = None):
157        """
158        @param controller: A reference to the GameSceneController.
159        @type controller: scripts.GameSceneController
160        @param commands: Special commands that are executed
161        @type commands: Dictionary
162        @param container: A reference to the container
163        """
164        super(LockBoxAction, self).__init__(controller, commands)
165        self.container = container
166       
167    def execute(self):
168        """Lock the box."""
169        self.container.lock()
170        super(LockBoxAction, self).execute()
171
172
173class ExamineAction(Action):
174    """Examine an object."""
175    def __init__(self, controller, examine_id, examine_name, examine_desc, commands = None):
176        """
177        @param controller: A reference to the GameSceneController.
178        @type controller: scripts.GameSceneController
179        @param examine_id: An object id
180        @type examine_id: integer
181        @param examine_name: An object name
182        @type examine_name: string
183        @param examine_desc: A description of the object that will be displayed.
184        @type examine_desc: string
185        @param commands: Special commands that are executed
186        @type commands: Dictionary
187        @type view: class derived from scripts.ViewBase
188        @param view: The view
189       
190        """
191        super(ExamineAction, self).__init__(controller, commands)
192        self.view = controller.view
193        self.examine_id = examine_id
194        self.examine_name = examine_name
195        self.examine_desc = examine_desc
196       
197    def execute(self):
198        """Display the text."""
199        action_text = self.examine_desc
200        self.view.hud.addAction(unicode(action_text))
201        print action_text
202        #this code will cut the line up into smaller lines that will be displayed
203        place = 25
204        while place <= len(action_text):
205            if action_text[place] == ' ':
206                action_text = action_text[:place] +'\n'+action_text[place:]
207                place += 26 #plus 1 character to offset the new line
208            else: place += 1
209        self.view.displayObjectText(self.examine_id, unicode(action_text), time=3000)
210
211class ExamineItemAction(Action):
212    """Examine an item."""
213    def __init__(self, controller, examine_name, examine_desc, commands = None):
214        """
215        @param controller: A reference to the GameSceneController.
216        @type controller: scripts.GameSceneController
217        @param commands: Special commands that are executed
218        @type commands: Dictionary
219        @type view: class derived from scripts.ViewBase
220        @param view: The view
221        @type examine_name: String
222        @param examine_name: Name of the object to be examined.
223        @type examine_name: String
224        @param examine_name: Description of the object to be examined.
225        """
226        super(ExamineItemAction, self).__init__(controller, commands)
227        self.view = controller.view
228        self.examine_name = examine_name
229        self.examine_desc = examine_desc
230       
231    def execute(self):
232        """Display the text."""
233        action_text = unicode(self.examine_desc)
234        self.view.hud.addAction(action_text)
235        print action_text
236
237class ReadAction(Action):
238    """Read a text."""
239    def __init__(self, controller, text_name, text, commands = None):
240        """
241        @param controller: A reference to the GameSceneController.
242        @type controller: scripts.GameSceneController
243        @param commands: Special commands that are executed
244        @type commands: Dictionary
245        @param view: The view
246        @type view: class derived from scripts.ViewBase
247        @param text_name: Name of the object containing the text
248        @type text_name: String
249        @param text: Text to be displayied
250        @type text: String
251        """
252        super(ReadAction, self).__init__(controller, commands)
253        self.view = controller.view
254        self.text_name = text_name
255        self.text = text
256       
257    def execute(self):
258        """Examine the box."""
259        action_text = unicode('\n'.join(["You read " + self.text_name + ".", 
260                                         self.text]))
261        self.view.hud.addAction(action_text)
262        print action_text
263        super(ReadAction, self).execute()
264
265class TalkAction(Action):
266    """An action to represent starting a dialogue"""
267    def __init__(self, controller, npc, commands = None):
268        """
269        @param controller: A reference to the GameSceneController.
270        @type controller: scripts.GameSceneController
271        @param commands: Special commands that are executed
272        @type commands: Dictionary
273        @type view: class derived from scripts.ViewBase
274        @param view: The view
275        @type npc: NonPlayerCharacter
276        @param npc: NPC to interact with.
277        """
278        super(TalkAction, self).__init__(controller, commands)
279        self.view = controller.view
280        self.npc = npc
281       
282    def execute(self):
283        """Talk with the NPC when close enough, otherwise move closer.
284           @return: None"""
285     
286        player_char = self.model.game_state.player_character
287        npc_coordinates = self.npc.getLocation().getLayerCoordinates()
288        pc_coordinates = player_char.behaviour.agent.\
289                            getLocation().getLayerCoordinates()
290       
291        distance_squared = (npc_coordinates.x - pc_coordinates.x) *\
292                           (npc_coordinates.x - pc_coordinates.x) +\
293                           (npc_coordinates.y - pc_coordinates.y) *\
294                           (npc_coordinates.y - pc_coordinates.y)
295       
296        # If we are too far away, we approach the NPC again
297        if distance_squared > 2:
298            player_char.approach([self.npc.getLocation().
299                         getLayerCoordinates().x,
300                         self.npc.getLocation().
301                         getLayerCoordinates().y], 
302                        TalkAction(self.controller,
303                                   self.npc, self.commands))       
304        else:
305            player_char.behaviour.agent.act('stand', self.npc.getLocation())
306   
307            if self.npc.dialogue is not None:
308                self.npc.talk(player_char)
309                self.view.hud.showDialogue(self.npc)
310            else:
311                self.npc.behaviour.agent.say("Leave me alone!", 1000)
312               
313            self.model.game_state.player_character.behaviour.idle()
314            self.model.game_state.player_character.nextAction = None
315            super(TalkAction, self).execute()
316
317class UseAction(Action):
318    """Action for carryable items. It executes special commands that can be only
319    used on carryable utens"""
320
321
322    def __init__(self, controller, item, commands = None):
323        """
324        @param controller: A reference to the GameSceneController.
325        @type controller: scripts.GameSceneController
326        @param item: Item on which the action is called
327        @type item: CarryableItem
328        @param commands: Special commands that are executed
329        @type commands: Dictionary
330        """
331        super(UseAction, self).__init__(controller, commands)
332        self.view = controller.view
333        self.item = item
334   
335    def execute(self):
336        #Check if there are special commands and execute them
337        for command_data in self.commands:
338            command = command_data["Command"]
339            if command == "ReplaceItem":
340                object_id = command_data["ID"]
341                object_type = command_data["ObjectType"]
342                container = self.item.in_container
343                inst_dict = {}
344                inst_dict["ID"] = object_id
345                inst_dict["object_type"] = object_type
346                new_item = self.model.createContainerObject(inst_dict)
347                container.replaceItem(self.item, new_item)
348                self.view.hud.inventory.updateInventoryButtons()
349        super(UseAction, self).execute()
350
351class PickUpAction(Action):
352    """Action for picking up items from a map"""
353
354    def __init__(self, controller, map_item, commands = None):
355        super(PickUpAction, self).__init__(controller, commands)
356        self.map_item = map_item
357        self.view = controller.view
358       
359    def execute(self):
360        real_item = self.map_item.item
361        self.model.deleteObject(self.map_item.ID)
362        self.model.game_state.player_character.\
363                                inventory.placeItem(real_item)
364        self.view.hud.inventory.updateInventoryButtons()
365        super(PickUpAction, self).execute()
366
367class DropItemAction(Action):
368    """Action for dropping an items on a map"""
369    def __init__(self, controller, item, commands = None):
370        super(DropItemAction, self).__init__(controller, commands)
371        self.item = item
372       
373    def execute(self):
374        map_name = self.model.game_state.current_map_name
375        map_item_values = {}
376        map_item_values["ViewName"] = self.item.name
377        map_item_values["ObjectType"] = "MapItem"
378        map_item_values["ItemType"] = self.item.item_type
379        map_item_values["Map"] = map_name
380        coords = self.model.game_state.player_character.\
381                                        getLocation().getExactLayerCoordinates()
382        map_item_values["Position"] = (coords.x, coords.y)
383        map_item_values["Rotation"] = 0
384        map_item_values["item"] = self.item
385        agent = {}
386        agent[self.item.ID] = map_item_values
387        self.model.addAgent("All", agent)
388        self.model.placeAgents()
389        super(DropItemAction, self).execute()
390       
391class DropItemFromContainerAction(DropItemAction):
392    """Action for dropping an items from the Inventory to a map"""
393
394    def __init__(self, controller, item, container_gui, commands = None):
395        super(DropItemFromContainerAction, self).__init__(controller, item, commands)
396        self.container_gui = container_gui
397
398    def execute(self):
399        super(DropItemFromContainerAction, self).execute()
400        self.item.in_container.takeItem(self.item)
401        self.container_gui.updateImages()
402       
403class BrewBeerAction(Action):
404    """Action for brewing beer in a pot"""
405    def __init__(self, controller, pot, commands = None):
406        super(BrewBeerAction, self).__init__(controller, commands)
407        self.pot = pot
408        self.view = controller.view
409       
410    def execute(self):
411        """Brew the beer"""
412        has_water = False
413        has_yeast = False
414        has_fruit = False
415        has_wood = False
416        has_bottle = False
417        player_character = self.model.game_state.player_character
418        for item in self.pot.items.itervalues():
419            if item.item_type == "Questionable water":
420                if has_water:
421                    self.view.hud.addAction(unicode(\
422                        "Please put only 1 water in the pot"))
423                    return
424                has_water = True
425                water_type = 1 
426                water = item
427            elif item.item_type == "Pure water":
428                if has_water:
429                    self.view.hud.addAction(unicode(\
430                        "Please put only 1 water in the pot"))
431                    return
432                has_water = True
433                water_type = 2
434                water = item
435            elif item.item_type == "Grain":
436                if has_fruit:
437                    self.view.hud.addAction(unicode(\
438                        "Please put only 1 fruit in the pot"))
439                    return
440                has_fruit = True
441                fruit_type = 3
442                fruit = item
443            elif item.item_type == "Wild potato":
444                if has_fruit:
445                    self.view.hud.addAction(unicode(\
446                        "Please put only 1 fruit in the pot"))
447                    return
448                has_fruit = True
449                fruit_type = 2
450                fruit = item
451            elif item.item_type == "Rotten yam":
452                if has_fruit:
453                    self.view.hud.addAction(unicode(\
454                        "Please put only 1 fruit in the pot"))
455                    return
456                has_fruit = True
457                fruit_type = 1
458                fruit = item
459            elif item.item_type == "Yeast":
460                if has_yeast:
461                    self.view.hud.addAction(unicode(\
462                        "Please put only 1 yeast in the pot"))
463                    return
464                has_yeast = True
465                yeast = item
466            else:
467                self.view.hud.addAction(unicode("Item " + item.name + \
468                                                " is not needed for brewing beer"))
469                self.view.hud.addAction(unicode(\
470                    "Please put only ingredients for the beer in the pot.\
471                    Things like bottles and wood have to be in your inventory"))
472                return
473        wood = player_character.hasItem("Wood")
474        if wood:
475            has_wood = True       
476        bottle = player_character.hasItem("Empty beer bottle")
477        if bottle:
478            has_bottle = True       
479        if has_water and has_fruit and has_wood and has_bottle:
480            self.pot.removeItem(water)
481            self.pot.removeItem(fruit)
482            if has_yeast:
483                self.pot.removeItem(yeast)
484            player_character.inventory.removeItem(wood)
485            inst_dict = {}
486            inst_dict["ID"] = "Beer"
487            inst_dict["object_type"] = "Beer"
488            new_item = self.model.createContainerObject(inst_dict)
489            player_character.inventory.placeItem(new_item)
490            self.view.hud.inventory.updateInventoryButtons()
491            beer_quality = 0
492            if water_type == 1:
493                if fruit_type == 1:
494                    beer_quality = -1
495                elif fruit_type == 2:
496                    beer_quality = 2
497                elif fruit_type == 3:
498                    beer_quality = 3
499            if water_type == 2:
500                if fruit_type == 1:
501                    beer_quality = 1
502                elif fruit_type == 2:
503                    beer_quality = 3
504                elif fruit_type == 3:
505                    beer_quality = 4
506            if beer_quality > 0 and has_yeast:
507                beer_quality += 1
508            self.model.game_state.quest_engine.quests["beer"].\
509                    setValue("beer_quality", beer_quality)
510        else:
511            self.view.hud.addAction(unicode(
512            """For brewing beer you need at least:
513            In the pot:
514                Fruit (like grain, potato, yam)
515                Water
516                Optionally:
517                    Good quality yeast.
518                    Wild yeast will be used if none present.
519            In the inventory:
520                Wood
521                Empty bottle"""))
522        super(BrewBeerAction, self).execute()
523
524ACTIONS = {"ChangeMap":ChangeMapAction, 
525           "Open":OpenAction,
526           "OpenBox":OpenBoxAction, 
527           "Unlock":UnlockBoxAction,
528           "Lock":LockBoxAction,
529           "ExamineItem":ExamineItemAction,
530           "Examine":ExamineAction,
531           "Look":ExamineItemAction,
532           "Read":ReadAction,
533           "Talk":TalkAction,
534           "Use":UseAction,
535           "PickUp":PickUpAction,
536           "DropFromInventory":DropItemFromContainerAction,
537           "BrewBeer":BrewBeerAction}
Note: See TracBrowser for help on using the repository browser.