summaryrefslogtreecommitdiff
path: root/client
diff options
context:
space:
mode:
authorJesusaves <cpntb1@ymail.com>2022-10-23 23:45:19 -0300
committerJesusaves <cpntb1@ymail.com>2022-10-23 23:45:19 -0300
commitc2ccb14ffff0e45398365e19dfd2874307ddb943 (patch)
tree976eaea586fb8f1ee0ab8cae67c69071aed8b952 /client
downloadtools-c2ccb14ffff0e45398365e19dfd2874307ddb943.tar.gz
tools-c2ccb14ffff0e45398365e19dfd2874307ddb943.tar.bz2
tools-c2ccb14ffff0e45398365e19dfd2874307ddb943.tar.xz
tools-c2ccb14ffff0e45398365e19dfd2874307ddb943.zip
Initial commit
Diffstat (limited to 'client')
-rwxr-xr-xclient/aurora.py37
-rwxr-xr-xclient/dailylogin.py86
-rwxr-xr-xclient/magicacademy.py60
-rwxr-xr-xclient/minimap-dyecmd.py17
-rwxr-xr-xclient/minimap-dyecmd.sh0
-rw-r--r--client/minimap-override/none.pngbin0 -> 280 bytes
-rwxr-xr-xclient/minimap-render.py171
-rwxr-xr-xclient/skills.py137
-rwxr-xr-xclient/tmxrasterizerbin0 -> 1525440 bytes
-rwxr-xr-xclient/weapons.py89
10 files changed, 597 insertions, 0 deletions
diff --git a/client/aurora.py b/client/aurora.py
new file mode 100755
index 0000000..38ed174
--- /dev/null
+++ b/client/aurora.py
@@ -0,0 +1,37 @@
+#!/usr/bin/python2.7
+
+# Setup
+events=["Expo", "Fishing", "Kamelot", "Regnum", "Raid", "Tower", "Mining",
+ "Anniversary", "Christmas", "Easter", "Patrick", "Thanksgiving", "Valentine",
+ "Olympics", "Candor", "Worker"]
+
+# Functions
+def headers(val):
+ return '\n\t<dialog name="aurora_%s" hideText="true">\n\t\t<menu>\n' % val
+
+def navigation():
+ nav=""
+ nav+='\t\t\t<button x="300" y="20" name="Next" value="Ok" />\n'
+ return nav
+
+def tail():
+ return '\t\t</menu>\n\t</dialog>\n'
+
+def data(val):
+ bf='\t\t\t<image x="0" y="0" image="graphics/images/aurora/%s.png" />\n' % val
+ return bf
+
+# Begin
+f=open("aurora.tmp", "w")
+
+f.write('<?xml version="1.0" encoding="utf-8"?>\n<!-- This file is generated automatically, editing it will have no effect.\n Aurora Event Framework\n (C) Jesusalva, 2020 -->\n<dialogs>')
+
+for evtc in sorted(events):
+ f.write(headers(evtc))
+ f.write(data(evtc))
+ f.write(navigation())
+ f.write(tail())
+
+f.write('\n</dialogs>')
+f.close()
+
diff --git a/client/dailylogin.py b/client/dailylogin.py
new file mode 100755
index 0000000..52c945d
--- /dev/null
+++ b/client/dailylogin.py
@@ -0,0 +1,86 @@
+#!/usr/bin/python2.7
+
+# Setup
+x=y=0
+i=j=0
+
+# Functions
+def headers(val):
+ return '\n\t<dialog name="daily_%d" hideText="true">\n\t\t<menu>\n\t\t\t<text x="45" y="0" width="310" height="30" text="##BDaily Login Rewards##b" />\n <button x="157" y="280" name="Claim" value="Ok" />\n\n' % val
+
+def tail():
+ return '\n\t\t</menu>\n\t</dialog>\n'
+
+def override_check(vl, over, text1, text2):
+ global j
+ if not over:
+ j=0
+ return '\t\t\t<image %s image="graphics/images/%s.png" />\n' % (text1, text2)
+ else:
+ j+=1
+ if (j == vl):
+ return '\t\t\t<image %s image="graphics/images/done.png" />\n' % (text1)
+ elif (j < vl):
+ return '\t\t\t<image %s image="graphics/images/ok.png" />\n' % (text1)
+ else:
+ return ""
+
+def spammer(val, override=False):
+ bf=""
+
+ bf+=override_check(val, override, 'x="35" y="35"', 'jexp')
+ bf+=override_check(val, override, 'x="70" y="35"', 'bexp')
+ bf+=override_check(val, override, 'x="105" y="35"', 'sc')
+ bf+=override_check(val, override, 'x="140" y="35"', 'jexp')
+ bf+=override_check(val, override, 'x="175" y="35"', 'bexp')
+
+ bf+=override_check(val, override, 'x="35" y="70"', 'gp')
+ bf+=override_check(val, override, 'x="70" y="70"', 'sc')
+ bf+=override_check(val, override, 'x="105" y="70"', 'bexp')
+ bf+=override_check(val, override, 'x="140" y="70"', 'gp')
+ bf+=override_check(val, override, 'x="175" y="70"', 'jexp')
+
+ bf+=override_check(val, override, 'x="35" y="105"', 'bexp')
+ bf+=override_check(val, override, 'x="70" y="105"', 'gp')
+ bf+=override_check(val, override, 'x="105" y="105"', 'jexp')
+ bf+=override_check(val, override, 'x="140" y="105"', 'gift')
+ bf+=override_check(val, override, 'x="175" y="105"', 'gp')
+
+ bf+=override_check(val, override, 'x="35" y="140"', 'jexp')
+ bf+=override_check(val, override, 'x="70" y="140"', 'bexp')
+ bf+=override_check(val, override, 'x="105" y="140"', 'gp')
+ bf+=override_check(val, override, 'x="140" y="140"', 'jexp')
+ bf+=override_check(val, override, 'x="175" y="140"', 'bexp')
+
+ bf+=override_check(val, override, 'x="35" y="175"', 'gift')
+ bf+=override_check(val, override, 'x="70" y="175"', 'jexp')
+ bf+=override_check(val, override, 'x="105" y="175"', 'bexp')
+ bf+=override_check(val, override, 'x="140" y="175"', 'gp')
+ bf+=override_check(val, override, 'x="175" y="175"', 'jexp')
+
+ bf+=override_check(val, override, 'x="35" y="210"', 'bexp')
+ bf+=override_check(val, override, 'x="70" y="210"', 'last')
+ bf+=override_check(val, override, 'x="105" y="210"', 'sc')
+ bf+=override_check(val, override, 'x="140" y="210"', 'sc')
+ bf+=override_check(val, override, 'x="175" y="210"', 'sc')
+
+ bf+=override_check(val, override, 'x="35" y="245"', 'sc')
+
+ return bf
+
+# Begin
+f=open("daily.tmp", "w")
+
+f.write('<?xml version="1.0" encoding="utf-8"?>\n<!-- This file is generated automatically, editing it will have no effect.\n (C) Jesusalva, 2019 -->\n<dialogs>')
+
+while (i < 31):
+ i+=1
+ f.write(headers(i))
+ f.write(spammer(i, False))
+ f.write('\n\t\t\t<image x="245" y="52" image="graphics/images/final.png" />\n\n\t\t\t<!-- Complete -->\n')
+ f.write(spammer(i, True))
+ f.write(tail())
+
+f.write('\n</dialogs>')
+f.close()
+
diff --git a/client/magicacademy.py b/client/magicacademy.py
new file mode 100755
index 0000000..c6ee44c
--- /dev/null
+++ b/client/magicacademy.py
@@ -0,0 +1,60 @@
+#!/usr/bin/python2.7
+
+# Setup
+class dlist(list):
+ def __setitem__(self, index, value):
+ size = len(self)
+ if index >= size:
+ self.extend(None for _ in range(size, index + 1))
+ list.__setitem__(self, index, value)
+
+class Skill:
+ def __init__(self, ID, NAME, DESC):
+ self.id=ID
+ self.name=NAME
+ self.desc=DESC
+
+def skill_tree(sk1=None, sk2=None, sk3=None, sk4=None, sk5=None):
+ return [sk1, sk2, sk3, sk4, sk5]
+
+academy={}
+
+# Skill shortcuts
+SK_HEAL=Skill("heal", "Healing", "Heals target")
+SK_ABHEAL=Skill("abheal", "High Healing", "Supremely heals target")
+
+# Scholarship
+academy["scholarship"]=dlist()
+academy["scholarship"].append(skill_tree(SK_HEAL, None, SK_ABHEAL, None, None))
+
+
+# Functions
+def headers(classe, val):
+ return '\n\t<dialog name="mga_%s_%s" hideText="true">\n\t\t<menu>\n' % (classe, val)
+
+def navigation():
+ nav=""
+ nav+='\t\t\t<button x="300" y="20" name="Next" value="Ok" />\n'
+ return nav
+
+def tail():
+ return '\t\t</menu>\n\t</dialog>\n'
+
+def data(val):
+ bf='\t\t\t<image x="0" y="0" image="graphics/images/aurora/%s.png" />\n' % val
+ return bf
+
+# Begin
+f=open("aurora.tmp", "w")
+
+f.write('<?xml version="1.0" encoding="utf-8"?>\n<!-- This file is generated automatically, editing it will have no effect.\n Magic Academy Learning Interface\n (C) Jesusalva, 2020 -->\n<dialogs>')
+
+for evtc in sorted(events):
+ f.write(headers("none", evtc))
+ f.write(data(evtc))
+ f.write(navigation())
+ f.write(tail())
+
+f.write('\n</dialogs>')
+f.close()
+
diff --git a/client/minimap-dyecmd.py b/client/minimap-dyecmd.py
new file mode 100755
index 0000000..c43a4e4
--- /dev/null
+++ b/client/minimap-dyecmd.py
@@ -0,0 +1,17 @@
+#!/usr/bin/env python
+#-*- coding:utf-8 -*-
+
+import os
+f=open("minimap-dyecmd.sh", "w");
+CLIENT_DATA_ROOT="../../clientdata"
+
+map_names = sorted([os.path.splitext(p)[0] for p in os.listdir(os.path.join(CLIENT_DATA_ROOT, u'graphics', u'minimaps'))])
+
+f.write('cd '+os.path.join(CLIENT_DATA_ROOT, u'graphics', u'minimaps')+'\n')
+for c in map_names:
+ if os.path.exists(os.path.join(CLIENT_DATA_ROOT, u'graphics', u'minimaps', c+u'.png')):
+ i=c+u'.png'
+ f.write("dyecmd %s tmp ; mv tmp %s\n" % (i, i))
+ f.write("echo \"Converted "+i+" successfully.\"\n")
+
+f.close()
diff --git a/client/minimap-dyecmd.sh b/client/minimap-dyecmd.sh
new file mode 100755
index 0000000..e69de29
--- /dev/null
+++ b/client/minimap-dyecmd.sh
diff --git a/client/minimap-override/none.png b/client/minimap-override/none.png
new file mode 100644
index 0000000..539e992
--- /dev/null
+++ b/client/minimap-override/none.png
Binary files differ
diff --git a/client/minimap-render.py b/client/minimap-render.py
new file mode 100755
index 0000000..9d4bac1
--- /dev/null
+++ b/client/minimap-render.py
@@ -0,0 +1,171 @@
+#!/usr/bin/env python
+#-*- coding:utf-8 -*-
+
+import sys
+import os
+import subprocess
+import tempfile
+
+CLIENT_DATA_ROOT = os.path.realpath(
+ os.path.join(
+ os.path.dirname(__file__),
+ u'../../clientdata',
+ )
+)
+
+SKIP_DOMAIN="030-"
+
+class MinimapRenderer(object):
+
+ PROGRAMS = {
+ 'default': {
+ 'tmxrasterizer': 'tmxrasterizer',
+ 'im_convert': 'convert',
+ },
+ 'win32': {
+ 'tmxrasterizer': 'tmxrasterizer.exe',
+ 'im_convert': 'convert.exe',
+ },
+ }
+
+ def __init__(self, map_name, tilesize, useAntiAliasing):
+ self.map_name = map_name
+ self.tilesize = tilesize
+ self.useAntiAliasing = useAntiAliasing
+
+ def render(self):
+ """
+ Processes a map
+ """
+ if not os.path.exists(os.path.join(CLIENT_DATA_ROOT, u'maps', self.map_name+u'.tmx')):
+ sys.stderr.write(u'Invalid map name: %s. Skipping.\n' % self.map_name)
+ return 1
+ if not self.map_name.endswith(u'.tmx'):
+ self.map_name = self.map_name+u'.tmx'
+ if SKIP_DOMAIN in self.map_name:
+ print(u'Skipping %s (regex)...\n' % self.map_name)
+ return 0
+
+ map_number = os.path.splitext(os.path.basename(self.map_name))[0]
+ tmx_file = os.path.join(CLIENT_DATA_ROOT, u'maps', self.map_name)
+ minimap_file = os.path.join(CLIENT_DATA_ROOT, u'graphics', u'minimaps', map_number+u'.png')
+
+ prefix = os.path.commonprefix((tmx_file, minimap_file))
+ sys.stdout.write(u'%s -> %s\n' % (os.path.relpath(tmx_file, prefix), os.path.relpath(minimap_file, prefix)))
+
+ try:
+ self.do_render(tmx_file, minimap_file)
+ except Exception as e:
+ sys.stderr.write(u'\x1b[31m\x1b[1mError while rendering %s: %s\x1b[0m\n' % (self.map_name, e))
+ return 1
+ else:
+ return 0
+
+ def do_render(self, tmx_file, bitmap_file):
+ """
+ The map rendering implementation
+ """
+ platform_programs = MinimapRenderer.PROGRAMS.get(sys.platform, MinimapRenderer.PROGRAMS.get('default'))
+ # tmx rasterize
+ mrf, map_raster = tempfile.mkstemp(suffix='.png')
+ tmxrasterizer_cmd = [
+ #platform_programs.get('tmxrasterizer'),
+ '../../tiled/default/install-root/usr/local/bin/tmxrasterizer',
+ '--tilesize', str(self.tilesize), '--hide-layer', 'Collision','--hide-layer', 'Height','--hide-layer', 'Collisions','--hide-layer', 'collision','--hide-layer', 'height','--hide-layer', 'Heights', '--hide-layer', 'height', '--ignore-visibility', '--hide-object-layers',
+ ]
+ if self.useAntiAliasing:
+ tmxrasterizer_cmd.append('--anti-aliasing')
+ tmxrasterizer_cmd += [tmx_file, map_raster]
+ subprocess.check_call(tmxrasterizer_cmd)
+ if os.stat(map_raster).st_size == 0:
+ raise Exception('A problem was encountered when rendering a map')
+ # add cell-shading to the minimap to improve readability
+ ebf, edges_bitmap = tempfile.mkstemp(suffix='.png')
+ subprocess.check_call([
+ platform_programs.get('im_convert'), map_raster,
+ '-set', 'option:convolve:scale', '-1!',
+ '-morphology', 'Convolve', 'Laplacian:0',
+ '-colorspace', 'gray',
+ '-auto-level',
+ '-threshold', '2.8%',
+ '-negate',
+ '-transparent', 'white',
+ edges_bitmap
+ ])
+ subprocess.check_call([
+ platform_programs.get('im_convert'), map_raster, edges_bitmap,
+ '-compose', 'Dissolve',
+ '-define', 'compose:args=35',
+ '-composite',
+ bitmap_file
+ ])
+ os.unlink(map_raster)
+ os.unlink(edges_bitmap)
+
+ @staticmethod
+ def check_programs():
+ """
+ Checks the require programs are available
+ """
+ def which(program):
+ import os
+ def is_exe(fpath):
+ return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
+ fpath, fname = os.path.split(program)
+ if fpath:
+ if is_exe(program):
+ return program
+ else:
+ for path in os.environ["PATH"].split(os.pathsep):
+ exe_file = os.path.join(path, program)
+ if is_exe(exe_file):
+ return exe_file
+ return None
+
+ platform_programs = MinimapRenderer.PROGRAMS.get(sys.platform, MinimapRenderer.PROGRAMS.get('default'))
+ for program in platform_programs.values():
+ if not which(program):
+ raise Exception('The required "%s" program is missing from your PATH.' % program)
+
+def usage():
+ sys.stderr.write(u'''Usage: %s MAP_NAME...
+
+ Example:
+ $ ./minimap-render.py 007-1
+ will render the map at maps/007-1.tmx in the graphics/minimaps directory.
+ $ ./minimap-render.py all
+ will render all existing maps found in the maps directory.
+ $ ./minimap-render.py update
+ will update all existing minimaps found in the graphics/minimaps directory.
+
+ For convenience,
+ $ ./minimap-render.py 007-1.tmx
+ is also accepted.
+ \n''' % sys.argv[0])
+
+def main():
+ if not len(sys.argv) > 1:
+ usage()
+ return 127
+ try:
+ MinimapRenderer.check_programs()
+ except Exception as e:
+ sys.stderr.write(u'%s\n' % e)
+ return 126
+
+ status = 0
+ if sys.argv[1].lower() == 'all':
+ map_names = sorted([os.path.splitext(p)[0] for p in os.listdir(os.path.join(CLIENT_DATA_ROOT, u'maps'))])
+ elif sys.argv[1].lower() == 'update':
+ map_names = sorted([os.path.splitext(p)[0] for p in os.listdir(os.path.join(CLIENT_DATA_ROOT, u'graphics', u'minimaps'))])
+ else:
+ map_names = sys.argv[1:]
+
+ for map_name in map_names:
+ # Render tiles at 1 pixel size
+ map_renderer = MinimapRenderer(map_name, 1, True)
+ status += map_renderer.render()
+ return 0
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/client/skills.py b/client/skills.py
new file mode 100755
index 0000000..bfe59f3
--- /dev/null
+++ b/client/skills.py
@@ -0,0 +1,137 @@
+#!/usr/bin/python2.7
+
+# Setup
+x=y=0
+i=j=0
+
+skills=[]
+
+class Skill:
+ def __init__(self, sid, name, icon, desc, bmp, amp, cmd, maxlv):
+ self.id=sid
+ self.lv=maxlv
+ self.name=name
+ self.icon=icon
+ self.cmd=cmd
+
+ self.desc=desc
+ self.bmp=bmp
+ self.amp=amp
+
+def fillskill(sk, lv):
+ sid=sk.id
+ name=sk.name
+ icon=sk.icon
+ desc=sk.desc
+ bmp=sk.bmp
+ amp=sk.amp
+ cmd=sk.cmd
+
+ if lv > 0:
+ lvstr='\t\t\tlevel="%d"\n' % lv
+ mpstr='%d MP. ' % int(bmp+(amp*(lv-1)))
+ cmdstr='\t\t\tinvokeCmd="@sk-%s"\n' % cmd
+ else:
+ lvstr=''
+ lv=1
+ mpstr=''
+ cmdstr=''
+
+ msg='\
+\t\t<skill\n\
+\t\t\tid="%d"\n\
+\t\t\tname="%s"\n\
+\t\t\ticon="graphics/skills/%s.png"\n\
+\t\t\tdescription="%s%s"\n\
+%s\
+%s\
+\t\t/>\n' % (sid, name, icon, mpstr, desc, cmdstr, lvstr)
+ return msg
+
+
+
+
+
+
+
+
+
+
+
+# Declare the skills
+
+#########################
+### Transmutation Skills
+#########################
+#skills.append(Skill(20024, "Parum", "other/parum", "Transmutate wood into stuff.",
+#50, 0, "parum", 0))
+#skills.append(Skill(20027, "Transmutation", "transmutation", "Transmute stuff into other stuff.",
+#215, -5, "trans", 10))
+
+#########################
+### Summon Skills
+#########################
+skills.append(Skill(20025, "Summon Maggots", "other/kalmurk", "2x Maggot Slime.",
+40, 5, "kalmurk", 0))
+skills.append(Skill(20029, "Summon Dragon", "none", "4x Dragon Scale.",
+50, 4, "dragokin", 0))
+skills.append(Skill(20030, "Summon Slimes", "none", "15x Maggot Slime.",
+30, 3, "limerizer", 0))
+skills.append(Skill(20043, "Summon Fluffies", "none", "1x White Fur.",
+25, 4, "cuteheart", 0))
+skills.append(Skill(20042, "Summon Spiky", "none", "1x Mushroom Spores.",
+25, 5, "kalspike", 0))
+skills.append(Skill(20041, "Summon Mouboo", "none", "1x Mouboo Figurine.",
+25, 5, "kalboo", 0))
+skills.append(Skill(20036, "Summon Snakes", "none", "1x Snake Egg.",
+35, 6, "halhiss", 0))
+skills.append(Skill(20037, "Summon Wolverns", "none", "5x White Fur.",
+45, 5, "kalwulf", 0))
+skills.append(Skill(20038, "Summon Fairies", "none", "1x Fluo Powder.",
+40, 4, "fairykingdom", 0))
+skills.append(Skill(20039, "Summon Yetis", "none", "1x Frozen Yeti Tear.",
+37, 5, "frozenheart", 0))
+skills.append(Skill(20040, "Summon Terranite", "none", "1x Terranite Ore.",
+47, 5, "stoneheart", 0))
+skills.append(Skill(20044, "Summon Plants", "none", "2x Root.",
+30, 3, "plantkingdom", 5))
+skills.append(Skill(20047, "Summon Ducks", "none", "1x Cherry Cake. Req. Rubber Ducky.",
+40, 7, "ducky", 0))
+skills.append(Skill(20049, "Summon Pixies", "none", "3x Fluo Powder.",
+40, 4, "fairyempire", 0))
+
+skills.append(Skill(20023, "Summon Cave Maggot", "none", "Req. Zarkor Scroll.",
+40, 7, "zarkor", 0))
+
+
+
+
+
+
+
+
+
+
+
+
+# Begin
+f=open("skills.tmp", "w")
+
+f.write('<?xml version="1.0" encoding="utf-8"?>\n<!-- This file is generated automatically, editing it will have no effect.\n (C) Jesusalva, 2019-2020 -->\n<skills>\n\t<set name="Summon">\n')
+
+for sk in skills:
+ i=0
+ while (i < sk.lv):
+ i+=1
+ f.write(fillskill(sk, i))
+
+ # Fill the fallback
+ if (int(sk.lv)):
+ sk.desc="MP + "+str(sk.amp)+"/lv. "+sk.desc
+ f.write(fillskill(sk, -1))
+ f.write("\n")
+
+# We're done
+f.write('\n\t</set>\n</skills>')
+f.close()
+
diff --git a/client/tmxrasterizer b/client/tmxrasterizer
new file mode 100755
index 0000000..f079132
--- /dev/null
+++ b/client/tmxrasterizer
Binary files differ
diff --git a/client/weapons.py b/client/weapons.py
new file mode 100755
index 0000000..cc45d01
--- /dev/null
+++ b/client/weapons.py
@@ -0,0 +1,89 @@
+#!/usr/bin/python2.7
+
+class Item:
+ def __init__(self, xid):
+ self.id=xid
+ self.lvl=0
+
+a=open("../../clientdata/items.xml", "r")
+
+swords=[]
+bows=[]
+shields=[]
+
+gid="0"
+rid=0
+ctx=Item(0)
+mem=[]
+
+for l in a:
+ if "<item id=" in l:
+ if ctx.id > 0:
+ mem.append(ctx)
+
+ gid=l.replace('\t', '').replace(' ','').replace('<itemid=', '').replace('"', '').replace("'", "")
+ rid=0
+ if "-" in gid:
+ gid="0"
+ continue
+ try:
+ rid=int(gid)
+ except:
+ print "[CRITICAL] Invalid item ID format: " + l
+ exit(1)
+
+ ctx=Item(rid)
+
+ if "\tlevel=" in l or " level=" in l:
+ gid=l.replace('\t', '').replace(' ','').replace('level=', '').replace('"', '').replace("'", "")
+ try:
+ rid=int(gid)
+ except:
+ print "[CRITICAL] Invalid item level format: " + l
+ exit(1)
+ ctx.lvl=0+rid
+
+mem=sorted(mem, key=lambda xcv: xcv.lvl, reverse=True)
+
+for r in mem:
+ rid=r.id
+ if rid >= 2700 and rid <= 2899:
+ shields.append(rid)
+ elif rid >= 3500 and rid <= 3999:
+ swords.append(rid)
+ elif rid >= 6000 and rid <= 6499:
+ bows.append(rid)
+
+a.close()
+
+#shields=sorted(shields, reverse=True)
+#bows=sorted(bows, reverse=True)
+#swords=sorted(swords, reverse=True)
+
+b=open("weapons.tmp", "w")
+
+b.write('<?xml version="1.0" encoding="utf-8"?>\n\
+<!-- Author: 4144, Jesusalva\n\
+Copyright (C) 2015 Evol Online\n\
+Copyright (C) 2018 TMW2: Moubootaur Legends\n -->\n\
+\n\
+<weapons>\n')
+
+b.write(' <swords>\n')
+
+for i in swords:
+ b.write(' <item id="%d"/>\n' % i)
+
+b.write(' </swords>\n <bows>\n')
+
+for i in bows:
+ b.write(' <item id="%d"/>\n' % i)
+
+b.write(' </bows>\n <shields>\n')
+
+for i in shields:
+ b.write(' <item id="%d"/>\n' % i)
+
+b.write(' </shields>\n</weapons>')
+
+b.close()