summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJesusaves <cpntb1@ymail.com>2022-11-03 21:40:32 -0300
committerJesusaves <cpntb1@ymail.com>2022-11-03 21:40:32 -0300
commit17ab5f3411b88bbf060007f7a57c5d960708c079 (patch)
tree731c5191560f9cbd3abc213a6b523f25279b9cfb
parentf846f9155df8b7b083e67e1e8e997582b20b688e (diff)
downloadtools-17ab5f3411b88bbf060007f7a57c5d960708c079.tar.gz
tools-17ab5f3411b88bbf060007f7a57c5d960708c079.tar.bz2
tools-17ab5f3411b88bbf060007f7a57c5d960708c079.tar.xz
tools-17ab5f3411b88bbf060007f7a57c5d960708c079.zip
wikigen, but optimized for Media Wiki
-rwxr-xr-xwiki/tmw_wikigen.py903
1 files changed, 903 insertions, 0 deletions
diff --git a/wiki/tmw_wikigen.py b/wiki/tmw_wikigen.py
new file mode 100755
index 0000000..17c881a
--- /dev/null
+++ b/wiki/tmw_wikigen.py
@@ -0,0 +1,903 @@
+#! /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{| class="wikitable"\n!Mode !!Desc\n')
+ wikib.write('|-\n|Lot||Looter\n')
+ wikib.write('|-\n|Ass||Assist\n')
+ wikib.write('|-\n|Agr||Aggressive\n|}\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("{| class=\"wikitable\"\n")
+ wikib.write("!ID !! Name !! HP !! Atk !! Delay !! Modes !! Misc Info !! Rewards !! Drops\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('|-\n|<span id="' + i.id + '"/>' +
+ i.id +" || "+
+ i.name +" || HP: "+
+ i.hp +" || Atk: "+
+ i.atk +" || "+
+ i.delay +" ms || "+
+ i.st +" || "+
+ mbdt('misc', mb_rdmisc(i)) +" || "+
+ mbdt('Exp\'s', mb_rdrw(i)) +" || "+
+ mbdt('drops', mb_rddrop(i)) +"\n"
+ )
+ wikib.write("|}\n")
+ wikib.write("\n[[Moubootaur_Legends:Monsters|(↑) Return to top]]\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 (Lv 0-20) ==\n\n")
+ MonsterWrite(Mobs1)
+
+ wikib.write("== Apprentice (Lv 21-40) ==\n\n")
+ MonsterWrite(Mobs2)
+
+ wikib.write("== Intermediary (Lv 41-60) ==\n\n")
+ MonsterWrite(Mobs3)
+
+ wikib.write("== Advanced (Lv 61-80) ==\n\n")
+ MonsterWrite(Mobs4)
+
+ wikib.write("== Expert (Lv 81-100) ==\n\n")
+ MonsterWrite(Mobs5)
+
+ wikib.write("== Master (Lv 101-150) ==\n\n")
+ MonsterWrite(Mobs6)
+
+ wikib.write("== Out Of Scope (Lv 151+) ==\n\n")
+ MonsterWrite(MobsA)
+
+
+def mbdt(summary, content):
+ return "<pre>%s</pre>" % content
+ ## TODO: FIXME
+ return """<div class="mw-collapsible" data-collapsetext="Hide" data-expandtext="%s">\n
+<pre>%s</pre></div>""" % (summary, content)
+
+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+=" "
+ #TODO: href='#restrictions-reference'
+ if not it.drop:
+ buff+="<i>(dp)</i>"
+ if not it.trade:
+ buff+="<i>(tr)</i>"
+ if not it.sell:
+ buff+="<i>(sl)</i>"
+ if not it.store:
+ buff+="<i>(gg)</i>"
+ 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("{| class=\"wikitable\"\n")
+ wikia.write("! ID")
+ if AEGIS:
+ wikia.write("!! Aegis")
+ if NAME:
+ wikia.write("!! Name")
+ if PRICE:
+ wikia.write("!! Price")
+ if WEIGHT:
+ wikia.write("!! Weight")
+ if DEF:
+ wikia.write("!! Def")
+ if LVL:
+ wikia.write("!! Lvl")
+ if ATK:
+ wikia.write("!! Atk")
+ wikia.write("!! Matk")
+ if RANGE:
+ wikia.write("!! Range")
+ if HEALING:
+ wikia.write("!! Min")
+ wikia.write("!! Max")
+ wikia.write("!! Delay")
+ if SCRIPT:
+ wikia.write("!! Script")
+ if DROPPER:
+ wikia.write("!! Mobs")
+
+ wikia.write("\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('|-\n')
+
+ wikia.write("|<span id=\"%s\"/>%s" % (i.id,i.id))
+ if AEGIS:
+ wikia.write("||%s" % hl(i))
+ if NAME:
+ wikia.write("||%s" % i.name)
+ if PRICE:
+ wikia.write("||%s GP" % i.price)
+ if WEIGHT:
+ wikia.write("||%s g" % i.weight)
+ if DEF:
+ wikia.write("||Def: %s" % i.defs)
+ if LVL:
+ wikia.write("||Lv: %s" % i.lvl)
+ if ATK:
+ wikia.write("||Atk: %s" % i.atk)
+ wikia.write("||%s" % i.matk)
+ if RANGE:
+ wikia.write("||%s" % i.range)
+ if HEALING:
+ wikia.write("||%s" % i.minheal)
+ wikia.write("||%s" % i.maxheal)
+ wikia.write("||%s s" % i.delheal)
+ if SCRIPT:
+ wikia.write("||<pre>%s</pre>" % 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("||%s" % mbdt("monsters", tmp_droppers))
+ else:
+ wikia.write("|| -")
+
+ wikia.write("\n")
+
+ wikia.write("|}\n")
+ wikia.write("\n[[Moubootaur_Legends:Items|(↑) Return to top]]\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(("[[Moubootaur_Legends:Q/%d|%s]] (Lv %d)" % (i.id, i.name, i.level), i.level))
+ else:
+ aktbl[i.group].append(("[[Moubootaur_Legends:Q/%d|%s]]" % (i.id, i.name), i.level))
+ except:
+ if (i.level):
+ aktbl[i.group]=[("[[Moubootaur_Legends:Q/%d|%s]] (Lv %d)" % (i.id, i.name, i.level), i.level)]
+ else:
+ aktbl[i.group]=[("[[Moubootaur_Legends:Q/%d|%s]]" % (i.id, i.name), 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.write('\n\n<hr/>\nThis file is generated automatically. Editing it will have no effect.\n')
+wikib.write('\n\n<hr/>\nThis file is generated automatically. Editing it will have no effect.\n')
+wikia.close()
+wikib.close()
+wikic.close()
+wikid.close()
+#print(str(SysDrops))
+
+showFooter()
+exit(0)