comparison clients/rio_de_hola/scripts/world.py @ 246:8156de05a544

Documentation for the World class in rio de hola.
author phoku@33b003aa-7bff-0310-803a-e67f0ece8222
date Wed, 25 Mar 2009 15:42:14 +0000
parents ed1565a5a2a0
children 040387b7167f
comparison
equal deleted inserted replaced
245:ed1565a5a2a0 246:8156de05a544
33 def onLayerDelete(self, map, layer): 33 def onLayerDelete(self, map, layer):
34 pass 34 pass
35 35
36 36
37 class World(EventListenerBase): 37 class World(EventListenerBase):
38 """
39 The world!
40
41 This class handles:
42 setup of map view (cameras ...)
43 loading the map
44 GUI for right clicks
45 handles mouse/key events which aren't handled by the GUI.
46 ( by inheriting from EventlistenerBase )
47
48 That's obviously too much, and should get factored out.
49 """
38 def __init__(self, engine): 50 def __init__(self, engine):
39 super(World, self).__init__(engine, regMouse=True, regKeys=True) 51 super(World, self).__init__(engine, regMouse=True, regKeys=True)
40 self.engine = engine 52 self.engine = engine
41 self.eventmanager = engine.getEventManager() 53 self.eventmanager = engine.getEventManager()
42 self.model = engine.getModel() 54 self.model = engine.getModel()
47 self.instancemenu = None 59 self.instancemenu = None
48 self.instance_to_agent = {} 60 self.instance_to_agent = {}
49 self.dynamic_widgets = {} 61 self.dynamic_widgets = {}
50 62
51 def show_instancemenu(self, clickpoint, instance): 63 def show_instancemenu(self, clickpoint, instance):
64 """
65 Build and show a popupmenu for an instance that the player
66 clicked on. The available actions are dynamically added to
67 the menu (and mapped to the onXYZ functions).
68 """
52 if instance.getFifeId() == self.hero.agent.getFifeId(): 69 if instance.getFifeId() == self.hero.agent.getFifeId():
53 return 70 return
54 71
55 dynamicbuttons = ('moveButton', 'talkButton', 'kickButton', 'inspectButton') 72 # Create the popup.
56 if not self.instancemenu: 73 self.build_instancemenu()
57 self.instancemenu = pychan.loadXML('gui/instancemenu.xml')
58 self.instancemenu.mapEvents({
59 'moveButton' : self.onMoveButtonPress,
60 'talkButton' : self.onTalkButtonPress,
61 'kickButton' : self.onKickButtonPress,
62 'inspectButton' : self.onInspectButtonPress,
63 })
64 for btn in dynamicbuttons:
65 self.dynamic_widgets[btn] = self.instancemenu.findChild(name=btn)
66 for btn in dynamicbuttons:
67 try:
68 self.instancemenu.removeChild(self.dynamic_widgets[btn])
69 except pychan.exceptions.RuntimeError:
70 pass
71
72 self.instancemenu.clickpoint = clickpoint 74 self.instancemenu.clickpoint = clickpoint
73 self.instancemenu.instance = instance 75 self.instancemenu.instance = instance
74 76
77 # Add the buttons according to circumstances.
75 self.instancemenu.addChild(self.dynamic_widgets['inspectButton']) 78 self.instancemenu.addChild(self.dynamic_widgets['inspectButton'])
76 target_distance = self.hero.agent.getLocationRef().getLayerDistanceTo(instance.getLocationRef()) 79 target_distance = self.hero.agent.getLocationRef().getLayerDistanceTo(instance.getLocationRef())
77 if target_distance > 3.0: 80 if target_distance > 3.0:
78 self.instancemenu.addChild(self.dynamic_widgets['moveButton']) 81 self.instancemenu.addChild(self.dynamic_widgets['moveButton'])
79 else: 82 else:
80 if self.instance_to_agent.has_key(instance.getFifeId()): 83 if self.instance_to_agent.has_key(instance.getFifeId()):
81 self.instancemenu.addChild(self.dynamic_widgets['talkButton']) 84 self.instancemenu.addChild(self.dynamic_widgets['talkButton'])
82 self.instancemenu.addChild(self.dynamic_widgets['kickButton']) 85 self.instancemenu.addChild(self.dynamic_widgets['kickButton'])
86 # And show it :)
83 self.instancemenu.position = (clickpoint.x, clickpoint.y) 87 self.instancemenu.position = (clickpoint.x, clickpoint.y)
84 self.instancemenu.show() 88 self.instancemenu.show()
89
90 def build_instancemenu(self):
91 """
92 Just loads the menu from an XML file
93 and hooks the events up.
94 The buttons are removed and later re-added if appropiate.
95 """
96 dynamicbuttons = ('moveButton', 'talkButton', 'kickButton', 'inspectButton')
97 self.instancemenu = pychan.loadXML('gui/instancemenu.xml')
98 self.instancemenu.mapEvents({
99 'moveButton' : self.onMoveButtonPress,
100 'talkButton' : self.onTalkButtonPress,
101 'kickButton' : self.onKickButtonPress,
102 'inspectButton' : self.onInspectButtonPress,
103 })
104 for btn in dynamicbuttons:
105 self.dynamic_widgets[btn] = self.instancemenu.findChild(name=btn)
106 self.instancemenu.removeAllChildren()
85 107
86 def hide_instancemenu(self): 108 def hide_instancemenu(self):
87 if self.instancemenu: 109 if self.instancemenu:
88 self.instancemenu.hide() 110 self.instancemenu.hide()
89 111
90 def reset(self): 112 def reset(self):
113 """
114 Clear the agent information and reset the moving secondary camera state.
115 """
91 self.map, self.agentlayer = None, None 116 self.map, self.agentlayer = None, None
92 self.cameras = {} 117 self.cameras = {}
93 self.hero, self.girl, self.clouds, self.beekeepers = None, None, [], [] 118 self.hero, self.girl, self.clouds, self.beekeepers = None, None, [], []
94 self.cur_cam2_x, self.initial_cam2_x, self.cam2_scrolling_right = 0, 0, True 119 self.cur_cam2_x, self.initial_cam2_x, self.cam2_scrolling_right = 0, 0, True
95 self.target_rotation = 0 120 self.target_rotation = 0
96 self.instance_to_agent = {} 121 self.instance_to_agent = {}
97 122
98 def load(self, filename): 123 def load(self, filename):
124 """
125 Load a xml map and setup agents and cameras.
126 """
99 self.filename = filename 127 self.filename = filename
100 self.reset() 128 self.reset()
101 self.map = loadMapFile(filename, self.engine) 129 self.map = loadMapFile(filename, self.engine)
102 self.maplistener = MapListener(self.map) 130 self.maplistener = MapListener(self.map)
103 131
132 self.initAgents()
133 self.initCameras()
134
135 def initAgents(self):
136 """
137 Setup agents.
138
139 For this techdemo we have a very simple 'active things on the map' model,
140 which is called agents. All rio maps will have a separate layer for them.
141
142 Note that we keep a mapping from map instances (C++ model of stuff on the map)
143 to the python agents for later reference.
144 """
104 self.agentlayer = self.map.getLayer('TechdemoMapGroundObjectLayer') 145 self.agentlayer = self.map.getLayer('TechdemoMapGroundObjectLayer')
105 self.hero = Hero(self.model, 'PC', self.agentlayer) 146 self.hero = Hero(self.model, 'PC', self.agentlayer)
106 self.instance_to_agent[self.hero.agent.getFifeId()] = self.hero 147 self.instance_to_agent[self.hero.agent.getFifeId()] = self.hero
107 self.hero.start() 148 self.hero.start()
108 149
113 self.beekeepers = create_anonymous_agents(self.model, 'beekeeper', self.agentlayer, Beekeeper) 154 self.beekeepers = create_anonymous_agents(self.model, 'beekeeper', self.agentlayer, Beekeeper)
114 for beekeeper in self.beekeepers: 155 for beekeeper in self.beekeepers:
115 self.instance_to_agent[beekeeper.agent.getFifeId()] = beekeeper 156 self.instance_to_agent[beekeeper.agent.getFifeId()] = beekeeper
116 beekeeper.start() 157 beekeeper.start()
117 158
159 # Clouds are currently defunct.
118 cloudlayer = self.map.getLayer('TechdemoMapTileLayer') 160 cloudlayer = self.map.getLayer('TechdemoMapTileLayer')
119 self.clouds = create_anonymous_agents(self.model, 'Cloud', cloudlayer, Cloud) 161 self.clouds = create_anonymous_agents(self.model, 'Cloud', cloudlayer, Cloud)
120 for cloud in self.clouds: 162 for cloud in self.clouds:
121 cloud.start(0.1, 0.05) 163 cloud.start(0.1, 0.05)
122 164
165
166 def initCameras(self):
167 """
168 Before we can actually see something on screen we have to specify the render setup.
169 This is done through Camera objects which offer a viewport on the map.
170
171 For this techdemo two cameras are used. One follows the hero(!) via 'attach'
172 the other one scrolls around a bit (see the pump function).
173 """
123 for cam in self.view.getCameras(): 174 for cam in self.view.getCameras():
124 self.cameras[cam.getId()] = cam 175 self.cameras[cam.getId()] = cam
125 self.cameras['main'].attach(self.hero.agent) 176 self.cameras['main'].attach(self.hero.agent)
126 177
127 self.view.resetRenderers() 178 self.view.resetRenderers()
179 # Floating text renderers currntly only support one font.
180 # ... so we set that up.
181 # You'll se that for our demo we use a image font, so we have to specify the font glyphs
182 # for that one.
128 renderer = fife.FloatingTextRenderer.getInstance(self.cameras['main']) 183 renderer = fife.FloatingTextRenderer.getInstance(self.cameras['main'])
129 textfont = self.engine.getGuiManager().createFont('fonts/rpgfont.png', 0, str(TDS.readSetting("FontGlyphs", strip=False))); 184 textfont = self.engine.getGuiManager().createFont('fonts/rpgfont.png', 0, str(TDS.readSetting("FontGlyphs", strip=False)));
130 renderer.changeDefaultFont(textfont) 185 renderer.changeDefaultFont(textfont)
131 186
187 # The small camera shouldn't be cluttered by the 'humm di dums' of our hero.
188 # So we disable the renderer simply by setting its font to None.
132 renderer = fife.FloatingTextRenderer.getInstance(self.cameras['small']) 189 renderer = fife.FloatingTextRenderer.getInstance(self.cameras['small'])
133 renderer.changeDefaultFont(None) 190 renderer.changeDefaultFont(None)
134 191
192 # The following renderers are used for debugging.
193 # Note that by default ( that is after calling View.resetRenderers or Camera.resetRenderers )
194 # renderers will be handed all layers. That's handled here.
135 renderer = self.cameras['main'].getRenderer('CoordinateRenderer') 195 renderer = self.cameras['main'].getRenderer('CoordinateRenderer')
136 renderer.clearActiveLayers() 196 renderer.clearActiveLayers()
137 renderer.addActiveLayer(self.map.getLayer(str(TDS.readSetting("CoordinateLayerName")))) 197 renderer.addActiveLayer(self.map.getLayer(str(TDS.readSetting("CoordinateLayerName"))))
138 198
139 renderer = self.cameras['main'].getRenderer('QuadTreeRenderer') 199 renderer = self.cameras['main'].getRenderer('QuadTreeRenderer')
140 renderer.setEnabled(True) 200 renderer.setEnabled(True)
141 renderer.clearActiveLayers() 201 renderer.clearActiveLayers()
142 if str(TDS.readSetting("QuadTreeLayerName")): 202 if str(TDS.readSetting("QuadTreeLayerName")):
143 renderer.addActiveLayer(self.map.getLayer(str(TDS.readSetting("QuadTreeLayerName")))) 203 renderer.addActiveLayer(self.map.getLayer(str(TDS.readSetting("QuadTreeLayerName"))))
144 204
145 self.cameras['small'].getLocationRef().setExactLayerCoordinates( fife.ExactModelCoordinate( 40.0, 40.0, 0.0 )) 205 # Set up the second camera
206 # NOTE: We need to explicitly call setLocation, there's a bit of a messup in the Camera code.
207 self.cameras['small'].setLocation(self.hero.agent.getLocation())
208 #self.cameras['small'].getLocationRef().setExactLayerCoordinates( fife.ExactModelCoordinate( 40.0, 40.0, 0.0 ))
146 self.initial_cam2_x = self.cameras['small'].getLocation().getExactLayerCoordinates().x 209 self.initial_cam2_x = self.cameras['small'].getLocation().getExactLayerCoordinates().x
147 self.cur_cam2_x = self.initial_cam2_x 210 self.cur_cam2_x = self.initial_cam2_x
148 self.cam2_scrolling_right = True 211 self.cam2_scrolling_right = True
149 # We need to set the second cameras location
150 self.cameras['small'].setLocation(self.hero.agent.getLocation())
151 self.target_rotation = self.cameras['main'].getRotation() 212 self.target_rotation = self.cameras['main'].getRotation()
152 213
153 def save(self, filename): 214 def save(self, filename):
154 saveMapFile(filename, self.engine, self.map) 215 saveMapFile(filename, self.engine, self.map)
155 216
164 r.setEnabled(not r.isEnabled()) 225 r.setEnabled(not r.isEnabled())
165 elif keystr == 's': 226 elif keystr == 's':
166 c = self.cameras['small'] 227 c = self.cameras['small']
167 c.setEnabled(not c.isEnabled()) 228 c.setEnabled(not c.isEnabled())
168 elif keystr == 'r': 229 elif keystr == 'r':
169 pass 230 self.model.deleteMaps()
170 # self.model.deleteMaps() 231 self.view.clearCameras()
171 # self.metamodel.deleteDatasets() 232 self.load(self.filename)
172 # self.view.clearCameras()
173 # self.load(self.filename)
174 elif keystr == 'o': 233 elif keystr == 'o':
175 self.target_rotation = (self.target_rotation + 90) % 360 234 self.target_rotation = (self.target_rotation + 90) % 360
176 elif keyval in (fife.Key.LEFT_CONTROL, fife.Key.RIGHT_CONTROL): 235 elif keyval in (fife.Key.LEFT_CONTROL, fife.Key.RIGHT_CONTROL):
177 self.ctrldown = True 236 self.ctrldown = True
178 237
225 284
226 def onConsoleCommand(self, command): 285 def onConsoleCommand(self, command):
227 result = '' 286 result = ''
228 try: 287 try:
229 result = str(eval(command)) 288 result = str(eval(command))
230 except: 289 except Exception, e:
231 pass 290 result = str(e)
232 return result 291 return result
233 292
293 # Callbacks from the popupmenu
234 def onMoveButtonPress(self): 294 def onMoveButtonPress(self):
235 self.hide_instancemenu() 295 self.hide_instancemenu()
236 self.hero.run(self.instancemenu.instance.getLocationRef()) 296 self.hero.run(self.instancemenu.instance.getLocationRef())
237 297
238 def onTalkButtonPress(self): 298 def onTalkButtonPress(self):