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