MaxShein

Nahida - off-field damage calculation script

Oct 2nd, 2022 (edited)
356
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 16.28 KB | Gaming | 0 0
  1. #enemy
  2. res = 10
  3. defense = 0.5
  4.  
  5. #weapon
  6. class Weapon:
  7.     def __init__(self, name, b_atk, ctr, cdm, atk_p, em, dmg, em_to_atk, songs):
  8.         self.name = name
  9.         self.b_atk = b_atk
  10.         self.ctr = ctr
  11.         self.cdm = cdm
  12.         self.atk_p = atk_p
  13.         self.em = em
  14.         self.dmg = dmg
  15.         self.em_to_atk = em_to_atk
  16.         self.songs = songs
  17.  
  18. #weapons
  19. ThrillingTalesofDragonSlayers = Weapon("Thrilling Tales of Dragon Slayers R5", 401.29, 0, 0, 0, 0, 0, 0, [])
  20. MagicGuide = Weapon("Magic Guide R5", 354.38, 0, 0, 0, 187.44, 24, 0, [])
  21. TwinNephrite = Weapon("Twin Nephrite R5", 448.22, 15.62, 0, 20, 0, 0, 0, [])
  22. FavoniusCodex = Weapon("Favonius Codex", 509.61, 0, 0, 0, 0, 0, 0, [])
  23. TheWidsithRecitative = Weapon("The Widsith - Recitative", 509.61, 0, 55.13, 20, 0, 0, 0, [])
  24. TheWidsithAria = Weapon("The Widsith - Aria", 509.61, 0, 55.13, 0, 0, 16, 0, [])
  25. TheWidsithInterlude = Weapon("The Widsith - Interlude", 509.61, 0, 55.13, 0, 80, 0, 0, [])
  26. TheWidsith = Weapon("The Widsith", 509.61, 0, 55.13, 0, 0, 0, 0, [TheWidsithRecitative,TheWidsithAria,TheWidsithInterlude])
  27. TheWidsithRecitativeR5 = Weapon("The Widsith R5 - Recitative", 509.61, 0, 55.13, 40, 0, 0, 0, [])
  28. TheWidsithAriaR5 = Weapon("The Widsith R5 - Aria", 509.61, 0, 55.13, 0, 0, 32, 0, [])
  29. TheWidsithInterludeR5 = Weapon("The Widsith R5 - Interlude", 509.61, 0, 55.13, 0, 160, 0, 0, [])
  30. TheWidsithR5 = Weapon("The Widsith R5", 509.61, 0, 55.13, 0, 0, 0, 0, [TheWidsithRecitativeR5,TheWidsithAriaR5,TheWidsithInterludeR5])
  31. SacrificialFragments = Weapon("Sacrificial Fragments", 454.36, 0, 0, 0, 220.51, 0, 0, [])
  32. SolarPearl = Weapon("Solar Pearl", 509.61, 27.56, 0, 0, 0, 10, 0, [])
  33. SolarPearlR5 = Weapon("Solar Pearl R5", 509.61, 27.56, 0, 0, 0, 20, 0, [])
  34. MappaMare = Weapon("Mappa Mare", 564.78, 0, 0, 0, 110.26, 8, 0, [])
  35. MappaMareR5 = Weapon("Mappa Mare R5", 564.78, 0, 0, 0, 110.26, 16, 0, [])
  36. BlackcliffAgate = Weapon("Blackcliff Agate", 509.61, 0, 55.13, 0, 0, 0, 0, [])
  37. HakushinRing = Weapon("Hakushin Ring", 564.78, 0, 0, 0, 0, 5, 0, [])
  38. HakushinRingR5 = Weapon("Hakushin Ring R5", 564.78, 0, 0, 0, 0, 10, 0, [])
  39. OathswornsEye = Weapon("Oathsworn’s Eye R5", 564.78, 0, 0, 27.56, 0, 0, 0, [])
  40. WanderingEvenstar = Weapon("Wandering Evenstar", 509.61, 0, 0, 0, 165.38, 0, 24, [])
  41. WanderingEvenstarR5 = Weapon("Wandering Evenstar R5", 509.61, 0, 0, 0, 165.38, 0, 48, [])
  42. FruitofFulfillment = Weapon("Fruit of Fulfillment", 509.61, 0, 0, -25, 120, 0, 0, [])
  43. FruitofFulfillmentR5 = Weapon("Fruit of Fulfillment R5", 509.61, 0, 0, -25, 180, 0, 0, [])
  44. SkywardAtlas = Weapon("Skyward Atlas", 674.33, 0, 0, 33.08, 0, 12, 0, [])
  45. SkywardAtlasR5 = Weapon("Skyward Atlas R5", 674.33, 0, 0, 33.08, 0, 24, 0, [])
  46. LostPrayertotheSacredWinds = Weapon("Lost Prayer to the Sacred Winds", 608.07, 33.08, 0, 0, 0, 0, 0, [])
  47. KagurasVerity = Weapon("Kagura’s Verity", 608.07, 0, 66.15, 0, 0, 48, 0, [])
  48. KagurasVerityR5 = Weapon("Kagura’s Verity R5", 608.07, 0, 66.15, 0, 0, 96, 0, [])
  49. AThousandFloatingDreams = Weapon("A Thousand Floating Dreams - No dendro", 541.83, 0, 0, 0, 264.61, 30, 0, [])
  50. AThousandFloatingDreamsDendro = Weapon("A Thousand Floating Dreams - One dendro", 541.83, 0, 0, 0, 296.61, 20, 0, [])
  51. AThousandFloatingDreamsR5 = Weapon("A Thousand Floating Dreams R5 - No dendro", 541.83, 0, 0, 0, 264.61, 78, 0, [])
  52. AThousandFloatingDreamsDendroR5 = Weapon("A Thousand Floating Dreams R5 - One dendro", 541.83, 0, 0, 0, 328.61, 20, 0, [])
  53. #books = [ThrillingTalesofDragonSlayers,MagicGuide,TwinNephrite,TheWidsith,TheWidsithR5,SacrificialFragments,SolarPearl,SolarPearlR5,MappaMare,MappaMareR5,BlackcliffAgate,HakushinRing,HakushinRingR5,OathswornsEye,WanderingEvenstar,WanderingEvenstarR5,FruitofFulfillment,FruitofFulfillmentR5,SkywardAtlas,SkywardAtlasR5,LostPrayertotheSacredWinds,KagurasVerity,KagurasVerityR5,AThousandFloatingDreams,AThousandFloatingDreamsR5]
  54. books = [MagicGuide,TheWidsith,TheWidsithR5,SacrificialFragments,SolarPearl,SolarPearlR5,MappaMare,MappaMareR5,BlackcliffAgate,HakushinRing,HakushinRingR5,OathswornsEye,WanderingEvenstar,WanderingEvenstarR5,FruitofFulfillment,FruitofFulfillmentR5,SkywardAtlas,SkywardAtlasR5,LostPrayertotheSacredWinds,KagurasVerity,KagurasVerityR5,AThousandFloatingDreams,AThousandFloatingDreamsR5]
  55.  
  56. #substats
  57. start_rolls = 3
  58. max_rolls_p_art = 4
  59. atk_p_roll = 5
  60. ctr_roll = 3.3
  61. cdm_roll = 6.6
  62. em_roll = 20
  63. #max_rolls_p_art = 5
  64. #atk_p_roll = 5.8
  65. #ctr_roll = 3.9
  66. #cdm_roll = 7.8
  67. #em_roll = 23
  68.  
  69. #stats
  70. class Stats:
  71.     def __init__(self, first, name, atk_p, ctr, cdm, em, dmg, sands, cup, cap):
  72.         self.name = name
  73.         self.atk_p = atk_p
  74.         self.ctr = ctr
  75.         self.cdm = cdm
  76.         self.f_atk = 311
  77.         self.em = em
  78.         self.ctr = ctr
  79.         self.cdm = cdm
  80.         self.dmg = dmg
  81.         self.sand = sands
  82.         self.cup = cup
  83.         self.cap = cap
  84.         if first and start_rolls > 0:
  85.             self.atk_p += max(0, min(start_rolls, 2 + sands[0] + cup[0] + cap[0])) * atk_p_roll
  86.             self.ctr += max(0, min(start_rolls, 2 + sands[1] + cup[1] + cap[1])) * ctr_roll
  87.             self.cdm += max(0, min(start_rolls, 2 + sands[2] + cup[2] + cap[2])) * cdm_roll
  88.             self.em += max(0, min(start_rolls, 2 + sands[3] + cup[3] + cap[3])) * em_roll
  89.            
  90. #AtkElCtr = Stats(True, "ATK%/Elemental/Crit Rate", 46.6, 31.1, 0, 0, 46.6, [0,1,1,1], [1,1,1,1], [1,0,1,1])
  91. #AtkElCdm = Stats(True, "ATK%/Elemental/Crit DMG", 46.6, 0, 62.2, 0, 46.6, [0,1,1,1], [1,1,1,1], [1,1,0,1])
  92. EmElCtr = Stats(True, "EM/Elemental/Crit Rate", 0, 31.1, 0, 187, 46.6, [1,1,1,0], [1,1,1,1], [1,0,1,1])
  93. EmElCdm = Stats(True, "EM/Elemental/Crit DMG", 0, 0, 62.2, 187, 46.6, [1,1,1,0], [1,1,1,1], [1,1,0,1])
  94. EmElCrt = Stats(True, "EM/Elemental/Crit", 0, 15.55, 31.1, 187, 46.6, [1,1,1,0], [1,1,1,1], [1,1,1,1])
  95. EmEmCtr = Stats(True, "EM/EM/Crit Rate", 0, 31.1, 0, 374, 0, [1,1,1,0], [1,1,1,0], [1,0,1,1])
  96. EmEmCdm = Stats(True, "EM/EM/Crit DMG", 0, 0, 62.2, 374, 0, [1,1,1,0], [1,1,1,0], [1,1,0,1])
  97. EmEmCrt = Stats(True, "EM/EM/Crit", 0, 15.55, 31.1, 374, 0, [1,1,1,0], [1,1,1,0], [1,1,1,1])
  98. #AtkElEm = Stats(True, "ATK%/Elemental/EM", 46.6, 0, 0, 187, 46.6, [0,1,1,1], [1,1,1,1], [1,1,1,0])
  99. EmElEm = Stats(True, "EM/Elemental/EM", 0, 0, 0, 374, 46.6, [1,1,1,0], [1,1,1,1], [1,1,1,0])
  100. EmEmEm = Stats(True, "EM/EM/EM", 0, 0, 0, 561, 0, [1,1,1,0], [1,1,1,1], [1,1,1,0])
  101. stats = [EmElCrt, EmEmCrt, EmElEm, EmEmEm]
  102.  
  103. #buffs
  104. class Buff:
  105.     def __init__(self, name, atk_p, em, dmg, res):
  106.         self.name = name
  107.         self.atk_p = atk_p
  108.         self.em = em
  109.         self.dmg = dmg
  110.         self.res = res
  111.  
  112. ToM = Buff("ToM", 20, 0, 0, 0)
  113. Zhongli = Buff("Zhongli", 0, 0, 0, -20)
  114. Instructor = Buff("Instructor", 0, 120, 0, 0)
  115. DeepwoodMemoriesBuff = Buff("Deepwood memories", 0, 0, 0, -30)
  116.  
  117. #set
  118. class Set:
  119.     def __init__(self, name, atk_p, em, dmg):
  120.         self.name = name
  121.         self.atk_p = atk_p
  122.         self.f_atk = 311
  123.         self.em = em
  124.         self.dmg = dmg
  125.  
  126. Thundersoother = Set("Thundersoother", 0, 0, 35)
  127. DeepwoodMemories = Set("Deepwood Memories", 0, 0, 15)
  128. GildedDreamsDendro = Set("Gilded Dreams, One dendro", 14, 180, 0)
  129. GildedDreams = Set("Gilded Dreams, No dendro", 0, 230, 0)
  130. ElAtk = Set("El/Atk% 2-piece", 18, 0, 15)
  131. AtkAtk = Set("Atk%/Atk% 2-piece", 36, 0, 0)
  132. ElEm = Set("El/EM 2-piece", 0, 80, 15)
  133. EmAtk = Set("EM/Atk% 2-piece", 18, 80, 0)
  134. EmEm = Set("EM/EM 2-piece", 0, 160, 0)
  135. sets = [Thundersoother,DeepwoodMemories,GildedDreams]
  136.  
  137. #character
  138. class Character:
  139.     def __init__(self, name, b_atk, ctr, cdm, dmg, em):
  140.         self.name = name
  141.         self.b_atk = b_atk
  142.         self.dmg = dmg
  143.         self.ctr = ctr
  144.         self.cdm = cdm
  145.         self.em = em
  146.  
  147. Nahida = Character("Nahida", 298.97, 5, 50, 0, 115.2)
  148. #C4
  149. #Nahida.em += 160
  150.  
  151. #calculation
  152. class Result:
  153.     def __init__(self, weapon, artSet, stat, atk, em, ctr, cdm, dmg, dps, av, crit):
  154.         self.weapon = weapon
  155.         self.artSet = artSet
  156.         self.stats = [stat.name]
  157.         self.atk = atk
  158.         self.em = em
  159.         self.ctr = ctr
  160.         self.cdm = cdm
  161.         self.dmg = dmg
  162.         self.dps = [dps]
  163.         self.av = av
  164.         self.crit = crit
  165.         self.second = ""
  166.         self.difference = 0.001
  167.  
  168. pyro = 0
  169. pyro_bonus = [0, 20.02, 30.1]
  170. electro = 2
  171. interval = 1.9
  172. electro_reduction = [0, 0.3, 0.45]
  173. interval -= electro_reduction[electro]
  174. icd = 2.5
  175. #icd = 0
  176. icd = max(icd, interval)
  177.  
  178. def Spread(em):
  179.     bonus = 5 * em / (em + 1200)
  180.     return 1663.88 * (1 + bonus)
  181.  
  182. def evaluate(character, weapon, artSet, stats, buffs):
  183.     stat = Stats(False, stats.name, stats.atk_p, stats.ctr, stats.cdm, stats.em, stats.dmg, stats.sand, stats.cup, stats.cap)
  184.     for i in range(max_rolls_p_art):
  185.         artifact(stat.cap, character,  weapon, artSet, stat, buffs)
  186.         artifact(stat.sand, character,  weapon, artSet, stat, buffs)
  187.         artifact(stat.cup, character,  weapon, artSet, stat, buffs)
  188.         artifact([1,1,1,1], character,  weapon, artSet, stat, buffs)
  189.         artifact([1,1,1,1], character,  weapon, artSet, stat, buffs)
  190.     result = calculate(character, weapon, artSet, stat, buffs)
  191.     if len(weapon.songs) > 0:
  192.         dps = 0
  193.         av = 0
  194.         for song in range(0, len(weapon.songs)):
  195.             newResult = calculate(character, weapon.songs[song], artSet, stat, buffs)
  196.             dps += newResult.dps[0]
  197.             av += newResult.av
  198.             result.crit = max(result.crit, newResult.crit)
  199.         result.dps = [dps / len(weapon.songs)]
  200.         result.av = av / len(weapon.songs)
  201.     return result
  202.  
  203. def artifact(weights, character, weapon, artSet, stat, buffs):
  204.     stat.atk_p += atk_p_roll * weights[0]
  205.     dmg1 = test(character, weapon, artSet, stat, buffs)
  206.     stat.atk_p -= atk_p_roll * weights[0]
  207.     stat.ctr += ctr_roll * weights[1]
  208.     dmg2 = test(character, weapon, artSet, stat, buffs)
  209.     stat.ctr -= ctr_roll * weights[1]
  210.     stat.cdm += cdm_roll * weights[2]
  211.     dmg3 = test(character, weapon, artSet, stat, buffs)
  212.     stat.cdm -= cdm_roll * weights[2]
  213.     stat.em += em_roll * weights[3]
  214.     dmg4 = test(character, weapon, artSet, stat, buffs)
  215.     stat.em -= em_roll * weights[3]
  216.  
  217.     top = max(dmg1, dmg2, dmg3, dmg4)
  218.     if top == dmg1:
  219.         print("Rolled Atk%!")
  220.         stat.atk_p += atk_p_roll * weights[0]
  221.     elif top == dmg2:
  222.         #print("Rolled Crit Rate!")
  223.         stat.ctr += ctr_roll * weights[1]
  224.     elif top == dmg3:
  225.         #print("Rolled Crit DMG!")
  226.         stat.cdm += cdm_roll * weights[2]
  227.     elif top == dmg4:
  228.         #print("Rolled EM!")
  229.         stat.em += em_roll * weights[3]
  230.  
  231. def test(character, weapon, artSet, stat, buffs):
  232.     if len(weapon.songs) <= 0:
  233.         return calculate(character, weapon, artSet, stat, buffs).dps
  234.     else:
  235.         dps = 0
  236.         for song in range(0, len(weapon.songs)):
  237.             dps += calculate(character, weapon.songs[song], artSet, stat, buffs).dps[0]
  238.         return dps / len(weapon.songs)
  239.  
  240. def calculate(character, weapon, artSet, stat, buffs):
  241.     em = character.em + weapon.em + stat.em + artSet.em
  242.     bonus_dmg = character.dmg + weapon.dmg + stat.dmg + artSet.dmg + pyro_bonus[pyro]
  243.     atk_p = weapon.atk_p + stat.atk_p + artSet.atk_p
  244.     f_atk = stat.f_atk
  245.     ctr = character.ctr + weapon.ctr + stat.ctr
  246.     cdm = character.cdm + weapon.cdm + stat.cdm
  247.    
  248.     global res
  249.     resistance = res
  250.  
  251.     for i in range(0, len(buffs)):
  252.         atk_p += buffs[i].atk_p
  253.         em += buffs[i].em
  254.         bonus_dmg += buffs[i].dmg
  255.         resistance += buffs[i].res
  256.     if resistance < 0:
  257.         resistance /= 2
  258.        
  259.     bonus_bonus_dmg = min(80, max(0, (round(em) - 200) * 0.1))
  260.     bonus_dmg += bonus_bonus_dmg
  261.     bonus_ctr = min(24, max(0, (round(em) - 200) * 0.03))
  262.     ctr += bonus_ctr
  263.     ctr = min(ctr, 100)
  264.    
  265.     atk = (character.b_atk + weapon.b_atk) * (1 + atk_p / 100) + f_atk
  266.     atk += em * weapon.em_to_atk / 100
  267.  
  268.     damage = 185.76 / 100 * atk + 371.52 / 100 * em
  269.     damage *= defense
  270.     damage *= 1 + bonus_dmg / 100
  271.     damage /= 1 + resistance / 100
  272.     spread = Spread(em) * defense
  273.     spread *= 1 + bonus_dmg / 100
  274.     spread /= 1 + resistance / 100
  275.     crit = damage + spread
  276.     crit *= 1 + cdm / 100
  277.     damage *= 1 + ctr / 100 * cdm / 100
  278.     spread *= 1 + ctr / 100 * cdm / 100
  279.     av = damage + spread
  280.     dps = damage / interval + spread / icd
  281.  
  282.     return Result(weapon, artSet, stat, atk, em, ctr, cdm, bonus_dmg, dps, av, crit)
  283.  
  284. def printResult(result):
  285.     print("======================================================================")
  286.     print(result.weapon.name)
  287.     print("Best set: " + result.artSet.name)
  288.     if not result.second == "":
  289.         print("Second best: " + result.second1)
  290.         print("Difference: " + str(round(result.difference1 * 100 - 100, 2)) + "%")
  291.     if len(result.dps) == 1:
  292.         print("Best main stat: " + result.stats[0])
  293.     else:
  294.         print("Main stats ranking:")
  295.         for i in range(len(result.stats)):
  296.             print(result.stats[i] + " - dps: " + str(round(result.dps[i], 2)))
  297.     print()
  298.     print("Best stats for this weapon:")
  299.     print("Atk: " + str(round(result.atk, 2)))
  300.     print("EM: " + str(round(result.em, 2)))
  301.     print("Crit Rate: " + str(round(result.ctr, 2)))
  302.     print("Crit DMG: " + str(round(result.cdm, 2)))
  303.     print("Total DMG bonus: " + str(round(result.dmg, 2)))
  304.     print()
  305.     print("Best DPS: " + str(round(result.dps[0], 2)))
  306.     print("Best Avg spread hit: " + str(round(result.av, 2)))
  307.     print("Biggest crit hit: " + str(round(result.crit, 2)))
  308.     print()
  309.  
  310. def testWeapons(weapons, artSets, stats, buffs):
  311.     for i in range(0, len(weapons)):
  312.         result = testSets(weapons[i], artSets, stats, buffs)
  313.         printResult(result)
  314.  
  315. def testSets(weapon, artSets, stats, buffs):
  316.     result = testStats(weapon, artSets[0], stats, buffs)
  317.     if len(artSets) <= 1:
  318.         return result
  319.     for i in range(1, len(artSets)):
  320.         newResult = testStats(weapon, artSets[i], stats, buffs)
  321.         if newResult.dps > result.dps:
  322.             newResult.second = result.artSet.name
  323.             newResult.difference = newResult.dps / result.dps
  324.             result = newResult
  325.         else:
  326.             gain = newResult.dps[0] / result.dps[0]
  327.             if gain > 1 / result.difference:
  328.                 result.second = newResult.stat.name
  329.                 result.difference = 1 / gain
  330.     return result
  331.  
  332. def testStats(weapon, artSet, stats, buffs):
  333.     result = evaluate(Nahida, weapon, artSet, stats[0], buffs)
  334.     if len(stats) <= 1:
  335.         return result
  336.     for i in range(1, len(stats)):
  337.         newResult = evaluate(Nahida, weapon, artSet, stats[i], buffs)
  338.         if newResult.dps[0] > result.dps[0]:
  339.             newResult.dps += result.dps
  340.             newResult.stats += result.stats
  341.             result = newResult
  342.         else:
  343.             for x in range(0, len(result.stats)):
  344.                 if newResult.dps[0] > result.dps[x]:
  345.                     result.dps.insert(x, newResult.dps[0])
  346.                     result.stats.insert(x, newResult.stats[0])
  347.                     break
  348.                 if x == len(result.stats) - 1:
  349.                     result.dps.append(newResult.dps[0])
  350.                     result.stats.append(newResult.stats[0])
  351.     return result
  352.  
  353. print("Weapon comparison:")
  354. testWeapons(books, [GildedDreams], stats, [DeepwoodMemoriesBuff])
  355.  
  356. if True:
  357.     print("######################################################################")
  358.     print("Artifact set comparison with Magic Guide:")
  359.     print()
  360.     printResult(testStats(MagicGuide, GildedDreams, stats, [DeepwoodMemoriesBuff]))
  361.     printResult(testStats(MagicGuide, Thundersoother, stats, [DeepwoodMemoriesBuff]))
  362.     printResult(testStats(MagicGuide, GildedDreams, stats, []))
  363.     printResult(testStats(MagicGuide, DeepwoodMemories, stats, [DeepwoodMemoriesBuff]))
  364.  
  365. if True:
  366.     print("######################################################################")
  367.     print("Artifact set comparison with A Thousand Floating Dreams - No dendro teammate:")
  368.     print()
  369.     printResult(testStats(AThousandFloatingDreams, GildedDreams, stats, [DeepwoodMemoriesBuff]))
  370.     printResult(testStats(AThousandFloatingDreams, Thundersoother, stats, [DeepwoodMemoriesBuff]))
  371.     printResult(testStats(AThousandFloatingDreams, GildedDreams, stats, []))
  372.     printResult(testStats(AThousandFloatingDreams, DeepwoodMemories, stats, [DeepwoodMemoriesBuff]))
  373.  
Advertisement
Add Comment
Please, Sign In to add comment