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

Revision 412, 14.4 KB checked in by orlandov, 10 years ago (diff)

Ticket #63 - patch by or1andov

  • Fade TopLayer? instances when the PC goes underneath them.
  • Unfade when the PC moves away. This can probably be optimized.
  • 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.gui import hud
28from scripts.gui.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        # faded objects in top layer
81        self.faded_objects = set()
82
83    def initHud(self):
84        """Initialize the hud member
85        @return: None"""
86        # setup the inventory model
87        # make slot 'A1' and 'A3' container daggers
88        inv_model = {'A1':'dagger01', 'A3':'dagger01'}
89
90        hud_callbacks = {
91            'saveGame': self.saveGame,
92            'loadGame': self.loadGame,
93            'quitGame': self.quitGame,
94        }
95        self.hud = hud.Hud(self.engine, TDS, inv_model, self.data, hud_callbacks)
96   
97    def quitGame(self):
98        """Quits the game
99        @return: None"""
100        self.quitFunction()
101
102    def saveGame(self, *args, **kwargs):
103        """Saves the game state, delegates call to engine.Engine
104           @return: None"""
105        self.data.save(*args, **kwargs)
106
107    def loadGame(self, *args, **kwargs):
108        """Loads the game state, delegates call to engine.Engine
109           @return: None"""
110        self.data.load(*args, **kwargs)
111
112    def loadMap(self, map_name, filename):
113        """Loads a map and stores it under the given name in the maps list.
114           @type map_name: String
115           @param map_name: The name of the map to load
116           @type filename: String
117           @param filename: File which contains the map to be loaded
118           @return: None"""
119        if not map_name in self.maps:
120            map = Map(self.engine, self.data)
121            self.maps[map_name] = map
122            map.load(filename)
123        else:
124            self.setActiveMap(map_name)
125
126    def setActiveMap(self, map_name):
127        """Sets the active map that is to be rendered.
128           @type map_name: String
129           @param map_name: The name of the map to load
130           @return: None"""
131        # Turn off the camera on the old map before we turn on the camera
132        # on the new map.
133        self.active_map.cameras[self.active_map.my_cam_id].setEnabled(False)
134        # Make the new map active.
135        self.active_map = self.maps[map_name]
136        self.active_map.makeActive()
137
138    def displayObjectText(self, obj, text):
139        """Display on screen the text of the object over the object.
140           @type obj: fife.instance
141           @param obj: object to draw over
142           @type text: String
143           @param text: text to display over object
144           @return: None"""
145        obj.say(str(text), 1000)
146
147    def keyPressed(self, evt):
148        """Whenever a key is pressed, fife calls this routine.
149           @type evt: fife.event
150           @param evt: The event that fife caught
151           @return: None"""
152        key = evt.getKey()
153        key_val = key.getValue()
154
155        if(key_val == key.Q):
156            # we need to quit the game
157            self.hud.quitGame()
158        if(key_val == key.T):
159            self.active_map.toggle_renderer('GridRenderer')
160        if(key_val == key.F1):
161            # display the help screen and pause the game
162            self.hud.displayHelp()
163        if(key_val == key.F5):
164            # logic would say we use similar code to above and toggle
165            # logic here does not work, my friend :-(
166            self.cord_render.setEnabled(not self.cord_render.isEnabled())
167        if(key_val == key.F7):
168            # F7 saves a screenshot to fife/clients/parpg/screenshots
169            t = "screenshots/screen-%s-%s.png" % \
170                    (date.today().strftime('%Y-%m-%d'),\
171                    time.strftime('%H-%M-%S'))
172            print "PARPG: Saved:",t
173            self.engine.getRenderBackend().captureScreen(t)
174        if(key_val == key.F10):
175            # F10 shows/hides the console
176            self.engine.getGuiManager().getConsole().toggleShowHide()
177        if(key_val == key.I):
178            # I opens and closes the inventory
179            self.hud.toggleInventory()
180        if(key_val == key.A):
181            # A adds a test action to the action box
182            # The test actions will follow this format: Action 1,
183            # Action 2, etc.
184            self.hud.addAction("Action " + str(self.action_number))
185            self.action_number += 1
186        if(key_val == key.ESCAPE):
187            # Escape brings up the main menu
188            self.hud.displayMenu()
189            # Hide the quit menu
190            self.hud.quit_window.hide()
191        if(key_val == key.M):
192            self.sounds.toggleMusic()
193
194    def mouseReleased(self, evt):
195        """If a mouse button is released, fife calls this routine.
196           We want to wait until the button is released, because otherwise
197           pychan captures the release if a menu is opened.
198           @type evt: fife.event
199           @param evt: The event that fife caught
200           @return: None"""
201        self.hud.hideContextMenu()
202        scr_point = fife.ScreenPoint(evt.getX(), evt.getY())
203        if(evt.getButton() == fife.MouseEvent.LEFT):
204            self.data.handleMouseClick(self.getCoords(scr_point))
205        elif(evt.getButton() == fife.MouseEvent.RIGHT):
206            # is there an object here?
207            instances = self.active_map.cameras[self.active_map.my_cam_id].\
208                            getMatchingInstances(scr_point, \
209                                                 self.active_map.agent_layer)
210            info = None
211            for inst in instances:
212                # check to see if this is an active item
213                if(self.data.objectActive(inst.getId())):
214                    # yes, get the data
215                    info = self.data.getItemActions(inst.getId())
216                    break
217
218            # take the menu items returned by the engine or show a
219            # default menu if no items
220            data = info or \
221                [["Walk", "Walk here", self.onWalk, self.getCoords(scr_point)]]
222            # show the menu
223            self.hud.showContextMenu(data, (scr_point.x, scr_point.y))
224
225    def onWalk(self, click):
226        """Callback sample for the context menu."""
227        self.hud.hideContainer()
228        self.data.game_state.PC.run(click)
229
230    def refreshTopLayerInstanceTransparencies(self):
231        """Fade or unfade TopLayer instances if the PC is under them."""
232
233        # get the PC's screen coordinates
234        camera = self.active_map.cameras[self.active_map.my_cam_id]
235        point = self.data.game_state.PC.behaviour.agent.getLocation()
236        scr_coords = camera.toScreenCoordinates(point.getMapCoordinates())
237
238        # find all instances on TopLayer that fall on those coordinates
239        instances = camera.getMatchingInstances(scr_coords,
240                        self.active_map.top_layer)
241        instance_ids = [ instance.getId() for instance in instances ]
242        faded_objects = self.faded_objects
243
244        # fade instances
245        for instance_id in instance_ids:
246            if instance_id not in faded_objects:
247                faded_objects.add(instance_id)
248                instance.get2dGfxVisual().setTransparency(128)
249
250        # unfade previously faded instances
251        for instance_id in faded_objects.copy():
252            if instance_id not in instance_ids:
253                faded_objects.remove(instance_id)
254                self.active_map.top_layer.getInstance(instance_id).\
255                        get2dGfxVisual().setTransparency(0)
256
257    def teleport(self, position):
258        """Called when a door is used that moves a player to a new
259           location on the same map. the setting of position may want
260           to be created as its own method down the road.
261           @type position: String Tuple
262           @param position: X,Y coordinates passed from engine.changeMap
263           @return: fife.Location
264        """
265        print position
266        coord = fife.DoublePoint3D(float(position[0]), float(position[1]), 0)
267        location = fife.Location(self.active_map.agent_layer)
268        location.setMapCoordinates(coord)
269        self.data.game_state.PC.teleport(location)
270
271    def mouseMoved(self, evt):
272        """Called when the mouse is moved
273           @type evt: fife.event
274           @param evt: The event that fife caught
275           @return: None"""
276        self.last_mousecoords = fife.ScreenPoint(evt.getX(), evt.getY())
277        self.highlightFrontObject()
278
279    def highlightFrontObject(self):
280        """Highlights the object that is at the current mouse coordinates"""
281        if self.last_mousecoords:
282            front_obj = self.getObjectAtCoords(self.last_mousecoords)
283            if front_obj != None:
284                if self.highlight_obj == None or front_obj.getId() != self.highlight_obj.getId():
285                    if self.highlight_obj:
286                        self.displayObjectText(self.highlight_obj,"")
287                    self.active_map.outline_render.removeAllOutlines()
288                    self.highlight_obj = front_obj
289                    self.active_map.outline_render.addOutlined(self.highlight_obj, 0, \
290                                                               137, 255, 2)
291                        # get the text
292                    item = self.data.objectActive(self.highlight_obj.getId())
293                    if item is not None:
294                        self.displayObjectText(self.highlight_obj, item.name)
295            else:
296                if self.highlight_obj:
297                    self.displayObjectText(self.highlight_obj,"")
298                self.active_map.outline_render.removeAllOutlines()
299                self.highlight_obj = None
300               
301    def getObjectAtCoords(self, coords):
302        """Get the object which is at the given coords
303            @type coords: fife.Screenpoint
304            @param coords: Coordinates where to check for an object
305            @rtype: fife.Object
306            @return: An object or None"""
307        i=self.active_map.cameras[self.active_map.my_cam_id].\
308            getMatchingInstances(coords, self.active_map.agent_layer)
309        # no object returns an empty tuple
310        if(i != ()):
311            front_y = 0
312           
313
314            for obj in i:
315                # check to see if this in our list at all
316                if(self.data.objectActive(obj.getId())):
317                    # check if the object is on the foreground
318                    obj_map_coords = \
319                                      obj.getLocation().getMapCoordinates()
320                    obj_screen_coords = self.active_map.\
321                        cameras[self.active_map.my_cam_id]\
322                        .toScreenCoordinates(obj_map_coords)
323
324                    if obj_screen_coords.y > front_y:
325                        #Object on the foreground
326                        front_y = obj_screen_coords.y
327                        return obj
328                    else:
329                        return None
330        else:
331            return None         
332
333    def getCoords(self, click):
334        """Get the map location x, y coordinates from the screen coordinates
335           @type click: fife.ScreenPoint
336           @param click: Screen coordinates
337           @rtype: fife.Location
338           @return: The map coordinates"""
339        coord = self.active_map.cameras[self.active_map.my_cam_id].\
340                    toMapCoordinates(click, False)
341        coord.z = 0
342        location = fife.Location(self.active_map.agent_layer)
343        location.setMapCoordinates(coord)
344        return location
345
346    def deleteMaps(self):
347        """Clear all currently loaded maps from FIFE as well as clear our
348            local map cache
349            @return: nothing"""
350        self.engine.getView().clearCameras()
351        self.engine.getModel().deleteMaps()
352        self.engine.getModel().deleteObjects()
353
354        self.maps = {}
355
356    def pump(self):
357        """Routine called during each frame. Our main loop is in ./run.py"""
358        # uncomment to instrument
359        # t0 = time.time()
360        self.highlightFrontObject()
361        self.refreshTopLayerInstanceTransparencies()
362        # print "%05f" % (time.time()-t0,)
Note: See TracBrowser for help on using the repository browser.