Alyssa

Hypixel Skyblock Damage Optimizer

Aug 9th, 2019
3,145
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 13.86 KB | None | 0 0
  1. import itertools
  2. import math
  3. # TODO: Configurable weapons / num talismans / potions / base stats / etc.
  4.  
  5. combat_level = 18
  6.  
  7. def num_combinations(elements, size):
  8.     # Return the number of combinations (With replacement) for a given number of elements choosing a size of them
  9.     return math.factorial(size + elements - 1) / ( math.factorial(size) * math.factorial(elements - 1))
  10.  
  11. def calc_max_crit_chances(reforges, valid_reforges, amounts):
  12.     output = {}
  13.     for rarity in valid_reforges:
  14.         highest = 0
  15.         for name in valid_reforges[rarity]:
  16.             if rarity == "common":
  17.                 crit_chance = reforges[name].common.crit_chance
  18.             elif rarity == "uncommon":
  19.                 crit_chance = reforges[name].uncommon.crit_chance
  20.             elif rarity == "rare":
  21.                 crit_chance = reforges[name].rare.crit_chance
  22.             elif rarity == "epic":
  23.                 crit_chance = reforges[name].epic.crit_chance
  24.             elif rarity == "legendary":
  25.                 crit_chance = reforges[name].legendary.crit_chance
  26.             crit_chance *= amounts[rarity]
  27.             if crit_chance > highest:
  28.                 highest = crit_chance
  29.         output[rarity] = highest
  30.     return output
  31.            
  32. def calc_crit_requirements(base_stats, max_crit_chances, order):
  33.     output = {}
  34.     for x in range(0, len(order)-1):
  35.         current_rarity = order[x]
  36.         total_remaining = 0
  37.         for y in range(x, len(order)):
  38.             remaining_rarity = order[y]
  39.             total_remaining += max_crit_chances[remaining_rarity]
  40.         output[current_rarity] =  100 - (total_remaining + base_stats.crit_chance)
  41.     return output
  42.  
  43. class Stats:
  44.     def __init__(self, damage = 0, strength = 0, crit_chance = 0, crit_dmg = 0, atk_speed = 0, health = 0, defense = 0, speed = 0, intelligence = 0):
  45.         self.damage = damage # Reforges can't give this, it's a damage modifier
  46.         self.strength = strength
  47.         self.crit_chance = crit_chance
  48.         self.crit_dmg = crit_dmg
  49.         self.atk_speed = atk_speed
  50.         self.health = health
  51.         self.defense = defense
  52.         self.speed = speed
  53.         self.intelligence = intelligence
  54.    
  55.     def calc_normal_damage(self):
  56.         return (5 + self.damage + math.floor(self.strength / 5)) * (1 + (self.strength / 100))
  57.    
  58.     def calc_crit_damage(self):
  59.         return self.calc_normal_damage() * (1 + (self.crit_dmg / 100))
  60.    
  61.     def calc_avg_damage(self, enchantments = []):
  62.         normal_damage = self.calc_damage(False, enchantments)
  63.         crit_damage = self.calc_damage(True, enchantments)
  64.         return (crit_damage * (self.crit_chance / 100)) + (normal_damage * (1 - (self.crit_chance / 100)))
  65.    
  66.     def calc_damage(self, is_crit, enchantments = []):
  67.         base_dmg = self.calc_normal_damage()
  68.         dmg = base_dmg
  69.         sharpness_dmg = 0
  70.         gk_dmg = 0
  71.         for enchantment in enchantments:
  72.             if enchantment.id == "sharpness":
  73.                 dmg += (enchantment.level * 0.05) * base_dmg
  74.                 sharpness_dmg = (enchantment.level * 0.05) * base_dmg
  75.             elif enchantment.id == "giant_killer":
  76.                 dmg += 0.25 * base_dmg
  77.                 gk_dmg = 0.25 * base_dmg
  78.             elif enchantment.id == "first_strike":
  79.                 dmg += 0.25 * enchantment.level * base_dmg
  80.         dmg += (combat_level * 0.04) * (base_dmg + sharpness_dmg + gk_dmg)
  81.         if is_crit:
  82.             dmg *= (1 + (self.crit_dmg / 100))
  83.         return dmg
  84.    
  85.     def add_stats(self, damage = 0, strength = 0, crit_chance = 0, crit_dmg = 0, atk_speed = 0, health = 0, defense = 0, speed = 0, intelligence = 0):
  86.         self.damage += damage
  87.         self.strength += strength
  88.         self.crit_chance += crit_chance
  89.         self.crit_dmg += crit_dmg
  90.         self.atk_speed += atk_speed
  91.         self.health += health
  92.         self.defense += defense
  93.         self.speed += speed
  94.         self.intelligence += intelligence
  95.    
  96.     def __add__(self, other):
  97.         return Stats(
  98.             damage = self.damage + other.damage,
  99.             strength = self.strength + other.strength,
  100.             crit_chance = self.crit_chance + other.crit_chance,
  101.             crit_dmg = self.crit_dmg + other.crit_dmg,
  102.             atk_speed = self.atk_speed + other.atk_speed,
  103.             health = self.health + other.health,
  104.             defense = self.defense + other.defense,
  105.             speed = self.speed + other.speed,
  106.             intelligence = self.intelligence + other.intelligence
  107.         )
  108.    
  109.     def __iadd__(self, other):
  110.         self.add_stats(other.damage, other.strength, other.crit_chance, other.crit_dmg, other.atk_speed, other.health, other.defense, other.speed, other.intelligence)
  111.         return self
  112.    
  113.     def __str__(self):
  114.         return str({
  115.             "damage": self.damage,
  116.             "strength": self.strength,
  117.             "crit_chance": self.crit_chance,
  118.             "crit_dmg": self.crit_dmg,
  119.             "atk_speed": self.atk_speed,
  120.             "health": self.health,
  121.             "defense": self.defense,
  122.             "speed": self.speed,
  123.             "intelligence": self.intelligence
  124.         })
  125.  
  126. class Reforge:
  127.     def __init__(self, common, uncommon, rare, epic, legendary):
  128.         self.common = common
  129.         self.uncommon = uncommon
  130.         self.rare = rare
  131.         self.epic = epic
  132.         self.legendary = legendary
  133.  
  134. class Weapon(Stats):
  135.     def __init__(self, stats, reforge, rarity, enchantments = []):
  136.         if rarity == "common":
  137.             self.reforge_stats = reforge.common
  138.         elif rarity == "uncommon":
  139.             self.reforge_stats = reforge.uncommon
  140.         elif rarity == "rare":
  141.             self.reforge_stats = reforge.rare
  142.         elif rarity == "epic":
  143.             self.reforge_stats = reforge.epic
  144.         elif rarity == "legendary":
  145.             self.reforge_stats = reforge.legendary
  146.         else:
  147.             self.reforge_stats = Stats()
  148.         self.damage = stats.damage + self.reforge_stats.damage
  149.         self.strength = stats.strength + self.reforge_stats.strength
  150.         self.crit_chance = stats.crit_chance + self.reforge_stats.crit_chance
  151.         self.crit_dmg = stats.crit_dmg + self.reforge_stats.crit_dmg
  152.         self.atk_speed = stats.atk_speed + self.reforge_stats.atk_speed
  153.         self.health = stats.health + self.reforge_stats.health
  154.         self.defense = stats.defense + self.reforge_stats.defense
  155.         self.speed = stats.speed + self.reforge_stats.speed
  156.         self.intelligence = stats.intelligence + self.reforge_stats.intelligence
  157.         self.enchantments = enchantments
  158.  
  159. class Armor(Stats):
  160.     def __init__(self, stats, reforge, rarity):
  161.         if rarity == "common":
  162.             self.reforge_stats = reforge.common
  163.         elif rarity == "uncommon":
  164.             self.reforge_stats = reforge.uncommon
  165.         elif rarity == "rare":
  166.             self.reforge_stats = reforge.rare
  167.         elif rarity == "epic":
  168.             self.reforge_stats = reforge.epic
  169.         elif rarity == "legendary":
  170.             self.reforge_stats = reforge.legendary
  171.         else:
  172.             self.reforge_stats = Stats()
  173.         self.damage = stats.damage + self.reforge_stats.damage
  174.         self.strength = stats.strength + self.reforge_stats.strength
  175.         self.crit_chance = stats.crit_chance + self.reforge_stats.crit_chance
  176.         self.crit_dmg = stats.crit_dmg + self.reforge_stats.crit_dmg
  177.         self.atk_speed = stats.atk_speed + self.reforge_stats.atk_speed
  178.         self.health = stats.health + self.reforge_stats.health
  179.         self.defense = stats.defense + self.reforge_stats.defense
  180.         self.speed = stats.speed + self.reforge_stats.speed
  181.         self.intelligence = stats.intelligence + self.reforge_stats.intelligence
  182.  
  183. class Enchantment:
  184.     def __init__(self, id, level):
  185.         self.id = id
  186.         self.level = level
  187.  
  188. reforges = {
  189.     "Demonic": Reforge(
  190.         Stats(strength = 1, intelligence = 3),
  191.         Stats(strength = 2, intelligence = 6),
  192.         Stats(strength = 2, intelligence = 10),
  193.         Stats(strength = 3, intelligence = 15),
  194.         Stats(strength = 5, intelligence = 20)
  195.     ),
  196.     "Forceful": Reforge(
  197.         Stats(strength = 2),
  198.         Stats(strength = 4),
  199.         Stats(strength = 7),
  200.         Stats(strength = 10),
  201.         Stats(strength = 15)
  202.     ),
  203.     "Godly": Reforge(
  204.         Stats(strength = 1, crit_chance = 1, crit_dmg = 1, intelligence = 1),
  205.         Stats(strength = 2, crit_chance = 2, crit_dmg = 2, intelligence = 2),
  206.         Stats(strength = 4, crit_chance = 2, crit_dmg = 3, intelligence = 2),
  207.         Stats(strength = 7, crit_chance = 3, crit_dmg = 6, intelligence = 3),
  208.         Stats(strength = 10, crit_chance = 5, crit_dmg = 8, intelligence = 5)
  209.     ),
  210.     "Itchy": Reforge(
  211.         Stats(strength = 1, crit_dmg = 3, atk_speed = 1),
  212.         Stats(strength = 2, crit_dmg = 5, atk_speed = 2),
  213.         Stats(strength = 2, crit_dmg = 8, atk_speed = 2),
  214.         Stats(strength = 3, crit_dmg = 12, atk_speed = 3),
  215.         Stats(strength = 5, crit_dmg = 15, atk_speed = 5)
  216.     ),
  217.     "Spicy": Reforge(
  218.         Stats(strength = 1, crit_chance = 1, crit_dmg = 5, atk_speed = 1),
  219.         Stats(strength = 2, crit_chance = 1, crit_dmg = 10, atk_speed = 2),
  220.         Stats(strength = 2, crit_chance = 1, crit_dmg = 18, atk_speed = 4),
  221.         Stats(strength = 3, crit_chance = 1, crit_dmg = 32, atk_speed = 7),
  222.         Stats(strength = 5, crit_chance = 1, crit_dmg = 50, atk_speed = 10)
  223.     ),
  224.     "Strange": Reforge(
  225.         Stats(strength = 1, crit_chance = 1, crit_dmg = 1, atk_speed = 1, defense = 1, intelligence = -5),
  226.         Stats(strength = 2, crit_chance = 2, crit_dmg = 2, atk_speed = 2, defense = 1, intelligence = -10),
  227.         Stats(strength = 1, crit_chance = 1, crit_dmg = 1, atk_speed = 1, defense = 1, intelligence = -18),
  228.         Stats(strength = 1, crit_chance = 1, crit_dmg = 1, atk_speed = 1, defense = 1, intelligence = -32),
  229.         Stats(strength = 1, crit_chance = 1, crit_dmg = 1, atk_speed = 1, defense = 1, intelligence = -50)
  230.     ),
  231.     "Strong": Reforge(
  232.         Stats(strength = 1, crit_dmg = 1),
  233.         Stats(strength = 2, crit_dmg = 2),
  234.         Stats(strength = 4, crit_dmg = 4),
  235.         Stats(strength = 7, crit_dmg = 7),
  236.         Stats(strength = 10, crit_dmg = 10)
  237.     ),
  238.     "Titanic": Reforge(
  239.         Stats(health = 3, defense = 3),
  240.         Stats(health = 6, defense = 6),
  241.         Stats(health = 10, defense = 10),
  242.         Stats(health = 15, defense = 15),
  243.         Stats(health = 20, defense = 20)
  244.     ),
  245.     "Unpleasant": Reforge(
  246.         Stats(crit_chance = 1, crit_dmg = 1, intelligence = 1),
  247.         Stats(crit_chance = 2, crit_dmg = 2, intelligence = 1),
  248.         Stats(crit_chance = 3, crit_dmg = 2, intelligence = 2),
  249.         Stats(crit_chance = 6, crit_dmg = 3, intelligence = 3),
  250.         Stats(crit_chance = 8, crit_dmg = 5, intelligence = 5)
  251.     ),
  252.     "Wise": Reforge(
  253.         Stats(health = 1, speed = 1, intelligence = 10),
  254.         Stats(health = 2, speed = 1, intelligence = 20),
  255.         Stats(health = 2, speed = 1, intelligence = 35),
  256.         Stats(health = 2, speed = 2, intelligence = 65),
  257.         Stats(health = 5, speed = 2, intelligence = 100)
  258.     )
  259. }
  260.  
  261. base_stats = Stats(
  262.     health = 594,
  263.     defense = 67,
  264.     strength = 59,
  265.     speed = 103,
  266.     crit_chance = 20 + combat_level,
  267.     crit_dmg = 50,
  268.     intelligence = 28
  269. )
  270.  
  271. modifiers = Stats()
  272.  
  273. # Strength IV
  274. modifiers += Stats(strength = 30)
  275.  
  276. # Critical  III
  277. modifiers += Stats(crit_chance = 20, crit_dmg = 30)
  278.  
  279. weapon = Weapon(Stats(damage = 150, strength = 100, crit_dmg = 25), reforges["Spicy"], "epic", [Enchantment("sharpness", 5), Enchantment("giant_killer", 5), Enchantment("first_strike", 4)])
  280. worn_armor = [
  281.     Armor(Stats(health = 75, defense = 90), reforges["Forceful"], "rare"),
  282.     Armor(Stats(health = 95, defense = 65), reforges["Forceful"], "rare"),
  283.     Armor(Stats(health = 275, defense = 80), reforges["Forceful"], "rare"),
  284.     Armor(Stats(health = 125, defense = 100), reforges["Forceful"], "epic")
  285. ]
  286.  
  287. player_stats = base_stats + modifiers + weapon
  288.  
  289. for armor in worn_armor:
  290.     player_stats += armor
  291.  
  292. talisman_amounts = {
  293.     "common": 16,
  294.     "uncommon": 11,
  295.     "rare": 10,
  296.     "epic": 2,
  297.     "legendary": 0
  298. }
  299.  
  300. #The more reforge possibilities you add, the MUCH MORE time it takes to calculate
  301.  
  302. talisman_reforges = {
  303.     "common": ["Godly", "Itchy"],
  304.     "uncommon": ["Godly", "Itchy"],
  305.     "rare": ["Godly", "Itchy"], # Unpleasant can be useful
  306.     "epic": ["Godly", "Itchy"], # Unpleasant can be useful
  307.     "legendary": ["Itchy"]
  308. }
  309.  
  310. # For efficiency with always_crit, we give up a combination early if it can't reach max crit chance
  311. # This is also why we are calculating from higher rarities down, to maximize ruled out combinations
  312. talisman_max_crit_chances = calc_max_crit_chances(reforges, talisman_reforges, talisman_amounts)
  313. order = ["epic", "rare", "uncommon", "common"]
  314. crit_requirements = calc_crit_requirements(player_stats, talisman_max_crit_chances, order)
  315.  
  316. # Aim for: highest_average or always_crit
  317. aim_for = "always_crit"
  318.  
  319. def stat_reforge_set(reforge_set, rarity):
  320.     output = Stats()
  321.     for reforge in reforge_set:
  322.         if rarity == "common":
  323.             output += reforges[reforge].common
  324.         elif rarity == "uncommon":
  325.             output += reforges[reforge].uncommon
  326.         elif rarity == "rare":
  327.             output += reforges[reforge].rare
  328.         elif rarity == "epic":
  329.             output += reforges[reforge].epic
  330.         elif rarity == "legendary":
  331.             output += reforges[reforge].legendary
  332.     return output
  333.  
  334. num_iterations = 0
  335.  
  336. def enumerate_combinations(order, index, highest, highest_data, current_reforges):
  337.     global num_iterations
  338.     num_iterations += 1
  339.     current_rarity = order[index]
  340.     for reforge_set in itertools.combinations_with_replacement(talisman_reforges[current_rarity], talisman_amounts[current_rarity]):
  341.         current_reforges[current_rarity] = [reforge_set, stat_reforge_set(reforge_set, current_rarity)]
  342.         if index == len(order) - 1:
  343.             total_mod = Stats()
  344.             for rarity in order:
  345.                 total_mod += current_reforges[rarity][1]
  346.             total_stats = player_stats + total_mod
  347.             if aim_for == "always_crit" and total_stats.crit_chance >= 100:
  348.                 #calculated_damage = total_stats.calc_crit_damage()
  349.                 calculated_damage = total_stats.calc_damage(True, weapon.enchantments)
  350.             elif aim_for == "always_crit":
  351.                 calculated_damage = 0
  352.             elif aim_for == "highest_average":
  353.                 calculated_damage = total_stats.calc_avg_damage(weapon.enchantments)
  354.            
  355.             if calculated_damage > highest:
  356.                 highest = calculated_damage
  357.                 current_reforges["total"] = [total_mod, total_stats]
  358.                 highest_data = dict(current_reforges)
  359.         else:
  360.             current_crit_chance = 0
  361.             for rarity in current_reforges:
  362.                 current_crit_chance += current_reforges[rarity][1].crit_chance
  363.             if aim_for != "always_crit" or current_crit_chance >= crit_requirements[current_rarity]:
  364.                 highest, highest_data = enumerate_combinations(order, index + 1, highest, highest_data, current_reforges)
  365.     return (highest, highest_data)
  366.  
  367. best_combo = enumerate_combinations(order, 0, 0, {}, {})
  368. print("Best combo does " + str(best_combo[0]) + " dmg after " + str(num_iterations) + " iterations")
  369. print("Total talismans: " + str(best_combo[1]["total"][0]))
  370. print("Total: " + str(best_combo[1]["total"][1]))
  371. for rarity in order:
  372.     makeup = ""
  373.     for reforge in best_combo[1][rarity][0]:
  374.         makeup += reforge[0:1]
  375.     print(rarity + ": " + makeup)
Advertisement
Add Comment
Please, Sign In to add comment