Last active
April 27, 2020 11:52
-
-
Save ygshi/2e91faa17974c0fe016fe9bddfc3d73c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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