#! /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('EleGen File') 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] []") 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 '%s' % (wmask) elif wmask == 'AIR': return '%s' % (wmask) elif wmask == 'WALL': return '%s' % (wmask) elif wmask == 'NORMAL' or wmask == 'DEFAULT': return '%s' % (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 "%s" % (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("../../server-data/db/re/mob_db.conf", "r", encoding="utf-8") wikib.write("

EleGen Monster Database

\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+="Lot," elif " Assist: true" in a: x.st+="Ass," elif " Aggressive: true" in a: x.st+="Agr," 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("\n") if stgen: wikib.write("\n") else: wikib.write("\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=""+i.name+"" if stgen: wikib.write('\n" ) else: wikib.write('\n" ) wikib.write("
IDNameMob InfoStgenElegenMisc InfoRewardsStatsDrops
IDNameMob InfoElegenMisc InfoRewardsStatsDrops
' + i.id +""+ i.name +""+ mb_core(i) +""+ mbdt('advise',mb_stgen(i)) +""+ mb_eleg(i) +""+ mbdt('misc', mb_rdmisc(i)) +""+ mbdt('Exp\'s', mb_rdrw(i)) +""+ mbdt('stats', mb_rdstat(i)) +""+ mbdt('drops', mb_rddrop(i)) +"
' + i.id +""+ i.name +""+ mb_core(i) +""+ mb_eleg(i) +""+ mbdt('misc', mb_rdmisc(i)) +""+ mbdt('Exp\'s', mb_rdrw(i)) +""+ mbdt('stats', mb_rdstat(i)) +""+ mbdt('drops', mb_rddrop(i)) +"
\n") wikib.write("Total: %02d Monsters
\n" % len(tbl)) wikib.write("\n(↑) Return to top

\n\n") def writeMob(): wikib.write(" ") wikib.write("

Lv 0-20

\n\n") MonsterWrite(Mobs1) wikib.write("

Lv 21-40

\n\n") MonsterWrite(Mobs2) wikib.write("

Lv 41-60

\n\n") MonsterWrite(Mobs3) wikib.write("

Lv 61-80

\n\n") MonsterWrite(Mobs4) wikib.write("

Lv 81-100

\n\n") MonsterWrite(Mobs5) wikib.write("

Lv 101-150

\n\n") MonsterWrite(Mobs6) wikib.write("

Lv 101+

\n\n") MonsterWrite(MobsA) def mbdt(summary, content): return ""+summary+"
"+content+"
" return "
\ "+summary+"\
"+content+"
" def mb_core(mb): buff="" buff+="Lvl: %s
\n" % (mb.mobpt) buff+="HP: %s
\n" % (mb.hp) buff+="ATK: %s
\n" % (mb.atk) buff+="DEF: %s/%s
\n" % (mb.dfn, mb.mdf) if mb.st != "": buff+="Modes: %s" % (mb.st) return buff def mb_eleg(mb): buff="" buff+="Race: %s
\n" % (WhatRace(mb)) buff+="Walk: %s
\n" % (fwalk(mb.walk)) buff+="Element: %s
\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("", "").replace("", ""))) 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="
"
    buff+="HP Range: %s ~ %s
\n" % (lhp, hhp) buff+="ATK Range: %s ~ %s
\n" % (lat, hat) buff+="Maximum XP: %s ~ %s
\n" % (lxp, hxp) buff+="DEF: %s / %s
\n" % (dfn, mdf) buff+="Drop, Move, Elegen, aspd
\n" buff+="
" return buff def mb_rdstat(mb): buff="
"
    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+="
" 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+="%s\n" % (mb.xp.replace(' ', ' ')) buff+="%s\n" % (mb.jp.replace(' ', ' ')) 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('

') wikib.write("Run at: " + datetime.datetime.now().isoformat()) wikib.write('
') wikib.write(""" Player Stats (melee warrior)
LevelStats 1Stats 2Average
00 str: 2 agi: 5 vit: 7 int:1 dex: 6 luk: 3 str: 2 agi: 5 vit: 7 int:1 dex: 6 luk: 3 str: 2 agi: 5 vit: 7 int:1 dex: 6 luk: 3
10 str:15 agi:10 vit: 5 int:1 dex:10 luk: 4 str:11 agi:11 vit: 6 int:1 dex:11 luk: 7 str:13 agi:11 vit: 5 int:1 dex:10 luk: 6
20 str:19 agi:10 vit:10 int:1 dex:20 luk:10 str:14 agi:19 vit: 8 int:1 dex:17 luk:11 str:17 agi:14 vit: 9 int:1 dex:18 luk:11
30 str:25 agi:30 vit:10 int:1 dex:20 luk:10 str:22 agi:28 vit:12 int:1 dex:21 luk:15 str:24 agi:29 vit:11 int:1 dex:20 luk:13
40 str:38 agi:30 vit:20 int:1 dex:25 luk:17 str:28 agi:35 vit:14 int:1 dex:32 luk:21 str:33 agi:33 vit:17 int:1 dex:28 luk:19
50 str:50 agi:40 vit:30 int:1 dex:25 luk:18 str:41 agi:41 vit:15 int:1 dex:41 luk:26 str:46 agi:41 vit:22 int:1 dex:33 luk:27
60 str:54 agi:50 vit:40 int:1 dex:35 luk:20 str:52 agi:52 vit:16 int:1 dex:45 luk:32 str:53 agi:51 vit:28 int:1 dex:40 luk:26
70 str:60 agi:60 vit:43 int:1 dex:50 luk:20 str:61 agi:61 vit:22 int:1 dex:51 luk:38 str:60 agi:61 vit:33 int:1 dex:50 luk:29
80 str:80 agi:60 vit:50 int:1 dex:50 luk:25 str:65 agi:71 vit:32 int:1 dex:60 luk:41 str:72 agi:66 vit:41 int:1 dex:55 luk:33
90 str:80 agi:70 vit:60 int:1 dex:60 luk:31 str:71 agi:71 vit:41 int:1 dex:71 luk:51 str:76 agi:70 vit:50 int:1 dex:66 luk:41
100 str:90 agi:80 vit:69 int:1 dex:60 luk:31 str:71 agi:81 vit:42 int:1 dex:81 luk:61 str:81 agi:80 vit:56 int:1 dex:70 luk:46
110 str:90 agi:90 vit:69 int:1 dex:70 luk:35 str:82 agi:82 vit:50 int:1 dex:82 luk:65 str:86 agi:86 vit:60 int:1 dex:76 luk:50
120 str:99 agi:90 vit:69 int:1 dex:70 luk:45 str:86 agi:86 vit:51 int:1 dex:86 luk:68 str:93 agi:88 vit:60 int:1 dex:78 luk:56
130 str:99 agi:91 vit:75 int:1 dex:70 luk:55 str:91 agi:90 vit:51 int:1 dex:90 luk:68 str:95 agi:91 vit:63 int:1 dex:80 luk:61
""") wikib.write('
') wikib.write("""

Elemental Count

%s%02d
%s%02d
%s%02d
%s%02d
%s%02d
%s%02d
%s%02d
%s%02d
%s%02d
""" % ( "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('') 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)