summaryrefslogtreecommitdiff
path: root/hercules/tmx_converter.py
diff options
context:
space:
mode:
Diffstat (limited to 'hercules/tmx_converter.py')
-rwxr-xr-xhercules/tmx_converter.py659
1 files changed, 659 insertions, 0 deletions
diff --git a/hercules/tmx_converter.py b/hercules/tmx_converter.py
new file mode 100755
index 0000000..96a37d9
--- /dev/null
+++ b/hercules/tmx_converter.py
@@ -0,0 +1,659 @@
+#!/usr/bin/env python
+# -*- encoding: utf-8 -*-
+
+## TMW2 Script
+## Modified by Jesusalva for Moubootaur Legends
+###################################################
+
+## tmx_converter.py - Extract walkmap, warp, and spawn information from maps.
+##
+## Copyright © 2012 Ben Longbons <b.r.longbons@gmail.com>
+## Copyright © 2016-2017 The Mana World Developers
+##
+## This file is part of The Mana World
+##
+## This program is free software: you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+from __future__ import print_function
+
+import sys
+import os
+import posixpath
+import xml.sax
+import traceback
+
+dump_all = False # wall of text
+check_mobs = False # mob_db.txt
+heigherror=True
+fatalError=False
+
+# lower case versions of everything except 'spawn' and 'warp'
+other_object_types = set([
+ 'particle_effect',
+ 'npc', # not interpreted by client
+ 'script', # for ManaServ
+ 'fixme', # flag for things that didn't have a type before
+ 'music',
+])
+
+# Somebody has put ManaServ fields in our data!
+other_spawn_fields = (
+ 'spawn_rate',
+)
+other_warp_fields = (
+)
+
+TILESIZE = 32
+SEPARATOR = ''
+MESSAGE = 'This file is generated automatically. All manually added changes will be removed when running the Converter.'
+CLIENT_MAPS = 'maps'
+SERVER_WLK = 'data'
+SERVER_NPCS = 'npc'
+MOB_DB_CONF = 'db/re/mob_db.conf'
+MAP_CONF = 'conf/map/maps.conf'
+MAP_DB_CONF = 'db/map_index.txt'
+NPC_MOBS = '_mobs.txt'
+NPC_CONFIG = '_config.txt'
+NPC_WARPS = '_warps.txt'
+NPC_IMPORTS = '_import.txt'
+NPC_MASTER_IMPORTS = NPC_IMPORTS
+
+def ifte(ifs, thens, elses):
+ if ifs:
+ return thens
+ else:
+ return elses
+
+class State(object):
+ pass
+State.INITIAL = State()
+State.LAYER = State()
+State.DATA = State()
+State.FINAL = State()
+
+class Object(object):
+ __slots__ = (
+ 'name',
+ 'x', 'y',
+ 'w', 'h',
+ )
+class Mob(Object):
+ __slots__ = (
+ 'monster_id',
+ 'max_beings',
+ 'spawn',
+ 'death',
+ 'script',
+ ) + other_spawn_fields
+ def __init__(self):
+ self.max_beings = 1
+ self.spawn = 0
+ self.death = 0
+ self.script = ''
+
+class Save(Object):
+ __slots__ = (
+ 'inn',
+ )
+
+class Warp(Object):
+ __slots__ = (
+ 'dest_map',
+ 'dest_x',
+ 'dest_y',
+ 'npc_id',
+ 'trigger_x',
+ 'trigger_y',
+ 'notes',
+ ) + other_warp_fields
+ def __init__(self):
+ self.npc_id = 'WARP'
+
+# TMW2 CUSTOM OBJECTS
+####################################
+class Slide(Object):
+ __slots__ = (
+ 'dest_x',
+ 'dest_y',
+ 'npc_id',
+ 'trigger_x',
+ 'trigger_y',
+ 'notes',
+ ) + other_warp_fields
+ def __init__(self):
+ self.npc_id = 'SLIDE'
+
+class DynCollision(Object):
+ __slots__ = (
+ 'colid',
+ 'enabled',
+ )
+ def __init__(self):
+ self.colid = 1
+ self.enabled = True
+
+class DungeonSwitch(Object):
+ __slots__ = (
+ 'enabled',
+ 'distance',
+ 'callfunc',
+ 'doevent',
+ 'args',
+ )
+ def __init__(self):
+ self.enabled = False
+ self.distance = 2
+ self.callfunc = ''
+ self.doevent = ''
+ self.args = ''
+
+class FunctionTrigger(Object):
+ __slots__ = (
+ 'callfunc',
+ 'doevent',
+ 'args',
+ )
+ def __init__(self):
+ self.callfunc = ''
+ self.doevent = ''
+ self.args = ''
+
+class Trap(Object):
+ __slots__ = (
+ 'disarmtime',
+ 'stuntime',
+ 'damage',
+ 'target',
+ )
+ def __init__(self):
+ self.disarmtime = 15
+ self.stuntime = 3
+ self.damage = 80
+ self.target = 3
+
+class TreasureChest(Object):
+ __slots__ = (
+ 'distance',
+ )
+ def __init__(self):
+ self.distance = 2
+
+####################################
+class ContentHandler(xml.sax.ContentHandler):
+ __slots__ = (
+ 'locator', # keeps track of location in document
+ 'state', # state of height info
+ 'tilesets', # first gid of each tileset
+ 'buffer', # characters within a section
+ 'encoding', # encoding of layer data
+ 'compression', # compression of layer data
+ 'width', # width of the height layer
+ 'height', # height of the height layer
+ 'firstgid', # first gid of height layer
+ 'heightmap',# height map
+ 'base', # base name of current map
+ 'npc_dir', # world/map/npc/<base>
+ 'mobs', # open file to _mobs.txt
+ 'warps', # open file to _warps.txt
+ 'imports', # open file to _import.txt
+ 'name', # name property of the current map
+ 'object', # stores properties of the latest <object> tag
+ 'mob_ids', # set of all mob types that spawn here
+ )
+ def __init__(self, npc_dir, mobs, confs, warps, imports):
+ xml.sax.ContentHandler.__init__(self)
+ self.locator = None
+ self.state = State.INITIAL
+ self.tilesets = set([0]) # consider the null tile as its own tileset
+ self.buffer = bytearray()
+ self.encoding = None
+ self.compression = None
+ self.width = None
+ self.height = None
+ self.firstgid = 0
+ self.heightmap = ''
+ self.base = posixpath.basename(npc_dir)
+ self.npc_dir = npc_dir
+ self.mobs = mobs
+ self.confs = confs
+ self.warps = warps
+ self.imports = imports
+ self.object = None
+ self.mob_ids = set()
+ self.mob_cnt = False
+ self.save_cnt = False
+ self.warp_cnt = False
+
+ def setDocumentLocator(self, loc):
+ self.locator = loc
+
+ # this method randomly cuts in the middle of a line; thus funky logic
+ def characters(self, s):
+ if not s.strip():
+ return
+ if self.state is State.DATA:
+ self.buffer += s.encode('ascii')
+
+ def startDocument(self):
+ pass
+
+ def startElement(self, name, attr):
+ global heigherror
+ if dump_all:
+ attrs = ' '.join('%s="%s"' % (k,v) for k,v in attr.items())
+ if attrs:
+ print('<%s %s>' % (name, attrs))
+ else:
+ print('<%s>' % name)
+
+ if self.state is State.INITIAL:
+ if name == u'property' and attr[u'name'].lower() == u'name':
+ self.name = attr[u'value']
+ self.mobs.write('// %s\n' % MESSAGE)
+ self.mobs.write('// Map %s: %s mobs\n' % (self.base, self.name))
+ self.confs.write('// %s\n' % MESSAGE)
+ self.confs.write('// Map %s: %s conf\n' % (self.base, self.name))
+ self.warps.write('// %s\n' % MESSAGE)
+ self.warps.write('// Map %s: %s warps\n' % (self.base, self.name))
+
+ if name == u'tileset':
+ self.tilesets.add(int(attr[u'firstgid']))
+ if 'name' in attr.__dict__['_attrs'].keys():
+ if attr[u'name'] == u'Height Numbers':
+ self.firstgid = int(attr[u'firstgid'])
+
+ if name == u'layer' and attr[u'name'].lower().startswith(u'height'):
+ self.width = int(attr[u'width'])
+ self.height = int(attr[u'height'])
+ self.state = State.LAYER
+ heigherror=False
+ # Map width must be enough to fill the largest widescreen on market
+ if (self.width < 1920/TILESIZE):
+ print('Bad map width: %d (min. %d)' % (self.width, 1920/TILESIZE))
+ elif self.state is State.LAYER:
+ if name == u'data':
+ if attr.get(u'encoding','') not in (u'', u'csv'):
+ print('Bad encoding:', attr.get(u'encoding',''))
+ return
+ self.encoding = attr.get(u'encoding','')
+ if attr.get(u'compression','') not in (u'', u'none'):
+ print('Bad compression:', attr.get(u'compression',''))
+ return
+ self.compression = attr.get(u'compression','')
+ self.state = State.DATA
+ elif self.state is State.FINAL:
+ if name == u'object':
+ obj_type = attr[u'type'].lower()
+ x = int(int(attr[u'x']) / TILESIZE);
+ y = int(int(attr[u'y']) / TILESIZE);
+ w = int(int(attr.get(u'width', 0)) / TILESIZE);
+ h = int(int(attr.get(u'height', 0)) / TILESIZE);
+ # I'm not sure exactly what the w/h shrinking is for,
+ # I just copied it out of the old converter.
+ # I know that the x += w/2 is to get centers, though.
+ if obj_type == 'spawn':
+ self.object = Mob()
+ w = int((w - 1) / 2)
+ h = int((h - 1) / 2)
+ if w < 0:
+ w = 0
+ else:
+ x += w
+ if h < 0:
+ h = 0
+ else:
+ y += h
+ elif obj_type == 'save':
+ self.object = Save()
+ x += w/2
+ y += h/2
+ w -= 2
+ h -= 2
+ elif obj_type == 'warp':
+ self.object = Warp()
+ x += w/2
+ y += h/2
+ w -= 1
+ h -= 1
+ ### TMW2 INSTANCES
+ ##########################################################
+ elif obj_type == 'slide':
+ self.object = Slide()
+ x += w/2
+ y += h/2
+ w -= 1
+ h -= 1
+ elif obj_type == 'dyncollision':
+ self.object = DynCollision()
+ w -= 1
+ h -= 1
+ elif obj_type == 'switch':
+ self.object = DungeonSwitch()
+ x += w/2
+ y += h/2
+ w -= 1
+ h -= 1
+ elif obj_type == 'treasure':
+ self.object = TreasureChest()
+ x += w/2
+ y += h/2
+ w -= 1
+ h -= 1
+ elif obj_type == 'function':
+ self.object = FunctionTrigger()
+ x += w/2
+ y += h/2
+ w -= 1
+ h -= 1
+ elif obj_type == 'trap':
+ self.object = Trap()
+ x += w/2
+ y += h/2
+ w -= 1
+ h -= 1
+ else:
+ if obj_type not in other_object_types:
+ print('Unknown object type:', obj_type, file=sys.stderr)
+ self.object = None
+ return
+ obj = self.object
+ obj.x = x
+ obj.y = y
+ obj.w = w
+ obj.h = h
+ obj.name = attr[u'name']
+ elif name == u'property':
+ obj = self.object
+ if obj is None:
+ return
+ key = attr[u'name'].lower()
+ value = attr[u'value']
+ # Not true due to defaulting
+ #assert not hasattr(obj, key)
+ try:
+ value = int(value)
+ except ValueError:
+ pass
+ setattr(obj, key, value)
+
+
+ def add_warp_line(self, line):
+ self.warps.write(line)
+
+ def endElement(self, name):
+ if dump_all:
+ print('</%s>' % name)
+
+ if name == u'object':
+ obj = self.object
+ if isinstance(obj, Mob):
+ mob_id = obj.monster_id
+ if mob_id < 1000:
+ mob_id += 1002
+ if check_mobs:
+ try:
+ name = mob_names[mob_id]
+ except KeyError:
+ print('Warning: unknown mob ID: %d (%s)' % (mob_id, obj.name))
+ else:
+ if name != obj.name:
+ print('Warning: wrong mob name: %s (!= %s)' % (obj.name, name))
+ obj.name = name
+ self.mob_ids.add(mob_id)
+ if obj.script:
+ obj.script = ",%s" % (obj.script)
+ self.mobs.write(
+ SEPARATOR.join([
+ '%s,%d,%d,%d,%d\t' % (self.base, obj.x, obj.y, obj.w, obj.h),
+ 'monster\t',
+ obj.name,
+ '\t%d,%d,%d,%d%s\n' % (mob_id, obj.max_beings, obj.spawn, obj.death, obj.script),
+ ])
+ )
+ self.mob_cnt = True
+ elif isinstance(obj, Save):
+ """
+ obj_name = "%s_%s_%s" % (self.base, obj.x, obj.y)
+ self.confs.write(
+ SEPARATOR.join([
+ '',
+ '%s,%d,%d,0\tscript\t#save_%s\tNPC_SAVE_POINT,{\n' % (self.base, obj.x, obj.y, obj_name),
+ ' savepointparticle .map$, .x, .y, %s;\n close;\n\nOnInit:\n .distance = 2;\n .sex = G_OTHER;\n end;\n}\n' % (obj.inn),
+ ])
+ )
+ self.save_cnt = True
+ """
+ print("[WARNING] Object type \"Save\" is deprecated!")
+ elif isinstance(obj, Warp):
+ if (obj.npc_id == u'WARP'):
+ obj_name = "#%s_%s_%s" % (self.base, obj.x, obj.y)
+ if (obj.dest_map.lower() in ["slide", "self"]):
+ self.warps.write(
+ SEPARATOR.join([
+ '%s,%d,%d,0\t' % (self.base, obj.x, (obj.y)),
+ 'script\t',
+ '%s\tNPC_HIDDEN,%d,%d,{\n\tend;\nOnTouch:\n\tslide %d,%d; end;\n}\n' % (obj_name, obj.w, obj.h, obj.dest_x, obj.dest_y),
+ ])
+ )
+ else:
+ self.warps.write(
+ SEPARATOR.join([
+ '%s,%d,%d,0\t' % (self.base, obj.x, obj.y),
+ 'warp\t',
+ '%s\t%s,%s,%s,%d,%d\n' % (obj_name, obj.w, obj.h, obj.dest_map, obj.dest_x, obj.dest_y),
+ ])
+ )
+ self.warp_cnt = True
+ ### TMW2 INSTANCES
+ ##############################################################
+ elif isinstance(obj, Slide):
+ if (obj.npc_id == u'SLIDE'):
+ obj_name = "#%s_%s_%s" % (self.base, obj.x, obj.y)
+ self.warps.write(
+ SEPARATOR.join([
+ '%s,%d,%d,0\t' % (self.base, obj.x, (obj.y)),
+ 'script\t',
+ '%s\tNPC_HIDDEN,%d,%d,{\n\tend;\nOnTouch:\n\tslide %d,%d; end;\n}\n' % (obj_name, obj.w, obj.h, obj.dest_x, obj.dest_y),
+ ])
+ )
+ self.warp_cnt = True
+ elif (not obj.npc_id == u'SCRIPT'):
+ obj_name = "#%s_%s_%s" % (self.base, obj.x, obj.y)
+ self.warps.write(
+ SEPARATOR.join([
+ '%s,%d,%d,0\tscript\t%s_h\tNPC_HIDDEN,0,0,{\n' % (self.base, obj.x, obj.y, obj_name),
+ 'OnTouch:\n warp "%s", %d, %d;\nclose;\n\nOnUnTouch:\n doevent "%s::OnUnTouch";\n}\n' % (obj.dest_map, obj.dest_x, obj.dest_y, obj_name),
+ '%s,%d,%d,0\tscript\t%s\t%s,%d,%d,{\n close;\nOnTouch:\n doorTouch;\n\nOnUnTouch:\n doorUnTouch;\n\nOnTimer340:\n doorTimer;\n\nOnInit:\n doorInit;\n}\n\n' % (self.base, obj.x, obj.y, obj_name, obj.npc_id, obj.trigger_x, obj.trigger_y),
+ ])
+ )
+ self.warp_cnt = True
+ elif isinstance(obj, DynCollision):
+ obj_name = "%s_%s_%s" % (self.base, obj.x, obj.y)
+ triggere = ifte(obj.enabled, "\nOnInit:", "")
+ triggerd = ifte(obj.enabled, "", "\nOnInit:")
+ self.confs.write(
+ SEPARATOR.join([
+ '\n',
+ '%s,%d,%d,0\t' % (self.base, obj.x, (obj.y)),
+ 'script\t',
+ '#%s\tNPC_HIDDEN,{\n\tend;\nOnDisable:%s\n\tdelcells "%s"; end;\n' % (obj_name, triggerd, obj_name),
+ 'OnEnable:%s\n\tsetcells "%s", %d, %d, %d, %d, %d, "%s";\n}\n' % (triggere, self.base, obj.x, obj.y, obj.x+obj.w, obj.y+obj.h, obj.colid, obj_name),
+ ])
+ )
+ self.save_cnt = True
+ elif isinstance(obj, DungeonSwitch):
+ obj_name = "%s_%s_%s" % (self.base, obj.x, obj.y)
+ status = ifte(obj.enabled, "OFFLINE", "ONLINE")
+ nstats = ifte(obj.enabled, "ONLINE", "OFFLINE")
+ func_name = ifte(obj.callfunc != "", "\tcallfunc \"%s\"%s;\n" % (obj.callfunc,
+ ifte(obj.args != "", ", %s" % obj.args, "")), "")
+ scrp_name = ifte(obj.doevent != "", "\tdoevent \"%s\";\n" % (obj.doevent), "")
+ self.confs.write(
+ SEPARATOR.join([
+ '\n',
+ '%s,%d,%d,0\t' % (self.base, obj.x, (obj.y)),
+ 'script\t',
+ '#%s\tNPC_SWITCH_%s,{\n' % (obj_name, status),
+ '\tif (getnpcclass() == NPC_SWITCH_%s)\n\t\tend;\n' % (nstats),
+ '%s%s' % (func_name, scrp_name),
+ '\tsetnpcdisplay "#%s", NPC_SWITCH_%s;\n\tend;\nOnInit:\n\t.distance=%d;\n}\n' % (obj_name, nstats, obj.distance),
+ ])
+ )
+ self.save_cnt = True
+ elif isinstance(obj, FunctionTrigger):
+ obj_name = "%s_%s_%s" % (self.base, obj.x, obj.y)
+ func_name = ifte(obj.callfunc != "", "\tcallfunc \"%s\"%s;\n" % (obj.callfunc,
+ ifte(obj.args != "", ", %s" % obj.args, "")), "")
+ scrp_name = ifte(obj.doevent != "", "\tdoevent \"%s\";\n" % (obj.doevent), "")
+ self.confs.write(
+ SEPARATOR.join([
+ '\n',
+ '%s,%d,%d,0\t' % (self.base, obj.x, (obj.y)),
+ 'script\t',
+ '#%s\tNPC_HIDDEN,%d,%d,{\n\tend;\n' % (obj_name, obj.w, obj.h),
+ 'OnTouch:\n%s%s\tend;\n}\n' % (func_name, scrp_name),
+ ])
+ )
+ self.save_cnt = True
+ elif isinstance(obj, Trap):
+ obj_name = "%s_%s_%s" % (self.base, obj.x, obj.y)
+ npcid = ifte(obj.disarmtime, "NPC_TRAP", "NPC_TRAP_ONLINE")
+ timer = ifte(obj.disarmtime, "OnTimer%d:\n\tstopnpctimer; setnpctimer 0; setnpcdisplay \"#%s\", NPC_TRAP; end;\n" % (obj.disarmtime*1000, obj_name), "")
+ self.confs.write(
+ SEPARATOR.join([
+ '\n',
+ '%s,%d,%d,0\t' % (self.base, obj.x, (obj.y)),
+ 'script\t',
+ '#%s\t%s,%d,%d,{\n\tmesn strcharinfo(0);\n\tmesq l("Something seems off with that!");\n\tclose;\n' % (obj_name, npcid, obj.w, obj.h),
+ '%s%s' % (ifte(obj.target & 1, "OnTouch:\n", ""), ifte(obj.target & 2, "OnTouchNPC:\n", "")),
+ '\tIronTrap(%d, %d, %d);\n\tend;\n%s}\n' % (obj.damage, obj.disarmtime, obj.stuntime, timer),
+ ])
+ )
+ self.save_cnt = True
+ elif isinstance(obj, TreasureChest):
+ obj_name = "%s_%s_%s" % (self.base, obj.x, obj.y)
+ self.confs.write(
+ SEPARATOR.join([
+ '\n',
+ '%s,%d,%d,0\t' % (self.base, obj.x, (obj.y)),
+ 'script\t',
+ '#%s\tNPC_CHEST,{\n\tTreasureBox();' % (obj_name),
+ '\n\tspecialeffect(.dir == 0 ? 24 : 25, AREA, getnpcid()); // closed ? opening : closing',
+ '\n\tclose;\nOnInit:\n\t.distance=%d;' % (obj.distance),
+ '\n\tend;\n}\n',
+ ])
+ )
+ self.save_cnt = True
+
+ ##############################################################
+
+ if name == u'data':
+ if self.state is State.DATA:
+ if self.encoding == u'csv':
+ for x in self.buffer.split(','):
+ if int(x) > 0:
+ self.heightmap += str((int(x) - int(self.firstgid)) + 1)
+ else:
+ self.heightmap += str(x)
+ self.state = State.FINAL
+
+ def endDocument(self):
+ if not self.mob_cnt:
+ os.remove(posixpath.join(main.this_map_npc_dir, NPC_MOBS))
+ if not self.save_cnt:
+ os.remove(posixpath.join(main.this_map_npc_dir, NPC_CONFIG))
+ if not self.warp_cnt:
+ os.remove(posixpath.join(main.this_map_npc_dir, NPC_WARPS))
+
+ imp_cnt = (len(os.walk(self.npc_dir).next()[2]))
+
+ if imp_cnt > 0:
+ self.imports.write('// Map %s: %s\n' % (self.base, self.name))
+ self.imports.write('// %s\n' % MESSAGE)
+
+ npcs = os.listdir(self.npc_dir)
+ npcs.sort()
+ for x in npcs:
+ if x == NPC_IMPORTS:
+ continue
+ if x.startswith('.'):
+ continue
+ if x.endswith('.txt') or x.endswith('.c'):
+ self.imports.write('"%s",\n' % posixpath.join(SERVER_NPCS, self.base, x))
+ else:
+ os.remove(posixpath.join(main.this_map_npc_dir, NPC_IMPORTS))
+
+def main(argv):
+ global heigherror, fatalError
+ _, client_data, server_data = argv
+ tmx_dir = posixpath.join(client_data, CLIENT_MAPS)
+ npc_dir = posixpath.join(server_data, SERVER_NPCS)
+ if check_mobs:
+ global mob_names
+ mob_names = {}
+ with open(posixpath.join(server_data, MOB_DB_CONF)) as mob_db:
+ for line in mob_db:
+ if not line.strip():
+ continue
+ if line.startswith('//'):
+ continue
+
+ npc_master = []
+ map_basenames = []
+
+ map_conf = open(posixpath.join(server_data,MAP_CONF), 'w')
+ map_db = open(posixpath.join(server_data,MAP_DB_CONF), 'w')
+ map_conf.write("map_removed: (\n)\nmap_list: (\n")
+ map_count = 1
+ for arg in sorted(os.listdir(tmx_dir)):
+ base, ext = posixpath.splitext(arg)
+
+ if ext == '.tmx':
+ map_basenames.append(base)
+ tmx = posixpath.join(tmx_dir, arg)
+ main.this_map_npc_dir = posixpath.join(npc_dir, base)
+ os.path.isdir(main.this_map_npc_dir) or os.mkdir(main.this_map_npc_dir)
+ print('Converting %s' % (tmx))
+ try:
+ with open(posixpath.join(main.this_map_npc_dir, NPC_MOBS), 'w') as mobs:
+ with open(posixpath.join(main.this_map_npc_dir, NPC_CONFIG), 'w') as confs:
+ with open(posixpath.join(main.this_map_npc_dir, NPC_WARPS), 'w') as warps:
+ with open(posixpath.join(main.this_map_npc_dir, NPC_IMPORTS), 'w') as imports:
+ xml.sax.parse(tmx, ContentHandler(main.this_map_npc_dir, mobs, confs, warps, imports))
+ except:
+ traceback.print_exc()
+ print("ERROR: MAP \"%s\" WAS NOT CONVERTED. ERROR FOUND!" % tmx)
+ fatalError=True
+ if os.path.isfile(posixpath.join(main.this_map_npc_dir, NPC_IMPORTS)):
+ npc_master.append('@include "%s"\n' % posixpath.join(SERVER_NPCS, base, NPC_IMPORTS))
+ if heigherror:
+ print("ERROR: Height layer possibly missing")
+ fatalError=True
+ heigherror=True
+
+ map_db.write('%s %d\n' % (arg.split('.')[0], map_count))
+ map_conf.write(' "%s",\n' % (arg.split('.')[0]))
+ map_count += 1
+ map_conf.write(")\n")
+ with open(posixpath.join(npc_dir, NPC_MASTER_IMPORTS), 'w') as out:
+ out.write('// %s\n\n' % MESSAGE)
+ npc_master.sort()
+ for line in npc_master:
+ out.write(line)
+ if fatalError:
+ exit(1)
+
+if __name__ == '__main__':
+ main(sys.argv)