Mercurial > fife-parpg
comparison demos/rio_de_hola/scripts/world.py @ 378:64738befdf3b
bringing in the changes from the build_system_rework branch in preparation for the 0.3.0 release. This commit will require the Jan2010 devkit. Clients will also need to be modified to the new way to import fife.
author | vtchill@33b003aa-7bff-0310-803a-e67f0ece8222 |
---|---|
date | Mon, 11 Jan 2010 23:34:52 +0000 |
parents | |
children | 70697641fca3 |
comparison
equal
deleted
inserted
replaced
377:fe6fb0e0ed23 | 378:64738befdf3b |
---|---|
1 # -*- coding: utf-8 -*- | |
2 from fife import fife | |
3 import math, random | |
4 from fife.extensions import pychan | |
5 from fife.extensions.pychan import widgets | |
6 | |
7 from scripts.common.eventlistenerbase import EventListenerBase | |
8 from fife.extensions.loaders import loadMapFile | |
9 from fife.extensions.savers import saveMapFile | |
10 from agents.hero import Hero | |
11 from agents.girl import Girl | |
12 from agents.cloud import Cloud | |
13 from agents.beekeeper import Beekeeper | |
14 from agents.agent import create_anonymous_agents | |
15 from settings import Setting | |
16 | |
17 TDS = Setting() | |
18 | |
19 class MapListener(fife.MapChangeListener): | |
20 def __init__(self, map): | |
21 fife.MapChangeListener.__init__(self) | |
22 map.addChangeListener(self) | |
23 | |
24 def onMapChanged(self, map, changedLayers): | |
25 return | |
26 print "Changes on map ", map.getId() | |
27 for layer in map.getLayers(): | |
28 print layer.getId() | |
29 print " ", ["%s, %x" % (i.getObject().getId(), i.getChangeInfo()) for i in layer.getChangedInstances()] | |
30 | |
31 def onLayerCreate(self, map, layer): | |
32 pass | |
33 | |
34 def onLayerDelete(self, map, layer): | |
35 pass | |
36 | |
37 | |
38 class World(EventListenerBase): | |
39 """ | |
40 The world! | |
41 | |
42 This class handles: | |
43 setup of map view (cameras ...) | |
44 loading the map | |
45 GUI for right clicks | |
46 handles mouse/key events which aren't handled by the GUI. | |
47 ( by inheriting from EventlistenerBase ) | |
48 | |
49 That's obviously too much, and should get factored out. | |
50 """ | |
51 def __init__(self, engine): | |
52 super(World, self).__init__(engine, regMouse=True, regKeys=True) | |
53 self.engine = engine | |
54 self.eventmanager = engine.getEventManager() | |
55 self.model = engine.getModel() | |
56 self.view = self.engine.getView() | |
57 self.filename = '' | |
58 self.pump_ctr = 0 # for testing purposis | |
59 self.ctrldown = False | |
60 self.instancemenu = None | |
61 self.instance_to_agent = {} | |
62 self.dynamic_widgets = {} | |
63 | |
64 def show_instancemenu(self, clickpoint, instance): | |
65 """ | |
66 Build and show a popupmenu for an instance that the player | |
67 clicked on. The available actions are dynamically added to | |
68 the menu (and mapped to the onXYZ functions). | |
69 """ | |
70 if instance.getFifeId() == self.hero.agent.getFifeId(): | |
71 return | |
72 | |
73 # Create the popup. | |
74 self.build_instancemenu() | |
75 self.instancemenu.clickpoint = clickpoint | |
76 self.instancemenu.instance = instance | |
77 | |
78 # Add the buttons according to circumstances. | |
79 self.instancemenu.addChild(self.dynamic_widgets['inspectButton']) | |
80 target_distance = self.hero.agent.getLocationRef().getLayerDistanceTo(instance.getLocationRef()) | |
81 if target_distance > 3.0: | |
82 self.instancemenu.addChild(self.dynamic_widgets['moveButton']) | |
83 else: | |
84 if self.instance_to_agent.has_key(instance.getFifeId()): | |
85 self.instancemenu.addChild(self.dynamic_widgets['talkButton']) | |
86 self.instancemenu.addChild(self.dynamic_widgets['kickButton']) | |
87 # And show it :) | |
88 self.instancemenu.position = (clickpoint.x, clickpoint.y) | |
89 self.instancemenu.show() | |
90 | |
91 def build_instancemenu(self): | |
92 """ | |
93 Just loads the menu from an XML file | |
94 and hooks the events up. | |
95 The buttons are removed and later re-added if appropiate. | |
96 """ | |
97 self.hide_instancemenu() | |
98 dynamicbuttons = ('moveButton', 'talkButton', 'kickButton', 'inspectButton') | |
99 self.instancemenu = pychan.loadXML('gui/instancemenu.xml') | |
100 self.instancemenu.mapEvents({ | |
101 'moveButton' : self.onMoveButtonPress, | |
102 'talkButton' : self.onTalkButtonPress, | |
103 'kickButton' : self.onKickButtonPress, | |
104 'inspectButton' : self.onInspectButtonPress, | |
105 }) | |
106 for btn in dynamicbuttons: | |
107 self.dynamic_widgets[btn] = self.instancemenu.findChild(name=btn) | |
108 self.instancemenu.removeAllChildren() | |
109 | |
110 def hide_instancemenu(self): | |
111 if self.instancemenu: | |
112 self.instancemenu.hide() | |
113 | |
114 def reset(self): | |
115 """ | |
116 Clear the agent information and reset the moving secondary camera state. | |
117 """ | |
118 self.map, self.agentlayer = None, None | |
119 self.cameras = {} | |
120 self.hero, self.girl, self.clouds, self.beekeepers = None, None, [], [] | |
121 self.cur_cam2_x, self.initial_cam2_x, self.cam2_scrolling_right = 0, 0, True | |
122 self.target_rotation = 0 | |
123 self.instance_to_agent = {} | |
124 | |
125 def load(self, filename): | |
126 """ | |
127 Load a xml map and setup agents and cameras. | |
128 """ | |
129 self.filename = filename | |
130 self.reset() | |
131 self.map = loadMapFile(filename, self.engine) | |
132 self.maplistener = MapListener(self.map) | |
133 | |
134 self.initAgents() | |
135 self.initCameras() | |
136 | |
137 def initAgents(self): | |
138 """ | |
139 Setup agents. | |
140 | |
141 For this techdemo we have a very simple 'active things on the map' model, | |
142 which is called agents. All rio maps will have a separate layer for them. | |
143 | |
144 Note that we keep a mapping from map instances (C++ model of stuff on the map) | |
145 to the python agents for later reference. | |
146 """ | |
147 self.agentlayer = self.map.getLayer('TechdemoMapGroundObjectLayer') | |
148 self.hero = Hero(self.model, 'PC', self.agentlayer) | |
149 self.instance_to_agent[self.hero.agent.getFifeId()] = self.hero | |
150 self.hero.start() | |
151 | |
152 self.girl = Girl(self.model, 'NPC:girl', self.agentlayer) | |
153 self.instance_to_agent[self.girl.agent.getFifeId()] = self.girl | |
154 self.girl.start() | |
155 | |
156 self.beekeepers = create_anonymous_agents(self.model, 'beekeeper', self.agentlayer, Beekeeper) | |
157 for beekeeper in self.beekeepers: | |
158 self.instance_to_agent[beekeeper.agent.getFifeId()] = beekeeper | |
159 beekeeper.start() | |
160 | |
161 # Clouds are currently defunct. | |
162 cloudlayer = self.map.getLayer('TechdemoMapTileLayer') | |
163 self.clouds = create_anonymous_agents(self.model, 'Cloud', cloudlayer, Cloud) | |
164 for cloud in self.clouds: | |
165 cloud.start(0.1, 0.05) | |
166 | |
167 | |
168 def initCameras(self): | |
169 """ | |
170 Before we can actually see something on screen we have to specify the render setup. | |
171 This is done through Camera objects which offer a viewport on the map. | |
172 | |
173 For this techdemo two cameras are used. One follows the hero(!) via 'attach' | |
174 the other one scrolls around a bit (see the pump function). | |
175 """ | |
176 camera_prefix = self.filename.rpartition('.')[0] # Remove file extension | |
177 camera_prefix = camera_prefix.rpartition('/')[2] # Remove path | |
178 camera_prefix += '_' | |
179 | |
180 for cam in self.view.getCameras(): | |
181 camera_id = cam.getId().replace(camera_prefix, '') | |
182 self.cameras[camera_id] = cam | |
183 | |
184 self.cameras['main'].attach(self.hero.agent) | |
185 | |
186 self.view.resetRenderers() | |
187 # Floating text renderers currntly only support one font. | |
188 # ... so we set that up. | |
189 # You'll se that for our demo we use a image font, so we have to specify the font glyphs | |
190 # for that one. | |
191 renderer = fife.FloatingTextRenderer.getInstance(self.cameras['main']) | |
192 textfont = self.engine.getGuiManager().createFont('fonts/rpgfont.png', 0, str(TDS.readSetting("FontGlyphs", strip=False))); | |
193 renderer.changeDefaultFont(textfont) | |
194 | |
195 # The small camera shouldn't be cluttered by the 'humm di dums' of our hero. | |
196 # So we disable the renderer simply by setting its font to None. | |
197 renderer = fife.FloatingTextRenderer.getInstance(self.cameras['small']) | |
198 renderer.changeDefaultFont(None) | |
199 | |
200 # The following renderers are used for debugging. | |
201 # Note that by default ( that is after calling View.resetRenderers or Camera.resetRenderers ) | |
202 # renderers will be handed all layers. That's handled here. | |
203 renderer = self.cameras['main'].getRenderer('CoordinateRenderer') | |
204 renderer.clearActiveLayers() | |
205 renderer.addActiveLayer(self.map.getLayer(str(TDS.readSetting("CoordinateLayerName")))) | |
206 | |
207 renderer = self.cameras['main'].getRenderer('QuadTreeRenderer') | |
208 renderer.setEnabled(True) | |
209 renderer.clearActiveLayers() | |
210 if str(TDS.readSetting("QuadTreeLayerName")): | |
211 renderer.addActiveLayer(self.map.getLayer(str(TDS.readSetting("QuadTreeLayerName")))) | |
212 | |
213 # Set up the second camera | |
214 # NOTE: We need to explicitly call setLocation, there's a bit of a messup in the Camera code. | |
215 self.cameras['small'].setLocation(self.hero.agent.getLocation()) | |
216 self.cameras['small'].attach(self.girl.agent) | |
217 | |
218 self.target_rotation = self.cameras['main'].getRotation() | |
219 | |
220 | |
221 def save(self, filename): | |
222 saveMapFile(filename, self.engine, self.map) | |
223 | |
224 def getInstancesAt(self, clickpoint): | |
225 """ | |
226 Query the main camera for instances on our active(agent) layer. | |
227 """ | |
228 return self.cameras['main'].getMatchingInstances(clickpoint, self.agentlayer) | |
229 | |
230 def getLocationAt(self, clickpoint): | |
231 """ | |
232 Query the main camera for the Map location (on the agent layer) | |
233 that a screen point refers to. | |
234 """ | |
235 target_mapcoord = self.cameras['main'].toMapCoordinates(clickpoint, False) | |
236 target_mapcoord.z = 0 | |
237 location = fife.Location(self.agentlayer) | |
238 location.setMapCoordinates(target_mapcoord) | |
239 return location | |
240 | |
241 def keyPressed(self, evt): | |
242 keyval = evt.getKey().getValue() | |
243 keystr = evt.getKey().getAsString().lower() | |
244 if keystr == 't': | |
245 r = self.cameras['main'].getRenderer('GridRenderer') | |
246 r.setEnabled(not r.isEnabled()) | |
247 elif keystr == 'c': | |
248 r = self.cameras['main'].getRenderer('CoordinateRenderer') | |
249 r.setEnabled(not r.isEnabled()) | |
250 elif keystr == 's': | |
251 c = self.cameras['small'] | |
252 c.setEnabled(not c.isEnabled()) | |
253 elif keystr == 'r': | |
254 self.model.deleteMaps() | |
255 self.view.clearCameras() | |
256 self.load(self.filename) | |
257 elif keystr == 'o': | |
258 self.target_rotation = (self.target_rotation + 90) % 360 | |
259 elif keyval in (fife.Key.LEFT_CONTROL, fife.Key.RIGHT_CONTROL): | |
260 self.ctrldown = True | |
261 | |
262 def keyReleased(self, evt): | |
263 keyval = evt.getKey().getValue() | |
264 if keyval in (fife.Key.LEFT_CONTROL, fife.Key.RIGHT_CONTROL): | |
265 self.ctrldown = False | |
266 | |
267 def mouseWheelMovedUp(self, evt): | |
268 if self.ctrldown: | |
269 self.cameras['main'].setZoom(self.cameras['main'].getZoom() * 1.05) | |
270 | |
271 def mouseWheelMovedDown(self, evt): | |
272 if self.ctrldown: | |
273 self.cameras['main'].setZoom(self.cameras['main'].getZoom() / 1.05) | |
274 | |
275 def changeRotation(self): | |
276 """ | |
277 Smoothly change the main cameras rotation until | |
278 the current target rotation is reached. | |
279 """ | |
280 currot = self.cameras['main'].getRotation() | |
281 if self.target_rotation != currot: | |
282 self.cameras['main'].setRotation((currot + 5) % 360) | |
283 | |
284 def mousePressed(self, evt): | |
285 if evt.isConsumedByWidgets(): | |
286 return | |
287 | |
288 clickpoint = fife.ScreenPoint(evt.getX(), evt.getY()) | |
289 if (evt.getButton() == fife.MouseEvent.LEFT): | |
290 self.hide_instancemenu() | |
291 self.hero.run( self.getLocationAt(clickpoint) ) | |
292 | |
293 if (evt.getButton() == fife.MouseEvent.RIGHT): | |
294 instances = self.getInstancesAt(clickpoint) | |
295 print "selected instances on agent layer: ", [i.getObject().getId() for i in instances] | |
296 if instances: | |
297 self.show_instancemenu(clickpoint, instances[0]) | |
298 | |
299 def mouseMoved(self, evt): | |
300 renderer = fife.InstanceRenderer.getInstance(self.cameras['main']) | |
301 renderer.removeAllOutlines() | |
302 | |
303 pt = fife.ScreenPoint(evt.getX(), evt.getY()) | |
304 instances = self.getInstancesAt(pt); | |
305 for i in instances: | |
306 if i.getObject().getId() in ('girl', 'beekeeper'): | |
307 renderer.addOutlined(i, 173, 255, 47, 2) | |
308 | |
309 def onConsoleCommand(self, command): | |
310 result = '' | |
311 try: | |
312 result = str(eval(command)) | |
313 except Exception, e: | |
314 result = str(e) | |
315 return result | |
316 | |
317 # Callbacks from the popupmenu | |
318 def onMoveButtonPress(self): | |
319 self.hide_instancemenu() | |
320 self.hero.run(self.instancemenu.instance.getLocationRef()) | |
321 | |
322 def onTalkButtonPress(self): | |
323 self.hide_instancemenu() | |
324 instance = self.instancemenu.instance | |
325 self.hero.talk(instance.getLocationRef()) | |
326 if instance.getObject().getId() == 'beekeeper': | |
327 beekeeperTexts = TDS.readSetting("beekeeperTexts", type='list', text=True) | |
328 instance.say(random.choice(beekeeperTexts), 5000) | |
329 if instance.getObject().getId() == 'girl': | |
330 girlTexts = TDS.readSetting("girlTexts", type='list', text=True) | |
331 instance.say(random.choice(girlTexts), 5000) | |
332 | |
333 def onKickButtonPress(self): | |
334 self.hide_instancemenu() | |
335 self.hero.kick(self.instancemenu.instance.getLocationRef()) | |
336 self.instancemenu.instance.say('Hey!', 1000) | |
337 | |
338 def onInspectButtonPress(self): | |
339 self.hide_instancemenu() | |
340 inst = self.instancemenu.instance | |
341 saytext = ['Engine told me that this instance has'] | |
342 if inst.getId(): | |
343 saytext.append(' name %s,' % inst.getId()) | |
344 saytext.append(' ID %s and' % inst.getFifeId()) | |
345 saytext.append(' object name %s' % inst.getObject().getId()) | |
346 self.hero.agent.say('\n'.join(saytext), 3500) | |
347 | |
348 def pump(self): | |
349 """ | |
350 Called every frame. | |
351 """ | |
352 | |
353 self.changeRotation() | |
354 self.pump_ctr += 1 |