mirror of
https://github.com/baiqwerdvd/StarRailUID.git
synced 2025-05-05 11:13:45 +08:00
✨实验性支持希儿伤害计算
This commit is contained in:
parent
cd6a6316ee
commit
f3273bfec4
@ -29,6 +29,9 @@ class Character:
|
||||
self.add_attr = {}
|
||||
self.equipment = card_prop['equipmentInfo']
|
||||
self.rarity = card_prop['avatarRarity']
|
||||
self.eidolons = (
|
||||
card_prop['rankList'] if card_prop.get('rankList') else []
|
||||
)
|
||||
|
||||
# 伤害计算
|
||||
self.def_ignore = 0
|
||||
|
@ -16,8 +16,10 @@ async def cal(char_data: Dict):
|
||||
raw_data['avatar']['id'] = char.char_id
|
||||
raw_data['avatar']['level'] = char.char_level
|
||||
raw_data['avatar']['rank'] = char.char_rank
|
||||
raw_data['avatar']['element'] = char.char_element
|
||||
raw_data['avatar']['promotion'] = char.char_promotion
|
||||
raw_data['avatar']['attribute_bonus'] = char.attribute_bonus
|
||||
raw_data['avatar']['extra_ability'] = char.extra_ability
|
||||
|
||||
raw_data['weapon']['id'] = char.equipment['equipmentID']
|
||||
raw_data['weapon']['level'] = char.equipment['equipmentLevel']
|
||||
@ -26,8 +28,10 @@ async def cal(char_data: Dict):
|
||||
|
||||
raw_data['relic'] = char.char_relic
|
||||
|
||||
raw_data['skill'] = char.char_skill
|
||||
|
||||
for skill_type in ['Normal', 'BPSkill', 'Ultra']:
|
||||
role = RoleInstance(raw_data)
|
||||
await role.cal_role_base_attr()
|
||||
await role.cal_relic_attr_add()
|
||||
await role.cal_avatar_attr_add()
|
||||
print(role)
|
||||
await role.cal_damage(skill_type)
|
||||
return '还没写完呢'
|
||||
|
@ -1,45 +1,54 @@
|
||||
from typing import Dict
|
||||
import json
|
||||
from pathlib import Path
|
||||
from typing import Dict, List
|
||||
from abc import abstractmethod
|
||||
|
||||
from mpmath import mp
|
||||
|
||||
from .Skill import BaseSkills
|
||||
from ....utils.excel.read_excel import AvatarPromotion
|
||||
|
||||
path = Path(__file__).parent
|
||||
with open(path / 'seele.json', 'r', encoding='utf-8') as f:
|
||||
skill_dict = json.load(f)
|
||||
|
||||
mp.dps = 14
|
||||
|
||||
|
||||
class BaseSkills:
|
||||
@abstractmethod
|
||||
async def Basic_ATK(self):
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
async def Skill(self):
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
async def Ultimate(self):
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
async def Talent(self):
|
||||
...
|
||||
class BaseAvatarBuff:
|
||||
def __init__(self, char: Dict, skills: List):
|
||||
self.extra_ability_id = []
|
||||
for extra_ability in char['extra_ability']:
|
||||
self.extra_ability_id.append(extra_ability['extraAbilityId'])
|
||||
|
||||
@abstractmethod
|
||||
async def Technique(self):
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
async def eidolons(self):
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
async def extra_ability(self):
|
||||
...
|
||||
|
||||
|
||||
class BaseAvatar:
|
||||
def __init__(self, char: Dict):
|
||||
Skill: BaseSkills
|
||||
|
||||
def __init__(self, char: Dict, skills: List):
|
||||
self.Skill = BaseSkills(char=char, skills=skills)
|
||||
self.avatar_id = char['id']
|
||||
self.avatar_level = char['level']
|
||||
self.avatar_rank = char['rank']
|
||||
self.avatar_element = char['element']
|
||||
self.avatar_promotion = char['promotion']
|
||||
self.avatar_attribute_bonus = char['attribute_bonus']
|
||||
self.avatar_extra_ability = char['extra_ability']
|
||||
self.avatar_attribute = {}
|
||||
|
||||
async def get_attribute(self):
|
||||
def get_attribute(self):
|
||||
promotion = AvatarPromotion[str(self.avatar_id)][
|
||||
str(self.avatar_promotion)
|
||||
]
|
||||
@ -73,28 +82,67 @@ class BaseAvatar:
|
||||
promotion["BaseAggro"]['Value']
|
||||
)
|
||||
|
||||
def Normal(self):
|
||||
return mp.mpf(
|
||||
skill_dict[str(self.avatar_id)]['Normal'][
|
||||
self.Skill.Normal_.level - 1
|
||||
]
|
||||
)
|
||||
|
||||
class Seele(BaseAvatar, BaseSkills):
|
||||
def __init__(self, char: Dict):
|
||||
super().__init__(char)
|
||||
def BPSkill(self):
|
||||
return mp.mpf(
|
||||
skill_dict[str(self.avatar_id)]['BPSkill'][
|
||||
self.Skill.BPSkill_.level - 1
|
||||
]
|
||||
)
|
||||
|
||||
async def Basic_ATK(self):
|
||||
def Ultra(self):
|
||||
return mp.mpf(
|
||||
skill_dict[str(self.avatar_id)]['Ultra'][
|
||||
self.Skill.Ultra_.level - 1
|
||||
]
|
||||
)
|
||||
|
||||
def Maze(self):
|
||||
return mp.mpf(
|
||||
skill_dict[str(self.avatar_id)]['Maze'][self.Skill.Maze_.level - 1]
|
||||
)
|
||||
|
||||
def Talent(self):
|
||||
return mp.mpf(
|
||||
skill_dict[str(self.avatar_id)][''][self.Skill.Talent_.level - 1]
|
||||
)
|
||||
|
||||
|
||||
class Seele(BaseAvatar):
|
||||
Buff: BaseAvatarBuff
|
||||
|
||||
def __init__(self, char: Dict, skills: List):
|
||||
super().__init__(char=char, skills=skills)
|
||||
self.Buff = BaseAvatarBuff(char=char, skills=skills)
|
||||
self.eidolon_attribute = {}
|
||||
self.extra_ability_attribute = {}
|
||||
self.eidolons()
|
||||
self.extra_ability()
|
||||
|
||||
def Technique(self):
|
||||
pass
|
||||
|
||||
async def Skill(self):
|
||||
pass
|
||||
def eidolons(self):
|
||||
if self.avatar_rank >= 1:
|
||||
self.eidolon_attribute['CriticalDamageBase'] = mp.mpf(0.15)
|
||||
if self.avatar_rank >= 2:
|
||||
self.eidolon_attribute['SpeedAddedRatio'] = mp.mpf(0.5)
|
||||
|
||||
async def Ultimate(self):
|
||||
pass
|
||||
|
||||
async def Talent(self):
|
||||
pass
|
||||
|
||||
async def Technique(self):
|
||||
pass
|
||||
def extra_ability(self):
|
||||
# 额外能力 割裂 抗性穿透提高20
|
||||
if 1102102 in self.Buff.extra_ability_id:
|
||||
self.extra_ability_attribute[
|
||||
'QuantumResistancePenetration'
|
||||
] = mp.mpf(0.2)
|
||||
|
||||
|
||||
class Avatar:
|
||||
def __new__(cls, char: Dict):
|
||||
def __new__(cls, char: Dict, skills: List):
|
||||
if char['id'] == 1102:
|
||||
return Seele(char)
|
||||
return Seele(char, skills)
|
||||
|
@ -0,0 +1,9 @@
|
||||
{
|
||||
"1102": [
|
||||
{
|
||||
"id": 1102102,
|
||||
"property": "QuantumResistancePenetration",
|
||||
"value": 0.2
|
||||
}
|
||||
]
|
||||
}
|
9
StarRailUID/starrailuid_damagecal/effect/Base/Rank.json
Normal file
9
StarRailUID/starrailuid_damagecal/effect/Base/Rank.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"1102": [
|
||||
{
|
||||
"rank": 1,
|
||||
"property" :"CriticalDamageBase",
|
||||
"value": 0.2
|
||||
}
|
||||
]
|
||||
}
|
@ -3,6 +3,10 @@ from abc import abstractmethod
|
||||
from collections import Counter
|
||||
|
||||
from mpmath import mp
|
||||
from gsuid_core.logger import logger
|
||||
|
||||
from .utils import merge_attribute
|
||||
from ....utils.map.SR_MAP_PATH import RelicSetSkill
|
||||
|
||||
mp.dps = 14
|
||||
|
||||
@ -16,8 +20,16 @@ class SingleRelic:
|
||||
self.relic_level = relic.get('Level', 0)
|
||||
self.relic_attribute_bonus = {}
|
||||
|
||||
async def get_attribute_(self):
|
||||
def get_attribute_(self):
|
||||
# MainAffix
|
||||
if (
|
||||
self.raw_relic['MainAffix']['Property']
|
||||
in self.relic_attribute_bonus
|
||||
):
|
||||
self.relic_attribute_bonus[
|
||||
self.raw_relic['MainAffix']['Property']
|
||||
] += mp.mpf(self.raw_relic['MainAffix']['Value'])
|
||||
else:
|
||||
self.relic_attribute_bonus[
|
||||
self.raw_relic['MainAffix']['Property']
|
||||
] = mp.mpf(self.raw_relic['MainAffix']['Value'])
|
||||
@ -34,45 +46,93 @@ class SingleRelic:
|
||||
|
||||
|
||||
class BaseRelicSetSkill:
|
||||
setId: int
|
||||
pieces2: bool = False
|
||||
pieces4: bool = False
|
||||
|
||||
def __init__(self, set_id: int, count: int):
|
||||
self.setId = set_id
|
||||
if count >= 2:
|
||||
self.pieces2 = True
|
||||
logger.info(f'Relic {set_id} 2 pieces set activated')
|
||||
if count == 4:
|
||||
self.pieces4 = True
|
||||
logger.info(f'Relic {set_id} 4 pieces set activated')
|
||||
self.relicSetAttribute = {}
|
||||
self.set_skill_property_ability()
|
||||
|
||||
@abstractmethod
|
||||
async def check(self):
|
||||
async def check(self, base_attr: Dict, attribute_bonus: Dict):
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
async def set_skill_ability(self, char):
|
||||
async def set_skill_ability(self, base_attr: Dict, attribute_bonus: Dict):
|
||||
'''
|
||||
战斗加成属性, 与 set_skill_property() 互斥
|
||||
'''
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
async def set_skill_property_ability(self, char):
|
||||
'''
|
||||
面板加成属性, 与 set_skill_ability_param() 互斥
|
||||
'''
|
||||
...
|
||||
def set_skill_property_ability(self):
|
||||
set_property = ''
|
||||
set_value = mp.mpf(0)
|
||||
if self.pieces2 and RelicSetSkill[str(self.setId)]['2'] != {}:
|
||||
set_property = RelicSetSkill[str(self.setId)]['2']['Property']
|
||||
set_value = mp.mpf(RelicSetSkill[str(self.setId)]['2']['Value'])
|
||||
if self.pieces4 and RelicSetSkill[str(self.setId)]['4'] != {}:
|
||||
set_property = RelicSetSkill[str(self.setId)]['4']['Property']
|
||||
set_value = mp.mpf(RelicSetSkill[str(self.setId)]['4']['Value'])
|
||||
if set_property != '':
|
||||
if set_property in self.relicSetAttribute:
|
||||
self.relicSetAttribute[set_property] = (
|
||||
self.relicSetAttribute[set_property] + set_value
|
||||
)
|
||||
else:
|
||||
self.relicSetAttribute[set_property] = set_value
|
||||
|
||||
|
||||
class Relic108(BaseRelicSetSkill):
|
||||
async def check(self):
|
||||
pass
|
||||
def __init__(self, set_id: int, count: int):
|
||||
super().__init__(set_id, count)
|
||||
|
||||
async def set_skill_ability(self, char):
|
||||
pass
|
||||
async def check(self, base_attr: Dict, attribute_bonus: Dict):
|
||||
'''
|
||||
装备者对敌方目标造成伤害
|
||||
目标拥有量子属性弱点
|
||||
'''
|
||||
logger.info('Relic108 check success')
|
||||
return True
|
||||
|
||||
async def set_skill_property_ability(self, char):
|
||||
pass
|
||||
async def set_skill_ability(self, base_attr: Dict, attribute_bonus: Dict):
|
||||
if self.pieces4 and await self.check(base_attr, attribute_bonus):
|
||||
ignore_defence = attribute_bonus.get('ignore_defence', 0)
|
||||
attribute_bonus['ignore_defence'] = (
|
||||
ignore_defence + mp.mpf(0.10000000009313226) * 2
|
||||
)
|
||||
return attribute_bonus
|
||||
|
||||
|
||||
class Relic306(BaseRelicSetSkill):
|
||||
async def check(self):
|
||||
pass
|
||||
def __init__(self, set_id: int, count: int):
|
||||
super().__init__(set_id, count)
|
||||
|
||||
async def set_skill_ability(self, char):
|
||||
pass
|
||||
async def check(self, base_attr: Dict, attribute_bonus: Dict):
|
||||
'''
|
||||
装备者当前暴击率大于等于50%
|
||||
'''
|
||||
merged_attr = await merge_attribute(base_attr, attribute_bonus)
|
||||
if merged_attr['CriticalChance'] >= mp.mpf(0.5):
|
||||
logger.info('Relic306 check success')
|
||||
return True
|
||||
|
||||
async def set_skill_property_ability(self, char):
|
||||
pass
|
||||
async def set_skill_ability(self, base_attr: Dict, attribute_bonus: Dict):
|
||||
if self.pieces2 and await self.check(base_attr, attribute_bonus):
|
||||
q_dmg = attribute_bonus.get('UltraDmgAdd', 0)
|
||||
attribute_bonus['UltraDmgAdd'] = q_dmg + mp.mpf(0.1500000001396984)
|
||||
a3_dmg = attribute_bonus.get('Follow-UpAttackDmgAdd', 0)
|
||||
attribute_bonus['Follow-UpDmgAdd'] = a3_dmg + mp.mpf(
|
||||
0.1500000001396984
|
||||
)
|
||||
return attribute_bonus
|
||||
|
||||
|
||||
class RelicSet:
|
||||
@ -84,10 +144,11 @@ class RelicSet:
|
||||
OBJECT: SingleRelic
|
||||
Unknow: SingleRelic
|
||||
|
||||
set_id_counter: List
|
||||
SetSkill: List = []
|
||||
set_id_counter: List = []
|
||||
SetSkill: List
|
||||
|
||||
def __init__(self, relic_list: List):
|
||||
self.SetSkill = []
|
||||
set_id_list = []
|
||||
for relic in relic_list:
|
||||
set_id_list.append(relic['SetId'])
|
||||
@ -108,20 +169,21 @@ class RelicSet:
|
||||
self.Unknow = SingleRelic(relic)
|
||||
|
||||
self.set_id_counter: List = Counter(set_id_list).most_common()
|
||||
self.check_set()
|
||||
|
||||
async def get_attribute(self):
|
||||
def get_attribute(self):
|
||||
for item in self.__dict__:
|
||||
if type(self.__dict__[item]) != SingleRelic:
|
||||
break
|
||||
await self.__dict__[item].get_attribute_()
|
||||
self.__dict__[item].get_attribute_()
|
||||
|
||||
async def check_set(self):
|
||||
def check_set(self):
|
||||
for item in self.set_id_counter:
|
||||
set_id = item[0]
|
||||
count = item[1]
|
||||
if count == 1:
|
||||
break
|
||||
if set_id == 108:
|
||||
self.SetSkill.append(Relic108())
|
||||
self.SetSkill.append(Relic108(set_id, count))
|
||||
if set_id == 306:
|
||||
self.SetSkill.append(Relic306())
|
||||
self.SetSkill.append(Relic306(set_id, count))
|
||||
|
@ -1,9 +1,11 @@
|
||||
from typing import Dict
|
||||
|
||||
from mpmath import mp
|
||||
from gsuid_core.logger import logger
|
||||
|
||||
from .Avatar import Avatar
|
||||
from .Weapon import Weapon
|
||||
from .utils import merge_attribute
|
||||
from .Relic import RelicSet, SingleRelic
|
||||
|
||||
mp.dps = 14
|
||||
@ -13,15 +15,21 @@ class RoleInstance:
|
||||
def __init__(self, raw_data: Dict):
|
||||
self.raw_data = raw_data
|
||||
|
||||
self.avatar = Avatar(raw_data['avatar'])
|
||||
self.avatar = Avatar(raw_data['avatar'], raw_data['skill'])
|
||||
self.weapon = Weapon(raw_data['weapon'])
|
||||
self.relic_set = RelicSet(raw_data['relic'])
|
||||
|
||||
self.base_attr = {}
|
||||
self.attribute_bonus = {}
|
||||
|
||||
async def cal_role_base_attr(self):
|
||||
await self.avatar.get_attribute()
|
||||
self.cal_role_base_attr()
|
||||
self.cal_relic_attr_add()
|
||||
self.cal_avatar_attr_add()
|
||||
self.cal_avatar_eidolon_add()
|
||||
self.cal_weapon_attr_add()
|
||||
|
||||
def cal_role_base_attr(self):
|
||||
self.avatar.get_attribute()
|
||||
avatar_attribute = self.avatar.__dict__['avatar_attribute']
|
||||
for attribute in avatar_attribute:
|
||||
if attribute in self.base_attr:
|
||||
@ -29,16 +37,17 @@ class RoleInstance:
|
||||
else:
|
||||
self.base_attr[attribute] = avatar_attribute[attribute]
|
||||
|
||||
await self.weapon.get_attribute()
|
||||
weapon_attribute = self.weapon.__dict__['weapon_attribute']
|
||||
self.weapon.get_attribute()
|
||||
weapon_attribute = self.weapon.__dict__['weapon_base_attribute']
|
||||
for attribute in weapon_attribute:
|
||||
if attribute in self.base_attr:
|
||||
self.base_attr[attribute] += weapon_attribute[attribute]
|
||||
else:
|
||||
self.base_attr[attribute] = weapon_attribute[attribute]
|
||||
|
||||
async def cal_relic_attr_add(self):
|
||||
await self.relic_set.get_attribute()
|
||||
def cal_relic_attr_add(self):
|
||||
# 单件属性
|
||||
self.relic_set.get_attribute()
|
||||
for relic_type in self.relic_set.__dict__:
|
||||
if type(self.relic_set.__dict__[relic_type]) != SingleRelic:
|
||||
break
|
||||
@ -53,7 +62,19 @@ class RoleInstance:
|
||||
attribute
|
||||
] = relic.relic_attribute_bonus[attribute]
|
||||
|
||||
async def cal_avatar_attr_add(self):
|
||||
# 套装面板加成属性
|
||||
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]
|
||||
|
||||
def cal_avatar_attr_add(self):
|
||||
attribute_bonus = self.avatar.avatar_attribute_bonus
|
||||
for bonus in attribute_bonus:
|
||||
status_add = bonus['statusAdd']
|
||||
@ -63,3 +84,144 @@ class RoleInstance:
|
||||
self.attribute_bonus[bonus_property] += value
|
||||
else:
|
||||
self.attribute_bonus[bonus_property] = value
|
||||
|
||||
def cal_avatar_eidolon_add(self):
|
||||
for attribute in self.avatar.eidolon_attribute:
|
||||
if attribute in self.attribute_bonus:
|
||||
self.attribute_bonus[
|
||||
attribute
|
||||
] += self.avatar.eidolon_attribute[attribute]
|
||||
else:
|
||||
self.attribute_bonus[
|
||||
attribute
|
||||
] = self.avatar.eidolon_attribute[attribute]
|
||||
for attribute in self.avatar.extra_ability_attribute:
|
||||
if attribute in self.attribute_bonus:
|
||||
self.attribute_bonus[
|
||||
attribute
|
||||
] += self.avatar.extra_ability_attribute[attribute]
|
||||
else:
|
||||
self.attribute_bonus[
|
||||
attribute
|
||||
] = self.avatar.extra_ability_attribute[attribute]
|
||||
|
||||
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
|
||||
]
|
||||
|
||||
async def cal_damage(self, skill_type):
|
||||
print(self.base_attr)
|
||||
print(self.attribute_bonus)
|
||||
# 检查武器战斗生效的buff
|
||||
logger.info('检查武器战斗生效的buff')
|
||||
self.attribute_bonus = await self.weapon.weapon_ability(
|
||||
self.base_attr, 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
|
||||
)
|
||||
merged_attr = await merge_attribute(
|
||||
self.base_attr, self.attribute_bonus
|
||||
)
|
||||
print(merged_attr)
|
||||
attack = merged_attr['attack']
|
||||
logger.info(f'攻击力: {attack}')
|
||||
# 模拟 同属性弱点 同等级 的怪物
|
||||
# 韧性条减伤
|
||||
enemy_damage_reduction = 0.1
|
||||
damage_reduction = 1 - enemy_damage_reduction
|
||||
logger.info(f'韧性区: {damage_reduction}')
|
||||
# 抗性区
|
||||
enemy_status_resistance = 0
|
||||
for attr in merged_attr:
|
||||
if attr.__contains__('ResistancePenetration'):
|
||||
# 先默认触发
|
||||
enemy_status_resistance = merged_attr[attr]
|
||||
resistance_area = 1 - (0 - enemy_status_resistance)
|
||||
logger.info(f'抗性区: {resistance_area}')
|
||||
|
||||
# 防御区
|
||||
# 检查是否有 ignore_defence
|
||||
logger.info('检查是否有 ignore_defence')
|
||||
ignore_defence = 1
|
||||
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}')
|
||||
|
||||
# 技能区
|
||||
if skill_type == 'Normal':
|
||||
skill_multiplier = self.avatar.Normal()
|
||||
elif skill_type == 'BPSkill':
|
||||
skill_multiplier = self.avatar.BPSkill()
|
||||
elif skill_type == 'Ultra':
|
||||
skill_multiplier = self.avatar.Ultra()
|
||||
else:
|
||||
raise Exception('skill type error')
|
||||
logger.info(f'技能区: {skill_multiplier}')
|
||||
|
||||
# 增伤区
|
||||
# TODO: 这里计算只考虑了希儿,需要重写 injury_area = self.avatar.Talent()
|
||||
injury_area = self.avatar.Talent()
|
||||
# 检查是否有对某一个技能的伤害加成
|
||||
logger.info('检查是否有对某一个技能的伤害加成')
|
||||
for attr in merged_attr:
|
||||
if attr.__contains__('DmgAdd'):
|
||||
attr_name = attr.split('DmgAdd')[0]
|
||||
if attr_name == skill_type:
|
||||
logger.info(
|
||||
f'{attr} 对 {skill_type} 有 {merged_attr[attr]} 伤害加成'
|
||||
)
|
||||
injury_area += merged_attr[attr]
|
||||
# 检查球有无符合属性的伤害加成
|
||||
logger.info('检查球有无符合属性的伤害加成')
|
||||
for attr in merged_attr:
|
||||
if attr.__contains__('AddedRatio'):
|
||||
attr_name = attr.split('AddedRatio')[0]
|
||||
if attr_name == self.avatar.avatar_element:
|
||||
logger.info(
|
||||
f'{attr} 对 {self.avatar.avatar_element} '
|
||||
f'有 {merged_attr[attr]} 伤害加成'
|
||||
)
|
||||
injury_area += merged_attr[attr]
|
||||
logger.info(f'增伤区: {injury_area}')
|
||||
|
||||
# 爆伤区
|
||||
critical_damage = merged_attr['CriticalDamage']
|
||||
# 检查是否有对特定技能的爆伤加成
|
||||
# Ultra_CriticalChance
|
||||
for attr in merged_attr:
|
||||
if attr.__contains__('_CriticalChance'):
|
||||
skill_name = attr.split('_')[0]
|
||||
if skill_name == skill_type:
|
||||
logger.info(
|
||||
f'{attr} 对 {skill_type} 有 {merged_attr[attr]} 爆伤加成'
|
||||
)
|
||||
critical_damage += merged_attr[attr]
|
||||
logger.info(f'暴伤: {critical_damage}')
|
||||
|
||||
damage = (
|
||||
attack
|
||||
* skill_multiplier
|
||||
* injury_area
|
||||
* defence_multiplier
|
||||
* resistance_area
|
||||
* damage_reduction
|
||||
* critical_damage
|
||||
)
|
||||
logger.info(f'{skill_type} 伤害: {damage}')
|
||||
|
48
StarRailUID/starrailuid_damagecal/effect/Base/Skill.py
Normal file
48
StarRailUID/starrailuid_damagecal/effect/Base/Skill.py
Normal file
@ -0,0 +1,48 @@
|
||||
import json
|
||||
from pathlib import Path
|
||||
from typing import Dict, List
|
||||
|
||||
from mpmath import mp
|
||||
|
||||
mp.dps = 14
|
||||
|
||||
|
||||
path = Path(__file__).parent
|
||||
with open(path / 'seele.json', 'r', encoding='utf-8') as f:
|
||||
skill_dict = json.load(f)
|
||||
|
||||
|
||||
class SingleSkill:
|
||||
def __init__(self, skill: Dict):
|
||||
self.id = skill['skillId']
|
||||
self.level = skill['skillLevel']
|
||||
|
||||
|
||||
class BaseSkills:
|
||||
Normal_: SingleSkill
|
||||
BPSkill_: SingleSkill
|
||||
Ultra_: SingleSkill
|
||||
Maze_: SingleSkill
|
||||
Talent_: SingleSkill
|
||||
|
||||
def __init__(self, char: Dict, skills: List):
|
||||
for skill in skills:
|
||||
skill_attack_type = skill['skillAttackType']
|
||||
if skill_attack_type == 'Normal':
|
||||
self.Normal_ = SingleSkill(skill)
|
||||
elif skill_attack_type == 'BPSkill':
|
||||
self.BPSkill_ = SingleSkill(skill)
|
||||
elif skill_attack_type == 'Ultra':
|
||||
self.Ultra_ = SingleSkill(skill)
|
||||
elif skill_attack_type == 'Maze':
|
||||
self.Maze_ = SingleSkill(skill)
|
||||
elif skill_attack_type == '':
|
||||
self.Talent_ = SingleSkill(skill)
|
||||
else:
|
||||
raise ValueError(
|
||||
f'Unknown skillAttackType: {skill_attack_type}'
|
||||
)
|
||||
|
||||
|
||||
# class SeeleSkill(BaseSkills):
|
||||
# pass
|
@ -21,31 +21,37 @@ class IntheNight(BaseWeapon):
|
||||
async def check(self):
|
||||
pass
|
||||
|
||||
async def weapon_ability(self, char):
|
||||
char = await self.weapon_property_ability(char)
|
||||
char_speed = mp.mpf(char.base_attributes['speed'])
|
||||
async def weapon_ability(self, base_attr: Dict, attribute_bonus: Dict):
|
||||
char_speed = mp.mpf(base_attr.get('speed', 0))
|
||||
count_ = min(6, int(mp.floor((char_speed - 100) / 10)))
|
||||
char.a_dmg += (
|
||||
mp.mpf(weapon_effect['23001']['Param']['a_dmg'][self.weapon_rank])
|
||||
* count_
|
||||
)
|
||||
char.e_dmg += (
|
||||
mp.mpf(weapon_effect['23001']['Param']['e_dmg'][self.weapon_rank])
|
||||
* count_
|
||||
)
|
||||
char.q_crit_dmg += (
|
||||
normal_dmg_add = attribute_bonus.get('NormalDmgAdd', 0)
|
||||
attribute_bonus['NormalDmgAdd'] = normal_dmg_add + (
|
||||
mp.mpf(
|
||||
weapon_effect['23001']['Param']['q_crit_dmg'][self.weapon_rank]
|
||||
weapon_effect['23001']['Param']['a_dmg'][self.weapon_rank - 1]
|
||||
)
|
||||
* count_
|
||||
)
|
||||
return char
|
||||
|
||||
async def weapon_property_ability(self, char):
|
||||
char.CriticalChanceBase += mp.mpf(
|
||||
weapon_effect['23001']['AbilityProperty'][self.weapon_rank]
|
||||
bp_skill_dmg_add = attribute_bonus.get('BPSkillDmgAdd', 0)
|
||||
attribute_bonus['BPSkillDmgAdd'] = bp_skill_dmg_add + (
|
||||
mp.mpf(
|
||||
weapon_effect['23001']['Param']['e_dmg'][self.weapon_rank - 1]
|
||||
)
|
||||
return char
|
||||
* count_
|
||||
)
|
||||
ultra_critical_chance_base = attribute_bonus.get(
|
||||
'Ultra_CriticalChanceBase', 0
|
||||
)
|
||||
attribute_bonus[
|
||||
'Ultra_CriticalChanceBase'
|
||||
] = ultra_critical_chance_base + (
|
||||
mp.mpf(
|
||||
weapon_effect['23001']['Param']['q_crit_dmg'][
|
||||
self.weapon_rank - 1
|
||||
]
|
||||
)
|
||||
* count_
|
||||
)
|
||||
return attribute_bonus
|
||||
|
||||
|
||||
class CruisingintheStellarSea(BaseWeapon):
|
||||
@ -57,26 +63,23 @@ class CruisingintheStellarSea(BaseWeapon):
|
||||
# 装备者消灭敌方目标
|
||||
return True
|
||||
|
||||
async def weapon_ability(self, char):
|
||||
char = await self.weapon_property_ability(char)
|
||||
if self.check():
|
||||
char.CriticalChanceBase += mp.mpf(
|
||||
async def weapon_ability(self, base_attr: Dict, attribute_bonus: Dict):
|
||||
if await self.check():
|
||||
critical_chance_base = attribute_bonus.get('CriticalChanceBase', 0)
|
||||
attribute_bonus[
|
||||
'CriticalChanceBase'
|
||||
] = critical_chance_base + mp.mpf(
|
||||
weapon_effect['24001']['Param']['CriticalChance'][
|
||||
self.weapon_rank
|
||||
self.weapon_rank - 1
|
||||
]
|
||||
)
|
||||
char.AttackAddedRatio += mp.mpf(
|
||||
attack_added_ratio = attribute_bonus.get('AttackAddedRatio', 0)
|
||||
attribute_bonus['AttackAddedRatio'] = attack_added_ratio + mp.mpf(
|
||||
weapon_effect['24001']['Param']['AttackAddedRatio'][
|
||||
self.weapon_rank
|
||||
self.weapon_rank - 1
|
||||
]
|
||||
)
|
||||
return char
|
||||
|
||||
async def weapon_property_ability(self, char):
|
||||
char.CriticalChanceBase += mp.mpf(
|
||||
weapon_effect['24001']['AbilityProperty'][self.weapon_rank]
|
||||
)
|
||||
return char
|
||||
return attribute_bonus
|
||||
|
||||
|
||||
class HuntWeapon:
|
||||
|
@ -4,6 +4,7 @@ from abc import abstractmethod
|
||||
from mpmath import mp
|
||||
|
||||
from ....utils.excel.read_excel import EquipmentPromotion
|
||||
from ....utils.map.SR_MAP_PATH import EquipmentID2AbilityProperty
|
||||
|
||||
mp.dps = 14
|
||||
|
||||
@ -14,42 +15,51 @@ class BaseWeapon:
|
||||
self.weapon_level = weapon['level']
|
||||
self.weapon_rank = weapon['rank']
|
||||
self.weapon_promotion = weapon['promotion']
|
||||
self.weapon_base_attribute = {}
|
||||
self.weapon_attribute = {}
|
||||
self.weapon_property_ability()
|
||||
|
||||
@abstractmethod
|
||||
async def weapon_ability(self, char):
|
||||
async def weapon_ability(self, base_attr: Dict, attribute_bonus: Dict):
|
||||
'''
|
||||
战斗加成属性, 与 weapon_property_ability() 互斥
|
||||
'''
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
async def weapon_property_ability(self, char):
|
||||
def weapon_property_ability(self):
|
||||
'''
|
||||
面板加成属性, 与 weapon_ability() 互斥
|
||||
'''
|
||||
...
|
||||
ability_property = EquipmentID2AbilityProperty[str(self.weapon_id)]
|
||||
equip_ability_property = ability_property[str(self.weapon_rank)]
|
||||
for equip_ability in equip_ability_property:
|
||||
property_type = equip_ability['PropertyType']
|
||||
value = equip_ability['Value']['Value']
|
||||
if property_type in self.weapon_attribute:
|
||||
self.weapon_attribute[property_type] += value
|
||||
else:
|
||||
self.weapon_attribute[property_type] = value
|
||||
|
||||
@abstractmethod
|
||||
async def check(self):
|
||||
...
|
||||
|
||||
async def get_attribute(self):
|
||||
def get_attribute(self):
|
||||
promotion = EquipmentPromotion[str(self.weapon_id)][
|
||||
str(self.weapon_promotion)
|
||||
]
|
||||
|
||||
self.weapon_attribute['hp'] = mp.mpf(
|
||||
self.weapon_base_attribute['hp'] = mp.mpf(
|
||||
promotion["BaseHP"]['Value']
|
||||
) + mp.mpf(promotion["BaseHPAdd"]['Value']) * (self.weapon_level - 1)
|
||||
|
||||
self.weapon_attribute['attack'] = mp.mpf(
|
||||
self.weapon_base_attribute['attack'] = mp.mpf(
|
||||
promotion["BaseAttack"]['Value']
|
||||
) + mp.mpf(promotion["BaseAttackAdd"]['Value']) * (
|
||||
self.weapon_level - 1
|
||||
)
|
||||
|
||||
self.weapon_attribute['defence'] = mp.mpf(
|
||||
self.weapon_base_attribute['defence'] = mp.mpf(
|
||||
promotion["BaseDefence"]['Value']
|
||||
) + mp.mpf(promotion["BaseDefenceAdd"]['Value']) * (
|
||||
self.weapon_level - 1
|
||||
|
68
StarRailUID/starrailuid_damagecal/effect/Base/seele.json
Normal file
68
StarRailUID/starrailuid_damagecal/effect/Base/seele.json
Normal file
@ -0,0 +1,68 @@
|
||||
{
|
||||
"1102": {
|
||||
"Normal": [
|
||||
0.5000000004656613,
|
||||
0.6000000005587935,
|
||||
0.7000000006519258,
|
||||
0.8000000007450581,
|
||||
0.9000000008381903,
|
||||
1.1000000000931323,
|
||||
1.2000000001862645,
|
||||
1.3000000002793968
|
||||
],
|
||||
"BPSkill": [
|
||||
1.1000000000931323,
|
||||
1.2100000001955777,
|
||||
1.3200000002980232,
|
||||
1.4300000004004687,
|
||||
1.5400000005029142,
|
||||
1.6500000006053597,
|
||||
1.7875000005587935,
|
||||
1.9250000005122274,
|
||||
2.0625000002328306,
|
||||
2.2000000001862645,
|
||||
2.31000000028871,
|
||||
2.4200000003911555,
|
||||
2.530000000493601,
|
||||
2.6400000005960464,
|
||||
2.750000000698492
|
||||
],
|
||||
"Ultra": [
|
||||
2.5500000005122274,
|
||||
2.7200000006705523,
|
||||
2.890000000828877,
|
||||
3.0600000000558794,
|
||||
3.230000000214204,
|
||||
3.400000000372529,
|
||||
3.612500000745058,
|
||||
3.825000000419095,
|
||||
4.037499999860302,
|
||||
4.250000000232831,
|
||||
4.4200000003911555,
|
||||
4.59000000054948,
|
||||
4.760000000707805,
|
||||
4.93000000086613,
|
||||
5.100000000093132
|
||||
],
|
||||
"": [
|
||||
0.40000000037252903,
|
||||
0.44000000040978193,
|
||||
0.48000000044703484,
|
||||
0.5200000004842877,
|
||||
0.5600000005215406,
|
||||
0.6000000005587935,
|
||||
0.6500000006053597,
|
||||
0.7000000006519258,
|
||||
0.7500000006984919,
|
||||
0.8000000007450581,
|
||||
0.840000000782311,
|
||||
0.8800000008195639,
|
||||
0.9200000008568168,
|
||||
0.9600000008940697,
|
||||
1
|
||||
],
|
||||
"Maze": [
|
||||
20
|
||||
]
|
||||
}
|
||||
}
|
45
StarRailUID/starrailuid_damagecal/effect/Base/utils.py
Normal file
45
StarRailUID/starrailuid_damagecal/effect/Base/utils.py
Normal file
@ -0,0 +1,45 @@
|
||||
from typing import Dict
|
||||
|
||||
|
||||
async def merge_attribute(base_attr: Dict, attribute_bonus: Dict) -> Dict:
|
||||
# hp attack defence need base_value and add_value
|
||||
merged_attr = {}
|
||||
for attribute in attribute_bonus:
|
||||
if (
|
||||
attribute.__contains__('Attack')
|
||||
or attribute.__contains__('Defence')
|
||||
or attribute.__contains__('HP')
|
||||
or attribute.__contains__('Speed')
|
||||
):
|
||||
if attribute.__contains__('Delta'):
|
||||
attr = attribute.split('Delta')[0].lower()
|
||||
attr_value = base_attr.get(attr, 0)
|
||||
merged_attr[attr] = attr_value + attribute_bonus[attribute]
|
||||
elif attribute.__contains__('AddedRatio'):
|
||||
attr = attribute.split('AddedRatio')[0].lower()
|
||||
attr_value = base_attr.get(attr, 0)
|
||||
merged_attr[attr] = attr_value + base_attr[attr] * (
|
||||
1 + attribute_bonus[attribute]
|
||||
)
|
||||
else:
|
||||
raise Exception(f'attribute error {attribute}')
|
||||
elif attribute.__contains__('Base'):
|
||||
attr = attribute.split('Base')[0]
|
||||
attr_value = base_attr.get(attr, 0)
|
||||
merged_attr[attr] = attr_value + attribute_bonus[attribute]
|
||||
elif attribute.__contains__('AddedRatio'):
|
||||
# attr = attribute.split('AddedRatio')[0]
|
||||
attr_value = base_attr.get(attribute, 0)
|
||||
merged_attr[attribute] = attr_value + attribute_bonus[attribute]
|
||||
elif attribute.__contains__('DmgAdd'):
|
||||
attr_value = base_attr.get(attribute, 0)
|
||||
merged_attr[attribute] = attr_value + attribute_bonus[attribute]
|
||||
elif attribute == 'ignore_defence':
|
||||
attr_value = base_attr.get(attribute, 0)
|
||||
merged_attr[attribute] = attr_value + attribute_bonus[attribute]
|
||||
elif attribute.__contains__('ResistancePenetration'):
|
||||
attr_value = base_attr.get(attribute, 0)
|
||||
merged_attr[attribute] = attr_value + attribute_bonus[attribute]
|
||||
else:
|
||||
raise Exception(f'attribute error {attribute}')
|
||||
return merged_attr
|
@ -1,58 +0,0 @@
|
||||
{
|
||||
"details": {
|
||||
"A普攻伤害": "a",
|
||||
"E战技伤害": "e",
|
||||
"Q终结技伤害": "q"
|
||||
},
|
||||
"buffs": {
|
||||
"Talent": {
|
||||
"id": 110204,
|
||||
"desc": "希儿天赋:击杀敌人进入增幅状态提高伤害",
|
||||
"type": "skillDmg",
|
||||
"value": [
|
||||
0.4,
|
||||
0.44,
|
||||
0.48,
|
||||
0.52,
|
||||
0.56,
|
||||
0.6,
|
||||
0.65,
|
||||
0.7,
|
||||
0.75,
|
||||
0.8,
|
||||
0.84,
|
||||
0.88,
|
||||
0.92,
|
||||
0.96,
|
||||
1.0
|
||||
]
|
||||
},
|
||||
"Skill": {
|
||||
"desc": "希儿战技:释放战技后,速度提高25%",
|
||||
"type": "SpeedAddedRatio",
|
||||
"value": 0.25
|
||||
},
|
||||
"Eidolons": [
|
||||
{
|
||||
"cons": 1,
|
||||
"desc": "对生命小于80%的敌人造成伤害时,暴击率提高15%",
|
||||
"type": "CriticalChance",
|
||||
"value": 0.15
|
||||
},
|
||||
{
|
||||
"cons": 2,
|
||||
"desc": "释放战技后,2层Buff速度提高50%",
|
||||
"type": "SpeedAddedRatio",
|
||||
"value": 0.5
|
||||
}
|
||||
],
|
||||
"SkillTree": [
|
||||
{
|
||||
"tree": 2,
|
||||
"desc": "行迹-割裂:量子抗性穿透提高20",
|
||||
"type": "QuantumAddedRatio",
|
||||
"value": 0.2
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -3,10 +3,14 @@ import threading
|
||||
|
||||
from gsuid_core.logger import logger
|
||||
|
||||
from ..utils.api import get_sqla
|
||||
from ..starrailuid_resource import startup
|
||||
|
||||
|
||||
async def all_start():
|
||||
try:
|
||||
pass
|
||||
get_sqla('TEMP')
|
||||
await startup()
|
||||
except Exception as e:
|
||||
logger.exception(e)
|
||||
|
||||
|
@ -66,7 +66,7 @@ async def download_all_file_from_cos():
|
||||
else:
|
||||
path = Path(WIKI_PATH / resource_type / name)
|
||||
if path.exists():
|
||||
is_diff = size == str(os.stat(path).st_size)
|
||||
is_diff = size == os.stat(path).st_size
|
||||
else:
|
||||
is_diff = True
|
||||
if (
|
||||
|
Loading…
x
Reference in New Issue
Block a user