import sys from functools import cache from uuid import uuid1 from core.basic.equipment import OathSuit, Suit, get_equipment from ..formula import 增幅计算, 强化技攻, 武器强化计算, 精通计算, 耳环计算, 左右计算, 锻造计算 from ..roleinfo import CharacterEmblemInfo, CharacterEquipInfo, CharacterOathInfo, get_key_by_value from .base import CharacterBase @cache def get_skill_classes(module_name: str) -> tuple[type, ...]: module = sys.modules[module_name] return tuple( memberClass for name in dir(module) if isinstance((memberClass := getattr(module, name)), type) and memberClass.__name__.startswith('Skill') ) class CalcEquipMixin(CharacterBase): """装备计算、角色初始化相关方法""" # region 打造信息导入 def SetDetail(self, info: dict[str, dict]) -> None: """打造信息导入""" self.charEquipInfo = {} self.charOathInfo = [] self.charEmblemInfo = [] self.bindAwake = info.get('bindAwake', 50) if info.get('emblems', None) is None: info['emblems'] = {} if info.get('oaths', None) is None: info['oaths'] = {} equs = get_equipment(self.equVersion) for key in info['equips']: self.charEquipInfo[key] = CharacterEquipInfo(info['equips'][key], self.equVersion, key, equs) for key in info['oaths']: # 导入誓约打造信息、誓约信息 self.charOathInfo.append(CharacterOathInfo(info['oaths'][key], self.equVersion, key, equs)) try: # 异常处理 彩色等级自动取最小值 minEmblemLv = min([info['emblems'][key]['lv'] for key in ['红色', '蓝色', '绿色', '黄色']], default=1) info['emblems']['彩色']['lv'] = minEmblemLv for key in info['emblems']: # 导入徽章打造信息、徽章信息 info['emblems'][key]['part'] = key self.charEmblemInfo.append(CharacterEmblemInfo(info['emblems'][key])) pass except Exception: pass self.charOathSkillId = info.get('oathSkill', 1) def calc_init(self, setInfo: dict[str, dict]): self.equ_options = setInfo.get('options', {}) self.setInfo = setInfo self.SetDetail(setInfo) self.SetSkills(setInfo.get('skills', {})) def SetSkills(self, skills: dict[str, dict]): """设置技能等级""" for key in skills: skill = self.GetSkillByID(key) if skill is not None: if skill.hasUP: skill.up = skills[key].get('up', 0) if skill.hasVP: skill.vp = skills[key].get('vp', 0) skill.lv += skills[key].get('lv', 0) def load_skills(self) -> None: """加载技能""" for memberClass in get_skill_classes(self.moduleName): skill = memberClass(char=self) self.skills_dict[skill.name] = skill self.skills_id_dict[str(skill.id)] = skill self.skills_uuid_dict[str(skill.uuid)] = skill self.skills.append(skill) # endregion # region 套装 / 装备 / 时装 / 基础属性 / 辟邪玉 / 杂项 def calc_suits(self): """套装效果统计""" suitInfo = {} oathSuitInfo = {} correction = 0 equs = get_equipment(self.equVersion) for item in self.charEquipInfo.values(): partEqu = item.equInfo if partEqu is None: continue # partFusion = item.fusionInfo for suit in partEqu.suit: suit_item = suitInfo.setdefault(suit, {'point': 0, 'count': 0}) if partEqu.Point == 0: suit_item['count'] += 1 else: suit_item['point'] += partEqu.Point for item in self.charOathInfo: partOath = item.oathInfo if partOath is None: continue for suit in partOath.suit: oath_suit_item = oathSuitInfo.setdefault(suit, {'point': 0, 'count': 0}) if partOath.Point == 0: oath_suit_item['count'] += 1 else: oath_suit_item['point'] += partOath.Point max_point_suit = max((suit for suit in suitInfo if suitInfo[suit]['point'] > 0), key=lambda suit: suitInfo[suit]['point'], default=None) max_point_oath_suit = max((suit for suit in oathSuitInfo if oathSuitInfo[suit]['point'] > 0), key=lambda suit: oathSuitInfo[suit]['point'], default=None) zero_point_suits = [suit for suit in suitInfo if suitInfo[suit]['point'] == 0] # 套装没有到太初的时候,优先把誓约套装的点数加到装备套装上,以达到更高的套装等级 if suitInfo is not None and oathSuitInfo is not None and max_point_suit is not None and 0 < suitInfo[max_point_suit]['point'] < 2550 and max_point_oath_suit is not None and oathSuitInfo.get(max_point_oath_suit, None) is not None: correction = min(2550 - suitInfo[max_point_suit]['point'], oathSuitInfo[max_point_oath_suit]['point']) suitInfo[max_point_suit]['point'] += correction oathSuitInfo[max_point_oath_suit]['point'] -= correction pass suits = zero_point_suits + ([max_point_suit] if max_point_suit is not None else []) suitList: list[Suit] = [] oathSuitList: list[OathSuit] = [] res = {'suit': None, 'oath': None, 'correction': correction} # print(max_point_suit, suitList) for suit in suits: if suitInfo[suit]['point'] == 0: suitList += equs.get_suit_info(suit, 0, suitInfo[suit]['count']) else: suitList += equs.get_suit_info(suit, suitInfo[suit]['point'], 0) if len(suitList) == 0: continue if suit == max_point_suit: self.suitInfo = suitList temp = suitList[-1] res['suit'] = { 'id': temp.id, 'name': temp.name, 'rarity': temp.rarity, 'point': suitInfo[suit]['point'], 'count': suitInfo[suit]['count'], 'level': temp.level, 'suitId': suit, 'imageUrl': temp.imageUrl, # 'value': temp.value, } for suit in oathSuitInfo: if oathSuitInfo[suit]['point'] == 0: oathSuitList += equs.get_oath_suit_info(suit, 0, oathSuitInfo[suit]['count']) else: oathSuitList += equs.get_oath_suit_info(suit, oathSuitInfo[suit]['point'], 0) if len(oathSuitList) == 0: continue oath_suit_by_suit_id = {item.suitId: item for item in oathSuitList} for suit in suitList: i = suit.id func = equs.funs.execture(f'suit_{i}') suit = equs.suit_id_dict.get(str(i), None) if suit is None: continue # 誓约和套装进行匹配 # 如果存在誓约和套装是同一个套装 # 则直接不执行原套装效果,执行誓约套装增强的效果 oathEffect = oath_suit_by_suit_id.get(suit.suitId, None) filtered_dict = {k: v for k, v in suit.__dict__.items() if k[0].isupper()} self.SetStatus(**filtered_dict) if func is not None and oathEffect is None: # print(f'套装 {suit.name} 生效') func(self) if max_point_suit != max_point_oath_suit: self.charOathSkillId = '1' oathSkillEffect = [] self.max_point = 0 if res['suit'] is None else res.get('suit', {}).get('point', 0) try: self.oath_max_point = oathSuitInfo.get(max_point_oath_suit, {}).get('point', 0) except Exception: self.oath_max_point = 0 self.oathSuitInfo = [] self.oathSkillInfo = [] # 当套装点数达到太初时,誓约技能生效 if self.max_point >= 2550: oathSuit = oath_suit_by_suit_id.get(max_point_oath_suit, None) if oathSuit is not None: skills = [x for x in oathSuit.skills if x.suitId == oathSuit.suitId] skill = next((x for x in oathSuit.skills if str(x.skillId) == str(self.charOathSkillId)), None) # 誓约套装效果生效 filtered_dict = {k: v for k, v in oathSuit.__dict__.items() if k[0].isupper()} self.SetStatus(**filtered_dict) if skill is not None: oathSkillEffect.append(skill) # 誓约技能效果生效 filtered_dict = {k: v for k, v in skill.__dict__.items() if k[0].isupper()} self.SetStatus(**filtered_dict) self.oathSkillInfo.append(skill) self.oathSuitInfo.append(oathSuit) if oathSuit.suitId == max_point_oath_suit: res['oath'] = { 'id': oathSuit.id, 'name': skill.name, 'rarity': oathSuit.rarity, 'point': oathSuitInfo[oathSuit.suitId]['point'], 'count': oathSuitInfo[oathSuit.suitId]['count'], 'level': oathSuit.level, 'imageUrl': oathSuit.imageUrl, 'suitId': oathSuit.suitId, 'skills': [{'id': skill.id, 'skillId': i.skillId, 'name': i.name, 'imageUrl': i.imageUrl, 'enable': i.skillId == '1' or max_point_oath_suit == max_point_suit} for i in skills], # 'value': oathSuit.value, } for skill in oathSkillEffect: func = equs.funs.execture(f'oath_skill_{skill.id}') if func is not None: # print(f'誓约技能 {skill.id} 生效') func(self) # 太初积分以上,每超过70点数增加1%技能攻击力 if self.max_point >= 2550: skillAttack = (self.max_point - 2550) // 70 * 0.02 buffer = (self.max_point - 2550) // 70 * 200 self.SetStatus(SkillAttack=skillAttack, Buffer=buffer) # 誓约积分 if self.oath_max_point >= 1200: self.SetSkillCD(1, 100, 0.185) SkillAttack, Buffer = equs.funs.execture('oathPointEffect')(self.oath_max_point) self.SetStatus(SkillAttack=SkillAttack, Buffer=Buffer) return res def calc_equs(self): """计算装备基础效果、附魔""" effects = get_equipment(self.equVersion).funs # for detail in [(item.equInfo, item.fusionInfo, item.enchant, item.emblem_0, item.emblem_1) for item in filter(lambda x: x.equInfo is not None, self.charEquipInfo.values())]: for item in self.charEquipInfo.values(): equ = item.equInfo if equ is None or equ.itemType == '副武器': continue enchat = item.enchant fun = effects.execture(f'equ_{equ.id}') if fun is None: continue filtered_dict = {k: v for k, v in equ.__dict__.items() if k[0].isupper()} self.SetStatus(**filtered_dict) fun(self) fun = effects.execture(f'enchant_{enchat}') if fun is not None: fun(self) # emblem_0 = detail[3] # emblem_1 = detail[4] # if str(emblem_0).isdigit(): # fun = effects.execture(f'emblem_{emblem_0}') # if fun is not None: # fun(self) # else: # skill = self.GetSkillByName(emblem_0) # if skill is not None: # skill.lv += 1 # self.SetStatus(四维=8) # fun = effects.execture(f'emblem_{emblem_1}') # if fun is not None: # fun(self) # if fusion is None: # continue # fun = effects.execture(f'stone_{fusion.id}') # filtered_dict = {k: v for k, v in fusion.__dict__.items() if k[0].isupper()} # self.SetStatus(**filtered_dict) # if fun is not None: # fun(self) def calc_emblems(self): """计算徽章效果""" effects = get_equipment(self.equVersion).funs emblemCombine = effects.execture('emblem_combine') for emblem in self.charEmblemInfo: for item in emblem.items: fun = effects.execture(f'emblem_{item}') if fun is not None: fun(self) emblemCombine(self, emblem.part, emblem.lv, emblem.items) pass pass def calc_oaths(self): """计算装备基础效果""" effects = get_equipment(self.equVersion).funs for item in self.charOathInfo: oath = item.oathInfo if oath is None: continue fun = effects.execture(f'oath_{oath.id}') if fun is None: continue filtered_dict = {k: v for k, v in oath.__dict__.items() if k[0].isupper()} self.SetStatus(**filtered_dict) fun(self) pass def calc_avatar(self, avatar: dict): """计算时装效果""" equ = get_equipment(self.equVersion) dress = {key: value for key, value in avatar.items() if key in ['头部', '帽子', '脸部', '胸部', '上衣', '腰带', '下装', '鞋']} equ.funs.calc_dress_effect(dress, self) avatarElse = {key: value for key, value in avatar.items() if key not in ['头部', '帽子', '脸部', '胸部', '上衣', '腰带', '下装', '鞋']} for key in avatarElse: value = avatarElse[key].get('enchant', None) emblem_0 = avatarElse[key].get('emblem_0', None) emblem_1 = avatarElse[key].get('emblem_1', None) if value is not None: fun = equ.funs.execture(f'enchant_{value}') if fun is not None: fun(self) for i in [emblem_0, emblem_1]: if i is None: continue fun = equ.funs.execture(f'emblem_{i}') if fun is not None: fun(self) def calc_weapon(self, cur: 'CharacterEquipInfo'): """武器强化、锻造计算""" value_1 = 锻造计算(115, '史诗', cur.refine, cur.equInfo.itemDetailType, 1.12 if '传世武器' in cur.equInfo.categorize else 0) value_2 = 武器强化计算(115, '史诗', cur.reinforce, cur.equInfo.itemDetailType, '独立', 1.12 if '传世武器' in cur.equInfo.categorize else 0) value = max(value_1, value_2) self.SetStatus(AtkI=value) if '传世武器' in cur.equInfo.categorize: value = 武器强化计算(115, '史诗', cur.reinforce, cur.equInfo.itemDetailType, '物理', 1.12) self.SetStatus(AtkP=value, AtkM=value) else: value = 武器强化计算(115, '史诗', cur.reinforce, cur.equInfo.itemDetailType, '物理') self.SetStatus(AtkP=value) value = 武器强化计算(115, '史诗', cur.reinforce, cur.equInfo.itemDetailType, '魔法') self.SetStatus(AtkM=value) def calc_basic(self): """计算基础属性:防具精通、增幅、强化等""" char_equip_info = self.charEquipInfo for part in ['上衣', '头肩', '下装', '腰带', '鞋']: cur = char_equip_info[part] if cur.equInfo is None: continue equ = cur.equInfo reinforce = cur.reinforce if equ is None: continue for key in self.防具精通属性: value = 精通计算(115, equ.rarity, reinforce, equ.itemDetailType, self.防具类型, self.buffer, key) key = get_key_by_value(key) setattr(self, key, getattr(self, key) + value) for part, cur in char_equip_info.items(): if cur.equInfo is None: continue if cur.reinforceType == 1: value = 增幅计算(115, '史诗', cur.reinforce) self.SetStatus(STR=value, INT=value, Spirit=value, Vitality=value) value = 强化技攻(cur.reinforce, cur.reinforceType, part) self.SetStatus(SkillAttack=value) if '武器' in part: self.calc_weapon(cur) if part == '耳环': value = 耳环计算(115, '史诗', cur.reinforce) self.SetStatus(AtkM=value, AtkP=value, AtkI=value) if part in ['辅助装备', '魔法石']: value = 左右计算(115, '史诗', cur.reinforce) self.SetStatus(STR=value, INT=value, Spirit=value, Vitality=value) def calc_jade(self, jades): """计算辟邪玉效果""" funs = get_equipment(self.equVersion).funs for key in jades: jade = jades[key] fun = funs.execture(f'jade_{jade.get("id", 0)}') if fun is not None: fun(self, jade.get('value', 0)) def calc_sundry(self, sundry: dict): """计算杂项效果""" funs = get_equipment(self.equVersion).funs primer = next((x for x in self.charOathInfo if x.id == '2000500'), None) if primer: fog = sundry.get('fog', 0) stats, Point, SkillAttack, Attack, Buffer = funs.execture('fog_oath_info')(fog) primer.oathInfo.STR = primer.oathInfo.INT = primer.oathInfo.Vitality = primer.oathInfo.Spirit = stats primer.oathInfo.Point = Point primer.oathInfo.SkillAttack = SkillAttack primer.oathInfo.Attack = Attack primer.oathInfo.Buffer = Buffer # funs.execture('sundry_0')( # self, # sundry.get('medal_rarity', 0), # sundry.get('medal_reinforce', 0), # [sundry.get('medal_gem_0', 0), sundry.get('medal_gem_1', 0), sundry.get('medal_gem_2', 0), sundry.get('medal_gem_3', 0)], # ) funs.execture('sundry_6')(self, sundry.get('adventure', 1)) # funs.execture('sundry_5')(self, sundry.get('fog', 1)) funs.execture('sundry_7')(self, sundry.get('marriage_house', 0), sundry.get('marriage_ring', 0)) funs.execture('sundry_9')(self, sundry.get('contract', 0)) funs.execture('sundry_10')( self, sundry.get('collection_type', 0), sundry.get('collection_num_0', 0), sundry.get('collection_num_1', 0), ) funs.execture('sundry_13')(self, sundry.get('costume_card', 0)) # endregion # region 主计算入口 def calc(self, setInfo: dict[str, dict]): self.calc_init(setInfo) self.SetBaseStatus() self.calc_jade(setInfo.get('jades', [])) self.calc_avatar(setInfo.get('avatar', {})) self.calc_basic() self.calc_sundry(setInfo.get('sundry', {})) self.calc_emblems() suit = self.calc_suits() self.calc_equs() self.calc_oaths() skillInfos = [] if self.buffer: skillInfos = self.calc_buffer_skills() info = self.get_buffer_info() else: if len(self.输出类型选项) > 1: temp = self.输出类型选项[0] if '固伤' in temp: if self.INT > self.STR: self.输出类型 = '魔法固伤' else: self.输出类型 = '物理固伤' else: if self.INT > self.STR and self.AtkM > self.AtkP: self.输出类型 = '魔法百分比' else: self.输出类型 = '物理百分比' skillInfos = self.calc_carry_skills(setInfo.get('DSB', False), setInfo.get('BUFF', False)) info = self.get_carry_info() return {'uuid': uuid1().hex, 'skills': skillInfos, 'info': info, 'suits': suit, 'buffer': self.buffer} # endregion