Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import itertools
- import math
- # TODO: Configurable weapons / num talismans / potions / base stats / etc.
- combat_level = 18
- def num_combinations(elements, size):
- # Return the number of combinations (With replacement) for a given number of elements choosing a size of them
- return math.factorial(size + elements - 1) / ( math.factorial(size) * math.factorial(elements - 1))
- def calc_max_crit_chances(reforges, valid_reforges, amounts):
- output = {}
- for rarity in valid_reforges:
- highest = 0
- for name in valid_reforges[rarity]:
- if rarity == "common":
- crit_chance = reforges[name].common.crit_chance
- elif rarity == "uncommon":
- crit_chance = reforges[name].uncommon.crit_chance
- elif rarity == "rare":
- crit_chance = reforges[name].rare.crit_chance
- elif rarity == "epic":
- crit_chance = reforges[name].epic.crit_chance
- elif rarity == "legendary":
- crit_chance = reforges[name].legendary.crit_chance
- crit_chance *= amounts[rarity]
- if crit_chance > highest:
- highest = crit_chance
- output[rarity] = highest
- return output
- def calc_crit_requirements(base_stats, max_crit_chances, order):
- output = {}
- for x in range(0, len(order)-1):
- current_rarity = order[x]
- total_remaining = 0
- for y in range(x, len(order)):
- remaining_rarity = order[y]
- total_remaining += max_crit_chances[remaining_rarity]
- output[current_rarity] = 100 - (total_remaining + base_stats.crit_chance)
- return output
- class Stats:
- def __init__(self, damage = 0, strength = 0, crit_chance = 0, crit_dmg = 0, atk_speed = 0, health = 0, defense = 0, speed = 0, intelligence = 0):
- self.damage = damage # Reforges can't give this, it's a damage modifier
- self.strength = strength
- self.crit_chance = crit_chance
- self.crit_dmg = crit_dmg
- self.atk_speed = atk_speed
- self.health = health
- self.defense = defense
- self.speed = speed
- self.intelligence = intelligence
- def calc_normal_damage(self):
- return (5 + self.damage + math.floor(self.strength / 5)) * (1 + (self.strength / 100))
- def calc_crit_damage(self):
- return self.calc_normal_damage() * (1 + (self.crit_dmg / 100))
- def calc_avg_damage(self, enchantments = []):
- normal_damage = self.calc_damage(False, enchantments)
- crit_damage = self.calc_damage(True, enchantments)
- return (crit_damage * (self.crit_chance / 100)) + (normal_damage * (1 - (self.crit_chance / 100)))
- def calc_damage(self, is_crit, enchantments = []):
- base_dmg = self.calc_normal_damage()
- dmg = base_dmg
- sharpness_dmg = 0
- gk_dmg = 0
- for enchantment in enchantments:
- if enchantment.id == "sharpness":
- dmg += (enchantment.level * 0.05) * base_dmg
- sharpness_dmg = (enchantment.level * 0.05) * base_dmg
- elif enchantment.id == "giant_killer":
- dmg += 0.25 * base_dmg
- gk_dmg = 0.25 * base_dmg
- elif enchantment.id == "first_strike":
- dmg += 0.25 * enchantment.level * base_dmg
- dmg += (combat_level * 0.04) * (base_dmg + sharpness_dmg + gk_dmg)
- if is_crit:
- dmg *= (1 + (self.crit_dmg / 100))
- return dmg
- 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):
- self.damage += damage
- self.strength += strength
- self.crit_chance += crit_chance
- self.crit_dmg += crit_dmg
- self.atk_speed += atk_speed
- self.health += health
- self.defense += defense
- self.speed += speed
- self.intelligence += intelligence
- def __add__(self, other):
- return Stats(
- damage = self.damage + other.damage,
- strength = self.strength + other.strength,
- crit_chance = self.crit_chance + other.crit_chance,
- crit_dmg = self.crit_dmg + other.crit_dmg,
- atk_speed = self.atk_speed + other.atk_speed,
- health = self.health + other.health,
- defense = self.defense + other.defense,
- speed = self.speed + other.speed,
- intelligence = self.intelligence + other.intelligence
- )
- def __iadd__(self, other):
- self.add_stats(other.damage, other.strength, other.crit_chance, other.crit_dmg, other.atk_speed, other.health, other.defense, other.speed, other.intelligence)
- return self
- def __str__(self):
- return str({
- "damage": self.damage,
- "strength": self.strength,
- "crit_chance": self.crit_chance,
- "crit_dmg": self.crit_dmg,
- "atk_speed": self.atk_speed,
- "health": self.health,
- "defense": self.defense,
- "speed": self.speed,
- "intelligence": self.intelligence
- })
- class Reforge:
- def __init__(self, common, uncommon, rare, epic, legendary):
- self.common = common
- self.uncommon = uncommon
- self.rare = rare
- self.epic = epic
- self.legendary = legendary
- class Weapon(Stats):
- def __init__(self, stats, reforge, rarity, enchantments = []):
- if rarity == "common":
- self.reforge_stats = reforge.common
- elif rarity == "uncommon":
- self.reforge_stats = reforge.uncommon
- elif rarity == "rare":
- self.reforge_stats = reforge.rare
- elif rarity == "epic":
- self.reforge_stats = reforge.epic
- elif rarity == "legendary":
- self.reforge_stats = reforge.legendary
- else:
- self.reforge_stats = Stats()
- self.damage = stats.damage + self.reforge_stats.damage
- self.strength = stats.strength + self.reforge_stats.strength
- self.crit_chance = stats.crit_chance + self.reforge_stats.crit_chance
- self.crit_dmg = stats.crit_dmg + self.reforge_stats.crit_dmg
- self.atk_speed = stats.atk_speed + self.reforge_stats.atk_speed
- self.health = stats.health + self.reforge_stats.health
- self.defense = stats.defense + self.reforge_stats.defense
- self.speed = stats.speed + self.reforge_stats.speed
- self.intelligence = stats.intelligence + self.reforge_stats.intelligence
- self.enchantments = enchantments
- class Armor(Stats):
- def __init__(self, stats, reforge, rarity):
- if rarity == "common":
- self.reforge_stats = reforge.common
- elif rarity == "uncommon":
- self.reforge_stats = reforge.uncommon
- elif rarity == "rare":
- self.reforge_stats = reforge.rare
- elif rarity == "epic":
- self.reforge_stats = reforge.epic
- elif rarity == "legendary":
- self.reforge_stats = reforge.legendary
- else:
- self.reforge_stats = Stats()
- self.damage = stats.damage + self.reforge_stats.damage
- self.strength = stats.strength + self.reforge_stats.strength
- self.crit_chance = stats.crit_chance + self.reforge_stats.crit_chance
- self.crit_dmg = stats.crit_dmg + self.reforge_stats.crit_dmg
- self.atk_speed = stats.atk_speed + self.reforge_stats.atk_speed
- self.health = stats.health + self.reforge_stats.health
- self.defense = stats.defense + self.reforge_stats.defense
- self.speed = stats.speed + self.reforge_stats.speed
- self.intelligence = stats.intelligence + self.reforge_stats.intelligence
- class Enchantment:
- def __init__(self, id, level):
- self.id = id
- self.level = level
- reforges = {
- "Demonic": Reforge(
- Stats(strength = 1, intelligence = 3),
- Stats(strength = 2, intelligence = 6),
- Stats(strength = 2, intelligence = 10),
- Stats(strength = 3, intelligence = 15),
- Stats(strength = 5, intelligence = 20)
- ),
- "Forceful": Reforge(
- Stats(strength = 2),
- Stats(strength = 4),
- Stats(strength = 7),
- Stats(strength = 10),
- Stats(strength = 15)
- ),
- "Godly": Reforge(
- Stats(strength = 1, crit_chance = 1, crit_dmg = 1, intelligence = 1),
- Stats(strength = 2, crit_chance = 2, crit_dmg = 2, intelligence = 2),
- Stats(strength = 4, crit_chance = 2, crit_dmg = 3, intelligence = 2),
- Stats(strength = 7, crit_chance = 3, crit_dmg = 6, intelligence = 3),
- Stats(strength = 10, crit_chance = 5, crit_dmg = 8, intelligence = 5)
- ),
- "Itchy": Reforge(
- Stats(strength = 1, crit_dmg = 3, atk_speed = 1),
- Stats(strength = 2, crit_dmg = 5, atk_speed = 2),
- Stats(strength = 2, crit_dmg = 8, atk_speed = 2),
- Stats(strength = 3, crit_dmg = 12, atk_speed = 3),
- Stats(strength = 5, crit_dmg = 15, atk_speed = 5)
- ),
- "Spicy": Reforge(
- Stats(strength = 1, crit_chance = 1, crit_dmg = 5, atk_speed = 1),
- Stats(strength = 2, crit_chance = 1, crit_dmg = 10, atk_speed = 2),
- Stats(strength = 2, crit_chance = 1, crit_dmg = 18, atk_speed = 4),
- Stats(strength = 3, crit_chance = 1, crit_dmg = 32, atk_speed = 7),
- Stats(strength = 5, crit_chance = 1, crit_dmg = 50, atk_speed = 10)
- ),
- "Strange": Reforge(
- Stats(strength = 1, crit_chance = 1, crit_dmg = 1, atk_speed = 1, defense = 1, intelligence = -5),
- Stats(strength = 2, crit_chance = 2, crit_dmg = 2, atk_speed = 2, defense = 1, intelligence = -10),
- Stats(strength = 1, crit_chance = 1, crit_dmg = 1, atk_speed = 1, defense = 1, intelligence = -18),
- Stats(strength = 1, crit_chance = 1, crit_dmg = 1, atk_speed = 1, defense = 1, intelligence = -32),
- Stats(strength = 1, crit_chance = 1, crit_dmg = 1, atk_speed = 1, defense = 1, intelligence = -50)
- ),
- "Strong": Reforge(
- Stats(strength = 1, crit_dmg = 1),
- Stats(strength = 2, crit_dmg = 2),
- Stats(strength = 4, crit_dmg = 4),
- Stats(strength = 7, crit_dmg = 7),
- Stats(strength = 10, crit_dmg = 10)
- ),
- "Titanic": Reforge(
- Stats(health = 3, defense = 3),
- Stats(health = 6, defense = 6),
- Stats(health = 10, defense = 10),
- Stats(health = 15, defense = 15),
- Stats(health = 20, defense = 20)
- ),
- "Unpleasant": Reforge(
- Stats(crit_chance = 1, crit_dmg = 1, intelligence = 1),
- Stats(crit_chance = 2, crit_dmg = 2, intelligence = 1),
- Stats(crit_chance = 3, crit_dmg = 2, intelligence = 2),
- Stats(crit_chance = 6, crit_dmg = 3, intelligence = 3),
- Stats(crit_chance = 8, crit_dmg = 5, intelligence = 5)
- ),
- "Wise": Reforge(
- Stats(health = 1, speed = 1, intelligence = 10),
- Stats(health = 2, speed = 1, intelligence = 20),
- Stats(health = 2, speed = 1, intelligence = 35),
- Stats(health = 2, speed = 2, intelligence = 65),
- Stats(health = 5, speed = 2, intelligence = 100)
- )
- }
- base_stats = Stats(
- health = 594,
- defense = 67,
- strength = 59,
- speed = 103,
- crit_chance = 20 + combat_level,
- crit_dmg = 50,
- intelligence = 28
- )
- modifiers = Stats()
- # Strength IV
- modifiers += Stats(strength = 30)
- # Critical III
- modifiers += Stats(crit_chance = 20, crit_dmg = 30)
- weapon = Weapon(Stats(damage = 150, strength = 100, crit_dmg = 25), reforges["Spicy"], "epic", [Enchantment("sharpness", 5), Enchantment("giant_killer", 5), Enchantment("first_strike", 4)])
- worn_armor = [
- Armor(Stats(health = 75, defense = 90), reforges["Forceful"], "rare"),
- Armor(Stats(health = 95, defense = 65), reforges["Forceful"], "rare"),
- Armor(Stats(health = 275, defense = 80), reforges["Forceful"], "rare"),
- Armor(Stats(health = 125, defense = 100), reforges["Forceful"], "epic")
- ]
- player_stats = base_stats + modifiers + weapon
- for armor in worn_armor:
- player_stats += armor
- talisman_amounts = {
- "common": 16,
- "uncommon": 11,
- "rare": 10,
- "epic": 2,
- "legendary": 0
- }
- #The more reforge possibilities you add, the MUCH MORE time it takes to calculate
- talisman_reforges = {
- "common": ["Godly", "Itchy"],
- "uncommon": ["Godly", "Itchy"],
- "rare": ["Godly", "Itchy"], # Unpleasant can be useful
- "epic": ["Godly", "Itchy"], # Unpleasant can be useful
- "legendary": ["Itchy"]
- }
- # For efficiency with always_crit, we give up a combination early if it can't reach max crit chance
- # This is also why we are calculating from higher rarities down, to maximize ruled out combinations
- talisman_max_crit_chances = calc_max_crit_chances(reforges, talisman_reforges, talisman_amounts)
- order = ["epic", "rare", "uncommon", "common"]
- crit_requirements = calc_crit_requirements(player_stats, talisman_max_crit_chances, order)
- # Aim for: highest_average or always_crit
- aim_for = "always_crit"
- def stat_reforge_set(reforge_set, rarity):
- output = Stats()
- for reforge in reforge_set:
- if rarity == "common":
- output += reforges[reforge].common
- elif rarity == "uncommon":
- output += reforges[reforge].uncommon
- elif rarity == "rare":
- output += reforges[reforge].rare
- elif rarity == "epic":
- output += reforges[reforge].epic
- elif rarity == "legendary":
- output += reforges[reforge].legendary
- return output
- num_iterations = 0
- def enumerate_combinations(order, index, highest, highest_data, current_reforges):
- global num_iterations
- num_iterations += 1
- current_rarity = order[index]
- for reforge_set in itertools.combinations_with_replacement(talisman_reforges[current_rarity], talisman_amounts[current_rarity]):
- current_reforges[current_rarity] = [reforge_set, stat_reforge_set(reforge_set, current_rarity)]
- if index == len(order) - 1:
- total_mod = Stats()
- for rarity in order:
- total_mod += current_reforges[rarity][1]
- total_stats = player_stats + total_mod
- if aim_for == "always_crit" and total_stats.crit_chance >= 100:
- #calculated_damage = total_stats.calc_crit_damage()
- calculated_damage = total_stats.calc_damage(True, weapon.enchantments)
- elif aim_for == "always_crit":
- calculated_damage = 0
- elif aim_for == "highest_average":
- calculated_damage = total_stats.calc_avg_damage(weapon.enchantments)
- if calculated_damage > highest:
- highest = calculated_damage
- current_reforges["total"] = [total_mod, total_stats]
- highest_data = dict(current_reforges)
- else:
- current_crit_chance = 0
- for rarity in current_reforges:
- current_crit_chance += current_reforges[rarity][1].crit_chance
- if aim_for != "always_crit" or current_crit_chance >= crit_requirements[current_rarity]:
- highest, highest_data = enumerate_combinations(order, index + 1, highest, highest_data, current_reforges)
- return (highest, highest_data)
- best_combo = enumerate_combinations(order, 0, 0, {}, {})
- print("Best combo does " + str(best_combo[0]) + " dmg after " + str(num_iterations) + " iterations")
- print("Total talismans: " + str(best_combo[1]["total"][0]))
- print("Total: " + str(best_combo[1]["total"][1]))
- for rarity in order:
- makeup = ""
- for reforge in best_combo[1][rarity][0]:
- makeup += reforge[0:1]
- print(rarity + ": " + makeup)
Advertisement
Add Comment
Please, Sign In to add comment