summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xevolved.py534
1 files changed, 534 insertions, 0 deletions
diff --git a/evolved.py b/evolved.py
new file mode 100755
index 0000000..427656a
--- /dev/null
+++ b/evolved.py
@@ -0,0 +1,534 @@
+#! /usr/bin/env python3
+# -*- coding: utf8 -*-
+#
+# Copyright (C) 2010-2011 Evol Online
+# Copyright (C) 2018-2021 TMW-2
+# Copyright (C) 2022 The Mana World
+# Author: Andrei Karas (4144)
+# Author: Jesusalva
+
+import datetime
+import sys, traceback
+
+wikia=open("Items.md", "w")
+wikib=open("Monsters.md", "w")
+aegis=open("../world/map/db/const-aegis.txt", "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_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
+ self.race="0" # TODO Convert RC_*
+ self.elem="0" # TODO Convert Ele_*
+ self.mode="0" # TODO Convert MD_* and fields
+
+ # General
+ self.mobpt="0" # Mob Points “Level”
+ self.hp="0"
+ self.sp="0"
+ self.xp="0"
+ self.jp="0"
+
+ # Defensive
+ self.st=""
+ self.df="0"
+ self.mdf="0"
+
+ # Stats
+ self.str="0"
+ self.agi="0"
+ self.int="0"
+ self.vit="0"
+ self.dex="0"
+ self.luk="0"
+
+ # Offensive
+ self.atk="[0, 0]"
+ self.range="0"
+ self.chase="1"
+ self.move="0"
+ self.delay="0"
+ self.drops=[]
+
+def MobAlloc(ab):
+ try:
+ maab=int(ab.mobpt)
+ except:
+ maab=9901
+
+ aegis.write("%s %s\n" % (ab.aegis, ab.id))
+ 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/pre-re/mob_db.conf", "r")
+ else:
+ src=open("../world/map/db/mob_db.conf", "r")
+
+ start=False
+ dropper=False
+ x=Mob() # Only for pyflakes2
+
+ for a in src:
+ # Evol2-only scripts
+ if "@EVOL2" in a:
+ continue
+ if "@TMWA" in a:
+ a=a.replace("//", "").replace("@TMWA", "")
+ # Initiate the script
+ if a == "{\n":
+ if start:
+ MobAlloc(x)
+ else:
+ start=True
+ x=Mob()
+
+ if " Id:" in a:
+ x.id=stp(a)
+ elif " SpriteName:" in a:
+ x.aegis=stp(a)
+ elif " Name:" in a:
+ x.name=stp(a)
+ elif " Hp:" in a:
+ x.hp=stp(a)
+ elif " Sp:" in a:
+ x.sp=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 " Def:" in a:
+ x.df=stp(a)
+ elif " Mdef:" in a:
+ x.mdf=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 " ChaseRange:" in a:
+ x.chase=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(": "))
+ elif "\tStr: " in a:
+ x.str=stp(a)
+ elif "\tAgi: " in a:
+ x.agi=stp(a)
+ elif "\tVit: " in a:
+ x.vit=stp(a)
+ elif "\tDex: " in a:
+ x.dex=stp(a)
+ elif "\tInt: " in a:
+ x.int=stp(a)
+ elif "\tLuk: " in a:
+ x.luk=stp(a)
+ # Write last entry
+ MobAlloc(x)
+
+ 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('SpriteName: ','').replace('Name: ','').replace('AttackDelay: ', '').replace('MoveSpeed: ', '').replace('AttackRange: ', '').replace('ViewRange: ','').replace('ChaseRange: ','').replace('Attack: ','').replace('ViewRange: ','').replace('Hp: ','').replace('Sp: ','').replace('Id: ','').replace('Lv: ','').replace('view range','').replace('attack range','').replace('move speed','').replace('health','').replace('(int','').replace('attack delay','atk.').replace("Str:", "").replace("Agi:", "").replace("Vit:", "").replace("Int:", "").replace("Dex:", "").replace("Luk:", "").replace("Mdef:","").replace("Def:","")
+
+
+
+
+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
+ try:
+ 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])
+ except:
+ traceback.print_exc()
+ print("Offender: %s" % 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_ARMOR' 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))
+
+ if "i" in it.id:
+ print("Invalid item: %s" % it.id)
+ return
+
+ ## Save the Aegis ID
+ aegis.write("%s %s\n" % (it.aegis, it.id))
+
+def newItemDB():
+ print("\nGenerating Item Wiki...")
+ if len(sys.argv) >= 2:
+ src=open(sys.argv[1]+"/db/pre-re/item_db.conf", "r")
+ else:
+ src=open("../world/map/db/item_db.conf", "r")
+
+ x=It()
+ for a in src:
+ # Evol2-only scripts
+ if "@EVOL2" in a:
+ continue
+ if "@TMWA" in a:
+ a=a.replace("//", "").replace("@TMWA", "")
+ # Initiate the script
+ 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)
+
+ 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 save_mobs():
+ global Mobs1, Mobs2, Mobs3, Mobs4, Mobs5, Mobs6, MobsA
+ return
+ ## Mobs
+ with open ("../world/map/db/mob_db_0_19.txt", "w") as f:
+ f.write("//THIS FILE IS GENERATED AUTOMATICALLY\n//DO NOT EDIT IT DIRECTLY\n//Edit mob_db.conf instead!\n")
+ f.write("//ID, Name, Jname, LV, HP, SP, EXP, JEXP, Range1, ATK1, ATK2, DEF, MDEF, STR, AGI, VIT, INT, DEX, LUK, Range2, Range3, Scale, Race, Element,Mode, Speed, Adelay, Amotion,Dmotion,Drop1id,Drop1per,Drop2id,Drop2%, Drop3id,Drop3%, Drop4id,Drop4%, Drop5id,Drop5%, Drop6id,Drop6%, Drop7id,Drop7%, Drop8id,Drop8%, Item1, Item2, MEXP, ExpPer, MVP1id, MVP1per,MVP2id, MVP2per,MVP3id, MVP3per,mutationcount,mutationstrength\n")
+ for m in Mobs1:
+ #Adelay, Amotion,Dmotion,Drop1id,Drop1per,Drop2id,Drop2%, Drop3id,Drop3%,
+ #Drop4id,Drop4%, Drop5id,Drop5%, Drop6id,Drop6%, Drop7id,Drop7%, Drop8id,Drop8%,
+ #Item1, Item2, MEXP, ExpPer, MVP1id, MVP1per,MVP2id, MVP2per,MVP3id,
+ #MVP3per,mutationcount,mutationstrength
+ f.write("""%s, %s, %s, %s, %s, %s,
+%s, %s, %s, %s, %s, %s, %s, %s, %s, %s,
+%s, %s, %s, %s, %s, 1, %s, %s, %s, %s,
+\n""" % (m.id, m.aegis, m.aegis, m.mobpt, m.hp, m.sp,
+m.xp, m.jp, m.range, m.atk.replace('[','').split(",")[0], m.atk.replace(']','').split(",")[1], m.df, m.mdf, m.str, m.agi, m.vit,
+m.int, m.dex, m.luk, m.view, m.chase, "Race", "Element", "Mode", self.move,
+ ))
+ continue
+
+ return
+
+
+
+
+
+
+
+
+
+
+
+
+showHeader()
+
+testMobs()
+newItemDB()
+
+save_mobs()
+
+wikia.close()
+wikib.close()
+aegis.close()
+#print(str(SysDrops))
+
+showFooter()
+exit(0)