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

Revision 356, 11.8 KB checked in by Kaydeth_parpg, 10 years ago (diff)

Ticket #73. Patch by Kaydeth. Most of the changes were made to the map loading logic in the Engine, World, and Map classes to make sure it could handle loading maps after the game state has been restored by a load game. Also added a floating door back to both maps so map changing can still be tested in game. fixes[s:trac, t:73]

  • 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        # setup the inventory model
65        # make slot 'A1' and 'A3' container daggers
66        inv_model = {'A1':'dagger01', 'A3':'dagger01'}
67
68        hud_callbacks = {
69            'saveGame': self.saveGame,
70            'loadGame': self.loadGame,
71            'quitGame': self.quitGame,
72        }
73        self.hud = hud.Hud(self.engine, TDS, inv_model, hud_callbacks)
74        self.action_number = 1
75
76        # init the sound
77        self.sounds = SoundEngine(engine)
78       
79        # don't force restart if skipping to new section
80        if (TDS.readSetting("PlaySounds") == "1"):
81            if(self.sounds.music_init == False):
82                self.sounds.playMusic("/music/preciouswasteland.ogg")
83               
84    def quitGame(self):
85        """Quits the game
86        @return: None"""
87        self.quitFunction()
88
89    def saveGame(self, *args, **kwargs):
90        """Saves the game state, delegates call to engine.Engine
91           @return: None"""
92        self.data.save(*args, **kwargs)
93
94    def loadGame(self, *args, **kwargs):
95        """Loads the game state, delegates call to engine.Engine
96           @return: None"""
97        self.data.load(*args, **kwargs)
98       
99    def loadMap(self, map_name, filename):
100        """Loads a map and stores it under the given name in the maps list.
101           @type map_name: String
102           @param map_name: The name of the map to load
103           @type filename: String
104           @param filename: File which contains the map to be loaded
105           @return: None"""
106        if not map_name in self.maps:
107            map = Map(self.engine, self.data)
108            self.maps[map_name] = map       
109            map.load(filename)
110        else:
111            self.setActiveMap(map_name)
112   
113    def setActiveMap(self, map_name):
114        """Sets the active map that is to be rendered.
115           @type map_name: String
116           @param map_name: The name of the map to load
117           @return: None"""
118        # Turn off the camera on the old map before we turn on the camera
119        # on the new map.
120        self.active_map.cameras[self.active_map.my_cam_id].setEnabled(False)
121        # Make the new map active.
122        self.active_map = self.maps[map_name]
123        self.active_map.makeActive()
124
125    def displayObjectText(self, obj, text):
126        """Display on screen the text of the object over the object.
127           @type obj: fife.instance
128           @param obj: object to draw over
129           @type text: String
130           @param text: text to display over object
131           @return: None"""
132        obj.say(str(text), 1000)
133
134    def keyPressed(self, evt):
135        """Whenever a key is pressed, fife calls this routine.
136           @type evt: fife.event
137           @param evt: The event that fife caught
138           @return: None"""
139        key = evt.getKey()
140        key_val = key.getValue()
141
142        if(key_val == key.Q):
143            # we need to quit the game
144            self.hud.quitGame()
145        if(key_val == key.T):
146            self.active_map.toggle_renderer('GridRenderer')
147        if(key_val == key.F1):
148            # display the help screen and pause the game
149            self.hud.displayHelp()
150        if(key_val == key.F5):
151            # logic would say we use similar code to above and toggle
152            # logic here does not work, my friend :-(
153            self.cord_render.setEnabled(not self.cord_render.isEnabled())
154        if(key_val == key.F7):
155            # F7 saves a screenshot to fife/clients/parpg/screenshots
156            t = "screenshots/screen-%s-%s.png" % \
157                    (date.today().strftime('%Y-%m-%d'),\
158                    time.strftime('%H-%M-%S'))
159            print "PARPG: Saved:",t
160            self.engine.getRenderBackend().captureScreen(t)
161        if(key_val == key.F10):
162            # F10 shows/hides the console
163            self.engine.getGuiManager().getConsole().toggleShowHide()
164        if(key_val == key.I):
165            # I opens and closes the inventory
166            self.hud.toggleInventory()
167        if(key_val == key.A):
168            # A adds a test action to the action box
169            # The test actions will follow this format: Action 1,
170            # Action 2, etc.
171            self.hud.addAction("Action " + str(self.action_number))
172            self.action_number += 1
173        if(key_val == key.ESCAPE):
174            # Escape brings up the main menu
175            self.hud.displayMenu()
176            # Hide the quit menu
177            self.hud.quit_window.hide()
178        if(key_val == key.M):
179            self.sounds.toggleMusic()
180
181    def mouseReleased(self, evt):
182        """If a mouse button is released, fife calls this routine.
183           We want to wait until the button is released, because otherwise
184           pychan captures the release if a menu is opened.
185           @type evt: fife.event
186           @param evt: The event that fife caught
187           @return: None"""
188        self.hud.hideContextMenu()
189        scr_point = fife.ScreenPoint(evt.getX(), evt.getY())
190        if(evt.getButton() == fife.MouseEvent.LEFT):
191            self.data.handleMouseClick(self.getCoords(scr_point))     
192        elif(evt.getButton() == fife.MouseEvent.RIGHT):
193            # is there an object here?
194            instances = self.active_map.cameras[self.active_map.my_cam_id].\
195                            getMatchingInstances(scr_point, \
196                                                 self.active_map.agent_layer)
197            info = None
198            for inst in instances:
199                # check to see if this is an active item
200                if(self.data.objectActive(inst.getId())):           
201                    # yes, get the data
202                    info = self.data.getItemActions(inst.getId())
203                    break
204               
205            # take the menu items returned by the engine or show a
206            # default menu if no items   
207            data = info or \
208                [["Walk", "Walk here", self.onWalk, self.getCoords(scr_point)]]
209            # show the menu
210            self.hud.showContextMenu(data, (scr_point.x, scr_point.y))
211
212    def onWalk(self, click):
213        """Callback sample for the context menu."""
214        self.hud.hideContainer()
215        self.data.game_state.PC.run(click)
216
217    def teleport(self, position):
218        """Called when a door is used that moves a player to a new
219           location on the same map. the setting of position may want
220           to be created as its own method down the road.
221           @type position: String Tuple
222           @param position: X,Y coordinates passed from engine.changeMap
223           @return: fife.Location
224        """
225        print position
226        coord = fife.DoublePoint3D(float(position[0]), float(position[1]), 0)
227        location = fife.Location(self.active_map.agent_layer)
228        location.setMapCoordinates(coord)
229        self.data.game_state.PC.teleport(location)
230
231    def mouseMoved(self, evt):
232        """Called when the mouse is moved
233           @type evt: fife.event
234           @param evt: The event that fife caught
235           @return: None"""
236        click = fife.ScreenPoint(evt.getX(), evt.getY())
237        i=self.active_map.cameras[self.active_map.my_cam_id].\
238                getMatchingInstances(click, self.active_map.agent_layer)
239        # no object returns an empty tuple
240        if(i != ()):
241            front_y = 0
242            front_obj = None
243
244            for obj in i:
245                # check to see if this in our list at all
246                if(self.data.objectActive(obj.getId())):
247                    # check if the object is on the foreground
248                    obj_map_coords = \
249                                      obj.getLocation().getMapCoordinates()
250                    obj_screen_coords = self.active_map.\
251                        cameras[self.active_map.my_cam_id]\
252                        .toScreenCoordinates(obj_map_coords)
253                   
254                    if obj_screen_coords.y > front_y:
255                        #Object on the foreground
256                        front_y = obj_screen_coords.y
257                        front_obj = obj
258
259            if front_obj:                   
260                self.active_map.outline_render.removeAllOutlines() 
261                self.active_map.outline_render.addOutlined(front_obj, 0, \
262                                                               137, 255, 2)
263                # get the text
264                item = self.data.objectActive(front_obj.getId())
265                if(item is not None):
266                    self.displayObjectText(front_obj, item.name)
267        else:
268            # erase the outline
269            self.active_map.outline_render.removeAllOutlines()
270
271    def getCoords(self, click):
272        """Get the map location x, y coordinates from the screen coordinates
273           @type click: fife.ScreenPoint
274           @param click: Screen coordinates
275           @rtype: fife.Location
276           @return: The map coordinates"""
277        coord = self.active_map.cameras[self.active_map.my_cam_id].\
278                    toMapCoordinates(click, False)
279        coord.z = 0
280        location = fife.Location(self.active_map.agent_layer)
281        location.setMapCoordinates(coord)
282        return location
283   
284    def deleteMaps(self):
285        """Clear all currently loaded maps from FIFE as well as clear our
286            local map cache
287            @return: nothing"""
288        self.engine.getView().clearCameras()
289        self.engine.getModel().deleteMaps()
290        self.engine.getModel().deleteObjects()
291
292        self.maps = {}
293
294    def pump(self):
295        """Routine called during each frame. Our main loop is in ./run.py
296           We ignore this main loop (but FIFE complains if it is missing)."""
297        pass
Note: See TracBrowser for help on using the repository browser.