diff --git a/StarRailUID/sruid_utils/api/mihomo/models.py b/StarRailUID/sruid_utils/api/mihomo/models.py index 429e3f5..30cd5ac 100644 --- a/StarRailUID/sruid_utils/api/mihomo/models.py +++ b/StarRailUID/sruid_utils/api/mihomo/models.py @@ -38,7 +38,7 @@ class Avatar(Struct): avatarId: int level: int equipment: Equipment | None = None - relicList: list[Relic] | None = None + relicList: list[Relic] | None = field(default=[]) pos: int | None = field(default=0) rank: int | None = field(default=0) promotion: int | None = field(default=0) diff --git a/StarRailUID/starrailuid_charinfo/cal_damage.py b/StarRailUID/starrailuid_charinfo/cal_damage.py index 2976008..c4a09d0 100644 --- a/StarRailUID/starrailuid_charinfo/cal_damage.py +++ b/StarRailUID/starrailuid_charinfo/cal_damage.py @@ -2,7 +2,7 @@ import json from pathlib import Path from typing import Dict, List, Union -from .effect.Role import RoleInstance +from .effect.damageCal import DamageCalculator from .mono.Character import Character Excel_path = Path(__file__).parent / 'effect' @@ -26,8 +26,7 @@ async def cal(char_data: Dict): skill_list = skill_dict[str(char.char_id)]['skillList'] skill_list = skill_list.keys() for skill_type in skill_list: - role = RoleInstance(char) - im_tmp = await role.cal_damage(skill_type) + im_tmp = await DamageCalculator(char).cal_damage(skill_type) skill_info_list.append(im_tmp) return skill_info_list return '角色伤害计算未完成' diff --git a/StarRailUID/starrailuid_charinfo/draw_char_img.py b/StarRailUID/starrailuid_charinfo/draw_char_img.py index 8d7f766..c059f1a 100644 --- a/StarRailUID/starrailuid_charinfo/draw_char_img.py +++ b/StarRailUID/starrailuid_charinfo/draw_char_img.py @@ -4,29 +4,14 @@ import textwrap from pathlib import Path from typing import Dict, Union -from PIL import Image, ImageDraw from gsuid_core.logger import logger from gsuid_core.utils.image.convert import convert_img from gsuid_core.utils.image.image_tools import draw_text_by_line +from PIL import Image, ImageDraw -from .to_data import api_to_dict from ..utils.error_reply import CHAR_HINT -from .cal_damage import cal, cal_char_info -from ..utils.fonts.first_world import fw_font_28 from ..utils.excel.read_excel import light_cone_ranks -from ..utils.map.name_covert import name_to_avatar_id, alias_to_char_name -from ..utils.map.SR_MAP_PATH import ( - RelicId2Rarity, - AvatarRelicScore, - avatarId2Name, -) -from ..utils.resource.RESOURCE_PATH import ( - RELIC_PATH, - SKILL_PATH, - PLAYER_PATH, - WEAPON_PATH, - CHAR_PORTRAIT_PATH, -) +from ..utils.fonts.first_world import fw_font_28 from ..utils.fonts.starrail_fonts import ( sr_font_18, sr_font_20, @@ -37,6 +22,21 @@ from ..utils.fonts.starrail_fonts import ( sr_font_34, sr_font_38, ) +from ..utils.map.name_covert import alias_to_char_name, name_to_avatar_id +from ..utils.map.SR_MAP_PATH import ( + AvatarRelicScore, + RelicId2Rarity, + avatarId2Name, +) +from ..utils.resource.RESOURCE_PATH import ( + CHAR_PORTRAIT_PATH, + PLAYER_PATH, + RELIC_PATH, + SKILL_PATH, + WEAPON_PATH, +) +from .cal_damage import cal, cal_char_info +from .to_data import api_to_dict Excel_path = Path(__file__).parent / 'effect' with Path.open(Excel_path / 'Excel' / 'SkillData.json', encoding='utf-8') as f: @@ -99,7 +99,7 @@ async def draw_char_img(char_data: Dict, sr_uid: str, msg: str): return char_data char = await cal_char_info(char_data) damage_len = 0 - if str(char.char_id) in skill_dict: + if char.char_id in skill_dict: skill_list = skill_dict[str(char.char_id)]['skillList'] damage_len = len(skill_list) bg_height = 0 diff --git a/StarRailUID/starrailuid_charinfo/effect/Avatar/Avatar.py b/StarRailUID/starrailuid_charinfo/effect/Avatar/Avatar.py index 16a1f46..2edc6bb 100644 --- a/StarRailUID/starrailuid_charinfo/effect/Avatar/Avatar.py +++ b/StarRailUID/starrailuid_charinfo/effect/Avatar/Avatar.py @@ -3,7 +3,7 @@ from typing import Dict, List from gsuid_core.logger import logger from ..Base.AvatarBase import BaseAvatar, BaseAvatarBuff -from ..Base.model import DamageInstanceSkill, DamageInstanceAvatar +from ..Base.model import DamageInstanceAvatar, DamageInstanceSkill class Seele(BaseAvatar): diff --git a/StarRailUID/starrailuid_charinfo/effect/Base/AvatarBase.py b/StarRailUID/starrailuid_charinfo/effect/Base/AvatarBase.py index 5841899..930c32c 100644 --- a/StarRailUID/starrailuid_charinfo/effect/Base/AvatarBase.py +++ b/StarRailUID/starrailuid_charinfo/effect/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/effect/Relic/Relic.py b/StarRailUID/starrailuid_charinfo/effect/Relic/Relic.py index cf40c97..7e2b21f 100644 --- a/StarRailUID/starrailuid_charinfo/effect/Relic/Relic.py +++ b/StarRailUID/starrailuid_charinfo/effect/Relic/Relic.py @@ -240,7 +240,6 @@ class Relic110(BaseRelicSetSkill): ): if self.pieces4 and await self.check(base_attr, attribute_bonus): logger.info('ModifyActionDelay') - pass return attribute_bonus @@ -263,7 +262,6 @@ class Relic111(BaseRelicSetSkill): ): if self.pieces4 and await self.check(base_attr, attribute_bonus): logger.info('ModifySPNew') - pass return attribute_bonus diff --git a/StarRailUID/starrailuid_charinfo/effect/Role.py b/StarRailUID/starrailuid_charinfo/effect/Role.py index e096a61..833bcd8 100644 --- a/StarRailUID/starrailuid_charinfo/effect/Role.py +++ b/StarRailUID/starrailuid_charinfo/effect/Role.py @@ -4,16 +4,12 @@ from typing import List, Union from gsuid_core.logger import logger -from .Avatar.Avatar import Avatar -from .Weapon.Weapon import Weapon -from .utils import merge_attribute from ..mono.Character import Character +from .Avatar.Avatar import Avatar from .Base.model import DamageInstance from .Relic.Relic import RelicSet, SingleRelic - -Excel_path = Path(__file__).parent -with Path.open(Excel_path / 'Excel' / 'SkillData.json', encoding='utf-8') as f: - skill_dict = json.load(f) +from .utils import merge_attribute +from .Weapon.Weapon import Weapon class RoleInstance: @@ -119,416 +115,3 @@ class RoleInstance: self.attribute_bonus[attribute] = self.weapon.weapon_attribute[ attribute ] - - async def cal_damage(self, skill_type: str): - logger.info('base_attr') - logger.info(self.base_attr) - logger.info('attribute_bonus') - logger.info(self.attribute_bonus) - logger.info(skill_type) - # 技能区 - skill_info = self.avatar.Skill_Info(skill_type) - skill_multiplier = self.avatar.Skill_num(skill_info[4], skill_type) - # 检查是否有对某一个技能的倍率加成 - for attr in self.attribute_bonus: - if attr.__contains__('SkillAdd'): - skill_name = attr.split('SkillAdd')[0] - if skill_name in (skill_type, skill_info[3]): - logger.info( - f'{skill_name}对{skill_type}有{self.attribute_bonus[attr]}倍率加成' - ) - skill_multiplier = ( - skill_multiplier + self.attribute_bonus[attr] - ) - - logger.info(f'技能区总: {skill_multiplier}') - - # 检查武器战斗生效的buff - logger.info('检查武器战斗生效的buff') - Ultra_Use = self.avatar.Ultra_Use() - logger.info('Ultra_Use') - logger.info(Ultra_Use) - self.attribute_bonus = await self.weapon.weapon_ability( - Ultra_Use, self.base_attr, self.attribute_bonus - ) - logger.info(self.attribute_bonus) - logger.info('检查遗器套装战斗生效的buff') - for set_skill in self.relic_set.SetSkill: - self.attribute_bonus = await set_skill.set_skill_ability( - self.base_attr, self.attribute_bonus - ) - if self.attribute_bonus is None: - raise Exception('attribute_bonus is None') - logger.info(self.attribute_bonus) - - # 检查是否有对某一个技能的属性加成 - logger.info('检查是否有对某一个技能的属性加成') - for attr in self.attribute_bonus: - # 攻击加成 - if attr.__contains__('AttackAddedRatio'): - attr_name = attr.split('AttackAddedRatio')[0] - if attr_name in (skill_type, skill_info[3]): - attack_added_ratio = self.attribute_bonus.get( - 'AttackAddedRatio', 0 - ) - self.attribute_bonus['AttackAddedRatio'] = ( - attack_added_ratio + self.attribute_bonus[attr] - ) - # 效果命中加成 - if attr.__contains__('StatusProbabilityBase'): - attr_name = attr.split('StatusProbabilityBase')[0] - if attr_name in (skill_type, skill_info[3]): - status_probability = self.attribute_bonus.get( - 'StatusProbabilityBase', 0 - ) - self.attribute_bonus['StatusProbabilityBase'] = ( - status_probability + self.attribute_bonus[attr] - ) - - merged_attr = await merge_attribute( - self.base_attr, self.attribute_bonus - ) - logger.info(f'{merged_attr}') - skill_info_list = [] - # 技能类型为攻击 - if skill_info[0] == 'attack': - if isinstance(skill_info[2], str): - raise Exception('skill_info[2] is str') - skill_multiplier = skill_multiplier / skill_info[2] - logger.info(f'技能区单段: {skill_multiplier}') - if self.raw_data.avatar.id_ == 1004: - if self.raw_data.avatar.rank >= 6 and skill_type == 'BPSkill': - skill_info[2] = skill_info[2] + 1 - multiplier_add = self.avatar.Talent() - skill_multiplier = skill_multiplier + multiplier_add - - if ( - self.raw_data.avatar.id_ == 1201 - and self.raw_data.avatar.rank >= 4 - and skill_type == 'Normal' - ): - skill_info[2] = skill_info[2] + 1 - - attack = merged_attr.get('attack', 0) - if self.raw_data.avatar.id_ == 1104: - # 杰帕德天赋加攻 - defence = merged_attr['defence'] - attack = attack + (defence * 0.35) - logger.info(f'攻击力: {attack}') - damage_add = 0 - hp_multiplier = 0 - hp_num = 0 - if self.raw_data.avatar.id_ in [1205, 1208]: - hp_num = merged_attr['hp'] - skill_type_hp = skill_type + '_HP' - if skill_type_hp in skill_dict[str(self.raw_data.avatar.id_)]: - hp_multiplier = self.avatar.Skill_num( - skill_info[4], skill_type_hp - ) - else: - hp_multiplier = 0 - for attr in self.attribute_bonus: - if attr.__contains__('HpSkillAdd'): - skill_name = attr.split('HpSkillAdd')[0] - if skill_name in (skill_type, skill_info[3]): - logger.info( - f'{skill_name}对{skill_type}有{self.attribute_bonus[attr]}倍率加成' - ) - hp_multiplier = ( - hp_multiplier + self.attribute_bonus[attr] - ) - - if skill_type == 'Talent': - if ( - self.raw_data.avatar.rank >= 6 - and self.raw_data.avatar.id_ == 1205 - ): - damage_add = hp_num * 0.5 - attack = (skill_multiplier * attack) + (hp_multiplier * hp_num) - skill_multiplier = 1 - logger.info(f'混伤区: {attack}') - - logger.info(f'额外伤害: {damage_add}') - # 模拟 同属性弱点 同等级 的怪物 - # 韧性条减伤 - enemy_damage_reduction = 0.1 - damage_reduction = 1 - enemy_damage_reduction - logger.info(f'韧性区: {damage_reduction}') - # 抗性区 - enemy_status_resistance = 0.0 - for attr in merged_attr: - if attr.__contains__('ResistancePenetration'): - # 检查是否有某一属性的抗性穿透 - attr_name = attr.split('ResistancePenetration')[0] - if attr_name in (self.avatar.avatar_element, 'AllDamage'): - logger.info(f'{attr_name}属性有{merged_attr[attr]}穿透加成') - enemy_status_resistance += merged_attr[attr] - # 检查是否有某一技能属性的抗性穿透 - if attr_name.__contains__('_'): - skill_name = attr_name.split('_')[0] - skillattr_name = attr_name.split('_')[1] - if skill_name in ( - skill_type, - skill_info[3], - ) and skillattr_name in ( - self.avatar.avatar_element, - 'AllDamage', - ): - enemy_status_resistance += merged_attr[attr] - logger.info( - f'{skill_name}对{skillattr_name}属性有{merged_attr[attr]}穿透加成' - ) - resistance_area = 1.0 - (0 - enemy_status_resistance) - logger.info(f'抗性区: {resistance_area}') - - # 防御区 - # 检查是否有 ignore_defence - logger.info('检查是否有 ignore_defence') - ignore_defence = 1.0 - for attr in merged_attr: - if attr == 'ignore_defence': - ignore_defence = 1 - merged_attr[attr] - break - logger.info(f'ignore_defence {ignore_defence}') - enemy_defence = ( - self.avatar.avatar_level * 10 + 200 - ) * ignore_defence - defence_multiplier = (self.avatar.avatar_level * 10 + 200) / ( - self.avatar.avatar_level * 10 + 200 + enemy_defence - ) - logger.info(f'防御区: {defence_multiplier}') - - # 增伤区 - # TODO: 这里计算只考虑了希儿,需要重写 injury_area = self.avatar.Talent_add() - injury_area = self.avatar.Talent_add() - # 检查是否有对某一个技能的伤害加成 - logger.info('检查是否有对某一个技能的伤害加成') - for attr in merged_attr: - if attr.__contains__('DmgAdd'): - attr_name = attr.split('DmgAdd')[0] - if attr_name in (skill_type, skill_info[3]): - logger.info( - f'{attr} 对 {skill_type} 有 {merged_attr[attr]} 伤害加成' - ) - injury_area += merged_attr[attr] - # 检查有无符合属性的伤害加成 - logger.info('检查球有无符合属性的伤害加成') - element_area = 0 - for attr in merged_attr: - if attr.__contains__('AddedRatio'): - attr_name = attr.split('AddedRatio')[0] - if attr_name in (self.avatar.avatar_element, 'AllDamage'): - logger.info( - f'{attr} 对 {self.avatar.avatar_element} ' - f'有 {merged_attr[attr]} 伤害加成' - ) - if attr_name == self.avatar.avatar_element: - element_area += merged_attr[attr] - injury_area += merged_attr[attr] - injury_area += 1 - logger.info(f'增伤区: {injury_area}') - - # 易伤区 - logger.info('检查是否有易伤加成') - damage_ratio = merged_attr.get('DmgRatio', 0) - # 检查是否有对特定技能的易伤加成 - # Talent_DmgRatio - for attr in merged_attr: - if attr.__contains__('_DmgRatio'): - skill_name = attr.split('_')[0] - if skill_name in (skill_type, skill_info[3]): - logger.info( - f'{attr} 对 {skill_type} 有 {merged_attr[attr]} 易伤加成' - ) - damage_ratio += merged_attr[attr] - damage_ratio = damage_ratio + 1 - logger.info(f'易伤: {damage_ratio}') - - # 爆伤区 - if skill_type == 'DOT': - critical_damage_base = 0.0 - else: - logger.info('检查是否有爆伤加成') - logger.info(f'{merged_attr}') - critical_damage_base = merged_attr.get('CriticalDamageBase', 0) - # 检查是否有对特定技能的爆伤加成 - # Ultra_CriticalChance - for attr in merged_attr: - if attr.__contains__('_CriticalDamageBase'): - skill_name = attr.split('_')[0] - if skill_name in (skill_type, skill_info[3]): - logger.info( - f'{attr} 对 {skill_type} 有 ' - f'{merged_attr[attr]} 爆伤加成' - ) - critical_damage_base += merged_attr[attr] - critical_damage = critical_damage_base + 1 - logger.info(f'暴伤: {critical_damage}') - - # 暴击区 - logger.info('检查是否有暴击加成') - critical_chance_base = merged_attr['CriticalChanceBase'] - # 检查是否有对特定技能的爆伤加成 - # Ultra_CriticalChance - for attr in merged_attr: - if attr.__contains__('_CriticalChance'): - skill_name = attr.split('_')[0] - if skill_name in (skill_type, skill_info[3]): - logger.info( - f'{attr} 对 {skill_type} 有 ' - f'{merged_attr[attr]} 暴击加成' - ) - critical_chance_base += merged_attr[attr] - critical_chance_base = min(1, critical_chance_base) - logger.info(f'暴击: {critical_chance_base}') - - # 期望伤害 - qiwang_damage = (critical_chance_base * critical_damage_base) + 1 - logger.info(f'暴击期望: {qiwang_damage}') - damage_cd_z = 0.0 - damage_qw_z = 0.0 - damage_tz_z = 0.0 - attack_tz = 0.0 - injury_add = 0.0 - critical_damage_add = 0 - for i in range(1, skill_info[2] + 1): - injury_add = 0 - critical_damage_add = 0 - if self.raw_data.avatar.id_ == 1213: - injury_add = self.avatar.Talent() - critical_damage_add = self.avatar.BPSkill() - normal_buff = merged_attr.get('Normal_buff', 0) - if i >= 4: - normal_buff = min(4, int(normal_buff + (i - 3))) - if normal_buff >= 1: - critical_damage_add = normal_buff * critical_damage_add - atk_buff = merged_attr.get('Atk_buff', 0) - atk_buff = min(10, int((i - 1) * (atk_buff + 1))) - injury_add = atk_buff * injury_add - qiwang_damage = ( - critical_chance_base - * (critical_damage_base + critical_damage_add) - ) + 1 - - damage_cd = ( - attack - * skill_multiplier - * damage_ratio - * (injury_area + injury_add) - * defence_multiplier - * resistance_area - * damage_reduction - * (critical_damage + critical_damage_add) - + damage_add - ) - damage_cd_z += damage_cd - damage_qw = ( - attack - * skill_multiplier - * damage_ratio - * (injury_area + injury_add) - * defence_multiplier - * resistance_area - * damage_reduction - * qiwang_damage - + damage_add - ) - damage_qw_z += damage_qw - - attr_value_tz: float = self.base_attr.get('attack', 0) - attribute_atk = self.attribute_bonus.get('AttackDelta', 0) - attack_tz = ( - attr_value_tz - + attr_value_tz - * ( - 1 - + self.attribute_bonus.get('AttackAddedRatio', 0) - + 2.144 - ) - + attribute_atk - ) - if self.raw_data.avatar.id_ in [1205, 1208]: - attack_tz = (skill_multiplier * attack_tz) + ( - hp_multiplier * hp_num - ) - injury_add_tz = 0 - if self.avatar.avatar_element == 'Imaginary': - injury_add_tz = 0.12 - damage_tz = ( - attack_tz - * skill_multiplier - * damage_ratio - * (injury_area + injury_add + injury_add_tz + 2.326) - * defence_multiplier - * resistance_area - * damage_reduction - * (critical_damage + critical_damage_add + 1.594) - * 10 - + damage_add - ) - - damage_tz_z += damage_tz - - if ( - self.raw_data.avatar.id_ == 1003 - and self.raw_data.avatar.rank >= 6 - ): - damage_cd_z = damage_cd_z * 1.8 - damage_qw_z = damage_qw_z * 1.8 - damage_tz_z = damage_tz_z * 1.8 - - if self.avatar.avatar_element == 'Thunder': - element_area = 0 - damage_tz_fj = ( - attack_tz - * 0.44 - * damage_ratio - * (injury_area + injury_add + 2.326 + element_area) - * defence_multiplier - * resistance_area - * damage_reduction - * (critical_damage + critical_damage_add + 1.594) - * 10 - ) - damage_tz_z += damage_tz_fj - skill_info_list: List[Union[str, float]] = [] - skill_info_list.append(skill_info[1]) - skill_info_list.append(damage_cd_z) - skill_info_list.append(damage_qw_z) - skill_info_list.append(damage_tz_z) - logger.info( - f'{skill_info[1]} 暴击伤害: {damage_cd_z} 期望伤害{damage_qw_z}' - ) - - # 技能类型为防御 - if skill_info[0] == 'defence': - defence = merged_attr['defence'] - logger.info(f'防御力: {defence}') - defence_multiplier = 0 - - # 获取技能提供的固定护盾值 - if skill_type == 'Normal': - defence_multiplier = self.avatar.Normalnum('Normal_G') - elif skill_type == 'BPSkill': - defence_multiplier = self.avatar.BPSkill_num('BPSkill_G') - elif skill_type == 'Ultra': - defence_multiplier = self.avatar.Ultra_num('Ultra_G') - elif skill_type == 'Talent': - defence_multiplier = self.avatar.Talent_num('Talent_G') - - # 检查是否有护盾加成 - shield_added_ratio = merged_attr.get('shield_added_ratio', 0) - shield_added = shield_added_ratio + 1 - logger.info(f'护盾加成: {shield_added}') - - defence_num = ( - defence * skill_multiplier + defence_multiplier - ) * shield_added - - skill_info_list: List[Union[str, float]] = [] - skill_info_list.append(skill_info[1]) - skill_info_list.append(defence_num) - skill_info_list.append(defence_num) - skill_info_list.append(defence_num) - - return skill_info_list diff --git a/StarRailUID/starrailuid_charinfo/effect/damageCal.py b/StarRailUID/starrailuid_charinfo/effect/damageCal.py new file mode 100644 index 0000000..6dc107c --- /dev/null +++ b/StarRailUID/starrailuid_charinfo/effect/damageCal.py @@ -0,0 +1,460 @@ +import json +from copy import deepcopy +from pathlib import Path +from typing import List, Union + +from gsuid_core.logger import logger + +from ..mono.Character import Character +from .Role import RoleInstance +from .utils import merge_attribute + +Excel_path = Path(__file__).parent +with Path.open(Excel_path / 'Excel' / 'SkillData.json', encoding='utf-8') as f: + skill_dict = json.load(f) + + +class DamageCalculator: + def __init__(self, char_data: Character): + self.char_data = deepcopy(char_data) + self.role = RoleInstance(self.char_data) + + def clear(self): + self.role = RoleInstance(self.char_data) + self.merged_attr = None + + def get_skill_info(self, skill_type: str): + return self.role.avatar.Skill_Info(skill_type) + + async def skill_calculation(self, skill_type: str): + skill_info = self.role.avatar.Skill_Info(skill_type) + skill_multiplier = self.role.avatar.Skill_num(skill_info[4], skill_type) + for attr in self.role.attribute_bonus: + if attr.__contains__('SkillAdd'): + skill_name = attr.split('SkillAdd')[0] + if skill_name in (skill_type, skill_info[3]): + logger.info( + f'{skill_name}对{skill_type}有{self.role.attribute_bonus[attr]}倍率加成' + ) + skill_multiplier = ( + skill_multiplier + self.role.attribute_bonus[attr] + ) + + logger.info(f'技能区总: {skill_multiplier}') + + async def weapon_calculation(self): + logger.info('检查武器战斗生效的buff') + Ultra_Use = self.role.avatar.Ultra_Use() + logger.info('Ultra_Use') + logger.info(Ultra_Use) + self.role.attribute_bonus = await self.role.weapon.weapon_ability( + Ultra_Use, self.role.base_attr, self.role.attribute_bonus + ) + logger.info(self.role.attribute_bonus) + logger.info('检查遗器套装战斗生效的buff') + for set_skill in self.role.relic_set.SetSkill: + self.role.attribute_bonus = await set_skill.set_skill_ability( + self.role.base_attr, self.role.attribute_bonus + ) + if self.role.attribute_bonus is None: + raise Exception('attribute_bonus is None') + logger.info(self.role.attribute_bonus) + + async def attribute_calculation(self, skill_type: str): + # 检查是否有对某一个技能的属性加成 + logger.info('检查是否有对某一个技能的属性加成') + for attr in self.role.attribute_bonus: + # 攻击加成 + if attr.__contains__('AttackAddedRatio'): + attr_name = attr.split('AttackAddedRatio')[0] + if attr_name in (skill_type, self.get_skill_info(skill_type)[3]): + attack_added_ratio = self.role.attribute_bonus.get( + 'AttackAddedRatio', 0 + ) + self.role.attribute_bonus['AttackAddedRatio'] = ( + attack_added_ratio + self.role.attribute_bonus[attr] + ) + # 效果命中加成 + if attr.__contains__('StatusProbabilityBase'): + attr_name = attr.split('StatusProbabilityBase')[0] + if attr_name in (skill_type, self.get_skill_info(skill_type)[3]): + status_probability = self.role.attribute_bonus.get( + 'StatusProbabilityBase', 0 + ) + self.role.attribute_bonus['StatusProbabilityBase'] = ( + status_probability + self.role.attribute_bonus[attr] + ) + + self.merged_attr = await merge_attribute( + self.role.base_attr, self.role.attribute_bonus + ) + logger.info(f'{self.merged_attr}') + + async def cal_attack_base_damage(self, skill_type: str): + if isinstance(self.get_skill_info(skill_type)[2], str): + raise TypeError('skill_info[2] is str') + skill_multiplier = self.role.avatar.Skill_num( + self.get_skill_info(skill_type)[4], + skill_type + ) + skill_multiplier = skill_multiplier / int(self.get_skill_info(skill_type)[2]) + logger.info(f'技能区单段: {skill_multiplier}') + if self.role.raw_data.avatar.id_ == 1004: + if self.role.raw_data.avatar.rank >= 6 and skill_type == 'BPSkill': + self.get_skill_info(skill_type)[2] = int(self.get_skill_info(skill_type)[2]) + 1 + multiplier_add = self.role.avatar.Talent() + skill_multiplier = skill_multiplier + multiplier_add + + if ( + self.role.raw_data.avatar.id_ == 1201 + and self.role.raw_data.avatar.rank >= 4 + and skill_type == 'Normal' + ): + self.get_skill_info(skill_type)[2] = int(self.get_skill_info(skill_type)[2]) + 1 + + assert(self.merged_attr is not None) + attack = self.merged_attr.get('attack', 0) + if self.role.raw_data.avatar.id_ == 1104: + # 杰帕德天赋加攻 + defence = self.merged_attr['defence'] + attack = attack + (defence * 0.35) + logger.info(f'攻击力: {attack}') + damage_add = 0 + hp_multiplier = 0 + hp_num = 0 + if self.role.raw_data.avatar.id_ in [1205, 1208]: + hp_num = self.merged_attr['hp'] + skill_type_hp = skill_type + '_HP' + if skill_type_hp in skill_dict[str(self.role.raw_data.avatar.id_)]: + hp_multiplier = self.role.avatar.Skill_num( + self.get_skill_info(skill_type)[4], skill_type_hp + ) + else: + hp_multiplier = 0 + for attr in self.role.attribute_bonus: + if attr.__contains__('HpSkillAdd'): + skill_name = attr.split('HpSkillAdd')[0] + if skill_name in (skill_type, self.get_skill_info(skill_type)[3]): + logger.info( + f'{skill_name}对{skill_type}有{self.role.attribute_bonus[attr]}倍率加成' + ) + hp_multiplier = ( + hp_multiplier + self.role.attribute_bonus[attr] + ) + + if skill_type == 'Talent': + if ( + self.role.raw_data.avatar.rank >= 6 + and self.role.raw_data.avatar.id_ == 1205 + ): + damage_add = hp_num * 0.5 + attack = (skill_multiplier * attack) + (hp_multiplier * hp_num) + skill_multiplier = 1 + logger.info(f'混伤区: {attack}') + + logger.info(f'额外伤害: {damage_add}') + # 模拟 同属性弱点 同等级 的怪物 + # 韧性条减伤 + enemy_damage_reduction = 0.1 + damage_reduction = 1 - enemy_damage_reduction + logger.info(f'韧性区: {damage_reduction}') + # 抗性区 + enemy_status_resistance = 0.0 + for attr in self.merged_attr: + if attr.__contains__('ResistancePenetration'): + # 检查是否有某一属性的抗性穿透 + attr_name = attr.split('ResistancePenetration')[0] + if attr_name in (self.role.avatar.avatar_element, 'AllDamage'): + logger.info(f'{attr_name}属性有{self.merged_attr[attr]}穿透加成') + enemy_status_resistance += self.merged_attr[attr] + # 检查是否有某一技能属性的抗性穿透 + if attr_name.__contains__('_'): + skill_name = attr_name.split('_')[0] + skillattr_name = attr_name.split('_')[1] + if skill_name in ( + skill_type, + self.get_skill_info(skill_type)[3], + ) and skillattr_name in ( + self.role.avatar.avatar_element, + 'AllDamage', + ): + enemy_status_resistance += self.merged_attr[attr] + logger.info( + f'{skill_name}对{skillattr_name}属性有{self.merged_attr[attr]}穿透加成' + ) + resistance_area = 1.0 - (0 - enemy_status_resistance) + logger.info(f'抗性区: {resistance_area}') + + # 防御区 + # 检查是否有 ignore_defence + logger.info('检查是否有 ignore_defence') + ignore_defence = 1.0 + for attr in self.merged_attr: + if attr == 'ignore_defence': + ignore_defence = 1 - self.merged_attr[attr] + break + logger.info(f'ignore_defence {ignore_defence}') + enemy_defence = ( + self.role.avatar.avatar_level * 10 + 200 + ) * ignore_defence + defence_multiplier = (self.role.avatar.avatar_level * 10 + 200) / ( + self.role.avatar.avatar_level * 10 + 200 + enemy_defence + ) + logger.info(f'防御区: {defence_multiplier}') + + # 增伤区 + # TODO: 这里计算只考虑了希儿,需要重写 injury_area = role.avatar.Talent_add() + injury_area = self.role.avatar.Talent_add() + # 检查是否有对某一个技能的伤害加成 + logger.info('检查是否有对某一个技能的伤害加成') + for attr in self.merged_attr: + if attr.__contains__('DmgAdd'): + attr_name = attr.split('DmgAdd')[0] + if attr_name in (skill_type, self.get_skill_info(skill_type)[3]): + logger.info( + f'{attr} 对 {skill_type} 有 {self.merged_attr[attr]} 伤害加成' + ) + injury_area += self.merged_attr[attr] + # 检查有无符合属性的伤害加成 + logger.info('检查球有无符合属性的伤害加成') + element_area = 0 + for attr in self.merged_attr: + if attr.__contains__('AddedRatio'): + attr_name = attr.split('AddedRatio')[0] + if attr_name in (self.role.avatar.avatar_element, 'AllDamage'): + logger.info( + f'{attr} 对 {self.role.avatar.avatar_element} ' + f'有 {self.merged_attr[attr]} 伤害加成' + ) + if attr_name == self.role.avatar.avatar_element: + element_area += self.merged_attr[attr] + injury_area += self.merged_attr[attr] + injury_area += 1 + logger.info(f'增伤区: {injury_area}') + + # 易伤区 + logger.info('检查是否有易伤加成') + damage_ratio = self.merged_attr.get('DmgRatio', 0) + # 检查是否有对特定技能的易伤加成 + # Talent_DmgRatio + for attr in self.merged_attr: + if attr.__contains__('_DmgRatio'): + skill_name = attr.split('_')[0] + if skill_name in (skill_type, self.get_skill_info(skill_type)[3]): + logger.info( + f'{attr} 对 {skill_type} 有 {self.merged_attr[attr]} 易伤加成' + ) + damage_ratio += self.merged_attr[attr] + damage_ratio = damage_ratio + 1 + logger.info(f'易伤: {damage_ratio}') + + # 爆伤区 + if skill_type == 'DOT': + critical_damage_base = 0.0 + else: + logger.info('检查是否有爆伤加成') + logger.info(f'{self.merged_attr}') + critical_damage_base = self.merged_attr.get('CriticalDamageBase', 0) + # 检查是否有对特定技能的爆伤加成 + # Ultra_CriticalChance + for attr in self.merged_attr: + if attr.__contains__('_CriticalDamageBase'): + skill_name = attr.split('_')[0] + if skill_name in (skill_type, self.get_skill_info(skill_type)[3]): + logger.info( + f'{attr} 对 {skill_type} 有 ' + f'{self.merged_attr[attr]} 爆伤加成' + ) + critical_damage_base += self.merged_attr[attr] + critical_damage = critical_damage_base + 1 + logger.info(f'暴伤: {critical_damage}') + + # 暴击区 + logger.info('检查是否有暴击加成') + critical_chance_base = self.merged_attr['CriticalChanceBase'] + # 检查是否有对特定技能的爆伤加成 + # Ultra_CriticalChance + for attr in self.merged_attr: + if attr.__contains__('_CriticalChance'): + skill_name = attr.split('_')[0] + if skill_name in (skill_type, self.get_skill_info(skill_type)[3]): + logger.info( + f'{attr} 对 {skill_type} 有 ' + f'{self.merged_attr[attr]} 暴击加成' + ) + critical_chance_base += self.merged_attr[attr] + critical_chance_base = min(1, critical_chance_base) + logger.info(f'暴击: {critical_chance_base}') + + # 期望伤害 + qiwang_damage = (critical_chance_base * critical_damage_base) + 1 + logger.info(f'暴击期望: {qiwang_damage}') + damage_cd_z = 0.0 + damage_qw_z = 0.0 + damage_tz_z = 0.0 + attack_tz = 0.0 + injury_add = 0.0 + critical_damage_add = 0 + for i in range(1, int(self.get_skill_info(skill_type)[2]) + 1): + injury_add = 0 + critical_damage_add = 0 + if self.role.raw_data.avatar.id_ == 1213: + injury_add = self.role.avatar.Talent() + critical_damage_add = self.role.avatar.BPSkill() + normal_buff = self.merged_attr.get('Normal_buff', 0) + if i >= 4: + normal_buff = min(4, int(normal_buff + (i - 3))) + if normal_buff >= 1: + critical_damage_add = normal_buff * critical_damage_add + atk_buff = self.merged_attr.get('Atk_buff', 0) + atk_buff = min(10, int((i - 1) * (atk_buff + 1))) + injury_add = atk_buff * injury_add + qiwang_damage = ( + critical_chance_base + * (critical_damage_base + critical_damage_add) + ) + 1 + + damage_cd = ( + attack + * skill_multiplier + * damage_ratio + * (injury_area + injury_add) + * defence_multiplier + * resistance_area + * damage_reduction + * (critical_damage + critical_damage_add) + + damage_add + ) + damage_cd_z += damage_cd + damage_qw = ( + attack + * skill_multiplier + * damage_ratio + * (injury_area + injury_add) + * defence_multiplier + * resistance_area + * damage_reduction + * qiwang_damage + + damage_add + ) + damage_qw_z += damage_qw + + attr_value_tz: float = self.role.base_attr.get('attack', 0) + attribute_atk = self.role.attribute_bonus.get('AttackDelta', 0) + attack_tz = ( + attr_value_tz + + attr_value_tz + * ( + 1 + + self.role.attribute_bonus.get('AttackAddedRatio', 0) + + 2.144 + ) + + attribute_atk + ) + if self.role.raw_data.avatar.id_ in [1205, 1208]: + attack_tz = (skill_multiplier * attack_tz) + ( + hp_multiplier * hp_num + ) + injury_add_tz = 0 + if self.role.avatar.avatar_element == 'Imaginary': + injury_add_tz = 0.12 + damage_tz = ( + attack_tz + * skill_multiplier + * damage_ratio + * (injury_area + injury_add + injury_add_tz + 2.326) + * defence_multiplier + * resistance_area + * damage_reduction + * (critical_damage + critical_damage_add + 1.594) + * 10 + + damage_add + ) + + damage_tz_z += damage_tz + + if ( + self.role.raw_data.avatar.id_ == 1003 + and self.role.raw_data.avatar.rank >= 6 + ): + damage_cd_z = damage_cd_z * 1.8 + damage_qw_z = damage_qw_z * 1.8 + damage_tz_z = damage_tz_z * 1.8 + + if self.role.avatar.avatar_element == 'Thunder': + element_area = 0 + damage_tz_fj = ( + attack_tz + * 0.44 + * damage_ratio + * (injury_area + injury_add + 2.326 + element_area) + * defence_multiplier + * resistance_area + * damage_reduction + * (critical_damage + critical_damage_add + 1.594) + * 10 + ) + damage_tz_z += damage_tz_fj + skill_info_list: List[Union[str, float]] = [] + skill_info_list.append(self.get_skill_info(skill_type)[1]) + skill_info_list.append(damage_cd_z) + skill_info_list.append(damage_qw_z) + skill_info_list.append(damage_tz_z) + logger.info( + f'{self.get_skill_info(skill_type)[1]} 暴击伤害: {damage_cd_z} 期望伤害{damage_qw_z}' + ) + return skill_info_list + + async def cal_defense_base_damage(self, skill_type: str): + ########################################### + ########################################### + # 这里我直接cv的, 记得改 # + ########################################### + ########################################### + assert(self.merged_attr is not None) + defence = self.merged_attr['defence'] + logger.info(f'防御力: {defence}') + defence_multiplier = 0 + + # 获取技能提供的固定护盾值 + if skill_type == 'Normal': + defence_multiplier = self.role.avatar.Normalnum('Normal_G') + elif skill_type == 'BPSkill': + defence_multiplier = self.role.avatar.BPSkill_num('BPSkill_G') + elif skill_type == 'Ultra': + defence_multiplier = self.role.avatar.Ultra_num('Ultra_G') + elif skill_type == 'Talent': + defence_multiplier = self.role.avatar.Talent_num('Talent_G') + + # 检查是否有护盾加成 + shield_added_ratio = self.merged_attr.get('shield_added_ratio', 0) + shield_added = shield_added_ratio + 1 + logger.info(f'护盾加成: {shield_added}') + + skill_multiplier = self.role.avatar.Skill_num( + self.get_skill_info(skill_type)[4], + skill_type + ) + skill_multiplier = skill_multiplier / int(self.get_skill_info(skill_type)[2]) + + defence_num = ( + defence * skill_multiplier + defence_multiplier + ) * shield_added + + skill_info_list: List[Union[str, float]] = [] + skill_info_list.append(self.get_skill_info(skill_type)[1]) + skill_info_list.append(defence_num) + skill_info_list.append(defence_num) + skill_info_list.append(defence_num) + + async def cal_heal_base_damage(self): + pass + + async def cal_damage(self, skill_type: str): + await self.skill_calculation(skill_type) + await self.weapon_calculation() + await self.attribute_calculation(skill_type) + skill_info_list = await self.cal_attack_base_damage(skill_type) + self.clear() + + return skill_info_list