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 | |
---|
18 | # there should be NO references to FIFE here! |
---|
19 | import fife |
---|
20 | from xml.sax import make_parser |
---|
21 | from xml.sax.handler import ContentHandler |
---|
22 | from agents.hero import Hero |
---|
23 | from agents.npc import NPC |
---|
24 | |
---|
25 | # design note: |
---|
26 | # there is a map file that FIFE reads. We use that file for half the map |
---|
27 | # format because the map editor in FIFE uses it, and secondly because it |
---|
28 | # save us writing a bunch of new code. |
---|
29 | # However, the objects and characters on a map are liable to change |
---|
30 | # whilst the game is being changed, so when we change the map, we |
---|
31 | # need to grab the objects and npc data EITHER from the engine state, |
---|
32 | # or from another file if in their initial state |
---|
33 | # This other file has the name AAA_objects.xml where AAA.xml is the name |
---|
34 | # of the original mapfile. |
---|
35 | |
---|
36 | class LocalXMLParser(ContentHandler): |
---|
37 | """Class inherits from ContantHandler, and is used to parse the |
---|
38 | local objects data""" |
---|
39 | def __init__(self): |
---|
40 | self.search="objects" |
---|
41 | self.pc=None |
---|
42 | self.objects=[] |
---|
43 | self.npcs=[] |
---|
44 | |
---|
45 | def startElement(self,name,attrs): |
---|
46 | """Called every time we meet a new element""" |
---|
47 | # we are only looking for the 'layer' elements, the rest we ignore |
---|
48 | if(name=="PC"): |
---|
49 | # already have a PC? |
---|
50 | if(self.pc!=None): |
---|
51 | sys.stderr.write("Error: 2 PC characters defined") |
---|
52 | sys.exit(False) |
---|
53 | # grab the data and store that as well |
---|
54 | try: |
---|
55 | xpos=attrs.getValue("xpos") |
---|
56 | ypos=attrs.getValue("ypos") |
---|
57 | except(KeyError): |
---|
58 | sys.stderr.write("Error: Data missing in PC definition") |
---|
59 | sys.exit(False) |
---|
60 | # store for later |
---|
61 | self.pc=[xpos,ypos] |
---|
62 | elif(name=="NPC"): |
---|
63 | # let's parse and add the data |
---|
64 | try: |
---|
65 | xpos=attrs.getValue("xpos") |
---|
66 | ypos=attrs.getValue("ypos") |
---|
67 | gfx=attrs.getValue("gfx") |
---|
68 | except(KeyError): |
---|
69 | sys.stderr.write("Error: Data missing in NPC definition\n") |
---|
70 | sys.exit(False) |
---|
71 | # now we have the data, save it for later |
---|
72 | self.npcs.append([xpos,ypos,gfx]) |
---|
73 | elif(name=="object"): |
---|
74 | # same old same old |
---|
75 | try: |
---|
76 | xpos=attrs.getValue("xpos") |
---|
77 | ypos=attrs.getValue("ypos") |
---|
78 | gfx=attrs.getValue("gfx") |
---|
79 | except(KeyError): |
---|
80 | sys.stderr.write("Error: Data missing in object definition\n") |
---|
81 | sys.exit(False) |
---|
82 | # now we have the data, save it for later |
---|
83 | self.objects.append([xpos,ypos,gfx]) |
---|
84 | |
---|
85 | class Engine: |
---|
86 | """Engine holds the logic for the game |
---|
87 | Since some data (object position and so forth) is held in the |
---|
88 | fife, and would be pointless to replicate, we hold a instance of |
---|
89 | the fife view here. This also prevents us from just having a |
---|
90 | function heavy controller""" |
---|
91 | def __init__(self,view): |
---|
92 | self.view=view |
---|
93 | self.PC=None |
---|
94 | self.npcs=[] |
---|
95 | self.objects=[] |
---|
96 | |
---|
97 | def loadObjects(self,filename): |
---|
98 | """Load objects from the XML file |
---|
99 | Returns True if it worked, False otherwise""" |
---|
100 | try: |
---|
101 | objects_file=open(filename,'rt') |
---|
102 | except(IOError): |
---|
103 | sys.stderr.write("Error: Can't find objects file\n") |
---|
104 | return False |
---|
105 | # now open and read the XML file |
---|
106 | parser=make_parser() |
---|
107 | cur_handler=LocalXMLParser() |
---|
108 | parser.setContentHandler(cur_handler) |
---|
109 | parser.parse(objects_file) |
---|
110 | objects_file.close() |
---|
111 | # must have at least 1 PC |
---|
112 | if(cur_handler.pc==None): |
---|
113 | sys.stderr.write("Error: No PC defined\n") |
---|
114 | sys.exit(False) |
---|
115 | # transfer the data |
---|
116 | self.pc=cur_handler.pc |
---|
117 | self.npcs=cur_handler.npcs |
---|
118 | self.objects=cur_handler.objects |
---|
119 | return True |
---|
120 | |
---|
121 | def loadMap(self,map_file): |
---|
122 | """Load a new map |
---|
123 | TODO: needs some error checking""" |
---|
124 | # first we go and grab the character details |
---|
125 | self.loadObjects(map_file[:-4]+"_objects.xml") |
---|
126 | # then we let FIFE load the rest of the map |
---|
127 | self.view.load(map_file) |
---|
128 | # finally, we update FIFE with the PC, NPC and object details |
---|
129 | self.view.addPC(self.pc[0],self.pc[1]) |
---|
130 | |
---|