Mercurial > parpg-core
comparison src/parpg/gamemodel.py @ 0:1fd2201f5c36
Initial commit of parpg-core.
author | M. George Hansen <technopolitica@gmail.com> |
---|---|
date | Sat, 14 May 2011 01:12:35 -0700 |
parents | |
children | d60f1dab8469 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:1fd2201f5c36 |
---|---|
1 # This file is part of PARPG. | |
2 | |
3 # PARPG is free software: you can redistribute it and/or modify | |
4 # it under the terms of the GNU General Public License as published by | |
5 # the Free Software Foundation, either version 3 of the License, or | |
6 # (at your option) any later version. | |
7 | |
8 # PARPG is distributed in the hope that it will be useful, | |
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 # GNU General Public License for more details. | |
12 | |
13 # You should have received a copy of the GNU General Public License | |
14 # along with PARPG. If not, see <http://www.gnu.org/licenses/>. | |
15 | |
16 # there should be NO references to FIFE here! | |
17 import sys | |
18 import os.path | |
19 import logging | |
20 from copy import deepcopy | |
21 | |
22 from fife import fife | |
23 from fife.extensions.serializers.xmlobject import XMLObjectLoader | |
24 | |
25 from gamestate import GameState | |
26 from objects import createObject | |
27 from objects.composed import CarryableItem, CarryableContainer | |
28 from gamemap import GameMap | |
29 from common.utils import locateFiles | |
30 from common.utils import parseBool | |
31 from inventory import Inventory | |
32 from parpg.dialogueparsers import YamlDialogueParser, DialogueFormatError | |
33 | |
34 try: | |
35 import xml.etree.cElementTree as ElementTree | |
36 except ImportError: | |
37 import xml.etree.ElementTree as ElementTree | |
38 | |
39 import yaml | |
40 | |
41 logger = logging.getLogger('gamemodel') | |
42 | |
43 class GameModel(object): | |
44 """GameModel holds the logic for the game. | |
45 Since some data (object position and so forth) is held in the | |
46 fife, and would be pointless to replicate, we hold a instance of | |
47 the fife view here. This also prevents us from just having a | |
48 function heavy controller.""" | |
49 ALL_AGENTS_KEY = "All" | |
50 MAX_ID_NUMBER = 1000 | |
51 | |
52 def __init__(self, engine, settings): | |
53 """Initialize the instance. | |
54 @param engine: A fife.Engine object | |
55 @type emgome: fife.Engine | |
56 @param setting: The applications settigns | |
57 @type setting: parpg.settings.Settings object | |
58 @return: None""" | |
59 self.settings = settings | |
60 | |
61 self.map_change = False | |
62 self.load_saver = False | |
63 self.savegame = None | |
64 quests_directory = os.path.join(self.settings.system_path, | |
65 self.settings.parpg.QuestsPath) | |
66 self.game_state = GameState(quests_dir=quests_directory) | |
67 #self.game_state.quest_engine = | |
68 #self.game_state.quest_engine.readQuests() | |
69 self.pc_run = 1 | |
70 self.target_position = None | |
71 self.target_map_name = None | |
72 self.object_db = {} | |
73 self.active_map = None | |
74 self.map_files = {} | |
75 self.agents = {} | |
76 self.agents[self.ALL_AGENTS_KEY] = {} | |
77 self.engine = engine | |
78 self.fife_model = engine.getModel() | |
79 | |
80 # set values from settings | |
81 maps_file = os.path.join(self.settings.system_path, | |
82 self.settings.parpg.MapsPath, | |
83 self.settings.parpg.MapsFile) | |
84 self.game_state.maps_file = maps_file | |
85 all_agents_file = os.path.join(self.settings.system_path, | |
86 self.settings.parpg.MapsPath, | |
87 self.settings.parpg.AllAgentsFile) | |
88 self.all_agents_file = all_agents_file | |
89 objects_dir = os.path.join(self.settings.system_path, | |
90 self.settings.parpg.ObjectsPath) | |
91 self.objects_directory = objects_dir | |
92 object_db_file = os.path.join(self.objects_directory, | |
93 self.settings.parpg.ObjectDatabaseFile) | |
94 self.object_db_file = object_db_file | |
95 dialogues_dir = os.path.join(self.settings.system_path, | |
96 self.settings.parpg.DialoguesPath) | |
97 self.dialogues_directory = dialogues_dir | |
98 self.dialogues = {} | |
99 self.agent_import_files = {} | |
100 self.obj_loader = XMLObjectLoader( | |
101 self.engine.getImagePool(), | |
102 self.engine.getAnimationPool(), | |
103 self.engine.getModel(), | |
104 self.engine.getVFS() | |
105 ) | |
106 | |
107 def checkAttributes(self, attributes): | |
108 """Checks for attributes that where not given in the map file | |
109 and fills them with values from the object database | |
110 @param attributes: attributes to check | |
111 @type attributes: Dictionary | |
112 @return: The modified attributes""" | |
113 if attributes.has_key("object_type"): | |
114 class_name = attributes.pop("object_type") | |
115 else: | |
116 class_name = attributes["type"] | |
117 if not attributes.has_key("type"): | |
118 attributes["type"] = class_name | |
119 if self.object_db.has_key(class_name): | |
120 db_attributes = deepcopy(self.object_db[class_name]) | |
121 for key in db_attributes.keys(): | |
122 if attributes.has_key(key): | |
123 attributes[key] = attributes[key] or db_attributes[key] | |
124 else: | |
125 attributes[key] = db_attributes[key] | |
126 return attributes | |
127 | |
128 def isIDUsed(self, ID): | |
129 if self.game_state.hasObject(ID): | |
130 return True | |
131 for namespace in self.agents: | |
132 if ID in self.agents[namespace]: | |
133 return True | |
134 return False | |
135 | |
136 def createUniqueID(self, ID): | |
137 if self.isIDUsed(ID): | |
138 id_number = 1 | |
139 while self.isIDUsed(ID + "_" + str(id_number)): | |
140 id_number += 1 | |
141 if id_number > self.MAX_ID_NUMBER: | |
142 raise ValueError( | |
143 "Number exceeds MAX_ID_NUMBER:" + str(self.MAX_ID_NUMBER)) | |
144 | |
145 ID = ID + "_" + str(id_number) | |
146 return ID | |
147 | |
148 def createContainerItems(self, container_objs): | |
149 """Create the items of a container from a dictionary | |
150 @param container_objs: Dictionary containing the items | |
151 @type container_objs: dict""" | |
152 items = [] | |
153 for container_obj in container_objs: | |
154 items.append(self.createContainerObject(container_obj)) | |
155 | |
156 return items | |
157 | |
158 def createContainerObject(self, attributes): | |
159 """Create an object that can be stored in | |
160 an container and return it | |
161 @param attributes: Dictionary of all object attributes | |
162 @type attributes: Dictionary | |
163 @return: The created object """ | |
164 # create the extra data | |
165 extra = {} | |
166 extra['controller'] = self | |
167 attributes = self.checkAttributes(attributes) | |
168 | |
169 info = {} | |
170 info.update(attributes) | |
171 info.update(extra) | |
172 ID = info.pop("id") if info.has_key("id") else info.pop("ID") | |
173 if not info.has_key("item_type"): | |
174 info["item_type"] = info["type"] | |
175 ID = self.createUniqueID(ID) | |
176 if info.has_key("attributes"): | |
177 attributes = info["attributes"] | |
178 if "Container" in attributes: | |
179 info["actions"]["Open"] = "" | |
180 if info.has_key("Items"): | |
181 inventory_objs = info["Items"] | |
182 info["items"] = self.createContainerItems(inventory_objs) | |
183 | |
184 new_item = CarryableContainer(ID = ID, **info) | |
185 else: | |
186 new_item = CarryableItem(ID = ID, **info) | |
187 else: | |
188 new_item = CarryableItem(ID = ID, **info) | |
189 self.game_state.addObject(None, new_item) | |
190 return new_item | |
191 | |
192 def createInventoryObject(self, container, attributes): | |
193 """Create an inventory object and place it into a container | |
194 @type container: base.Container | |
195 @param container: Container where the item is on | |
196 @type attributes: Dictionary | |
197 @param attributes: Dictionary of all object attributes | |
198 @return: None""" | |
199 index = attributes.pop("index") if attributes.has_key("index") else None | |
200 slot = attributes.pop("slot") if attributes.has_key("slot") else None | |
201 obj = self.createContainerObject(attributes) | |
202 #obj = createObject(attributes, extra) | |
203 if slot: | |
204 container.moveItemToSlot(obj, slot) | |
205 else: | |
206 container.placeItem(obj, index) | |
207 | |
208 def deleteObject(self, object_id): | |
209 """Removes an object from the game | |
210 @param object_id: ID of the object | |
211 @type object_id: str """ | |
212 del self.agents["All"][object_id] | |
213 self.game_state.deleteObject(object_id) | |
214 | |
215 def save(self, path, filename): | |
216 """Writes the saver to a file. | |
217 @type filename: string | |
218 @param filename: the name of the file to write to | |
219 @return: None""" | |
220 fname = '/'.join([path, filename]) | |
221 try: | |
222 save_file = open(fname, 'w') | |
223 except(IOError): | |
224 sys.stderr.write("Error: Can't create save game: " + fname + "\n") | |
225 return | |
226 save_state = {} | |
227 save_state["Agents"] = {} | |
228 for map_name in self.agents: | |
229 if map_name == self.ALL_AGENTS_KEY: | |
230 continue | |
231 agents_dict = {} | |
232 for agent in self.agents[map_name]: | |
233 agent_obj = self.game_state.getObjectById(agent, map_name) | |
234 agent_inst = self.game_state.maps[map_name].\ | |
235 agent_layer.getInstance(agent) | |
236 agent_dict = self.agents[map_name][agent] | |
237 agent_dict.update(agent_obj.getStateForSaving()) | |
238 agent_dict["Rotation"] = agent_inst.getRotation() | |
239 agents_dict[agent] = agent_dict | |
240 save_state["Agents"][map_name] = agents_dict | |
241 agents_dict = {} | |
242 for agent in self.agents["All"]: | |
243 map_name = self.agents["All"][agent]["Map"] | |
244 agent_dict = self.agents["All"][agent] | |
245 agent_obj = None | |
246 if agent == "PlayerCharacter": | |
247 agent_obj = self.game_state.player_character | |
248 else: | |
249 agent_obj = self.game_state.getObjectById(agent, map_name) | |
250 if agent_obj: | |
251 agent_inst = self.game_state.maps[map_name].\ | |
252 agent_layer.getInstance(agent) | |
253 agent_dict.update(agent_obj.getStateForSaving()) | |
254 agent_dict["Rotation"] = agent_inst.getRotation() | |
255 agent_dict["MapName"] = map_name | |
256 agents_dict[agent] = agent_dict | |
257 save_state["Agents"]["All"] = agents_dict | |
258 save_state["GameState"] = self.game_state.getStateForSaving() | |
259 yaml.dump(save_state, save_file) | |
260 | |
261 save_file.close() | |
262 | |
263 def load(self, path, filename): | |
264 """Loads a saver from a file. | |
265 @type filename: string | |
266 @param filename: the name of the file (including path) to load from | |
267 @return: None""" | |
268 fname = '/'.join([path, filename]) | |
269 | |
270 try: | |
271 load_file = open(fname, 'r') | |
272 except(IOError): | |
273 sys.stderr.write("Error: Can't find save game file\n") | |
274 return | |
275 self.deleteMaps() | |
276 self.clearAgents() | |
277 | |
278 save_state = yaml.load(load_file) | |
279 self.game_state.restoreFromState(save_state["GameState"]) | |
280 maps = save_state["Agents"] | |
281 for map_name in maps: | |
282 for agent_name in maps[map_name]: | |
283 agent = {agent_name:maps[map_name][agent_name]} | |
284 self.addAgent(map_name, agent) | |
285 | |
286 # Load the current map | |
287 if self.game_state.current_map_name: | |
288 self.loadMap(self.game_state.current_map_name) | |
289 load_file.close() | |
290 | |
291 | |
292 # Recreate all the behaviours. These can't be saved because FIFE | |
293 # objects cannot be pickled | |
294 | |
295 self.placeAgents() | |
296 self.placePC() | |
297 | |
298 # In most maps we'll create the PlayerCharacter Instance internally. | |
299 # In these cases we need a target position | |
300 | |
301 def teleport(self, agent, position): | |
302 """Called when a an agent is moved instantly to a new position. | |
303 The setting of position may wan to be created as its own method down the road. | |
304 @type position: String Tuple | |
305 @param position: X,Y coordinates passed from engine.changeMap | |
306 @return: fife.Location""" | |
307 logging.debug(position) | |
308 coord = fife.DoublePoint3D(float(position[0]), float(position[1]), 0) | |
309 location = fife.Location(self.active_map.agent_layer) | |
310 location.setMapCoordinates(coord) | |
311 agent.teleport(location) | |
312 | |
313 def getObjectAtCoords(self, coords): | |
314 """Get the object which is at the given coords | |
315 @type coords: fife.Screenpoint | |
316 @param coords: Coordinates where to check for an object | |
317 @rtype: fife.Object | |
318 @return: An object or None""" | |
319 instances = self.active_map.cameras[ | |
320 self.active_map.my_cam_id].\ | |
321 getMatchingInstances(coords, self.active_map.agent_layer) | |
322 # no object returns an empty tuple | |
323 if(instances != ()): | |
324 front_y = 0 | |
325 | |
326 | |
327 for obj in instances: | |
328 # check to see if this in our list at all | |
329 if(self.objectActive(obj.getId())): | |
330 # check if the object is on the foreground | |
331 obj_map_coords = \ | |
332 obj.getLocation().getMapCoordinates() | |
333 obj_screen_coords = self.active_map.\ | |
334 cameras[self.active_map.my_cam_id]\ | |
335 .toScreenCoordinates(obj_map_coords) | |
336 | |
337 if obj_screen_coords.y > front_y: | |
338 #Object on the foreground | |
339 front_y = obj_screen_coords.y | |
340 return obj | |
341 else: | |
342 return None | |
343 else: | |
344 return None | |
345 | |
346 def getCoords(self, click): | |
347 """Get the map location x, y coordinates from the screen coordinates | |
348 @type click: fife.ScreenPoint | |
349 @param click: Screen coordinates | |
350 @rtype: fife.Location | |
351 @return: The map coordinates""" | |
352 coord = self.active_map.cameras[self.active_map.my_cam_id].\ | |
353 toMapCoordinates(click, False) | |
354 coord.z = 0 | |
355 location = fife.Location(self.active_map.agent_layer) | |
356 location.setMapCoordinates(coord) | |
357 return location | |
358 | |
359 def pause(self, paused): | |
360 """ Pause/Unpause the game | |
361 @return: nothing""" | |
362 if self.active_map: | |
363 self.active_map.pause(paused) | |
364 | |
365 def togglePause(self): | |
366 """ Toggle paused state. | |
367 @return: nothing""" | |
368 self.active_map.togglePause() | |
369 | |
370 def isPaused(self): | |
371 """Returns wheter the game is paused or not""" | |
372 return self.active_map.isPaused() | |
373 | |
374 def readMapFiles(self): | |
375 """Read all a available map-files and store them""" | |
376 maps_data = file(self.game_state.maps_file) | |
377 self.map_files = yaml.load(maps_data)["Maps"] | |
378 | |
379 def addAgent(self, namespace, agent): | |
380 """Adds an agent to the agents dictionary | |
381 @param namespace: the namespace where the agent is to be added to | |
382 @type namespace: str | |
383 @param agent: The agent to be added | |
384 @type agent: dict """ | |
385 from fife.extensions.serializers.xml_loader_tools import loadImportFile | |
386 if not self.agents.has_key(namespace): | |
387 self.agents[namespace] = {} | |
388 | |
389 agent_values = agent.values()[0] | |
390 unique_agent_id = self.createUniqueID(agent.keys()[0]) | |
391 del agent[agent.keys()[0]] | |
392 agent[unique_agent_id] = agent_values | |
393 self.agents[namespace].update(agent) | |
394 object_model = "" | |
395 if agent_values.has_key("ObjectModel"): | |
396 object_model = agent_values["ObjectModel"] | |
397 elif agent_values["ObjectType"] == "MapItem": | |
398 object_data = self.object_db[agent_values["ItemType"]] | |
399 object_model = object_data["gfx"] if object_data.has_key("gfx") \ | |
400 else "generic_item" | |
401 else: | |
402 object_model = self.object_db[agent_values["ObjectType"]]["gfx"] | |
403 import_file = self.agent_import_files[object_model] | |
404 loadImportFile(self.obj_loader, import_file, self.engine) | |
405 | |
406 def readAgentsOfMap(self, map_name): | |
407 """Read the agents of the map | |
408 @param map_name: Name of the map | |
409 @type map_name: str """ | |
410 #Get the agents of the map | |
411 map_agents_file = self.map_files[map_name].\ | |
412 replace(".xml", "_agents.yaml") | |
413 agents_data = file(map_agents_file) | |
414 agents = yaml.load_all(agents_data) | |
415 for agent in agents: | |
416 if not agent == None: | |
417 self.addAgent(map_name, agent) | |
418 | |
419 def readAllAgents(self): | |
420 """Read the agents of the all_agents_file and store them""" | |
421 agents_data = file(self.all_agents_file) | |
422 agents = yaml.load_all(agents_data) | |
423 for agent in agents: | |
424 if not agent == None: | |
425 self.addAgent(self.ALL_AGENTS_KEY, agent) | |
426 | |
427 def getAgentsOfMap(self, map_name): | |
428 """Returns the agents that are on the given map | |
429 @param map_name: Name of the map | |
430 @type map_name: str | |
431 @return: A dictionary with the agents of the map""" | |
432 if not self.agents.has_key(map_name): | |
433 return {} | |
434 ret_dict = self.agents[map_name].copy() | |
435 for agent_name, agent_value in self.agents[self.ALL_AGENTS_KEY]\ | |
436 .iteritems(): | |
437 if agent_value["Map"] == map_name: | |
438 ret_dict[agent_name] = agent_value | |
439 return ret_dict | |
440 | |
441 def getAgentsOfActiveMap(self): | |
442 """Returns the agents that are on active map | |
443 @return: A dictionary with the agents of the map """ | |
444 return self.getAgentsOfMap(self.active_map.map.getId()) | |
445 | |
446 def clearAgents(self): | |
447 """Resets the agents dictionary""" | |
448 self.agents = {} | |
449 self.agents[self.ALL_AGENTS_KEY] = {} | |
450 | |
451 def loadMap(self, map_name): | |
452 """Load a new map. | |
453 @type map_name: string | |
454 @param map_name: Name of the map to load | |
455 @return: None""" | |
456 if not map_name in self.game_state.maps: | |
457 map_file = self.map_files[map_name] | |
458 new_map = GameMap(self.engine, self) | |
459 self.game_state.maps[map_name] = new_map | |
460 new_map.load(map_file) | |
461 | |
462 def createAgent(self, agent, inst_id): | |
463 object_type = agent["ObjectType"] | |
464 object_id = agent["ObjectModel"] \ | |
465 if agent.has_key("ObjectModel") \ | |
466 else None | |
467 if object_id == None: | |
468 if object_type == "MapItem": | |
469 object_data = self.object_db[agent["ItemType"]] | |
470 object_id = object_data["gfx"] if object_data.has_key("gfx") \ | |
471 else "generic_item" | |
472 else: | |
473 object_id = self.object_db[object_type]["gfx"] | |
474 map_obj = self.fife_model.getObject(str(object_id), "PARPG") | |
475 if not map_obj: | |
476 logging.warning("Object with inst_id={0}, ns=PARPG, " | |
477 "could not be found. " | |
478 "Omitting...".format(str(obj_id))) | |
479 | |
480 x_pos = agent["Position"][0] | |
481 y_pos = agent["Position"][1] | |
482 z_pos = agent["Position"][2] if len(agent["Position"]) == 3 \ | |
483 else -0.1 if object_type == "MapItem" \ | |
484 else 0.0 | |
485 stack_pos = agent["Stackposition"] if \ | |
486 agent.has_key("StackPosition") \ | |
487 else None | |
488 inst = self.active_map.agent_layer.\ | |
489 createInstance(map_obj, | |
490 fife.ExactModelCoordinate(x_pos, | |
491 y_pos, | |
492 z_pos), | |
493 inst_id) | |
494 inst.setId(inst_id) | |
495 | |
496 rotation = agent["Rotation"] | |
497 inst.setRotation(rotation) | |
498 | |
499 fife.InstanceVisual.create(inst) | |
500 if (stack_pos): | |
501 inst.get2dGfxVisual().setStackPosition(int(stack_pos)) | |
502 | |
503 if (map_obj.getAction('default')): | |
504 target = fife.Location(self.active_map.agent_layer) | |
505 inst.act('default', target, True) | |
506 | |
507 inst_dict = {} | |
508 inst_dict["id"] = inst_id | |
509 inst_dict["type"] = object_type | |
510 inst_dict["xpos"] = x_pos | |
511 inst_dict["ypos"] = y_pos | |
512 inst_dict["gfx"] = object_id | |
513 inst_dict["is_open"] = parseBool(agent["Open"]) \ | |
514 if agent.has_key("Open") \ | |
515 else False | |
516 inst_dict["locked"] = parseBool(agent["Locked"]) \ | |
517 if agent.has_key("Locked") \ | |
518 else False | |
519 inst_dict["name"] = agent["ViewName"] | |
520 inst_dict["real_name"] = agent["RealName"] \ | |
521 if agent.has_key("RealName") \ | |
522 else agent["ViewName"] | |
523 inst_dict["text"] = agent["Text"] \ | |
524 if agent.has_key("Text") \ | |
525 else None | |
526 if self.dialogues.has_key(inst_id): | |
527 inst_dict["dialogue"] = self.dialogues[inst_id] | |
528 inst_dict["target_map_name"] = agent["TargetMap"] \ | |
529 if agent.\ | |
530 has_key("TargetMap") \ | |
531 else None | |
532 inst_dict["target_x"] = agent["TargetPosition"][0] \ | |
533 if agent.\ | |
534 has_key("TargetPosition") \ | |
535 else None | |
536 inst_dict["target_y"] = agent["TargetPosition"][1] \ | |
537 if agent.\ | |
538 has_key("TargetPosition") \ | |
539 else None | |
540 if agent.has_key("Inventory"): | |
541 inventory = Inventory() | |
542 inventory_objs = agent["Inventory"] | |
543 for inventory_obj in inventory_objs: | |
544 self.createInventoryObject(inventory, | |
545 inventory_obj | |
546 ) | |
547 inst_dict["inventory"] = inventory | |
548 | |
549 if agent.has_key("Items"): | |
550 container_objs = agent["Items"] | |
551 items = self.createContainerItems(container_objs) | |
552 inst_dict["items"] = items | |
553 | |
554 if agent.has_key("ItemType"): | |
555 if not agent.has_key("item"): | |
556 item_data = {} | |
557 item_data["type"] = agent["ItemType"] | |
558 item_data["ID"] = inst_id | |
559 item_data = self.createContainerObject(item_data) | |
560 else: | |
561 item_data = agent["item"] | |
562 inst_dict["item"] = item_data | |
563 inst_dict["item_type"] = agent["ItemType"] | |
564 | |
565 self.createMapObject(self.active_map.agent_layer, inst_dict) | |
566 | |
567 def placeAgents(self): | |
568 """Places the current maps agents """ | |
569 if not self.active_map: | |
570 return | |
571 agents = self.getAgentsOfMap(self.game_state.current_map_name) | |
572 for agent in agents: | |
573 if agent == "PlayerCharacter": | |
574 continue | |
575 if self.active_map.agent_layer.getInstances(agent): | |
576 continue | |
577 self.createAgent(agents[agent], agent) | |
578 | |
579 def placePC(self): | |
580 """Places the PlayerCharacter on the map""" | |
581 agent = self.agents[self.ALL_AGENTS_KEY]["PlayerCharacter"] | |
582 inst_id = "PlayerCharacter" | |
583 self.createAgent(agent, inst_id) | |
584 | |
585 # create the PlayerCharacter agent | |
586 self.active_map.addPC() | |
587 self.game_state.player_character.start() | |
588 if agent.has_key("PeopleKnown"): | |
589 self.game_state.player_character.people_i_know = agent["PeopleKnown"] | |
590 | |
591 def changeMap(self, map_name, target_position = None): | |
592 """Registers for a map change on the next pump(). | |
593 @type map_name: String | |
594 @param map_name: Id of the map to teleport to | |
595 @type map_file: String | |
596 @param map_file: Filename of the map to teleport to | |
597 @type target_position: Tuple | |
598 @param target_position: Position of PlayerCharacter on target map. | |
599 @return None""" | |
600 # set the parameters for the map change if moving to a new map | |
601 if map_name != self.game_state.current_map_name: | |
602 self.target_map_name = map_name | |
603 self.target_position = target_position | |
604 # issue the map change | |
605 self.map_change = True | |
606 | |
607 def deleteMaps(self): | |
608 """Clear all currently loaded maps from FIFE as well as clear our | |
609 local map cache | |
610 @return: nothing""" | |
611 self.engine.getModel().deleteMaps() | |
612 self.engine.getModel().deleteObjects() | |
613 self.game_state.clearObjects() | |
614 self.game_state.maps = {} | |
615 | |
616 def setActiveMap(self, map_name): | |
617 """Sets the active map that is to be rendered. | |
618 @type map_name: String | |
619 @param map_name: The name of the map to load | |
620 @return: None""" | |
621 # Turn off the camera on the old map before we turn on the camera | |
622 # on the new map. | |
623 self.active_map.cameras[self.active_map.my_cam_id].setEnabled(False) | |
624 # Make the new map active. | |
625 self.active_map = self.game_state.maps[map_name] | |
626 self.active_map.makeActive() | |
627 self.game_state.current_map_name = map_name | |
628 | |
629 def createMapObject (self, layer, attributes): | |
630 """Create an object and add it to the current map. | |
631 @type layer: fife.Layer | |
632 @param layer: FIFE layer object exists in | |
633 @type attributes: Dictionary | |
634 @param attributes: Dictionary of all object attributes | |
635 @type instance: fife.Instance | |
636 @param instance: FIFE instance corresponding to the object | |
637 @return: None""" | |
638 # create the extra data | |
639 extra = {} | |
640 if layer is not None: | |
641 extra['agent_layer'] = layer | |
642 attributes = self.checkAttributes(attributes) | |
643 | |
644 obj = createObject(attributes, extra) | |
645 | |
646 if obj.trueAttr("PC"): | |
647 self.addPC(layer, obj) | |
648 else: | |
649 self.addObject(layer, obj) | |
650 | |
651 def addPC(self, layer, player_char): | |
652 """Add the PlayerCharacter to the map | |
653 @type layer: fife.Layer | |
654 @param layer: FIFE layer object exists in | |
655 @type player_char: PlayerCharacter | |
656 @param player_char: PlayerCharacter object | |
657 @type instance: fife.Instance | |
658 @param instance: FIFE instance of PlayerCharacter | |
659 @return: None""" | |
660 # For now we copy the PlayerCharacter, | |
661 # in the future we will need to copy | |
662 # PlayerCharacter specifics between the different PlayerCharacter's | |
663 self.game_state.player_character = player_char | |
664 self.game_state.player_character.setup() | |
665 self.game_state.player_character.behaviour.speed = self.settings.parpg.PCSpeed | |
666 | |
667 | |
668 def addObject(self, layer, obj): | |
669 """Adds an object to the map. | |
670 @type layer: fife.Layer | |
671 @param layer: FIFE layer object exists in | |
672 @type obj: GameObject | |
673 @param obj: corresponding object class | |
674 @type instance: fife.Instance | |
675 @param instance: FIFE instance of object | |
676 @return: None""" | |
677 ref = self.game_state.getObjectById(obj.ID, \ | |
678 self.game_state.current_map_name) | |
679 if ref is None: | |
680 # no, add it to the game state | |
681 self.game_state.addObject(self.game_state.current_map_name, obj) | |
682 else: | |
683 # yes, use the current game state data | |
684 obj.X = ref.X | |
685 obj.Y = ref.Y | |
686 obj.gfx = ref.gfx | |
687 | |
688 if obj.trueAttr("NPC"): | |
689 # create the agent | |
690 obj.setup() | |
691 obj.behaviour.speed = self.settings.parpg.PCSpeed - 1 | |
692 # create the PlayerCharacter agent | |
693 obj.start() | |
694 if obj.trueAttr("AnimatedContainer"): | |
695 # create the agent | |
696 obj.setup() | |
697 | |
698 def objectActive(self, ident): | |
699 """Given the objects ID, pass back the object if it is active, | |
700 False if it doesn't exist or not displayed | |
701 @type ident: string | |
702 @param ident: ID of object | |
703 @rtype: boolean | |
704 @return: Status of result (True/False)""" | |
705 for game_object in \ | |
706 self.game_state.getObjectsFromMap(self.game_state.current_map_name): | |
707 if (game_object.ID == ident): | |
708 # we found a match | |
709 return game_object | |
710 # no match | |
711 return False | |
712 | |
713 def movePlayer(self, position): | |
714 """Code called when the player should move to another location | |
715 @type position: fife.ScreenPoint | |
716 @param position: Screen position to move to | |
717 @return: None""" | |
718 if(self.pc_run == 1): | |
719 self.game_state.player_character.run(position) | |
720 else: | |
721 self.game_state.player_character.walk(position) | |
722 | |
723 def teleportAgent(self, agent, position): | |
724 """Code called when an agent should teleport to another location | |
725 @type position: fife.ScreenPoint | |
726 @param position: Screen position to teleport to | |
727 @return: None""" | |
728 agent.teleport(position) | |
729 self.agents[agent.ID]["Position"] = position | |
730 | |
731 def readObjectDB(self): | |
732 """Reads the Object Information Database from a file. """ | |
733 database_file = file(self.object_db_file, "r") | |
734 database = yaml.load_all(database_file) | |
735 for object_info in database: | |
736 self.object_db.update(object_info) | |
737 | |
738 def getAgentImportFiles(self): | |
739 """Searches the agents directory for import files """ | |
740 files = locateFiles("*.xml", self.objects_directory) | |
741 for xml_file in files: | |
742 xml_file = os.path.relpath(xml_file).replace("\\", "/") | |
743 try: | |
744 root = ElementTree.parse(xml_file).getroot() | |
745 if root.tag == "object": | |
746 self.agent_import_files[root.attrib["id"]] = xml_file | |
747 except SyntaxError as error: | |
748 assert(isinstance(error, SyntaxError)) | |
749 logging.critical("Error parsing file {0}: " | |
750 "{1}".format(xml_file, error.msg)) | |
751 sys.exit(1) | |
752 | |
753 def getDialogues(self): | |
754 """Searches the dialogue directory for dialogues """ | |
755 files = locateFiles("*.yaml", self.dialogues_directory) | |
756 dialogue_parser = YamlDialogueParser() | |
757 for dialogue_filepath in files: | |
758 dialogue_filepath = os.path.relpath(dialogue_filepath) \ | |
759 .replace("\\", "/") | |
760 # Note Technomage 2010-11-13: the new DialogueEngine uses its own | |
761 # parser now, YamlDialogueParser. | |
762 # dialogues = yaml.load_all(file(dialogue_file, "r")) | |
763 with file(dialogue_filepath, 'r') as dialogue_file: | |
764 try: | |
765 dialogue = dialogue_parser.load(dialogue_file) | |
766 except (DialogueFormatError,) as error: | |
767 logging.error('unable to load dialogue file {0}: {1}' | |
768 .format(dialogue_filepath, error)) | |
769 else: | |
770 self.dialogues[dialogue.npc_name] = dialogue | |
771 # Note Technomage 2010-11-13: the below code is used to load | |
772 # multiple dialogues from a single file. Is this functionality | |
773 # used/necessary? | |
774 # for dialogue in dialogues: | |
775 # self.dialogues[dialogue["NPC"]] = dialogue |