source: trunk/PARPG/scripts/world.py @ 105

Revision 105, 11.8 KB checked in by maximinus_parpg, 10 years ago (diff)

Cleaned up the map and removed the test files.
Small clean-up of XML and world.py.

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
19import time
20from datetime import date
21from scripts.common.eventlistenerbase import EventListenerBase
22from loaders import loadMapFile
23from agents.hero import Hero
24from agents.npc import NPC
25from settings import Setting
26from scripts import inventory
27from scripts import hud
28from pychan.tools import callbackWithArguments as cbwa
29
30TDS = Setting()
31
32# this file should be the meta-file for all FIFE-related code
33# engine.py handles is our data model, whilst this is our view
34# in order to not replicate data, some of our data model will naturally
35# reside on this side of the fence (PC xpos and ypos, for example).
36# we should aim to never replicate any data as this leads to maintainance
37# issues (and just looks plain bad).
38# however, any logic needed to resolve this should sit in engine.py
39
40class MapListener(fife.MapChangeListener):
41    """This class listens to changes happening on the map.
42       Since in theory we initiate these ourselves, do we need this class?"""
43    def __init__(self, map):
44        fife.MapChangeListener.__init__(self)
45
46    def onMapChanged(self, map, changedLayers):
47        pass
48
49    def onLayerCreate(self, map, layer):
50        pass
51
52    def onLayerDelete(self, map, layer):
53        pass
54
55class Map:
56    def __init__(self, fife_map):
57        self.listener = MapListener
58        self.map = fife_map
59
60class World(EventListenerBase):
61    """World holds the data needed by fife to render the engine
62       The engine keeps a copy of this class"""
63    def __init__(self, engine):
64        """Constructor for engine
65           TODO: Comment these variables"""
66        super(World, self).__init__(engine, regMouse = True, regKeys = True)
67        self.engine = engine
68        self.eventmanager = engine.getEventManager()
69        self.model = engine.getModel()
70        self.view = self.engine.getView()
71        self.quitFunction = None
72        self.inventoryShown = False
73        self.data = None
74        self.mouseCallback = None
75        self.obj_hash={}
76
77        self.hud = hud.Hud(self.engine, TDS)
78        self.hud.events_to_map["inventoryButton"] = cbwa(self.displayInventory, True)
79        self.hud.hud.mapEvents(self.hud.events_to_map)
80        self.hud.menu_events["quitButton"] = self.quitGame
81        self.hud.main_menu.mapEvents(self.hud.menu_events)
82        self.action_number = 1
83
84        self.inventory = inventory.Inventory(self.engine, self.refreshReadyImages)
85        self.inventory.events_to_map['close_button'] = self.closeInventoryAndToggle
86        self.inventory.inventory.mapEvents(self.inventory.events_to_map)
87        self.refreshReadyImages()
88
89    def reset(self):
90        """Reset the map to default settings"""
91        self.transitions = []
92        self.PC = None
93        self.npcs = []
94        self.map,self.agent_layer = None,None
95        self.cameras = {}
96        self.PC = None
97        self.npcs = []
98        self.cur_cam2_x,self.initial_cam2_x,self.cam2_scrolling_right = 0,0,True
99        self.target_rotation = 0
100
101    def load(self, filename):
102        """Load a map given the filename
103           TODO: a map should only contain static items and floor tiles
104           Everything else should be loaded from the engine, because it
105           is subject to change"""
106        self.reset()
107        self.map = loadMapFile(filename, self.engine)
108        self.maplistener = MapListener(self.map)
109
110        # there must be a PC object on the objects layer!
111        self.agent_layer = self.map.getLayer('ObjectLayer')
112        # it's possible there's no transition layer
113        size = len('TransitionLayer')
114        for layer in self.map.getLayers():
115            # could be many layers, but hopefully no more than 3
116            if(layer.getId()[:size] == 'TransitionLayer'):
117                self.transitions.append(self.map.getLayer(layer.getId()))
118
119        # init the camera
120        for cam in self.view.getCameras():
121            self.cameras[cam.getId()] = cam
122        self.view.resetRenderers()
123        self.target_rotation = self.cameras['main'].getRotation()
124        self.cord_render = self.cameras['main'].getRenderer('CoordinateRenderer')
125        self.outline_render = fife.InstanceRenderer.getInstance(self.cameras['main'])
126       
127        # set the rnder text
128        rend = fife.FloatingTextRenderer.getInstance(self.cameras['main'])
129        text = self.engine.getGuiManager().createFont('fonts/rpgfont.png',
130                                                          0, str(TDS.readSetting("FontGlyphs", strip=False)))
131        rend.changeDefaultFont(text)
132
133    def addPC(self, agent):
134        """Add the player character to the map"""
135        # actually this is real easy, we just have to
136        # attach the main camera to the PC
137        self.cameras['main'].attach(agent)
138   
139    def addObject(self, xpos, ypos, gfx, name):
140        """Add an object or an NPC to the map
141           It makes no difference to fife which is which"""
142        obj = self.agent_layer.createInstance(
143                self.model.getObject(str(gfx), "PARPG"),
144                fife.ExactModelCoordinate(xpos,ypos,0.0), str(name))
145        obj.setRotation(0)
146        fife.InstanceVisual.create(obj)
147        # save it for later use
148        self.obj_hash[name]=obj
149
150    def displayObjectText(self, obj, text):
151        """Display on screen the text of the object over the object"""
152        # make sure that the object exists first
153        if obj in self.obj_hash:
154            self.obj_hash[obj].say(str(text), 3500)
155
156    def refreshReadyImages(self):
157        """Make the Ready slot images on the HUD be the same as those on the inventory"""
158        self.setImages(self.hud.hud.findChild(name="hudReady1"),
159                       self.inventory.inventory.findChild(name="Ready1").up_image)
160        self.setImages(self.hud.hud.findChild(name="hudReady2"),
161                       self.inventory.inventory.findChild(name="Ready2").up_image)
162        self.setImages(self.hud.hud.findChild(name="hudReady3"),
163                       self.inventory.inventory.findChild(name="Ready3").up_image)
164        self.setImages(self.hud.hud.findChild(name="hudReady4"),
165                       self.inventory.inventory.findChild(name="Ready4").up_image)
166
167    def setImages(self, widget, image):
168        """Set the up, down, and hover images of an Imagebutton"""
169        widget.up_image = image
170        widget.down_image = image
171        widget.hover_image = image
172
173    def closeInventoryAndToggle(self):
174        self.inventory.closeInventory()
175        self.hud.toggleInventory()
176        self.inventoryShown = False
177
178    def displayInventory(self, callFromHud):
179        """Pause the game and enter the inventory screen
180           or close the inventory screen and resume the game
181           callFromHud should be set to true if you call this
182           function from the hud script"""
183        if (self.inventoryShown == False):
184            self.inventory.showInventory()
185            self.inventoryShown = True
186            if (callFromHud == False):
187                self.hud.toggleInventory()
188        else:
189            self.inventory.closeInventory()
190            self.inventoryShown = False
191            if (callFromHud == False):
192                self.hud.toggleInventory()
193
194    # all key / mouse event handling routines go here
195    def keyPressed(self, evt):
196        """When a key is pressed, fife calls this routine."""
197        key = evt.getKey()
198        keyval = key.getValue()
199
200        if(keyval == key.Q):
201            # we need to quit the game
202            self.quitGame()
203        if(keyval == key.T):
204            self.toggle_renderer('GridRenderer')
205        if(keyval == key.F1):
206            # display the help screen and pause the game
207            self.displayHelp()
208        if(keyval == key.F5):
209            # logic would say we use similar code to above and toggle
210            # logic here does not work, my friend :-(
211            self.cord_render.setEnabled(not self.cord_render.isEnabled())
212        if(keyval == key.F7):
213            # F7 saves a screenshot to fife/clients/parpg/screenshots
214            t = "screenshots/screen-%s-%s.png" % (date.today().strftime('%Y-%m-%d'),
215                                                  time.strftime('%H-%M-%S'))
216            print "PARPG: Saved:",t
217            self.engine.getRenderBackend().captureScreen(t)
218        if(keyval == key.I):
219            # I opens and closes the inventory
220            self.displayInventory(callFromHud=False)
221        if(keyval == key.A):
222            # A adds a test action to the action box
223            # The test actions will follow this format: Action 1, Action 2, etc.
224            self.hud.addAction("Action " + str(self.action_number))
225            self.action_number += 1
226        if(keyval == key.ESCAPE):
227            # Escape brings up the main menu
228            self.hud.displayMenu()
229
230    def getCoords(self, click):
231        """Get the map location x, y cords that have been clicked"""
232        coord = self.cameras["main"].toMapCoordinates(click, False)
233        coord.z = 0
234        location = fife.Location(self.agent_layer)
235        location.setMapCoordinates(coord)
236        return location
237
238    def mousePressed(self, evt):
239        """If a mouse button is pressed down, fife cals this routine
240           Currently we only check for a left click, and we assume this is on
241           the map"""
242        click = fife.ScreenPoint(evt.getX(), evt.getY())
243        if(evt.getButton() == fife.MouseEvent.LEFT):
244            self.data.handleMouseClick(self.getCoords(click))
245        elif(evt.getButton() == fife.MouseEvent.RIGHT):
246            # although the engine code knows, fife can be more accurate
247            i=self.cameras['main'].getMatchingInstances(click, self.agent_layer)
248            if(i != ()):
249                for obj in i:
250                    # check to see if this in our list at all
251                    test = self.data.objectActive(obj.getId())
252                    if(test != False):
253                        # finally, display the text   
254                        self.displayObjectText(obj.getId(), test.text)
255
256    def mouseMoved(self, evt):
257        """Called when the mouse is moved"""
258        click = fife.ScreenPoint(evt.getX(), evt.getY())
259        i=self.cameras['main'].getMatchingInstances(click, self.agent_layer)
260        # no object returns an empty tuple
261        if(i != ()):
262            for obj in i:
263                # check to see if this in our list at all
264                if(self.data.objectActive(obj.getId())!=False):
265                    # yes, so outline   
266                    self.outline_render.addOutlined(obj, 0, 137, 255, 2)
267        else:
268            # erase the outline
269            self.outline_render.removeAllOutlines()
270
271    def toggle_renderer(self, r_name):
272        """Enable or disable the renderer named `r_name`"""
273        renderer = self.cameras['main'].getRenderer('GridRenderer')
274        renderer.setEnabled(not renderer.isEnabled())
275
276    def displayHelp(self):
277        """Displays the pop-up info and help screen"""
278        print "Help not yet coded"
279
280    def quitGame(self):
281        """Called when user requests to quit game
282           Just calls the ApplicationListener to do the quit"""
283        if(self.quitFunction != None):
284            self.quitFunction()
285
286    def pump(self):
287        """Routine called during each frame. Our main loop is in ./run.py
288           We ignore this main loop (but FIFE complains if it is missing)"""
289        pass
290
Note: See TracBrowser for help on using the repository browser.