source: trunk/game/local_loaders/xmlmap.py @ 336

Revision 336, 14.3 KB checked in by eliedebrauwer, 10 years ago (diff)

Ticket #122: Patch by eliedebrauwer, fixed problem with target position in the loading/saving of the map, map.xml is still faulty. comments[s:trac, t:122]

  • Property svn:eol-style set to native
Line 
1#!/usr/bin/python
2
3#   This program 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#   This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
15
16# Most of this code was copied from the FIFE file xmlmap.py
17# It is part of the local code base now so we can customize what happens
18# as we read map files
19
20import fife 
21try:
22    import xml.etree.cElementTree as ET
23except:
24    import xml.etree.ElementTree as ET
25
26import loaders
27from serializers import *
28import time
29
30FORMAT = '1.0'
31
32class XMLMapLoader(fife.ResourceLoader):
33    def __init__(self, engine, data, callback):
34        """ The XMLMapLoader parses the xml map using several section.
35        Each section fires a callback (if given) which can e. g. be
36        used to show a progress bar.
37       
38        The callback sends two values, a string and a float (which shows
39        the overall process): callback(string, float)
40       
41        Inputs:
42            engine = FIFE engine
43            data = Engine object for PARPG data
44            callback = function callback
45        """
46        fife.ResourceLoader.__init__(self)
47        self.thisown = 0
48       
49        self.callback = callback
50
51        self.engine = engine
52        self.data = data
53        self.vfs = self.engine.getVFS()
54        self.model = self.engine.getModel()
55        self.pool = self.engine.getImagePool()
56        self.anim_pool = self.engine.getAnimationPool()
57        self.map = None
58        self.source = None
59        self.time_to_load = 0
60
61        self.n_space = None
62
63    def _err(self, msg):
64        raise SyntaxError(''.join(['File: ', self.source, ' . ', msg]))
65
66    def loadResource(self, location):
67        start_time = time.time()
68        self.source = location.getFilename()
69        f = self.vfs.open(self.source)
70        f.thisown = 1
71        tree = ET.parse(f)
72        root = tree.getroot()
73           
74        map = self.parseMap(root)
75        self.time_to_load = time.time() - start_time
76        return map
77
78    def parseMap(self, map_elt):
79        if not map_elt:
80            self._err(\
81                'No <map> element found at top level of map file definition.')
82        id,format = map_elt.get('id'),map_elt.get('format')
83
84        if not format == FORMAT: self._err(''.join(['This file has format ', \
85                                            format, \
86                                            ' but this loader has format ', \
87                                            FORMAT]))
88        if not id: self._err('Map declared without an identifier.')
89
90        map = None
91        try:
92            self.map = self.model.createMap(str(id))
93            self.map.setResourceFile(self.source)
94        # NameClash appears as general fife.Exception; any ideas?
95        except fife.Exception, e: 
96            print e.getMessage()
97            print ''.join(['File: ', self.source, '. The map ', str(id), \
98                           ' already exists! Ignoring map definition.'])
99            return None
100
101        # xml-specific directory imports. This is used by xml savers.
102        self.map.importDirs = []
103
104        if self.callback is not None:
105            self.callback('created map', float(0.25) )
106
107        self.parseImports(map_elt, self.map)
108       
109        self.parseLayers(map_elt, self.map)   
110       
111        self.parseCameras(map_elt, self.map)
112
113        return self.map
114
115    def parseImports(self, map_elt, map):
116        parsedImports = {}
117
118        if self.callback:       
119            tmp_list = map_elt.findall('import')
120            i = float(0)
121       
122        for item in map_elt.findall('import'):
123            file = item.get('file')
124            if file:
125                file = reverse_root_subfile(self.source, file)
126            dir = item.get('dir')
127            if dir:
128                dir = reverse_root_subfile(self.source, dir)
129
130            # Don't parse duplicate imports
131            if (dir,file) in parsedImports:
132                print "Duplicate import:" ,(dir,file)
133                continue
134            parsedImports[(dir,file)] = 1
135
136            if file and dir:
137                loaders.loadImportFile('/'.join(dir, file), self.engine)
138            elif file:
139                loaders.loadImportFile(file, self.engine)
140            elif dir:
141                loaders.loadImportDirRec(dir, self.engine)
142                map.importDirs.append(dir)
143            else:
144                print 'Empty import statement?'
145               
146            if self.callback:
147                i += 1               
148                self.callback('loaded imports', \
149                              float( i / float(len(tmp_list)) * 0.25 + 0.25 ))
150
151
152    def parseLayers(self, map_elt, map):
153        if self.callback is not None:       
154            tmp_list = map_elt.findall('layer')
155            i = float(0)
156
157        for layer in map_elt.findall('layer'):
158            id = layer.get('id')
159            grid_type = layer.get('grid_type')
160            x_scale = layer.get('x_scale')
161            y_scale = layer.get('y_scale')
162            rotation = layer.get('rotation')
163            x_offset = layer.get('x_offset')
164            y_offset = layer.get('y_offset')
165            pathing = layer.get('pathing')
166            transparency = layer.get('transparency')
167
168            if not x_scale: x_scale = 1.0
169            if not y_scale: y_scale = 1.0
170            if not rotation: rotation = 0.0
171            if not x_offset: x_offset = 0.0
172            if not y_offset: y_offset = 0.0
173            if not pathing: pathing = "cell_edges_only"
174            if not transparency:
175                    transparency = 0
176            else:
177                    transparency = int(transparency)
178           
179
180            if not id: self._err('<layer> declared with no id attribute.')
181            if not grid_type: self._err(''.join(['Layer ', str(id), \
182                                            ' has no grid_type attribute.']))
183
184            allow_diagonals = pathing == "cell_edges_and_diagonals"
185            cell_grid = self.model.getCellGrid(grid_type)
186            if not cell_grid: self._err('<layer> declared with invalid '\
187                                       'cell grid type. (%s)' % grid_type)
188
189            cell_grid.setRotation(float(rotation))
190            cell_grid.setXScale(float(x_scale))
191            cell_grid.setYScale(float(y_scale))
192            cell_grid.setXShift(float(x_offset))
193            cell_grid.setYShift(float(y_offset))
194
195            layer_obj = None
196            try:
197                layer_obj = map.createLayer(str(id), cell_grid)
198            except fife.Exception, e:
199                print e.getMessage()
200                print 'The layer ' + str(id) + \
201                        ' already exists! Ignoring this layer.'
202                continue
203
204            strgy = fife.CELL_EDGES_ONLY
205            if pathing == "cell_edges_and_diagonals":
206                strgy = fife.CELL_EDGES_AND_DIAGONALS
207            if pathing == "freeform":
208                strgy = fife.FREEFORM
209            layer_obj.setPathingStrategy(strgy)
210
211            layer_obj.setLayerTransparency(transparency)
212
213            self.parseInstances(layer, layer_obj)
214
215            if self.callback is not None:
216                i += 1
217                self.callback('loaded layer :' + \
218                              str(id), float( i / float(len(tmp_list)) * \
219                                              0.25 + 0.5 ) )
220
221        # cleanup
222        if self.callback is not None:
223            del tmp_list
224            del i
225
226    def parseInstances(self, layer_elt, layer):
227        inst_elt = layer_elt.find('instances')
228
229        instances = inst_elt.findall('i')
230        instances.extend(inst_elt.findall('inst'))
231        instances.extend(inst_elt.findall('instance'))
232        for instance in instances:
233
234            object_id = instance.get('object')
235            if not object_id:
236                object_id = instance.get('obj')
237            if not object_id:
238                object_id = instance.get('o')
239
240            if not object_id: self._err('<instance> does not specify an '\
241                                        'object attribute.')
242
243            n_space = instance.get('namespace')
244            if not n_space:
245                n_space = instance.get('ns')
246            if not n_space:
247                n_space = self.n_space
248
249            if not n_space: self._err('<instance> %s does not specify an '\
250                                      'object namespace, and no default is '\
251                                      'available.' % str(object_id))
252
253            self.n_space = n_space
254
255            object = self.model.getObject(str(object_id), str(n_space))
256            if not object:
257                print ''.join(['Object with id=', str(object_id), ' ns=', \
258                               str(n_space), \
259                               ' could not be found. Omitting...'])
260                continue
261
262            x = instance.get('x')
263            y = instance.get('y')
264            z = instance.get('z')
265            stack_pos = instance.get('stackpos')
266            id = instance.get('id')
267
268            if x:
269                x = float(x)
270                self.x = x
271            else:
272                self.x = self.x + 1
273                x = self.x
274
275            if y:
276                y = float(y)
277                self.y = y
278            else:
279                y = self.y
280
281            if z:
282                z = float(z)
283            else:
284                z = 0.0
285
286            if not id:
287                id = ''
288            else:
289                id = str(id)
290
291            inst = layer.createInstance(object, \
292                                        fife.ExactModelCoordinate(x,y,z), \
293                                        str(id))
294
295            rotation = instance.get('r')
296            if not rotation:
297                rotation = instance.get('rotation')
298            if not rotation:
299                angles = object.get2dGfxVisual().getStaticImageAngles()
300                if angles:
301                    rotation = angles[0]
302                else:
303                    rotation = 0
304            else:
305                rotation = int(rotation)
306            inst.setRotation(rotation)
307
308            fife.InstanceVisual.create(inst)
309            if (stack_pos):
310                inst.get2dGfxVisual().setStackPosition(int(stack_pos))
311
312            if (object.getAction('default')):
313                target = fife.Location(layer)
314                inst.act('default', target, True)
315               
316            #Check for PARPG specific object attributes
317            object_type = instance.get('object_type')
318            if object_type:
319                inst_dict = {}
320                inst_dict["type"] = object_type
321                inst_dict["id"] = id
322                inst_dict["xpos"] = x
323                inst_dict["ypos"] = y
324                inst_dict["gfx"] = object_id
325                inst_dict["is_open"] = instance.get('is_open')
326                inst_dict["locked"] = instance.get('locked')
327                inst_dict["name"] = instance.get('name')
328                inst_dict["text"] = instance.get('text')
329                if instance.get('dialogue'):
330                    inst_dict['dialogue'] = instance.get('dialogue')
331                inst_dict["target_map_name"] = instance.get('target_map_name')
332                inst_dict["target_map"] = instance.get('target_map')
333                inst_dict["target_x"] = instance.get('target_x')
334                inst_dict["target_y"] = instance.get('target_y')
335
336                self.data.createObject(layer, inst_dict, inst)
337               
338    def parseCameras(self, map_elt, map):
339        if self.callback:       
340            tmp_list = map_elt.findall('camera')
341            i = float(0)
342
343        for camera in map_elt.findall('camera'):
344            id = camera.get('id')
345            zoom = camera.get('zoom')
346            tilt = camera.get('tilt')
347            rotation = camera.get('rotation')
348            ref_layer_id = camera.get('ref_layer_id')
349            ref_cell_width = camera.get('ref_cell_width')
350            ref_cell_height = camera.get('ref_cell_height')
351            view_port = camera.get('viewport')
352
353            if not zoom: zoom = 1
354            if not tilt: tilt = 0
355            if not rotation: rotation = 0
356
357            if not id: self._err('Camera declared without an id.')
358            if not ref_layer_id: self._err(''.join(['Camera ', str(id), \
359                                                    ' declared with no '\
360                                                    'reference layer.']))
361            if not (ref_cell_width and ref_cell_height):
362                self._err(''.join(['Camera ', str(id), \
363                                   ' declared without reference cell '\
364                                   'dimensions.']))
365
366            try:
367                if view_port:
368                    cam = self.engine.getView().addCamera(str(id), \
369                                    map.getLayer(str(ref_layer_id)), \
370                                    fife.Rect(\
371                                    *[int(c) for c in view_port.split(',')]),\
372                                    fife.ExactModelCoordinate(0,0,0))
373                else:
374                    screen = self.engine.getRenderBackend()
375                    cam = self.engine.getView().addCamera(str(id), \
376                                    map.getLayer(str(ref_layer_id)), \
377                                    fife.Rect(0, 0, screen.getScreenWidth(), \
378                                              screen.getScreenHeight()), \
379                                              fife.ExactModelCoordinate(0, 0,\
380                                                                        0))
381
382                cam.setCellImageDimensions(int(ref_cell_width), \
383                                           int(ref_cell_height))
384                cam.setRotation(float(rotation))
385                cam.setTilt(float(tilt))
386                cam.setZoom(float(zoom))
387            except fife.Exception, e:
388                print e.getMessage()
389               
390            if self.callback:
391                i += 1
392                self.callback('loaded camera: ' +  str(id), \
393                              float( i / len(tmp_list) * 0.25 + 0.75 ) )   
Note: See TracBrowser for help on using the repository browser.