StarRailDamageCal/starrail_damage_cal/damage/Role.py
2023-11-14 17:30:31 +08:00

446 lines
12 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import copy
from typing import Dict
from starrail_damage_cal.damage.utils import merge_attribute
async def calculate_heal(
base_attr: Dict[str, float],
attribute_bonus: Dict[str, float],
skill_type: str,
skill_multiplier: float,
skill_num: float,
is_atk=0,
):
add_attr_bonus = copy.deepcopy(attribute_bonus)
merged_attr = await merge_attribute(base_attr, add_attr_bonus)
hp = merged_attr.get("attack", 0) if is_atk == 1 else merged_attr.get("hp", 0)
# 检查是否有治疗量加成
heal_ratio_base = merged_attr.get("HealRatioBase", 0)
for attr in merged_attr:
if "_HealRatioBase" in attr and attr.split("_")[0] in (skill_type):
heal_ratio_base += merged_attr[attr]
heal_ratio = heal_ratio_base + 1
heal_num = (hp * skill_multiplier + skill_num) * heal_ratio
return [heal_num]
async def calculate_shield(
base_attr: Dict[str, float],
attribute_bonus: Dict[str, float],
skill_multiplier: float,
skill_num: float,
is_atk=0,
):
add_attr_bonus = copy.deepcopy(attribute_bonus)
merged_attr = await merge_attribute(base_attr, add_attr_bonus)
if is_atk == 1:
defence = merged_attr.get("attack", 0)
else:
defence = merged_attr.get("defence", 0)
# 检查是否有护盾加成
shield_added_ratio = merged_attr.get("shield_added_ratio", 0)
shield_added = shield_added_ratio + 1
defence_num = (defence * skill_multiplier + skill_num) * shield_added
return [defence_num]
async def get_damage(
damege: int,
base_attr: Dict[str, float],
attribute_bonus: Dict[str, float],
skill_type: str,
add_skill_type: str,
element: str,
skill_multiplier: float,
):
add_attr_bonus = copy.deepcopy(attribute_bonus)
add_attr_bonus = apply_attribute_bonus(add_attr_bonus, skill_type, add_skill_type)
merged_attr = await merge_attribute(base_attr, add_attr_bonus)
injury_area, element_area = calculate_injury_area(
merged_attr,
skill_type,
add_skill_type,
element,
)
critical_damage = calculate_critical_damage(merged_attr, skill_type, add_skill_type)
critical_chance = calculate_critical_chance(merged_attr, skill_type, add_skill_type)
expected_damage = calculate_expected_damage(critical_chance, critical_damage)
damage_cd = damege * skill_multiplier * injury_area * critical_damage
damage_qw = damege * skill_multiplier * injury_area * expected_damage
damage_tz = damege * skill_multiplier * (injury_area + 2.626) * (critical_damage + 1.794) * 10
return [damage_cd, damage_qw, damage_tz]
async def break_damage(
base_attr: Dict[str, float],
attribute_bonus: Dict[str, float],
skill_type: str,
add_skill_type: str,
element: str,
level: int,
):
break_element = {
'Ice': 1,
'Imaginary': 1,
'Quantum': 1,
'Thunder': 2,
'Wind': 3,
'Physical': 4,
'Fire': 5,
}
add_attr_bonus = copy.deepcopy(attribute_bonus)
add_attr_bonus = apply_attribute_bonus(add_attr_bonus, skill_type, add_skill_type)
merged_attr = await merge_attribute(base_attr, add_attr_bonus)
break_atk = 3767.55 #80级敌人击破伤害基数我也不知道为什么是这个反正都说是这个
damage_reduction = calculate_damage_reduction(level)
resistance_area = calculate_resistance_area(
merged_attr,
skill_type,
add_skill_type,
element,
)
defence_multiplier = calculate_defence_multiplier(level, merged_attr)
damage_ratio = calculate_damage_ratio(merged_attr, skill_type, add_skill_type)
break_damage = merged_attr.get("BreakDamageAddedRatioBase", 0) + 1
damage_cd = break_atk * break_element[element] * 2 * break_damage * damage_ratio * damage_reduction * resistance_area * defence_multiplier
return [damage_cd]
async def calculate_damage(
base_attr: Dict[str, float],
attribute_bonus: Dict[str, float],
skill_type: str,
add_skill_type: str,
element: str,
skill_multiplier: float,
level: int,
is_hp=0,
):
add_attr_bonus = copy.deepcopy(attribute_bonus)
add_attr_bonus = apply_attribute_bonus(add_attr_bonus, skill_type, add_skill_type)
merged_attr = await merge_attribute(base_attr, add_attr_bonus)
if is_hp == 1:
attack = merged_attr.get("hp", 0)
elif is_hp == 2:
attack = merged_attr.get("defence", 0)
else:
attack = merged_attr.get("attack", 0)
damage_reduction = calculate_damage_reduction(level)
resistance_area = calculate_resistance_area(
merged_attr,
skill_type,
add_skill_type,
element,
)
defence_multiplier = calculate_defence_multiplier(level, merged_attr)
injury_area, element_area = calculate_injury_area(
merged_attr,
skill_type,
add_skill_type,
element,
)
damage_ratio = calculate_damage_ratio(merged_attr, skill_type, add_skill_type)
critical_damage = calculate_critical_damage(merged_attr, skill_type, add_skill_type)
critical_chance = calculate_critical_chance(merged_attr, skill_type, add_skill_type)
expected_damage = calculate_expected_damage(critical_chance, critical_damage)
damage_cd = calculate_damage_cd(
attack,
skill_multiplier,
damage_ratio,
injury_area,
defence_multiplier,
resistance_area,
damage_reduction,
critical_damage,
)
damage_qw = calculate_damage_qw(
attack,
skill_multiplier,
damage_ratio,
injury_area,
defence_multiplier,
resistance_area,
damage_reduction,
expected_damage,
)
damage_tz = calculate_damage_tz(
attack,
skill_multiplier,
damage_ratio,
injury_area,
defence_multiplier,
resistance_area,
damage_reduction,
critical_damage,
element,
element_area,
base_attr,
)
return [damage_cd, damage_qw, damage_tz]
def apply_attribute_bonus(
add_attr_bonus: Dict[str, float],
skill_type: str,
add_skill_type: str,
):
# Apply attribute bonuses to attack and status probability
for attr in add_attr_bonus:
if "AttackAddedRatio" in attr and attr.split("AttackAddedRatio")[0] in (
skill_type,
add_skill_type,
):
add_attr_bonus["AttackAddedRatio"] += add_attr_bonus[attr]
if "StatusProbabilityBase" in attr and attr.split("StatusProbabilityBase")[
0
] in (skill_type, add_skill_type):
add_attr_bonus["StatusProbabilityBase"] += add_attr_bonus[attr]
return add_attr_bonus
def calculate_damage_reduction(level: int):
enemy_damage_reduction = 0.1
return 1 - enemy_damage_reduction
def calculate_resistance_area(
merged_attr: Dict[str, float],
skill_type: str,
add_skill_type: str,
element: str,
):
enemy_status_resistance = 0.0
for attr in merged_attr:
if "ResistancePenetration" in attr:
# 检查是否有某一属性的抗性穿透
attr_name = attr.split("ResistancePenetration")[0]
if attr_name in (element, "AllDamage"):
# logger.info(f'{attr_name}属性有{merged_attr[attr]}穿透加成')
enemy_status_resistance += merged_attr[attr]
# 检查是否有某一技能属性的抗性穿透
if "_" in attr_name:
skill_name = attr_name.split("_")[0]
skillattr_name = attr_name.split("_")[1]
if skill_name == add_skill_type and skillattr_name in (
element,
"AllDamage",
):
enemy_status_resistance += merged_attr[attr]
# logger.info(
# f'{skill_name}对{skillattr_name}属性有{merged_attr[attr]}穿透加成'
# )
return 1.0 - (0 - enemy_status_resistance)
def calculate_defence_multiplier(
level: int,
merged_attr: Dict[str, float],
):
ignore_defence = merged_attr.get("ignore_defence", 0.0)
enemy_defence = (level * 10 + 200) * (1 - ignore_defence)
return (level * 10 + 200) / (level * 10 + 200 + enemy_defence)
def calculate_injury_area(
merged_attr: Dict[str, float],
skill_type: str,
add_skill_type: str,
element: str,
):
injury_area = 0.0
element_area = 0.0
for attr in merged_attr:
attr_name = attr.split("AddedRatio")[0]
skill_name = attr.split("DmgAdd")[0]
if "DmgAdd" in attr and skill_name in (
skill_type,
add_skill_type,
):
# logger.info(
# f'{attr} 对 {skill_type} 有 {merged_attr[attr]} 伤害加成'
# )
injury_area += merged_attr[attr]
if "AddedRatio" in attr and attr_name in (
element,
"AllDamage",
):
# logger.info(
# f'{attr} 对 {element} 属性有 {merged_attr[attr]} 伤害加成'
# )
if attr_name == element:
element_area += merged_attr[attr]
injury_area += merged_attr[attr]
return injury_area + 1, element_area
def calculate_damage_ratio(
merged_attr: Dict[str, float],
skill_type: str,
add_skill_type: str,
):
damage_ratio = merged_attr.get("DmgRatio", 0)
for attr in merged_attr:
if "_DmgRatio" in attr and attr.split("_")[0] in (
skill_type,
add_skill_type,
):
damage_ratio += merged_attr[attr]
return damage_ratio + 1
def calculate_critical_damage(
merged_attr: Dict[str, float],
skill_type: str,
add_skill_type: str,
):
if skill_type == "DOT":
return 1.0
critical_damage_base = merged_attr.get("CriticalDamageBase", 0)
for attr in merged_attr:
if "_CriticalDamageBase" in attr and attr.split("_")[0] in (
skill_type,
add_skill_type,
):
critical_damage_base += merged_attr[attr]
return critical_damage_base + 1
def calculate_critical_chance(
merged_attr: Dict[str, float],
skill_type: str,
add_skill_type: str,
):
critical_chance_base = merged_attr["CriticalChanceBase"]
for attr in merged_attr:
if "_CriticalChance" in attr and attr.split("_")[0] in (
skill_type,
add_skill_type,
):
critical_chance_base += merged_attr[attr]
return min(1, critical_chance_base)
def calculate_expected_damage(
critical_chance_base: float,
critical_damage_base: float,
):
return critical_chance_base * (critical_damage_base - 1) + 1
def calculate_damage_cd(
attack: float,
skill_multiplier: float,
damage_ratio: float,
injury_area: float,
defence_multiplier: float,
resistance_area: float,
damage_reduction: float,
critical_damage: float,
):
return (
attack
* skill_multiplier
* damage_ratio
* injury_area
* defence_multiplier
* resistance_area
* damage_reduction
* critical_damage
)
def calculate_damage_qw(
attack: float,
skill_multiplier: float,
damage_ratio: float,
injury_area: float,
defence_multiplier: float,
resistance_area: float,
damage_reduction: float,
expected_damage: float,
):
return (
attack
* skill_multiplier
* damage_ratio
* injury_area
* defence_multiplier
* resistance_area
* damage_reduction
* expected_damage
)
def calculate_damage_tz(
attack: float,
skill_multiplier: float,
damage_ratio: float,
injury_area: float,
defence_multiplier: float,
resistance_area: float,
damage_reduction: float,
critical_damage: float,
element: str,
element_area: float,
base_attr: Dict[str, float],
):
injury_add_tz = 0.0
attack_tz = attack + 355 + base_attr["attack"] * 2.334
# logger.info(f'attack_tz: {attack_tz}')
if element == "Imaginary":
injury_add_tz = 0.12
return (
attack_tz
* skill_multiplier
* damage_ratio
* (injury_area + injury_add_tz + 2.626)
* defence_multiplier
* resistance_area
* damage_reduction
* (critical_damage + 1.794)
* 10
)