diff options
-rwxr-xr-x | evolved.py | 534 |
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) |