Skip to content

Instantly share code, notes, and snippets.

@ygshi
Last active April 27, 2020 11:52
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ygshi/2e91faa17974c0fe016fe9bddfc3d73c to your computer and use it in GitHub Desktop.
Save ygshi/2e91faa17974c0fe016fe9bddfc3d73c to your computer and use it in GitHub Desktop.
import numpy as np
import random as rd
#settings-----------
#damage and stun settings---------------
mh_hit_damage_all_types=[341448,2134432] #read from PoB; 2 integers.
mh_hit_damage_physical=[341448,2134432] #read from PoB; 2 integers.
mh_att_per_second=6.12 #read from PoB; decimal number.
stun_threshold_reduction=106 #read from tooltip; integer.
stun_duration_modifier=330 #read from tooltip; integer.
double_stun_duration=35 #it's your chance to double stun duration; integer.
#double damage and Ruthless settings-----------
enable_double_damage=1 #set to 1 if there's chance for double damage.
double_damage_chance=91 #set double damage chance; integer.
enable_ruthless=1 #set to 1 if Ruthless gem used.
ruthless_multi=132 #set ruthless multiplier; 132 should be default; integer.
#Multistrike settings-----------
enable_multistrike=0 #set to 1 if Multistrike gem used.
multi_repeat_1=122 #set multistrike 1st repeat multiplier; 122 should be default; integer.
multi_repeat_2=144 #set multistrike 2nd repeat multiplier; 144 should be default; integer.
enable_awakened_multistrike=1 #set 1 to if Awakened Multistrike gem used.
a_multi_repeat_1=120 #set awakened multistrike 1st repeat multiplier; 120 should be default; integer.
a_multi_repeat_2=140 #set awakened multistrike 2nd repeat multiplier; 140 should be default; integer.
a_multi_repeat_3=160 #set awakened multistrike 3rd repeat multiplier; 160 should be default; integer.
#crit settings---------------
enable_crit=0 #set to 1 if Resolute Technique isn't picked.
if_lucky=1 #set to 1 if crit chance is lucky.
hit_chance=82 #read from PoB; integer.
crit_chance=50.00 #read from PoB; not the effective crit chance; decimal number.
crit_multiplier=665 #read from PoB; integer.
#curse settings--------------
enable_warlords_mark=0 #set to 1 if Warlords Mark used.
enable_temporal_chains=0 #set to 1 if Temporal Chains used.
curse_effectiveness=0 #set increased curse effectiveness; integer.
#cull settings---------------
enable_slayer_cull=0 #set to 1 if Slayer ascendancy Bane of Legends picked.
enable_cull=1 #set to 1 if Skull Cracking passive notable picked or have other sources of culling.
#other settings--------------
simulation_time=3600 #set simulated time in unit of seconds; integer.
#end of settings-------------
def load():
global atkmin,atkmlt,phys_bonus,atkint,effhp,dschns,curefft,durm,cull_factor,ruthc,multic,time
atkmin=np.float(mh_hit_damage_all_types[0])/1000.
atkmax=np.float(mh_hit_damage_all_types[1])/1000.
atkmlt=1000.*atkmin/(atkmax-atkmin)
physmin=np.float(mh_hit_damage_physical[0])/1000.
physmax=np.float(mh_hit_damage_physical[1])/1000.
phys_bonus = 1. + 0.25 * (physmin + physmax) / (atkmin + atkmax)
atkint=np.int(1000./np.float(mh_att_per_second))
tstr=np.float(stun_threshold_reduction)
rstr=1.-((tstr-75.)/(tstr-50.))
effhp=boss_life*0.25*rstr
dschns=double_stun_duration
curefft = (100. + np.float(curse_effectiveness)) * 0.01 * 0.34
tsdm=np.float(stun_duration_modifier)
if (enable_warlords_mark == 1):
tsdm = tsdm + 30. * curefft
durm=1.+tsdm/100.
if (enable_temporal_chains == 1):
durm = durm * (1. + 0.14 * curefft)
cull_factor = 1.
if (enable_cull == 1):
cull_factor = 0.9
if (enable_slayer_cull == 1):
cull_factor = 0.8
ruthc=1
multic=1
time=np.linspace(0,simulation_time*1000-1,simulation_time*1000)
def doubledf():
if (enable_double_damage == 1):
if (rd.randint(1, 100) <= double_damage_chance):
return 2.
return 1.
def critf():
if (enable_crit == 1):
if (rd.randint(1,100) > hit_chance):
return 0.
if (rd.randint(1,100) > hit_chance):
return 1.
temp = np.float(crit_multiplier) / 100.
if (rd.randint(1,10000) <= np.float(crit_chance) * 100.):
return temp
if (if_lucky == 1) and (rd.randint(1,10000) <= np.float(crit_chance) * 100.):
return temp
return 1.
def atkdmg():
temp = atkmin * (1. + np.float(rd.randint(0, 1000)) / atkmlt)
temp = temp * doubledf() * critf()
if (enable_ruthless == 1):
temp = temp * 3. / (3. + np.float(ruthless_multi) / 100.)
if (enable_double_damage == 1):
temp = temp / (1. + np.float(double_damage_chance) / 100.)
if (enable_awakened_multistrike == 1):
temp = temp * 400. / (100. + np.float(a_multi_repeat_1) + np.float(a_multi_repeat_2) + np.float(a_multi_repeat_3))
elif (enable_multistrike == 1):
temp = temp * 300. / (100. + np.float(multi_repeat_1) + np.float(multi_repeat_2))
return temp
def ruthl():
global ruthc
if (enable_ruthless == 1):
temp = (1. + np.float(ruthless_multi) / 100.)
if (enable_awakened_multistrike == 1):
if (ruthc < 9):
ruthc = ruthc + 1
return 1.
if (ruthc >= 9):
if (ruthc == 12):
ruthc = 1
return temp
ruthc = ruthc + 1
return temp
elif (enable_multistrike == 1):
if (ruthc < 7):
ruthc = ruthc + 1
return 1.
if (ruthc >= 7):
if (ruthc == 9):
ruthc = 1
return temp
ruthc = ruthc + 1
return temp
if (ruthc < 3):
ruthc = ruthc + 1
return 1.
if (ruthc == 3):
ruthc = 1
return temp
else:
return 1.
def multim():
global multic
if (enable_awakened_multistrike == 1):
if (multic == 1):
multic = multic + 1
return 1.
if (multic == 2):
multic = multic + 1
return np.float(a_multi_repeat_1)/100.
if (multic == 3):
multic = multic + 1
return np.float(a_multi_repeat_2)/100.
if (multic == 4):
multic = 1
return np.float(a_multi_repeat_3)/100.
elif (enable_multistrike == 1):
if (multic == 1):
multic = multic + 1
return 1.
if (multic == 2):
multic = multic + 1
return np.float(multi_repeat_1)/100.
if (multic == 3):
multic = 1
return np.float(multi_repeat_2)/100.
return 1.
def ifstun(totdmg):
stunch = np.int(20000. * totdmg * phys_bonus / effhp)
if (enable_warlords_mark == 1):
stunch = stunch + 1000. * curefft
if (stunch < 2000):
return 0
if (rd.randint(1, 10000) > stunch):
return 0
else:
return 1
def stundur():
ruthlim=3
if (enable_awakened_multistrike == 1):
ruthlim=9
elif (enable_multistrike == 1):
ruthlim=7
if (ruthc < ruthlim):
if (rd.randint(1, 100) <= dschns):
return np.int(700 * durm)
else:
return np.int(350 * durm)
if (ruthc >= ruthlim):
if (rd.randint(1, 100) <= dschns):
return np.int(1600 * durm)
else:
return np.int(800 * durm)
def calc():
load()
record=[]
dmgdone=0
atkcnt=0
stunrt=0
for i in time:
if (i == atkint * atkcnt):
atkcnt = atkcnt + 1
totdmg = atkdmg() * ruthl() * multim()
dmgdone = dmgdone + totdmg
if (ifstun(totdmg) == 1):
if (stundur() > stunrt):
stunrt = stundur()
if (stunrt > 0):
record.append(1)
stunrt = stunrt - 1
else:
record.append(0)
return (record, dmgdone)
def analyze():
somearray=[[],0]
somearray=calc()
arraycount=0
firstone=-1
locks=[0]
nlock=-1
prev=0
lockchance=0
for i in somearray[0]:
if (i == 1) and (firstone == -1):
firstone = arraycount
if (i == 1) and (prev == 0):
nlock = nlock + 1
locks.append(0)
if (i == 1):
locks[nlock] = locks[nlock] + 1
arraycount = arraycount + 1
prev = i
uptime = np.float(np.sum(locks)) / np.float(simulation_time * 1000. - firstone)
dmgneeded = boss_life * cull_factor * phase_factor
if (phase_factor == 25):
dmgneeded = boss_life * 75. / 100.
killtime = np.int(dmgneeded / somearray[1] * simulation_time * 1000)
for i in locks:
if (i >= killtime):
lockchance = lockchance + i - killtime + 1
lockchance = np.float(lockchance) / np.float(simulation_time * 1000 - firstone - killtime)
return (uptime, lockchance)
def fight(para1, para2, boss_name):
global boss_life, phase_factor
boss_life=para1
phase_factor=para2
answer=[0,0]
answer=analyze()
print boss_name
print 'Percentage of stun up-time', "%.2f" %(answer[0]*100.), '%'
print 'Chance of perfect stun-locking', "%.2f" %(answer[1]*100.), '%'
print ''
def main():
print 'Start simulating boss fights with total duration of', simulation_time, 'seconds. Please be patient.'
print ''
fight(8000., 1., "T15") #estimation
fight(16500., 1./3., "Uber_Izaro")
fight(25100., 1., "Guardian") #lower 2 guardians
fight(46600., 25, "Elder") #Uber Elder only a tiny bit higher
fight(74700., 0.5, "Shaper")
fight(86900., 0.5, "A8 Sirus")
print 'End.'
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment