source: trunk/game/scripts/world.py @ 366

Revision 361, 12.9 KB checked in by orlandov, 10 years ago (diff)

Ticket #104 - Patch by Vaporice and or1andov. Integrate quests into game dialogue and make it possible to persist quest state. fixes[s:trac, t:134]

  • Integrate Vaporice's quest engine implementation
  • Discontinue or1andov's sample dialogue and use Zenbitz's Drunkard
  • Reuse Zenbitz's dialogue functions and callbacks in the game PlayerCharacter? class
  • Whitespace and style tweaks
  • Property svn:eol-style set to native
Line 
1#!/usr/bin/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
18import time
19import fife
20import pychan
21from sounds import SoundEngine
22from datetime import date
23from scripts.common.eventlistenerbase import EventListenerBase
24from local_loaders.loaders import loadMapFile
25from sounds import SoundEngine
26from settings import Setting
27from scripts import hud
28from scripts.popups import *
29from pychan.tools import callbackWithArguments as cbwa
30from map import Map
31
32TDS = Setting()
33
34# this file should be the meta-file for all FIFE-related code
35# engine.py handles is our data model, whilst this is our view
36# in order to not replicate data, some of our data model will naturally
37# reside on this side of the fence (PC xpos and ypos, for example).
38# we should aim to never replicate any data as this leads to maintenance
39# issues (and just looks plain bad).
40# however, any logic needed to resolve this should sit in engine.py
41
42class World(EventListenerBase):
43    """World holds the data needed by fife to render the engine
44       The engine keeps a copy of this class"""
45    def __init__(self, engine):
46        """Constructor for engine
47           @type engine: fife.Engine
48           @param engine: A fife.Engine instance
49           @return: None"""
50        super(World, self).__init__(engine, reg_mouse=True, reg_keys=True)
51        # self.engine is a fife.Engine object, not an Engine object
52        self.engine = engine
53        self.event_manager = engine.getEventManager()
54        self.quitFunction = None
55
56        # self.data is an engine.Engine object, but is set in run.py
57        self.data = None
58        self.mouseCallback = None
59
60        # self.map is a Map object, set to none here
61        self.active_map = None
62        self.maps = {}
63
64        self.action_number = 1
65
66        # init the sound
67        self.sounds = SoundEngine(engine)
68
69        # don't force restart if skipping to new section
70        if TDS.readSetting("PlaySounds") == "1":
71            if not self.sounds.music_init:
72                self.sounds.playMusic("/music/preciouswasteland.ogg")
73
74        # The current highlighted object
75        self.highlight_obj = None
76       
77        # Last saved mouse coords
78        self.last_mousecoords = None
79
80    def initHud(self):
81        """Initialize the hud member
82        @return: None"""
83        # setup the inventory model
84        # make slot 'A1' and 'A3' container daggers
85        inv_model = {'A1':'dagger01', 'A3':'dagger01'}
86
87        hud_callbacks = {
88            'saveGame': self.saveGame,
89            'loadGame': self.loadGame,
90            'quitGame': self.quitGame,
91        }
92        self.hud = hud.Hud(self.engine, TDS, inv_model, self.data, hud_callbacks)
93   
94    def quitGame(self):
95        """Quits the game
96        @return: None"""
97        self.quitFunction()
98
99    def saveGame(self, *args, **kwargs):
100        """Saves the game state, delegates call to engine.Engine
101           @return: None"""
102        self.data.save(*args, **kwargs)
103
104    def loadGame(self, *args, **kwargs):
105        """Loads the game state, delegates call to engine.Engine
106           @return: None"""
107        self.data.load(*args, **kwargs)
108
109    def loadMap(self, map_name, filename):
110        """Loads a map and stores it under the given name in the maps list.
111           @type map_name: String
112           @param map_name: The name of the map to load
113           @type filename: String
114           @param filename: File which contains the map to be loaded
115           @return: None"""
116        if not map_name in self.maps:
117            map = Map(self.engine, self.data)
118            self.maps[map_name] = map
119            map.load(filename)
120        else:
121            self.setActiveMap(map_name)
122
123    def setActiveMap(self, map_name):
124        """Sets the active map that is to be rendered.
125           @type map_name: String
126           @param map_name: The name of the map to load
127           @return: None"""
128        # Turn off the camera on the old map before we turn on the camera
129        # on the new map.
130        self.active_map.cameras[self.active_map.my_cam_id].setEnabled(False)
131        # Make the new map active.
132        self.active_map = self.maps[map_name]
133        self.active_map.makeActive()
134
135    def displayObjectText(self, obj, text):
136        """Display on screen the text of the object over the object.
137           @type obj: fife.instance
138           @param obj: object to draw over
139           @type text: String
140           @param text: text to display over object
141           @return: None"""
142        obj.say(str(text), 1000)
143
144    def keyPressed(self, evt):
145        """Whenever a key is pressed, fife calls this routine.
146           @type evt: fife.event
147           @param evt: The event that fife caught
148           @return: None"""
149        key = evt.getKey()
150        key_val = key.getValue()
151
152        if(key_val == key.Q):
153            # we need to quit the game
154            self.hud.quitGame()
155        if(key_val == key.T):
156            self.active_map.toggle_renderer('GridRenderer')
157        if(key_val == key.F1):
158            # display the help screen and pause the game
159            self.hud.displayHelp()
160        if(key_val == key.F5):
161            # logic would say we use similar code to above and toggle
162            # logic here does not work, my friend :-(
163            self.cord_render.setEnabled(not self.cord_render.isEnabled())
164        if(key_val == key.F7):
165            # F7 saves a screenshot to fife/clients/parpg/screenshots
166            t = "screenshots/screen-%s-%s.png" % \
167                    (date.today().strftime('%Y-%m-%d'),\
168                    time.strftime('%H-%M-%S'))
169            print "PARPG: Saved:",t
170            self.engine.getRenderBackend().captureScreen(t)
171        if(key_val == key.F10):
172            # F10 shows/hides the console
173            self.engine.getGuiManager().getConsole().toggleShowHide()
174        if(key_val == key.I):
175            # I opens and closes the inventory
176            self.hud.toggleInventory()
177        if(key_val == key.A):
178            # A adds a test action to the action box
179            # The test actions will follow this format: Action 1,
180            # Action 2, etc.
181            self.hud.addAction("Action " + str(self.action_number))
182            self.action_number += 1
183        if(key_val == key.ESCAPE):
184            # Escape brings up the main menu
185            self.hud.displayMenu()
186            # Hide the quit menu
187            self.hud.quit_window.hide()
188        if(key_val == key.M):
189            self.sounds.toggleMusic()
190
191    def mouseReleased(self, evt):
192        """If a mouse button is released, fife calls this routine.
193           We want to wait until the button is released, because otherwise
194           pychan captures the release if a menu is opened.
195           @type evt: fife.event
196           @param evt: The event that fife caught
197           @return: None"""
198        self.hud.hideContextMenu()
199        scr_point = fife.ScreenPoint(evt.getX(), evt.getY())
200        if(evt.getButton() == fife.MouseEvent.LEFT):
201            self.data.handleMouseClick(self.getCoords(scr_point))
202        elif(evt.getButton() == fife.MouseEvent.RIGHT):
203            # is there an object here?
204            instances = self.active_map.cameras[self.active_map.my_cam_id].\
205                            getMatchingInstances(scr_point, \
206                                                 self.active_map.agent_layer)
207            info = None
208            for inst in instances:
209                # check to see if this is an active item
210                if(self.data.objectActive(inst.getId())):
211                    # yes, get the data
212                    info = self.data.getItemActions(inst.getId())
213                    break
214
215            # take the menu items returned by the engine or show a
216            # default menu if no items
217            data = info or \
218                [["Walk", "Walk here", self.onWalk, self.getCoords(scr_point)]]
219            # show the menu
220            self.hud.showContextMenu(data, (scr_point.x, scr_point.y))
221
222    def onWalk(self, click):
223        """Callback sample for the context menu."""
224        self.hud.hideContainer()
225        self.data.game_state.PC.run(click)
226
227    def teleport(self, position):
228        """Called when a door is used that moves a player to a new
229           location on the same map. the setting of position may want
230           to be created as its own method down the road.
231           @type position: String Tuple
232           @param position: X,Y coordinates passed from engine.changeMap
233           @return: fife.Location
234        """
235        print position
236        coord = fife.DoublePoint3D(float(position[0]), float(position[1]), 0)
237        location = fife.Location(self.active_map.agent_layer)
238        location.setMapCoordinates(coord)
239        self.data.game_state.PC.teleport(location)
240
241    def mouseMoved(self, evt):
242        """Called when the mouse is moved
243           @type evt: fife.event
244           @param evt: The event that fife caught
245           @return: None"""
246        self.last_mousecoords = fife.ScreenPoint(evt.getX(), evt.getY())
247        self.highlightFrontObject()
248
249    def highlightFrontObject(self):
250        """Highlights the object that is at the current mouse coordinates"""
251        if self.last_mousecoords:
252            front_obj = self.getObjectAtCoords(self.last_mousecoords)
253            if front_obj != None:
254                if self.highlight_obj == None or front_obj.getId() != self.highlight_obj.getId():
255                    if self.highlight_obj:
256                        self.displayObjectText(self.highlight_obj,"")
257                    self.active_map.outline_render.removeAllOutlines()
258                    self.highlight_obj = front_obj
259                    self.active_map.outline_render.addOutlined(self.highlight_obj, 0, \
260                                                               137, 255, 2)
261                        # get the text
262                    item = self.data.objectActive(self.highlight_obj.getId())
263                    if item is not None:
264                        self.displayObjectText(self.highlight_obj, item.name)
265            else:
266                if self.highlight_obj:
267                    self.displayObjectText(self.highlight_obj,"")
268                self.active_map.outline_render.removeAllOutlines()
269                self.highlight_obj = None
270               
271    def getObjectAtCoords(self, coords):
272        """Get the object which is at the given coords
273            @type coords: fife.Screenpoint
274            @param coords: Coordinates where to check for an object
275            @rtype: fife.Object
276            @return: An object or None"""
277        i=self.active_map.cameras[self.active_map.my_cam_id].\
278            getMatchingInstances(coords, self.active_map.agent_layer)
279        # no object returns an empty tuple
280        if(i != ()):
281            front_y = 0
282           
283
284            for obj in i:
285                # check to see if this in our list at all
286                if(self.data.objectActive(obj.getId())):
287                    # check if the object is on the foreground
288                    obj_map_coords = \
289                                      obj.getLocation().getMapCoordinates()
290                    obj_screen_coords = self.active_map.\
291                        cameras[self.active_map.my_cam_id]\
292                        .toScreenCoordinates(obj_map_coords)
293
294                    if obj_screen_coords.y > front_y:
295                        #Object on the foreground
296                        front_y = obj_screen_coords.y
297                        return obj
298                    else:
299                        return None
300        else:
301            return None         
302
303    def getCoords(self, click):
304        """Get the map location x, y coordinates from the screen coordinates
305           @type click: fife.ScreenPoint
306           @param click: Screen coordinates
307           @rtype: fife.Location
308           @return: The map coordinates"""
309        coord = self.active_map.cameras[self.active_map.my_cam_id].\
310                    toMapCoordinates(click, False)
311        coord.z = 0
312        location = fife.Location(self.active_map.agent_layer)
313        location.setMapCoordinates(coord)
314        return location
315
316    def deleteMaps(self):
317        """Clear all currently loaded maps from FIFE as well as clear our
318            local map cache
319            @return: nothing"""
320        self.engine.getView().clearCameras()
321        self.engine.getModel().deleteMaps()
322        self.engine.getModel().deleteObjects()
323
324        self.maps = {}
325
326    def pump(self):
327        """Routine called during each frame. Our main loop is in ./run.py"""
328        self.highlightFrontObject()
Note: See TracBrowser for help on using the repository browser.