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

Revision 325, 12.8 KB checked in by barra_parpg, 10 years ago (diff)
  • 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.nspace = 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('No <map> element found at top level of map file definition.')
81        id,format = map_elt.get('id'),map_elt.get('format')
82
83        if not format == FORMAT: self._err(''.join(['This file has format ', format, ' but this loader has format ', FORMAT]))
84        if not id: self._err('Map declared without an identifier.')
85
86        map = None
87        try:
88            self.map = self.model.createMap(str(id))
89            self.map.setResourceFile(self.source)
90        except fife.Exception, e: # NameClash appears as general fife.Exception; any ideas?
91            print e.getMessage()
92            print ''.join(['File: ', self.source, '. The map ', str(id), ' already exists! Ignoring map definition.'])
93            return None
94
95        # xml-specific directory imports. This is used by xml savers.
96        self.map.importDirs = []
97
98        if self.callback is not None:
99            self.callback('created map', float(0.25) )
100
101        self.parseImports(map_elt, self.map)
102       
103        self.parseLayers(map_elt, self.map)   
104       
105        self.parseCameras(map_elt, self.map)
106
107        return self.map
108
109    def parseImports(self, map_elt, map):
110        parsedImports = {}
111
112        if self.callback:       
113            tmplist = map_elt.findall('import')
114            i = float(0)
115       
116        for item in map_elt.findall('import'):
117            file = item.get('file')
118            if file:
119                file = reverse_root_subfile(self.source, file)
120            dir = item.get('dir')
121            if dir:
122                dir = reverse_root_subfile(self.source, dir)
123
124            # Don't parse duplicate imports
125            if (dir,file) in parsedImports:
126                print "Duplicate import:" ,(dir,file)
127                continue
128            parsedImports[(dir,file)] = 1
129
130            if file and dir:
131                loaders.loadImportFile('/'.join(dir, file), self.engine)
132            elif file:
133                loaders.loadImportFile(file, self.engine)
134            elif dir:
135                loaders.loadImportDirRec(dir, self.engine)
136                map.importDirs.append(dir)
137            else:
138                print 'Empty import statement?'
139               
140            if self.callback:
141                i += 1               
142                self.callback('loaded imports', float( i / float(len(tmplist)) * 0.25 + 0.25 ) )
143
144
145    def parseLayers(self, map_elt, map):
146        if self.callback is not None:       
147            tmplist = map_elt.findall('layer')
148            i = float(0)
149
150        for layer in map_elt.findall('layer'):
151            id = layer.get('id')
152            grid_type = layer.get('grid_type')
153            x_scale = layer.get('x_scale')
154            y_scale = layer.get('y_scale')
155            rotation = layer.get('rotation')
156            x_offset = layer.get('x_offset')
157            y_offset = layer.get('y_offset')
158            pathing = layer.get('pathing')
159            transparency = layer.get('transparency')
160
161            if not x_scale: x_scale = 1.0
162            if not y_scale: y_scale = 1.0
163            if not rotation: rotation = 0.0
164            if not x_offset: x_offset = 0.0
165            if not y_offset: y_offset = 0.0
166            if not pathing: pathing = "cell_edges_only"
167            if not transparency:
168                    transparency = 0
169            else:
170                    transparency = int(transparency)
171           
172
173            if not id: self._err('<layer> declared with no id attribute.')
174            if not grid_type: self._err(''.join(['Layer ', str(id), ' has no grid_type attribute.']))
175
176            allow_diagonals = pathing == "cell_edges_and_diagonals"
177            cellgrid = self.model.getCellGrid(grid_type)
178            if not cellgrid: self._err('<layer> declared with invalid cellgrid type. (%s)' % grid_type)
179
180            cellgrid.setRotation(float(rotation))
181            cellgrid.setXScale(float(x_scale))
182            cellgrid.setYScale(float(y_scale))
183            cellgrid.setXShift(float(x_offset))
184            cellgrid.setYShift(float(y_offset))
185
186            layer_obj = None
187            try:
188                layer_obj = map.createLayer(str(id), cellgrid)
189            except fife.Exception, e:
190                print e.getMessage()
191                print 'The layer ' + str(id) + ' already exists! Ignoring this layer.'
192                continue
193
194            strgy = fife.CELL_EDGES_ONLY
195            if pathing == "cell_edges_and_diagonals":
196                strgy = fife.CELL_EDGES_AND_DIAGONALS
197            if pathing == "freeform":
198                strgy = fife.FREEFORM
199            layer_obj.setPathingStrategy(strgy)
200
201            layer_obj.setLayerTransparency(transparency)
202
203            self.parseInstances(layer, layer_obj)
204
205            if self.callback is not None:
206                i += 1
207                self.callback('loaded layer :' + str(id), float( i / float(len(tmplist)) * 0.25 + 0.5 ) )
208
209        # cleanup
210        if self.callback is not None:
211            del tmplist
212            del i
213
214    def parseInstances(self, layerelt, layer):
215        instelt = layerelt.find('instances')
216
217        instances = instelt.findall('i')
218        instances.extend(instelt.findall('inst'))
219        instances.extend(instelt.findall('instance'))
220        for instance in instances:
221
222            objectID = instance.get('object')
223            if not objectID:
224                objectID = instance.get('obj')
225            if not objectID:
226                objectID = instance.get('o')
227
228            if not objectID: self._err('<instance> does not specify an object attribute.')
229
230            nspace = instance.get('namespace')
231            if not nspace:
232                nspace = instance.get('ns')
233            if not nspace:
234                nspace = self.nspace
235
236            if not nspace: self._err('<instance> %s does not specify an object namespace, and no default is available.' % str(objectID))
237
238            self.nspace = nspace
239
240            object = self.model.getObject(str(objectID), str(nspace))
241            if not object:
242                print ''.join(['Object with id=', str(objectID), ' ns=', str(nspace), ' could not be found. Omitting...'])
243                continue
244
245            x = instance.get('x')
246            y = instance.get('y')
247            z = instance.get('z')
248            stackpos = instance.get('stackpos')
249            id = instance.get('id')
250
251            if x:
252                x = float(x)
253                self.x = x
254            else:
255                self.x = self.x + 1
256                x = self.x
257
258            if y:
259                y = float(y)
260                self.y = y
261            else:
262                y = self.y
263
264            if z:
265                z = float(z)
266            else:
267                z = 0.0
268
269            if not id:
270                id = ''
271            else:
272                id = str(id)
273
274            inst = layer.createInstance(object, fife.ExactModelCoordinate(x,y,z), str(id))
275
276            rotation = instance.get('r')
277            if not rotation:
278                rotation = instance.get('rotation')
279            if not rotation:
280                angles = object.get2dGfxVisual().getStaticImageAngles()
281                if angles:
282                    rotation = angles[0]
283                else:
284                    rotation = 0
285            else:
286                rotation = int(rotation)
287            inst.setRotation(rotation)
288
289            fife.InstanceVisual.create(inst)
290            if (stackpos):
291                inst.get2dGfxVisual().setStackPosition(int(stackpos))
292
293            if (object.getAction('default')):
294                target = fife.Location(layer)
295                inst.act('default', target, True)
296               
297            #Check for PARPG specific object attributes
298            object_type = instance.get('object_type')
299            if object_type:
300                inst_dict = {}
301                inst_dict["type"] = object_type
302                inst_dict["id"] = id
303                inst_dict["xpos"] = x
304                inst_dict["ypos"] = y
305                inst_dict["gfx"] = objectID
306                inst_dict["is_open"] = instance.get('is_open')
307                inst_dict["locked"] = instance.get('locked')
308                inst_dict["name"] = instance.get('name')
309                inst_dict["text"] = instance.get('text')
310                if instance.get('dialogue'):
311                    inst_dict['dialogue'] = instance.get('dialogue')
312                inst_dict["target_map_name"] = instance.get('target_map_name')
313                inst_dict["target_map"] = instance.get('target_map')
314                inst_dict["target_pos"] = (instance.get('target_x'), instance.get('target_y'))
315                self.data.createObject(layer, inst_dict, inst)
316               
317    def parseCameras(self, map_elt, map):
318        if self.callback:       
319            tmplist = map_elt.findall('camera')
320            i = float(0)
321
322        for camera in map_elt.findall('camera'):
323            id = camera.get('id')
324            zoom = camera.get('zoom')
325            tilt = camera.get('tilt')
326            rotation = camera.get('rotation')
327            ref_layer_id = camera.get('ref_layer_id')
328            ref_cell_width = camera.get('ref_cell_width')
329            ref_cell_height = camera.get('ref_cell_height')
330            viewport = camera.get('viewport')
331
332            if not zoom: zoom = 1
333            if not tilt: tilt = 0
334            if not rotation: rotation = 0
335
336            if not id: self._err('Camera declared without an id.')
337            if not ref_layer_id: self._err(''.join(['Camera ', str(id), ' declared with no reference layer.']))
338            if not (ref_cell_width and ref_cell_height): self._err(''.join(['Camera ', str(id), ' declared without reference cell dimensions.']))
339
340            try:
341                if viewport:
342                    cam = self.engine.getView().addCamera(str(id), map.getLayer(str(ref_layer_id)),fife.Rect(*[int(c) for c in viewport.split(',')]),fife.ExactModelCoordinate(0,0,0))
343                else:
344                    screen = self.engine.getRenderBackend()
345                    cam = self.engine.getView().addCamera(str(id), map.getLayer(str(ref_layer_id)),fife.Rect(0,0,screen.getScreenWidth(),screen.getScreenHeight()),fife.ExactModelCoordinate(0,0,0))
346
347                cam.setCellImageDimensions(int(ref_cell_width), int(ref_cell_height))
348                cam.setRotation(float(rotation))
349                cam.setTilt(float(tilt))
350                cam.setZoom(float(zoom))
351            except fife.Exception, e:
352                print e.getMessage()
353               
354            if self.callback:
355                i += 1
356                self.callback('loaded camera: ' +  str(id), float( i / len(tmplist) * 0.25 + 0.75 ) )   
Note: See TracBrowser for help on using the repository browser.