diff --git a/StarRailUID/starrailuid_charinfo/damage/Avatar.py b/StarRailUID/starrailuid_charinfo/damage/Avatar.py index ba3e3b5..f10e14e 100644 --- a/StarRailUID/starrailuid_charinfo/damage/Avatar.py +++ b/StarRailUID/starrailuid_charinfo/damage/Avatar.py @@ -1,14 +1,15 @@ import json from pathlib import Path +from typing import Dict from gsuid_core.logger import logger -from .Weapon.Weapon import Weapon from ..mono.Character import Character -from .Base.model import DamageInstance -from .Base.AvatarBase import BaseAvatarinfo -from .Relic.Relic import RelicSet, SingleRelic from .AvatarDamage.AvatarDamage import AvatarDamage +from .Base.AvatarBase import BaseAvatarinfo +from .Base.model import DamageInstance +from .Relic.Relic import RelicSet, SingleRelic +from .Weapon.Weapon import Weapon Excel_path = Path(__file__).parent with Path.open(Excel_path / 'Excel' / 'SkillData.json', encoding='utf-8') as f: @@ -33,6 +34,17 @@ class AvatarInstance: self.cal_avatar_eidolon_add() self.cal_weapon_attr_add() + def merge_attribute_bonus(self, add_attribute: Dict[str, float]): + for attribute in add_attribute: + if attribute in self.attribute_bonus: + self.attribute_bonus[ + attribute + ] += add_attribute[attribute] + else: + self.attribute_bonus[ + attribute + ] = add_attribute[attribute] + def cal_role_base_attr(self): logger.info('cal_role_base_attr') base_attr: dict[str, float] = {} @@ -56,47 +68,15 @@ class AvatarInstance: for relic_type in self.relic_set.__dict__: if type(self.relic_set.__dict__[relic_type]) == SingleRelic: relic: SingleRelic = self.relic_set.__dict__[relic_type] - for attribute in relic.relic_attribute_bonus: - if attribute in self.attribute_bonus: - self.attribute_bonus[ - attribute - ] += relic.relic_attribute_bonus[attribute] - else: - self.attribute_bonus[ - attribute - ] = relic.relic_attribute_bonus[attribute] + self.merge_attribute_bonus(relic.relic_attribute_bonus) # 套装面板加成属性 for set_skill in self.relic_set.SetSkill: - for attribute in set_skill.relicSetAttribute: - if attribute in self.attribute_bonus: - self.attribute_bonus[ - attribute - ] += set_skill.relicSetAttribute[attribute] - else: - self.attribute_bonus[ - attribute - ] = set_skill.relicSetAttribute[attribute] + self.merge_attribute_bonus(set_skill.relicSetAttribute) def cal_avatar_eidolon_add(self): - for attribute in self.avatardamage.eidolon_attribute: - if attribute in self.attribute_bonus: - self.attribute_bonus[ - attribute - ] += self.avatardamage.eidolon_attribute[attribute] - else: - self.attribute_bonus[ - attribute - ] = self.avatardamage.eidolon_attribute[attribute] - for attribute in self.avatardamage.extra_ability_attribute: - if attribute in self.attribute_bonus: - self.attribute_bonus[ - attribute - ] += self.avatardamage.extra_ability_attribute[attribute] - else: - self.attribute_bonus[ - attribute - ] = self.avatardamage.extra_ability_attribute[attribute] + self.merge_attribute_bonus(self.avatardamage.eidolon_attribute) + self.merge_attribute_bonus(self.avatardamage.extra_ability_attribute) def cal_avatar_attr_add(self): attribute_bonus = self.avatar.avatar_attribute_bonus @@ -111,15 +91,7 @@ class AvatarInstance: self.attribute_bonus[bonus_property] = value def cal_weapon_attr_add(self): - for attribute in self.weapon.weapon_attribute: - if attribute in self.attribute_bonus: - self.attribute_bonus[ - attribute - ] += self.weapon.weapon_attribute[attribute] - else: - self.attribute_bonus[attribute] = self.weapon.weapon_attribute[ - attribute - ] + self.merge_attribute_bonus(self.weapon.weapon_attribute) async def gat_damage(self): logger.info('base_attr') diff --git a/StarRailUID/starrailuid_charinfo/damage/Base/AvatarBase.py b/StarRailUID/starrailuid_charinfo/damage/Base/AvatarBase.py index 61fda3a..dc75d3e 100644 --- a/StarRailUID/starrailuid_charinfo/damage/Base/AvatarBase.py +++ b/StarRailUID/starrailuid_charinfo/damage/Base/AvatarBase.py @@ -1,14 +1,14 @@ import json -from pathlib import Path from abc import abstractmethod -from typing import List, Union +from pathlib import Path +from typing import List, Tuple, Union import msgspec from msgspec import Struct -from .SkillBase import BaseSkills from ....utils.excel.model import AvatarPromotionConfig -from .model import DamageInstanceSkill, DamageInstanceAvatar +from .model import DamageInstanceAvatar, DamageInstanceSkill +from .SkillBase import BaseSkills path = Path(__file__).parent.parent with Path.open(path / 'Excel' / 'SkillData.json', encoding='utf-8') as f: @@ -24,7 +24,7 @@ class BaseAvatarAttribute(Struct): CriticalDamageBase: float BaseAggro: float - def items(self): + def items(self) -> List[Tuple[str, float]]: return [ ('attack', self.attack), ('defence', self.defence), diff --git a/StarRailUID/starrailuid_charinfo/damage/Base/RelicBase.py b/StarRailUID/starrailuid_charinfo/damage/Base/RelicBase.py index 174013d..d24a8d9 100644 --- a/StarRailUID/starrailuid_charinfo/damage/Base/RelicBase.py +++ b/StarRailUID/starrailuid_charinfo/damage/Base/RelicBase.py @@ -1,10 +1,13 @@ -from typing import Dict from abc import abstractmethod +from typing import TYPE_CHECKING, Dict from gsuid_core.logger import logger -from .model import DamageInstanceRelic from ....utils.map.SR_MAP_PATH import RelicSetSkill +from .model import DamageInstanceRelic + +if TYPE_CHECKING: + from ....utils.map.model.RelicSetSkill import RelicSetStatusAdd class SingleRelic: @@ -69,25 +72,24 @@ class BaseRelicSetSkill: ... def set_skill_property_ability(self): - set_property = '' - set_value = 0 + + def add_relic_set_attribute(status_add: RelicSetStatusAdd): + set_property = status_add.Property + set_value = status_add.Value + if set_property != '': + relic_set_attribute[set_property] = ( + relic_set_attribute.get(set_property, 0) + set_value + ) + relic_set_attribute: Dict[str, float] = {} if self.pieces2: status_add = RelicSetSkill.RelicSet[str(self.setId)]['2'] if status_add: - set_property = status_add.Property - set_value = status_add.Value - if set_property != '': - relic_set_attribute[set_property] = ( - relic_set_attribute.get(set_property, 0) + set_value - ) + add_relic_set_attribute(status_add) + if self.pieces4: status_add = RelicSetSkill.RelicSet[str(self.setId)]['4'] if status_add: - set_property = status_add.Property - set_value = status_add.Value - if set_property != '': - relic_set_attribute[set_property] = ( - relic_set_attribute.get(set_property, 0) + set_value - ) + add_relic_set_attribute(status_add) + return relic_set_attribute diff --git a/StarRailUID/starrailuid_charinfo/damage/Base/SkillBase.py b/StarRailUID/starrailuid_charinfo/damage/Base/SkillBase.py index e3c84df..7dbdf65 100644 --- a/StarRailUID/starrailuid_charinfo/damage/Base/SkillBase.py +++ b/StarRailUID/starrailuid_charinfo/damage/Base/SkillBase.py @@ -1,14 +1,23 @@ import json -from typing import List from pathlib import Path +from typing import List -from .model import DamageInstanceSkill, DamageInstanceAvatar +from .model import DamageInstanceAvatar, DamageInstanceSkill path = Path(__file__).parent.parent with Path.open(path / 'Excel' / 'SkillData.json', encoding='utf-8') as f: skill_dict = json.load(f) +skill_types = { + 'Normal': 'Normal_', + 'BPSkill': 'BPSkill_', + 'Ultra': 'Ultra_', + 'Maze': 'Maze_', + '': 'Talent_' +} + + class SingleSkill: def __init__(self, skill: DamageInstanceSkill): self.id = skill.skillId @@ -28,18 +37,9 @@ class BaseSkills: ): for skill in skills: skill_attack_type = skill.skillAttackType - if skill_attack_type == 'Normal': - cls.Normal_ = SingleSkill(skill) - elif skill_attack_type == 'BPSkill': - cls.BPSkill_ = SingleSkill(skill) - elif skill_attack_type == 'Ultra': - cls.Ultra_ = SingleSkill(skill) - elif skill_attack_type == 'Maze': - cls.Maze_ = SingleSkill(skill) - elif skill_attack_type == '': - cls.Talent_ = SingleSkill(skill) - else: + if skill_attack_type not in skill_types: raise ValueError( f'Unknown skillAttackType: {skill_attack_type}' ) + setattr(cls, skill_types[skill_attack_type], SingleSkill(skill)) return cls diff --git a/StarRailUID/starrailuid_charinfo/damage/Base/WeaponBase.py b/StarRailUID/starrailuid_charinfo/damage/Base/WeaponBase.py index d6bb1ab..cd12fe7 100644 --- a/StarRailUID/starrailuid_charinfo/damage/Base/WeaponBase.py +++ b/StarRailUID/starrailuid_charinfo/damage/Base/WeaponBase.py @@ -1,11 +1,11 @@ -from typing import Dict from abc import abstractmethod +from typing import Dict, List, Tuple from msgspec import Struct -from .model import DamageInstanceWeapon from ....utils.excel.model import EquipmentPromotionConfig from ....utils.map.SR_MAP_PATH import EquipmentID2AbilityProperty +from .model import DamageInstanceWeapon class BaseWeaponAttribute(Struct): @@ -13,7 +13,7 @@ class BaseWeaponAttribute(Struct): attack: float defence: float - def items(self): + def items(self) -> List[Tuple[str, float]]: return [ ('hp', self.hp), ('attack', self.attack), diff --git a/StarRailUID/starrailuid_charinfo/damage/Role.py b/StarRailUID/starrailuid_charinfo/damage/Role.py index 721106e..6e57603 100644 --- a/StarRailUID/starrailuid_charinfo/damage/Role.py +++ b/StarRailUID/starrailuid_charinfo/damage/Role.py @@ -28,7 +28,9 @@ async def calculate_damage( logger.info(f'Attack: {attack}') damage_reduction = calculate_damage_reduction(level) - resistance_area = calculate_resistance_area(merged_attr, element) + resistance_area = calculate_resistance_area( + merged_attr, skill_type, add_skill_type, element + ) defence_multiplier = calculate_defence_multiplier(level, merged_attr) injury_area = calculate_injury_area( merged_attr, skill_type, add_skill_type, element @@ -111,13 +113,33 @@ def calculate_damage_reduction(level: int): return 1 - enemy_damage_reduction -def calculate_resistance_area(merged_attr: Dict[str, float], element: str): - enemy_status_resistance = sum( - merged_attr.get(attr, 0) - for attr in merged_attr - if 'ResistancePenetration' in attr - ) - return 1.0 - max(0, -enemy_status_resistance) +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] + # 检查是否有某一技能属性的抗性穿透 + skill_name, skillattr_name = ( + attr_name.split('_', 1) if '_' in attr_name else (None, None) + ) + if skill_name in ( + skill_type, + 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( diff --git a/StarRailUID/starrailuid_charinfo/damage/Weapon/Weapon.py b/StarRailUID/starrailuid_charinfo/damage/Weapon/Weapon.py index 09be5e6..7fb50fc 100644 --- a/StarRailUID/starrailuid_charinfo/damage/Weapon/Weapon.py +++ b/StarRailUID/starrailuid_charinfo/damage/Weapon/Weapon.py @@ -1,9 +1,9 @@ import json -from typing import Dict from pathlib import Path +from typing import Dict -from ..Base.WeaponBase import BaseWeapon from ..Base.model import DamageInstanceWeapon +from ..Base.WeaponBase import BaseWeapon path = Path(__file__).parent.parent with Path.open(path / 'Excel' / 'weapon_effect.json', encoding='utf-8') as f: @@ -1698,14 +1698,15 @@ class SleepLiketheDead(BaseWeapon): base_attr: Dict[str, float], attribute_bonus: Dict[str, float], ): - if await self.check(): - critical_chance_base = attribute_bonus.get('CriticalChanceBase', 0) - attribute_bonus['CriticalChanceBase'] = ( - critical_chance_base - + weapon_effect['23012']['Param']['CriticalChance'][ - self.weapon_rank - 1 - ] - ) + if not await self.check(): + return attribute_bonus + critical_chance_base = attribute_bonus.get('CriticalChanceBase', 0) + attribute_bonus['CriticalChanceBase'] = ( + critical_chance_base + + weapon_effect['23012']['Param']['CriticalChance'][ + self.weapon_rank - 1 + ] + ) return attribute_bonus