diff options
Diffstat (limited to 'wiki')
-rwxr-xr-x | wiki/elegen.py | 426 | ||||
-rwxr-xr-x | wiki/lanalysis.py | 394 | ||||
-rwxr-xr-x | wiki/redesign.py | 1050 | ||||
-rwxr-xr-x | wiki/sedesign.py | 515 | ||||
-rw-r--r-- | wiki/tmp-arm | 247 | ||||
-rw-r--r-- | wiki/tmp-dec | 8 | ||||
-rw-r--r-- | wiki/tmp-etc | 25 | ||||
-rw-r--r-- | wiki/tmp-wpn | 59 | ||||
-rwxr-xr-x | wiki/webwikigen.py | 758 | ||||
-rwxr-xr-x | wiki/wikigen.py | 898 |
10 files changed, 4380 insertions, 0 deletions
diff --git a/wiki/elegen.py b/wiki/elegen.py new file mode 100755 index 0000000..e8385f0 --- /dev/null +++ b/wiki/elegen.py @@ -0,0 +1,426 @@ +#! /usr/bin/env python3 +# -*- coding: utf8 -*- +# +# Copyright (C) 2010-2011 Evol Online +# Copyright (C) 2018 TMW-2 +# Author: Andrei Karas (4144) +# Author: Jesusalva + +import datetime + +wikib=open("EleMonsters.html", "w") +wikib.write('<html><head><meta charset=utf8 /><title>EleGen File</title></head><body>') +totalid=0 +bifs=False + +def printSeparator(): + print("--------------------------------------------------------------------------------") + +def showHeader(): + print("TMW2 Ele Generator") + print("This stuff analyzes and sorts mobs elementals, races and walkmasks.") + ##print "Evol client data validator." + print("Run at: " + datetime.datetime.now().isoformat()) + ##print "https://gitlab.com/evol/evol-tools/blob/master/testxml/testxml.py" + printSeparator() + +def showFooter(): + #pass + #printSeparator() + print("Done.") + + + +Mobs0=[] +Mobs1=[] +Mobs2=[] +Mobs3=[] +Mobs4=[] +Mobs5=[] +Mobs6=[] +Mobs7=[] +Mobs8=[] +Mobs9=[] +MobsA=[] + +SysDrops=[] + +def fwalk(wmask): + if wmask == 'WATER': + return '<font color=#00f>%s</font>' % (wmask) + elif wmask == 'AIR': + return '<font color=#093>%s</font>' % (wmask) + elif wmask == 'WALL': + return '<font color=#f00>%s</font>' % (wmask) + elif wmask == 'NORMAL' or wmask == 'DEFAULT': + return '<font color=#111>%s</font>' % (wmask) + else: + print("Invalid walk mask: "+wmask) + exit(1) + +def WhatRace(rac): + rc=rac.race + if rc == 0: + return "Formless" + elif rc == 1: + return "Undead" + elif rc == 2: + return "Brute" + elif rc == 3: + return "Plant" + elif rc == 4: + return "Insect" + elif rc == 5: + return "Mineral" + elif rc == 6: + return "Evil" + elif rc == 7: + return "SemiHuman" + elif rc == 8: + return "Angel" + elif rc == 9: + return "Dragon" + elif rc == 10: + return "Player" + elif rc == 11: + return "Boss" + elif rc == 12: + return "NonBoss" + elif rc == 14: + return "NonSemiHuman" + elif rc == 15: + return "NonPlayer" + elif rc == 16: + return "SemiPlayer" + elif rc == 17: + return "NonSemiPlayer" + else: + print("ERROR, INVALID RACE ID: %d (ID: %s)" % (rc, rac.id)) + exit(1) + +def WhatElem(rac): + rc=rac.elem + tl="ERROR" + cl="#F00" + if rc == 0: + tl,cl="Neutral","#000" + elif rc == 1: + tl,cl="Water","#00F" + elif rc == 2: + tl,cl="Earth","#7A0" + elif rc == 3: + tl,cl="Fire","#F00" + elif rc == 4: + tl,cl="Wind","#093" + elif rc == 5: + tl,cl="Nature","#040" + elif rc == 6: + tl,cl="Holy","#afa" + elif rc == 7: + tl,cl="Dark","#908" + elif rc == 8: + tl,cl="Ghost","#404" + elif rc == 9: + tl,cl="Undead","#440" + else: + print("ERROR, INVALID ELEM ID: %d (ID: %s)" % (rc, rac.id)) + exit(1) + return "<font color=%s>%s</font>" % (cl, tl) + +class Mob: + def __init__(self): + # Basic + self.id="0" + #self.aegis="UnknownMonster" # SpriteName is not used anywhere, we are using its ID + self.name="Unknown Monster Name" + self.view="1" + + # Defensive + self.mobpt="0" # Mob Points “Level” + self.hp="0" + self.xp="0" + self.jp="0" + self.st="" + + # Offensive + self.atk="[0, 0]" + self.range="0" + self.move="0" + self.delay="0" + self.drops=[] + + # New + self.race=-1 + self.elem=-1 + self.elel=-1 + self.walk="NORMAL" + +def MobAlloc(ab): + try: + maab=int(ab.elem) + except: + maab=9901 + + if maab == 0: + Mobs0.append(ab) + elif maab == 1: + Mobs1.append(ab) + elif maab == 2: + Mobs2.append(ab) + elif maab == 3: + Mobs3.append(ab) + elif maab == 4: + Mobs4.append(ab) + elif maab == 5: + Mobs5.append(ab) + elif maab == 6: + Mobs6.append(ab) + elif maab == 7: + Mobs7.append(ab) + elif maab == 8: + Mobs8.append(ab) + elif maab == 9: + Mobs9.append(ab) + else: + MobsA.append(ab) + +def testMobs(): + global totalid + print("Generating Elem-Mob Wiki...") + src=open("../../serverdata/db/re/mob_db.conf", "r") + wikib.write("<h1 id=#x>EleGen Monster Database</h1>\n") + start=False + dropper=False + x=Mob() # Only for pyflakes2 + + for a in src: + if a == "{\n": + if start and not bifs and ((int(x.hp) <= 50) or (x.race == 3)): + start=False + + if start: + MobAlloc(x) + else: + start=True + x=Mob() + + if " Id:" in a: + x.id=stp(a) + totalid+=1 + if x.id == "ID": + continue + + if " Name:" in a: + x.name=stp(a) + elif " Hp:" in a: + x.hp=stp(a) + elif " Lv:" in a: + x.mobpt=stp(a) + elif " Exp:" in a: + x.xp=stp(a) + elif " JExp:" in a: + x.jp=stp(a) + elif " Attack:" in a: + x.atk=stp(a) + elif " AttackRange:" in a: + x.range=stp(a) + elif " MoveSpeed:" in a: + x.move=stp(a) + elif " ViewRange:" in a: + x.view=stp(a) + elif " AttackDelay:" in a: + x.delay=stp(a) + elif " Looter: true" in a: + x.st+="<font color=#790>Lot</font>," + elif " Assist: true" in a: + x.st+="<font color=#0a0>Ass</font>," + elif " Aggressive: true" in a: + x.st+="<font color=#f00>Agr</font>," + elif " WalkMask:" in a: + x.walk=stp(a) + elif " Element:" in a: + tmp=stp(a) + tmp2=tmp.split(',') + try: + x.elem=int(tmp2[0]) + x.elel=int(tmp2[1]) + except: + print("Invalid Element for mob %s: %s" % (x.id, tmp)) + exit(1) + elif " Race:" in a: + try: + x.race=int(stp(a)) + except: + print("Invalid Race for mob %s: %s" % (x.id, a)) + exit(1) + elif 'Drops: ' in a: + dropper=True + elif dropper and '}' in a: + dropper=False + elif dropper: + x.drops.append(stp(a).split(": ")) + # Write last entry + MobAlloc(x) + + writeMob() + + wikib.write('\n\n|Mode|Desc|\n|----|----|\n') + wikib.write('|Lot|Looter|\n') + wikib.write('|Ass|Assist|\n') + wikib.write('|Agr|Aggressive|\n') + + src.close() + +def stp(x): + return x.replace('\n', '').replace('|', '').replace('(int, defaults to ', '').replace(')', '').replace('basic experience', '').replace('"','').replace(" ","").replace("\t","").replace('(string', '').replace('Name: ','').replace('Element: ','').replace('Race: ','').replace('AttackDelay: ', '').replace('WalkMask: ','').replace('MoveSpeed: ', '').replace('AttackRange: ', '').replace('ViewRange: ','').replace('Attack: ','').replace('ViewRange: ','').replace('Hp: ','').replace('Id: ','').replace('Lv: ','').replace('view range','').replace('attack range','').replace('move speed','').replace('health','').replace('(int','').replace('attack delay','atk.').replace('(','').replace(')','').replace('WALK_','') + + +def MonsterWrite(tbl): + # TODO: Check _mobs files to determine the usual monster density (a misc info to aid adding proper drop specs) + wikib.write("<table border=1>\n") + wikib.write("<tr><th>ID</th><th>Name</th><th>Mob Info</th><th>Elegen</th><th>Misc Info</th><th>Rewards</th><th>Drops</th></tr>\n") + for i in sorted(tbl, key=lambda tbl: int(tbl.mobpt)): + if i.id == 'ID': + continue + wikib.write('<tr><td><a name="' + i.id + '"></a>' + + i.id +"</td><td>"+ + i.name +"</td><td>"+ + mb_core(i) +"</td><td>"+ + mb_eleg(i) +"</td><td>"+ + mbdt('misc', mb_rdmisc(i)) +"</td><td>"+ + mbdt('Exp\'s', mb_rdrw(i)) +"</td><td>"+ + mbdt('drops', mb_rddrop(i)) +"</td></tr>\n" + ) + wikib.write("</table>\n") + wikib.write("\n<a href=#x>(↑) Return to top</a><br/><br/>\n\n") + +def writeMob(): + wikib.write("Total monsters: %d<br/>" % totalid) + wikib.write("<ul>\ +<li><a href=#0>Neutral</a></li>\n\ +<li><a href=#1>Water</a></li>\n\ +<li><a href=#2>Earth</a></li>\n\ +<li><a href=#3>Fire</a></li>\n\ +<li><a href=#4>Wind</a></li>\n\ +<li><a href=#5>Nature (Poison)</a></li>\n\ +<li><a href=#6>Holy</a></li>\n\ +<li><a href=#7>Dark (Shadow)</a></li>\n\ +<li><a href=#8>Ghost</a></li>\n\ +<li><a href=#9>Undead</a></li>\n\ +<li><a href=#Nan>-</a></li>\n\ +<li><a href=Elements><font color=#f00>Elemental Reference</font></a></li>\n\ +</ul> ") + + wikib.write("<h1 id=0>Neutral</h1>\n\n") + wikib.write("<i>Total: %d Monsters</i><br/>\n\n" % len(Mobs0)) + MonsterWrite(Mobs0) + wikib.write("<h1 id=1>Water</h1>\n\n") + wikib.write("<i>Total: %d Monsters</i><br/>\n\n" % len(Mobs1)) + MonsterWrite(Mobs1) + wikib.write("<h1 id=2>Earth</h1>\n\n") + wikib.write("<i>Total: %d Monsters</i><br/>\n\n" % len(Mobs2)) + MonsterWrite(Mobs2) + wikib.write("<h1 id=3>Fire</h1>\n\n") + wikib.write("<i>Total: %d Monsters</i><br/>\n\n" % len(Mobs3)) + MonsterWrite(Mobs3) + wikib.write("<h1 id=4>Wind</h1>\n\n") + wikib.write("<i>Total: %d Monsters</i><br/>\n\n" % len(Mobs4)) + MonsterWrite(Mobs4) + wikib.write("<h1 id=5>Nature</h1>\n\n") + wikib.write("<i>Total: %d Monsters</i><br/>\n\n" % len(Mobs5)) + MonsterWrite(Mobs5) + wikib.write("<h1 id=6>Holy</h1>\n\n") + wikib.write("<i>Total: %d Monsters</i><br/>\n\n" % len(Mobs6)) + MonsterWrite(Mobs6) + wikib.write("<h1 id=7>Dark</h1>\n\n") + wikib.write("<i>Total: %d Monsters</i><br/>\n\n" % len(Mobs7)) + MonsterWrite(Mobs7) + wikib.write("<h1 id=8>Ghost</h1>\n\n") + wikib.write("<i>Total: %d Monsters</i><br/>\n\n" % len(Mobs8)) + MonsterWrite(Mobs8) + wikib.write("<h1 id=9>Undead</h1>\n\n") + wikib.write("<i>Total: %d Monsters</i><br/>\n\n" % len(Mobs9)) + MonsterWrite(Mobs9) + + wikib.write("<h1 id=NaN>Error</h1>\n\n") + wikib.write("<i>Total: %d Monsters</i><br/>\n\n" % len(MobsA)) + MonsterWrite(MobsA) + + +def mbdt(summary, content): + return "<pre>%s</pre>" % (content) + return "<details>\ +<summary>"+summary+"</summary>\ +<pre>"+content+"</pre></details>" + +def mb_core(mb): + buff="" + buff+="Lvl: %s<br/>\n" % (mb.mobpt) + buff+="HP: <b><font color=#0a0>%s</font></b><br/>\n" % (mb.hp) + buff+="ATK: <b><font color=#a00>%s</font></b><br/>\n" % (mb.atk) + if mb.st != "": + buff+="Modes: <i>%s</i>" % (mb.st) + return buff + +def mb_eleg(mb): + buff="" + buff+="Race: %s<br/>\n" % (WhatRace(mb)) + buff+="Walk: %s<br/>\n" % (fwalk(mb.walk)) + buff+="Element: %s<br/>\n" % (WhatElem(mb)) + return buff + +def mb_rdmisc(mb): + buff="" + if "agr" in mb.st.lower(): + buff+="View Range: %s\n" % (mb.view) + buff+="Attack Range: %s\n" % (mb.range) + buff+="AtkDelay: %s ms\n" % (mb.delay) + buff+="Move speed: %s ms\n" % (mb.move) + buff+="Element Level: %d\n" % (mb.elel) + return buff + +def mb_rdrw(mb): + buff="" + try: + buff+="MobPoints: %d\n" % (int(mb.mobpt)*11/10) + except: + pass + buff+="%s\n" % (mb.xp) + buff+="%s\n" % (mb.jp) + return buff + +def mb_rddrop(mb): + buff="" + for ax in mb.drops: + # Ignore disabled drops + if ax[0].startswith("//"): + continue + + # Write drop + try: + buff+=ax[0]+': ' + str(int(ax[1])/100.0) + ' %\n' + except IndexError: + print("Fatal: invalid %s mob with %s drops" % (mb.name, str(ax))) + exit(1) + except: + print("[Warning] %s incorrect drop: %s" % (mb.name, str(ax))) + buff+=ax[0]+': ' + ax[1] + ' ppm\n' + + # Save to SysDrops + SysDrops.append([ax[0], ax[1], mb.name]) + + return buff + + + +showHeader() + +testMobs() +print("Total monsters: %d" % totalid) + +wikib.write('</body></html>') +wikib.close() +#print(str(SysDrops)) + +showFooter() +exit(0) diff --git a/wiki/lanalysis.py b/wiki/lanalysis.py new file mode 100755 index 0000000..bc2ffe2 --- /dev/null +++ b/wiki/lanalysis.py @@ -0,0 +1,394 @@ +#! /usr/bin/env python3 +# -*- coding: utf8 -*- +# +# Copyright (C) 2010-2011 Evol Online +# Copyright (C) 2018 TMW-2 +# Author: Andrei Karas (4144) +# Author: Jesusalva + +import datetime +import sys + +wikib=open("EleMonsters.html", "w") +wikib.write('<html><head><meta charset=utf8 /><title>EleGen File</title></head><body>') + +def printSeparator(): + print("--------------------------------------------------------------------------------") + +def showHeader(): + print("TMW2 Ele Generator") + print("This stuff analyzes and sorts mobs elementals, races and walkmasks.") + ##print "Evol client data validator." + print("Run at: " + datetime.datetime.now().isoformat()) + print("Output is: EleMonsters.html") + ##print "https://gitlab.com/evol/evol-tools/blob/master/testxml/testxml.py" + printSeparator() + +def showFooter(): + #pass + #printSeparator() + print("Done.") + + + +Mobs1=[] +Mobs2=[] +Mobs3=[] +Mobs4=[] +Mobs5=[] +Mobs6=[] +MobsA=[] + +SysDrops=[] + +def fwalk(wmask): + if wmask == 'WATER': + return '<font color=#00f>%s</font>' % (wmask) + elif wmask == 'AIR': + return '<font color=#093>%s</font>' % (wmask) + elif wmask == 'WALL': + return '<font color=#f00>%s</font>' % (wmask) + elif wmask == 'NORMAL' or wmask == 'DEFAULT': + return '<font color=#111>%s</font>' % (wmask) + else: + print("Invalid walk mask: "+wmask) + exit(1) + +def WhatRace(rac): + rc=rac.race + if rc == 0: + return "Formless" + elif rc == 1: + return "Undead" + elif rc == 2: + return "Brute" + elif rc == 3: + return "Plant" + elif rc == 4: + return "Insect" + elif rc == 5: + return "Fish" + elif rc == 6: + return "-" + elif rc == 7: + return "SemiHuman" + elif rc == 8: + return "Angel" + elif rc == 9: + return "Dragon" + elif rc == 10: + return "Player" + elif rc == 11: + return "Boss" + elif rc == 12: + return "NonBoss" + elif rc == 14: + return "NonSemiHuman" + elif rc == 15: + return "NonPlayer" + elif rc == 16: + return "SemiPlayer" + elif rc == 17: + return "NonSemiPlayer" + else: + print("ERROR, INVALID RACE ID: %d (ID: %s)" % (rc, rac.id)) + exit(1) + +def WhatElem(rac): + rc=rac.elem + tl="ERROR" + cl="#F00" + if rc == 0: + tl,cl="Neutral","#000" + elif rc == 1: + tl,cl="Water","#00F" + elif rc == 2: + tl,cl="Earth","#7A0" + elif rc == 3: + tl,cl="Fire","#F00" + elif rc == 4: + tl,cl="Wind","#093" + elif rc == 5: + tl,cl="Nature","#040" + elif rc == 6: + tl,cl="Holy","#afa" + elif rc == 7: + tl,cl="Dark","#908" + elif rc == 8: + tl,cl="Ghost","#404" + elif rc == 9: + tl,cl="Undead","#440" + else: + print("ERROR, INVALID ELEM ID: %d (ID: %s)" % (rc, rac.id)) + exit(1) + return "<font color=%s>%s</font>" % (cl, tl) + +class Mob: + def __init__(self): + # Basic + self.id="0" + #self.aegis="UnknownMonster" # SpriteName is not used anywhere, we are using its ID + self.name="Unknown Monster Name" + self.view="1" + self.boss=False + + # Defensive + self.mobpt="0" # Mob Points “Level” + self.hp="0" + self.xp="Exp: 0" + self.jp="JExp: 0" + self.st="" + + # Offensive + self.atk="[0, 0]" + self.range="0" + self.move="0" + self.delay="0" + self.drops=[] + + # New + self.race=-1 + self.elem=-1 + self.elel=-1 + self.walk="NORMAL" + +def MobAlloc(ab): + try: + maab=int(ab.mobpt) + except: + maab=9901 + + if maab <= 20: + Mobs1.append(ab) + elif maab <= 40: + Mobs2.append(ab) + elif maab <= 60: + Mobs3.append(ab) + elif maab <= 80: + Mobs4.append(ab) + elif maab <= 100: + Mobs5.append(ab) + elif maab <= 150: + Mobs6.append(ab) + else: + MobsA.append(ab) + +def testMobs(): + print("Generating Elem-Mob Wiki...") + if len(sys.argv) >= 2: + src=open(sys.argv[1]+"/db/re/mob_db.conf", "r") + else: + src=open("../../server-data/db/re/mob_db.conf", "r") + + wikib.write("<h1 id=#x>EleGen Monster Database</h1>\n") + start=False + dropper=False + x=Mob() # Only for pyflakes2 + + for a in src: + if a == "{\n": + if start: + MobAlloc(x) + else: + start=True + x=Mob() + + if " Id:" in a: + x.id=stp(a) + if x.id == "ID": + continue + + if " Name:" in a: + x.name=stp(a) + elif " Hp:" in a: + x.hp=stp(a) + elif " Lv:" in a: + x.mobpt=stp(a) + elif " Exp:" in a: + x.xp=stp(a) + elif " JExp:" in a: + x.jp=stp(a) + elif " Attack:" in a: + x.atk=stp(a) + elif " AttackRange:" in a: + x.range=stp(a) + elif " MoveSpeed:" in a: + x.move=stp(a) + elif " ViewRange:" in a: + x.view=stp(a) + elif " AttackDelay:" in a: + x.delay=stp(a) + elif " Boss: true" in a: + x.boss=True + elif " Looter: true" in a: + x.st+="<font color=#790>Lot</font>," + elif " Assist: true" in a: + x.st+="<font color=#0a0>Ass</font>," + elif " Aggressive: true" in a: + x.st+="<font color=#f00>Agr</font>," + elif " WalkMask:" in a: + x.walk=stp(a) + elif " Element:" in a: + tmp=stp(a) + tmp2=tmp.split(',') + try: + x.elem=int(tmp2[0]) + x.elel=int(tmp2[1]) + except: + print("Invalid Element for mob %s: %s" % (x.id, tmp)) + exit(1) + elif " Race:" in a: + try: + x.race=int(stp(a)) + except: + print("Invalid Race for mob %s: %s" % (x.id, a)) + exit(1) + elif 'Drops: ' in a: + dropper=True + elif dropper and '}' in a: + dropper=False + elif dropper: + x.drops.append(stp(a).split(": ")) + # Write last entry + MobAlloc(x) + + writeMob() + + wikib.write('\n\n|Mode|Desc|\n|----|----|\n') + wikib.write('|Lot|Looter|\n') + wikib.write('|Ass|Assist|\n') + wikib.write('|Agr|Aggressive|\n') + + src.close() + +def stp(x): + return x.replace('\n', '').replace('|', '').replace('(int, defaults to ', '').replace(')', '').replace('basic experience', '').replace('"','').replace(" ","").replace("\t","").replace('(string', '').replace('Name: ','').replace('Element: ','').replace('Race: ','').replace('AttackDelay: ', '').replace('WalkMask: ','').replace('MoveSpeed: ', '').replace('AttackRange: ', '').replace('ViewRange: ','').replace('Attack: ','').replace('ViewRange: ','').replace('Hp: ','').replace('Id: ','').replace('Lv: ','').replace('view range','').replace('attack range','').replace('move speed','').replace('health','').replace('(int','').replace('attack delay','atk.').replace('(','').replace(')','').replace('WALK_','') + + +def MonsterWrite(tbl): + # TODO: Check _mobs files to determine the usual monster density (a misc info to aid adding proper drop specs) + wikib.write("<table border=1>\n") + wikib.write("<tr><th>ID</th><th>Name</th><th>Mob Info</th><th>Elegen</th><th>Misc Info</th><th>Rewards</th><th>Drops</th></tr>\n") + for i in sorted(tbl, key=lambda tbl: int(tbl.mobpt)): + if i.id == 'ID': + continue + if i.boss: + i.name="<b>"+i.name+"</b>" + wikib.write('<tr><td><a name="' + i.id + '"></a>' + + i.id +"</td><td>"+ + i.name +"</td><td>"+ + mb_core(i) +"</td><td>"+ + mb_eleg(i) +"</td><td>"+ + mbdt('misc', mb_rdmisc(i)) +"</td><td>"+ + mbdt('Exp\'s', mb_rdrw(i)) +"</td><td>"+ + mbdt('drops', mb_rddrop(i)) +"</td></tr>\n" + ) + wikib.write("</table>\n") + wikib.write("\n<a href=#x>(↑) Return to top</a><br/><br/>\n\n") + +def writeMob(): + wikib.write("<ul>\ +<li><a href=#0>Starter</a></li>\n\ +<li><a href=#1>Apprentice</a></li>\n\ +<li><a href=#2>Intermediary</a></li>\n\ +<li><a href=#3>Advanced</a></li>\n\ +<li><a href=#4>Expert</a></li>\n\ +<li><a href=#5>Master</a></li>\n\ +<li><a href=#Nan>OoS</a></li>\n\ +</ul> ") + + wikib.write("<h1 id=0>Lv 0-20</h1>\n\n") + MonsterWrite(Mobs1) + wikib.write("<h1 id=1>Lv 21-40</h1>\n\n") + MonsterWrite(Mobs2) + wikib.write("<h1 id=2>Lv 41-60</h1>\n\n") + MonsterWrite(Mobs3) + wikib.write("<h1 id=3>Lv 61-80</h1>\n\n") + MonsterWrite(Mobs4) + wikib.write("<h1 id=4>Lv 81-100</h1>\n\n") + MonsterWrite(Mobs5) + wikib.write("<h1 id=5>Lv 101-150</h1>\n\n") + MonsterWrite(Mobs6) + + wikib.write("<h1 id=NaN>Lv 101+</h1>\n\n") + MonsterWrite(MobsA) + + +def mbdt(summary, content): + return "<b>"+summary+"</b><br/><pre>"+content+"</pre>" + return "<details>\ +<summary>"+summary+"</summary>\ +<pre>"+content+"</pre></details>" + +def mb_core(mb): + buff="" + buff+="Lvl: %s<br/>\n" % (mb.mobpt) + buff+="HP: <b><font color=#0a0>%s</font></b><br/>\n" % (mb.hp) + buff+="ATK: <b><font color=#a00>%s</font></b><br/>\n" % (mb.atk) + if mb.st != "": + buff+="Modes: <i>%s</i>" % (mb.st) + return buff + +def mb_eleg(mb): + buff="" + buff+="Race: %s<br/>\n" % (WhatRace(mb)) + buff+="Walk: %s<br/>\n" % (fwalk(mb.walk)) + buff+="Element: %s<br/>\n" % (WhatElem(mb)) + return buff + +def mb_rdmisc(mb): + buff="" + if "agr" in mb.st.lower(): + buff+="View Range: %s\n" % (mb.view) + buff+="Attack Range: %s\n" % (mb.range) + buff+="AtkDelay: %s ms\n" % (mb.delay) + buff+="Move speed: %s ms\n" % (mb.move) + buff+="Element Level: %d\n" % (mb.elel) + return buff + +def mb_rdrw(mb): + buff="" + buff+="<font color=#060><u>%s</b></u></font>\n" % (mb.xp.replace(' ', ' <b>')) + buff+="<font color=#006><u>%s</b></u></font>\n" % (mb.jp.replace(' ', ' <b>')) + try: + buff+="MobPoints: %d\n" % (int(mb.mobpt)*11/10) + except: + pass + return buff + +def mb_rddrop(mb): + buff="" + for ax in mb.drops: + # Ignore disabled drops + if ax[0].startswith("//"): + continue + + # Write drop + try: + buff+=ax[0]+': ' + str(int(ax[1])/100.0) + ' %\n' + except IndexError: + print("Fatal: invalid %s mob with %s drops" % (mb.name, str(ax))) + exit(1) + except: + print("[Warning] %s incorrect drop: %s" % (mb.name, str(ax))) + buff+=ax[0]+': ' + ax[1] + ' ppm\n' + + # Save to SysDrops + SysDrops.append([ax[0], ax[1], mb.name]) + + return buff + + + +showHeader() + +testMobs() + +wikib.write('<br/><hr/>') +wikib.write("Run at: " + datetime.datetime.now().isoformat()) +wikib.write('</body></html>') +wikib.close() +#print(str(SysDrops)) + +showFooter() +exit(0) diff --git a/wiki/redesign.py b/wiki/redesign.py new file mode 100755 index 0000000..8e94c52 --- /dev/null +++ b/wiki/redesign.py @@ -0,0 +1,1050 @@ +#! /usr/bin/env python3 +# -*- coding: utf8 -*- +# +# Copyright (C) 2010-2011 Evol Online +# Copyright (C) 2018 TMW-2 +# Author: Andrei Karas (4144) +# Author: Jesusalva +# +# The use of the data + +import datetime +import sys + +stgen=True +aeros=False +bifs=False +skipCI=False + +wikib=open("EleMonsters.html", "w") +wikib.write('<html><head><meta charset=utf8 /><title>EleGen File</title></head><body>') + +exp=[ 9,16,25,36,77,112,153,200,253,320, + 385,490,585,700,830,970,1120,1260,1420,1620, + 1860,1990,2240,2504,2950,3426,3934,4474,6889,7995, + 9174,10425,11748,13967,15775,17678,19677,21773,28543,34212, + 38065,42102,46323,53026,58419,64041,69892,75973,92468,115254, + 128692,142784,157528,178184,196300,215198,234879,255341,310188,365914, + 402508,442769,487051,535756,589342,648281,713112,784421,862867,949158, + 1044076,1148484,1263331,1389671,1528642,1681509,1849671,2034639,2238111, + 2461928, + 2708132,2978946,3276840,3604530,3964987,4361495,4797656,5277432,5805184,6095442, + 6400217,6720231,7056251,7409070,7779531,8168509,8576941,9005793,9456080,9928893, + 10425342,10946613,11493946,12068655,12672087,13305690,13970980,14669530,15403013,16173172, + 16981833,17830934,18722479,19658611,20641552,21673632,22757319,23895184,25089950,25591758, + 26103599,26625670,27158181,27701356,28255388,28820507,29396920,29984867,30584571,31196260, + 31820184,32456596,33105727,33767845,34443202,35132065,35834705,36551410,37282446,38028099, + 38788671,39564454,40355745,41162860,41986116,42825838,43682362,44556009,45447138,45901616, + 46360641,46824255,47292503,47765432,48243093,48725528,49212784,49704921,50201982,50704003, + 51211047,51723162,52240405,52762810,53290446,53823354,54361598,54905214,55454271,56008820, + 56568910,57134610,57705965,58283032,58865873,59454536,60049086,60649586,61256083,61868649, + 62487336,63112216,63743344,64380779,65024597,65674843,66331602,66994930,67664885,68341538, + 69024959,69715207,70412360,71116485,71827658,72545940,73271398,74004114,74744153,75491595, + 76246518,77008984,77779077,78556879,79342456,80135878,80937236,81746616,82564087,83389730, + 84223638,85065880,85916545,86775711,87643468,88519912,89405121,90299171,91202163,92114182, + 93035322,93965687,94905347,95854406,96812948,97781076,98758892,99746478,100743951,101751398, + 102768911,103796609,104834582,105882930,106941769,108011193,109091315,110182230,111284052,112396904, + 113520874,114656091,115802657,116960692,118130296,119311601,120504716,121709770,122926875,124156150, + 125397711,126651686,127918206,129197392,130489375,131794267,133112212,134443338,135787774,137145652, + 138517109,139902284,141301316,142714335,144141489,145582902,147038738,148509126,149994219,150894194, + 151799571,152710366,153626627,154548387,155475676,156408540,157346998,158291079,159240837,160196288, + 161157464,162124419,163097165,164075757,165060214,166050576,167046878,168049166,169057470,170071823, + 171092262,172118826,173151541,174190460,175235604,176287026,177344758,178408837,179479294,180556179, + 181639518,182729367,183825754,184928711,186038293,187154528,188277464,189407130,190543577,191686849, + 192836981,193994007,195157974,196328927,197506910,198691949,199884102,201083405,202289908,203503646, + 204724676,205953024,207188754,208431886,209682484,210940582,212206225,213479467,214760350,216048919, + 217345224,218649298,219961193,221280960,222608645,223944302,225287974,226639708,227999552,229367554, + 230743762,232128226,233520999,234922133,236331675,237749668,239176170,240611236,242054915,243507252, + 244968307,246438117,247916753,249404252,250900687,252406101,253920540,255444067,256976742,258518609, + 260069729,261630158,263199938,264779135,266367816,267966025,269573820,271191260,272818408,274455326, + 276102061,277758679,279425234,281101787,282788399,284485141,286192050,287909214,289636677,291374496, + 293122752,294881486,296650782,298430689,300221275,302022609,303834742,305657759,307491713,309336672, + 311192696,313059863,314938223,316827859,318728836,320641216,322565061,324500459,326447460,328406143, + 330376584,332358847,334353004,336359128,338377288,340407551,342449994,344504696,346571722,348651151, + 350743062,352847532,354964629,357094423,359236990,361392422,363560778,365742141,367936599,370144221, + 372365091,374599279,376846874,379107955,381382611,383670915,385972949,388288794,390618537,392962257, + 395320037,397691969,400078129,402478601,404893475,407322841,409766782,412225383,414698739,417186939, + 419690069,422208209,424741456,427289911,429853651,432432776,435027370,437637543,440263366,442024421, + 443792521,445567690,447349963,449139360,450935926,452739673,454550638,456368839,458194326,460027115, + 461867221,463714693,465569558,467431848,469301579,471178794,473063508,474955766,476855601,478763022, + 480678083,482600803,484531205,486469328,488415217,490368880,492330355,494299675,496276878,498261990, + 500255043,502256068,504265102,506282171,508307305,510340540,512381907,514431439,516489176,518555144, + 520629376,522711891,524802748,526901963,529009581,531125618,533250127,535383137,537524678,539674777, + 541833486,544000830,546176836,548361554,550555012,552757234,554968274,557188159,559416915,561654583, + 563901210,566156820,568421455,570695142,572977924,575269847,577570928,579881219,582200741,584529542, + 586867672,589215145,591572009,593938303,596314063,598699319,601094122,603498497,605912494,608336152, + 610769496,613212575,615665434,618128102,620600617,623083026,625575357,628077658,630589971,633112332, + 635644789,638187373,640740134,643303101,645876314,648459827,651053675,653657891,656272528,658897623, + 661533224,664179368,666836088,669503437,672181451,674870184,677569669,680279959,683001081,685733085, + 688476023,691229930,693994859,696770843,699557927,702356165,705165600,707986270,710818214,713661496, + 716516145,719382218,722259755,725148792,728049398,730961596,733885443,736820993,739768279,742727359, + 745698276,748681079,751675801,754682510,757701238,760732051,763774987,766830096,769897426,772977027, + 776068941,779173220,782289911,785419075,788560754,791714999,794881861,798061393,801253640,804458666, + 807676501,810907214,814150847,817407448,820677081,823959788,827255638,830564665,833886935,837222492 + ] + +def printSeparator(): + print("--------------------------------------------------------------------------------") + +def showHeader(): + global stgen, aeros, bifs, skipCI + print("TMW2 Ele Generator") + print("Run at: " + datetime.datetime.now().isoformat()) + print("Usage: ./redesign.py [default|aeros|none|update|all] [<path_to_serverdata>]") + if len(sys.argv) >= 2: + if sys.argv[1] == "default": + stgen=True + aeros=False + bifs=False + skipCI=False + elif sys.argv[1] == "aeros": + stgen=False + aeros=True + bifs=False + skipCI=False + elif sys.argv[1] == "none": + stgen=False + aeros=False + bifs=False + skipCI=False + elif sys.argv[1] == "update": + stgen=True + aeros=False + bifs=False + skipCI=True + elif sys.argv[1] == "all": + stgen=True + aeros=True + bifs=True + skipCI=False + else: + exit(1) + print("This stuff analyzes and sorts monsters and then create base stats for Moubootaur Legends.") + print("Drops aren't calculated or taken in account, TWEAK AS NEEDED") + printSeparator() + print("Output is: EleMonsters.html") + +def showFooter(): + #pass + #printSeparator() + print("Done.") + + + +Mobs1=[] +Mobs2=[] +Mobs3=[] +Mobs4=[] +Mobs5=[] +Mobs6=[] +MobsA=[] + +# [N, W, E, F, W, -, H, H, G, -] +Ele=[0, 0, 0, 0, 0, 0, 0, 0, 0] + +# This is for Aeros +Plants=[] +Level50=[] +Level100=[] +Aggressive=[] +Assistant=[] +Looter=[] +Boss=[] + +SysDrops=[] + +def fwalk(wmask): + if wmask == 'WATER': + return '<font color=#00f>%s</font>' % (wmask) + elif wmask == 'AIR': + return '<font color=#093>%s</font>' % (wmask) + elif wmask == 'WALL': + return '<font color=#f00>%s</font>' % (wmask) + elif wmask == 'NORMAL' or wmask == 'DEFAULT': + return '<font color=#111>%s</font>' % (wmask) + else: + print("Invalid walk mask: "+wmask) + exit(1) + +def WhatRace(rac): + rc=rac.race + if rc == 0: + return "Formless" + elif rc == 1: + return "Undead" + elif rc == 2: + return "Brute" + elif rc == 3: + return "Plant" + elif rc == 4: + return "Insect" + elif rc == 5: + return "Mineral" + elif rc == 6: + return "-" + elif rc == 7: + return "SemiHuman" + elif rc == 8: + return "Angel" + elif rc == 9: + return "Dragon" + elif rc == 10: + return "Player" + elif rc == 11: + return "Boss" + elif rc == 12: + return "NonBoss" + elif rc == 14: + return "NonSemiHuman" + elif rc == 15: + return "NonPlayer" + elif rc == 16: + return "SemiPlayer" + elif rc == 17: + return "NonSemiPlayer" + else: + print("ERROR, INVALID RACE ID: %d (ID: %s)" % (rc, rac.id)) + exit(1) + +def WhatElem(rac): + rc=rac.elem + tl="ERROR" + cl="#F00" + if rc == 0: + tl,cl="Neutral","#000" + elif rc == 1: + tl,cl="Water","#00F" + elif rc == 2: + tl,cl="Earth","#7A0" + elif rc == 3: + tl,cl="Fire","#F00" + elif rc == 4: + tl,cl="Wind","#093" + elif rc == 5: + tl,cl="Nature","#040" + elif rc == 6: + tl,cl="Holy","#afa" + elif rc == 7: + tl,cl="Dark","#908" + elif rc == 8: + tl,cl="Ghost","#404" + elif rc == 9: + tl,cl="Undead","#440" + else: + print("ERROR, INVALID ELEM ID: %d (ID: %s)" % (rc, rac.id)) + exit(1) + Ele[rc]+=1 + return "<font color=%s>%s</font>" % (cl, tl) + +class Mob: + def __init__(self): + # Basic + self.id="0" + #self.aegis="UnknownMonster" # SpriteName is not used anywhere, we are using its ID + self.name="Unknown Monster Name" + self.view="1" + self.boss=False + self.plant=False + + # Defensive + self.mobpt="0" # Mob Points “Level” + self.hp="0" + self.xp="Exp: 0" + self.jp="JExp: 0" + self.st="" + self.dfn=0 + self.mdf=0 + + # Offensive + self.atk="[0, 0]" + self.range="1" + self.move="0" + self.delay="0" + self.drops=[] + + # New + self.race=-1 + self.elem=-1 + self.elel=-1 + self.walk="NORMAL" + + # Stats + self.str='0' + self.agi='0' + self.vit='0' + self.int='0' + self.dex='0' + self.luk='0' + +def MobAlloc(ab): + try: + maab=int(ab.mobpt) + except: + maab=9901 + + if maab <= 20 or skipCI: + Mobs1.append(ab) + elif maab <= 40: + Mobs2.append(ab) + elif maab <= 60: + Mobs3.append(ab) + elif maab <= 80: + Mobs4.append(ab) + elif maab <= 100: + Mobs5.append(ab) + elif maab <= 150: + Mobs6.append(ab) + else: + MobsA.append(ab) + + # Aeros allocation + """Plants=[] + Level50=[] + Level100=[] + Aggressive=[] + Assistant=[] + Looter=[] + Boss=[]""" + normie=True + if ab.plant: + Plants.append(ab.id) + normie=False + if ab.boss: + Boss.append(ab.id) + normie=False + if normie: + if "Agr" in ab.st: + Aggressive.append(ab.id) + normie=False + if "Lot" in ab.st: + Looter.append(ab.id) + normie=False + if "Ass" in ab.st: + Assistant.append(ab.id) + normie=False + if normie: + if maab <= 55: + Level50.append(ab.id) + else: + Level100.append(ab.id) + +def testMobs(): + print("Generating Elem-Mob Wiki...") + if len(sys.argv) >= 3: + src=open(sys.argv[2]+"/db/re/mob_db.conf", "r", encoding="utf-8") + else: + src=open("../../serverdata/db/re/mob_db.conf", "r", encoding="utf-8") + + wikib.write("<h1 id=#x>EleGen Monster Database</h1>\n") + start=False + dropper=False + skip=0 + x=Mob() # Only for pyflakes2 + + for a2 in src: + a=a2.replace(' ', '\t'); + if a == "{\n": + if skip: + skip=0 + if start: + MobAlloc(x) + else: + start=True + x=Mob() + + if skip: + start=False + x=Mob() + continue + if " Id:" in a: + x.id=stp(a) + if x.id == "ID": + continue + + if " Name:" in a: + x.name=stp(a) + elif " Hp:" in a: + x.hp=stp(a) + elif " Lv:" in a: + x.mobpt=stp(a) + elif " Exp:" in a: + x.xp=stp(a) + elif " JExp:" in a: + x.jp=stp(a) + elif " Attack:" in a: + x.atk=stp(a) + elif " AttackRange:" in a: + x.range=stp(a) + elif " MoveSpeed:" in a: + x.move=stp(a) + elif " ViewRange:" in a: + x.view=stp(a) + elif " AttackDelay:" in a: + x.delay=stp(a) + + elif " Def:" in a: + x.dfn=stp(a) + elif " Mdef:" in a: + x.mdf=stp(a) + + elif " Str:" in a: + x.str=stp(a) + elif " Agi:" in a: + x.agi=stp(a) + elif " Vit:" in a: + x.vit=stp(a) + elif " Int:" in a: + x.int=stp(a) + elif " Dex:" in a: + x.dex=stp(a) + elif " Luk:" in a: + x.luk=stp(a) + + + elif " Boss: true" in a: + x.boss=True + elif " Plant: true" in a: + x.plant=True + elif " Looter: true" in a: + x.st+="<font color=#790>Lot</font>," + elif " Assist: true" in a: + x.st+="<font color=#0a0>Ass</font>," + elif " Aggressive: true" in a: + x.st+="<font color=#f00>Agr</font>," + elif " WalkMask:" in a: + x.walk=stp(a) + elif " Element:" in a: + tmp=stp(a) + tmp2=tmp.split(',') + try: + x.elem=int(tmp2[0]) + x.elel=int(tmp2[1]) + except: + print("Invalid Element for mob %s: %s" % (x.id, tmp)) + exit(1) + elif " Race:" in a: + try: + x.race=int(stp(a)) + except: + print("Invalid Race for mob %s: %s" % (x.id, a)) + exit(1) + elif 'Drops: ' in a: + dropper=True + elif dropper and '}' in a: + dropper=False + elif dropper: + x.drops.append(stp(a).split(": ")) + elif "Plant: true" in a: + skip=1 + # Write last entry + MobAlloc(x) + + writeMob() + + wikib.write('\n\n|Mode|Desc|\n|----|----|\n') + wikib.write('|Lot|Looter|\n') + wikib.write('|Ass|Assist|\n') + wikib.write('|Agr|Aggressive|\n') + + src.close() + +def stp(x): + return x.replace('\n', '').replace('|', '').replace('(int, defaults to ', '').replace(')', '').replace('basic experience', '').replace('"','').replace(" ","").replace("\t","").replace('(string', '').replace('Name: ','').replace('Element: ','').replace('Race: ','').replace('AttackDelay: ', '').replace('WalkMask: ','').replace('MoveSpeed: ', '').replace('AttackRange: ', '').replace('ViewRange: ','').replace('Attack: ','').replace('ViewRange: ','').replace('Hp: ','').replace('Id: ','').replace('Lv: ','').replace('view range','').replace('attack range','').replace('move speed','').replace('health','').replace('(int','').replace('attack delay','atk.').replace('(','').replace(')','').replace('WALK_','').replace('Def: ','').replace('Mdef: ','') + + +def MonsterWrite(tbl): + global skipCI + # TODO: Check _mobs files to determine the usual monster density (a misc info to aid adding proper drop specs) + wikib.write("<table border=1>\n") + if stgen: + wikib.write("<tr><th>ID</th><th>Name</th><th>Mob Info</th><th>Stgen</th><th>Elegen</th><th>Misc Info</th><th>Rewards</th><th>Stats</th><th>Drops</th></tr>\n") + else: + wikib.write("<tr><th>ID</th><th>Name</th><th>Mob Info</th><th>Elegen</th><th>Misc Info</th><th>Rewards</th><th>Stats</th><th>Drops</th></tr>\n") + + if not skipCI: + tbl=sorted(tbl, key=lambda tbl: int(tbl.mobpt)) + + for i in tbl: + if i.id == 'ID': + continue + + # Special skips for REDESIGN + #if (int(i.id) < 1187): + # continue + if not bifs and ((int(i.hp) <= 50) or (i.race == 3)): + continue + + if i.boss: + i.name="<b>"+i.name+"</b>" + if stgen: + wikib.write('<tr><td><a name="' + i.id + '"></a>' + + i.id +"</td><td>"+ + i.name +"</td><td>"+ + mb_core(i) +"</td><td>"+ + mbdt('advise',mb_stgen(i)) +"</td><td>"+ + mb_eleg(i) +"</td><td>"+ + mbdt('misc', mb_rdmisc(i)) +"</td><td>"+ + mbdt('Exp\'s', mb_rdrw(i)) +"</td><td>"+ + mbdt('stats', mb_rdstat(i)) +"</td><td>"+ + mbdt('drops', mb_rddrop(i)) +"</td></tr>\n" + ) + else: + wikib.write('<tr><td><a name="' + i.id + '"></a>' + + i.id +"</td><td>"+ + i.name +"</td><td>"+ + mb_core(i) +"</td><td>"+ + mb_eleg(i) +"</td><td>"+ + mbdt('misc', mb_rdmisc(i)) +"</td><td>"+ + mbdt('Exp\'s', mb_rdrw(i)) +"</td><td>"+ + mbdt('stats', mb_rdstat(i)) +"</td><td>"+ + mbdt('drops', mb_rddrop(i)) +"</td></tr>\n" + ) + wikib.write("</table>\n") + wikib.write("<b>Total: %02d Monsters</b><br/>\n" % len(tbl)) + wikib.write("\n<a href=#x>(↑) Return to top</a><br/><br/>\n\n") + +def writeMob(): + wikib.write("<ul>\ +<li><a href=#0>Starter</a></li>\n\ +<li><a href=#1>Apprentice</a></li>\n\ +<li><a href=#2>Intermediary</a></li>\n\ +<li><a href=#3>Advanced</a></li>\n\ +<li><a href=#4>Expert</a></li>\n\ +<li><a href=#5>Master</a></li>\n\ +<li><a href=#Nan>OoS</a></li>\n\ +</ul> ") + + wikib.write("<h1 id=0>Lv 0-20</h1>\n\n") + MonsterWrite(Mobs1) + wikib.write("<h1 id=1>Lv 21-40</h1>\n\n") + MonsterWrite(Mobs2) + wikib.write("<h1 id=2>Lv 41-60</h1>\n\n") + MonsterWrite(Mobs3) + wikib.write("<h1 id=3>Lv 61-80</h1>\n\n") + MonsterWrite(Mobs4) + wikib.write("<h1 id=4>Lv 81-100</h1>\n\n") + MonsterWrite(Mobs5) + wikib.write("<h1 id=5>Lv 101-150</h1>\n\n") + MonsterWrite(Mobs6) + + wikib.write("<h1 id=NaN>Lv 101+</h1>\n\n") + MonsterWrite(MobsA) + + +def mbdt(summary, content): + return "<b>"+summary+"</b><br/><pre>"+content+"</pre>" + return "<details>\ +<summary>"+summary+"</summary>\ +<pre>"+content+"</pre></details>" + +def mb_core(mb): + buff="" + buff+="Lvl: %s<br/>\n" % (mb.mobpt) + buff+="HP: <b><font color=#0a0>%s</font></b><br/>\n" % (mb.hp) + buff+="ATK: <b><font color=#a00>%s</font></b><br/>\n" % (mb.atk) + buff+="DEF: <b><font color=#775>%s/%s</font></b><br/>\n" % (mb.dfn, mb.mdf) + if mb.st != "": + buff+="Modes: <i>%s</i>" % (mb.st) + return buff + +def mb_eleg(mb): + buff="" + buff+="Race: %s<br/>\n" % (WhatRace(mb)) + buff+="Walk: %s<br/>\n" % (fwalk(mb.walk)) + buff+="Element: %s<br/>\n" % (WhatElem(mb)) + return buff + +############################################################ +def mb_stgen(mb): + lv=int(mb.mobpt) + st=int(mb.str.replace(' ', '').replace('Str:','')) + #ag=int(mb.agi.replace(' ', '').replace('Agi:','')) + vi=int(mb.vit.replace(' ', '').replace('Vit:','')) + #it=int(mb.int.replace(' ', '').replace('Int:','')) + #dx=int(mb.dex.replace(' ', '').replace('Dex:','')) + #lk=int(mb.luk.replace(' ', '').replace('Luk:','')) + + # Attack Range vs Attack Delay + ar=int(mb.range) + ad=int(mb.delay) + mv=int(mb.move) + magr=False + mass=False + if ('Agr' in mb.st): + magr=True + if ('Ass' in mb.st): + mass=True + + if (not ar): + ar=1 + + # Fórmula do dano: + # Tal que level 10 cause 150 dano + # Tal que level 50 cause 1000 dano + # Tal que a fórmula seja exponencial + """ + lhp=lv**1.5+lv*(vi/100)+lv*15 + hhp=lv**1.8+lv*(vi/100)+lv*15 + # Casos especiais + if mb.boss: + lhp*=1.6 + hhp*=4.2 + if "slime" in mb.name.lower(): + lhp*=0.4 + hhp*=0.4 + if ar > 1: + lhp-=ar**2 + hhp-=ar**2 + + # Fórmula da HPTable: 400+(x*50) + # MASTERED + lat=(lv*40+lv**1.2+lv*(st/100))/ar + hat=(lv*40+lv**1.5+lv*(st/100))/ar + # Casos especiais + if mb.boss: + lat*=1.2 + hat*=1.4 + if "slime" in mb.name.lower(): + lat*=0.3 + hat*=0.3 + # Attack is DPS. So we must adjust to be a damage per second + lat*=(ad/1872) + hat*=(ad/1872) + # Formula is not reliable + lat/=2 + hat/=2 + # Consider Aggressive and Assist mobs + if magr: + lat*=0.8 + hat*=0.8 + if mass: + lat*=0.9 + hat*=0.9 + + # Experience + lxp=(lv**1.2+lat+(lhp/8)) / max(1,(12-(lv/10))) + hxp=(lv**1.6+hat+(hhp/8)) / max(1,(15-(lv/10))) + # Casos especiais + if mb.boss: + lxp*=4.2 + hxp*=4.7 + """ + + # Over100 Special Formula + OVER100=0 + if lv > 100: + OVER100=lv-100 + lv=100+OVER100*0.25 + + # Fórmula da HPTable: 400+(x*50) + # MASTERED + lat=(lv*40+lv**1.2+lv*(st/100)) + hat=(lv*40+lv**1.5+lv*(st/100)) + if (ar > 1): + lat*=max(0.5, 1.0-((ar-1)/10.0)) + hat*=max(0.5, 1.0-((ar-1)/10.0)) + + # Casos especiais + if mb.boss: + lat*=1.2 + hat*=1.4 + if "slime" in mb.name.lower(): + lat*=0.3 + hat*=0.3 + # Attack is DPS. So we must adjust to be a damage per second + lat*=(ad/1872) + hat*=(ad/1872) + # Formula is not reliable + lat*=0.55 + hat*=0.55 + lat*=max(0.5, 1.0-(lv/10.0)) + hat*=max(0.5, 1.0-(lv/10.0)) + # Consider Aggressive and Assist mobs + if magr: + lat*=0.78 + hat*=0.78 + if mass: + lat*=0.89 + hat*=0.89 + + + # Over100 Special Formula + if OVER100: + lv=100+OVER100*2 + + # HP: Each 10 levels give you 100 extra weapon damage + # I expect from 6 to 14 hits to kill + # You deliver in average two hits per second + # Mobs deliver one hit each four seconds (and that's 1hand advantage) + lhp=lv*20*6+lv*(vi/100) + hhp=lv*20*14+lv*(vi/100) + if mb.boss: + lhp*=1.4 + hhp*=1.8 + if "slime" in mb.name.lower(): + lhp*=0.6 + hhp*=0.6 + if ar > 1 and not OVER100: + lhp*=0.9 + hhp*=0.9 + + # Experience is way too non-linear and I prefer to do it with reference formula + # like I was doing before + # But let's use a formula based on mobs-to-lvl-up where you must kill 1580 lv 60 mobs + # to raise from lv 60 (you can kill lv 50 mobs easier - but then I expect 3700 kills) + # mobs to kill to raise level + + # This is the current mob-lvl-exp-table generated by this software + # As you see, it is somewhat similar to TMW Org. + # Remember aggressive, fast, and assistant mobs give even more exp + + # Level 1: total 1 mobs individual 3 xp (1.450) + # Level 2: total 3 mobs individual 5 xp (1.450) + # Level 3: total 8 mobs individual 5 xp (1.450) + # Level 4: total 16 mobs individual 4 xp (1.450) + # Level 5: total 26 mobs individual 7 xp (1.450) + # Level 6: total 39 mobs individual 8 xp (1.450) + # Level 7: total 56 mobs individual 9 xp (1.450) + # Level 8: total 77 mobs individual 9 xp (1.450) + # Level 9: total 101 mobs individual 10 xp (1.450) + # Level 10: total 129 mobs individual 11 xp (1.450) + # Level 20: total 667 mobs individual 21 xp (1.450) + # Level 30: total 1767 mobs individual 57 xp (1.450) + # Level 31: total 1912 mobs individual 63 xp (1.450) + # Level 32: total 2064 mobs individual 68 xp (1.450) + # Level 33: total 2223 mobs individual 73 xp (1.450) + # Level 34: total 2390 mobs individual 84 xp (1.450) + # Level 35: total 2563 mobs individual 91 xp (1.450) + # Level 36: total 2747 mobs individual 96 xp (1.455) + # Level 37: total 2942 mobs individual 101 xp (1.460) + # Level 38: total 3148 mobs individual 105 xp (1.465) + # Level 39: total 3366 mobs individual 130 xp (1.470) + # Level 40: total 3597 mobs individual 148 xp (1.475) + # Level 41: total 3841 mobs individual 156 xp (1.480) + # Level 42: total 4098 mobs individual 163 xp (1.485) + # Level 43: total 4369 mobs individual 170 xp (1.490) + # Level 44: total 4656 mobs individual 185 xp (1.495) + # Level 45: total 4958 mobs individual 193 xp (1.500) + # Level 46: total 5276 mobs individual 201 xp (1.505) + # Level 47: total 5611 mobs individual 208 xp (1.510) + # Level 48: total 5963 mobs individual 215 xp (1.515) + # Level 49: total 6334 mobs individual 249 xp (1.520) + # Level 50: total 6724 mobs individual 295 xp (1.525) + # Level 51: total 7133 mobs individual 314 xp (1.530) + # Level 52: total 7564 mobs individual 331 xp (1.535) + # Level 53: total 8016 mobs individual 348 xp (1.540) + # Level 54: total 8491 mobs individual 375 xp (1.545) + # Level 55: total 8990 mobs individual 393 xp (1.550) + # Level 56: total 9512 mobs individual 411 xp (1.555) + # Level 57: total 10061 mobs individual 428 xp (1.560) + # Level 58: total 10636 mobs individual 443 xp (1.565) + # Level 59: total 11239 mobs individual 514 xp (1.570) + # Level 60: total 11871 mobs individual 579 xp (1.575) + # Level 61: total 12533 mobs individual 608 xp (1.580) + # Level 62: total 13226 mobs individual 638 xp (1.585) + # Level 63: total 13952 mobs individual 670 xp (1.590) + # Level 64: total 14712 mobs individual 704 xp (1.595) + # Level 65: total 15508 mobs individual 740 xp (1.600) + # Level 66: total 16340 mobs individual 778 xp (1.605) + # Level 67: total 17211 mobs individual 818 xp (1.610) + # Level 68: total 18122 mobs individual 861 xp (1.615) + # Level 69: total 19075 mobs individual 905 xp (1.620) + # Level 70: total 20071 mobs individual 952 xp (1.625) + # Level 80: total 32389 mobs individual 1783 xp (1.650) + # Level 90: total 47806 mobs individual 3635 xp (1.650) + # Level 100: total 66308 mobs individual 4976 xp (1.650) + + # Over100 Special Formula + if OVER100: + lv=100+OVER100 + + try: + mxp=exp[lv] + hxp=exp[lv] + lxp=exp[lv-1] + minxp=exp[lv-1] + except: + mxp=exp[len(exp)-1] + hxp=exp[len(exp)-1] + lxp=exp[len(exp)-2] + minxp=exp[len(exp)-2] + print("Warning: Invalid exp for mob \033[1m%s\033[0m" % (mb.name.replace("<b>", "").replace("</b>", ""))) + + if not mb.boss: + if lv > 35: + fx=1.45+((lv-35)/200.0) + else: + fx=1.45 + if fx > 1.65: + fx=1.65 + + # Aggressive, assistant and fast mobs yield more exp + # Slow monsters yield less exp, because they're easier to kill on any playstyle + if magr: + fx-=0.09 + else: + fx-=0.04 + if mass: + fx-=0.08 + if mv < 200: + fx-=0.02 + if mv > 500: + fx+=0.02 + + # 1 ^ anything = 1, so we need a better rule + if lv != 1: + lxp=minxp/(lv**fx) + else: + lxp=3 # 3~5 is fine + # Boss are BOSS. It gives roughly 0.1% ~ 10.0% from lvlup xp. + else: + lxp=mxp/1000 + hxp=mxp/10 + del minxp, mxp + + # Over100 Special Formula (kinda) + olv=0 + if lv > 80: + olv=lv+0 + lv=80+(lv-80)*0.25 + + # Defense follows the same player formula + dfn=((lv**1.255)*2.5) + dfn=dfn*350.0/810.0 + mdf=max(0, lv-5)+(lv/10.0) + if not mb.boss: + mdf/=2 + if ar > 3: + dfn/=2 + + # Nerf mobs def in 50% (to be more realistic to what we have) + dfn/=2 + + # Over100 Special Formula + if OVER100: + lv=100+OVER100 + else: + lv=olv+0 + del olv + + # Force HP to be higher + # It'll only start applying from level 40 onwards + # It gives a bonus of 0.5% HP per mob level + # This means a level 100 mob got 60 times that stronger: 30% + if lv > 40: + lhp=lhp*(1.0+((lv-40)/210.0)) + lhp=int(lhp) + + # Norm + lhp=int(lhp) + hhp=int(hhp) + lat=int(lat) + hat=int(hat) + lxp=int(lxp) + hxp=int(hxp) + dfn=int(dfn) + mdf=int(mdf) + + buff="<pre><font size=-2px>" + buff+="HP Range: %s ~ %s<br/>\n" % (lhp, hhp) + buff+="ATK Range: %s ~ %s<br/>\n" % (lat, hat) + buff+="Maximum XP: %s ~ %s<br/>\n" % (lxp, hxp) + buff+="DEF: %s / %s<br/>\n" % (dfn, mdf) + buff+="<b>Drop, Move, Elegen, aspd<br/>\n" + buff+="</b></font></pre>" + return buff + +def mb_rdstat(mb): + buff="<pre><font size=-4px>" + buff+="%s\n" % (mb.str) + buff+="%s\n" % (mb.agi) + buff+="%s\n" % (mb.vit) + buff+="%s\n" % (mb.int) + buff+="%s\n" % (mb.dex) + buff+="%s\n" % (mb.luk) + buff+="</font></pre>" + return buff + +def mb_rdmisc(mb): + buff="" + if "agr" in mb.st.lower(): + buff+="View Range: %s\n" % (mb.view) + buff+="Attack Range: %s\n" % (mb.range) + buff+="AtkDelay: %s ms\n" % (mb.delay) + buff+="Move speed: %s ms\n" % (mb.move) + buff+="Element Level: %d\n" % (mb.elel) + return buff + +def mb_rdrw(mb): + buff="" + buff+="<font color=#060><u>%s</b></u></font>\n" % (mb.xp.replace(' ', ' <b>')) + buff+="<font color=#006><u>%s</b></u></font>\n" % (mb.jp.replace(' ', ' <b>')) + try: + buff+="MobPoints: %d\n" % (int(mb.mobpt)*11/10) + except: + pass + return buff + +def mb_rddrop(mb): + buff="" + tdr=0 + for ax in mb.drops: + # Ignore disabled drops + if ax[0].startswith("//"): + continue + + # Write drop + try: + buff+=ax[0]+': ' + str(int(ax[1])/100.0) + ' %\n' + tdr+=int(ax[1]) + except IndexError: + print("Fatal: invalid %s mob with %s drops" % (mb.name, str(ax))) + exit(1) + except: + print("[Warning] %s incorrect drop: %s" % (mb.name, str(ax))) + buff+=ax[0]+': ' + ax[1] + ' ppm\n' + + # Save to SysDrops + SysDrops.append([ax[0], ax[1], mb.name]) + + if tdr < 500: + print("[INFO] %s has %d/500 drops. Disqualified for Realm of Drops." % (mb.name, tdr)) + return buff + + + +showHeader() + +testMobs() + +wikib.write('<br/><hr/>') +wikib.write("Run at: " + datetime.datetime.now().isoformat()) +wikib.write('<hr/>') + +wikib.write(""" +<b>Player Stats (melee warrior)</b> +<table border=1> +<tr><th>Level</th><th>Stats 1</th><th>Stats 2</th><th>Average</th></tr> + +<tr><th>00</th> +<td>str: 2 agi: 5 vit: 7 int:1 dex: 6 luk: 3</td> +<td>str: 2 agi: 5 vit: 7 int:1 dex: 6 luk: 3</td> +<th>str: 2 agi: 5 vit: 7 int:1 dex: 6 luk: 3</th></tr> + +<tr><th>10</th> +<td>str:15 agi:10 vit: 5 int:1 dex:10 luk: 4</td> +<td>str:11 agi:11 vit: 6 int:1 dex:11 luk: 7</td> +<th>str:13 agi:11 vit: 5 int:1 dex:10 luk: 6</th></tr> + +<tr><th>20</th> +<td>str:19 agi:10 vit:10 int:1 dex:20 luk:10</td> +<td>str:14 agi:19 vit: 8 int:1 dex:17 luk:11</td> +<th>str:17 agi:14 vit: 9 int:1 dex:18 luk:11</th></tr> + +<tr><th>30</th> +<td>str:25 agi:30 vit:10 int:1 dex:20 luk:10</td> +<td>str:22 agi:28 vit:12 int:1 dex:21 luk:15</td> +<th>str:24 agi:29 vit:11 int:1 dex:20 luk:13</th></tr> + +<tr><th>40</th> +<td>str:38 agi:30 vit:20 int:1 dex:25 luk:17</td> +<td>str:28 agi:35 vit:14 int:1 dex:32 luk:21</td> +<th>str:33 agi:33 vit:17 int:1 dex:28 luk:19</th></tr> + +<tr><th>50</th> +<td>str:50 agi:40 vit:30 int:1 dex:25 luk:18</td> +<td>str:41 agi:41 vit:15 int:1 dex:41 luk:26</td> +<th>str:46 agi:41 vit:22 int:1 dex:33 luk:27</th></tr> + +<tr><th>60</th> +<td>str:54 agi:50 vit:40 int:1 dex:35 luk:20</td> +<td>str:52 agi:52 vit:16 int:1 dex:45 luk:32</td> +<th>str:53 agi:51 vit:28 int:1 dex:40 luk:26</th></tr> + +<tr><th>70</th> +<td>str:60 agi:60 vit:43 int:1 dex:50 luk:20</td> +<td>str:61 agi:61 vit:22 int:1 dex:51 luk:38</td> +<th>str:60 agi:61 vit:33 int:1 dex:50 luk:29</th></tr> + +<tr><th>80</th> +<td>str:80 agi:60 vit:50 int:1 dex:50 luk:25</td> +<td>str:65 agi:71 vit:32 int:1 dex:60 luk:41</td> +<th>str:72 agi:66 vit:41 int:1 dex:55 luk:33</th></tr> + +<tr><th>90</th> +<td>str:80 agi:70 vit:60 int:1 dex:60 luk:31</td> +<td>str:71 agi:71 vit:41 int:1 dex:71 luk:51</td> +<th>str:76 agi:70 vit:50 int:1 dex:66 luk:41</th></tr> + +<tr><th>100</th> +<td>str:90 agi:80 vit:69 int:1 dex:60 luk:31</td> +<td>str:71 agi:81 vit:42 int:1 dex:81 luk:61</td> +<th>str:81 agi:80 vit:56 int:1 dex:70 luk:46</th></tr> + +<tr><th>110</th> +<td>str:90 agi:90 vit:69 int:1 dex:70 luk:35</td> +<td>str:82 agi:82 vit:50 int:1 dex:82 luk:65</td> +<th>str:86 agi:86 vit:60 int:1 dex:76 luk:50</th></tr> + +<tr><th>120</th> +<td>str:99 agi:90 vit:69 int:1 dex:70 luk:45</td> +<td>str:86 agi:86 vit:51 int:1 dex:86 luk:68</td> +<th>str:93 agi:88 vit:60 int:1 dex:78 luk:56</th></tr> + +<tr><th>130</th> +<td>str:99 agi:91 vit:75 int:1 dex:70 luk:55</td> +<td>str:91 agi:90 vit:51 int:1 dex:90 luk:68</td> +<th>str:95 agi:91 vit:63 int:1 dex:80 luk:61</th></tr> + +</table> +""") +wikib.write('<hr/>') +wikib.write(""" +<h3>Elemental Count</h3> +<table border=1> +<tr><td>%s</td><td>%02d</td></tr> +<tr><td>%s</td><td>%02d</td></tr> +<tr><td>%s</td><td>%02d</td></tr> +<tr><td>%s</td><td>%02d</td></tr> +<tr><td>%s</td><td>%02d</td></tr> +<tr><td>%s</td><td>%02d</td></tr> +<tr><td>%s</td><td>%02d</td></tr> +<tr><td>%s</td><td>%02d</td></tr> +<tr><td>%s</td><td>%02d</td></tr> +</table> +""" % ( +"Neutral", Ele[0], +"Water", Ele[1], +"Earth", Ele[2], +"Fire", Ele[3], +"Wind", Ele[4], +"Holy", Ele[6], +"Dark", Ele[7], +"Ghost", Ele[8], +"Error", Ele[5])) + +wikib.write('</body></html>') +wikib.close() +#print(str(SysDrops)) + +# Aeros allocation +if aeros: + print("// These arrays are filled automatically by redesign.py"); + print("setarray .ML_Plants, "+ + str(Plants).replace('[','').replace(']','').replace("'","")+";") + print("setarray .ML_Boss, "+ + str(Boss).replace('[','').replace(']','').replace("'","")+";") + print("setarray .ML_Aggr, "+ + str(Aggressive).replace('[','').replace(']','').replace("'","")+";") + print("setarray .ML_Asst, "+ + str(Assistant).replace('[','').replace(']','').replace("'","")+";") + print("setarray .ML_Loot, "+ + str(Looter).replace('[','').replace(']','').replace("'","")+";") + print("setarray .ML_Lv50, "+ + str(Level50).replace('[','').replace(']','').replace("'","").replace('ID, ','')+ + ";") + print("setarray .ML_Lv99, "+ + str(Level100).replace('[','').replace(']','').replace("'","")+";") + +showFooter() +exit(0) diff --git a/wiki/sedesign.py b/wiki/sedesign.py new file mode 100755 index 0000000..26d956b --- /dev/null +++ b/wiki/sedesign.py @@ -0,0 +1,515 @@ +#! /usr/bin/env python3 +# -*- coding: utf8 -*- +# +# Copyright (C) 2010-2011 Evol Online +# Copyright (C) 2018 TMW-2 +# Author: Andrei Karas (4144) +# Author: Jesusalva + +import datetime +import sys + +stgen=True + +wikia=open("EleItems.html", "w") + +# the TYPEs we use to determine where to pack things +IT_ARMOR={ 'MISC': [], # FOR FAILURE + 'EQP_ACC_L': [], # ACCESSORY LEFT + 'EQP_ACC_R': [], # ACCESSORT RIGHT + 'EQP_HEAD_MID': [], # CHEST + 'EQP_SHOES': [], # FEET + 'EQP_GARMENT': [], # GLOVES + 'EQP_HEAD_LOW':[], # PANTS + '1024': [], # NECKLACES (should be EQP_COSTUME_HEAD_TOP instead of number) + '2048': [], # RINGS (should be EQP_COSTUME_HEAD_MID instead of number) + 'EQP_MOUNT':[], # MOUNTS (ie. EQP_SHADOW_SHOES) + 'EQP_HEAD_TOP':[], # HATS/HELMETS + 'EQP_HAND_L': []} # SHIELDS +IT_WEAPON={ 'RANGED': [], # RANGED WEAPONS + 'MAGICAL':[], # MAGICAL WEAPONS + 'HAND_2':[], # TWO HAND (LR) + 'HAND_1':[]} # WEAPONS (R) + +def printSeparator(): + print("--------------------------------------------------------------------------------") + +def showHeader(): + print("TMW2 EleItems Generator") + print("Run at: " + datetime.datetime.now().isoformat()) + print("Usage: ./sedesign.py [info|level|none] [<path_to_serverdata>]") + print("SeDesign determines the reference defense for every item.") + print("Tweak as needed. Bonuses/Rarity/etc not taken in account.") + print("Running this without Redesign (or vice versa) will break balance") + printSeparator() + print("Output is: EleItems.html") + +def showFooter(): + #pass + #printSeparator() + print("Done.") + + + + + + + +class It: + def __init__(self): + # Basic + self.id="0" + self.aegis="UnknownItem" + self.name="Unknown Item Name" + self.price="0" # Sell price, of course + self.weight="0" + self.type="IT_ETC" # default type + self.loc="" + self.fc=0.0 + + # Offensive/Defensive + self.atk="0" + self.matk="0" + self.range="0" + self.defs="0" + + # Restrictions (EquipLv) + self.lvl="0" + self.drop=True + self.trade=True + self.sell=True + self.store=True + + # Special settings + self.rare=False # DropAnnounce + self.script="" + + # Visual + self.sl="0" # Slots + self.ac=False # Allow Cards + +def ItAlloc(it): + if (it.sl == "0" and it.ac) or (it.sl in ["1","2","3","4"] and not it.ac): + print("WARNING, item id "+it.id+" invalid dye/card setting!") + if (len(it.sl) > 1 and it.id != "ID(int"): + print("WARNING, item id "+it.id+" bad slots length: %d (%s)" % (len(it.sl), it.sl)) + + a=it.type + if "IT_ARMOR" in a: + if 'EQP_ACC_L' in it.loc: + IT_ARMOR['EQP_ACC_L'].append(it) + it.fc=0.00 + elif 'EQP_ACC_R' in it.loc: + IT_ARMOR['EQP_ACC_R'].append(it) + it.fc=0.00 + elif 'EQP_HEAD_MID' in it.loc: + IT_ARMOR['EQP_HEAD_MID'].append(it) + if ("bSpeedAddRate, -" in it.script or "bSpeedAddRate,-" in it.script): + it.fc=0.40 + else: + it.fc=0.30 + elif 'EQP_SHOES' in it.loc: + IT_ARMOR['EQP_SHOES'].append(it) + it.fc=0.08 + elif 'EQP_GARMENT' in it.loc: + IT_ARMOR['EQP_GARMENT'].append(it) + it.fc=0.07 + elif 'EQP_HEAD_LOW' in it.loc: + IT_ARMOR['EQP_HEAD_LOW'].append(it) + it.fc=0.10 + elif 'EQP_HEAD_TOP' in it.loc: + IT_ARMOR['EQP_HEAD_TOP'].append(it) + if ("bSpeedAddRate, -" in it.script or "bSpeedAddRate,-" in it.script): + it.fc=0.15 + else: + it.fc=0.10 + elif 'EQP_HAND_L' in it.loc: + IT_ARMOR['EQP_HAND_L'].append(it) + it.fc=0.25 + elif '1024' in it.loc: + IT_ARMOR['1024'].append(it) + it.fc=0.00 + elif '2048' in it.loc: + IT_ARMOR['2048'].append(it) + it.fc=0.00 + elif 'EQP_SHADOW_SHOES' in it.loc: + IT_ARMOR['EQP_MOUNT'].append(it) + it.fc=0.00 + elif 'EQP_SHADOW_ACC_R' in it.loc: + IT_ARMOR['EQP_ACC_R'].append(it) # Not really + it.fc=0.00 + else: + raise Exception("Invalid Loc for ID %s: %s" % (it.id, it.loc)) + elif "IT_WEAPON" in a: + if int(it.matk) > 0: + IT_WEAPON["MAGICAL"].append(it) + elif int(it.range) > 2: + IT_WEAPON["RANGED"].append(it) + elif "HAND_L" in it.loc or "EQP_ARMS" in it.loc: + IT_WEAPON["HAND_2"].append(it) + elif "HAND_R" in it.loc: + IT_WEAPON["HAND_1"].append(it) + else: + raise Exception("Invalid location for weapon: %s" % it.loc) + +def newItemDB(): + print("\nGenerating Item Wiki...") + if len(sys.argv) >= 3: + src=open(sys.argv[2]+"/db/re/item_db.conf", "r", encoding="utf-8") + else: + src=open("../../server-data/db/re/item_db.conf", "r", encoding="utf-8") + + lg=False + x=It() + for a2 in src: + a=a2.replace(' ', '\t'); + if a == "{\n": + ItAlloc(x) + x=It() + + # sti() block + if " Id:" in a: + x.id=sti(a) + elif " AegisName:" in a: + x.aegis=sti(a) + elif " Name:" in a: + x.name=stin(a) + elif " Sell:" in a: + x.price=sti(a) + elif " Weight:" in a: + x.weight=sti(a) + elif " Type:" in a: + x.type=sti(a) + elif " Loc:" in a: + x.loc=sti(a) + elif " Atk:" in a: + x.atk=sti(a) + elif " Matk:" in a: + x.matk=sti(a) + elif " Range:" in a: + x.range=sti(a) + elif " Def:" in a: + x.defs=sti(a) + elif " EquipLv:" in a: + x.lvl=sti(a) + elif " Slots:" in a: + x.sl=sti(a) + elif " AllowCards:" in a: + x.ac=True + # Write booleans + elif "DropAnnounce: true" in a: + x.rare=True + elif "nodrop: true" in a: + x.drop=False + elif "notrade: true" in a: + x.trade=False + elif "noselltonpc: true" in a: + x.sell=False + elif "nostorage: true" in a: + x.store=False + elif "Script" in a: + lg=True + x.script+="<pre>" + elif lg and "\">" in a: + lg=False + x.script+="</pre>" + elif lg: + if not "announce" in a and not "debugmes" in a and not "logmes" in a: + x.script+=str(a.replace('\t', '').replace('getiteminfo(getequipid(', 'iteminfo((').replace('Flee2','Block')) + + # Write last entry + ItAlloc(x) + writeItems() + + src.close() + +def sti(x): + return x.replace('\n', '').replace('|', '').replace(')', '').replace('Id: ', '').replace('"','').replace(" ","").replace("\t","").replace('AegisName: ', '').replace('Name: ','').replace('Sell: ', '').replace('Weight: ', '').replace('Type: ', '').replace('Loc: ', '').replace('Atk: ', '').replace('Matk: ', '').replace('Range: ', '').replace('Def: ', '').replace('EquipLv: ', '').replace('Slots: ','').replace(" ", "").replace('@min=','').replace('@max=','').replace('@delay=','').replace(';','') + +def stin(x): + return x.replace('\n', '').replace('|', '').replace(')', '').replace('Id: ', '').replace('"','').replace(" ","").replace("\t","").replace('Name: ','').replace(';','') + + +def writeItems(): + wikia.write("<h1>Armors</h1>\n\ +<ul>\ +<li><a href=#armors>Armors</a></li>\n\ +<li><a href=#left-accessory>Left Accessory</a></li>\n\ +<li><a href=#right-accessory>Right Accessory</a></li>\n\ +<li><a href=#headgear>Headgear</a></li>\n\ +<li><a href=#chest>Chest</a></li>\n\ +<li><a href=#pants>Pants</a></li>\n\ +<li><a href=#shoes>Shoes</a></li>\n\ +<li><a href=#necklaces>Necklaces</a></li>\n\ +<li><a href=#rings>Rings</a></li>\n\ +<li><a href=#gloves>Gloves</a></li>\n\ +<li><a href=#shields>Shields</a></li>\n\ +</ul>\n\n") + wikia.write("<u>Restrictions Reference</u><br/>\n") + wikia.write("<ul>\n\ +<li> * - Rare item with drop announce.</li>\n\ +<li> (dp) - This item cannot be dropped.</li>\n\ +<li> (tr) - This item cannot de traded.</li>\n\ +<li> (sl) - This item cannot be sold.</li>\n\ +<li> (gg) - This item cannot go to storage.</li>\n\ +</ul><br/>\n") + + #################################################################### + wikia.write("<h2>Armors</h2>\n") + + ArmorWrite("Left Accessory",'EQP_ACC_L') + ArmorWrite("Right Accessory",'EQP_ACC_R') + ArmorWrite("Headgear",'EQP_HEAD_TOP') + ArmorWrite("Chest",'EQP_HEAD_MID') + ArmorWrite("Pants",'EQP_HEAD_LOW') + ArmorWrite("Shoes",'EQP_SHOES') + ArmorWrite("Necklaces",'1024') + ArmorWrite("Rings",'2048') + ArmorWrite("Gloves",'EQP_GARMENT') + ArmorWrite("Shields",'EQP_HAND_L') + #for i in sorted(IT_ARMOR['EQP_HEAD_TOP'], key=lambda xcv: int(xcv.lvl)): + # # Name | Level | Location | Specification + # print("`%s`|%d| :grey_question: | " % (i.name, int(i.lvl))) + + #################################################################### + wikia.write("<hr/><h2>Weapons</h2>\n") + + # 1 Hand Items + wikia.write("<h3>1H Weapons</h3>\n") + ItemWrite(IT_WEAPON['HAND_1'], ID=True, AEGIS=True, PRICE=True, WEIGHT=True, ATK=True, LVL=True) + + # 2 Hand Items + wikia.write("<h3>2H Weapons</h3>\n") + ItemWrite(IT_WEAPON['HAND_2'], ID=True, AEGIS=True, PRICE=True, WEIGHT=True, ATK=True, LVL=True, RANGE=True) + + # Ranged Items + wikia.write("<h3>Ranged Weapons</h3>\n") + ItemWrite(IT_WEAPON['RANGED'], ID=True, AEGIS=True, PRICE=True, WEIGHT=True, ATK=True, LVL=True, RANGE=True) + + # Magic Items + wikia.write("<h3>Magical Weapons</h3>\n") + ItemWrite(IT_WEAPON['MAGICAL'], ID=True, AEGIS=True, PRICE=True, WEIGHT=True, ATK=True, MATK=True, LVL=True, RANGE=True) + +# Write AegisName with restrictions +def hl(it): + buff="" + if it.rare: + buff+="*" + buff+=it.aegis + buff+=" " + if not it.drop: + buff+="<a href='#restrictions-reference'>(dp)</a>" + if not it.trade: + buff+="<a href='#restrictions-reference'>(tr)</a>" + if not it.sell: + buff+="<a href='#restrictions-reference'>(sl)</a>" + if not it.store: + buff+="<a href='#restrictions-reference'>(gg)</a>" + return buff + +# wikia.write("Id|Aegis|Name|Weight|Atk|Matk|\n") +# wikia.write("Id|Aegis|Name|Price|Weight|\n") + +def ItemWrite(tbl, ID=False, AEGIS=False, NAME=False, PRICE=False, WEIGHT=False, DEF=False, LVL=False, ATK=False, MATK=False, RANGE=False, HEALING=False, SCRIPT=False, DROPPER=False): + global stgen + wikia.write("<table border=1>\n") + wikia.write("<tr>") + if ID: + wikia.write("<th>ID</th>") + if AEGIS: + wikia.write("<th>Aegis</th>") + if NAME: + wikia.write("<th>Name</th>") + if PRICE: + wikia.write("<th>Price</th>") + if WEIGHT: + wikia.write("<th>Weight</th>") + if DEF: + wikia.write("<th>Def</th>") + if stgen: + wikia.write("<th>Adj.Def</th>") + if LVL: + wikia.write("<th>Lvl</th>") + if ATK: + wikia.write("<th>Atk</th>") + if MATK: + wikia.write("<th>Matk</th>") + if ATK and MATK: + wikia.write("<th>+</th>") + if ATK or MATK: + if stgen: + wikia.write("<th>Adj. Atk.</th>") + if RANGE: + wikia.write("<th>Range</th>") + if HEALING: + wikia.write("<th>Min</th>") + wikia.write("<th>Max</th>") + wikia.write("<th>Delay</th>") + if SCRIPT: + wikia.write("<th>Script</th>") + if DROPPER: + wikia.write("<th>Mobs</th>") + + wikia.write("</tr>\n") + + try: + if (sys.argv[1] in ["level", "info"]): + sort=sorted(tbl, key=lambda xcv: int(xcv.lvl)) + elif (sys.argv[1] == "none"): + sort=tbl + else: + print("Syntax: ./sedesign.py [info|level|none]") + sort=tbl + + if (sys.argv[1] == "info"): + stgen=False + except: + sort=tbl + + for i in sort: + wikia.write('<tr>') + + if ID: + wikia.write("<td><a name=\"%s\"></a>%s</td>" % (i.id,i.id)) + if AEGIS: + wikia.write("<td>%s</td>" % hl(i)) + if NAME: + wikia.write("<td>%s</td>" % i.name) + if PRICE: + wikia.write("<td>%s GP</td>" % i.price) + if WEIGHT: + wikia.write("<td>%s g</td>" % i.weight) + if DEF: + wikia.write("<td>Def: %s</td>" % i.defs) + if stgen: + lv=int(i.lvl) + + bb=(lv**1.255)*2.5*i.fc + hc=bb*350.0/810.0 # Hercules value: Capped at 350 + + # Magic penalty + if ("bMatk," in i.script): + hc=hc/2.0 + + # Precise rounding + if (hc % 1 >= 0.5): + hc+=1 + wikia.write("<td>Adj. Df: %d</td>" % int(hc)) + if LVL: + wikia.write("<td>Lv: %s</td>" % i.lvl) + if ATK: + wikia.write("<td>Atk: %s</td>" % i.atk) + if MATK: + wikia.write("<td>%s</td>" % i.matk) + if ATK and MATK: + try: + tmpatmat=i.atk.replace("Atk: ", "") + #print("`%s`+`%s`=?" % (tmpatmat, i.matk)) + wikia.write("<td><i>%s</i></td>" % str(int(i.matk)+int(tmpatmat))) + except: + wikia.write("<td><i>?</i></td>") + if ATK or MATK: + if stgen: + lv=int(i.lvl) + at=int(i.atk) + fc=7.5 + ## Two hand swords are stronger + if i in IT_WEAPON['HAND_2']: + fc+=0.62 + ## Calculate guns + if int(i.id) == 6010 or int(i.id) == 6050: + lv+=20 + if int(i.id) == 6020: + lv=0 + if int(i.id) == 6040: + fc/=2.5 + + ## Progression + if int(i.matk) <= 0 or int(at) > 0: + fc-=1.0 + fc+=((100-lv)/100.0) + + ## Even slower progression (note bows doesn't gets the 0.8 2hand bonus) + if not i in IT_WEAPON['RANGED']: + fc-=(lv/15.0)/10.0 + + ## After level 50 weapons progression is slowed down + if lv > 45: + fc-=(lv-45)/90.0 + + ## This is because mob HP scaling is buggy + if lv > 45 and not i in IT_WEAPON['RANGED']: + fc-=(lv-45)/100.0 + + ## Magic Weapons adjustment + if int(i.matk) > 0: + fc+=0.0 + + ## Physical and Magic Weapons adjustment + if int(i.matk) > 0 and int(at) > 0: + fc=7.0+((100-lv)/100.0) + + ## HAT is for craft or rare items. + lat=lv*fc + hat=lv*(fc+max(0.01, 1.0-(lv/100.0))) + + # Edge Cases + ## Don't recalculate noob weapon + if lv <= 20: + lat=hat=at + + wikia.write("<th>%d ~ %d <i>(%.2f)</i></th>" % (lat, hat, fc)) + if RANGE: + wikia.write("<td>%s</td>" % i.range) + if HEALING: + wikia.write("<td>%s</td>" % i.minheal) + wikia.write("<td>%s</td>" % i.maxheal) + wikia.write("<td>%s s</td>" % i.delheal) + if SCRIPT: + wikia.write("<td>%s</td>" % i.script) + if DROPPER: + wikia.write("<td>-</td>") + + wikia.write("</tr>") + + wikia.write("</table><br/>\n") + wikia.write("\n<br/><a href=#items>(↑) Return to top</a><Br/><br/>\n\n") + +def ArmorWrite(name,scope): + wikia.write("<h3>"+name+"</h3>\n") + ItemWrite(IT_ARMOR[scope], ID=True, AEGIS=True, PRICE=True, WEIGHT=True, DEF=True, LVL=True, SCRIPT=True) + + + + + + + + + + + +showHeader() + +wikia.write("<html><head>") +wikia.write('<title>SeDesign</title><meta charset=utf8 />\n') +wikia.write("<body>") +newItemDB() + +# Ending +wikia.write("<hr/>") +wikia.write("Run at: " + datetime.datetime.now().isoformat()) +wikia.write("</body></html>") +wikia.close() + +# Print for reference the landmarks +i=0 +while i < 100: + i+=10 + bb=(i**1.255)*2.5 + hc=bb*350.0/810.0 # Hercules value: Capped at 350 + df=(100.0 - hc / (hc + 400.0) * 90.0) / 100.0 * 100 + print("%d Level %d Defense (%.2f%% DMG)" % (i, hc, df) ); + +showFooter() +exit(0) diff --git a/wiki/tmp-arm b/wiki/tmp-arm new file mode 100644 index 0000000..53e733e --- /dev/null +++ b/wiki/tmp-arm @@ -0,0 +1,247 @@ +"791": 0, +"1151": 4, +"1152": 8, +"1153": 5, +"1155": 0, +"1156": 5, +"1159": 2, +"1161": 2, +"1162": 2, +"1163": 2, +"1164": 8, +"1165": 3, +"1169": 5, +"1170": 5, +"1171": 5, +"1178": 10, +"3200": 2, +"3201": 2, +"3202": 0, +"3203": 0, +"3204": 1, +"3205": 4, +"3206": 0, +"3207": 0, +"3210": 1, +"2900": 1, +"2901": 0, +"2902": 1, +"2903": 3, +"2904": 3, +"2905": 3, +"2906": 9, +"2907": 9, +"2908": 3, +"2909": 5, +"2910": 3, +"2911": 3, +"2913": 3, +"2914": 4, +"2915": 5, +"2916": 4, +"2917": 2, +"2918": 2, +"2919": 6, +"2920": 6, +"2921": 4, +"2923": 1, +"2924": 0, +"2926": 0, +"2927": 9, +"2928": 3, +"2929": 9, +"2930": 1, +"2932": 6, +"2934": 0, +"2935": 0, +"2936": 1, +"2937": 4, +"2938": 0, +"2939": 0, +"2940": 4, +"2941": 7, +"2942": 8, +"2943": 6, +"2944": 4, +"2945": 3, +"2946": 1, +"2983": 1, +"2985": 2, +"2986": 2, +"2987": 3, +"2989": 0, +"2990": 0, +"2991": 2, +"2992": 1, +"2993": 2, +"2994": 2, +"2995": 3, +"2996": 15, +"2997": 3, +"2998": 4, +"2999": 5, +"3000": 2, +"3001": 5, +"3002": 3, +"3003": 5, +"3004": 8, +"3005": 8, +"3006": 1, +"3007": 6, +"3008": 7, +"3010": 3, +"3011": 2, +"3012": 5, +"3013": 3, +"3014": 1, +"3015": 2, +"3017": 2, +"3018": 6, +"3019": 4, +"3020": 7, +"3021": 0, +"3022": 1, +"3023": 3, +"3024": 3, +"3028": 3, +"3029": 3, +"3030": 10, +"1300": 0, +"1301": 4, +"1302": 0, +"1303": 2, +"1304": 3, +"1305": 5, +"1306": 7, +"1307": 7, +"1308": 5, +"1309": 0, +"1310": 4, +"1311": 8, +"1312": 6, +"1313": 0, +"1314": 2, +"1315": 1, +"1316": 2, +"1317": 5, +"1318": 4, +"1319": 1, +"1320": 3, +"1321": 0, +"1323": 8, +"1324": 3, +"1325": 0, +"1326": 0, +"1327": 0, +"1328": 6, +"1329": 7, +"1330": 0, +"1331": 10, +"1332": 1, +"1333": 8, +"1334": 3, +"1335": 0, +"1336": 6, +"1337": 7, +"1338": 2, +"1339": 5, +"2200": 0, +"2201": 3, +"2202": 8, +"2203": 7, +"2204": 5, +"2205": 1, +"2206": 1, +"2207": 3, +"2208": 5, +"2209": 1, +"2210": 8, +"2211": 6, +"2212": 2, +"2213": 4, +"2214": 4, +"2215": 7, +"2216": 10, +"2217": 0, +"2218": 2, +"2219": 2, +"2220": 3, +"1800": 1, +"1801": 8, +"1802": 5, +"1803": 0, +"1804": 3, +"1805": 2, +"1806": 2, +"1807": 3, +"1808": 4, +"1809": 5, +"1810": 6, +"1811": 9, +"1812": 7, +"1813": 8, +"1814": 7, +"1815": 10, +"1816": 0, +"1817": 1, +"1818": 2, +"1819": 3, +"1000": 4, +"1001": 5, +"1002": 4, +"1003": 4, +"1004": 4, +"1005": 6, +"1007": 4, +"1008": 6, +"1009": 8, +"1010": 7, +"1012": 2, +"1013": 2, +"1014": 4, +"1015": 5, +"1016": 5, +"1017": 5, +"1019": 5, +"2500": 0, +"2501": 4, +"2510": 0, +"2511": 0, +"2512": 2, +"2000": 3, +"2001": 5, +"2002": 7, +"2003": 9, +"2004": 0, +"2005": 1, +"2006": 2, +"2007": 2, +"2008": 4, +"2009": 5, +"2010": 6, +"2011": 9, +"2012": 9, +"2013": 7, +"2014": 7, +"2015": 8, +"2016": 0, +"2700": 0, +"2701": 1, +"2702": 3, +"2703": 7, +"2704": 5, +"2705": 10, +"2706": 6, +"2707": 0, +"2708": 6, +"2709": 4, +"2710": 2, +"2711": 8, +"2712": 9, +"2713": 1, +"2714": 2, +"2715": 2, +"2716": 3, +"2717": 3, +"2718": 4, +"2719": 4, diff --git a/wiki/tmp-dec b/wiki/tmp-dec new file mode 100644 index 0000000..8337ac2 --- /dev/null +++ b/wiki/tmp-dec @@ -0,0 +1,8 @@ +"3208": BurglarMask, +"3209": BanditMask, +"3211": AutumnMask, +"2922": YetiMask, +"2925": OperaMask, +"2931": SkullMask, +"3009": FafiMask, +"3016": TerraniteMask, diff --git a/wiki/tmp-etc b/wiki/tmp-etc new file mode 100644 index 0000000..5e1d879 --- /dev/null +++ b/wiki/tmp-etc @@ -0,0 +1,25 @@ +Armor: + "1150": FourLeafClover, + "1154": Doll, + "1157": LeatherBall, + "1158": ZarkorScroll, + "1160": PlushMouboo, + "1166": Blanket, + "1167": EarthScroll, + "1168": CursedSkull, + "1172": LeatherQuiver, + "1173": IronQuiver, + "1174": BronzeQuiver, + "1175": PlatinumQuiver, + "1176": DragonStar, + "1177": MichelSoul, + "1179": RubberDucky, + "1006": LifestonePendant, + "1011": 1, + "1020": 2, + "1021": 1, + "2508": 2, + "2509": 3, + "2720": 0 + + diff --git a/wiki/tmp-wpn b/wiki/tmp-wpn new file mode 100644 index 0000000..f86e7b4 --- /dev/null +++ b/wiki/tmp-wpn @@ -0,0 +1,59 @@ +"3500": 0, +"3501": 2, +"3502": 3, +"3503": 2, +"3504": 4, +"3505": 1, +"3506": 0, +"3507": 1, +"3508": 7, +"3509": 9, +"3510": 0, +"3511": 10, +"3512": 3, +"3513": 8, +"3514": 3, +"3515": 6, +"3516": 8, +"3518": 2, +"3519": 6, +"3520": 2, +"3527": 5, +"3528": 3, +"3529": 1, +"3531": 6, +"3536": 6, +"3538": 6, +"3539": 6, +"3600": 99, +"6040": 6, +"3517": 4, +"3521": 2, +"3522": 6, +"3523": 4, +"3524": 5, +"3525": 6, +"3526": 7, +"3530": 7, +"3532": 9, +"3533": 7, +"3534": 8, +"3537": 6, +"3601": 99, +"3602": 99, +"3603": 99, +"6000": 0, +"6001": 1, +"6002": 2, +"6003": 4, +"6004": 6, +"6005": 8, +"6006": 10, +"6010": 6, +"6030": 6, +"6050": 7, +"7020": 6, +"7400": 4, +"7401": 5, +"7421": 10, +"3604": 99, diff --git a/wiki/webwikigen.py b/wiki/webwikigen.py new file mode 100755 index 0000000..51a8d7a --- /dev/null +++ b/wiki/webwikigen.py @@ -0,0 +1,758 @@ +#! /usr/bin/env python3 +# -*- coding: utf8 -*- +# +# Copyright (C) 2010-2011 Evol Online +# Copyright (C) 2018 TMW-2 +# Author: Andrei Karas (4144) +# Author: Jesusalva + +import datetime + +wikia=open("Items.md", "w") +wikib=open("Monsters.md", "w") +wikic=open("../../client-data/x.diff", "w") + +# the TYPEs we use to determine where to pack things +IT_HEALING=[] +IT_ETC=[] +IT_USABLE=[] +IT_AMMO=[] +IT_CARD=[] +IT_PETEGG=[] +IT_WEAPON={ 'HAND_2': [], # TWO HAND (LR) + 'HAND_1':[]} # WEAPONS (R) +IT_ARMOR={ 'MISC': [], # FOR FAILURE + 'EQP_ACC_L': [], # ACCESSORY LEFT + 'EQP_ACC_R': [], # ACCESSORT RIGHT + 'EQP_HEAD_MID': [], # CHEST + 'EQP_SHOES': [], # FEET + 'EQP_GARMENT': [], # GLOVES + 'EQP_HEAD_LOW':[], # PANTS + '1024': [], # NECKLACES (should be EQP_COSTUME_HEAD_TOP instead of number) + '2048': [], # RINGS (should be EQP_COSTUME_HEAD_MID instead of number) + 'EQP_HEAD_TOP':[], # HATS/HELMETS + 'EQP_HAND_L': []} # SHIELDS + +Mobs1=[] +Mobs2=[] +Mobs3=[] +Mobs4=[] +Mobs5=[] +MobsA=[] + +SysDrops=[] + + +def printSeparator(): + print("--------------------------------------------------------------------------------") + +def showHeader(): + print("TMW2 Wiki Generator") + ##print "Evol client data validator." + print("Run at: " + datetime.datetime.now().isoformat()) + ##print "https://gitlab.com/evol/evol-tools/blob/master/testxml/testxml.py" + printSeparator() + +def showFooter(): + #pass + #printSeparator() + print("Done.") + + + + + +def fwalk(wmask): + if wmask == 'WATER': + return '<font color=#00f>%s</font>' % (wmask) + elif wmask == 'AIR': + return '<font color=#093>%s</font>' % (wmask) + elif wmask == 'WALL': + return '<font color=#f00>%s</font>' % (wmask) + elif wmask == 'NORMAL' or wmask == 'DEFAULT': + return '<font color=#111>%s</font>' % (wmask) + else: + print("Invalid walk mask: "+wmask) + exit(1) + +def WhatRace(rac): + rc=rac.race + if rc == 0: + return "Formless" + elif rc == 1: + return "Undead" + elif rc == 2: + return "Brute" + elif rc == 3: + return "Plant" + elif rc == 4: + return "Insect" + elif rc == 5: + return "Fish" + elif rc == 6: + return "-" + elif rc == 7: + return "SemiHuman" + elif rc == 8: + return "Angel" + elif rc == 9: + return "Dragon" + elif rc == 10: + return "Player" + elif rc == 11: + return "Boss" + elif rc == 12: + return "NonBoss" + elif rc == 14: + return "NonSemiHuman" + elif rc == 15: + return "NonPlayer" + elif rc == 16: + return "SemiPlayer" + elif rc == 17: + return "NonSemiPlayer" + else: + print("ERROR, INVALID RACE ID: %d (ID: %s)" % (rc, rac.id)) + exit(1) + +def WhatElem(rac): + rc=rac.elem + tl="ERROR" + cl="#F00" + if rc == 0: + tl,cl="Neutral","#000" + elif rc == 1: + tl,cl="Water","#00F" + elif rc == 2: + tl,cl="Earth","#7A0" + elif rc == 3: + tl,cl="Fire","#F00" + elif rc == 4: + tl,cl="Wind","#093" + elif rc == 5: + tl,cl="Poison","#040" + elif rc == 6: + tl,cl="Holy","#afa" + elif rc == 7: + tl,cl="Dark","#908" + elif rc == 8: + tl,cl="Ghost","#404" + elif rc == 9: + tl,cl="Undead","#440" + else: + print("ERROR, INVALID ELEM ID: %d (ID: %s)" % (rc, rac.id)) + exit(1) + return "<font color=%s>%s</font>" % (cl, tl) + +class Mob: + def __init__(self): + # Basic + self.id="0" + #self.aegis="UnknownMonster" # SpriteName is not used anywhere, we are using its ID + self.name="Unknown Monster Name" + self.view="1" + + # Defensive + self.mobpt="0" # Mob Points “Level” + self.hp="0" + self.xp="0" + self.jp="0" + self.st="" + + # Offensive + self.atk="[0, 0]" + self.range="0" + self.move="0" + self.delay="0" + self.drops=[] + + # Elegen Info + self.race=-1 + self.elem=-1 + self.elel=-1 + self.walk="NORMAL" + +def MobAlloc(ab): + try: + maab=int(ab.mobpt) + except: + maab=9901 + + if maab <= 20: + Mobs1.append(ab) + elif maab <= 40: + Mobs2.append(ab) + elif maab <= 60: + Mobs3.append(ab) + elif maab <= 80: + Mobs4.append(ab) + elif maab <= 100: + Mobs5.append(ab) + else: + MobsA.append(ab) + +def testMobs(): + print("Generating Mob Wiki...") + src=open("../../server-data/db/re/mob_db.conf", "r") + wikib.write("<h1 id='monster-database'>Monster Database</h1>\n") + start=False + dropper=False + x=Mob() # Only for pyflakes2 + + for a in src: + if a == "{\n": + if start: + MobAlloc(x) + else: + start=True + x=Mob() + + if " Id:" in a: + x.id=stp(a) + if x.id == "ID": + continue + + if " Name:" in a: + x.name=stp(a) + elif " Hp:" in a: + x.hp=stp(a) + elif " Lv:" in a: + x.mobpt=stp(a) + elif " Exp:" in a: + x.xp=stp(a) + elif " JExp:" in a: + x.jp=stp(a) + elif " Attack:" in a: + x.atk=stp(a) + elif " AttackRange:" in a: + x.range=stp(a) + elif " MoveSpeed:" in a: + x.move=stp(a) + elif " ViewRange:" in a: + x.view=stp(a) + elif " AttackDelay:" in a: + x.delay=stp(a) + elif " Looter: true" in a: + x.st+="<font color=#790>Lot</font>," + elif " Assist: true" in a: + x.st+="<font color=#0a0>Ass</font>," + elif " Aggressive: true" in a: + x.st+="<font color=#f00>Agr</font>," + elif " WalkMask:" in a: + x.walk=stp(a) + elif " Element:" in a: + tmp=stp(a) + tmp2=tmp.split(',') + try: + x.elem=int(tmp2[0]) + x.elel=int(tmp2[1]) + except: + print("Invalid Element for mob %s: %s" % (x.id, tmp)) + exit(1) + elif " Race:" in a: + try: + x.race=int(stp(a)) + except: + print("Invalid Race for mob %s: %s" % (x.id, a)) + exit(1) + elif 'Drops: ' in a: + dropper=True + elif dropper and '}' in a: + dropper=False + elif dropper: + x.drops.append(stp(a).split(": ")) + # Write last entry + MobAlloc(x) + + writeMob() + + wikib.write('\n\n|Mode|Desc|\n|----|----|\n') + wikib.write('|Lot|Looter|\n') + wikib.write('|Ass|Assist|\n') + wikib.write('|Agr|Aggressive|\n') + + src.close() + +def stp(x): + return x.replace('\n', '').replace('|', '').replace('(int, defaults to ', '').replace(')', '').replace('basic experience', '').replace('"','').replace(" ","").replace("\t","").replace('(string', '').replace('Name: ','').replace('Element: ','').replace('Race: ','').replace('AttackDelay: ', '').replace('WalkMask: ','').replace('MoveSpeed: ', '').replace('AttackRange: ', '').replace('ViewRange: ','').replace('Attack: ','').replace('ViewRange: ','').replace('Hp: ','').replace('Id: ','').replace('Lv: ','').replace('view range','').replace('attack range','').replace('move speed','').replace('health','').replace('(int','').replace('attack delay','atk.').replace('(','').replace(')','').replace('WALK_','') + + +def MonsterWrite(tbl): + # TODO: Check _mobs files to determine the usual monster density (a misc info to aid adding proper drop specs) + wikib.write("<table border=1>\n") + wikib.write("<tr><th>ID</th><th>Name</th><th>Mob Info</th><th>Elegen</th><th>Misc Info</th><th>Rewards</th><th>Drops</th></tr>\n") + for i in tbl: + if i.id == 'ID': + continue + wikib.write('<tr><td><a name="' + i.id + '"></a>' + + i.id +"</td><td>"+ + i.name +"</td><td>"+ + mb_core(i) +"</td><td>"+ + mb_eleg(i) +"</td><td>"+ + mbdt('misc', mb_rdmisc(i)) +"</td><td>"+ + mbdt('Exp\'s', mb_rdrw(i)) +"</td><td>"+ + mbdt('drops', mb_rddrop(i)) +"</td></tr>\n" + ) + wikib.write("</table>\n") + wikib.write("\n<a href=#monster-database>(↑) Return to top</a>\n\n") + +def writeMob(): + wikib.write("\ ++ [Level 0-20](#starter)\n\ ++ [Level 21-40](#apprentice)\n\ ++ [Level 41-60](#intermediary)\n\ ++ [Level 61-80](#advanced)\n\ ++ [Level 81-100](#expert)\n\ ++ [Level 100+](#out-of-scope)\n\n\ + ") + + wikib.write("## Starter\n\n") + MonsterWrite(Mobs1) + + wikib.write("## Apprentice\n\n") + MonsterWrite(Mobs2) + + wikib.write("## Intermediary\n\n") + MonsterWrite(Mobs3) + + wikib.write("## Advanced\n\n") + MonsterWrite(Mobs4) + + wikib.write("## Expert\n\n") + MonsterWrite(Mobs5) + + wikib.write("## Out Of Scope\n\n") + MonsterWrite(MobsA) + + +def mbdt(summary, content): + return "<details>\ +<summary>"+summary+"</summary>\ +<pre>"+content+"</pre></details>" + +def mb_core(mb): + buff="" + buff+="Lvl: %s<br/>\n" % (mb.mobpt) + buff+="HP: <b><font color=#0a0>%s</font></b><br/>\n" % (mb.hp) + buff+="ATK: <b><font color=#a00>%s</font></b><br/>\n" % (mb.atk) + if mb.st != "": + buff+="Modes: <i>%s</i>" % (mb.st) + return buff + +def mb_eleg(mb): + buff="" + buff+="Race: %s<br/>\n" % (WhatRace(mb)) + buff+="Walk: %s<br/>\n" % (fwalk(mb.walk)) + buff+="Element: %s<br/>\n" % (WhatElem(mb)) + return buff + +def mb_rdmisc(mb): + buff="" + if "agr" in mb.st.lower(): + buff+="View Range: %s\n" % (mb.view) + buff+="Attack Range: %s\n" % (mb.range) + buff+="AtkDelay: %s ms\n" % (mb.delay) + buff+="Move speed: %s ms\n" % (mb.move) + buff+="Element Level: %d\n" % (mb.elel) + return buff + +def mb_rdrw(mb): + buff="" + try: + buff+="MobPoints: %d\n" % (int(mb.mobpt)*11/10) + except: + pass + buff+="%s\n" % (mb.xp) + buff+="%s\n" % (mb.jp) + return buff + +def mb_rddrop(mb): + buff="" + for ax in mb.drops: + # Ignore disabled drops + if ax[0].startswith("//"): + continue + + # Write drop + try: + buff+=ax[0]+': ' + str(int(ax[1])/100.0) + ' %\n' + except IndexError: + print("Fatal: invalid %s mob with %s drops" % (mb.name, str(ax))) + exit(1) + except: + print("[Warning] %s incorrect drop: %s" % (mb.name, str(ax))) + buff+=ax[0]+': ' + ax[1] + ' ppm\n' + + # Save to SysDrops + SysDrops.append([ax[0], ax[1], mb.name]) + + return buff + + +class It: + def __init__(self): + # Basic + self.id="0" + self.aegis="UnknownItem" + self.name="Unknown Item Name" + self.price="0" # Sell price, of course + self.weight="0" + self.type="IT_ETC" # default type + self.loc="" + + # Offensive/Defensive + self.atk="0" + self.matk="0" + self.range="0" + self.defs="0" + + # Restrictions (EquipLv) + self.lvl="0" + self.drop=True + self.trade=True + self.sell=True + self.store=True + + # Special settings + self.rare=False # DropAnnounce + self.script=False + + # Visual + self.sl="0" # Slots + self.ac=False # Allow Cards + + # Script settings + self.minheal="0" + self.maxheal="0" + self.delheal="0" + +def ItAlloc(it): + if (it.sl == "0" and it.ac) or (it.sl in ["1","2","3","4"] and not it.ac): + print("WARNING, item id "+it.id+" invalid dye/card setting!") + if (len(it.sl) > 1): + print("WARNING, item id "+it.id+" bad slots length: %d (%s)" % (len(it.sl), it.sl)) + if it.ac: + wikic.write(it.id + ": " + it.name + "\n") + + a=it.type + if "IT_HEALING" in a: + IT_HEALING.append(it) + elif "IT_ETC" in a: + IT_ETC.append(it) + elif "IT_USABLE" in a: + IT_USABLE.append(it) + elif "IT_AMMO" in a: + IT_AMMO.append(it) + elif "IT_CARD" in a: + IT_CARD.append(it) + elif "IT_PETEGG" in a: + IT_PETEGG.append(it) + + elif "IT_WEAPON" in a: + if "HAND_L" in it.loc or "EQP_ARMS" in it.loc: + IT_WEAPON["HAND_2"].append(it) + elif "HAND_R" in it.loc: + IT_WEAPON["HAND_1"].append(it) + else: + raise Exception("Invalid location for weapon: %s" % it.loc) + + elif "IT_ARMOR" in a: + if 'EQP_ACC_L' in it.loc: + IT_ARMOR['EQP_ACC_L'].append(it) + elif 'EQP_ACC_R' in it.loc: + IT_ARMOR['EQP_ACC_R'].append(it) + elif 'EQP_HEAD_MID' in it.loc: + IT_ARMOR['EQP_HEAD_MID'].append(it) + elif 'EQP_SHOES' in it.loc: + IT_ARMOR['EQP_SHOES'].append(it) + elif 'EQP_GARMENT' in it.loc: + IT_ARMOR['EQP_GARMENT'].append(it) + elif 'EQP_HEAD_LOW' in it.loc: + IT_ARMOR['EQP_HEAD_LOW'].append(it) + elif 'EQP_HEAD_TOP' in it.loc: + IT_ARMOR['EQP_HEAD_TOP'].append(it) + elif 'EQP_HAND_L' in it.loc: + IT_ARMOR['EQP_HAND_L'].append(it) + elif '1024' in it.loc: + IT_ARMOR['1024'].append(it) + elif '2048' in it.loc: + IT_ARMOR['2048'].append(it) + elif 'EQP_SHADOW_ACC_R' in it.loc: + IT_ARMOR['EQP_ACC_R'].append(it) + else: + raise Exception("Invalid Loc for ID %s: %s" % (it.id, it.loc)) + +def newItemDB(): + print("Generating Item Wiki...") + src=open("../../server-data/db/re/item_db.conf", "r") + + x=It() + for a in src: + if a == "{\n": + ItAlloc(x) + x=It() + + # sti() block + if " Id:" in a: + x.id=sti(a) + elif " AegisName:" in a: + x.aegis=sti(a) + elif " Name:" in a: + x.name=stin(a) + elif " Sell:" in a: + x.price=sti(a) + elif " Weight:" in a: + x.weight=sti(a) + elif " Type:" in a: + x.type=sti(a) + elif " Loc:" in a: + x.loc=sti(a) + elif " Atk:" in a: + x.atk=sti(a) + elif " Matk:" in a: + x.matk=sti(a) + elif " Range:" in a: + x.range=sti(a) + elif " Def:" in a: + x.defs=sti(a) + elif " EquipLv:" in a: + x.lvl=sti(a) + elif " Slots:" in a: + x.sl=sti(a) + elif " AllowCards:" in a: + x.ac=True + # Write booleans + elif "DropAnnounce: true" in a: + x.rare=True + elif "nodrop: true" in a: + x.drop=False + elif "notrade: true" in a: + x.trade=False + elif "noselltonpc: true" in a: + x.sell=False + elif "nostorage: true" in a: + x.store=False + elif "Script" in a: + x.script=True + # For healing items + elif "@min" in a: + x.minheal=sti(a) + elif "@max" in a: + x.maxheal=sti(a) + elif "@delay" in a: + x.delheal=sti(a) + + # Write last entry + ItAlloc(x) + writeItems() + + src.close() + +def sti(x): + return x.replace('\n', '').replace('|', '').replace(')', '').replace('Id: ', '').replace('"','').replace(" ","").replace("\t","").replace('AegisName: ', '').replace('Name: ','').replace('Sell: ', '').replace('Weight: ', '').replace('Type: ', '').replace('Loc: ', '').replace('Atk: ', '').replace('Matk: ', '').replace('Range: ', '').replace('Def: ', '').replace('EquipLv: ', '').replace('Slots: ','').replace(" ", "").replace('@min=','').replace('@max=','').replace('@delay=','').replace(';','') + +def stin(x): + return x.replace('\n', '').replace('|', '').replace(')', '').replace('Id: ', '').replace('"','').replace(" ","").replace("\t","").replace('Name: ','').replace(';','') + + +def writeItems(): + wikia.write("# Items\n\ ++ [Healing Items](#healing-items)\n\ ++ [Usable Items](#usable-items)\n\ ++ [Generic Items](#generic-items)\n\ ++ [Ammo](#ammo)\n\ ++ [Cards](#cards)\n\ ++ [Pet Eggs](#pet-eggs)\n\ ++ [Weapons](#weapons)\n\ + + [1H Weapons](#1h-weapons)\n\ + + [2H Weapons](#2h-weapons)\n\ ++ [Armors](#armors)\n\ + + [Left Accessory](#left-accessory)\n\ + + [Right Accessory](#right-accessory)\n\ + + [Headgear](#headgear)\n\ + + [Chest](#chest)\n\ + + [Pants](#pants)\n\ + + [Shoes](#shoes)\n\ + + [Necklaces](#necklaces)\n\ + + [Rings](#rings)\n\ + + [Gloves](#gloves)\n\ + + [Shields](#shields)\n\ +\n\n") + wikia.write("#### Restrictions Reference\n") + wikia.write("Special Aegis Name Markers:\n\ ++ * - Rare item with drop announce.\n\ ++ (dp) - This item cannot be dropped.\n\ ++ (tr) - This item cannot de traded.\n\ ++ (sl) - This item cannot be sold.\n\ ++ (gg) - This item cannot go to storage.\n\n") + + # Healing Items + wikia.write("## Healing Items\n\n") + ItemWrite(IT_HEALING, ID=True, AEGIS=True, PRICE=True, WEIGHT=True, HEALING=True, DROPPER=True) + + # Usable Items + wikia.write("## Usable Items\n") + ItemWrite(IT_USABLE, ID=True, AEGIS=True, NAME=True, PRICE=True, WEIGHT=True, DROPPER=True) + + # Generic Items + wikia.write("## Generic Items\n") + ItemWrite(IT_ETC, ID=True, AEGIS=True, NAME=True, PRICE=True, WEIGHT=True, DROPPER=True) + + # Ammo Items + wikia.write("## Ammo\n") + ItemWrite(IT_AMMO, ID=True, AEGIS=True, NAME=True, WEIGHT=True, ATK=True) + + # Card Items + wikia.write("## Cards\n") + ItemWrite(IT_CARD, ID=True, AEGIS=True, NAME=True, PRICE=True, WEIGHT=True) + + # Pet Egg Items + wikia.write("## Pet Eggs\n") + ItemWrite(IT_PETEGG, ID=True, AEGIS=True, NAME=True, WEIGHT=True) + + #################################################################### + wikia.write("# Weapons\n") + + # 1 Hand Items + wikia.write("## 1H Weapons\n") + ItemWrite(IT_WEAPON['HAND_1'], ID=True, AEGIS=True, PRICE=True, WEIGHT=True, ATK=True, LVL=True, DROPPER=True) + + # 2 Hand Items + wikia.write("## 2H Weapons\n") + ItemWrite(IT_WEAPON['HAND_2'], ID=True, AEGIS=True, PRICE=True, WEIGHT=True, ATK=True, LVL=True, RANGE=True) + + + #################################################################### + wikia.write("# Armors\n") + + ArmorWrite("Left Accessory",'EQP_ACC_L') + ArmorWrite("Right Accessory",'EQP_ACC_R') + ArmorWrite("Headgear",'EQP_HEAD_TOP') + ArmorWrite("Chest",'EQP_HEAD_MID') + ArmorWrite("Pants",'EQP_HEAD_LOW') + ArmorWrite("Shoes",'EQP_SHOES') + ArmorWrite("Necklaces",'1024') + ArmorWrite("Rings",'2048') + ArmorWrite("Gloves",'EQP_GARMENT') + ArmorWrite("Shields",'EQP_HAND_L') + +# Write AegisName with restrictions +def hl(it): + buff="" + if it.rare: + buff+="*" + buff+=it.aegis + buff+=" " + if not it.drop: + buff+="<a href='#restrictions-reference'>(dp)</a>" + if not it.trade: + buff+="<a href='#restrictions-reference'>(tr)</a>" + if not it.sell: + buff+="<a href='#restrictions-reference'>(sl)</a>" + if not it.store: + buff+="<a href='#restrictions-reference'>(gg)</a>" + return buff + +# wikia.write("Id|Aegis|Name|Weight|Atk|Matk|\n") +# wikia.write("Id|Aegis|Name|Price|Weight|\n") + +def ItemWrite(tbl, ID=False, AEGIS=False, NAME=False, PRICE=False, WEIGHT=False, DEF=False, LVL=False, ATK=False, RANGE=False, HEALING=False, SCRIPT=False, DROPPER=False): + wikia.write("<table border=1>\n") + wikia.write("<tr>") + if ID: + wikia.write("<th>ID</th>") + if AEGIS: + wikia.write("<th>Aegis</th>") + if NAME: + wikia.write("<th>Name</th>") + if PRICE: + wikia.write("<th>Price</th>") + if WEIGHT: + wikia.write("<th>Weight</th>") + if DEF: + wikia.write("<th>Def</th>") + if LVL: + wikia.write("<th>Lvl</th>") + if ATK: + wikia.write("<th>Atk</th>") + wikia.write("<th>Matk</th>") + if RANGE: + wikia.write("<th>Range</th>") + if HEALING: + wikia.write("<th>Min</th>") + wikia.write("<th>Max</th>") + wikia.write("<th>Delay</th>") + if SCRIPT: + wikia.write("<th>Script</th>") + if DROPPER: + wikia.write("<th>Mobs</th>") + + wikia.write("</tr>\n") + + for i in tbl: + wikia.write('<tr>') + + if ID: + wikia.write("<td><a name=\"%s\"></a>%s</td>" % (i.id,i.id)) + if AEGIS: + wikia.write("<td>%s</td>" % hl(i)) + if NAME: + wikia.write("<td>%s</td>" % i.name) + if PRICE: + wikia.write("<td>%s GP</td>" % i.price) + if WEIGHT: + wikia.write("<td>%s g</td>" % i.weight) + if DEF: + wikia.write("<td>Def: %s</td>" % i.defs) + if LVL: + wikia.write("<td>Lv: %s</td>" % i.lvl) + if ATK: + wikia.write("<td>Atk: %s</td>" % i.atk) + wikia.write("<td>%s</td>" % i.matk) + if RANGE: + wikia.write("<td>%s</td>" % i.range) + if HEALING: + wikia.write("<td>%s</td>" % i.minheal) + wikia.write("<td>%s</td>" % i.maxheal) + wikia.write("<td>%s s</td>" % i.delheal) + if SCRIPT: + wikia.write("<td>%s</td>" % i.script) + # TODO: Check for item Aegis in npc/ folder too, to determine shops and quests. + if DROPPER: + tmp_droppers="" + tmp_drpalign=[] + for ax in SysDrops: + if ax[0] == i.aegis: + tmp_drpalign.append([ax[2], ax[1]]) + if len(tmp_drpalign) > 0: + for a in sorted(tmp_drpalign, key=lambda xcv: xcv[1], reverse=True): + try: + ppm=int(a[1])/100.0 + tmp_droppers+=("%s: %.2f %% \n" % (a[0], ppm)) + except: + print("[Warning] %s whodrop error: %s" % (i.name, str(a))) + wikia.write("<td>%s</td>" % mbdt("monsters", tmp_droppers)) + else: + wikia.write("<td>-</td>") + + wikia.write("</tr>") + + wikia.write("</table>\n") + wikia.write("\n[(↑) Return to top](#items)\n\n") + +def ArmorWrite(name,scope): + wikia.write("## "+name+"\n") + ItemWrite(IT_ARMOR[scope], ID=True, AEGIS=True, PRICE=True, WEIGHT=True, DEF=True, LVL=True, SCRIPT=True) + +showHeader() + +testMobs() +newItemDB() + +wikia.close() +wikib.close() +wikic.close() +#print(str(SysDrops)) + +showFooter() +exit(0) diff --git a/wiki/wikigen.py b/wiki/wikigen.py new file mode 100755 index 0000000..c5ce71e --- /dev/null +++ b/wiki/wikigen.py @@ -0,0 +1,898 @@ +#! /usr/bin/env python3 +# -*- coding: utf8 -*- +# +# Copyright (C) 2010-2011 Evol Online +# Copyright (C) 2018 TMW-2 +# Author: Andrei Karas (4144) +# Author: Jesusalva + +import datetime +import sys + +wikia=open("Items.md", "w") +wikib=open("Monsters.md", "w") +wikic=open("../../client-data/dyes.diff", "w") # Dye Report +wikid=open("../../server-data/changechase.diff", "w") # ChangeChase Report + +# the TYPEs we use to determine where to pack things +IT_HEALING=[] +IT_ETC=[] +IT_USABLE=[] +IT_AMMO=[] +IT_CARD=[] +IT_PETEGG=[] +IT_WEAPON={ 'HAND_2': [], # TWO HAND (LR) + 'HAND_1':[]} # WEAPONS (R) +IT_ARMOR={ 'MISC': [], # FOR FAILURE + 'EQP_ACC_L': [], # ACCESSORY LEFT + 'EQP_ACC_R': [], # ACCESSORT RIGHT + 'EQP_HEAD_MID': [], # CHEST + 'EQP_SHOES': [], # FEET + 'EQP_GARMENT': [], # GLOVES + 'EQP_HEAD_LOW':[], # PANTS + '1024': [], # NECKLACES (should be EQP_COSTUME_HEAD_TOP instead of number) + '2048': [], # RINGS (should be EQP_COSTUME_HEAD_MID instead of number) + 'EQP_MOUNT':[], # MOUNTS (ie. EQP_SHADOW_SHOES) + 'EQP_HEAD_TOP':[], # HATS/HELMETS + 'EQP_HAND_L': []} # SHIELDS + +Mobs1=[] +Mobs2=[] +Mobs3=[] +Mobs4=[] +Mobs5=[] +Mobs6=[] +MobsA=[] + +SysDrops=[] + + +def printSeparator(): + print("--------------------------------------------------------------------------------") + +def showHeader(): + print("TMW2 Wiki Generator") + ##print "Evol client data validator." + print("Run at: " + datetime.datetime.now().isoformat()) + print("Usage: ./wikigen.py [<path_to_serverdata> <path_to_clientdata>]") + ##print "https://gitlab.com/evol/evol-tools/blob/master/testxml/testxml.py" + printSeparator() + +def showFooter(): + #pass + #printSeparator() + print("Done.") + + + + + + +class Mob: + def __init__(self): + # Basic + self.id="0" + #self.aegis="UnknownMonster" # SpriteName is not used anywhere, we are using its ID + self.name="Unknown Monster Name" + self.view="1" + self.chch=False + self.boss=False + + # Defensive + self.mobpt="0" # Mob Points “Level” + self.hp="0" + self.xp="0" + self.jp="0" + self.st="" + + # Offensive + self.atk="[0, 0]" + self.range="0" + self.move="0" + self.delay="0" + self.drops=[] + +def MobAlloc(ab): + try: + maab=int(ab.mobpt) + except: + maab=9901 + + if maab <= 20: + Mobs1.append(ab) + elif maab <= 40: + Mobs2.append(ab) + elif maab <= 60: + Mobs3.append(ab) + elif maab <= 80: + Mobs4.append(ab) + elif maab <= 100: + Mobs5.append(ab) + elif maab <= 150: + Mobs6.append(ab) + elif maab != 9901: + MobsA.append(ab) + else: + print("WARNING, Disregarding \"%s\" (ID: %s) as invalid mob" % (ab.name, ab.id)) + +def testMobs(): + print("\nGenerating Mob Wiki...") + if len(sys.argv) >= 2: + src=open(sys.argv[1]+"/db/re/mob_db.conf", "r") + else: + src=open("../../server-data/db/re/mob_db.conf", "r") + + wikib.write("# Monster Database\n") + start=False + dropper=False + x=Mob() # Only for pyflakes2 + + for a in src: + if a == "{\n": + if start: + MobAlloc(x) + else: + start=True + x=Mob() + + if " Id:" in a: + x.id=stp(a) + elif " Name:" in a: + x.name=stp(a) + elif " Hp:" in a: + x.hp=stp(a) + elif " Lv:" in a: + x.mobpt=stp(a) + elif " Exp:" in a: + x.xp=stp(a) + elif " JExp:" in a: + x.jp=stp(a) + elif " Attack:" in a: + x.atk=stp(a) + elif " AttackRange:" in a: + x.range=stp(a) + elif " MoveSpeed:" in a: + x.move=stp(a) + elif " ViewRange:" in a: + x.view=stp(a) + elif " AttackDelay:" in a: + x.delay=stp(a) + elif " Boss: true" in a: + x.boss=True + elif " Looter: true" in a: + x.st+="Lot," + elif " Assist: true" in a: + x.st+="Ass," + elif " Aggressive: true" in a: + x.st+="Agr," + elif " ChangeChase: true" in a: + x.chch=True + elif 'Drops: ' in a: + dropper=True + elif dropper and '}' in a: + dropper=False + elif dropper: + x.drops.append(stp(a).split(": ")) + # Write last entry + MobAlloc(x) + + writeMob() + + wikib.write('\n\n|Mode|Desc|\n|----|----|\n') + wikib.write('|Lot|Looter|\n') + wikib.write('|Ass|Assist|\n') + wikib.write('|Agr|Aggressive|\n') + + src.close() + +def stp(x): + return x.replace('\n', '').replace('|', '').replace('(int, defaults to ', '').replace(')', '').replace('basic experience', '').replace('"','').replace(" ","").replace("\t","").replace('(string', '').replace('Name: ','').replace('AttackDelay: ', '').replace('MoveSpeed: ', '').replace('AttackRange: ', '').replace('ViewRange: ','').replace('Attack: ','').replace('ViewRange: ','').replace('Hp: ','').replace('Id: ','').replace('Lv: ','').replace('view range','').replace('attack range','').replace('move speed','').replace('health','').replace('(int','').replace('attack delay','atk.') + + +def MonsterWrite(tbl): + # TODO: Check _mobs files to determine the usual monster density (a misc info to aid adding proper drop specs) + wikib.write("<table border=1>\n") + wikib.write("<tr><th>ID</th><th>Name</th><th>HP</th><th>Atk</th><th>Delay</th><th>Modes</th><th>Misc Info</th><th>Rewards</th><th>Drops</th></tr>\n") + for i in tbl: + if not i.chch: + wikid.write("%s:%s\n" % (i.id, i.name)) + if i.boss: + i.name="<b>"+i.name+"</b>" + wikib.write('<tr><td><a name="' + i.id + '"></a>' + + i.id +"</td><td>"+ + i.name +"</td><td>HP: "+ + i.hp +"</td><td>Atk: "+ + i.atk +"</td><td>"+ + i.delay +" ms</td><td>"+ + i.st +"</td><td>"+ + mbdt('misc', mb_rdmisc(i)) +"</td><td>"+ + mbdt('Exp\'s', mb_rdrw(i)) +"</td><td>"+ + mbdt('drops', mb_rddrop(i)) +"</td></tr>\n" + ) + wikib.write("</table>\n") + wikib.write("\n[(↑) Return to top](#monster-database)\n\n") + +def writeMob(): + wikib.write("\ ++ [Level 0-20](#starter)\n\ ++ [Level 21-40](#apprentice)\n\ ++ [Level 41-60](#intermediary)\n\ ++ [Level 61-80](#advanced)\n\ ++ [Level 81-100](#expert)\n\ ++ [Level 101-150](#master)\n\ ++ [Level 100+](#out-of-scope)\n\n\ + ") + + wikib.write("## Starter\n\n") + MonsterWrite(Mobs1) + + wikib.write("## Apprentice\n\n") + MonsterWrite(Mobs2) + + wikib.write("## Intermediary\n\n") + MonsterWrite(Mobs3) + + wikib.write("## Advanced\n\n") + MonsterWrite(Mobs4) + + wikib.write("## Expert\n\n") + MonsterWrite(Mobs5) + + wikib.write("## Master\n\n") + MonsterWrite(Mobs6) + + wikib.write("## Out Of Scope\n\n") + MonsterWrite(MobsA) + + +def mbdt(summary, content): + return "<details>\ +<summary>"+summary+"</summary>\ +<pre>"+content+"</pre></details>" + +def mb_rdmisc(mb): + buff="" + if "agr" in mb.st.lower(): + buff+="View Range: %s\n" % (mb.view) + buff+="Attack Range: %s\n" % (mb.range) + buff+="Move speed: %s ms\n" % (mb.move) + return buff + +def mb_rdrw(mb): + buff="" + buff+="MobPoints: %s\n" % (mb.mobpt) + buff+="%s\n" % (mb.xp) + buff+="%s\n" % (mb.jp) + return buff + +def mb_rddrop(mb): + buff="" + # sorted + for ax in sorted(mb.drops, key=lambda xcv: float(xcv[1]), reverse=True): + # Ignore disabled drops + if ax[0].startswith("//"): + continue + + # Write drop + try: + buff+=ax[0]+': ' + str(int(ax[1])/100.0) + ' %\n' + except IndexError: + print("Fatal: invalid %s mob with %s drops" % (mb.name, str(ax))) + exit(1) + except: + print("[Warning] %s incorrect drop: %s" % (mb.name, str(ax))) + buff+=ax[0]+': ' + ax[1] + ' ppm\n' + + # Save to SysDrops + SysDrops.append([ax[0], ax[1], mb.name]) + + return buff + + +class It: + def __init__(self): + # Basic + self.id="0" + self.aegis="UnknownItem" + self.name="Unknown Item Name" + self.price="0" # Sell price, of course + self.weight="0" + self.type="IT_ETC" # default type + self.loc="" + + # Offensive/Defensive + self.atk="0" + self.matk="0" + self.range="0" + self.defs="0" + + # Restrictions (EquipLv) + self.lvl="0" + self.drop=True + self.trade=True + self.sell=True + self.store=True + + # Special settings + self.rare=False # DropAnnounce + self.script=False + + # Visual + self.sl="0" # Slots + self.ac=False # Allow Cards + + # Script settings + self.minheal="0" + self.maxheal="0" + self.delheal="0" + self.typheal="0" + self.rarheal="0" + +def ItAlloc(it): + if (it.sl == "0" and it.ac) or (it.sl in ["1","2","3","4"] and not it.ac): + print("WARNING, item id "+it.id+" invalid dye/card setting!") + if (len(it.sl) > 1): + print("WARNING, item id "+it.id+" bad slots length: %d (%s)" % (len(it.sl), it.sl)) + if it.ac: + wikic.write(it.id + ": " + it.name + "\n") + + a=it.type + if "IT_HEALING" in a: + IT_HEALING.append(it) + elif "IT_ETC" in a: + IT_ETC.append(it) + elif "IT_USABLE" in a: + IT_USABLE.append(it) + elif "IT_AMMO" in a: + IT_AMMO.append(it) + elif "IT_CARD" in a: + IT_CARD.append(it) + elif "IT_PETEGG" in a: + IT_PETEGG.append(it) + + elif "IT_WEAPON" in a: + if "HAND_L" in it.loc or "EQP_ARMS" in it.loc: + IT_WEAPON["HAND_2"].append(it) + elif "HAND_R" in it.loc: + IT_WEAPON["HAND_1"].append(it) + else: + raise Exception("Invalid location for weapon: %s" % it.loc) + + elif "IT_ARMOR" in a: + if 'EQP_ACC_L' in it.loc: + IT_ARMOR['EQP_ACC_L'].append(it) + elif 'EQP_ACC_R' in it.loc: + IT_ARMOR['EQP_ACC_R'].append(it) + elif 'EQP_HEAD_MID' in it.loc: + IT_ARMOR['EQP_HEAD_MID'].append(it) + elif 'EQP_SHOES' in it.loc: + IT_ARMOR['EQP_SHOES'].append(it) + elif 'EQP_GARMENT' in it.loc: + IT_ARMOR['EQP_GARMENT'].append(it) + elif 'EQP_HEAD_LOW' in it.loc: + IT_ARMOR['EQP_HEAD_LOW'].append(it) + elif 'EQP_HEAD_TOP' in it.loc: + IT_ARMOR['EQP_HEAD_TOP'].append(it) + elif 'EQP_HAND_L' in it.loc: + IT_ARMOR['EQP_HAND_L'].append(it) + elif '1024' in it.loc: + IT_ARMOR['1024'].append(it) + elif '2048' in it.loc: + IT_ARMOR['2048'].append(it) + elif 'EQP_SHADOW_SHOES' in it.loc: + IT_ARMOR['EQP_MOUNT'].append(it) + elif 'EQP_SHADOW_ACC_R' in it.loc: + IT_ARMOR['EQP_ACC_R'].append(it) # Not really + else: + raise Exception("Invalid Loc for ID %s: %s" % (it.id, it.loc)) + +def newItemDB(): + print("\nGenerating Item Wiki...") + if len(sys.argv) >= 2: + src=open(sys.argv[1]+"/db/re/item_db.conf", "r") + else: + src=open("../../server-data/db/re/item_db.conf", "r") + + x=It() + for a in src: + if a == "{\n": + ItAlloc(x) + x=It() + + # sti() block + if " Id:" in a: + x.id=sti(a) + elif " AegisName:" in a: + x.aegis=sti(a) + elif " Name:" in a: + x.name=stin(a) + elif " Sell:" in a: + x.price=sti(a) + elif " Weight:" in a: + x.weight=sti(a) + elif " Type:" in a: + x.type=sti(a) + elif " Loc:" in a: + x.loc=sti(a) + elif " Atk:" in a: + x.atk=sti(a) + elif " Matk:" in a: + x.matk=sti(a) + elif " Range:" in a: + x.range=sti(a) + elif " Def:" in a: + x.defs=sti(a) + elif " EquipLv:" in a: + x.lvl=sti(a) + elif " Slots:" in a: + x.sl=sti(a) + elif " AllowCards:" in a: + x.ac=True + # Write booleans + elif "DropAnnounce: true" in a: + x.rare=True + elif "nodrop: true" in a: + x.drop=False + elif "notrade: true" in a: + x.trade=False + elif "noselltonpc: true" in a: + x.sell=False + elif "nostorage: true" in a: + x.store=False + elif "Script" in a: + x.script=True + # For healing items + elif "@min " in a: + x.minheal=sti(a) + elif "@max " in a: + x.maxheal=sti(a) + elif "@delay" in a: + x.delheal=sti(a) + elif "@type" in a: + x.typheal=sti(a) + try: + x.minheal=str(int(x.rarheal) * (int(x.typheal)*1 + 1)) + " %" + x.maxheal=str(int(x.rarheal) * (int(x.typheal)*2 + 1)) + " %" + if (x.delheal == "0"): + x.delheal=int(x.typheal)*2 + 1 + except: + x.delheal="ERROR" + pass + elif "@rarity" in a: + x.rarheal=sti(a) + x.minheal=str(int(x.rarheal) * (int(x.typheal)*1 + 1)) + " %" + x.maxheal=str(int(x.rarheal) * (int(x.typheal)*2 + 1)) + " %" + + # Write last entry + ItAlloc(x) + writeItems() + + src.close() + +def sti(x): + return x.replace('\n', '').replace('|', '').replace(')', '').replace('Id: ', '').replace('"','').replace(" ","").replace("\t","").replace('AegisName: ', '').replace('Name: ','').replace('Sell: ', '').replace('Weight: ', '').replace('Type: ', '').replace('Loc: ', '').replace('Atk: ', '').replace('Matk: ', '').replace('Range: ', '').replace('Def: ', '').replace('EquipLv: ', '').replace('Slots: ','').replace(" ", "").replace('@min=','').replace('@max=','').replace('@delay=','').replace('@type=','').replace('@rarity=','').replace(';','') + +def stin(x): + return x.replace('\n', '').replace('|', '').replace(')', '').replace('Id: ', '').replace('"','').replace(" ","").replace("\t","").replace('Name: ','').replace(';','') + + +def writeItems(): + wikia.write("# Items\n\ ++ [Healing Items](#healing-items)\n\ ++ [Usable Items](#usable-items)\n\ ++ [Generic Items](#generic-items)\n\ ++ [Ammo](#ammo)\n\ ++ [Cards](#cards)\n\ ++ [Pet Eggs](#pet-eggs)\n\ ++ [Mounts](#mounts)\n\ ++ [Weapons](#weapons)\n\ + + [1H Weapons](#1h-weapons)\n\ + + [2H Weapons](#2h-weapons)\n\ ++ [Armors](#armors)\n\ + + [Left Accessory](#left-accessory)\n\ + + [Right Accessory](#right-accessory)\n\ + + [Headgear](#headgear)\n\ + + [Chest](#chest)\n\ + + [Pants](#pants)\n\ + + [Shoes](#shoes)\n\ + + [Necklaces](#necklaces)\n\ + + [Rings](#rings)\n\ + + [Gloves](#gloves)\n\ + + [Shields](#shields)\n\ +\n\n") + wikia.write("#### Restrictions Reference\n") + wikia.write("Special Aegis Name Markers:\n\ ++ * - Rare item with drop announce.\n\ ++ (dp) - This item cannot be dropped.\n\ ++ (tr) - This item cannot de traded.\n\ ++ (sl) - This item cannot be sold.\n\ ++ (gg) - This item cannot go to storage.\n\n") + + # Healing Items + wikia.write("## Healing Items\n\n") + ItemWrite(IT_HEALING, ID=True, AEGIS=True, PRICE=True, WEIGHT=True, HEALING=True, DROPPER=True) + + # Usable Items + wikia.write("## Usable Items\n") + ItemWrite(IT_USABLE, ID=True, AEGIS=True, NAME=True, PRICE=True, WEIGHT=True, DROPPER=True) + + # Generic Items + wikia.write("## Generic Items\n") + ItemWrite(IT_ETC, ID=True, AEGIS=True, NAME=True, PRICE=True, WEIGHT=True, DROPPER=True) + + # Ammo Items + wikia.write("## Ammo\n") + ItemWrite(IT_AMMO, ID=True, AEGIS=True, NAME=True, WEIGHT=True, ATK=True) + + # Card Items + wikia.write("## Cards\n") + ItemWrite(IT_CARD, ID=True, AEGIS=True, NAME=True, PRICE=True, WEIGHT=True) + + # Pet Egg Items + wikia.write("## Pet Eggs\n") + ItemWrite(IT_PETEGG, ID=True, AEGIS=True, NAME=True, WEIGHT=True) + + # Mount Items + wikia.write("## Mounts\n") + ItemWrite(IT_ARMOR['EQP_MOUNT'], ID=True, AEGIS=True, NAME=True, WEIGHT=True) + + #################################################################### + wikia.write("# Weapons\n") + + # 1 Hand Items + wikia.write("## 1H Weapons\n") + ItemWrite(IT_WEAPON['HAND_1'], ID=True, AEGIS=True, PRICE=True, WEIGHT=True, ATK=True, LVL=True, DROPPER=True) + + # 2 Hand Items + wikia.write("## 2H Weapons\n") + ItemWrite(IT_WEAPON['HAND_2'], ID=True, AEGIS=True, PRICE=True, WEIGHT=True, ATK=True, LVL=True, RANGE=True) + + + #################################################################### + wikia.write("# Armors\n") + + ArmorWrite("Left Accessory",'EQP_ACC_L', False) + ArmorWrite("Right Accessory",'EQP_ACC_R', False) + ArmorWrite("Headgear",'EQP_HEAD_TOP') + ArmorWrite("Chest",'EQP_HEAD_MID') + ArmorWrite("Pants",'EQP_HEAD_LOW') + ArmorWrite("Shoes",'EQP_SHOES') + ArmorWrite("Necklaces",'1024', False) + ArmorWrite("Rings",'2048', False) + ArmorWrite("Gloves",'EQP_GARMENT') + ArmorWrite("Shields",'EQP_HAND_L') + +# Write AegisName with restrictions +def hl(it): + buff="" + if it.rare: + buff+="*" + buff+=it.aegis + buff+=" " + if not it.drop: + buff+="<a href='#restrictions-reference'>(dp)</a>" + if not it.trade: + buff+="<a href='#restrictions-reference'>(tr)</a>" + if not it.sell: + buff+="<a href='#restrictions-reference'>(sl)</a>" + if not it.store: + buff+="<a href='#restrictions-reference'>(gg)</a>" + return buff + +# wikia.write("Id|Aegis|Name|Weight|Atk|Matk|\n") +# wikia.write("Id|Aegis|Name|Price|Weight|\n") + +def ItemWrite(tbl, ID=False, AEGIS=False, NAME=False, PRICE=False, WEIGHT=False, DEF=False, LVL=False, ATK=False, RANGE=False, HEALING=False, SCRIPT=False, DROPPER=False): + wikia.write("<table border=1>\n") + wikia.write("<tr>") + if ID: + wikia.write("<th>ID</th>") + if AEGIS: + wikia.write("<th>Aegis</th>") + if NAME: + wikia.write("<th>Name</th>") + if PRICE: + wikia.write("<th>Price</th>") + if WEIGHT: + wikia.write("<th>Weight</th>") + if DEF: + wikia.write("<th>Def</th>") + if LVL: + wikia.write("<th>Lvl</th>") + if ATK: + wikia.write("<th>Atk</th>") + wikia.write("<th>Matk</th>") + if RANGE: + wikia.write("<th>Range</th>") + if HEALING: + wikia.write("<th>Min</th>") + wikia.write("<th>Max</th>") + wikia.write("<th>Delay</th>") + if SCRIPT: + wikia.write("<th>Script</th>") + if DROPPER: + wikia.write("<th>Mobs</th>") + + wikia.write("</tr>\n") + + for i in tbl: + """ + # To sort by weight, for example, uncomment this block. + try: + zt=int(i.weight) + except: + tbl.remove(i) + + for i in sorted(tbl, key=lambda xcv: int(xcv.weight), reverse=True): + """ + + wikia.write('<tr>') + + if ID: + wikia.write("<td><a name=\"%s\"></a>%s</td>" % (i.id,i.id)) + if AEGIS: + wikia.write("<td>%s</td>" % hl(i)) + if NAME: + wikia.write("<td>%s</td>" % i.name) + if PRICE: + wikia.write("<td>%s GP</td>" % i.price) + if WEIGHT: + wikia.write("<td>%s g</td>" % i.weight) + if DEF: + wikia.write("<td>Def: %s</td>" % i.defs) + if LVL: + wikia.write("<td>Lv: %s</td>" % i.lvl) + if ATK: + wikia.write("<td>Atk: %s</td>" % i.atk) + wikia.write("<td>%s</td>" % i.matk) + if RANGE: + wikia.write("<td>%s</td>" % i.range) + if HEALING: + wikia.write("<td>%s</td>" % i.minheal) + wikia.write("<td>%s</td>" % i.maxheal) + wikia.write("<td>%s s</td>" % i.delheal) + if SCRIPT: + wikia.write("<td>%s</td>" % i.script) + # TODO: Check for item Aegis in npc/ folder too, to determine shops and quests. + if DROPPER: + tmp_droppers="" + tmp_drpalign=[] + for ax in SysDrops: + if ax[0] == i.aegis: + tmp_drpalign.append([ax[2], ax[1]]) + if len(tmp_drpalign) > 0: + for a in sorted(tmp_drpalign, key=lambda xcv: float(xcv[1]), reverse=True): + try: + ppm=int(a[1])/100.0 + tmp_droppers+=("%s: %.2f %% \n" % (a[0], ppm)) + except: + print("[Warning] %s whodrop error: %s" % (i.name, str(a))) + wikia.write("<td>%s</td>" % mbdt("monsters", tmp_droppers)) + else: + wikia.write("<td>-</td>") + + wikia.write("</tr>") + + wikia.write("</table>\n") + wikia.write("\n[(↑) Return to top](#items)\n\n") + +def ArmorWrite(name,scope,defitem=True): + wikia.write("## "+name+"\n") + ItemWrite(IT_ARMOR[scope], ID=True, AEGIS=True, PRICE=True, WEIGHT=True, DEF=defitem, LVL=True, DROPPER=True) + + + + + + + + + + + +class Quest: + def __init__(self, ide): + # Basic + self.id=ide + self.name="Unknown Quest Name" + self.group="Unknown" + self.ent=[] + self.level=0 + +class QuestEntry: + def __init__(self): + # Basic + self.complete=False + self.entry=[] # collection of <text> + self.giver="" + self.reward="" + self.loc="" + +def sortlv(val): + return val[1] + +def qnt(string): + return string.replace(' ','').replace('"','').replace("'","").replace('<','').replace('>','').replace('nowiki=1', '').replace('nowiki', '') + +def qnt2(string): + return string.replace('##B','**').replace('##b','**').replace('##0','*').replace('##1','*').replace('##2','*').replace('##3','*').replace('##','*') + +def DoQuest(): + print("\nGenerating Quest Wiki...") + if len(sys.argv) >= 3: + src=open(sys.argv[2]+"/quests.xml", "r") + else: + src=open("../../client-data/quests.xml", "r") + + qlog=[] + q=Quest(-1) + qe=QuestEntry() + ig=False + nw=False + + for e in src: + # Handle Comments and Ignored lines + if '<!--' in e and '-->' in e: + continue + elif '<!--' in e: + ig=True + elif '-->' in e: + ig=False + if '<effect' in e: + continue + + if ig: + continue + + # Handle Quest Headers + if '</var' in e: + if (nw): + nw=False + else: + qlog.append(q) + elif '<var' in e: + if 'nowiki' in e: + nw=True + g=qnt(e) + try: + q=Quest(int( g.replace('varid=','') )) + except: + print("Invalid quest: %s" % g) + exit(1) + + # Handle quest entries + if '</quest>' in e: + q.ent.append(qe) + elif '<quest ' in e: + qe=QuestEntry() + l=e.split('"') + rc=[False, ""] + for arg in l: + if not rc[0]: + if "name" in arg: + rc=[True, 'name'] + elif "group" in arg: + rc=[True, 'group'] + elif "complete" in arg: + rc=[True, arg.replace('=','').replace(' ','')] + else: + if rc[1] == "name": + q.name=arg + elif rc[1] == "group": + q.group=arg + elif rc[1] == "complete": + qe.complete=True + elif rc[1] == "incomplete": + qe.complete=False + else: + print("Invalid <quest> tag: %s (arg was %s) (line was %s)" % (e, rc[1], l)) + exit(1) + rc=[False, ""] + + # Fill stuff in Quest Entry + if '<text' in e: + a=qnt2(e) + qe.entry.append( a.replace('<text>','').replace('</text>','').replace('<text ','<').replace("@@1", "text").replace("@@", "").strip() ) + elif '<wiki' in e: + a=qnt2(e) + qe.entry.append( a.replace('<wiki>','').replace('</wiki>','').replace('<wiki ','<').replace("@@1", "text").replace("@@", "").strip() ) + elif '<questgiver' in e: + a=qnt2(e) + qe.giver=a.replace('<questgiver>','').replace('</questgiver>','').strip() + elif '<reward' in e: + a=qnt2(e) + qe.reward=a.replace('<reward>','').replace('</reward>','').replace("@@", "text").replace('<reward ','<').strip() + elif '<coord' in e: + a=qnt2(e) + b=a.split('>') + qe.loc=b[1].replace('</coordinates','').strip() + elif '<level' in e: + a=qnt2(e) + qe.entry.append( "Required Level: " + a.replace('<level>','').replace('</level>','').strip() ) + if (not q.level): + try: + q.level=int(a.replace('<level>','').replace('</level>','').strip()) + except: + pass + + # Done reading file + src.close() + aktbl={} + aksort=[] + print("\033[32;1mTotal quests: %d\033[0m" % len(qlog)) + for i in qlog: + if i.name=="Unknown Quest Name": + print("Warning, invalid quest: %d" % (i.id)) + qlog.remove(i) + continue + # Total Table + #print(str(i.id)+": "+i.name) + try: + if (i.level): + aktbl[i.group].append(("[%s](q/%d) (Lv %d)" % (i.name, i.id, i.level), i.level)) + else: + aktbl[i.group].append(("[%s](q/%d)" % (i.name, i.id), i.level)) + except: + if (i.level): + aktbl[i.group]=[("[%s](q/%d) (Lv %d)" % (i.name, i.id, i.level), i.level)] + else: + aktbl[i.group]=[("[%s](q/%d)" % (i.name, i.id), i.level)] + aksort.append(i.group) + + for key in aktbl: + #print(aktbl[key]); + aktbl[key]=sorted(aktbl[key], key=sortlv) + + # Individual file + f=open("../../wiki/q/"+str(i.id)+'.md', "w") + f.write("<!-- --- title: %d: %s -->\n\n" % (i.id, i.name)) + f.write("# %s\n" % i.name) + f.write('\n') + + totalcnt=0 + for a in i.ent: + totalcnt+=1 + f.write('\n### %d Stage\n\n' % totalcnt) + if a.complete: + f.write('*This completes quest*\n\n') + + if a.giver != "" or a.reward != "" or a.loc != "": + f.write('```\n') + if a.giver != "": + f.write('Quest Giver: %s\n' % a.giver) + if a.reward != "": + f.write('Reward: %s\n' % a.reward.replace('@@', '')) + if a.loc != "": + f.write('Location: %s\n' % a.loc) + f.write('```\n\n') + + for line in a.entry: + f.write('%s\n' % line) + + f.write('\n\n****\nThis file is generated automatically. Editing it will have no effect.\n') + f.close() + + # Write total table + f=open("Quests.txt", "w") + f.write("***Total quests: %d***\n" % len(qlog)) + for key in aksort: + f.write('\n## %s\n\n' % key) + # TODO: Sort by Quest Level + for a in aktbl[key]: + f.write('+ '+a[0]+'\n') + f.close() + +showHeader() + +testMobs() +newItemDB() +DoQuest() + +wikia.close() +wikib.close() +wikic.close() +wikid.close() +#print(str(SysDrops)) + +showFooter() +exit(0) |