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

Revision 358, 12.9 KB checked in by eliedebrauwer, 10 years ago (diff)

Ticket #124 Patch by Beliar, fixed highlight of front object when the object moves away from under the mouse. Patch by eliedebrauwer to only display the name of the currently highlighted object. fixes[s:trac, t:124]

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