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

Revision 253, 15.4 KB checked in by tZee_parpg, 10 years ago (diff)

#65 Exported map data in a separate class. Next is to sort out the loading strategy (right now the call goes through the engine, then to the world and then to the map class) and the ownership of objects like the cameras.

  • 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 fife, time
19import pychan
20from sounds import SoundEngine
21from scripts.parpgfilebrowser import PARPGFileBrowser
22from datetime import date
23from scripts.common.eventlistenerbase import EventListenerBase
24from settings import Setting
25from scripts import inventory, hud
26from scripts.popups import *
27from scripts.context_menu import ContextMenu
28from pychan.tools import callbackWithArguments as cbwa
29from map import Map
30
31TDS = Setting()
32
33# this file should be the meta-file for all FIFE-related code
34# engine.py handles is our data model, whilst this is our view
35# in order to not replicate data, some of our data model will naturally
36# reside on this side of the fence (PC xpos and ypos, for example).
37# we should aim to never replicate any data as this leads to maintainance
38# issues (and just looks plain bad).
39# however, any logic needed to resolve this should sit in engine.py
40
41class World(EventListenerBase):
42    """World holds the data needed by fife to render the engine
43       The engine keeps a copy of this class"""
44    def __init__(self, engine):
45        """Constructor for engine
46           @type engine: fife.Engine
47           @param engine: A fife.Engine instance
48           @return: None"""
49        super(World, self).__init__(engine, regMouse = True, regKeys = True)
50        # self.engine is a fife.Engine object, not an Engine object
51        self.engine = engine
52        self.eventmanager = engine.getEventManager()
53        self.quitFunction = None
54        self.inventoryShown = False 
55       
56        # self.data is an engine.Engine object, but is set in run.py
57        self.data = None
58        self.mouseCallback = None
59        self.obj_hash={}
60        # self.map is a Map object, set to none here
61        self.activeMap = None
62        self.maps = {}
63        self.hud = hud.Hud(self.engine, TDS)
64        self.hud.events_to_map["inventoryButton"] = cbwa(self.displayInventory, True)
65        self.hud.events_to_map["saveButton"] = self.saveGame
66        self.hud.events_to_map["loadButton"] = self.loadGame
67        hud_ready_buttons = ["hudReady1", "hudReady2", "hudReady3", "hudReady4"]
68        for item in hud_ready_buttons:
69            self.hud.events_to_map[item] = cbwa(self.hud.readyAction, item)
70        self.hud.hud.mapEvents(self.hud.events_to_map)
71        self.hud.menu_events["newButton"] = self.newGame
72        self.hud.menu_events["quitButton"] = self.quitGame
73        self.hud.menu_events["saveButton"] = self.saveGame
74        self.hud.menu_events["loadButton"] = self.loadGame
75        self.hud.main_menu.mapEvents(self.hud.menu_events)
76        self.action_number = 1
77        # setup the inventory
78        # make slot 'A1' and 'A3' container daggers
79        inv_data = {'A1':'dagger01', 'A3':'dagger01'}
80        self.inventory = inventory.Inventory(self.engine, inv_data, self.refreshReadyImages)
81        self.inventory.events_to_map['close_button'] = self.closeInventoryAndToggle
82        self.inventory.inventory.mapEvents(self.inventory.events_to_map)
83        self.refreshReadyImages()
84       
85        self.context_menu = ContextMenu (self.engine, [], (0,0))
86        self.context_menu.hide()
87        self.boxOpen = False
88        self.boxCreated = False
89       
90        # init the sound
91        self.sounds = SoundEngine(engine)
92       
93        # don't force restart if skipping to new section
94        if (TDS.readSetting("PlaySounds") == "1"):
95            if(self.sounds.music_init == False):
96                self.sounds.playMusic("/music/preciouswasteland.ogg")
97               
98    def loadMap(self, mapname, filename):
99        """Loads a map an stores it under the given name in the maps list.
100        """
101        map = Map(self.engine)
102        map.load(filename)
103        self.maps[mapname] = map
104   
105    def setActiveMap(self, mapname):
106        """Sets the active map that is to be rendered.
107        """
108        self.activeMap = self.maps[mapname]
109        self.activeMap.makeActive()
110
111    def displayObjectText(self, obj, text):
112        """Display on screen the text of the object over the object.
113           @type obj: fife.instance
114           @param obj: object to draw over
115           @type text: text
116           @param text: text to display over object
117           @return: None"""
118        obj.say(str(text), 1000)
119
120    def refreshReadyImages(self):
121        """Make the Ready slot images on the HUD be the same as those
122           on the inventory
123           @return: None"""
124        self.setImages(self.hud.hud.findChild(name="hudReady1"),
125                       self.inventory.inventory.findChild(name="Ready1").up_image)
126        self.setImages(self.hud.hud.findChild(name="hudReady2"),
127                       self.inventory.inventory.findChild(name="Ready2").up_image)
128        self.setImages(self.hud.hud.findChild(name="hudReady3"),
129                       self.inventory.inventory.findChild(name="Ready3").up_image)
130        self.setImages(self.hud.hud.findChild(name="hudReady4"),
131                       self.inventory.inventory.findChild(name="Ready4").up_image)
132
133    def setImages(self, widget, image):
134        """Set the up, down, and hover images of an Imagebutton.
135           @type widget: pychan.widget
136           @param widget: widget to set
137           @type image: string
138           @param image: image to use
139           @return: None"""
140        widget.up_image = image
141        widget.down_image = image
142        widget.hover_image = image
143
144    def closeInventoryAndToggle(self):
145        """Close the inventory screen.
146           @return: None"""
147        self.inventory.closeInventory()
148        self.hud.toggleInventory()
149        self.inventoryShown = False
150
151    def displayInventory(self, callFromHud):
152        """Pause the game and enter the inventory screen, or close the
153           inventory screen and resume the game. callFromHud should be true
154           (must be True?) if you call this function from the HUD script
155           @type callFromHud: boolean
156           @param callFromHud: Whether this function is being called
157                               from the HUD script
158           @return: None"""
159        if (self.inventoryShown == False):
160            self.inventory.showInventory()
161            self.inventoryShown = True
162        else:
163            self.inventory.closeInventory()
164            self.inventoryShown = False
165        if (callFromHud == False):
166            self.hud.toggleInventory()
167
168    # all key / mouse event handling routines go here
169    def keyPressed(self, evt):
170        """Whenever a key is pressed, fife calls this routine.
171           @type evt: fife.event
172           @param evt: The event that fife caught
173           @return: None"""
174        key = evt.getKey()
175        keyval = key.getValue()
176
177        if(keyval == key.Q):
178            # we need to quit the game
179            self.quitGame()
180        if(keyval == key.T):
181            self.toggle_renderer('GridRenderer')
182        if(keyval == key.F1):
183            # display the help screen and pause the game
184            self.displayHelp()
185        if(keyval == key.F5):
186            # logic would say we use similar code to above and toggle
187            # logic here does not work, my friend :-(
188            self.cord_render.setEnabled(not self.cord_render.isEnabled())
189        if(keyval == key.F7):
190            # F7 saves a screenshot to fife/clients/parpg/screenshots
191            t = "screenshots/screen-%s-%s.png" % (date.today().strftime('%Y-%m-%d'),
192                                                  time.strftime('%H-%M-%S'))
193            print "PARPG: Saved:",t
194            self.engine.getRenderBackend().captureScreen(t)
195        if(keyval == key.F10):
196            # F10 shows/hides the console
197            self.engine.getGuiManager().getConsole().toggleShowHide()
198        if(keyval == key.I):
199            # I opens and closes the inventory
200            self.displayInventory(callFromHud=False)
201        if(keyval == key.A):
202            # A adds a test action to the action box
203            # The test actions will follow this format: Action 1, Action 2, etc.
204            self.hud.addAction("Action " + str(self.action_number))
205            self.action_number += 1
206        if(keyval == key.ESCAPE):
207            # Escape brings up the main menu
208            self.hud.displayMenu()
209        if(keyval == key.M):
210            self.sounds.toggleMusic()
211
212    def mouseReleased(self, evt):
213        """If a mouse button is released, fife calls this routine.
214           We want to wait until the button is released, because otherwise
215           pychan captures the release if a menu is opened.
216           @type evt: fife.event
217           @param evt: The event that fife caught
218           @return: None"""
219        self.context_menu.hide() # hide the context menu in case it is displayed
220        scr_point = fife.ScreenPoint(evt.getX(), evt.getY())
221        if(evt.getButton() == fife.MouseEvent.LEFT):
222            self.data.handleMouseClick(self.getCoords(scr_point))     
223        elif(evt.getButton() == fife.MouseEvent.RIGHT):
224            # is there an object here?
225            instances = self.activeMap.cameras['main'].getMatchingInstances(scr_point, self.activeMap.agent_layer)
226            info = None
227            for inst in instances:
228                # check to see if this is an active item
229                if(self.data.objectActive(inst.getId())):           
230                    # yes, get the data
231                    info = self.data.getItemActions(inst.getId())
232                    break
233               
234            # take the menu items returned by the engine or show a default menu if no items   
235            data = info or [["Walk", "Walk here", self.onWalk, self.getCoords(scr_point)]]
236            # show the menu
237            self.context_menu = ContextMenu(self.engine, data, (scr_point.x,scr_point.y))
238
239    def onWalk(self, click):
240        """Callback sample for the context menu.
241        """
242        self.context_menu.hide()
243        self.data.gameState.PC.run(click)
244
245    def mouseMoved(self, evt):
246        """Called when the mouse is moved
247           @type evt: fife.event
248           @param evt: The event that fife caught
249           @return: None"""
250        click = fife.ScreenPoint(evt.getX(), evt.getY())
251        i=self.activeMap.cameras['main'].getMatchingInstances(click, self.activeMap.agent_layer)
252        # no object returns an empty tuple
253        if(i != ()):
254            for obj in i:
255                # check to see if this in our list at all
256                if(self.data.objectActive(obj.getId())):
257                    # yes, so outline   
258                    self.activeMap.outline_render.addOutlined(obj, 0, 137, 255, 2)
259                    # get the text
260                    item = self.data.objectActive(obj.getId())
261                    if(item):
262                        self.displayObjectText(obj, item.name)
263        else:
264            # erase the outline
265            self.activeMap.outline_render.removeAllOutlines()
266
267    def getCoords(self, click):
268        """Get the map location x, y cords from the screen co-ords
269           @type click: fife.ScreenPoint
270           @param click: Screen co-ords
271           @rtype: fife.Location
272           @return: The map co-ords"""
273        coord = self.activeMap.cameras["main"].toMapCoordinates(click, False)
274        coord.z = 0
275        location = fife.Location(self.activeMap.agent_layer)
276        location.setMapCoordinates(coord)
277        return location
278
279    def clearMenu(self):
280        """ Hides the context menu. Just nice to have it as a function.
281            @return: None"""
282        if hasattr(self, "context_menu"):
283            self.context_menu.vbox.hide()
284            delattr(self, "context_menu")
285
286    def newGame(self):
287        """Called when user request to start a new game.
288           @return: None"""
289        print 'new game'
290
291    def quitGame(self):
292        """Called when user requests to quit game.
293           @return: None"""
294        if(self.quitFunction != None):
295            window = pychan.widgets.Window(title=unicode("Quit?"))
296
297            hbox = pychan.widgets.HBox()
298            are_you_sure = "Are you sure you want to quit?"
299            label = pychan.widgets.Label(text=unicode(are_you_sure))
300            yes_button = pychan.widgets.Button(name="yes_button", 
301                                               text=unicode("Yes"))
302            no_button = pychan.widgets.Button(name="no_button",
303                                              text=unicode("No"))
304
305            window.addChild(label)
306            hbox.addChild(yes_button)
307            hbox.addChild(no_button)
308            window.addChild(hbox)
309
310            events_to_map = {"yes_button":self.quitFunction,
311                             "no_button":window.hide}
312           
313            window.mapEvents(events_to_map)
314            window.show()
315
316    def saveGame(self):
317        """ Called when the user wants to save the game.
318            @return: None"""
319        self.save_browser = PARPGFileBrowser(self.engine,
320                                        self.data.save,
321                                        savefile=True,
322                                        guixmlpath="gui/savebrowser.xml",
323                                        extensions = ('.dat'))
324        self.save_browser.showBrowser()
325           
326
327    def loadGame(self):
328        """ Called when the user wants to load a game.
329            @return: None"""
330        self.load_browser = PARPGFileBrowser(self.engine,
331                                        self.data.load,
332                                        savefile=False,
333                                        guixmlpath='gui/loadbrowser.xml',
334                                        extensions=('.dat'))
335        self.load_browser.showBrowser()
336
337
338    def createBoxGUI(self, title):
339        """
340        Creates a window to display the contents of a box
341
342        @type title: string
343        @param title: The title for the window
344        @return: None
345        """
346        if ((self.boxCreated == True) and (self.boxOpen == False)):
347            # if it has already been created, just show it
348            self.box_container.showContainer()
349            self.boxOpen = True
350        else:
351            # otherwise create it then show it
352            data = ["dagger01", "empty", "empty", "empty", "empty",
353                    "empty", "empty", "empty", "empty"]
354            self.box_container = ContainerGUI(self.engine, unicode(title), data)
355            def close_and_delete():
356                self.box_container.hideContainer()
357                self.boxOpen = False
358            events = {'takeAllButton':close_and_delete,
359                      'closeButton':close_and_delete}
360            self.box_container.container_gui.mapEvents(events)
361            self.box_container.showContainer()
362            self.boxOpen = True
363            self.boxCreated = True
364
365    def createExamineBox(self, title, desc):
366        self.examineBox = ExaminePopup(self.engine, title, desc)
367        self.examineBox.showPopUp()
368
369    def pump(self):
370        """Routine called during each frame. Our main loop is in ./run.py
371           We ignore this main loop (but FIFE complains if it is missing)."""
372        pass
Note: See TracBrowser for help on using the repository browser.