mirror of
https://github.com/PaiGramTeam/StarRailDamageCal.git
synced 2024-11-30 18:59:26 +00:00
471 lines
13 KiB
Python
471 lines
13 KiB
Python
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)
|
|
|
|
_ = calculate_expected_damage(critical_chance, critical_damage)
|
|
|
|
damage_cd = damege * skill_multiplier * injury_area
|
|
|
|
damage_qw = damege * skill_multiplier * injury_area
|
|
|
|
damage_tz = damege * skill_multiplier * (injury_area + 2.626) * 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, skill_type, add_skill_type
|
|
)
|
|
|
|
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, skill_type, add_skill_type
|
|
)
|
|
|
|
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],
|
|
skill_type: str,
|
|
add_skill_type: str,
|
|
):
|
|
ignore_defence = merged_attr.get("ignore_defence", 0.0)
|
|
for attr in merged_attr:
|
|
skill_name = attr.split("ignore_defence")[0]
|
|
if "ignore_defence" in attr and skill_name in (
|
|
skill_type,
|
|
add_skill_type,
|
|
):
|
|
ignore_defence += merged_attr[attr]
|
|
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
|
|
)
|