diff --git a/.gitmodules b/.gitmodules index 8f6e12e0..c76c5d99 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ [submodule "backend/openapi"] path = backend/openapi - url = https://gitee.com/dnftools/dcalcopenapi.git + url = ../dcalcopenapi.git [submodule "images"] path = images - url = https://gitee.com/dnftools/dcalcimages.git + url = ../dcalcimages.git diff --git a/backend/api/routes/info.py b/backend/api/routes/info.py index 2a23f3e5..01249dd5 100644 --- a/backend/api/routes/info.py +++ b/backend/api/routes/info.py @@ -2,11 +2,12 @@ import re from api.core.Auth import createToken from api.core.Gzip import register_gzip_request import json -from fastapi import APIRouter,Request, Depends, Body +from fastapi import APIRouter, Request, Depends, Body from typing import Annotated from api.core.Response import Return, response from api.core.Redis import get_redis_info -from api.dp import RedisDep,AltersDep +from api.dp import RedisDep, AltersDep +from core.basic.equipment import get_equipment from core.character.adventure import get_adv_list from core.basic.character import createCharacter from core.open.helper import get_user_info_by_id @@ -17,6 +18,7 @@ router = APIRouter() register_gzip_request(router) + def replace_placeholders(template): # 匹配 、、、 等 pattern = re.compile(r'<(int|float\d*)>') @@ -30,44 +32,60 @@ def replace_placeholders(template): return pattern.sub(repl, template) - @router.get('/adventure') -async def get_adventure_info(request: Request,redis:RedisDep): +async def get_adventure_info(request: Request, redis: RedisDep): adventure_info = get_redis_info(redis, 'dcalc:adventure', get_adv_list) return response(data=adventure_info) -@router.get("/token/get/{alter}") -async def getToken(redis:RedisDep, - alter: str, request: Request, version: str = None, equVersion: str = "0" -): + +@router.get('/token/get/{alter}') +async def getToken(redis: RedisDep, alter: str, request: Request, version: str = None, equVersion: str = '0'): token = createToken(alter, equVersion, redis) return response(data=token) -@router.get("/character") -async def get_character_info( - request: Request, state: AltersDep ,redis:RedisDep -): + +@router.get('/character') +async def get_character_info(request: Request, state: AltersDep, redis: RedisDep): character = createCharacter(state.alter, state.equVersion) + def get_character(): return character.getInfo() - info = get_redis_info(redis, f"dcalc:character:{state.alter}:{state.equVersion}", get_character) + + info = get_redis_info(redis, f'dcalc:character:{state.alter}:{state.equVersion}', get_character) # info = character.getInfo() return response(data=info) -@router.get("/skill/{skillId}/{level}") -async def get_skill_info( - state: AltersDep, skillId: str, level: int, redis: RedisDep -): + +@router.get('/info/oath/{suitId}/{skillId}') +async def get_oath_info(state: AltersDep, suitId: str, skillId: str, rarity: str, redis: RedisDep): + def get_info(): + skill = None + version = state.equVersion + equ = get_equipment(version) + oath = next((x for x in equ.oath_suits if x.suitId == suitId and x.rarity == rarity), None) + if oath is not None: + oathSkill = next((x for x in oath.skills if x.skillId == skillId), None) + if oathSkill is not None: + skill = {**oathSkill.__dict__, 'point': oath.points, 'imageUrl': oath.imageUrl} + return skill + + info = get_redis_info(redis, f'dcalc:oath:{rarity}:{skillId}', get_info) + return response(data=info) + + +@router.get('/skill/{skillId}/{level}') +async def get_skill_info(state: AltersDep, skillId: str, level: int, redis: RedisDep): """ 获取技能信息 """ alter = state.alter - jobId = alter.split(".")[1] - jobGrowId = alter.split(".")[2] + jobId = alter.split('.')[1] + jobGrowId = alter.split('.')[2] skill_info = {} key = f'openapi:{jobId}:{jobGrowId}:{skillId}' try: + def get_skill_info(): # This function should retrieve the skill info based on job and jobGrow # For now, we return a placeholder dictionary @@ -97,25 +115,27 @@ async def get_skill_info( return response(data=skill_info) -@router.get("/dnfhelper/{uid}/") +@router.get('/dnfhelper/{uid}/') async def get_info_by_dnfhelper(uid: str, state: AltersDep, redis: RedisDep): try: - result = await get_user_info_by_id(uid,state) + result = await get_user_info_by_id(uid, state) return response(data=result) except Exception as e: if isinstance(e, ResponseException): return response(code=500, message=str(e), data=None) - return response(code=500, message="Failed to fetch DNFHelper info", data=None) + print(e) + return response(code=500, message='Failed to fetch DNFHelper info', data=None) -@router.post("/skillTree/") -async def get_skill_by_code(state: AltersDep, code = Body(None)): + +@router.post('/skillTree/') +async def get_skill_by_code(state: AltersDep, code=Body(None)): try: - skills = get_skill_tree_info(code.get("code", "")) - if skills.get("job",{}).get("class","") != state.alter: - return response(code=500, message="技能加点代码职业与登录职业不匹配", data=None) + skills = get_skill_tree_info(code.get('code', '')) + if skills.get('job', {}).get('class', '') != state.alter: + return response(code=500, message='技能加点代码职业与登录职业不匹配', data=None) return response(data=skills) except Exception as e: - print(f"Error fetching skill tree info: {e}") + print(f'Error fetching skill tree info: {e}') if isinstance(e, ResponseException): return response(code=500, message=str(e), data=None) - return response(code=500, message="解析技能加点失败", data=None) \ No newline at end of file + return response(code=500, message='解析技能加点失败', data=None) diff --git a/backend/config/.env b/backend/config/.env index 39486e01..802cba66 100644 --- a/backend/config/.env +++ b/backend/config/.env @@ -3,6 +3,6 @@ MCPPORT=47174 DEBUG_MODE=True WORKERS=1 REDIS_URL=redis://localhost:6379/1 -COLG_TOKEN="Bearer " -HELPER_TOKEN="" -HELPER_ID="" \ No newline at end of file +COLG_TOKEN="Bearer 7B8B817D9BC838B813A1E6B1A0CAFD5F" +HELPER_TOKEN="ESc6Z2kW" +HELPER_ID="706194702" \ No newline at end of file diff --git a/backend/core/abstract/character.py b/backend/core/abstract/character.py index fcb455c8..040a1c36 100644 --- a/backend/core/abstract/character.py +++ b/backend/core/abstract/character.py @@ -1,6 +1,7 @@ from abc import ABC, abstractmethod from typing import Any, Literal, Mapping + class CharacterProperty(ABC): """ 抽象类,用于定义Character的接口和属性 @@ -152,7 +153,8 @@ class CharacterProperty(ABC): 攻击强化P=0, 增益量=0, 增益量P=0, - **kwargs: Mapping[Literal[ + **kwargs: Mapping[ + Literal[ 'STR', 'INT', 'AtkP', @@ -187,7 +189,9 @@ class CharacterProperty(ABC): 'Spirit', 'Vitality', 'EquEffectRatio', - ], Any], + ], + Any, + ], ) -> None: """设置角色属性""" pass @@ -198,7 +202,7 @@ class CharacterProperty(ABC): pass @abstractmethod - def AddSkillLv(self, min: int, max: int, lv: int, type=-1,exceptSkills:list[str]=[]) -> None: + def AddSkillLv(self, min: int, max: int, lv: int, type=-1, exceptSkills: list[str] = []) -> None: """增加技能等级""" pass @@ -236,3 +240,8 @@ class CharacterProperty(ABC): def calc(self, setInfo: dict[str, dict]) -> dict: """计算角色属性""" pass + + @abstractmethod + def GetReinforceSum(self) -> list[int]: + """获取强化总和""" + pass diff --git a/backend/core/basic/character/__init__.py b/backend/core/basic/character/__init__.py new file mode 100644 index 00000000..6106bb9a --- /dev/null +++ b/backend/core/basic/character/__init__.py @@ -0,0 +1,43 @@ +""" +core.basic.character 包 +- jade.py : Jade(辟邪玉)数据类 +- base.py : CharacterBase — 属性声明、__init__、基础状态设置、技能操作 +- calc_equip.py : CalcEquipMixin — 套装/装备/时装/基础强化/辟邪玉/杂项计算 + calc 主入口 +- calc_carry.py : CalcCarryMixin — 输出角色伤害系数与技能伤害计算 +- calc_buffer.py : CalcBufferMixin — 辅助角色 Buff 技能计算 +- info.py : CharacterInfoMixin — 前端展示信息查询 +""" + +import importlib + +from .jade import Jade +from .calc_equip import CalcEquipMixin +from .calc_carry import CalcCarryMixin +from .calc_buffer import CalcBufferMixin +from .info import CharacterInfoMixin + + +class Character(CalcEquipMixin, CalcCarryMixin, CalcBufferMixin, CharacterInfoMixin): + """ + 角色类,通过多重继承组合各模块能力。 + + MRO(方法解析顺序): + Character → CalcEquipMixin → CalcCarryMixin → CalcBufferMixin + → CharacterInfoMixin → CharacterBase → CharacterProperty + """ + + +def createCharacter(alter: str, equVersion: str = '0') -> 'Character': + character: Character = None + module_name = 'core.character.' + alter + if equVersion is None or equVersion == '': + equVersion = '0' + try: + character = importlib.import_module(module_name).classChange(equVersion) + except Exception as ex: + print(ex) + print('create character ' + module_name + ' error.') + return character + + +__all__ = ['Character', 'Jade', 'createCharacter'] diff --git a/backend/core/basic/character/base.py b/backend/core/basic/character/base.py new file mode 100644 index 00000000..1a329239 --- /dev/null +++ b/backend/core/basic/character/base.py @@ -0,0 +1,378 @@ +from collections.abc import Mapping +import sys +from typing import Any, Literal + +from core.abstract.character import CharacterProperty +from core.basic.skill import Skill +from core.basic.equipment import EquEffect, OathSuit, OathSuitSkill, Suit +from ..formula import 获取基础属性, 获取唤醒属性 +from ..roleinfo import CharacterEmblemInfo, CharacterEquipInfo, get_key_by_value, CharacterOathInfo +from .jade import Jade + + +class CharacterBase(CharacterProperty): + # region 额外类属性(CharacterProperty 中未声明的) + + BindAwake: int + """绑定觉醒等级""" + skills: list['Skill'] = [] + skills_dict: dict[str, 'Skill'] = {} + equVersion: str = '0' + """装备版本""" + charEquipInfo: dict[str, 'CharacterEquipInfo'] + """装备打造信息""" + charEmblemInfo: list['CharacterEmblemInfo'] + """徽章打造信息""" + charOathInfo: list['CharacterOathInfo'] + """誓约打造信息""" + charOathSkillId: int + """誓约技能ID""" + suitInfo: list['Suit'] + """套装信息""" + oathSuitInfo: list['OathSuit'] + """誓约套装信息""" + oathSkillInfo: list['OathSuitSkill'] + """誓约技能信息""" + equ_effect: list['EquEffect'] = [] + """装备效果列表""" + equ_options: dict[str, int] = {} + """装备选项列表""" + EquEffectRatio = 1.0 + """装备效果倍率""" + max_point = 0 + """套装效果点数""" + buffer: bool = False + + # region 职业属性 + 实际名称: str = '' + 名称: str = '' + 角色: str = '' + 角色类型: str = '' + 职业: str = '' + 武器选项: list[str] = [] + 副武器选项: list[str] = [] + 输出类型选项: list[str] = [] + 防具精通属性: list[str] = [] + 输出类型: str = '物理百分比' + # endregion + + # endregion + + # region 跨 Mixin 方法前向声明(供静态类型检查使用,由对应 Mixin 实现) + + def load_skills(self) -> None: + """加载技能(由 CalcEquipMixin 实现)""" + + def calc_carry_skills(self, DSB: bool, BUFF: bool) -> list: + """计算输出技能(由 CalcCarryMixin 实现)""" + return [] + + def get_carry_info(self) -> list: + """获取输出信息(由 CalcCarryMixin 实现)""" + return [] + + def calc_buffer_skills(self) -> list: + """计算辅助技能(由 CalcBufferMixin 实现)""" + return [] + + def get_buffer_info(self) -> list: + """获取辅助信息(由 CalcBufferMixin 实现)""" + return [] + + # endregion + + def __init__(self, equVersion, moduleName) -> None: + self.equVersion = equVersion + self.moduleName = moduleName + # 工会四维 + self.STR = 0 + 120 + self.INT = 0 + 120 + self.Spirit = 0 + 120 + self.Vitality = 0 + 120 + # 唤醒的情况下的基础数据 + self.AtkP = 0 + 65 + self.AtkM = 0 + 65 + self.AtkI = 0 + 65 + self.PAtkP = 1.0 + self.PAtkM = 1.0 + self.PAtkI = 1.0 + self.ElementA = { + '火': False, + '冰': False, + '光': False, + '暗': False, + } + self.ElementDB = { + '火': 13, + '冰': 13, + '光': 13, + '暗': 13, + } + self.ElementR = { + '火': 0, + '冰': 0, + '光': 0, + '暗': 0, + } + self.Abnormal = { + '出血': False, + '灼伤': False, + '感电': False, + '中毒': False, + } + self.CriticalM = 0 + self.CriticalP = 0 + self.SkillAttack = 1 + self.SpeedA = 0 + self.SpeedM = 0 + self.SpeedR = 0 + self.HitP = 0 + self.Hit = 0 + self.MonsterInfo = { + 'DefenseP': 0, + 'DefenseM': 0, + '火抗': 0, + '冰抗': 0, + '光抗': 0, + '暗抗': 0, + } + self.Buffer = 0 + self.BufferP = 1.0 + self.Attack = 0 + self.AttackP = 1.0 + self.ElementIncrease = 1.0 + self.equs = {} + self.jade_effect = Jade() + self.equ_effect = [] + self.equ_options = {} + self.max_point = 0 + self.skills = [] + self.skills_dict = {} + self.load_skills() + + # region 角色属性设置 + + def SetBaseStatus(self) -> None: + """设角色基础属性""" + temp = 获取基础属性(self.角色, self.职业) + 唤醒 = 获取唤醒属性() + for index, i in enumerate([get_key_by_value(i) for i in ['力量', '体力', '智力', '精神']]): + setattr(self, i, getattr(self, i) + temp[index] + 唤醒) + + def SetStatus( + self, + 力量=0, + 智力=0, + 力智=0, + 体力=0, + 精神=0, + 体精=0, + 四维=0, + 物攻=0, + 魔攻=0, + 独立=0, + 三攻=0, + 技攻=0, + 全属强=0, + 全属抗=0, + 移动速度=0, + 攻击速度=0, + 施放速度=0, + 三速=0, + 命中=0, + 命中率=0, + 物暴=0, + 魔暴=0, + 攻击强化=0, + 攻击强化P=0, + 增益量=0, + 增益量P=0, + **kwargs: Mapping[ + Literal[ + 'STR', + 'INT', + 'AtkP', + 'AtkM', + 'AtkI', + 'PAtkP', + 'PAtkM', + 'PAtkI', + 'PATKIPDamage', + 'PDamageC', + 'PSTR', + 'PINT', + 'PDamageB', + 'ElementA', + 'ElementDB', + 'ElementR', + 'CriticalMP', + 'CriticalM', + 'CriticalPP', + 'CriticalP', + 'EquipmentSkillAttack', + 'SkillAttack', + 'SpeedA', + 'SpeedM', + 'SpeedR', + 'HitP', + 'Hit', + 'Attack', + 'AttackP', + 'Buffer', + 'BufferP', + 'Spirit', + 'Vitality', + 'EquEffectRatio', + '火强', + '冰强', + '光强', + '暗强', + '火属性抗性', + '冰属性抗性', + '光属性抗性', + '暗属性抗性', + '火属性攻击', + '冰属性攻击', + '光属性攻击', + '暗属性攻击', + ], + Any, + ], + ) -> None: + """设置角色属性""" + # if kwargs.get('SkillAttack', 0) != 0: + # frame = sys._getframe(1) # 1 表示上一级调用帧 + # caller_name = frame.f_code.co_name + # print(caller_name, kwargs.get('SkillAttack', 0)) + self.STR += 力量 + kwargs.get('STR', 0) + 四维 + 力智 + self.INT += 智力 + kwargs.get('INT', 0) + 四维 + 力智 + self.Spirit += 精神 + kwargs.get('Spirit', 0) + 四维 + 体精 + self.Vitality += 体力 + kwargs.get('Vitality', 0) + 四维 + 体精 + self.AtkP += 物攻 + kwargs.get('AtkP', 0) + 三攻 + self.AtkM += 魔攻 + kwargs.get('AtkM', 0) + 三攻 + self.AtkI += 独立 + kwargs.get('AtkI', 0) + 三攻 + self.PAtkP *= kwargs.get('PAtkP', 1.0) + self.PAtkM *= kwargs.get('PAtkM', 1.0) + self.PAtkI *= kwargs.get('PAtkI', 1.0) + for elem in ['火', '冰', '光', '暗']: + self.ElementA[elem] = kwargs.get(f'{elem}属性攻击', False) or kwargs.get('ElementA', {}).get(elem, False) or self.ElementA[elem] + self.ElementDB[elem] += kwargs.get(f'{elem}强', 0) + kwargs.get('ElementDB', {}).get(elem, 0) + 全属强 + self.ElementR[elem] += kwargs.get(f'{elem}抗', 0) + kwargs.get('ElementR', {}).get(elem, 0) + 全属抗 + self.CriticalM += kwargs.get('CriticalM', 0) + 魔暴 + self.CriticalP += kwargs.get('CriticalP', 0) + 物暴 + self.SkillAttack *= (1 + 技攻) * (1 + kwargs.get('SkillAttack', 0)) + self.SpeedA += 攻击速度 + kwargs.get('SpeedA', 0) + 三速 + self.SpeedM += 移动速度 + kwargs.get('SpeedM', 0) + 三速 + self.SpeedR += 施放速度 + kwargs.get('SpeedR', 0) + 三速 + self.HitP += 命中率 + kwargs.get('HitP', 0) + self.Hit += 命中 + kwargs.get('Hit', 0) + self.Attack += 攻击强化 + kwargs.get('Attack', 0) + self.AttackP += 攻击强化P + kwargs.get('AttackP', 0.0) + self.Buffer += 增益量 + kwargs.get('Buffer', 0) + self.BufferP += 增益量P + kwargs.get('BufferP', 0) + self.EquEffectRatio += kwargs.get('EquEffectRatio', 0.0) + + def AddElementDB(self, element: str, value: float, type: int = 0) -> None: + """ + 增加属性强化 + type: 0 站街 1 进图 + """ + if element not in self.ElementDB: + raise ValueError(f'Invalid element: {element}') + if type == 0: + value = value * (1 + self.jade_effect.ElementIncrease) + if type == 1: + value = int(value * (1 + self.jade_effect.ElementIncrease)) + self.ElementDB[element] += value + + def AddSkillLv(self, min: int, max: int, lv: int, type=-1, exceptSkills: list[str] = []) -> None: + """ + 增加技能等级 + type: -1 全部, 0 被动, 1 主动 + """ + skillType = 'all' if type == -1 else ('active' if type == 1 else 'passive') + for skill in self.skills: + if min <= skill.learnLv <= max: + if (skillType == 'all' or skill.type == skillType) and skill.lv > 0 and skill.name not in exceptSkills: + skill.lv += lv + + def SetSkillCD(self, min=1, max=100, cd=0, exclude=[50, 85, 100]) -> None: + """设置技能CD""" + for skill in self.skills: + if min <= skill.learnLv <= max and (skill.type == 'active' or skill.damage) and skill.learnLv not in exclude: + skill.cdReduce *= 1 - cd + + def SetSkillCDRecover(self, min=1, max=100, cd=0, exclude=[50, 85, 100]) -> None: + """设置技能CD恢复""" + for skill in self.skills: + if min <= skill.learnLv <= max and (skill.type == 'active' or skill.damage) and skill.learnLv not in exclude: + skill.cdRecover += cd + + def SetSkillRation(self, min=1, max=100, ratio=1, type=-1) -> None: + """设置技能倍率 + 0 修改技能面板 1 不修改技能面板 + type: -1 全部, 0 被动, 1 主动 + """ + for skill in self.skills: + if min <= skill.learnLv <= max and skill.damage and skill.type == 'active': + if type == 0: + skill.skillRation *= 1 + ratio + else: + skill.skillDamage *= 1 + ratio + + # endregion + + # region 技能查询 + + def GetSkillByName(self, name) -> 'Skill': + """通过技能名获取技能""" + return self.skills_dict.get(name, None) + + def GetSkillByID(self, id: str) -> 'Skill': + """通过技能ID获取技能""" + skill = list(filter(lambda x: str(x.id) == id, self.skills)) + return skill[0] if len(skill) > 0 else None + + def GetSkillByUUID(self, uuid: str) -> 'Skill': + """通过技能UUID获取技能""" + skill = list(filter(lambda x: str(x.uuid) == uuid, self.skills)) + return skill[0] if len(skill) > 0 else None + + def GetSkillNames(self, type: Literal['active', 'passive', 'all'] = 'all', damage: Literal[True, False, 'all'] = 'all') -> list[str]: + """获取技能名字""" + return [skill.name for skill in self.skills if (type == 'all' or skill.type == type) and (damage == 'all' or skill.damage == damage)] + + def GetWeaponType(self) -> tuple[str, str]: + """获取武器类型""" + weapon = self.charEquipInfo['武器'].equInfo + if weapon is None: + return None, None + else: + return weapon.itemDetailType, weapon.categorize + + # endregion + + def GetReinforceSum(self) -> list[int]: + """获取强化总和""" + reinforce_0 = 0 + """防具""" + reinforce_1 = 0 + """首饰""" + reinforce_2 = 0 + """特殊装备""" + reinforce_3 = 0 + """武器""" + for part in self.charEquipInfo.keys(): + if self.charEquipInfo[part] is None: + continue + num = self.charEquipInfo[part].reinforce + # if part == '武器': + # reinforce_3 += num + if part in ['上衣', '头肩', '下装', '腰带', '鞋']: + reinforce_0 += num + if part in ['手镯', '项链', '戒指']: + reinforce_1 += num + if part in ['耳环', '辅助装备', '魔法石']: + reinforce_2 += num + reinforce = reinforce_0 + reinforce_1 + reinforce_2 + reinforce_3 + return [reinforce, reinforce_0, reinforce_1, reinforce_2] diff --git a/backend/core/basic/character/calc_buffer.py b/backend/core/basic/character/calc_buffer.py new file mode 100644 index 00000000..ebfa4b75 --- /dev/null +++ b/backend/core/basic/character/calc_buffer.py @@ -0,0 +1,64 @@ +from core.basic.property import CharacterInfo +from ..roleinfo import get_key_by_value +from .base import CharacterBase + + +class CalcBufferMixin(CharacterBase): + """辅助角色 Buff 技能计算相关方法""" + + # region 辅助计算项 + + def calc_buffer_skills(self): + skillInfos = [] + # 适用属性 + main = getattr(self, get_key_by_value(self.适用属性)) + # 增益量 + buffer_power = self.Buffer * self.BufferP + # buff系数 + buff_ratio_new = (main / 2993 + 1) * (buffer_power / 4800 + 1) if buffer_power > 0 else 0 + buff_ratio_old = main / 2993 + 1 + # 觉醒系数 + awake_ratio_new = ((main + 7500) / 7500 + 1) * ((buffer_power + 68000) / 8500 + 1) if buffer_power > 0 else 0 + awake_ratio_old = main / 7500 + 1 + for i in self.skills: + if i.lv > 0 and i.hasUP and i.up is not None and i.up > 0: + self.SetStatus(四维=40) + if i.buffer and i.lv > 0: + info = i.skillInfo() + value = info[0] + if i.buffType == 'buff' or i.buffType == 'buffSub': + value1 = (info[1][0] + info[1][2]) * info[1][1] * buff_ratio_old + info[1][0] * buff_ratio_new + value2 = (info[2][0] + info[2][2]) * info[2][1] * buff_ratio_old + info[2][0] * buff_ratio_new + elif i.buffType == 'awake' or i.buffType == 'awakeSub': + value1 = (info[1][0] + info[1][2]) * info[1][1] * awake_ratio_old + info[1][0] * awake_ratio_new + value2 = (info[2][0] + info[2][2]) * info[2][1] * awake_ratio_old + info[2][0] * awake_ratio_new + else: + value1 = (info[1][0] + info[1][2]) * info[1][1] + value2 = (info[2][0] + info[2][2]) * info[2][1] + value3 = info[3] + value4 = info[4] + if i.buffType == 'awake' and self.bindAwake == 50: + pass + else: + skillInfos.append( + { + 'name': i.name, + 'cd': value4, + 'icon': i.icon, + 'lv': i.lv, + 'buff': [value, value1, value2, value3], + 'type': i.type, + } + ) + return skillInfos + + def get_buffer_info(self): + attrs = [get_key_by_value(self.适用属性), 'Buffer', 'BufferP'] + info = [] + for attr in attrs: + temp = getattr(CharacterInfo, attr) + value = getattr(self, attr) + info.append({'name': temp.name, 'value': temp.value(value)}) + return info + + # endregion diff --git a/backend/core/basic/character/calc_carry.py b/backend/core/basic/character/calc_carry.py new file mode 100644 index 00000000..956d41d5 --- /dev/null +++ b/backend/core/basic/character/calc_carry.py @@ -0,0 +1,103 @@ +from ..formula import 获取基础属性 +from core.basic.property import CharacterInfo +from .base import CharacterBase + + +class CalcCarryMixin(CharacterBase): + """输出角色技能伤害计算相关方法""" + + # region 输出计算项 + + def calc_damage_ration(self, DSB: bool, BUFF: bool): + """计算属性系数""" + attrs = [] + if self.输出类型 == '物理百分比': + attrs.extend(['STR', 'AtkP', 'PAtkP']) + if self.输出类型 == '魔法百分比': + attrs.extend(['INT', 'AtkM', 'PAtkM']) + if self.输出类型 == '物理固伤': + attrs.extend(['STR', 'AtkI', 'PAtkI']) + if self.输出类型 == '魔法固伤': + attrs.extend(['INT', 'AtkI', 'PAtkI']) + # 力智系数 + value0_1 = getattr(self, attrs[0]) + value0_2 = 获取基础属性(self.角色, self.职业)[0] if attrs[0] == 'STR' else 获取基础属性(self.角色, self.职业)[1] + # 系统奶及奶系增幅 + value = value0_1 + ((value0_1 - value0_2) * 3.08 + 2886) * (1 if DSB else 0) + (170000 + 300000) * (1 if BUFF else 0) + ratio_0: float = value / 250 + 1 + # 物理/魔法/独立攻击力 + ratio_1: float = getattr(self, attrs[1]) + 30000 * (1 if BUFF else 0) + # 技能 物理/魔法/独立攻击力% + ratio_2: float = getattr(self, attrs[2]) + # 属强系数 + ratio_3 = max(self.ElementDB.values()) * 0.0045 + 1.05 + # 暴击系数 + ratio_4 = 1.5 + # BUFF系数 + ratio_5 = self.buff + # 技攻系数 + ratio_6 = self.SkillAttack * (self.jade_effect.SkillAttack + 1) + # 攻击强化 + ratio_7 = 1 + self.Attack / 100 * (self.AttackP + self.jade_effect.AttackP) + # 防御系数,暂定145沙袋防御 + monster_defense = 81417275817 + ratio_8 = 1 - monster_defense / (monster_defense + 200 * 100) + # 杂项 + ratio_9 = 1.0 * self.ElementIncrease + return (ratio_0, ratio_1, ratio_2, ratio_3, ratio_4, ratio_5, ratio_6, ratio_7, ratio_8, ratio_9) + + def calc_carry_skills(self, DSB: bool, BUFF: bool): + skillInfos = [] + for i in self.skills: + if i.damage and i.lv > 0: + for mode in i.mode: + temp = i.skillInfo(mode) + if temp[0] > 0: + skillInfos.append( + { + 'name': i.name, + 'icon': i.icon, + 'lv': i.lv, + 'data': temp[0], + 'ratio': temp[1], + 'cd': temp[2], + 'mode': mode, + 'learnLv': i.learnLv, + 'type': i.type, + } + ) + ratios = self.calc_damage_ration(DSB, BUFF) + ratio_char_skill = ratios[0] * ratios[1] * ratios[2] * ratios[3] * ratios[4] * ratios[5] * ratios[6] * ratios[7] * ratios[8] * ratios[9] / 1000 + ratuio_equ_skill = ratios[0] * ratios[1] * ratios[3] * ratios[4] * ratios[6] * ratios[7] * ratios[8] * ratios[9] / 1000 + for i in skillInfos: + i['damage'] = ratio_char_skill * i['data'] * i['ratio'] / 100 + for i in self.equ_effect: + skillInfos.append({'name': i.name, 'icon': i.icon, 'lv': 0, 'data': i.data, 'ratio': 10.0, 'cd': i.cd, 'damage': ratuio_equ_skill * i.data * 10 * self.EquEffectRatio / 100, 'mode': ''}) + return skillInfos + + def get_carry_info(self): + attrs = [] + if self.输出类型 == '物理百分比': + attrs.extend(['STR', 'AtkP']) + if self.输出类型 == '魔法百分比': + attrs.extend(['INT', 'AtkM']) + if self.输出类型 == '物理固伤': + attrs.extend(['STR', 'AtkI']) + if self.输出类型 == '魔法固伤': + attrs.extend(['INT', 'AtkI']) + info = [] + attrs.extend(['Attack', 'AttackP', 'SkillAttack', 'EquEffectRatio', 'ElementDB']) + for attr in attrs: + temp = getattr(CharacterInfo, attr) + if attr.startswith('Atk'): + info.append({'name': temp.name, 'value': temp.value(getattr(self, attr) * getattr(self, f'P{attr}'))}) + else: + value = getattr(self, attr) + if attr == 'SkillAttack': + value *= self.jade_effect.SkillAttack + 1 + if attr == 'AttackP': + value += self.jade_effect.AttackP + info.append({'name': temp.name, 'value': temp.value(value)}) + return info + + # endregion diff --git a/backend/core/basic/character/calc_equip.py b/backend/core/basic/character/calc_equip.py new file mode 100644 index 00000000..3b097376 --- /dev/null +++ b/backend/core/basic/character/calc_equip.py @@ -0,0 +1,379 @@ +import sys +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 + + +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'] = {} + for key in info['equips']: + self.charEquipInfo[key] = CharacterEquipInfo(info['equips'][key], self.equVersion, key) + for key in info['oaths']: + # 导入誓约打造信息、誓约信息 + self.charOathInfo.append(CharacterOathInfo(info['oaths'][key], self.equVersion, key)) + 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 as e: + 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: + """加载技能""" + module = sys.modules[self.moduleName] + for name in dir(module): + memberClass = getattr(module, name) + if isinstance(memberClass, type) and memberClass.__name__.startswith('Skill'): + skill = memberClass(char=self) + self.skills_dict[skill.name] = skill + self.skills.append(skill) + + # endregion + + # region 套装 / 装备 / 时装 / 基础属性 / 辟邪玉 / 杂项 + + def calc_suits(self): + """套装效果统计""" + suitInfo = {} + oathSuitInfo = {} + equs = get_equipment(self.equVersion) + for item in filter(lambda x: x.equInfo is not None, self.charEquipInfo.values()): + partEqu = item.equInfo + # partFusion = item.fusionInfo + if partEqu is not None: + for suit in partEqu.suit: + if suitInfo.get(suit, None) is None: + suitInfo[suit] = {'point': 0, 'count': 0} + if partEqu.Point == 0: + suitInfo[suit]['count'] += 1 + else: + suitInfo[suit]['point'] += partEqu.Point + for item in self.charOathInfo: + partOath = item.oathInfo + if partOath is not None: + for suit in partOath.suit: + if oathSuitInfo.get(suit, None) is None: + oathSuitInfo[suit] = {'point': 0, 'count': 0} + if partOath.Point == 0: + oathSuitInfo[suit]['count'] += 1 + else: + oathSuitInfo[suit]['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 0 < suitInfo[max_point_suit]['point'] < 2550 and oathSuitInfo.get('max_point_oath_suit', None) is not None: + suitInfo[max_point_suit]['point'] += min(2550 - suitInfo[max_point_suit]['point'], oathSuitInfo[max_point_oath_suit]['point']) + oathSuitInfo[max_point_oath_suit]['point'] -= min(2550 - suitInfo[max_point_suit]['point'], oathSuitInfo[max_point_oath_suit]['point']) + pass + suits = zero_point_suits + ([max_point_suit] if max_point_suit is not None else []) + suitList: list[Suit] = [] + oathSuitList: list[OathSuit] = [] + res = [] + 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 + self.suitInfo = suitList + temp = suitList[-1] + res.append( + { + 'id': temp.id, + 'name': temp.name, + 'rarity': temp.rarity, + 'point': suitInfo[suit]['point'], + 'count': suitInfo[suit]['count'], + 'level': temp.level, + '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 + for suit in suitList: + i = suit.id + func = equs.funs.execture(f'suit_{i}') + suit = next((x for x in equs.suits if str(x.id) == str(i)), None) + # 誓约和套装进行匹配 + # 如果存在誓约和套装是同一个套装 + # 则直接不执行原套装效果,执行誓约套装增强的效果 + oathEffect = next((x for x in oathSuitList if x.suitId == suit.suitId), None) + if suit is not 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) + else: + # 当存在套装和誓约不匹配的时候,誓约技能只能是1号位 + self.charOathSkillId = 1 + oathSkillEffect = [] + self.max_point = max([i['point'] for i in res], default=0) + self.oathSuitInfo = [] + self.oathSkillInfo = [] + # 当套装点数达到太初时,誓约技能生效 + if self.max_point >= 2550: + for oathSuit in oathSuitList: + skill = next((x for x in oathSuit.skills if x.skillId == 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) + + for skill in oathSkillEffect: + func = equs.funs.execture(f'oath_skill_{skill.id}') + if func is not None: + print(f'誓约技能 {skill.id} 生效') + func(self) + if self.max_point >= 2550: + skillAttack = (self.max_point - 2550) // 70 * 0.01 + buffer = (self.max_point - 2550) // 70 * 100 + 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 detail in [(item.equInfo, item.enchant) for item in filter(lambda x: x.equInfo is not None, self.charEquipInfo.values())]: + equ = detail[0] + if equ is None or equ.itemType == '副武器': + continue + enchat = detail[1] + 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 + 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): + """计算基础属性:防具精通、增幅、强化等""" + for part in ['上衣', '头肩', '下装', '腰带', '鞋']: + cur = self.charEquipInfo[part] + if cur.equInfo is None: + continue + equ = cur.equInfo + reinforce = self.charEquipInfo[part].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 in self.charEquipInfo.keys(): + cur = self.charEquipInfo[part] + 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 + 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 diff --git a/backend/core/basic/character/info.py b/backend/core/basic/character/info.py new file mode 100644 index 00000000..1ead3c67 --- /dev/null +++ b/backend/core/basic/character/info.py @@ -0,0 +1,147 @@ +from core.basic.equipment import get_equipment +from core.basic.property import CharacterInfo +from .base import CharacterBase + + +class CharacterInfoMixin(CharacterBase): + """角色信息查询相关方法(用于前端展示)""" + + def getInfo(self): + """返回到前端信息""" + info = {} + info['role'] = self.role + info['alter'] = self.name + info['equVersion'] = self.equVersion + info['name'] = self.nameCN + info['weapons'] = self.武器选项 + info['subweapons'] = self.副武器选项 + info['buffer'] = self.buffer + if self.buffer: + info['properties'] = self.防具精通属性 + info['properties'] = self.输出类型选项 + skillInfo = [] + skill_clothes = [] + platinum = [] + for skill in self.skills: + if 15 <= skill.learnLv <= 70 and skill.learnLv not in [48, 50]: + platinum.append(skill.name) + if skill.learnLv <= 95: + skill_clothes.append(skill.name) + skillInfo.append( + { + 'id': skill.id, + 'name': skill.name, + 'icon': skill.icon, + 'type': skill.type, + 'learnLv': skill.learnLv, + 'masterLv': skill.masterLv, + 'maxLearnLv': skill.calculate_lv(), + 'maxLv': skill.maxLv, + 'position': skill.position, + 'line': skill.line, + 'bind': skill.bind, + 'hasVP': skill.hasVP, + 'hasUP': skill.hasUP, + 'upType': skill.upType, + 'uuid': skill.uuid, + 'vps': [{'name': i['name'], 'desc': i['desc']} for i in skill.vps], + } + ) + info['skills'] = skillInfo + equInfos = get_equipment(self.equVersion) + equs = [] + suits = [] + oaths = [] + oaths_skills = {} + # stones = [] + for i in equInfos.equs: + if i.itemType == '武器' and i.itemDetailType not in self.武器选项: + continue + equs.append(i.__dict__) + for i in equInfos.suits: + suits.append(i.__dict__) + for i in equInfos.oaths: + oaths.append(i.__dict__) + for i in equInfos.oath_suits: + if i.suitId not in oaths_skills: + oaths_skills[i.suitId] = {'suitInfo': [], 'skills': []} + oaths_skills[i.suitId]['suitInfo'].append( + { + 'name': i.name, + 'rarity': i.rarity, + 'SkillAttack': i.SkillAttack, + 'Buffer': i.Buffer, + 'Attack': i.Attack, + } + ) + if len(oaths_skills[i.suitId]['skills']) == 0: + for skill in i.skills: + oaths_skills[i.suitId]['skills'].append( + { + 'skillId': skill.skillId, + 'name': skill.name, + 'icon': skill.imageUrl, + } + ) + # for i in equInfos.stones: + # stones.append(i.__dict__) + info['oaths'] = oaths + info['equips'] = equs + info['suits'] = suits + info['oaths_skills'] = oaths_skills + # info['stones'] = stones + key = '辅助' if self.buffer else '输出' + info['enchants'] = list(filter(lambda x: key in x['categorize'], equInfos.enchants)) + info['emblems'] = [i for i in equInfos.emblems] + info['avatar'] = equInfos.funs.get_dress_list(skill_clothes) + info['jades'] = equInfos.jades + info['options'] = equInfos.funs.options + info['sundry'] = equInfos.funs.sundryList + for skill in platinum: + info['emblems'].append( + { + 'id': skill, + 'fame': 232, + 'position': ['辅助装备', '魔法石'], + 'detail': skill + ' Lv+1' + ' 四维 + 8', + 'categorize': ['技能'], + 'rarity': '白金', + } + ) + return info + + def getBasicInos(self): + res = [] + attrs = [] + if self.输出类型.includes('物理'): + attrs = ['STR', 'PSTR', 'AtkP', 'PAtkP', 'CriticalPP', 'CriticalP'] + if self.输出类型.includes('魔法'): + attrs = ['INT', 'PINT', 'AtkM', 'PAtkM', 'CriticalMP', 'CriticalM'] + for attr in attrs + ['PDamage', 'PDamageC', 'PDamageB', 'SpeedA', 'SpeedM', 'SpeedR']: + temp = getattr(CharacterInfo, attr) + res.append( + { + 'name': temp.name, + 'value': temp.value(getattr(self, attr)), + 'icon': temp.icon, + } + ) + keys = ['火', '冰', '光', '暗'] + for index in range(0, 4): + temp = getattr(CharacterInfo, f'ElementDB{index}') + res.append( + { + 'name': temp.name, + 'value': temp.value(getattr(self, 'ElementDB')[keys[index]]), + 'icon': temp.icon, + } + ) + temp = getattr(CharacterInfo, f'ElementR{index}') + res.append( + { + 'name': temp.name, + 'value': temp.value(getattr(self, 'ElementR')[keys[index]]), + 'icon': temp.icon, + } + ) + return res diff --git a/backend/core/basic/character/jade.py b/backend/core/basic/character/jade.py new file mode 100644 index 00000000..301e6a7f --- /dev/null +++ b/backend/core/basic/character/jade.py @@ -0,0 +1,12 @@ +class Jade: + ElementIncrease: float + """属性增幅""" + AttackP: float + """攻击强化%""" + SkillAttack: float + """技能攻击力%""" + + def __init__(self) -> None: + self.ElementIncrease = 0.0 + self.AttackP = 0.0 + self.SkillAttack = 0.0 diff --git a/backend/core/basic/character.py b/backend/core/basic/character_old.py similarity index 98% rename from backend/core/basic/character.py rename to backend/core/basic/character_old.py index e1654a97..8d7a1da6 100644 --- a/backend/core/basic/character.py +++ b/backend/core/basic/character_old.py @@ -1,3 +1,15 @@ +# ⚠️ 此文件已被 character/ 包目录取代。 +# Python 会优先加载 character/__init__.py,此文件不会被 import 执行。 +# +# 模块拆分结构(位于 core/basic/character/): +# jade.py — Jade 辟邪玉类 +# base.py — CharacterBase(属性 / __init__ / 基础状态方法 / 技能操作) +# calc_equip.py — CalcEquipMixin(套装/装备/时装/强化/辟邪玉/杂项 + calc 主入口) +# calc_carry.py — CalcCarryMixin(输出伤害计算) +# calc_buffer.py — CalcBufferMixin(辅助 Buff 技能计算) +# info.py — CharacterInfoMixin(前端信息查询) +# __init__.py — 组装 Character 类 + createCharacter 工厂函数 + from functools import cache import importlib import sys @@ -8,7 +20,7 @@ from core.abstract.character import CharacterProperty from core.basic.property import CharacterInfo from core.basic.skill import Skill -from core.basic.equipment import get_equipment, EquEffect, Equ +from core.basic.equipment import Suit, get_equipment, EquEffect, Equ, OathSuit # from core.basic.equipment import equipments # from core.basic.skill import Skill, ActiveSkill, PassiveSkill diff --git a/backend/core/basic/equipment.py b/backend/core/basic/equipment.py index 1c652067..40940518 100644 --- a/backend/core/basic/equipment.py +++ b/backend/core/basic/equipment.py @@ -80,24 +80,25 @@ class Equipments: self.equs: list[Equ] = [] self.oaths: list[Oath] = [] self.oath_dict: dict[str, Oath] = {} - self.stones: list[Equ] = [] + # self.stones: list[Equ] = [] self.funs = self.init_func() self.equ_dict: dict[str, Equ] = {} - self.stone_dict: dict[str, Equ] = {} + # self.stone_dict: dict[str, Equ] = {} self.jades = [] self.enchants = [] self.emblems = [] self.suits: list[Suit] = [] self.suit_dict: dict[str, Suit] = {} - self.oath_suits: list[Suit] = [] + self.oath_suits: list[OathSuit] = [] + self.oath_suit_dict: dict[str, OathSuit] = {} self.init_equs() self.init_suits() self.init_enchants() - self.init_stones() + # self.init_stones() self.init_emblem() self.init_jades() - # self.init_oaths() - # self.init_oath_suits() + self.init_oaths() + self.init_oath_suits() self.engine.dispose() def init_equs(self): @@ -123,36 +124,49 @@ class Equipments: self.equs.append(equ) self.equ_dict[equ.id] = equ - def init_stones(self): - """从数据库中获取所有装备信息""" - with Session(self.engine) as session: - db_list = session.query(StoneData).all() - keys = [key for key in StoneData.__dict__.keys() if key[0].isupper()] + ['suit'] - for item in db_list: - max_adaptation = 0 - item.id = str(item.id) - for attr in keys: - if attr == 'suit': - value = parse_to_number_list(getattr(item, attr), []) - value = [str(int(i)) for i in value] - else: - value = parse_to_number_list(getattr(item, attr)) - max_adaptation = max(max_adaptation, len(value) - 1) - setattr(item, attr, value) - stone_dict = {k: v for k, v in item.__dict__.items() if not k.startswith('_')} - stone_dict['max_adaptation'] = max_adaptation - stone = Equ(**stone_dict) - self.stones.append(stone) - self.stone_dict[stone.id] = stone + # def init_stones(self): + # """从数据库中获取所有装备信息""" + # with Session(self.engine) as session: + # db_list = session.query(StoneData).all() + # keys = [key for key in StoneData.__dict__.keys() if key[0].isupper()] + ['suit'] + # for item in db_list: + # max_adaptation = 0 + # item.id = str(item.id) + # for attr in keys: + # if attr == 'suit': + # value = parse_to_number_list(getattr(item, attr), []) + # value = [str(int(i)) for i in value] + # else: + # value = parse_to_number_list(getattr(item, attr)) + # max_adaptation = max(max_adaptation, len(value) - 1) + # setattr(item, attr, value) + # stone_dict = {k: v for k, v in item.__dict__.items() if not k.startswith('_')} + # stone_dict['max_adaptation'] = max_adaptation + # stone = Equ(**stone_dict) + # self.stones.append(stone) + # self.stone_dict[stone.id] = stone def init_suits(self): """从数据库中获取所有套装信息""" with Session(self.engine) as session: db_list = session.query(SuitData).all() for item in db_list: - suit = Suit(**{k: v for k, v in item.__dict__.items() if not k.startswith('_')}) - self.suits.append(suit) - self.suit_dict.setdefault(str(suit.suitId), []).append(suit) + lvs = len(item.point.split(',')) + suits = {k: v for k, v in item.__dict__.items() if not k.startswith('_')} + for i in range(1, lvs + 1): + suit = {k: v for k, v in suits.items()} + suit['point'] = int(suit['point'].split(',')[i - 1]) + suit['level'] = i + skillAttaks = parse_to_number_list(suit['SkillAttack'], [0]) + suit['SkillAttack'] = 0 if i - 1 >= len(skillAttaks) else skillAttaks[i - 1] + attacks = parse_to_number_list(suit['Attack'], [0]) + suit['Attack'] = 0 if i - 1 >= len(attacks) else attacks[i - 1] + buffers = parse_to_number_list(suit['Buffer'], [0]) + suit['Buffer'] = 0 if i - 1 >= len(buffers) else buffers[i - 1] + suit_obj = Suit(**suit) + self.suits.append(suit_obj) + self.suit_dict.setdefault(str(suit['suitId']), []).append(suit_obj) + pass pass def init_enchants(self): @@ -174,9 +188,9 @@ class Equipments: db_list = session.query(EmblemData).all() for item in db_list: emblem = {k: v for k, v in item.__dict__.items() if not k.startswith('_')} - emblem['position'] = [] if emblem['itemType'] is None else emblem['itemType'].split(',') - emblem['categorize'] = [] if emblem['categorize'] is None else emblem['categorize'].split(',') - del emblem['itemType'] + # emblem['position'] = [] if emblem['itemType'] is None else emblem['itemType'].split(',') + # emblem['categorize'] = [] if emblem['categorize'] is None else emblem['categorize'].split(',') + # del emblem['itemType'] self.emblems.append(emblem) pass pass @@ -225,17 +239,20 @@ class Equipments: suits = {k: v for k, v in item.__dict__.items() if not k.startswith('_')} for i in range(1, lvs + 1): suit = {k: v for k, v in suits.items()} + suit['points'] = suit['point'] suit['point'] = int(suit['point'].split(',')[i - 1]) skills = [x for x in db_skills_list if x.suitId == suit['suitId'] and x.key == suit['key']] suit['level'] = i skillAttaks = parse_to_number_list(suit['SkillAttack'], [0]) - suit['SkillAttack'] = 0 if i - 1 >= len(skillAttaks) else skillAttaks[i - 1] + suit['SkillAttack'] = (0 if len(skillAttaks) == 0 else skillAttaks[0]) if i - 1 >= len(skillAttaks) else skillAttaks[i - 1] attacks = parse_to_number_list(suit['Attack'], [0]) - suit['Attack'] = 0 if i - 1 >= len(attacks) else attacks[i - 1] + suit['Attack'] = (0 if len(attacks) == 0 else attacks[0]) if i - 1 >= len(attacks) else attacks[i - 1] buffers = parse_to_number_list(suit['Buffer'], [0]) - suit['Buffer'] = 0 if i - 1 >= len(buffers) else buffers[i - 1] + suit['Buffer'] = (0 if len(buffers) == 0 else buffers[0]) if i - 1 >= len(buffers) else buffers[i - 1] suit['skills'] = [OathSuitSkill(**{k: v for k, v in skill.__dict__.items() if not k.startswith('_')}) for skill in skills] - self.oath_suits.append(suit) + oath_suit = OathSuit(**suit) + self.oath_suits.append(oath_suit) + self.oath_suit_dict.setdefault(str(suit['suitId']), []).append(oath_suit) pass pass @@ -263,7 +280,7 @@ class Equipments: result[suit.count] = suit return list(result.values()) - def get_oath_suit_info(self, suitId: str | int, point: int = 0, count: int = 0) -> list[Suit]: + def get_oath_suit_info(self, suitId: str | int, point: int = 0, count: int = 0) -> list['OathSuit']: """根据套装点数返回对应适用的誓约套装属性\n 新套装只需要传入suitID和point即可,count默认为0\n 老套装需要传入suitID和count即可,point默认为0 @@ -271,8 +288,8 @@ class Equipments: if suitId not in self.oath_suit_dict: return [] # 先筛选出点数小于等于point和数量小于等于count的套装 - suits: list[Suit] = [suit for suit in self.oath_suit_dict[str(suitId)] if suit.point <= point and suit.count <= count] - result: dict[int, Suit] = {} + suits: list[OathSuit] = [suit for suit in self.oath_suit_dict[str(suitId)] if suit.point <= point and suit.count <= count] + result: dict[int, OathSuit] = {} # 取每种count套装中点数最高的 for suit in suits: if suit.count not in result or suit.point > result[suit.count].point: @@ -320,6 +337,8 @@ class Oath: Buffer: list[float] | float wearUrl: list[str] max_adaptation: int + itemType: str + itemDetailType: str def __init__(self, **kwargs): self.__dict__.update(kwargs) @@ -354,6 +373,9 @@ class OathSuitSkill: bufferValue: str def __init__(self, **kwargs): + for key in ['SkillAttack', 'Attack', 'Buffer']: + if kwargs.get(key) is None: + kwargs[key] = 0 self.__dict__.update(kwargs) @@ -365,6 +387,7 @@ class OathSuit: rarity: str name: str point: int + points: str level: int count: int imageUrl: str diff --git a/backend/core/basic/formula.py b/backend/core/basic/formula.py index 8bd1306c..52e886b8 100644 --- a/backend/core/basic/formula.py +++ b/backend/core/basic/formula.py @@ -127,16 +127,17 @@ def 勋章计算(装备等级, 品质, 强化等级): # region 武器 武器强化系数 = (0, 2, 2.6, 3.6, 4.7, 5.8, 6.9, 8.2, 11, 14.6, 18.7, 26.9, 36.7, 43, 49.2, 55.4, 61.7, 68, 74.3, 80.6, 86.9, 93.2, 99.5, 105.8, 112.1, 118.3, 124.6, 130.9, 137.1, 143.4, 149.7, 156.0) -武器锻造系数 = (0, 2, 3, 4, 6, 8, 13, 18, 25, 32, 41) +# 武器锻造系数 = (0, 2, 3, 4, 6, 8, 13, 18, 25, 32, 41) +武器锻造系数 = (0, 2.6, 3.6, 5.8, 8.2, 11, 18.7, 26.9, 42.1) 武器成长系数 = {'普通': 0.4, '高级': 0.7, '稀有': 1, '神器': 1.25, '勇者': 1.1, '传说': 1.35, '史诗': 1.45, '神话': 1.55} 武器品级加分 = {'普通': 8, '高级': 8, '稀有': 10, '神器': 12, '勇者': 11, '传说': 13, '史诗': 14, '神话': 15} 武器类型系数 = { '短剑': (1.095, 1.115, 1.11), - '太刀': (1.095, 1.105, 1.1), - '钝器': (1.11, 1.095, 1.1), - '巨剑': (1.12, 1.09, 1.1), - '光剑': (1.093, 1.09, 1.1), - '手套': (1.095, 1.115, 1.1), + '太刀': (1.095, 1.105, 1.11), + '钝器': (1.11, 1.095, 1.11), + '巨剑': (1.12, 1.09, 1.11), + '光剑': (1.093, 1.09, 1.11), + '手套': (1.095, 1.115, 1.11), '臂铠': (1.12, 1.09, 1.11), '爪': (1.1, 1.1, 1.11), '拳套': (1.105, 1.095, 1.11), @@ -178,17 +179,24 @@ def 勋章计算(装备等级, 品质, 强化等级): def 武器强化计算(装备等级, 品质, 强化等级, 武器类型, 类型, 默认系数=0): - index = 0 if 类型 == '物理' else (1 if 类型 == '魔法' else ()) + index = 0 + if 类型 == '物理': + index = 0 + elif 类型 == '魔法': + index = 1 + elif 类型 == '独立': + index = 2 武器系数 = max(武器类型系数[武器类型][index], 默认系数) return int((装备等级 + 武器品级加分[品质]) / 8 * 武器成长系数[品质] * 武器强化系数[强化等级] * 武器系数) -def 锻造计算(装备等级, 品质, 锻造等级): - return round((装备等级 + 武器品级加分[品质]) / 8 * 武器成长系数[品质] * 武器锻造系数[锻造等级]) +def 锻造计算(装备等级, 品质, 锻造等级, 武器类型, 默认系数=0): + 武器系数 = max(武器类型系数[武器类型][2], 默认系数) + return int((装备等级 + 武器品级加分[品质]) / 8 * 武器成长系数[品质] * 武器锻造系数[锻造等级] * 武器系数) def 锻造四维(装备等级, 品质, 锻造等级): - return round((装备等级 + 武器品级加分[品质]) / 80 * 武器成长系数[品质] * 武器锻造系数[锻造等级]) + return round((装备等级 + 武器品级加分[品质]) / 130 * 武器成长系数[品质] * 武器锻造系数[锻造等级]) 武器冷却惩罚系数 = { diff --git a/backend/core/basic/roleinfo.py b/backend/core/basic/roleinfo.py index 6087d36e..c9252ad8 100644 --- a/backend/core/basic/roleinfo.py +++ b/backend/core/basic/roleinfo.py @@ -13,32 +13,32 @@ class CharacterEquipInfo: """强化类型""" enchant: str """附魔""" - emblem_0: str - """徽章1""" - emblem_1: str - """徽章2""" - fusion: int | None - """贴膜ID""" + # emblem_0: str + # """徽章1""" + # emblem_1: str + # """徽章2""" + # fusion: int | None + # """贴膜ID""" refine: int | None """锻造等级""" - weaponFusion: int | None - """武器融合详情""" + # weaponFusion: int | None + # """武器融合详情""" adaptation: int """调适等级""" equInfo: Union['Equ', None] """装备信息""" - fusionInfo: Union['Equ', None] - """贴膜信息""" + # fusionInfo: Union['Equ', None] + # """贴膜信息""" precision: float """秘宝精度""" def __init__(self, info={}, equVerison=0, part='') -> None: - info['fusion'] = info.get('fusion', None) + # info['fusion'] = info.get('fusion', None) info['precision'] = info.get('precision', 0) - info['weaponFusion'] = info.get('weaponFusion', None) + # info['weaponFusion'] = info.get('weaponFusion', None) self.__dict__.update(info) equ = get_equipment(equVerison).equ_dict.get(self.id, None) - fusion = get_equipment(equVerison).stone_dict.get(self.fusion, None) + # fusion = get_equipment(equVerison).stone_dict.get(self.fusion, None) if equ is not None and (equ.itemType == part or equ.itemDetailType == part or (equ.itemType == '武器' and part == '副武器')): self.equInfo = equ.adapt(self.adaptation) self.adaptation = min(self.adaptation, self.equInfo.max_adaptation) @@ -46,10 +46,10 @@ class CharacterEquipInfo: self.equInfo.itemType = '副武器' else: self.equInfo = None - if fusion is not None and (fusion.itemType == part or fusion.itemDetailType == part): - self.fusionInfo = fusion.adapt(self.adaptation) - else: - self.fusionInfo = None + # if fusion is not None and (fusion.itemType == part or fusion.itemDetailType == part): + # self.fusionInfo = fusion.adapt(self.adaptation) + # else: + # self.fusionInfo = None class CharacterOathInfo: @@ -71,6 +71,18 @@ class CharacterOathInfo: self.oathInfo = None +class CharacterEmblemInfo: + part: str + """星徽部位""" + items: list[str] + """徽章id列表""" + lv: int + """星徽等级""" + + def __init__(self, info={}) -> None: + self.__dict__.update(info) + + class CharacterWeaponInfo(CharacterEquipInfo): refine: int """锻造等级""" diff --git a/backend/core/equipment/version_0/__init__.py b/backend/core/equipment/version_0/__init__.py index 935f0e09..8702d1df 100644 --- a/backend/core/equipment/version_0/__init__.py +++ b/backend/core/equipment/version_0/__init__.py @@ -6,10 +6,18 @@ from . import emblem from . import enchant from . import sundry from . import suit +from . import oathSuitSkill from .register import execture -options = [{'id': 1, 'name': '龙战八荒', 'options': ['BUFF OFF', 'BUFF ON', '期望']}, {'id': 2, 'name': '混沌净化', 'options': ['净化', '堕落']}, {'id': 3, 'name': '群猎美学', 'options': ['单刷', '组队']}, {'id': 4, 'name': '魔攻核', 'options': ['普通', '追击']}, {'id': 5, 'name': '传世手杖', 'options': ['BUFF ON', 'BUFF OFF', '期望']}, {'id': 6, 'name': '传世嵌合弓', 'options': ['本能飞跃', '非理性着陆']}] +options = [ + {'id': 1, 'name': '龙战八荒', 'options': ['BUFF OFF', 'BUFF ON', '期望']}, + {'id': 2, 'name': '混沌净化', 'options': ['净化', '堕落']}, + {'id': 3, 'name': '群猎美学', 'options': ['单刷', '组队']}, + {'id': 4, 'name': '魔攻核', 'options': ['普通', '追击']}, + {'id': 5, 'name': '传世手杖', 'options': ['BUFF ON', 'BUFF OFF', '期望']}, + {'id': 6, 'name': '传世嵌合弓', 'options': ['本能飞跃', '非理性着陆']}, +] sundryList = { 'medal_rarity': {'id': 0, 'options': [{'name': f'品质:{i}', 'value': idx} for idx, i in enumerate(['普通', '高级', '稀有', '神器', '传说', '史诗'])]}, @@ -28,4 +36,29 @@ sundryList = { 'costume_card': {'id': 13, 'options': [{'name': f'{i}', 'value': idx} for idx, i in enumerate(['无', '四维(3)|三速(1%)'])]}, } -__all__ = [get_dress_list, calc_dress_effect, options, execture, sundryList, equ, stone, jade, emblem, enchant, sundry, suit] +__all__ = [get_dress_list, calc_dress_effect, options, execture, sundryList, equ, stone, jade, emblem, enchant, sundry, suit, oathSuitSkill] + + +def get_reinforce_sum(char): + reinforce_0 = 0 + """防具""" + reinforce_1 = 0 + """首饰""" + reinforce_2 = 0 + """特殊装备""" + reinforce_3 = 0 + """武器""" + for part in char.charEquipInfo.keys(): + if char.charEquipInfo[part] is None: + continue + num = char.charEquipInfo[part].reinforce + # if part == '武器': + # reinforce_3 += num + if part in ['上衣', '头肩', '下装', '腰带', '鞋']: + reinforce_0 += num + if part in ['手镯', '项链', '戒指']: + reinforce_1 += num + if part in ['耳环', '辅助装备', '魔法石']: + reinforce_2 += num + reinforce = reinforce_0 + reinforce_1 + reinforce_2 + reinforce_3 + return reinforce diff --git a/backend/core/equipment/version_0/emblem.py b/backend/core/equipment/version_0/emblem.py index 65d1fac9..a4965606 100644 --- a/backend/core/equipment/version_0/emblem.py +++ b/backend/core/equipment/version_0/emblem.py @@ -1,235 +1,565 @@ from core.abstract.character import CharacterProperty from .register import register -emblem_func_list = {} @register -def emblem_1(char: CharacterProperty): +def emblem_2101(char: CharacterProperty): # DCALC_REMOVE: emblem_1 - # 力智+20 暴击+1.9% - # rarity: 玲珑 - char.SetStatus(力智=20) - pass - - -@register -def emblem_2(char: CharacterProperty): - # DCALC_REMOVE: emblem_2 - # 力智+15 暴击+1.5% - # rarity: 玲珑 - char.SetStatus(力智=15) - pass - - -@register -def emblem_3(char: CharacterProperty): - # DCALC_REMOVE: emblem_3 - # 力智+10 暴击+1.1% - # rarity: 玲珑 - char.SetStatus(力智=10) - pass - - -@register -def emblem_4(char: CharacterProperty): - # DCALC_REMOVE: emblem_4 - # 力智+35 - # rarity: 玲珑 + # 力智 +35 + # rarity: 灿烂 (红色) char.SetStatus(力智=35) pass @register -def emblem_5(char: CharacterProperty): - # DCALC_REMOVE: emblem_5 - # 体精+35 - # rarity: 玲珑 +def emblem_2102(char: CharacterProperty): + # DCALC_REMOVE: emblem_2 + # 体精 +35 + # rarity: 灿烂 (红色) char.SetStatus(体精=35) pass @register -def emblem_6(char: CharacterProperty): - # DCALC_REMOVE: emblem_6 - # 体精+25 - # rarity: 玲珑 - char.SetStatus(体精=25) +def emblem_2103(char: CharacterProperty): + # DCALC_REMOVE: emblem_3 + # 四维 +15 + # rarity: 灿烂 (红色) + char.SetStatus(四维=15) pass @register -def emblem_7(char: CharacterProperty): - # DCALC_REMOVE: emblem_7 - # 体精+17 - # rarity: 玲珑 - char.SetStatus(体精=17) - pass - - -@register -def emblem_8(char: CharacterProperty): - # DCALC_REMOVE: emblem_8 - # 力智+30 - # rarity: 玲珑 - char.SetStatus(力智=30) - pass - - -@register -def emblem_9(char: CharacterProperty): - # DCALC_REMOVE: emblem_9 - # 攻速+2% - # rarity: 玲珑 - char.SetStatus(攻速=0.02) - pass - - -@register -def emblem_10(char: CharacterProperty): - # DCALC_REMOVE: emblem_10 - # 体精+30 - # rarity: 玲珑 - char.SetStatus(体精=30) - pass - - -@register -def emblem_11(char: CharacterProperty): - # DCALC_REMOVE: emblem_11 - # 三攻+20 - # rarity: 玲珑 - char.SetStatus(三攻=20) - pass - - -@register -def emblem_12(char: CharacterProperty): - # DCALC_REMOVE: emblem_12 - # 力智+30 - # rarity: 玲珑 - char.SetStatus(力智=30) - pass - - -@register -def emblem_13(char: CharacterProperty): - # DCALC_REMOVE: emblem_13 - # 体精+30 - # rarity: 玲珑 - char.SetStatus(体精=30) - pass - - -@register -def emblem_14(char: CharacterProperty): - # DCALC_REMOVE: emblem_14 - # 力智+25 - # rarity: 灿烂 +def emblem_2201(char: CharacterProperty): + # DCALC_REMOVE: emblem_4 + # 力智 +25 + # rarity: 灿烂 (黄色) char.SetStatus(力智=25) pass @register -def emblem_15(char: CharacterProperty): +def emblem_2202(char: CharacterProperty): + # DCALC_REMOVE: emblem_5 + # 体精 +25 + # rarity: 灿烂 (黄色) + char.SetStatus(体精=25) + pass + + +@register +def emblem_2203(char: CharacterProperty): + # DCALC_REMOVE: emblem_6 + # 攻速 +1.5% 四维 +10 + # rarity: 灿烂 (黄色) + char.SetStatus(攻速=0.015, 四维=10) + pass + + +@register +def emblem_2204(char: CharacterProperty): + # DCALC_REMOVE: emblem_7 + # 施放 +2.2% 四维 +10 + # rarity: 灿烂 (黄色) + char.SetStatus(施放=0.022, 四维=10) + pass + + +@register +def emblem_2205(char: CharacterProperty): + # DCALC_REMOVE: emblem_8 + # 四维 +10 + # rarity: 灿烂 (黄色) + char.SetStatus(四维=10) + pass + + +@register +def emblem_2301(char: CharacterProperty): + # DCALC_REMOVE: emblem_9 + # 力智 +25 + # rarity: 灿烂 (绿色) + char.SetStatus(力智=25) + pass + + +@register +def emblem_2302(char: CharacterProperty): + # DCALC_REMOVE: emblem_10 + # 体精 +25 + # rarity: 灿烂 (绿色) + char.SetStatus(体精=25) + pass + + +@register +def emblem_2303(char: CharacterProperty): + # DCALC_REMOVE: emblem_11 + # 暴击 +3% 四维 +10 + # rarity: 灿烂 (绿色) + char.SetStatus(暴击=0.030, 四维=10) + pass + + +@register +def emblem_2304(char: CharacterProperty): + # DCALC_REMOVE: emblem_12 + # 四维 +10 + # rarity: 灿烂 (绿色) + char.SetStatus(四维=10) + pass + + +@register +def emblem_2401(char: CharacterProperty): + # DCALC_REMOVE: emblem_13 + # 三攻 +30 + # rarity: 灿烂 (蓝色) + char.SetStatus(三攻=30) + pass + + +@register +def emblem_2402(char: CharacterProperty): + # DCALC_REMOVE: emblem_14 + # 移动 +1.5% 四维 +10 + # rarity: 灿烂 (蓝色) + char.SetStatus(移动=0.015, 四维=10) + pass + + +@register +def emblem_2403(char: CharacterProperty): # DCALC_REMOVE: emblem_15 - # 力智+15 - # rarity: 灿烂 - char.SetStatus(力智=15) + # 四维 +10 + # rarity: 灿烂 (蓝色) + char.SetStatus(四维=10) pass @register -def emblem_16(char: CharacterProperty): +def emblem_2501(char: CharacterProperty): # DCALC_REMOVE: emblem_16 - # 攻速+1.5% - # rarity: 灿烂 - char.SetStatus(攻速=0.015) + # 四维 +10 + # rarity: 灿烂 (彩色) + char.SetStatus(四维=10) pass @register -def emblem_17(char: CharacterProperty): +def emblem_2601(char: CharacterProperty): # DCALC_REMOVE: emblem_17 - # 体精+15 - # rarity: 灿烂 - char.SetStatus(体精=15) + # 力智 +20 暴击 +1.5% + # rarity: 灿烂 (红绿) + char.SetStatus(力智=20, 暴击=0.015) pass @register -def emblem_18(char: CharacterProperty): +def emblem_2602(char: CharacterProperty): # DCALC_REMOVE: emblem_18 - # 三攻+15 - # rarity: 灿烂 - char.SetStatus(三攻=15) + # 力智 +20 + # rarity: 灿烂 (红绿) + char.SetStatus(力智=20) pass @register -def emblem_19(char: CharacterProperty): +def emblem_2701(char: CharacterProperty): # DCALC_REMOVE: emblem_19 - # 体精+15 - # rarity: 灿烂 - char.SetStatus(体精=15) + # 四维 +10 + # rarity: 灿烂 (黄蓝) + char.SetStatus(四维=10) pass @register -def emblem_20(char: CharacterProperty): +def emblem_3101(char: CharacterProperty): # DCALC_REMOVE: emblem_20 - # 力智+17 - # rarity: 华丽 - char.SetStatus(力智=17) + # 力智 +50 + # rarity: 玲珑 (红色) + char.SetStatus(力智=50) pass @register -def emblem_21(char: CharacterProperty): +def emblem_3102(char: CharacterProperty): # DCALC_REMOVE: emblem_21 - # 力智+10 - # rarity: 华丽 - char.SetStatus(力智=10) + # 体精 +50 + # rarity: 玲珑 (红色) + char.SetStatus(体精=50) pass @register -def emblem_22(char: CharacterProperty): +def emblem_3103(char: CharacterProperty): # DCALC_REMOVE: emblem_22 - # 攻速+1.1% - # rarity: 华丽 - char.SetStatus(攻速=0.011) + # 四维 +20 + # rarity: 玲珑 (红色) + char.SetStatus(四维=20) pass @register -def emblem_23(char: CharacterProperty): +def emblem_3201(char: CharacterProperty): # DCALC_REMOVE: emblem_23 - # 体精+10 - # rarity: 华丽 - char.SetStatus(体精=10) + # 力智 +40 + # rarity: 玲珑 (黄色) + char.SetStatus(力智=40) pass @register -def emblem_24(char: CharacterProperty): +def emblem_3202(char: CharacterProperty): # DCALC_REMOVE: emblem_24 - # 三攻+10 - # rarity: 华丽 - char.SetStatus(三攻=10) + # 体精 +40 + # rarity: 玲珑 (黄色) + char.SetStatus(体精=40) pass @register -def emblem_25(char: CharacterProperty): +def emblem_3203(char: CharacterProperty): # DCALC_REMOVE: emblem_25 - # 体精+10 - # rarity: 华丽 - char.SetStatus(体精=10) + # 攻速 +2% 四维 +15 + # rarity: 玲珑 (黄色) + char.SetStatus(攻速=0.020, 四维=15) pass -for i in range(0, 3000): - try: - if str(i) not in emblem_func_list.keys(): - emblem_func_list[str(i)] = eval(f'emblem_{i}') - except Exception: + +@register +def emblem_3204(char: CharacterProperty): + # DCALC_REMOVE: emblem_26 + # 施放 +3% 四维 +15 + # rarity: 玲珑 (黄色) + char.SetStatus(施放=0.030, 四维=15) + pass + + +@register +def emblem_3205(char: CharacterProperty): + # DCALC_REMOVE: emblem_27 + # 四维 +15 + # rarity: 玲珑 (黄色) + char.SetStatus(四维=15) + pass + + +@register +def emblem_3301(char: CharacterProperty): + # DCALC_REMOVE: emblem_28 + # 力智 +40 + # rarity: 玲珑 (绿色) + char.SetStatus(力智=40) + pass + + +@register +def emblem_3302(char: CharacterProperty): + # DCALC_REMOVE: emblem_29 + # 体精 +40 + # rarity: 玲珑 (绿色) + char.SetStatus(体精=40) + pass + + +@register +def emblem_3303(char: CharacterProperty): + # DCALC_REMOVE: emblem_30 + # 暴击 +4% 四维 +15 + # rarity: 玲珑 (绿色) + char.SetStatus(暴击=0.040, 四维=15) + pass + + +@register +def emblem_3304(char: CharacterProperty): + # DCALC_REMOVE: emblem_31 + # 四维 +15 + # rarity: 玲珑 (绿色) + char.SetStatus(四维=15) + pass + + +@register +def emblem_3401(char: CharacterProperty): + # DCALC_REMOVE: emblem_32 + # 三攻 +40 + # rarity: 玲珑 (蓝色) + char.SetStatus(三攻=40) + pass + + +@register +def emblem_3402(char: CharacterProperty): + # DCALC_REMOVE: emblem_33 + # 移动 +2% 四维 +15 + # rarity: 玲珑 (蓝色) + char.SetStatus(移动=0.020, 四维=15) + pass + + +@register +def emblem_3403(char: CharacterProperty): + # DCALC_REMOVE: emblem_34 + # 四维 +15 + # rarity: 玲珑 (蓝色) + char.SetStatus(四维=15) + pass + + +@register +def emblem_3501(char: CharacterProperty): + # DCALC_REMOVE: emblem_35 + # 四维 +15 + # rarity: 玲珑 (彩色) + char.SetStatus(四维=15) + pass + + +@register +def emblem_3601(char: CharacterProperty): + # DCALC_REMOVE: emblem_36 + # 力智 +25 暴击 +1.9% + # rarity: 玲珑 (红绿) + char.SetStatus(力智=25, 暴击=0.019) + pass + + +@register +def emblem_3602(char: CharacterProperty): + # DCALC_REMOVE: emblem_37 + # 力智 +25 + # rarity: 玲珑 (红绿) + char.SetStatus(力智=25) + pass + + +@register +def emblem_3701(char: CharacterProperty): + # DCALC_REMOVE: emblem_38 + # 四维 +15 + # rarity: 玲珑 (黄蓝) + char.SetStatus(四维=15) + pass + + +@register +def emblem_4101(char: CharacterProperty): + # DCALC_REMOVE: emblem_39 + # 力智 +70 + # rarity: 神圣 (红色) + char.SetStatus(力智=70) + pass + + +@register +def emblem_4102(char: CharacterProperty): + # DCALC_REMOVE: emblem_40 + # 体精 +70 + # rarity: 神圣 (红色) + char.SetStatus(体精=70) + pass + + +@register +def emblem_4103(char: CharacterProperty): + # DCALC_REMOVE: emblem_41 + # 四维 +25 + # rarity: 神圣 (红色) + char.SetStatus(四维=25) + pass + + +@register +def emblem_4201(char: CharacterProperty): + # DCALC_REMOVE: emblem_42 + # 力智 +55 + # rarity: 神圣 (黄色) + char.SetStatus(力智=55) + pass + + +@register +def emblem_4202(char: CharacterProperty): + # DCALC_REMOVE: emblem_43 + # 体精 +55 + # rarity: 神圣 (黄色) + char.SetStatus(体精=55) + pass + + +@register +def emblem_4203(char: CharacterProperty): + # DCALC_REMOVE: emblem_44 + # 攻速 +2.5% 四维 +20 + # rarity: 神圣 (黄色) + char.SetStatus(攻速=0.025, 四维=20) + pass + + +@register +def emblem_4204(char: CharacterProperty): + # DCALC_REMOVE: emblem_45 + # 施放 +4% 四维 +20 + # rarity: 神圣 (黄色) + char.SetStatus(施放=0.040, 四维=20) + pass + + +@register +def emblem_4205(char: CharacterProperty): + # DCALC_REMOVE: emblem_46 + # 四维 +20 + # rarity: 神圣 (黄色) + char.SetStatus(四维=20) + pass + + +@register +def emblem_4301(char: CharacterProperty): + # DCALC_REMOVE: emblem_47 + # 力智 +55 + # rarity: 神圣 (绿色) + char.SetStatus(力智=55) + pass + + +@register +def emblem_4302(char: CharacterProperty): + # DCALC_REMOVE: emblem_48 + # 体精 +55 + # rarity: 神圣 (绿色) + char.SetStatus(体精=55) + pass + + +@register +def emblem_4303(char: CharacterProperty): + # DCALC_REMOVE: emblem_49 + # 暴击 +3% 四维 +20 + # rarity: 神圣 (绿色) + char.SetStatus(暴击=0.030, 四维=20) + pass + + +@register +def emblem_4304(char: CharacterProperty): + # DCALC_REMOVE: emblem_50 + # 四维 +20 + # rarity: 神圣 (绿色) + char.SetStatus(四维=20) + pass + + +@register +def emblem_4401(char: CharacterProperty): + # DCALC_REMOVE: emblem_51 + # 三攻 +60 + # rarity: 神圣 (蓝色) + char.SetStatus(三攻=60) + pass + + +@register +def emblem_4402(char: CharacterProperty): + # DCALC_REMOVE: emblem_52 + # 移动 +2.5% 四维 +20 + # rarity: 神圣 (蓝色) + char.SetStatus(移动=0.025, 四维=20) + pass + + +@register +def emblem_4403(char: CharacterProperty): + # DCALC_REMOVE: emblem_53 + # 四维 +20 + # rarity: 神圣 (蓝色) + char.SetStatus(四维=20) + pass + + +@register +def emblem_4501(char: CharacterProperty): + # DCALC_REMOVE: emblem_54 + # 四维 +20 + # rarity: 神圣 (彩色) + char.SetStatus(四维=20) + pass + + +@register +def emblem_4601(char: CharacterProperty): + # DCALC_REMOVE: emblem_55 + # 力智 +30 暴击 +2.5% + # rarity: 神圣 (红绿) + char.SetStatus(力智=30, 暴击=0.025) + pass + + +@register +def emblem_4602(char: CharacterProperty): + # DCALC_REMOVE: emblem_56 + # 力智 +30 + # rarity: 神圣 (红绿) + char.SetStatus(力智=30) + pass + + +@register +def emblem_4701(char: CharacterProperty): + # DCALC_REMOVE: emblem_57 + # 四维 +20 + # rarity: 神圣 (黄蓝) + char.SetStatus(四维=20) + pass + + +@register +def emblem_combine(char: CharacterProperty, position: str, lv: int = 1, emblem_list: list[int | str] = []): + bufferP = [0.001, 0.002, 0.004, 0.006, 0.008, 0.01, 0.013, 0.016, 0.019, 0.022, 0.025, 0.026, 0.027, 0.028, 0.029, 0.03] + buffer = [10, 30, 60, 90, 120, 150, 180, 210, 240270, 300, 320, 340, 360, 380, 400] + skillAttack = [0.002, 0.004, 0.008, 0.012, 0.016, 0.02, 0.023, 0.026, 0.029, 0.032, 0.035, 0.036, 0.037, 0.038, 0.039, 0.04] + attackP = [0.005, 0.009, 0.013, 0.017, 0.021, 0.025, 0.028, 0.031, 0.034, 0.037, 0.04, 0.042, 0.044, 0.046, 0.048, 0.05] + if position == '白金': + return + # 固有属性 + if position == '彩色': + char.SetStatus(BufferP=bufferP[lv - 1], SkillAttack=skillAttack[lv - 1]) + else: + char.SetStatus(Buffer=buffer[lv - 1], AttackP=attackP[lv - 1]) + rarity = (lv - 1) // 5 + emblems = list(filter(lambda x: safeParseInt(x) > 0, emblem_list)) or [] + emblem_raritys = [safeParseInt(i) // 1000 for i in emblems] + # 稀有 + if rarity == 0: + skillAttack = [0.001, 0.001, 0.002, 0.002] + buffer = [10, 10, 20, 20] + # 神器 + elif rarity == 1: + skillAttack = [0.001, 0.002, 0.003, 0.004] + buffer = [10, 20, 30, 40] pass + # 传说 + elif rarity == 2: + skillAttack = [0.002, 0.003, 0.004, 0.005] + buffer = [20, 30, 40, 50] + pass + # 史诗 + elif rarity == 3: + skillAttack = [0.002, 0.003, 0.005, 0.006] + buffer = [20, 30, 50, 60] + pass + SkillAttack = 0 + Buffer = 0 + for i in emblem_raritys: + SkillAttack += skillAttack[i - 1] + Buffer += buffer[i - 1] + char.SetStatus(SkillAttack=SkillAttack, Buffer=Buffer) + + +def safeParseInt(x: int | str | None) -> int: + try: + return int(x) + except Exception: + return 0 diff --git a/backend/core/equipment/version_0/oath.py b/backend/core/equipment/version_0/oath.py new file mode 100644 index 00000000..bee80f95 --- /dev/null +++ b/backend/core/equipment/version_0/oath.py @@ -0,0 +1,543 @@ +from core.basic.equipment import EquEffect +from core.abstract.character import CharacterProperty +from .register import register + + +@register +def oath_2010100(char: CharacterProperty): + pass + + +@register +def oath_2010200(char: CharacterProperty): + pass + + +@register +def oath_2010201(char: CharacterProperty): + pass + + +@register +def oath_2010300(char: CharacterProperty): + pass + + +@register +def oath_2010301(char: CharacterProperty): + pass + + +@register +def oath_2010400(char: CharacterProperty): + pass + + +@register +def oath_2010401(char: CharacterProperty): + pass + + +@register +def oath_2010500(char: CharacterProperty): + pass + + +@register +def oath_2010501(char: CharacterProperty): + pass + + +@register +def oath_2020100(char: CharacterProperty): + pass + + +@register +def oath_2020200(char: CharacterProperty): + pass + + +@register +def oath_2020201(char: CharacterProperty): + pass + + +@register +def oath_2020300(char: CharacterProperty): + pass + + +@register +def oath_2020301(char: CharacterProperty): + pass + + +@register +def oath_2020400(char: CharacterProperty): + pass + + +@register +def oath_2020401(char: CharacterProperty): + pass + + +@register +def oath_2020500(char: CharacterProperty): + pass + + +@register +def oath_2020501(char: CharacterProperty): + pass + + +@register +def oath_2030100(char: CharacterProperty): + pass + + +@register +def oath_2030200(char: CharacterProperty): + pass + + +@register +def oath_2030201(char: CharacterProperty): + pass + + +@register +def oath_2030300(char: CharacterProperty): + pass + + +@register +def oath_2030301(char: CharacterProperty): + pass + + +@register +def oath_2030400(char: CharacterProperty): + pass + + +@register +def oath_2030401(char: CharacterProperty): + pass + + +@register +def oath_2030500(char: CharacterProperty): + pass + + +@register +def oath_2030501(char: CharacterProperty): + pass + + +@register +def oath_2040100(char: CharacterProperty): + pass + + +@register +def oath_2040200(char: CharacterProperty): + pass + + +@register +def oath_2040201(char: CharacterProperty): + pass + + +@register +def oath_2040300(char: CharacterProperty): + pass + + +@register +def oath_2040301(char: CharacterProperty): + pass + + +@register +def oath_2040400(char: CharacterProperty): + pass + + +@register +def oath_2040401(char: CharacterProperty): + pass + + +@register +def oath_2040500(char: CharacterProperty): + pass + + +@register +def oath_2040501(char: CharacterProperty): + pass + + +@register +def oath_2050100(char: CharacterProperty): + pass + + +@register +def oath_2050200(char: CharacterProperty): + pass + + +@register +def oath_2050201(char: CharacterProperty): + pass + + +@register +def oath_2050300(char: CharacterProperty): + pass + + +@register +def oath_2050301(char: CharacterProperty): + pass + + +@register +def oath_2050400(char: CharacterProperty): + pass + + +@register +def oath_2050401(char: CharacterProperty): + pass + + +@register +def oath_2050500(char: CharacterProperty): + pass + + +@register +def oath_2050501(char: CharacterProperty): + pass + + +@register +def oath_2060100(char: CharacterProperty): + pass + + +@register +def oath_2060200(char: CharacterProperty): + pass + + +@register +def oath_2060201(char: CharacterProperty): + pass + + +@register +def oath_2060300(char: CharacterProperty): + pass + + +@register +def oath_2060301(char: CharacterProperty): + pass + + +@register +def oath_2060400(char: CharacterProperty): + pass + + +@register +def oath_2060401(char: CharacterProperty): + pass + + +@register +def oath_2060500(char: CharacterProperty): + pass + + +@register +def oath_2060501(char: CharacterProperty): + pass + + +@register +def oath_2070100(char: CharacterProperty): + pass + + +@register +def oath_2070200(char: CharacterProperty): + pass + + +@register +def oath_2070201(char: CharacterProperty): + pass + + +@register +def oath_2070300(char: CharacterProperty): + pass + + +@register +def oath_2070301(char: CharacterProperty): + pass + + +@register +def oath_2070400(char: CharacterProperty): + pass + + +@register +def oath_2070401(char: CharacterProperty): + pass + + +@register +def oath_2070500(char: CharacterProperty): + pass + + +@register +def oath_2070501(char: CharacterProperty): + pass + + +@register +def oath_2080100(char: CharacterProperty): + pass + + +@register +def oath_2080200(char: CharacterProperty): + pass + + +@register +def oath_2080201(char: CharacterProperty): + pass + + +@register +def oath_2080300(char: CharacterProperty): + pass + + +@register +def oath_2080301(char: CharacterProperty): + pass + + +@register +def oath_2080400(char: CharacterProperty): + pass + + +@register +def oath_2080401(char: CharacterProperty): + pass + + +@register +def oath_2080500(char: CharacterProperty): + pass + + +@register +def oath_2080501(char: CharacterProperty): + pass + + +@register +def oath_2090100(char: CharacterProperty): + pass + + +@register +def oath_2090200(char: CharacterProperty): + pass + + +@register +def oath_2090201(char: CharacterProperty): + pass + + +@register +def oath_2090300(char: CharacterProperty): + pass + + +@register +def oath_2090301(char: CharacterProperty): + pass + + +@register +def oath_2090400(char: CharacterProperty): + pass + + +@register +def oath_2090401(char: CharacterProperty): + pass + + +@register +def oath_2090500(char: CharacterProperty): + pass + + +@register +def oath_2090501(char: CharacterProperty): + pass + + +@register +def oath_2100100(char: CharacterProperty): + pass + + +@register +def oath_2100200(char: CharacterProperty): + pass + + +@register +def oath_2100201(char: CharacterProperty): + pass + + +@register +def oath_2100300(char: CharacterProperty): + pass + + +@register +def oath_2100301(char: CharacterProperty): + pass + + +@register +def oath_2100400(char: CharacterProperty): + pass + + +@register +def oath_2100401(char: CharacterProperty): + pass + + +@register +def oath_2100500(char: CharacterProperty): + pass + + +@register +def oath_2100501(char: CharacterProperty): + pass + + +@register +def oath_2110100(char: CharacterProperty): + pass + + +@register +def oath_2110200(char: CharacterProperty): + pass + + +@register +def oath_2110201(char: CharacterProperty): + pass + + +@register +def oath_2110300(char: CharacterProperty): + pass + + +@register +def oath_2110301(char: CharacterProperty): + pass + + +@register +def oath_2110400(char: CharacterProperty): + pass + + +@register +def oath_2110401(char: CharacterProperty): + pass + + +@register +def oath_2110500(char: CharacterProperty): + pass + + +@register +def oath_2110501(char: CharacterProperty): + pass + + +@register +def oath_2120100(char: CharacterProperty): + pass + + +@register +def oath_2120200(char: CharacterProperty): + pass + + +@register +def oath_2120201(char: CharacterProperty): + pass + + +@register +def oath_2120300(char: CharacterProperty): + pass + + +@register +def oath_2120301(char: CharacterProperty): + pass + + +@register +def oath_2120400(char: CharacterProperty): + pass + + +@register +def oath_2120401(char: CharacterProperty): + pass + + +@register +def oath_2120500(char: CharacterProperty): + pass + + +@register +def oath_2120501(char: CharacterProperty): + pass diff --git a/backend/core/equipment/version_0/oathSuitSkill.py b/backend/core/equipment/version_0/oathSuitSkill.py new file mode 100644 index 00000000..20822a7c --- /dev/null +++ b/backend/core/equipment/version_0/oathSuitSkill.py @@ -0,0 +1,1016 @@ +import inspect + +from core.abstract.character import CharacterProperty +from core.basic.equipment import EquEffect +from .register import register + + +def check_suit(char: CharacterProperty) -> bool: + caller_frame = inspect.stack()[1] + fun_name = caller_frame.function + suitId = int(fun_name.split('_')[-1]) % 10000 + 16000 + print(f'检查套装 {suitId}') + return next((x for x in char.suitInfo if x.suitId == suitId), None) is not None + + +# region 潜影暗袭 + + +@register +def oath_skill_2010101(char: CharacterProperty): + pass + + +@register +def oath_skill_2010102(char: CharacterProperty): + pass + + +@register +def oath_skill_2010103(char: CharacterProperty): + pass + + +@register +def oath_skill_2010201(char: CharacterProperty): + pass + + +@register +def oath_skill_2010202(char: CharacterProperty): + pass + + +@register +def oath_skill_2010203(char: CharacterProperty): + pass + + +@register +def oath_skill_2010301(char: CharacterProperty): + pass + + +@register +def oath_skill_2010302(char: CharacterProperty): + pass + + +@register +def oath_skill_2010303(char: CharacterProperty): + pass + + +@register +def oath_skill_2010401(char: CharacterProperty): + pass + + +@register +def oath_skill_2010402(char: CharacterProperty): + pass + + +@register +def oath_skill_2010403(char: CharacterProperty): + pass + + +@register +def oath_skill_2010501(char: CharacterProperty): + pass + + +@register +def oath_skill_2010502(char: CharacterProperty): + pass + + +@register +def oath_skill_2010503(char: CharacterProperty): + pass + + +# endregion + + +# region 精灵国度 +@register +def oath_skill_2020101(char: CharacterProperty): + pass + + +@register +def oath_skill_2020102(char: CharacterProperty): + pass + + +@register +def oath_skill_2020103(char: CharacterProperty): + pass + + +@register +def oath_skill_2020201(char: CharacterProperty): + pass + + +@register +def oath_skill_2020202(char: CharacterProperty): + pass + + +@register +def oath_skill_2020203(char: CharacterProperty): + pass + + +@register +def oath_skill_2020301(char: CharacterProperty): + pass + + +@register +def oath_skill_2020302(char: CharacterProperty): + pass + + +@register +def oath_skill_2020303(char: CharacterProperty): + pass + + +@register +def oath_skill_2020401(char: CharacterProperty): + pass + + +@register +def oath_skill_2020402(char: CharacterProperty): + pass + + +@register +def oath_skill_2020403(char: CharacterProperty): + pass + + +@register +def oath_skill_2020501(char: CharacterProperty): + pass + + +@register +def oath_skill_2020502(char: CharacterProperty): + pass + + +@register +def oath_skill_2020503(char: CharacterProperty): + pass + + +# endregion + + +# region 理想之黄金乡 +@register +def oath_skill_2030101(char: CharacterProperty): + oath_skill_2030501(char) + pass + + +@register +def oath_skill_2030102(char: CharacterProperty): + pass + + +@register +def oath_skill_2030103(char: CharacterProperty): + pass + + +@register +def oath_skill_2030201(char: CharacterProperty): + pass + + +@register +def oath_skill_2030202(char: CharacterProperty): + pass + + +@register +def oath_skill_2030203(char: CharacterProperty): + pass + + +@register +def oath_skill_2030301(char: CharacterProperty): + pass + + +@register +def oath_skill_2030302(char: CharacterProperty): + pass + + +@register +def oath_skill_2030303(char: CharacterProperty): + pass + + +@register +def oath_skill_2030401(char: CharacterProperty): + pass + + +@register +def oath_skill_2030402(char: CharacterProperty): + pass + + +@register +def oath_skill_2030403(char: CharacterProperty): + pass + + +@register +def oath_skill_2030501(char: CharacterProperty): + # 所有速度+7% + # 技能范围+14% + # 所受伤害-14% + + # 根据防具/首饰/特殊装备的强化/增幅数值总和,适用以下效果。 + # - 每+11,技能伤害+0.5%(最多可叠加12次) + # - 防具:每+5,所受伤害-0.5%(最多可叠加12次) + # - 首饰:每+3,技能范围+1%(最多可叠加12次) + # - 特殊装备:每+3,所有速度+1%(最多可叠加12次) + + # 穿戴[黄金乡:永恒国度]套装时,根据防具/首饰/特殊装备的强化/增幅数值总和,适用以下效果: + # - 110以上:技能伤害+0.5% + # - 121以上:技能伤害+1.5% + # - 132以上:技能伤害+2.5%,赋予霸体,删除[淘金热] + char.SetStatus(SpeedA=0.07, SpeedM=0.07, SpeedR=0.07) + reinforce, reinforce_0, reinforce_1, reinforce_2 = char.GetReinforceSum() + char.SetStatus(SkillAttack=0.005 * min(reinforce_1 // 3, 12)) + char.SetStatus(SpeedA=0.01 * min(reinforce_2 // 3, 12)) + char.SetStatus(SpeedM=0.01 * min(reinforce_2 // 3, 12)) + char.SetStatus(SpeedR=0.01 * min(reinforce_2 // 3, 12)) + if check_suit(char): + print('穿戴黄金乡') + char.SetStatus(SkillRange=0.02 * min(reinforce // 11, 12)) + # char.SetStatus(DamageReduce=0.01 * min(reinforce_0 // 5, 7)) + char.SetStatus(SkillAttack=0.01 * min(reinforce_1 // 3, 12)) + char.SetStatus(SpeedA=0.02 * min(reinforce_2 // 3, 12)) + char.SetStatus(SpeedM=0.02 * min(reinforce_2 // 3, 12)) + char.SetStatus(SpeedR=0.02 * min(reinforce_2 // 3, 12)) + if char.buffer: + char.SetSkillCD(cd=0.02 * min(reinforce // 1, 12)) + if reinforce >= 110: + char.SetStatus(SkillAttack=0.02 * min((reinforce - 110) // 11, 2)) + if char.buffer: + char.SetStatus(Buffer=1500 * min((reinforce - 110) // 11, 2)) + # TODO + # 穿戴[黄金乡:永恒国度]套装时,根据防具/首饰/特殊装备的强化/增幅数值总和,适用以下效果: + # - 110以上:技能伤害+0.5% + # - 121以上:技能伤害+1.5% + # - 132以上:技能伤害+2.5%,赋予霸体,删除[淘金热] + pass + + +@register +def oath_skill_2030502(char: CharacterProperty): + char.SetStatus(SkillAttack=0.132, SpeedA=0.22, SpeedM=0.22, SpeedR=0.22) + pass + + +@register +def oath_skill_2030503(char: CharacterProperty): + reinforce, reinforce_0, reinforce_1, reinforce_2 = char.GetReinforceSum() + if reinforce >= 121: + char.SetStatus(SkillAttack=0.1, SpeedA=0.3, SpeedM=0.3, SpeedR=0.3) + pass + + +# endregion + +# region 龙战八荒 + + +@register +def oath_skill_2040101(char: CharacterProperty): + pass + + +@register +def oath_skill_2040102(char: CharacterProperty): + pass + + +@register +def oath_skill_2040103(char: CharacterProperty): + pass + + +@register +def oath_skill_2040201(char: CharacterProperty): + pass + + +@register +def oath_skill_2040202(char: CharacterProperty): + pass + + +@register +def oath_skill_2040203(char: CharacterProperty): + pass + + +@register +def oath_skill_2040301(char: CharacterProperty): + pass + + +@register +def oath_skill_2040302(char: CharacterProperty): + pass + + +@register +def oath_skill_2040303(char: CharacterProperty): + pass + + +@register +def oath_skill_2040401(char: CharacterProperty): + pass + + +@register +def oath_skill_2040402(char: CharacterProperty): + pass + + +@register +def oath_skill_2040403(char: CharacterProperty): + pass + + +@register +def oath_skill_2040501(char: CharacterProperty): + pass + + +@register +def oath_skill_2040502(char: CharacterProperty): + pass + + +@register +def oath_skill_2040503(char: CharacterProperty): + pass + + +# endregion + +# region 暗黑净化 + + +@register +def oath_skill_2050101(char: CharacterProperty): + pass + + +@register +def oath_skill_2050102(char: CharacterProperty): + pass + + +@register +def oath_skill_2050103(char: CharacterProperty): + pass + + +@register +def oath_skill_2050201(char: CharacterProperty): + pass + + +@register +def oath_skill_2050202(char: CharacterProperty): + pass + + +@register +def oath_skill_2050203(char: CharacterProperty): + pass + + +@register +def oath_skill_2050301(char: CharacterProperty): + pass + + +@register +def oath_skill_2050302(char: CharacterProperty): + pass + + +@register +def oath_skill_2050303(char: CharacterProperty): + pass + + +@register +def oath_skill_2050401(char: CharacterProperty): + pass + + +@register +def oath_skill_2050402(char: CharacterProperty): + pass + + +@register +def oath_skill_2050403(char: CharacterProperty): + pass + + +@register +def oath_skill_2050501(char: CharacterProperty): + pass + + +@register +def oath_skill_2050502(char: CharacterProperty): + pass + + +@register +def oath_skill_2050503(char: CharacterProperty): + pass + + +# endregion + +# region 天命者的气运 + + +@register +def oath_skill_2060101(char: CharacterProperty): + pass + + +@register +def oath_skill_2060102(char: CharacterProperty): + pass + + +@register +def oath_skill_2060103(char: CharacterProperty): + pass + + +@register +def oath_skill_2060201(char: CharacterProperty): + pass + + +@register +def oath_skill_2060202(char: CharacterProperty): + pass + + +@register +def oath_skill_2060203(char: CharacterProperty): + pass + + +@register +def oath_skill_2060301(char: CharacterProperty): + pass + + +@register +def oath_skill_2060302(char: CharacterProperty): + pass + + +@register +def oath_skill_2060303(char: CharacterProperty): + pass + + +@register +def oath_skill_2060401(char: CharacterProperty): + pass + + +@register +def oath_skill_2060402(char: CharacterProperty): + pass + + +@register +def oath_skill_2060403(char: CharacterProperty): + pass + + +@register +def oath_skill_2060501(char: CharacterProperty): + pass + + +@register +def oath_skill_2060502(char: CharacterProperty): + pass + + +@register +def oath_skill_2060503(char: CharacterProperty): + pass + + +# endregion + +# region 究极能量 + + +@register +def oath_skill_2070101(char: CharacterProperty): + pass + + +@register +def oath_skill_2070102(char: CharacterProperty): + pass + + +@register +def oath_skill_2070103(char: CharacterProperty): + pass + + +@register +def oath_skill_2070201(char: CharacterProperty): + pass + + +@register +def oath_skill_2070202(char: CharacterProperty): + pass + + +@register +def oath_skill_2070203(char: CharacterProperty): + pass + + +@register +def oath_skill_2070301(char: CharacterProperty): + pass + + +@register +def oath_skill_2070302(char: CharacterProperty): + pass + + +@register +def oath_skill_2070303(char: CharacterProperty): + pass + + +@register +def oath_skill_2070401(char: CharacterProperty): + pass + + +@register +def oath_skill_2070402(char: CharacterProperty): + pass + + +@register +def oath_skill_2070403(char: CharacterProperty): + pass + + +@register +def oath_skill_2070501(char: CharacterProperty): + pass + + +@register +def oath_skill_2070502(char: CharacterProperty): + pass + + +@register +def oath_skill_2070503(char: CharacterProperty): + pass + + +# endregion + +# region 造化自然 + + +@register +def oath_skill_2080101(char: CharacterProperty): + pass + + +@register +def oath_skill_2080102(char: CharacterProperty): + pass + + +@register +def oath_skill_2080103(char: CharacterProperty): + pass + + +@register +def oath_skill_2080201(char: CharacterProperty): + pass + + +@register +def oath_skill_2080202(char: CharacterProperty): + pass + + +@register +def oath_skill_2080203(char: CharacterProperty): + pass + + +@register +def oath_skill_2080301(char: CharacterProperty): + pass + + +@register +def oath_skill_2080302(char: CharacterProperty): + pass + + +@register +def oath_skill_2080303(char: CharacterProperty): + pass + + +@register +def oath_skill_2080401(char: CharacterProperty): + pass + + +@register +def oath_skill_2080402(char: CharacterProperty): + pass + + +@register +def oath_skill_2080403(char: CharacterProperty): + pass + + +@register +def oath_skill_2080501(char: CharacterProperty): + pass + + +@register +def oath_skill_2080502(char: CharacterProperty): + pass + + +@register +def oath_skill_2080503(char: CharacterProperty): + pass + + +# endregion + +# region 诸神黄昏之女武神 + + +@register +def oath_skill_2090101(char: CharacterProperty): + pass + + +@register +def oath_skill_2090102(char: CharacterProperty): + pass + + +@register +def oath_skill_2090103(char: CharacterProperty): + pass + + +@register +def oath_skill_2090201(char: CharacterProperty): + pass + + +@register +def oath_skill_2090202(char: CharacterProperty): + pass + + +@register +def oath_skill_2090203(char: CharacterProperty): + pass + + +@register +def oath_skill_2090301(char: CharacterProperty): + pass + + +@register +def oath_skill_2090302(char: CharacterProperty): + pass + + +@register +def oath_skill_2090303(char: CharacterProperty): + pass + + +@register +def oath_skill_2090401(char: CharacterProperty): + pass + + +@register +def oath_skill_2090402(char: CharacterProperty): + pass + + +@register +def oath_skill_2090403(char: CharacterProperty): + pass + + +@register +def oath_skill_2090501(char: CharacterProperty): + pass + + +@register +def oath_skill_2090502(char: CharacterProperty): + pass + + +@register +def oath_skill_2090503(char: CharacterProperty): + pass + + +# endregion + +# region 青丘灵珠 + + +@register +def oath_skill_2100101(char: CharacterProperty): + pass + + +@register +def oath_skill_2100102(char: CharacterProperty): + pass + + +@register +def oath_skill_2100103(char: CharacterProperty): + pass + + +@register +def oath_skill_2100201(char: CharacterProperty): + pass + + +@register +def oath_skill_2100202(char: CharacterProperty): + pass + + +@register +def oath_skill_2100203(char: CharacterProperty): + pass + + +@register +def oath_skill_2100301(char: CharacterProperty): + pass + + +@register +def oath_skill_2100302(char: CharacterProperty): + pass + + +@register +def oath_skill_2100303(char: CharacterProperty): + pass + + +@register +def oath_skill_2100401(char: CharacterProperty): + pass + + +@register +def oath_skill_2100402(char: CharacterProperty): + pass + + +@register +def oath_skill_2100403(char: CharacterProperty): + pass + + +@register +def oath_skill_2100501(char: CharacterProperty): + pass + + +@register +def oath_skill_2100502(char: CharacterProperty): + pass + + +@register +def oath_skill_2100503(char: CharacterProperty): + pass + + +# endregion + +# region 群猎美学 + + +@register +def oath_skill_2110101(char: CharacterProperty): + pass + + +@register +def oath_skill_2110102(char: CharacterProperty): + pass + + +@register +def oath_skill_2110103(char: CharacterProperty): + pass + + +@register +def oath_skill_2110201(char: CharacterProperty): + pass + + +@register +def oath_skill_2110202(char: CharacterProperty): + pass + + +@register +def oath_skill_2110203(char: CharacterProperty): + pass + + +@register +def oath_skill_2110301(char: CharacterProperty): + pass + + +@register +def oath_skill_2110302(char: CharacterProperty): + pass + + +@register +def oath_skill_2110303(char: CharacterProperty): + pass + + +@register +def oath_skill_2110401(char: CharacterProperty): + pass + + +@register +def oath_skill_2110402(char: CharacterProperty): + pass + + +@register +def oath_skill_2110403(char: CharacterProperty): + pass + + +@register +def oath_skill_2110501(char: CharacterProperty): + pass + + +@register +def oath_skill_2110502(char: CharacterProperty): + pass + + +@register +def oath_skill_2110503(char: CharacterProperty): + pass + + +# endregion + +# region 冥思者的魔力领域 + + +@register +def oath_skill_2120101(char: CharacterProperty): + pass + + +@register +def oath_skill_2120102(char: CharacterProperty): + pass + + +@register +def oath_skill_2120103(char: CharacterProperty): + pass + + +@register +def oath_skill_2120201(char: CharacterProperty): + pass + + +@register +def oath_skill_2120202(char: CharacterProperty): + pass + + +@register +def oath_skill_2120203(char: CharacterProperty): + pass + + +@register +def oath_skill_2120301(char: CharacterProperty): + pass + + +@register +def oath_skill_2120302(char: CharacterProperty): + pass + + +@register +def oath_skill_2120303(char: CharacterProperty): + pass + + +@register +def oath_skill_2120401(char: CharacterProperty): + pass + + +@register +def oath_skill_2120402(char: CharacterProperty): + pass + + +@register +def oath_skill_2120403(char: CharacterProperty): + pass + + +@register +def oath_skill_2120501(char: CharacterProperty): + pass + + +@register +def oath_skill_2120502(char: CharacterProperty): + pass + + +@register +def oath_skill_2120503(char: CharacterProperty): + pass + + +# endregion diff --git a/backend/core/equipment/version_0/suit.py b/backend/core/equipment/version_0/suit.py index 3adebbad..42250c26 100644 --- a/backend/core/equipment/version_0/suit.py +++ b/backend/core/equipment/version_0/suit.py @@ -14,42 +14,6 @@ def suit_1(char: CharacterProperty): pass -@register -def suit_2(char: CharacterProperty): - # DCALC_REMOVE: suit_2 - 潜影之初心 - # level: 2 - # value: - - # rarity: 稀有 - pass - - -@register -def suit_3(char: CharacterProperty): - # DCALC_REMOVE: suit_3 - 潜影之初心 - # level: 3 - # value: - - # rarity: 稀有 - pass - - -@register -def suit_4(char: CharacterProperty): - # DCALC_REMOVE: suit_4 - 潜影之初心 - # level: 4 - # value: - - # rarity: 稀有 - pass - - -@register -def suit_5(char: CharacterProperty): - # DCALC_REMOVE: suit_5 - 潜影之初心 - # level: 5 - # value: - - # rarity: 稀有 - pass - - @register def suit_6(char: CharacterProperty): # DCALC_REMOVE: suit_6 - 潜影之藏锋 @@ -59,42 +23,6 @@ def suit_6(char: CharacterProperty): pass -@register -def suit_7(char: CharacterProperty): - # DCALC_REMOVE: suit_7 - 潜影之藏锋 - # level: 2 - # value: 逆转与影子的因果关系,实现超乎寻常的动作。 [潜影藏锋][装备主动技能] - 强制中断角色动作(觉醒技能除外) - 冷却时间5秒 - # rarity: 神器 - pass - - -@register -def suit_8(char: CharacterProperty): - # DCALC_REMOVE: suit_8 - 潜影之藏锋 - # level: 3 - # value: 逆转与影子的因果关系,实现超乎寻常的动作。 [潜影藏锋][装备主动技能] - 强制中断角色动作(觉醒技能除外) - 冷却时间5秒 - # rarity: 神器 - pass - - -@register -def suit_9(char: CharacterProperty): - # DCALC_REMOVE: suit_9 - 潜影之藏锋 - # level: 4 - # value: 逆转与影子的因果关系,实现超乎寻常的动作。 [潜影藏锋][装备主动技能] - 强制中断角色动作(觉醒技能除外) - 冷却时间5秒 - # rarity: 神器 - pass - - -@register -def suit_10(char: CharacterProperty): - # DCALC_REMOVE: suit_10 - 潜影之藏锋 - # level: 5 - # value: 逆转与影子的因果关系,实现超乎寻常的动作。 [潜影藏锋][装备主动技能] - 强制中断角色动作(觉醒技能除外) - 冷却时间5秒 - # rarity: 神器 - pass - - @register def suit_11(char: CharacterProperty): # DCALC_REMOVE: suit_11 - 潜影之伏击 @@ -105,46 +33,6 @@ def suit_11(char: CharacterProperty): pass -@register -def suit_12(char: CharacterProperty): - # DCALC_REMOVE: suit_12 - 潜影之伏击 - # level: 2 - # value: 逆转与影子的因果关系,实现超乎寻常的动作。 施放技能时,获得[影子]层数。(最多叠加10次) 所有速度 +15% [潜影灭迹][装备主动技能]存在[影子]层数时,施放装备技能时发动以下效果。 - 消耗3个[影子]层数 - 强制中断角色动作(觉醒技能除外) - # rarity: 传说 - suit_11(char) - pass - - -@register -def suit_13(char: CharacterProperty): - # DCALC_REMOVE: suit_13 - 潜影之伏击 - # level: 3 - # value: 逆转与影子的因果关系,实现超乎寻常的动作。 施放技能时,获得[影子]层数。(最多叠加10次) 所有速度 +15% [潜影灭迹][装备主动技能]存在[影子]层数时,施放装备技能时发动以下效果。 - 消耗3个[影子]层数 - 强制中断角色动作(觉醒技能除外) - # rarity: 传说 - suit_11(char) - pass - - -@register -def suit_14(char: CharacterProperty): - # DCALC_REMOVE: suit_14 - 潜影之伏击 - # level: 4 - # value: 逆转与影子的因果关系,实现超乎寻常的动作。 施放技能时,获得[影子]层数。(最多叠加10次) 所有速度 +15% [潜影灭迹][装备主动技能]存在[影子]层数时,施放装备技能时发动以下效果。 - 消耗3个[影子]层数 - 强制中断角色动作(觉醒技能除外) - # rarity: 传说 - suit_11(char) - pass - - -@register -def suit_15(char: CharacterProperty): - # DCALC_REMOVE: suit_15 - 潜影之伏击 - # level: 5 - # value: 逆转与影子的因果关系,实现超乎寻常的动作。 施放技能时,获得[影子]层数。(最多叠加10次) 所有速度 +15% [潜影灭迹][装备主动技能]存在[影子]层数时,施放装备技能时发动以下效果。 - 消耗3个[影子]层数 - 强制中断角色动作(觉醒技能除外) - # rarity: 传说 - suit_11(char) - pass - - @register def suit_16(char: CharacterProperty): # DCALC_REMOVE: suit_16 - 潜影之灭迹 @@ -155,46 +43,6 @@ def suit_16(char: CharacterProperty): pass -@register -def suit_17(char: CharacterProperty): - # DCALC_REMOVE: suit_17 - 潜影之灭迹 - # level: 2 - # value: 逆转与影子的因果关系,实现超乎寻常的动作。 施放技能时,获得[影子]层数。(最多叠加10次) 所有速度 +15% [潜影灭迹][装备主动技能] 存在[影子]层数时,施放装备技能时发动以下效果。 - 消耗2个[影子]层数 - 强制中断角色动作(觉醒技能除外) [追击替罪羊][装备主动技能] - 消耗7个[影子]层数 - 强制中断角色动作(觉醒技能除外) - 瞬移到最强大的敌人背后 - 追击范围:600px - 冷却时间:8秒 - # rarity: 史诗 - suit_11(char) - pass - - -@register -def suit_18(char: CharacterProperty): - # DCALC_REMOVE: suit_18 - 潜影之灭迹 - # level: 3 - # value: 逆转与影子的因果关系,实现超乎寻常的动作。 施放技能时,获得[影子]层数。(最多叠加10次) 所有速度 +15% [潜影灭迹][装备主动技能] 存在[影子]层数时,施放装备技能时发动以下效果。 - 消耗2个[影子]层数 - 强制中断角色动作(觉醒技能除外) [追击替罪羊][装备主动技能] - 消耗7个[影子]层数 - 强制中断角色动作(觉醒技能除外) - 瞬移到最强大的敌人背后 - 追击范围:600px - 冷却时间:8秒 - # rarity: 史诗 - suit_11(char) - pass - - -@register -def suit_19(char: CharacterProperty): - # DCALC_REMOVE: suit_19 - 潜影之灭迹 - # level: 4 - # value: 逆转与影子的因果关系,实现超乎寻常的动作。 施放技能时,获得[影子]层数。(最多叠加10次) 所有速度 +15% [潜影灭迹][装备主动技能] 存在[影子]层数时,施放装备技能时发动以下效果。 - 消耗2个[影子]层数 - 强制中断角色动作(觉醒技能除外) [追击替罪羊][装备主动技能] - 消耗7个[影子]层数 - 强制中断角色动作(觉醒技能除外) - 瞬移到最强大的敌人背后 - 追击范围:600px - 冷却时间:8秒 - # rarity: 史诗 - suit_11(char) - pass - - -@register -def suit_20(char: CharacterProperty): - # DCALC_REMOVE: suit_20 - 潜影之灭迹 - # level: 5 - # value: 逆转与影子的因果关系,实现超乎寻常的动作。 施放技能时,获得[影子]层数。(最多叠加10次) 所有速度 +15% [潜影灭迹][装备主动技能] 存在[影子]层数时,施放装备技能时发动以下效果。 - 消耗2个[影子]层数 - 强制中断角色动作(觉醒技能除外) [追击替罪羊][装备主动技能] - 消耗7个[影子]层数 - 强制中断角色动作(觉醒技能除外) - 瞬移到最强大的敌人背后 - 追击范围:600px - 冷却时间:8秒 - # rarity: 史诗 - suit_11(char) - pass - - @register def suit_21(char: CharacterProperty): # DCALC_REMOVE: suit_21 - 潜影之幽冥代理 @@ -218,42 +66,6 @@ def suit_22(char: CharacterProperty): pass -@register -def suit_23(char: CharacterProperty): - # DCALC_REMOVE: suit_23 - 精灵元气 - # level: 2 - # value: - - # rarity: 稀有 - pass - - -@register -def suit_24(char: CharacterProperty): - # DCALC_REMOVE: suit_24 - 精灵元气 - # level: 3 - # value: - - # rarity: 稀有 - pass - - -@register -def suit_25(char: CharacterProperty): - # DCALC_REMOVE: suit_25 - 精灵元气 - # level: 4 - # value: - - # rarity: 稀有 - pass - - -@register -def suit_26(char: CharacterProperty): - # DCALC_REMOVE: suit_26 - 精灵元气 - # level: 5 - # value: - - # rarity: 稀有 - pass - - @register def suit_27(char: CharacterProperty): # DCALC_REMOVE: suit_27 - 初阶精灵 @@ -264,46 +76,6 @@ def suit_27(char: CharacterProperty): pass -@register -def suit_28(char: CharacterProperty): - # DCALC_REMOVE: suit_28 - 初阶精灵 - # level: 2 - # value: 召唤精灵一起战斗。 [火灵安珀] 每2秒施放一次火花:伤害量19,200% 每3秒恢复1%的生命值 [停止攻击开关][装备主动技能] 控制精灵们的攻击。 - 攻击中止/继续攻击 - 冷却时间1秒 - # rarity: 神器 - suit_27(char) - pass - - -@register -def suit_29(char: CharacterProperty): - # DCALC_REMOVE: suit_29 - 初阶精灵 - # level: 3 - # value: 召唤精灵一起战斗。 [火灵安珀] 每2秒施放一次火花:伤害量19,200% 每3秒恢复1%的生命值 [停止攻击开关][装备主动技能] 控制精灵们的攻击。 - 攻击中止/继续攻击 - 冷却时间1秒 - # rarity: 神器 - suit_27(char) - pass - - -@register -def suit_30(char: CharacterProperty): - # DCALC_REMOVE: suit_30 - 初阶精灵 - # level: 4 - # value: 召唤精灵一起战斗。 [火灵安珀] 每2秒施放一次火花:伤害量19,200% 每3秒恢复1%的生命值 [停止攻击开关][装备主动技能] 控制精灵们的攻击。 - 攻击中止/继续攻击 - 冷却时间1秒 - # rarity: 神器 - suit_27(char) - pass - - -@register -def suit_31(char: CharacterProperty): - # DCALC_REMOVE: suit_31 - 初阶精灵 - # level: 5 - # value: 召唤精灵一起战斗。 [火灵安珀] 每2秒施放一次火花:伤害量19,200% 每3秒恢复1%的生命值 [停止攻击开关][装备主动技能] 控制精灵们的攻击。 - 攻击中止/继续攻击 - 冷却时间1秒 - # rarity: 神器 - suit_27(char) - pass - - @register def suit_32(char: CharacterProperty): # DCALC_REMOVE: suit_32 - 高阶精灵 @@ -316,46 +88,6 @@ def suit_32(char: CharacterProperty): pass -@register -def suit_33(char: CharacterProperty): - # DCALC_REMOVE: suit_33 - 高阶精灵 - # level: 2 - # value: 召唤精灵一起战斗。 [火灵安珀] 每2秒施放一次火花:伤害量19,200% 每3秒恢复1%的生命值 [水灵阿库娅] 每3秒施放一次水弹:伤害量24,000% 每3秒恢复1%的魔法值 [停止攻击开关][装备主动技能]控制精灵们的攻击。 - 攻击中止/继续攻击 - 冷却时间1秒 [元素释放][装备主动技能] 对精灵下达协同攻击指令。 - 消耗150精灵之魂 - 攻击时,精灵之魂 +10(冷却时间1秒) - 被击时,精灵之魂 -5(冷却时间1秒) - 元素释放伤害量:102700% - # rarity: 传说 - suit_32(char) - pass - - -@register -def suit_34(char: CharacterProperty): - # DCALC_REMOVE: suit_34 - 高阶精灵 - # level: 3 - # value: 召唤精灵一起战斗。 [火灵安珀] 每2秒施放一次火花:伤害量19,200% 每3秒恢复1%的生命值 [水灵阿库娅] 每3秒施放一次水弹:伤害量24,000% 每3秒恢复1%的魔法值 [停止攻击开关][装备主动技能]控制精灵们的攻击。 - 攻击中止/继续攻击 - 冷却时间1秒 [元素释放][装备主动技能] 对精灵下达协同攻击指令。 - 消耗150精灵之魂 - 攻击时,精灵之魂 +10(冷却时间1秒) - 被击时,精灵之魂 -5(冷却时间1秒) - 元素释放伤害量:102700% - # rarity: 传说 - suit_32(char) - pass - - -@register -def suit_35(char: CharacterProperty): - # DCALC_REMOVE: suit_35 - 高阶精灵 - # level: 4 - # value: 召唤精灵一起战斗。 [火灵安珀] 每2秒施放一次火花:伤害量19,200% 每3秒恢复1%的生命值 [水灵阿库娅] 每3秒施放一次水弹:伤害量24,000% 每3秒恢复1%的魔法值 [停止攻击开关][装备主动技能]控制精灵们的攻击。 - 攻击中止/继续攻击 - 冷却时间1秒 [元素释放][装备主动技能] 对精灵下达协同攻击指令。 - 消耗150精灵之魂 - 攻击时,精灵之魂 +10(冷却时间1秒) - 被击时,精灵之魂 -5(冷却时间1秒) - 元素释放伤害量:102700% - # rarity: 传说 - suit_32(char) - pass - - -@register -def suit_36(char: CharacterProperty): - # DCALC_REMOVE: suit_36 - 高阶精灵 - # level: 5 - # value: 召唤精灵一起战斗。 [火灵安珀] 每2秒施放一次火花:伤害量19,200% 每3秒恢复1%的生命值 [水灵阿库娅] 每3秒施放一次水弹:伤害量24,000% 每3秒恢复1%的魔法值 [停止攻击开关][装备主动技能]控制精灵们的攻击。 - 攻击中止/继续攻击 - 冷却时间1秒 [元素释放][装备主动技能] 对精灵下达协同攻击指令。 - 消耗150精灵之魂 - 攻击时,精灵之魂 +10(冷却时间1秒) - 被击时,精灵之魂 -5(冷却时间1秒) - 元素释放伤害量:102700% - # rarity: 传说 - suit_32(char) - pass - - @register def suit_37(char: CharacterProperty): # DCALC_REMOVE: suit_37 - 贵族精灵 @@ -370,46 +102,6 @@ def suit_37(char: CharacterProperty): pass -@register -def suit_38(char: CharacterProperty): - # DCALC_REMOVE: suit_38 - 贵族精灵 - # level: 2 - # value: 召唤精灵一起战斗。 [火灵安珀] 每2秒施放一次火花:伤害量19,200% 每3秒恢复1%的生命值 [水灵阿库娅] 每3秒施放一次水弹:伤害量24,000% 每3秒恢复1%的魔法值 [风灵希尔珂] 每2秒施放一次刀风:伤害量20,500% 移动速度 +15% [停止攻击开关][装备主动技能] 控制精灵们的攻击。 - 攻击中止/继续攻击 - 冷却时间1秒 [元素释放][装备主动技能] 对精灵下达协同攻击指令。 - 消耗150精灵之魂 - 攻击时,精灵之魂 +10(冷却时间1秒) - 被击时,精灵之魂 -5(冷却时间1秒) - 元素释放伤害量:158200% - # rarity: 史诗 - suit_37(char) - pass - - -@register -def suit_39(char: CharacterProperty): - # DCALC_REMOVE: suit_39 - 贵族精灵 - # level: 3 - # value: 召唤精灵一起战斗。 [火灵安珀] 每2秒施放一次火花:伤害量19,200% 每3秒恢复1%的生命值 [水灵阿库娅] 每3秒施放一次水弹:伤害量24,000% 每3秒恢复1%的魔法值 [风灵希尔珂] 每2秒施放一次刀风:伤害量20,500% 移动速度 +15% [停止攻击开关][装备主动技能] 控制精灵们的攻击。 - 攻击中止/继续攻击 - 冷却时间1秒 [元素释放][装备主动技能] 对精灵下达协同攻击指令。 - 消耗150精灵之魂 - 攻击时,精灵之魂 +10(冷却时间1秒) - 被击时,精灵之魂 -5(冷却时间1秒) - 元素释放伤害量:158200% - # rarity: 史诗 - suit_37(char) - pass - - -@register -def suit_40(char: CharacterProperty): - # DCALC_REMOVE: suit_40 - 贵族精灵 - # level: 4 - # value: 召唤精灵一起战斗。 [火灵安珀] 每2秒施放一次火花:伤害量19,200% 每3秒恢复1%的生命值 [水灵阿库娅] 每3秒施放一次水弹:伤害量24,000% 每3秒恢复1%的魔法值 [风灵希尔珂] 每2秒施放一次刀风:伤害量20,500% 移动速度 +15% [停止攻击开关][装备主动技能] 控制精灵们的攻击。 - 攻击中止/继续攻击 - 冷却时间1秒 [元素释放][装备主动技能] 对精灵下达协同攻击指令。 - 消耗150精灵之魂 - 攻击时,精灵之魂 +10(冷却时间1秒) - 被击时,精灵之魂 -5(冷却时间1秒) - 元素释放伤害量:158200% - # rarity: 史诗 - suit_37(char) - pass - - -@register -def suit_41(char: CharacterProperty): - # DCALC_REMOVE: suit_41 - 贵族精灵 - # level: 5 - # value: 召唤精灵一起战斗。 [火灵安珀] 每2秒施放一次火花:伤害量19,200% 每3秒恢复1%的生命值 [水灵阿库娅] 每3秒施放一次水弹:伤害量24,000% 每3秒恢复1%的魔法值 [风灵希尔珂] 每2秒施放一次刀风:伤害量20,500% 移动速度 +15% [停止攻击开关][装备主动技能] 控制精灵们的攻击。 - 攻击中止/继续攻击 - 冷却时间1秒 [元素释放][装备主动技能] 对精灵下达协同攻击指令。 - 消耗150精灵之魂 - 攻击时,精灵之魂 +10(冷却时间1秒) - 被击时,精灵之魂 -5(冷却时间1秒) - 元素释放伤害量:158200% - # rarity: 史诗 - suit_37(char) - pass - - @register def suit_42(char: CharacterProperty): # DCALC_REMOVE: suit_42 - 皇室精灵 @@ -438,69 +130,13 @@ def suit_43(char: CharacterProperty): pass -@register -def suit_44(char: CharacterProperty): - # DCALC_REMOVE: suit_44 - 黄金乡 : 雏形 - # level: 2 - # value: - - # rarity: 稀有 - pass - - -@register -def suit_45(char: CharacterProperty): - # DCALC_REMOVE: suit_45 - 黄金乡 : 雏形 - # level: 3 - # value: - - # rarity: 稀有 - pass - - -@register -def suit_46(char: CharacterProperty): - # DCALC_REMOVE: suit_46 - 黄金乡 : 雏形 - # level: 4 - # value: - - # rarity: 稀有 - pass - - -@register -def suit_47(char: CharacterProperty): - # DCALC_REMOVE: suit_47 - 黄金乡 : 雏形 - # level: 5 - # value: - - # rarity: 稀有 - pass - - @register def suit_48(char: CharacterProperty): # DCALC_REMOVE: suit_48 - 黄金乡 : 构想 # level: 1 # value: 根据装备的强化/增幅数值,发动额外的能力。 根据防具/首饰/特殊装备的强化/增幅数值总和,适用以下效果。 - 数值总和每达到+11时,技能范围 +2% (最多叠加7次) - 防具:数值每达到+5,所受物理/魔法伤害 -1% (最多叠加7次) - 首饰:数值每达到+3,技能伤害 +1% (最多叠加7次) - 特殊装备:数值每达到+3,所有速度 +2% (最多叠加7次) # rarity: 神器 - reinforce_0 = 0 - """防具""" - reinforce_1 = 0 - """首饰""" - reinforce_2 = 0 - """特殊装备""" - reinforce_3 = 0 - """武器""" - for part in char.charEquipInfo.keys(): - if char.charEquipInfo[part] is None: - continue - num = char.charEquipInfo[part].reinforce - # if part == '武器': - # reinforce_3 += num - if part in ['上衣', '头肩', '下装', '腰带', '鞋']: - reinforce_0 += num - if part in ['手镯', '项链', '戒指']: - reinforce_1 += num - if part in ['耳环', '辅助装备', '魔法石']: - reinforce_2 += num - reinforce = reinforce_0 + reinforce_1 + reinforce_2 + reinforce_3 + reinforce, reinforce_0, reinforce_1, reinforce_2 = char.GetReinforceSum() char.SetStatus(SkillRange=0.02 * min(reinforce // 11, 7)) # char.SetStatus(DamageReduce=0.01 * min(reinforce_0 // 5, 7)) char.SetStatus(SkillAttack=0.01 * min(reinforce_1 // 3, 7)) @@ -510,73 +146,13 @@ def suit_48(char: CharacterProperty): pass -@register -def suit_49(char: CharacterProperty): - # DCALC_REMOVE: suit_49 - 黄金乡 : 构想 - # level: 2 - # value: 根据装备的强化/增幅数值,发动额外的能力。 根据防具/首饰/特殊装备的强化/增幅数值总和,适用以下效果。 - 数值总和每达到+11时,技能范围 +2% (最多叠加7次) - 防具:数值每达到+5,所受物理/魔法伤害 -1% (最多叠加7次) - 首饰:数值每达到+3,技能伤害 +1% (最多叠加7次) - 特殊装备:数值每达到+3,所有速度 +2% (最多叠加7次) - # rarity: 神器 - suit_48(char) - pass - - -@register -def suit_50(char: CharacterProperty): - # DCALC_REMOVE: suit_50 - 黄金乡 : 构想 - # level: 3 - # value: 根据装备的强化/增幅数值,发动额外的能力。 根据防具/首饰/特殊装备的强化/增幅数值总和,适用以下效果。 - 数值总和每达到+11时,技能范围 +2% (最多叠加7次) - 防具:数值每达到+5,所受物理/魔法伤害 -1% (最多叠加7次) - 首饰:数值每达到+3,技能伤害 +1% (最多叠加7次) - 特殊装备:数值每达到+3,所有速度 +2% (最多叠加7次) - # rarity: 神器 - suit_48(char) - pass - - -@register -def suit_51(char: CharacterProperty): - # DCALC_REMOVE: suit_51 - 黄金乡 : 构想 - # level: 4 - # value: 根据装备的强化/增幅数值,发动额外的能力。 根据防具/首饰/特殊装备的强化/增幅数值总和,适用以下效果。 - 数值总和每达到+11时,技能范围 +2% (最多叠加7次) - 防具:数值每达到+5,所受物理/魔法伤害 -1% (最多叠加7次) - 首饰:数值每达到+3,技能伤害 +1% (最多叠加7次) - 特殊装备:数值每达到+3,所有速度 +2% (最多叠加7次) - # rarity: 神器 - suit_48(char) - pass - - -@register -def suit_52(char: CharacterProperty): - # DCALC_REMOVE: suit_52 - 黄金乡 : 构想 - # level: 5 - # value: 根据装备的强化/增幅数值,发动额外的能力。 根据防具/首饰/特殊装备的强化/增幅数值总和,适用以下效果。 - 数值总和每达到+11时,技能范围 +2% (最多叠加7次) - 防具:数值每达到+5,所受物理/魔法伤害 -1% (最多叠加7次) - 首饰:数值每达到+3,技能伤害 +1% (最多叠加7次) - 特殊装备:数值每达到+3,所有速度 +2% (最多叠加7次) - # rarity: 神器 - suit_48(char) - pass - - @register def suit_53(char: CharacterProperty): # DCALC_REMOVE: suit_53 - 黄金乡 : 梦想成真 # level: 1 # value: 根据装备的强化/增幅数值,发动额外的能力。 根据防具/首饰/特殊装备的强化/增幅数值总和,适用以下效果。 - 数值总和每达到+11时,技能范围 +2% (最多叠加12次) - 防具:数值每达到+5,所受物理/魔法伤害 -1% (最多叠加12次) - 首饰:数值每达到+3,技能伤害 +1% (最多叠加12次) - 特殊装备:数值每达到+3,所有速度 +2% (最多叠加12次) # rarity: 传说 - reinforce_0 = 0 - """防具""" - reinforce_1 = 0 - """首饰""" - reinforce_2 = 0 - """特殊装备""" - reinforce_3 = 0 - """武器""" - for part in char.charEquipInfo.keys(): - if char.charEquipInfo[part] is None: - continue - num = char.charEquipInfo[part].reinforce - # if part == '武器': - # reinforce_3 += num - if part in ['上衣', '头肩', '下装', '腰带', '鞋']: - reinforce_0 += num - if part in ['手镯', '项链', '戒指']: - reinforce_1 += num - if part in ['耳环', '辅助装备', '魔法石']: - reinforce_2 += num - reinforce = reinforce_0 + reinforce_1 + reinforce_2 + reinforce_3 + reinforce, reinforce_0, reinforce_1, reinforce_2 = char.GetReinforceSum() char.SetStatus(SkillRange=0.02 * min(reinforce // 11, 12)) # char.SetStatus(DamageReduce=0.01 * min(reinforce_0 // 5, 7)) char.SetStatus(SkillAttack=0.01 * min(reinforce_1 // 3, 12)) @@ -589,73 +165,13 @@ def suit_53(char: CharacterProperty): pass -@register -def suit_54(char: CharacterProperty): - # DCALC_REMOVE: suit_54 - 黄金乡 : 梦想成真 - # level: 2 - # value: 根据装备的强化/增幅数值,发动额外的能力。 根据防具/首饰/特殊装备的强化/增幅数值总和,适用以下效果。 - 数值总和每达到+11时,技能范围 +2% (最多叠加12次) - 防具:数值每达到+5,所受物理/魔法伤害 -1% (最多叠加12次) - 首饰:数值每达到+3,技能伤害 +1% (最多叠加12次) - 特殊装备:数值每达到+3,所有速度 +2% (最多叠加12次) - # rarity: 传说 - suit_53(char) - pass - - -@register -def suit_55(char: CharacterProperty): - # DCALC_REMOVE: suit_55 - 黄金乡 : 梦想成真 - # level: 3 - # value: 根据装备的强化/增幅数值,发动额外的能力。 根据防具/首饰/特殊装备的强化/增幅数值总和,适用以下效果。 - 数值总和每达到+11时,技能范围 +2% (最多叠加12次) - 防具:数值每达到+5,所受物理/魔法伤害 -1% (最多叠加12次) - 首饰:数值每达到+3,技能伤害 +1% (最多叠加12次) - 特殊装备:数值每达到+3,所有速度 +2% (最多叠加12次) - # rarity: 传说 - suit_53(char) - pass - - -@register -def suit_56(char: CharacterProperty): - # DCALC_REMOVE: suit_56 - 黄金乡 : 梦想成真 - # level: 4 - # value: 根据装备的强化/增幅数值,发动额外的能力。 根据防具/首饰/特殊装备的强化/增幅数值总和,适用以下效果。 - 数值总和每达到+11时,技能范围 +2% (最多叠加12次) - 防具:数值每达到+5,所受物理/魔法伤害 -1% (最多叠加12次) - 首饰:数值每达到+3,技能伤害 +1% (最多叠加12次) - 特殊装备:数值每达到+3,所有速度 +2% (最多叠加12次) - # rarity: 传说 - suit_53(char) - pass - - -@register -def suit_57(char: CharacterProperty): - # DCALC_REMOVE: suit_57 - 黄金乡 : 梦想成真 - # level: 5 - # value: 根据装备的强化/增幅数值,发动额外的能力。 根据防具/首饰/特殊装备的强化/增幅数值总和,适用以下效果。 - 数值总和每达到+11时,技能范围 +2% (最多叠加12次) - 防具:数值每达到+5,所受物理/魔法伤害 -1% (最多叠加12次) - 首饰:数值每达到+3,技能伤害 +1% (最多叠加12次) - 特殊装备:数值每达到+3,所有速度 +2% (最多叠加12次) - # rarity: 传说 - suit_53(char) - pass - - @register def suit_58(char: CharacterProperty): # DCALC_REMOVE: suit_58 - 黄金乡 : 璀璨理想 # level: 1 # value: 根据装备的强化/增幅数值,发动额外的能力。 根据防具/首饰/特殊装备的强化/增幅数值总和,适用以下效果。 - 超过110时,每11点,技能伤害 +2%(最多叠加2次) - 数值总和每达到+11时,技能范围 +2% (最多叠加12次) - 防具:数值每达到+5,所受物理/魔法伤害-1% (最多叠加12次) - 首饰:数值每达到+3,技能伤害 +1% (最多叠加12次) - 特殊装备:数值每达到+3,所有速度 +2% (最多叠加12次) [淘银热] 根据防具/首饰/特殊装备的强化/增幅数值总和,降落相应数量的银币进行攻击(冷却时间10秒) * 银币伤害量信息 - 低于88:17000% - 88~109:18700% - 110~131:21250% - 132以上:25500% # rarity: 史诗 - reinforce_0 = 0 - """防具""" - reinforce_1 = 0 - """首饰""" - reinforce_2 = 0 - """特殊装备""" - reinforce_3 = 0 - """武器""" - for part in char.charEquipInfo.keys(): - if char.charEquipInfo is None: - continue - num = char.charEquipInfo[part].reinforce - # if part == '武器': - # reinforce_3 += num - if part in ['上衣', '头肩', '下装', '腰带', '鞋']: - reinforce_0 += num - if part in ['手镯', '项链', '戒指']: - reinforce_1 += num - if part in ['耳环', '辅助装备', '魔法石']: - reinforce_2 += num - reinforce = reinforce_0 + reinforce_1 + reinforce_2 + reinforce_3 + reinforce, reinforce_0, reinforce_1, reinforce_2 = char.GetReinforceSum() char.SetStatus(SkillRange=0.02 * min(reinforce // 11, 12)) # char.SetStatus(DamageReduce=0.01 * min(reinforce_0 // 5, 7)) char.SetStatus(SkillAttack=0.01 * min(reinforce_1 // 3, 12)) @@ -683,73 +199,13 @@ def suit_58(char: CharacterProperty): pass -@register -def suit_59(char: CharacterProperty): - # DCALC_REMOVE: suit_59 - 黄金乡 : 璀璨理想 - # level: 2 - # value: 根据装备的强化/增幅数值,发动额外的能力。 根据防具/首饰/特殊装备的强化/增幅数值总和,适用以下效果。 - 超过110时,每11点,技能伤害 +2%(最多叠加2次) - 数值总和每达到+11时,技能范围 +2% (最多叠加12次) - 防具:数值每达到+5,所受物理/魔法伤害-1% (最多叠加12次) - 首饰:数值每达到+3,技能伤害 +1% (最多叠加12次) - 特殊装备:数值每达到+3,所有速度 +2% (最多叠加12次) [淘银热] 根据防具/首饰/特殊装备的强化/增幅数值总和,降落相应数量的银币进行攻击(冷却时间10秒) * 银币伤害量信息 - 低于88:17000% - 88~109:18700% - 110~131:21250% - 132以上:25500% - # rarity: 史诗 - suit_58(char) - pass - - -@register -def suit_60(char: CharacterProperty): - # DCALC_REMOVE: suit_60 - 黄金乡 : 璀璨理想 - # level: 3 - # value: 根据装备的强化/增幅数值,发动额外的能力。 根据防具/首饰/特殊装备的强化/增幅数值总和,适用以下效果。 - 超过110时,每11点,技能伤害 +2%(最多叠加2次) - 数值总和每达到+11时,技能范围 +2% (最多叠加12次) - 防具:数值每达到+5,所受物理/魔法伤害-1% (最多叠加12次) - 首饰:数值每达到+3,技能伤害 +1% (最多叠加12次) - 特殊装备:数值每达到+3,所有速度 +2% (最多叠加12次) [淘银热] 根据防具/首饰/特殊装备的强化/增幅数值总和,降落相应数量的银币进行攻击(冷却时间10秒) * 银币伤害量信息 - 低于88:17000% - 88~109:18700% - 110~131:21250% - 132以上:25500% - # rarity: 史诗 - suit_58(char) - pass - - -@register -def suit_61(char: CharacterProperty): - # DCALC_REMOVE: suit_61 - 黄金乡 : 璀璨理想 - # level: 4 - # value: 根据装备的强化/增幅数值,发动额外的能力。 根据防具/首饰/特殊装备的强化/增幅数值总和,适用以下效果。 - 超过110时,每11点,技能伤害 +2%(最多叠加2次) - 数值总和每达到+11时,技能范围 +2% (最多叠加12次) - 防具:数值每达到+5,所受物理/魔法伤害-1% (最多叠加12次) - 首饰:数值每达到+3,技能伤害 +1% (最多叠加12次) - 特殊装备:数值每达到+3,所有速度 +2% (最多叠加12次) [淘银热] 根据防具/首饰/特殊装备的强化/增幅数值总和,降落相应数量的银币进行攻击(冷却时间10秒) * 银币伤害量信息 - 低于88:17000% - 88~109:18700% - 110~131:21250% - 132以上:25500% - # rarity: 史诗 - suit_58(char) - pass - - -@register -def suit_62(char: CharacterProperty): - # DCALC_REMOVE: suit_62 - 黄金乡 : 璀璨理想 - # level: 5 - # value: 根据装备的强化/增幅数值,发动额外的能力。 根据防具/首饰/特殊装备的强化/增幅数值总和,适用以下效果。 - 超过110时,每11点,技能伤害 +2%(最多叠加2次) - 数值总和每达到+11时,技能范围 +2% (最多叠加12次) - 防具:数值每达到+5,所受物理/魔法伤害-1% (最多叠加12次) - 首饰:数值每达到+3,技能伤害 +1% (最多叠加12次) - 特殊装备:数值每达到+3,所有速度 +2% (最多叠加12次) [淘银热] 根据防具/首饰/特殊装备的强化/增幅数值总和,降落相应数量的银币进行攻击(冷却时间10秒) * 银币伤害量信息 - 低于88:17000% - 88~109:18700% - 110~131:21250% - 132以上:25500% - # rarity: 史诗 - suit_58(char) - pass - - @register def suit_63(char: CharacterProperty): # DCALC_REMOVE: suit_63 - 黄金乡 : 永恒国度 # level: 1 # value: 根据装备的强化/增幅数值,发动额外的能力。 根据防具/首饰/特殊装备的强化/增幅数值总和,适用以下效果。 - 超过110时,每11点,技能伤害 +2%(最多叠加2次) - 数值总和每达到+11时,技能范围 +2% (最多叠加12次) - 防具:数值每达到+5,所受物理/魔法伤害 -1% (最多叠加12次) - 首饰:数值每达到+3,技能伤害 +1% (最多叠加12次) - 特殊装备:数值每达到+3,所有速度 +2%(最多叠加12次) [淘银热] 根据防具/首饰/特殊装备的强化/增幅数值总和,降落相应数量的银币进行攻击(冷却时间10秒) * 银币伤害量信息 - 低于88:17000% - 88~109:18700% - 110~131:21250% - 132以上:25500% [太初的记忆] 套装积分达到2550后,每增加70点套装积分,可以获得以下效果。 - 技能伤害 增加 1% - 增益量 +100 # rarity: 太初 - reinforce_0 = 0 - """防具""" - reinforce_1 = 0 - """首饰""" - reinforce_2 = 0 - """特殊装备""" - reinforce_3 = 0 - """武器""" - for part in char.charEquipInfo.keys(): - if char.charEquipInfo[part] is None: - continue - num = char.charEquipInfo[part].reinforce - # if part == '武器': - # reinforce_3 += num - if part in ['上衣', '头肩', '下装', '腰带', '鞋']: - reinforce_0 += num - if part in ['手镯', '项链', '戒指']: - reinforce_1 += num - if part in ['耳环', '辅助装备', '魔法石']: - reinforce_2 += num - reinforce = reinforce_0 + reinforce_1 + reinforce_2 + reinforce_3 + reinforce, reinforce_0, reinforce_1, reinforce_2 = char.GetReinforceSum() char.SetStatus(SkillRange=0.02 * min(reinforce // 11, 12)) # char.SetStatus(DamageReduce=0.01 * min(reinforce_0 // 5, 7)) char.SetStatus(SkillAttack=0.01 * min(reinforce_1 // 3, 12)) @@ -790,42 +246,6 @@ def suit_64(char: CharacterProperty): pass -@register -def suit_65(char: CharacterProperty): - # DCALC_REMOVE: suit_65 - 蒙昧未觉之螭龙 - # level: 2 - # value: - - # rarity: 稀有 - pass - - -@register -def suit_66(char: CharacterProperty): - # DCALC_REMOVE: suit_66 - 蒙昧未觉之螭龙 - # level: 3 - # value: - - # rarity: 稀有 - pass - - -@register -def suit_67(char: CharacterProperty): - # DCALC_REMOVE: suit_67 - 蒙昧未觉之螭龙 - # level: 4 - # value: - - # rarity: 稀有 - pass - - -@register -def suit_68(char: CharacterProperty): - # DCALC_REMOVE: suit_68 - 蒙昧未觉之螭龙 - # level: 5 - # value: - - # rarity: 稀有 - pass - - @register def suit_69(char: CharacterProperty): # DCALC_REMOVE: suit_69 - 鸿蒙初开之虬龙 @@ -836,46 +256,6 @@ def suit_69(char: CharacterProperty): pass -@register -def suit_70(char: CharacterProperty): - # DCALC_REMOVE: suit_70 - 鸿蒙初开之虬龙 - # level: 2 - # value: 通过释放龙之力来增强自己。 [虬龙之火] 无色小晶块消耗量减少1个。 - 不会减少到少于1个 所有速度 +10% - # rarity: 神器 - suit_69(char) - pass - - -@register -def suit_71(char: CharacterProperty): - # DCALC_REMOVE: suit_71 - 鸿蒙初开之虬龙 - # level: 3 - # value: 通过释放龙之力来增强自己。 [虬龙之火] 无色小晶块消耗量减少1个。 - 不会减少到少于1个 所有速度 +10% - # rarity: 神器 - suit_69(char) - pass - - -@register -def suit_72(char: CharacterProperty): - # DCALC_REMOVE: suit_72 - 鸿蒙初开之虬龙 - # level: 4 - # value: 通过释放龙之力来增强自己。 [虬龙之火] 无色小晶块消耗量减少1个。 - 不会减少到少于1个 所有速度 +10% - # rarity: 神器 - suit_69(char) - pass - - -@register -def suit_73(char: CharacterProperty): - # DCALC_REMOVE: suit_73 - 鸿蒙初开之虬龙 - # level: 5 - # value: 通过释放龙之力来增强自己。 [虬龙之火] 无色小晶块消耗量减少1个。 - 不会减少到少于1个 所有速度 +10% - # rarity: 神器 - suit_69(char) - pass - - @register def suit_74(char: CharacterProperty): # DCALC_REMOVE: suit_74 - 鸡鸣拂晓之蛟龙 @@ -887,46 +267,6 @@ def suit_74(char: CharacterProperty): pass -@register -def suit_75(char: CharacterProperty): - # DCALC_REMOVE: suit_75 - 鸡鸣拂晓之蛟龙 - # level: 2 - # value: 通过释放龙之力来增强自己。 [虬龙之火] 无色小晶块消耗量减少2个。 - 不会减少到少于1个 所有速度 +10% [蛟龙腾霄] 攻击时,蛟龙腾霄。 (冷却时间10秒) * 蛟龙腾霄伤害量:14,400% - # rarity: 传说 - suit_74(char) - pass - - -@register -def suit_76(char: CharacterProperty): - # DCALC_REMOVE: suit_76 - 鸡鸣拂晓之蛟龙 - # level: 3 - # value: 通过释放龙之力来增强自己。 [虬龙之火] 无色小晶块消耗量减少2个。 - 不会减少到少于1个 所有速度 +10% [蛟龙腾霄] 攻击时,蛟龙腾霄。 (冷却时间10秒) * 蛟龙腾霄伤害量:14,400% - # rarity: 传说 - suit_74(char) - pass - - -@register -def suit_77(char: CharacterProperty): - # DCALC_REMOVE: suit_77 - 鸡鸣拂晓之蛟龙 - # level: 4 - # value: 通过释放龙之力来增强自己。 [虬龙之火] 无色小晶块消耗量减少2个。 - 不会减少到少于1个 所有速度 +10% [蛟龙腾霄] 攻击时,蛟龙腾霄。 (冷却时间10秒) * 蛟龙腾霄伤害量:14,400% - # rarity: 传说 - suit_74(char) - pass - - -@register -def suit_78(char: CharacterProperty): - # DCALC_REMOVE: suit_78 - 鸡鸣拂晓之蛟龙 - # level: 5 - # value: 通过释放龙之力来增强自己。 [虬龙之火] 无色小晶块消耗量减少2个。 - 不会减少到少于1个 所有速度 +10% [蛟龙腾霄] 攻击时,蛟龙腾霄。 (冷却时间10秒) * 蛟龙腾霄伤害量:14,400% - # rarity: 传说 - suit_74(char) - pass - - @register def suit_79(char: CharacterProperty): # DCALC_REMOVE: suit_79 - 朝露晨辉之烛龙 @@ -948,46 +288,6 @@ def suit_79(char: CharacterProperty): pass -@register -def suit_80(char: CharacterProperty): - # DCALC_REMOVE: suit_80 - 朝露晨辉之烛龙 - # level: 2 - # value: 通过释放龙之力来增强自己。 [烛龙之火] 无色小晶块消耗量减少3个。 - 不会减少到少于1个 所有速度 +10% [烛龙腾霄] 攻击时,烛龙腾霄。(冷却时间10秒) * 烛龙腾霄伤害量:14,400% [荧惑如意珠][装备主动技能] 将[烛龙之火]变更为[烛龙的如意珠],效果持续30秒。 - 冷却时间60秒 [烛龙的如意珠] - 所有速度 +30% - 技能伤害 +3% - 无色小晶块技能的消耗量固定30个 - 施放消耗无色小晶块的技能时,发动白龙强袭(冷却时间3秒) * 白龙强袭伤害量:10980% - # rarity: 史诗 - suit_79(char) - pass - - -@register -def suit_81(char: CharacterProperty): - # DCALC_REMOVE: suit_81 - 朝露晨辉之烛龙 - # level: 3 - # value: 通过释放龙之力来增强自己。 [烛龙之火] 无色小晶块消耗量减少3个。 - 不会减少到少于1个 所有速度 +10% [烛龙腾霄] 攻击时,烛龙腾霄。(冷却时间10秒) * 烛龙腾霄伤害量:14,400% [荧惑如意珠][装备主动技能] 将[烛龙之火]变更为[烛龙的如意珠],效果持续30秒。 - 冷却时间60秒 [烛龙的如意珠] - 所有速度 +30% - 技能伤害 +3% - 无色小晶块技能的消耗量固定30个 - 施放消耗无色小晶块的技能时,发动白龙强袭(冷却时间3秒) * 白龙强袭伤害量:10980% - # rarity: 史诗 - suit_79(char) - pass - - -@register -def suit_82(char: CharacterProperty): - # DCALC_REMOVE: suit_82 - 朝露晨辉之烛龙 - # level: 4 - # value: 通过释放龙之力来增强自己。 [烛龙之火] 无色小晶块消耗量减少3个。 - 不会减少到少于1个 所有速度 +10% [烛龙腾霄] 攻击时,烛龙腾霄。(冷却时间10秒) * 烛龙腾霄伤害量:14,400% [荧惑如意珠][装备主动技能] 将[烛龙之火]变更为[烛龙的如意珠],效果持续30秒。 - 冷却时间60秒 [烛龙的如意珠] - 所有速度 +30% - 技能伤害 +3% - 无色小晶块技能的消耗量固定30个 - 施放消耗无色小晶块的技能时,发动白龙强袭(冷却时间3秒) * 白龙强袭伤害量:10980% - # rarity: 史诗 - suit_79(char) - pass - - -@register -def suit_83(char: CharacterProperty): - # DCALC_REMOVE: suit_83 - 朝露晨辉之烛龙 - # level: 5 - # value: 通过释放龙之力来增强自己。 [烛龙之火] 无色小晶块消耗量减少3个。 - 不会减少到少于1个 所有速度 +10% [烛龙腾霄] 攻击时,烛龙腾霄。(冷却时间10秒) * 烛龙腾霄伤害量:14,400% [荧惑如意珠][装备主动技能] 将[烛龙之火]变更为[烛龙的如意珠],效果持续30秒。 - 冷却时间60秒 [烛龙的如意珠] - 所有速度 +30% - 技能伤害 +3% - 无色小晶块技能的消耗量固定30个 - 施放消耗无色小晶块的技能时,发动白龙强袭(冷却时间3秒) * 白龙强袭伤害量:10980% - # rarity: 史诗 - suit_79(char) - pass - - @register def suit_84(char: CharacterProperty): # DCALC_REMOVE: suit_84 - 明光耀世之应龙 @@ -1019,42 +319,6 @@ def suit_85(char: CharacterProperty): pass -@register -def suit_86(char: CharacterProperty): - # DCALC_REMOVE: suit_86 - 混沌净化:初始 - # level: 2 - # value: - - # rarity: 稀有 - pass - - -@register -def suit_87(char: CharacterProperty): - # DCALC_REMOVE: suit_87 - 混沌净化:初始 - # level: 3 - # value: - - # rarity: 稀有 - pass - - -@register -def suit_88(char: CharacterProperty): - # DCALC_REMOVE: suit_88 - 混沌净化:初始 - # level: 4 - # value: - - # rarity: 稀有 - pass - - -@register -def suit_89(char: CharacterProperty): - # DCALC_REMOVE: suit_89 - 混沌净化:初始 - # level: 5 - # value: - - # rarity: 稀有 - pass - - @register def suit_90(char: CharacterProperty): # DCALC_REMOVE: suit_90 - 混沌净化:挣扎 @@ -1066,46 +330,6 @@ def suit_90(char: CharacterProperty): pass -@register -def suit_91(char: CharacterProperty): - # DCALC_REMOVE: suit_91 - 混沌净化:挣扎 - # level: 2 - # value: [净化] - 技能冷却时间 -30.0%(觉醒技能除外) - 特效伤害 +15% - 每秒恢复0.5%的生命值和魔法值 - # rarity: 神器 - suit_90(char) - pass - - -@register -def suit_92(char: CharacterProperty): - # DCALC_REMOVE: suit_92 - 混沌净化:挣扎 - # level: 3 - # value: [净化] - 技能冷却时间 -30.0%(觉醒技能除外) - 特效伤害 +15% - 每秒恢复0.5%的生命值和魔法值 - # rarity: 神器 - suit_90(char) - pass - - -@register -def suit_93(char: CharacterProperty): - # DCALC_REMOVE: suit_93 - 混沌净化:挣扎 - # level: 4 - # value: [净化] - 技能冷却时间 -30.0%(觉醒技能除外) - 特效伤害 +15% - 每秒恢复0.5%的生命值和魔法值 - # rarity: 神器 - suit_90(char) - pass - - -@register -def suit_94(char: CharacterProperty): - # DCALC_REMOVE: suit_94 - 混沌净化:挣扎 - # level: 5 - # value: [净化] - 技能冷却时间 -30.0%(觉醒技能除外) - 特效伤害 +15% - 每秒恢复0.5%的生命值和魔法值 - # rarity: 神器 - suit_90(char) - pass - - @register def suit_95(char: CharacterProperty): # DCALC_REMOVE: suit_95 - 混沌净化:失衡 @@ -1122,46 +346,6 @@ def suit_95(char: CharacterProperty): pass -@register -def suit_96(char: CharacterProperty): - # DCALC_REMOVE: suit_96 - 混沌净化:失衡 - # level: 2 - # value: [暗黑净化][装备主动技能] 根据使用者的意愿调整净化与堕落状态。 - 进入地下城时,净化状态自动生效 - 冷却时间:300秒 [净化] - 技能伤害 +17.5% - 技能冷却时间 -30%(觉醒技能除外) - 特效伤害 +15% - 每秒恢复0.5%的生命值和魔法值 [堕落] - 技能冷却时间 -55%(觉醒技能除外) - 特效伤害 +32.5% - 进入霸体状态 - # rarity: 传说 - suit_95(char) - pass - - -@register -def suit_97(char: CharacterProperty): - # DCALC_REMOVE: suit_97 - 混沌净化:失衡 - # level: 3 - # value: [暗黑净化][装备主动技能] 根据使用者的意愿调整净化与堕落状态。 - 进入地下城时,净化状态自动生效 - 冷却时间:300秒 [净化] - 技能伤害 +17.5% - 技能冷却时间 -30%(觉醒技能除外) - 特效伤害 +15% - 每秒恢复0.5%的生命值和魔法值 [堕落] - 技能冷却时间 -55%(觉醒技能除外) - 特效伤害 +32.5% - 进入霸体状态 - # rarity: 传说 - suit_95(char) - pass - - -@register -def suit_98(char: CharacterProperty): - # DCALC_REMOVE: suit_98 - 混沌净化:失衡 - # level: 4 - # value: [暗黑净化][装备主动技能] 根据使用者的意愿调整净化与堕落状态。 - 进入地下城时,净化状态自动生效 - 冷却时间:300秒 [净化] - 技能伤害 +17.5% - 技能冷却时间 -30%(觉醒技能除外) - 特效伤害 +15% - 每秒恢复0.5%的生命值和魔法值 [堕落] - 技能冷却时间 -55%(觉醒技能除外) - 特效伤害 +32.5% - 进入霸体状态 - # rarity: 传说 - suit_95(char) - pass - - -@register -def suit_99(char: CharacterProperty): - # DCALC_REMOVE: suit_99 - 混沌净化:失衡 - # level: 5 - # value: [暗黑净化][装备主动技能] 根据使用者的意愿调整净化与堕落状态。 - 进入地下城时,净化状态自动生效 - 冷却时间:300秒 [净化] - 技能伤害 +17.5% - 技能冷却时间 -30%(觉醒技能除外) - 特效伤害 +15% - 每秒恢复0.5%的生命值和魔法值 [堕落] - 技能冷却时间 -55%(觉醒技能除外) - 特效伤害 +32.5% - 进入霸体状态 - # rarity: 传说 - suit_95(char) - pass - - @register def suit_100(char: CharacterProperty): # DCALC_REMOVE: suit_100 - 混沌净化:协调 @@ -1172,46 +356,6 @@ def suit_100(char: CharacterProperty): pass -@register -def suit_101(char: CharacterProperty): - # DCALC_REMOVE: suit_101 - 混沌净化:协调 - # level: 2 - # value: [暗黑净化][装备主动技能] 根据使用者的意愿调整净化与堕落状态。 - 进入地下城时,净化状态自动生效 - 冷却时间:300秒 [净化] - 技能伤害 +17.5% - 技能冷却时间 -30%(觉醒技能除外) - 特效伤害 +15% - 每秒恢复0.5%的生命值和魔法值 - 每10秒生成最大生命值10%的保护罩 [堕落] - 技能冷却时间 -55%(觉醒技能除外) - 特效伤害 +32.5% - 进入霸体状态 - 跳跃时可以再跳跃一次 - # rarity: 史诗 - suit_95(char) - pass - - -@register -def suit_102(char: CharacterProperty): - # DCALC_REMOVE: suit_102 - 混沌净化:协调 - # level: 3 - # value: [暗黑净化][装备主动技能] 根据使用者的意愿调整净化与堕落状态。 - 进入地下城时,净化状态自动生效 - 冷却时间:300秒 [净化] - 技能伤害 +17.5% - 技能冷却时间 -30%(觉醒技能除外) - 特效伤害 +15% - 每秒恢复0.5%的生命值和魔法值 - 每10秒生成最大生命值10%的保护罩 [堕落] - 技能冷却时间 -55%(觉醒技能除外) - 特效伤害 +32.5% - 进入霸体状态 - 跳跃时可以再跳跃一次 - # rarity: 史诗 - suit_95(char) - pass - - -@register -def suit_103(char: CharacterProperty): - # DCALC_REMOVE: suit_103 - 混沌净化:协调 - # level: 4 - # value: [暗黑净化][装备主动技能] 根据使用者的意愿调整净化与堕落状态。 - 进入地下城时,净化状态自动生效 - 冷却时间:300秒 [净化] - 技能伤害 +17.5% - 技能冷却时间 -30%(觉醒技能除外) - 特效伤害 +15% - 每秒恢复0.5%的生命值和魔法值 - 每10秒生成最大生命值10%的保护罩 [堕落] - 技能冷却时间 -55%(觉醒技能除外) - 特效伤害 +32.5% - 进入霸体状态 - 跳跃时可以再跳跃一次 - # rarity: 史诗 - suit_95(char) - pass - - -@register -def suit_104(char: CharacterProperty): - # DCALC_REMOVE: suit_104 - 混沌净化:协调 - # level: 5 - # value: [暗黑净化][装备主动技能] 根据使用者的意愿调整净化与堕落状态。 - 进入地下城时,净化状态自动生效 - 冷却时间:300秒 [净化] - 技能伤害 +17.5% - 技能冷却时间 -30%(觉醒技能除外) - 特效伤害 +15% - 每秒恢复0.5%的生命值和魔法值 - 每10秒生成最大生命值10%的保护罩 [堕落] - 技能冷却时间 -55%(觉醒技能除外) - 特效伤害 +32.5% - 进入霸体状态 - 跳跃时可以再跳跃一次 - # rarity: 史诗 - suit_95(char) - pass - - @register def suit_105(char: CharacterProperty): # DCALC_REMOVE: suit_105 - 混沌净化:均衡 @@ -1235,42 +379,6 @@ def suit_106(char: CharacterProperty): pass -@register -def suit_107(char: CharacterProperty): - # DCALC_REMOVE: suit_107 - 天命者的微妙气运 - # level: 2 - # value: - - # rarity: 稀有 - pass - - -@register -def suit_108(char: CharacterProperty): - # DCALC_REMOVE: suit_108 - 天命者的微妙气运 - # level: 3 - # value: - - # rarity: 稀有 - pass - - -@register -def suit_109(char: CharacterProperty): - # DCALC_REMOVE: suit_109 - 天命者的微妙气运 - # level: 4 - # value: - - # rarity: 稀有 - pass - - -@register -def suit_110(char: CharacterProperty): - # DCALC_REMOVE: suit_110 - 天命者的微妙气运 - # level: 5 - # value: - - # rarity: 稀有 - pass - - @register def suit_111(char: CharacterProperty): # DCALC_REMOVE: suit_111 - 天命者的华丽气运 @@ -1282,46 +390,6 @@ def suit_111(char: CharacterProperty): pass -@register -def suit_112(char: CharacterProperty): - # DCALC_REMOVE: suit_112 - 天命者的华丽气运 - # level: 2 - # value: 幸运蝴蝶以一定几率初始化技能冷却时间,从而提供更多的技能使用机会。 [第一次幸运] - 技能伤害 +3% - 特效伤害 +3% [天命所归] - 攻击时,有1%几率发动以下效果。(发动机会冷却时间1秒) - 剩余冷却时间33秒以下的技能中,初始化剩余时间最长的1个技能(觉醒技能除外) - # rarity: 神器 - suit_111(char) - pass - - -@register -def suit_113(char: CharacterProperty): - # DCALC_REMOVE: suit_113 - 天命者的华丽气运 - # level: 3 - # value: 幸运蝴蝶以一定几率初始化技能冷却时间,从而提供更多的技能使用机会。 [第一次幸运] - 技能伤害 +3% - 特效伤害 +3% [天命所归] - 攻击时,有1%几率发动以下效果。(发动机会冷却时间1秒) - 剩余冷却时间33秒以下的技能中,初始化剩余时间最长的1个技能(觉醒技能除外) - # rarity: 神器 - suit_111(char) - pass - - -@register -def suit_114(char: CharacterProperty): - # DCALC_REMOVE: suit_114 - 天命者的华丽气运 - # level: 4 - # value: 幸运蝴蝶以一定几率初始化技能冷却时间,从而提供更多的技能使用机会。 [第一次幸运] - 技能伤害 +3% - 特效伤害 +3% [天命所归] - 攻击时,有1%几率发动以下效果。(发动机会冷却时间1秒) - 剩余冷却时间33秒以下的技能中,初始化剩余时间最长的1个技能(觉醒技能除外) - # rarity: 神器 - suit_111(char) - pass - - -@register -def suit_115(char: CharacterProperty): - # DCALC_REMOVE: suit_115 - 天命者的华丽气运 - # level: 5 - # value: 幸运蝴蝶以一定几率初始化技能冷却时间,从而提供更多的技能使用机会。 [第一次幸运] - 技能伤害 +3% - 特效伤害 +3% [天命所归] - 攻击时,有1%几率发动以下效果。(发动机会冷却时间1秒) - 剩余冷却时间33秒以下的技能中,初始化剩余时间最长的1个技能(觉醒技能除外) - # rarity: 神器 - suit_111(char) - pass - - @register def suit_116(char: CharacterProperty): # DCALC_REMOVE: suit_116 - 天命者的华丽气运 @@ -1329,54 +397,14 @@ def suit_116(char: CharacterProperty): # value: 幸运蝴蝶以一定几率初始化技能冷却时间,从而提供更多的技能使用机会。 [第一次幸运] - 技能伤害 +3% - 特效伤害 +4.5% [第二次幸运] - 攻击时,有3%的几率使所有属性强化 +33(持续时间33秒;发动机会冷却时间1秒) [天命所归] - 攻击时,有3%几率发动[天命所归]。(发动机会冷却时间1秒) - 剩余冷却时间33秒以下的技能中,初始化剩余时间最长的1个技能(觉醒技能除外) - 剩余冷却时间33秒以下的技能中,初始化剩余时间最短的1个技能(觉醒技能除外) - 立即发动[第二次幸运] # rarity: 传说 char.SetStatus(SkillAttack=0.03) - char.AddElementDB('火',33,1) - char.AddElementDB('冰',33,1) - char.AddElementDB('光',33,1) - char.AddElementDB('暗',33,1) + char.AddElementDB('火', 33, 1) + char.AddElementDB('冰', 33, 1) + char.AddElementDB('光', 33, 1) + char.AddElementDB('暗', 33, 1) char.SetStatus(EquEffectRatio=0.045) pass -@register -def suit_117(char: CharacterProperty): - # DCALC_REMOVE: suit_117 - 天命者的耀眼气运 - # level: 2 - # value: 幸运蝴蝶以一定几率初始化技能冷却时间,从而提供更多的技能使用机会。 [第一次幸运] - 技能伤害 +3% - 特效伤害 +4.5% [第二次幸运] - 攻击时,有3%的几率使所有属性强化 +33(持续时间33秒;发动机会冷却时间1秒) [天命所归] - 攻击时,有3%几率发动[天命所归]。(发动机会冷却时间1秒) - 剩余冷却时间33秒以下的技能中,初始化剩余时间最长的1个技能(觉醒技能除外) - 剩余冷却时间33秒以下的技能中,初始化剩余时间最短的1个技能(觉醒技能除外) - 立即发动[第二次幸运] - # rarity: 传说 - suit_116(char) - pass - - -@register -def suit_118(char: CharacterProperty): - # DCALC_REMOVE: suit_118 - 天命者的耀眼气运 - # level: 3 - # value: 幸运蝴蝶以一定几率初始化技能冷却时间,从而提供更多的技能使用机会。 [第一次幸运] - 技能伤害 +3% - 特效伤害 +4.5% [第二次幸运] - 攻击时,有3%的几率使所有属性强化 +33(持续时间33秒;发动机会冷却时间1秒) [天命所归] - 攻击时,有3%几率发动[天命所归]。(发动机会冷却时间1秒) - 剩余冷却时间33秒以下的技能中,初始化剩余时间最长的1个技能(觉醒技能除外) - 剩余冷却时间33秒以下的技能中,初始化剩余时间最短的1个技能(觉醒技能除外) - 立即发动[第二次幸运] - # rarity: 传说 - suit_116(char) - pass - - -@register -def suit_119(char: CharacterProperty): - # DCALC_REMOVE: suit_119 - 天命者的耀眼气运 - # level: 4 - # value: 幸运蝴蝶以一定几率初始化技能冷却时间,从而提供更多的技能使用机会。 [第一次幸运] - 技能伤害 +3% - 特效伤害 +4.5% [第二次幸运] - 攻击时,有3%的几率使所有属性强化 +33(持续时间33秒;发动机会冷却时间1秒) [天命所归] - 攻击时,有3%几率发动[天命所归]。(发动机会冷却时间1秒) - 剩余冷却时间33秒以下的技能中,初始化剩余时间最长的1个技能(觉醒技能除外) - 剩余冷却时间33秒以下的技能中,初始化剩余时间最短的1个技能(觉醒技能除外) - 立即发动[第二次幸运] - # rarity: 传说 - suit_116(char) - pass - - -@register -def suit_120(char: CharacterProperty): - # DCALC_REMOVE: suit_120 - 天命者的耀眼气运 - # level: 5 - # value: 幸运蝴蝶以一定几率初始化技能冷却时间,从而提供更多的技能使用机会。 [第一次幸运] - 技能伤害 +3% [第二次幸运] - 攻击时,有3%的几率使所有属性强化 +33(持续时间33秒;发动机会冷却时间1秒) [天命所归] - 攻击时,有3%几率发动[天命所归]。(发动机会冷却时间1秒) - 剩余冷却时间33秒以下的技能中,初始化剩余时间最长的1个技能(觉醒技能除外) - 剩余冷却时间33秒以下的技能中,初始化剩余时间最短的1个技能(觉醒技能除外) - 立即发动[第二次幸运] - # rarity: 传说 - suit_116(char) - pass - - @register def suit_121(char: CharacterProperty): # DCALC_REMOVE: suit_121 - 天命者的璀璨气运 @@ -1384,54 +412,14 @@ def suit_121(char: CharacterProperty): # value: 幸运蝴蝶以一定几率初始化技能冷却时间,从而提供更多的技能使用机会。 [第一次幸运] - 技能伤害 +3% - 特效伤害 +13.5% [第二次幸运] - 攻击时,有3%的几率使所有属性强化 +33(持续时间33秒;发动机会冷却时间1秒) [天命所归] - 攻击时,有3%几率发动[天命所归]。(发动机会冷却时间1秒) - 剩余冷却时间33秒以下的技能中,初始化剩余时间最长的1个技能(觉醒技能除外) - 剩余冷却时间33秒以下的技能中,初始化剩余时间最短的1个技能(觉醒技能除外) - 当技能冷却时间生效中的技能超过3个时,初始化剩余冷却时间超过33秒的所有技能(觉醒技能除外,冷却时间33秒) - 立即发动[第二次幸运] [幸运之翼][装备主动技能] - [第二次幸运]、[天命所归]发动几率提高3倍,效果持续33秒 - 立即发动[第二次幸运] - [幸运之翼]结束时发动[天命所归],33秒后可以再次使用 # rarity: 史诗 char.SetStatus(SkillAttack=0.03) - char.AddElementDB('火',33,1) - char.AddElementDB('冰',33,1) - char.AddElementDB('光',33,1) - char.AddElementDB('暗',33,1) + char.AddElementDB('火', 33, 1) + char.AddElementDB('冰', 33, 1) + char.AddElementDB('光', 33, 1) + char.AddElementDB('暗', 33, 1) char.SetStatus(EquEffectRatio=0.135) pass -@register -def suit_122(char: CharacterProperty): - # DCALC_REMOVE: suit_122 - 天命者的璀璨气运 - # level: 2 - # value: 幸运蝴蝶以一定几率初始化技能冷却时间,从而提供更多的技能使用机会。 [第一次幸运] - 技能伤害 +3% - 特效伤害 +13.5% [第二次幸运] - 攻击时,有3%的几率使所有属性强化 +33(持续时间33秒;发动机会冷却时间1秒) [天命所归] - 攻击时,有3%几率发动[天命所归]。(发动机会冷却时间1秒) - 剩余冷却时间33秒以下的技能中,初始化剩余时间最长的1个技能(觉醒技能除外) - 剩余冷却时间33秒以下的技能中,初始化剩余时间最短的1个技能(觉醒技能除外) - 当技能冷却时间生效中的技能超过3个时,初始化剩余冷却时间超过33秒的所有技能(觉醒技能除外,冷却时间33秒) - 立即发动[第二次幸运] [幸运之翼][装备主动技能] - [第二次幸运]、[天命所归]发动几率提高3倍,效果持续33秒 - 立即发动[第二次幸运] - [幸运之翼]结束时发动[天命所归],33秒后可以再次使用 - # rarity: 史诗 - suit_121(char) - pass - - -@register -def suit_123(char: CharacterProperty): - # DCALC_REMOVE: suit_123 - 天命者的璀璨气运 - # level: 3 - # value: 幸运蝴蝶以一定几率初始化技能冷却时间,从而提供更多的技能使用机会。 [第一次幸运] - 技能伤害 +3% - 特效伤害 +13.5% [第二次幸运] - 攻击时,有3%的几率使所有属性强化 +33(持续时间33秒;发动机会冷却时间1秒) [天命所归] - 攻击时,有3%几率发动[天命所归]。(发动机会冷却时间1秒) - 剩余冷却时间33秒以下的技能中,初始化剩余时间最长的1个技能(觉醒技能除外) - 剩余冷却时间33秒以下的技能中,初始化剩余时间最短的1个技能(觉醒技能除外) - 当技能冷却时间生效中的技能超过3个时,初始化剩余冷却时间超过33秒的所有技能(觉醒技能除外,冷却时间33秒) - 立即发动[第二次幸运] [幸运之翼][装备主动技能] - [第二次幸运]、[天命所归]发动几率提高3倍,效果持续33秒 - 立即发动[第二次幸运] - [幸运之翼]结束时发动[天命所归],33秒后可以再次使用 - # rarity: 史诗 - suit_121(char) - pass - - -@register -def suit_124(char: CharacterProperty): - # DCALC_REMOVE: suit_124 - 天命者的璀璨气运 - # level: 4 - # value: 幸运蝴蝶以一定几率初始化技能冷却时间,从而提供更多的技能使用机会。 [第一次幸运] - 技能伤害 +3% - 特效伤害 +13.5% [第二次幸运] - 攻击时,有3%的几率使所有属性强化 +33(持续时间33秒;发动机会冷却时间1秒) [天命所归] - 攻击时,有3%几率发动[天命所归]。(发动机会冷却时间1秒) - 剩余冷却时间33秒以下的技能中,初始化剩余时间最长的1个技能(觉醒技能除外) - 剩余冷却时间33秒以下的技能中,初始化剩余时间最短的1个技能(觉醒技能除外) - 当技能冷却时间生效中的技能超过3个时,初始化剩余冷却时间超过33秒的所有技能(觉醒技能除外,冷却时间33秒) - 立即发动[第二次幸运] [幸运之翼][装备主动技能] - [第二次幸运]、[天命所归]发动几率提高3倍,效果持续33秒 - 立即发动[第二次幸运] - [幸运之翼]结束时发动[天命所归],33秒后可以再次使用 - # rarity: 史诗 - suit_121(char) - pass - - -@register -def suit_125(char: CharacterProperty): - # DCALC_REMOVE: suit_125 - 天命者的璀璨气运 - # level: 5 - # value: 幸运蝴蝶以一定几率初始化技能冷却时间,从而提供更多的技能使用机会。 [第一次幸运] - 技能伤害 +3% - 特效伤害 +13.5% [第二次幸运] - 攻击时,有3%的几率使所有属性强化 +33(持续时间33秒;发动机会冷却时间1秒) [天命所归] - 攻击时,有3%几率发动[天命所归]。(发动机会冷却时间1秒) - 剩余冷却时间33秒以下的技能中,初始化剩余时间最长的1个技能(觉醒技能除外) - 剩余冷却时间33秒以下的技能中,初始化剩余时间最短的1个技能(觉醒技能除外) - 当技能冷却时间生效中的技能超过3个时,初始化剩余冷却时间超过33秒的所有技能(觉醒技能除外,冷却时间33秒) - 立即发动[第二次幸运] [幸运之翼][装备主动技能] - [第二次幸运]、[天命所归]发动几率提高3倍,效果持续33秒 - 立即发动[第二次幸运] - [幸运之翼]结束时发动[天命所归],33秒后可以再次使用 - # rarity: 史诗 - suit_121(char) - pass - - @register def suit_126(char: CharacterProperty): # DCALC_REMOVE: suit_126 - 天命者的梦幻气运 @@ -1439,10 +427,10 @@ def suit_126(char: CharacterProperty): # value: 幸运蝴蝶以一定几率初始化技能冷却时间,从而提供更多的技能使用机会。 [第一次幸运] - 技能伤害 +3% - 特效伤害 +19% [第二次幸运] - 攻击时,有3%的几率使所有属性强化 +33(持续时间33秒;发动机会冷却时间1秒) [天命所归] - 攻击时,有3%几率发动[天命所归]。(发动机会冷却时间1秒) - 剩余冷却时间33秒以下的技能中,初始化剩余时间最长的1个技能(觉醒技能除外) - 剩余冷却时间33秒以下的技能中,初始化剩余时间最短的1个技能(觉醒技能除外) - 存在3个以上冷却中的技能时,初始化剩余冷却时间超过33秒的所有技能(觉醒技能除外,冷却时间33秒) - 立即发动[第二次幸运] [幸运之翼][装备主动技能] - 立即发动[第二次幸运] - [第二次幸运]、[天命所归]发动几率提高3倍,效果持续33秒 - [幸运之翼]结束时,发动[天命所归],可33秒后可以再次施放。 [太初的记忆] 套装积分达到2550后,每增加70点套装积分,可以获得以下效果。 - 技能伤害 增加 1% - 增益量 +100 # rarity: 太初 char.SetStatus(SkillAttack=0.03) - char.AddElementDB('火',33,1) - char.AddElementDB('冰',33,1) - char.AddElementDB('光',33,1) - char.AddElementDB('暗',33,1) + char.AddElementDB('火', 33, 1) + char.AddElementDB('冰', 33, 1) + char.AddElementDB('光', 33, 1) + char.AddElementDB('暗', 33, 1) char.SetStatus(EquEffectRatio=0.19) pass @@ -1460,42 +448,6 @@ def suit_127(char: CharacterProperty): pass -@register -def suit_128(char: CharacterProperty): - # DCALC_REMOVE: suit_128 - 最初的能量 - # level: 2 - # value: - - # rarity: 稀有 - pass - - -@register -def suit_129(char: CharacterProperty): - # DCALC_REMOVE: suit_129 - 最初的能量 - # level: 3 - # value: - - # rarity: 稀有 - pass - - -@register -def suit_130(char: CharacterProperty): - # DCALC_REMOVE: suit_130 - 最初的能量 - # level: 4 - # value: - - # rarity: 稀有 - pass - - -@register -def suit_131(char: CharacterProperty): - # DCALC_REMOVE: suit_131 - 最初的能量 - # level: 5 - # value: - - # rarity: 稀有 - pass - - @register def suit_132(char: CharacterProperty): # DCALC_REMOVE: suit_132 - 涌动的能量 @@ -1503,54 +455,14 @@ def suit_132(char: CharacterProperty): # value: 觉醒技能发挥出超越极限的破坏力。 [限制器解除] - 解除觉醒技能关联 - 100级技能攻击力 +30% - 85级技能攻击力 +30% - 85级技能冷却时间 -30% - 50级技能冷却时间 -30% - 特效伤害 +13% * 组队时,辅助职业不适用解除觉醒技能关联、减少技能冷却时间的属性 # rarity: 神器 if not char.buffer: - char.SetSkillCD(50,50,0.3,[]) - char.SetSkillCD(85,85,0.3,[]) - char.SetSkillRation(100,100,0.3) - char.SetSkillRation(85,85,0.3) + char.SetSkillCD(50, 50, 0.3, []) + char.SetSkillCD(85, 85, 0.3, []) + char.SetSkillRation(100, 100, 0.3) + char.SetSkillRation(85, 85, 0.3) char.SetStatus(EquEffectRatio=0.13) pass -@register -def suit_133(char: CharacterProperty): - # DCALC_REMOVE: suit_133 - 涌动的能量 - # level: 2 - # value: 觉醒技能发挥出超越极限的破坏力。 [限制器解除] - 解除觉醒技能关联 - 100级技能攻击力 +30% - 85级技能攻击力 +30% - 85级技能冷却时间 -30% - 50级技能冷却时间 -30% - 特效伤害 +13% * 组队时,辅助职业不适用解除觉醒技能关联、减少技能冷却时间的属性 - # rarity: 神器 - suit_132(char) - pass - - -@register -def suit_134(char: CharacterProperty): - # DCALC_REMOVE: suit_134 - 涌动的能量 - # level: 3 - # value: 觉醒技能发挥出超越极限的破坏力。 [限制器解除] - 解除觉醒技能关联 - 100级技能攻击力 +30% - 85级技能攻击力 +30% - 85级技能冷却时间 -30% - 50级技能冷却时间 -30% - 特效伤害 +13% * 组队时,辅助职业不适用解除觉醒技能关联、减少技能冷却时间的属性 - # rarity: 神器 - suit_132(char) - pass - - -@register -def suit_135(char: CharacterProperty): - # DCALC_REMOVE: suit_135 - 涌动的能量 - # level: 4 - # value: 觉醒技能发挥出超越极限的破坏力。 [限制器解除] - 解除觉醒技能关联 - 100级技能攻击力 +30% - 85级技能攻击力 +30% - 85级技能冷却时间 -30% - 50级技能冷却时间 -30% - 特效伤害 +13% * 组队时,辅助职业不适用解除觉醒技能关联、减少技能冷却时间的属性 - # rarity: 神器 - suit_132(char) - pass - - -@register -def suit_136(char: CharacterProperty): - # DCALC_REMOVE: suit_136 - 涌动的能量 - # level: 5 - # value: 觉醒技能发挥出超越极限的破坏力。 [限制器解除] - 解除觉醒技能关联 - 100级技能攻击力 +30% - 85级技能攻击力 +30% - 85级技能冷却时间 -30% - 50级技能冷却时间 -30% - 特效伤害 +13% * 组队时,辅助职业不适用解除觉醒技能关联、减少技能冷却时间的属性 - # rarity: 神器 - suit_132(char) - pass - - @register def suit_137(char: CharacterProperty): # DCALC_REMOVE: suit_137 - 满溢的能量 @@ -1558,55 +470,15 @@ def suit_137(char: CharacterProperty): # value: 觉醒技能发挥出超越极限的破坏力。 [限制器解除] - 解除觉醒技能关联 - 100级技能攻击力 +40% - 85级技能攻击力 +40% - 100级技能冷却时间 -50% - 85级技能冷却时间 -40%- 50级技能冷却时间 -50% - 特效伤害 +16.5% * 组队时,辅助职业不适用解除觉醒技能关联、减少技能冷却时间的属性 [能量护盾] 施放50、85级技能时,发动以下效果。 - 获得生命值最大值5%的保护罩(最多10%),持续30秒 - 拥有保护罩时每秒恢复1%的魔法值 - 相同技能间存在30秒冷却时间 # rarity: 传说 if not char.buffer: - char.SetSkillCD(50,50,0.5,[]) - char.SetSkillCD(85,85,0.4,[]) - char.SetSkillCD(100,100,0.5,[]) - char.SetSkillRation(100,100,0.4) - char.SetSkillRation(85,85,0.4) + char.SetSkillCD(50, 50, 0.5, []) + char.SetSkillCD(85, 85, 0.4, []) + char.SetSkillCD(100, 100, 0.5, []) + char.SetSkillRation(100, 100, 0.4) + char.SetSkillRation(85, 85, 0.4) char.SetStatus(EquEffectRatio=0.165) pass -@register -def suit_138(char: CharacterProperty): - # DCALC_REMOVE: suit_138 - 满溢的能量 - # level: 2 - # value: 觉醒技能发挥出超越极限的破坏力。 [限制器解除] - 解除觉醒技能关联 - 100级技能攻击力 +40% - 85级技能攻击力 +40% - 100级技能冷却时间 -50% - 85级技能冷却时间 -40%- 50级技能冷却时间 -50% - 特效伤害 +16.5% * 组队时,辅助职业不适用解除觉醒技能关联、减少技能冷却时间的属性 [能量护盾] 施放50、85级技能时,发动以下效果。 - 获得生命值最大值5%的保护罩(最多10%),持续30秒 - 拥有保护罩时每秒恢复1%的魔法值 - 相同技能间存在30秒冷却时间 - # rarity: 传说 - suit_137(char) - pass - - -@register -def suit_139(char: CharacterProperty): - # DCALC_REMOVE: suit_139 - 满溢的能量 - # level: 3 - # value: 觉醒技能发挥出超越极限的破坏力。 [限制器解除] - 解除觉醒技能关联 - 100级技能攻击力 +40% - 85级技能攻击力 +40% - 100级技能冷却时间 -50% - 85级技能冷却时间 -40%- 50级技能冷却时间 -50% - 特效伤害 +16.5% * 组队时,辅助职业不适用解除觉醒技能关联、减少技能冷却时间的属性 [能量护盾] 施放50、85级技能时,发动以下效果。 - 获得生命值最大值5%的保护罩(最多10%),持续30秒 - 拥有保护罩时每秒恢复1%的魔法值 - 相同技能间存在30秒冷却时间 - # rarity: 传说 - suit_137(char) - pass - - -@register -def suit_140(char: CharacterProperty): - # DCALC_REMOVE: suit_140 - 满溢的能量 - # level: 4 - # value: 觉醒技能发挥出超越极限的破坏力。 [限制器解除] - 解除觉醒技能关联 - 100级技能攻击力 +40% - 85级技能攻击力 +40% - 100级技能冷却时间 -50% - 85级技能冷却时间 -40%- 50级技能冷却时间 -50% - 特效伤害 +16.5% * 组队时,辅助职业不适用解除觉醒技能关联、减少技能冷却时间的属性 [能量护盾] 施放50、85级技能时,发动以下效果。 - 获得生命值最大值5%的保护罩(最多10%),持续30秒 - 拥有保护罩时每秒恢复1%的魔法值 - 相同技能间存在30秒冷却时间 - # rarity: 传说 - suit_137(char) - pass - - -@register -def suit_141(char: CharacterProperty): - # DCALC_REMOVE: suit_141 - 满溢的能量 - # level: 5 - # value: 觉醒技能发挥出超越极限的破坏力。 [限制器解除] - 解除觉醒技能关联 - 100级技能攻击力 +40% - 85级技能攻击力 +40% - 100级技能冷却时间 -50% - 85级技能冷却时间 -40%- 50级技能冷却时间 -50% - 特效伤害 +16.5% * 组队时,辅助职业不适用解除觉醒技能关联、减少技能冷却时间的属性 [能量护盾] 施放50、85级技能时,发动以下效果。 - 获得生命值最大值5%的保护罩(最多10%),持续30秒 - 拥有保护罩时每秒恢复1%的魔法值 - 相同技能间存在30秒冷却时间 - # rarity: 传说 - suit_137(char) - pass - - @register def suit_142(char: CharacterProperty): # DCALC_REMOVE: suit_142 - 极限的能量 @@ -1614,12 +486,12 @@ def suit_142(char: CharacterProperty): # value: 觉醒技能发挥出超越极限的破坏力。 [限制器解除] - 解除觉醒技能关联 - 100级技能攻击力 +60% - 85级技能攻击力 +50%- 50级技能攻击力 +10% - 100级技能冷却时间 -60% - 85级技能冷却时间 -50%- 50级技能冷却时间 -70% - 特效伤害 +23% * 组队时,辅助职业不适用解除觉醒技能关联、减少技能冷却时间的属性 [抵达极限的能量] 施放[三觉技能]时,合算[抵达极限的能量]。 - 能量释放伤害量:331000% - 该伤害量为特效伤害 [能量护盾] 施放50、85级技能时,发动以下效果。 - 获得生命值最大值10%的保护罩(最多20%),持续30秒 - 拥有保护罩时每秒恢复1%的魔法值 - 相同技能间存在30秒冷却时间 # rarity: 史诗 if not char.buffer: - char.SetSkillCD(50,50,0.7,[]) - char.SetSkillCD(85,85,0.5,[]) - char.SetSkillCD(100,100,0.6,[]) - char.SetSkillRation(100,100,0.6) - char.SetSkillRation(85,85,0.5) - char.SetSkillRation(50,50,0.1) + char.SetSkillCD(50, 50, 0.7, []) + char.SetSkillCD(85, 85, 0.5, []) + char.SetSkillCD(100, 100, 0.6, []) + char.SetSkillRation(100, 100, 0.6) + char.SetSkillRation(85, 85, 0.5) + char.SetSkillRation(50, 50, 0.1) char.SetStatus(EquEffectRatio=0.23) cd = 0 for item in char.skills: @@ -1629,46 +501,6 @@ def suit_142(char: CharacterProperty): pass -@register -def suit_143(char: CharacterProperty): - # DCALC_REMOVE: suit_143 - 极限的能量 - # level: 2 - # value: 觉醒技能发挥出超越极限的破坏力。 [限制器解除] - 解除觉醒技能关联 - 100级技能攻击力 +60% - 85级技能攻击力 +50%- 50级技能攻击力 +10% - 100级技能冷却时间 -60% - 85级技能冷却时间 -50%- 50级技能冷却时间 -70% - 特效伤害 +23% * 组队时,辅助职业不适用解除觉醒技能关联、减少技能冷却时间的属性 [抵达极限的能量] 施放[三觉技能]时,合算[抵达极限的能量]。 - 能量释放伤害量:331000% - 该伤害量为特效伤害 [能量护盾] 施放50、85级技能时,发动以下效果。 - 获得生命值最大值10%的保护罩(最多20%),持续30秒 - 拥有保护罩时每秒恢复1%的魔法值 - 相同技能间存在30秒冷却时间 - # rarity: 史诗 - suit_142(char) - pass - - -@register -def suit_144(char: CharacterProperty): - # DCALC_REMOVE: suit_144 - 极限的能量 - # level: 3 - # value: 觉醒技能发挥出超越极限的破坏力。 [限制器解除] - 解除觉醒技能关联 - 100级技能攻击力 +60% - 85级技能攻击力 +50%- 50级技能攻击力 +10% - 100级技能冷却时间 -60% - 85级技能冷却时间 -50%- 50级技能冷却时间 -70% - 特效伤害 +23% * 组队时,辅助职业不适用解除觉醒技能关联、减少技能冷却时间的属性 [抵达极限的能量] 施放[三觉技能]时,合算[抵达极限的能量]。 - 能量释放伤害量:331000% - 该伤害量为特效伤害 [能量护盾] 施放50、85级技能时,发动以下效果。 - 获得生命值最大值10%的保护罩(最多20%),持续30秒 - 拥有保护罩时每秒恢复1%的魔法值 - 相同技能间存在30秒冷却时间 - # rarity: 史诗 - suit_142(char) - pass - - -@register -def suit_145(char: CharacterProperty): - # DCALC_REMOVE: suit_145 - 极限的能量 - # level: 4 - # value: 觉醒技能发挥出超越极限的破坏力。 [限制器解除] - 解除觉醒技能关联 - 100级技能攻击力 +60% - 85级技能攻击力 +50%- 50级技能攻击力 +10% - 100级技能冷却时间 -60% - 85级技能冷却时间 -50%- 50级技能冷却时间 -70% - 特效伤害 +23% * 组队时,辅助职业不适用解除觉醒技能关联、减少技能冷却时间的属性 [抵达极限的能量] 施放[三觉技能]时,合算[抵达极限的能量]。 - 能量释放伤害量:331000% - 该伤害量为特效伤害 [能量护盾] 施放50、85级技能时,发动以下效果。 - 获得生命值最大值10%的保护罩(最多20%),持续30秒 - 拥有保护罩时每秒恢复1%的魔法值 - 相同技能间存在30秒冷却时间 - # rarity: 史诗 - suit_142(char) - pass - - -@register -def suit_146(char: CharacterProperty): - # DCALC_REMOVE: suit_146 - 极限的能量 - # level: 5 - # value: 觉醒技能发挥出超越极限的破坏力。 [限制器解除] - 解除觉醒技能关联 - 100级技能攻击力 +60% - 85级技能攻击力 +50%- 50级技能攻击力 +10% - 100级技能冷却时间 -60% - 85级技能冷却时间 -50%- 50级技能冷却时间 -70% - 特效伤害 +23% * 组队时,辅助职业不适用解除觉醒技能关联、减少技能冷却时间的属性 [抵达极限的能量] 施放[三觉技能]时,合算[抵达极限的能量]。 - 能量释放伤害量:331000% - 该伤害量为特效伤害 [能量护盾] 施放50、85级技能时,发动以下效果。 - 获得生命值最大值10%的保护罩(最多20%),持续30秒 - 拥有保护罩时每秒恢复1%的魔法值 - 相同技能间存在30秒冷却时间 - # rarity: 史诗 - suit_142(char) - pass - - @register def suit_147(char: CharacterProperty): # DCALC_REMOVE: suit_147 - 超越极限的能量 @@ -1676,12 +508,12 @@ def suit_147(char: CharacterProperty): # value: 觉醒技能发挥出超越极限的破坏力。 [限制器解除] - 解除觉醒技能关联 - 100级技能攻击力 +76% - 85级技能攻击力 +60%- 50级技能攻击力 +15% - 100级技能冷却时间 -60% - 85级技能冷却时间 -60%- 50级技能冷却时间 -70% - 特效伤害 +27.5% * 组队时,辅助职业不适用解除觉醒技能关联、减少技能冷却时间的属性 [冲破极限] 施放[三觉技能]时,合算[冲破极限]。 - 能量释放伤害量:480000% - 该伤害量为特效伤害 [能量护盾] 施放50、85级技能时,发动以下效果。 - 获得生命值最大值15%的保护罩(最多30%),持续30秒 - 拥有保护罩时每秒恢复1%的魔法值 - 拥有保护罩时所有速度 +10% - 相同技能间存在30秒冷却时间 [太初的记忆] 套装积分达到2550后,每增加70点套装积分,可以获得以下效果。 - 技能伤害 增加 1% - 增益量 +100 # rarity: 太初 if not char.buffer: - char.SetSkillCD(50,50,0.7,[]) - char.SetSkillCD(85,85,0.6,[]) - char.SetSkillCD(100,100,0.6,[]) - char.SetSkillRation(100,100,0.76) - char.SetSkillRation(85,85,0.6) - char.SetSkillRation(50,50,0.15) + char.SetSkillCD(50, 50, 0.7, []) + char.SetSkillCD(85, 85, 0.6, []) + char.SetSkillCD(100, 100, 0.6, []) + char.SetSkillRation(100, 100, 0.76) + char.SetSkillRation(85, 85, 0.6) + char.SetSkillRation(50, 50, 0.15) char.SetStatus(EquEffectRatio=0.275) cd = 0 for item in char.skills: @@ -1704,42 +536,6 @@ def suit_148(char: CharacterProperty): pass -@register -def suit_149(char: CharacterProperty): - # DCALC_REMOVE: suit_149 - 自然的造化 - # level: 2 - # value: - - # rarity: 稀有 - pass - - -@register -def suit_150(char: CharacterProperty): - # DCALC_REMOVE: suit_150 - 自然的造化 - # level: 3 - # value: - - # rarity: 稀有 - pass - - -@register -def suit_151(char: CharacterProperty): - # DCALC_REMOVE: suit_151 - 自然的造化 - # level: 4 - # value: - - # rarity: 稀有 - pass - - -@register -def suit_152(char: CharacterProperty): - # DCALC_REMOVE: suit_152 - 自然的造化 - # level: 5 - # value: - - # rarity: 稀有 - pass - - @register def suit_153(char: CharacterProperty): # DCALC_REMOVE: suit_153 - 自然的干预 @@ -1750,46 +546,6 @@ def suit_153(char: CharacterProperty): pass -@register -def suit_154(char: CharacterProperty): - # DCALC_REMOVE: suit_154 - 自然的干预 - # level: 2 - # value: 利用无可违背的自然之力,对敌人造成巨大伤害。 [无可违背的自然 - 干预] 攻击时引发自然爆炸攻击敌人。 (冷却时间5秒) - 自然燃烧伤害12750% - # rarity: 神器 - char.equ_effect.append(EquEffect(name='自燃爆炸', icon='/equipment/suit/6.png', cd=5, data=12750)) - pass - - -@register -def suit_155(char: CharacterProperty): - # DCALC_REMOVE: suit_155 - 自然的干预 - # level: 3 - # value: 利用无可违背的自然之力,对敌人造成巨大伤害。 [无可违背的自然 - 干预] 攻击时引发自然爆炸攻击敌人。 (冷却时间5秒) - 自然燃烧伤害12750% - # rarity: 神器 - suit_154(char) - pass - - -@register -def suit_156(char: CharacterProperty): - # DCALC_REMOVE: suit_156 - 自然的干预 - # level: 4 - # value: 利用无可违背的自然之力,对敌人造成巨大伤害。 [无可违背的自然 - 干预] 攻击时引发自然爆炸攻击敌人。 (冷却时间5秒) - 自然燃烧伤害12750% - # rarity: 神器 - suit_154(char) - pass - - -@register -def suit_157(char: CharacterProperty): - # DCALC_REMOVE: suit_157 - 自然的干预 - # level: 5 - # value: 利用无可违背的自然之力,对敌人造成巨大伤害。 [无可违背的自然 - 干预] 攻击时引发自然爆炸攻击敌人。 (冷却时间5秒) - 自然燃烧伤害12750% - # rarity: 神器 - suit_154(char) - pass - - @register def suit_158(char: CharacterProperty): # DCALC_REMOVE: suit_158 - 自然的震怒 @@ -1800,46 +556,6 @@ def suit_158(char: CharacterProperty): pass -@register -def suit_159(char: CharacterProperty): - # DCALC_REMOVE: suit_159 - 自然的震怒 - # level: 2 - # value: 利用无可违背的自然之力,对敌人造成巨大伤害。 所有速度 +5% [无可违背的自然 - 干预] 攻击时产生小型旋风,攻击小范围的敌人,并吸附敌人。 (冷却时间5秒) - 小型旋风伤害33300% - # rarity: 传说 - suit_158(char) - pass - - -@register -def suit_160(char: CharacterProperty): - # DCALC_REMOVE: suit_160 - 自然的震怒 - # level: 3 - # value: 利用无可违背的自然之力,对敌人造成巨大伤害。 所有速度 +5% [无可违背的自然 - 干预] 攻击时产生小型旋风,攻击小范围的敌人,并吸附敌人。 (冷却时间5秒) - 小型旋风伤害33300% - # rarity: 传说 - suit_158(char) - pass - - -@register -def suit_161(char: CharacterProperty): - # DCALC_REMOVE: suit_161 - 自然的震怒 - # level: 4 - # value: 利用无可违背的自然之力,对敌人造成巨大伤害。 所有速度 +5% [无可违背的自然 - 干预] 攻击时产生小型旋风,攻击小范围的敌人,并吸附敌人。 (冷却时间5秒) - 小型旋风伤害33300% - # rarity: 传说 - suit_158(char) - pass - - -@register -def suit_162(char: CharacterProperty): - # DCALC_REMOVE: suit_162 - 自然的震怒 - # level: 5 - # value: 利用无可违背的自然之力,对敌人造成巨大伤害。 所有速度 +5% [无可违背的自然 - 干预] 攻击时产生小型旋风,攻击小范围的敌人,并吸附敌人。 (冷却时间5秒) - 小型旋风伤害33300% - # rarity: 传说 - suit_158(char) - pass - - @register def suit_163(char: CharacterProperty): # DCALC_REMOVE: suit_163 - 自然的制裁 @@ -1851,46 +567,6 @@ def suit_163(char: CharacterProperty): pass -@register -def suit_164(char: CharacterProperty): - # DCALC_REMOVE: suit_164 - 自然的制裁 - # level: 2 - # value: 利用无可违背的自然之力,对敌人造成巨大伤害。 所有速度 +5% 所有技能范围 +5% [无可违背的自然 - 干预] 攻击时引发落雷,攻击并吸附大范围敌人。 (冷却时间5秒) - 落雷伤害55500% - # rarity: 史诗 - suit_163(char) - pass - - -@register -def suit_165(char: CharacterProperty): - # DCALC_REMOVE: suit_165 - 自然的制裁 - # level: 3 - # value: 利用无可违背的自然之力,对敌人造成巨大伤害。 所有速度 +5% 所有技能范围 +5% [无可违背的自然 - 干预] 攻击时引发落雷,攻击并吸附大范围敌人。 (冷却时间5秒) - 落雷伤害55500% - # rarity: 史诗 - suit_163(char) - pass - - -@register -def suit_166(char: CharacterProperty): - # DCALC_REMOVE: suit_166 - 自然的制裁 - # level: 4 - # value: 利用无可违背的自然之力,对敌人造成巨大伤害。 所有速度 +5% 所有技能范围 +5% [无可违背的自然 - 干预] 攻击时引发落雷,攻击并吸附大范围敌人。 (冷却时间5秒) - 落雷伤害55500% - # rarity: 史诗 - suit_163(char) - pass - - -@register -def suit_167(char: CharacterProperty): - # DCALC_REMOVE: suit_167 - 自然的制裁 - # level: 5 - # value: 利用无可违背的自然之力,对敌人造成巨大伤害。 所有速度 +5% 所有技能范围 +5% [无可违背的自然 - 干预] 攻击时引发落雷,攻击并吸附大范围敌人。 (冷却时间5秒) - 落雷伤害55500% - # rarity: 史诗 - suit_163(char) - pass - - @register def suit_168(char: CharacterProperty): # DCALC_REMOVE: suit_168 - 自然的灾变 @@ -1916,42 +592,6 @@ def suit_169(char: CharacterProperty): pass -@register -def suit_170(char: CharacterProperty): - # DCALC_REMOVE: suit_170 - 女武神 - 英勇的战士 - # level: 2 - # value: - - # rarity: 稀有 - pass - - -@register -def suit_171(char: CharacterProperty): - # DCALC_REMOVE: suit_171 - 女武神 - 英勇的战士 - # level: 3 - # value: - - # rarity: 稀有 - pass - - -@register -def suit_172(char: CharacterProperty): - # DCALC_REMOVE: suit_172 - 女武神 - 英勇的战士 - # level: 4 - # value: - - # rarity: 稀有 - pass - - -@register -def suit_173(char: CharacterProperty): - # DCALC_REMOVE: suit_173 - 女武神 - 英勇的战士 - # level: 5 - # value: - - # rarity: 稀有 - pass - - @register def suit_174(char: CharacterProperty): # DCALC_REMOVE: suit_174 - 女武神 - 战场的先锋 @@ -1962,46 +602,6 @@ def suit_174(char: CharacterProperty): pass -@register -def suit_175(char: CharacterProperty): - # DCALC_REMOVE: suit_175 - 女武神 - 战场的先锋 - # level: 2 - # value: 可以借用来自女武神的力量,获得全新的力量。 [破阵][装备发动属性] 与女武神融合,向前方突进。 - 正面突破伤害:10200% - 冷却时间8秒 - # rarity: 神器 - suit_174(char) - pass - - -@register -def suit_176(char: CharacterProperty): - # DCALC_REMOVE: suit_176 - 女武神 - 战场的先锋 - # level: 3 - # value: 可以借用来自女武神的力量,获得全新的力量。 [破阵][装备发动属性] 与女武神融合,向前方突进。 - 正面突破伤害:10200% - 冷却时间8秒 - # rarity: 神器 - suit_174(char) - pass - - -@register -def suit_177(char: CharacterProperty): - # DCALC_REMOVE: suit_177 - 女武神 - 战场的先锋 - # level: 4 - # value: 可以借用来自女武神的力量,获得全新的力量。 [破阵][装备发动属性] 与女武神融合,向前方突进。 - 正面突破伤害:10200% - 冷却时间8秒 - # rarity: 神器 - suit_174(char) - pass - - -@register -def suit_178(char: CharacterProperty): - # DCALC_REMOVE: suit_178 - 女武神 - 战场的先锋 - # level: 5 - # value: 可以借用来自女武神的力量,获得全新的力量。 [破阵][装备发动属性] 与女武神融合,向前方突进。 - 正面突破伤害:10200% - 冷却时间8秒 - # rarity: 神器 - suit_174(char) - pass - - @register def suit_179(char: CharacterProperty): # DCALC_REMOVE: suit_179 - 女武神 - 逆袭的战魂 @@ -2013,46 +613,6 @@ def suit_179(char: CharacterProperty): pass -@register -def suit_180(char: CharacterProperty): - # DCALC_REMOVE: suit_180 - 女武神 - 逆袭的战魂 - # level: 2 - # value: 可以借用来自女武神的力量,获得全新的力量。 [突破][装备发动属性] 与女武神融合,向前方突进。 - 正面突破伤害:10200% - 冷却时间8秒 [审判][装备发动属性] 与女武神融合,移动到最强的敌人后方进行攻击。 - 审判伤害:19000% - 追击范围:800px - 冷却时间:15秒 - # rarity: 传说 - suit_179(char) - pass - - -@register -def suit_181(char: CharacterProperty): - # DCALC_REMOVE: suit_181 - 女武神 - 逆袭的战魂 - # level: 3 - # value: 可以借用来自女武神的力量,获得全新的力量。 [突破][装备发动属性] 与女武神融合,向前方突进。 - 正面突破伤害:10200% - 冷却时间8秒 [审判][装备发动属性] 与女武神融合,移动到最强的敌人后方进行攻击。 - 审判伤害:19000% - 追击范围:800px - 冷却时间:15秒 - # rarity: 传说 - suit_179(char) - pass - - -@register -def suit_182(char: CharacterProperty): - # DCALC_REMOVE: suit_182 - 女武神 - 逆袭的战魂 - # level: 4 - # value: 可以借用来自女武神的力量,获得全新的力量。 [突破][装备发动属性] 与女武神融合,向前方突进。 - 正面突破伤害:10200% - 冷却时间8秒 [审判][装备发动属性] 与女武神融合,移动到最强的敌人后方进行攻击。 - 审判伤害:19000% - 追击范围:800px - 冷却时间:15秒 - # rarity: 传说 - suit_179(char) - pass - - -@register -def suit_183(char: CharacterProperty): - # DCALC_REMOVE: suit_183 - 女武神 - 逆袭的战魂 - # level: 5 - # value: 可以借用来自女武神的力量,获得全新的力量。 [突破][装备发动属性] 与女武神融合,向前方突进。 - 正面突破伤害:10200% - 冷却时间8秒 [审判][装备发动属性] 与女武神融合,移动到最强的敌人后方进行攻击。 - 审判伤害:19000% - 追击范围:800px - 冷却时间:15秒 - # rarity: 传说 - suit_179(char) - pass - - @register def suit_184(char: CharacterProperty): # DCALC_REMOVE: suit_184 - 女武神 - 不灭的英雄 @@ -2065,45 +625,6 @@ def suit_184(char: CharacterProperty): pass -@register -def suit_185(char: CharacterProperty): - # DCALC_REMOVE: suit_185 - 女武神 - 不灭的英雄 - # level: 2 - # value: 可以借用来自女武神的力量,获得全新的力量。 [突破][装备发动属性] 与女武神融合,向前方突进。 - 正面突破伤害:10200% - 冷却时间8秒 [审判][装备发动属性] 与女武神融合,移动到最强的敌人后方进行攻击。 - 审判伤害:19000% - 追击范围:800px - 冷却时间:15秒 施放无色小晶块技能时,获得“女武神的意志”。(最多8个) [天罚] 充满“女武神意志”后发动攻击,可召唤女武神,对四周敌人施以天罚。 - 天罚伤害:200400% - 冷却时间20秒 - # rarity: 史诗 - suit_184(char) - pass - - -@register -def suit_186(char: CharacterProperty): - # DCALC_REMOVE: suit_186 - 女武神 - 不灭的英雄 - # level: 3 - # value: 可以借用来自女武神的力量,获得全新的力量。 [突破][装备发动属性] 与女武神融合,向前方突进。 - 正面突破伤害:10200% - 冷却时间8秒 [审判][装备发动属性] 与女武神融合,移动到最强的敌人后方进行攻击。 - 审判伤害:19000% - 追击范围:800px - 冷却时间:15秒 施放无色小晶块技能时,获得“女武神的意志”。(最多8个) [天罚] 充满“女武神意志”后发动攻击,可召唤女武神,对四周敌人施以天罚。 - 天罚伤害:200400% - 冷却时间20秒 - # rarity: 史诗 - suit_184(char) - pass - -@register -def suit_187(char: CharacterProperty): - # DCALC_REMOVE: suit_187 - 女武神 - 不灭的英雄 - # level: 4 - # value: 借用女武神的一部分神秘力量。 [突破][装备发动属性] 与女武神融合,向前方突进。 - 正面突破伤害:10200% - 冷却时间8秒 [审判][装备发动属性] 与女武神融合,移动到最强的敌人后方进行攻击。 - 审判伤害:19000% - 追击范围:800px - 冷却时间:15秒 施放无色小晶块技能时,获得“女武神的意志”。(最多8个) [天罚] 充满“女武神意志”后发动攻击,可召唤女武神,对四周敌人施以天罚。 - 天罚伤害:200400% - 冷却时间20秒 - # rarity: 史诗 - suit_184(char) - pass - - -@register -def suit_188(char: CharacterProperty): - # DCALC_REMOVE: suit_188 - 女武神 - 不灭的英雄 - # level: 5 - # value: 可以借用来自女武神的力量,获得全新的力量。 [突破][装备发动属性] 与女武神融合,向前方突进。 - 正面突破伤害:10200% - 冷却时间8秒 [审判][装备发动属性] 与女武神融合,移动到最强的敌人后方进行攻击。 - 审判伤害:19000% - 追击范围:800px - 冷却时间:15秒 施放无色小晶块技能时,获得“女武神的意志”。(最多8个) [天罚] 充满“女武神意志”后发动攻击,可召唤女武神,对四周敌人施以天罚。 - 天罚伤害:200400% - 冷却时间20秒 - # rarity: 史诗 - suit_184(char) - pass - - @register def suit_189(char: CharacterProperty): # DCALC_REMOVE: suit_189 - 女武神 - 英灵的引导者 @@ -2130,42 +651,6 @@ def suit_190(char: CharacterProperty): pass -@register -def suit_191(char: CharacterProperty): - # DCALC_REMOVE: suit_191 - 黯淡的青丘灵珠 - # level: 2 - # value: - - # rarity: 稀有 - pass - - -@register -def suit_192(char: CharacterProperty): - # DCALC_REMOVE: suit_192 - 黯淡的青丘灵珠 - # level: 3 - # value: - - # rarity: 稀有 - pass - - -@register -def suit_193(char: CharacterProperty): - # DCALC_REMOVE: suit_193 - 黯淡的青丘灵珠 - # level: 4 - # value: - - # rarity: 稀有 - pass - - -@register -def suit_194(char: CharacterProperty): - # DCALC_REMOVE: suit_194 - 黯淡的青丘灵珠 - # level: 5 - # value: - - # rarity: 稀有 - pass - - @register def suit_195(char: CharacterProperty): # DCALC_REMOVE: suit_195 - 微光的青丘灵珠 @@ -2176,46 +661,6 @@ def suit_195(char: CharacterProperty): pass -@register -def suit_196(char: CharacterProperty): - # DCALC_REMOVE: suit_196 - 微光的青丘灵珠 - # level: 2 - # value: 借用青丘狐的灵珠之力,瞬间变强。 [青丘灵珠]激活 - 攻击时,灵珠能量 +5(冷却时间1秒) - 灵珠最多可填充1个 - 青丘灵珠增益效果生效时,无法充能灵珠 - 进入地下城时,灵珠能量填充100 [青丘灵珠][装备主动技能] - 发动时,消耗能量充满的所有灵珠,激活增益效果 - 每消耗1个灵珠,技能伤害 +10% - 增益效果持续时间30秒 - 冷却时间30秒 - # rarity: 神器 - suit_195(char) - pass - - -@register -def suit_197(char: CharacterProperty): - # DCALC_REMOVE: suit_197 - 微光的青丘灵珠 - # level: 3 - # value: 借用青丘狐的灵珠之力,瞬间变强。 [青丘灵珠]激活 - 攻击时,灵珠能量 +5(冷却时间1秒) - 灵珠最多可填充1个 - 青丘灵珠增益效果生效时,无法充能灵珠 - 进入地下城时,灵珠能量填充100 [青丘灵珠][装备主动技能] - 发动时,消耗能量充满的所有灵珠,激活增益效果 - 每消耗1个灵珠,技能伤害 +10% - 增益效果持续时间30秒 - 冷却时间30秒 - # rarity: 神器 - suit_195(char) - pass - - -@register -def suit_198(char: CharacterProperty): - # DCALC_REMOVE: suit_198 - 微光的青丘灵珠 - # level: 4 - # value: 借用青丘狐的灵珠之力,瞬间变强。 [青丘灵珠]激活 - 攻击时,灵珠能量 +5(冷却时间1秒) - 灵珠最多可填充1个 - 青丘灵珠增益效果生效时,无法充能灵珠 - 进入地下城时,灵珠能量填充100 [青丘灵珠][装备主动技能] - 发动时,消耗能量充满的所有灵珠,激活增益效果 - 每消耗1个灵珠,技能伤害 +10% - 增益效果持续时间30秒 - 冷却时间30秒 - # rarity: 神器 - suit_195(char) - pass - - -@register -def suit_199(char: CharacterProperty): - # DCALC_REMOVE: suit_199 - 微光的青丘灵珠 - # level: 5 - # value: 借用青丘狐的灵珠之力,瞬间变强。 [青丘灵珠]激活 - 攻击时,灵珠能量 +5(冷却时间1秒) - 灵珠最多可填充1个 - 青丘灵珠增益效果生效时,无法充能灵珠 - 进入地下城时,灵珠能量填充100 [青丘灵珠][装备主动技能] - 发动时,消耗能量充满的所有灵珠,激活增益效果 - 每消耗1个灵珠,技能伤害 +10% - 增益效果持续时间30秒 - 冷却时间30秒 - # rarity: 神器 - suit_195(char) - pass - - @register def suit_200(char: CharacterProperty): # DCALC_REMOVE: suit_200 - 清澈的青丘灵珠 @@ -2226,46 +671,6 @@ def suit_200(char: CharacterProperty): pass -@register -def suit_201(char: CharacterProperty): - # DCALC_REMOVE: suit_201 - 清澈的青丘灵珠 - # level: 2 - # value: 借用青丘狐的灵珠之力,瞬间变强。 [青丘灵珠]激活 - 攻击时,灵珠能量 +6(冷却时间1秒) - 每秒灵珠能量 +1 - 灵珠最多可填充2个 - 青丘灵珠增益效果生效时,可以充能灵珠 - 进入地下城时,灵珠能量填充200 [青丘灵珠][装备主动技能] - 发动时,消耗能量充满的所有灵珠,激活增益效果 - 每消耗1个灵珠,技能伤害 +10% - 增益效果持续时间30秒 - 冷却时间30秒 - # rarity: 传说 - suit_200(char) - pass - - -@register -def suit_202(char: CharacterProperty): - # DCALC_REMOVE: suit_202 - 清澈的青丘灵珠 - # level: 3 - # value: 借用青丘狐的灵珠之力,瞬间变强。 [青丘灵珠]激活 - 攻击时,灵珠能量 +6(冷却时间1秒) - 每秒灵珠能量 +1 - 灵珠最多可填充2个 - 青丘灵珠增益效果生效时,可以充能灵珠 - 进入地下城时,灵珠能量填充200 [青丘灵珠][装备主动技能] - 发动时,消耗能量充满的所有灵珠,激活增益效果 - 每消耗1个灵珠,技能伤害 +10% - 增益效果持续时间30秒 - 冷却时间30秒 - # rarity: 传说 - suit_200(char) - pass - - -@register -def suit_203(char: CharacterProperty): - # DCALC_REMOVE: suit_203 - 清澈的青丘灵珠 - # level: 4 - # value: 借用青丘狐的灵珠之力,瞬间变强。 [青丘灵珠]激活 - 攻击时,灵珠能量 +6(冷却时间1秒) - 每秒灵珠能量 +1 - 灵珠最多可填充2个 - 青丘灵珠增益效果生效时,可以充能灵珠 - 进入地下城时,灵珠能量填充200 [青丘灵珠][装备主动技能] - 发动时,消耗能量充满的所有灵珠,激活增益效果 - 每消耗1个灵珠,技能伤害 +10% - 增益效果持续时间30秒 - 冷却时间30秒 - # rarity: 传说 - suit_200(char) - pass - - -@register -def suit_204(char: CharacterProperty): - # DCALC_REMOVE: suit_204 - 清澈的青丘灵珠 - # level: 5 - # value: 借用青丘狐的灵珠之力,瞬间变强。 [青丘灵珠]激活 - 攻击时,灵珠能量 +6(冷却时间1秒) - 每秒灵珠能量 +1 - 灵珠最多可填充2个 - 青丘灵珠增益效果生效时,可以充能灵珠 - 进入地下城时,灵珠能量填充200 [青丘灵珠][装备主动技能] - 发动时,消耗能量充满的所有灵珠,激活增益效果 - 每消耗1个灵珠,技能伤害 +10% - 增益效果持续时间30秒 - 冷却时间30秒 - # rarity: 传说 - suit_200(char) - pass - - @register def suit_205(char: CharacterProperty): # DCALC_REMOVE: suit_205 - 耀眼的青丘灵珠 @@ -2276,46 +681,6 @@ def suit_205(char: CharacterProperty): pass -@register -def suit_206(char: CharacterProperty): - # DCALC_REMOVE: suit_206 - 耀眼的青丘灵珠 - # level: 2 - # value: 借用青丘狐的灵珠之力,瞬间变强。 [青丘灵珠]激活 - 攻击时,灵珠能量 +8(冷却时间1秒) - 每秒灵珠能量 +3 - 灵珠最多可填充3个 - 青丘灵珠增益效果生效时,也可以充能灵珠 - 进入地下城时,灵珠能量填充200 [青丘灵珠][装备主动技能] - 发动时,消耗能量充满的所有灵珠,激活增益效果 - 每消耗1个灵珠,技能伤害 +10% - 增益效果持续时间30秒 - 冷却时间30秒 [青丘灵珠开关][装备主动技能] - 灵珠全部填满时,自动使用青丘灵珠增益效果(冷却时间1秒) - 再次使用时,关闭自动使用功能 - # rarity: 史诗 - suit_205(char) - pass - - -@register -def suit_207(char: CharacterProperty): - # DCALC_REMOVE: suit_207 - 耀眼的青丘灵珠 - # level: 3 - # value: 借用青丘狐的灵珠之力,瞬间变强。 [青丘灵珠]激活 - 攻击时,灵珠能量 +8(冷却时间1秒) - 每秒灵珠能量 +3 - 灵珠最多可填充3个 - 青丘灵珠增益效果生效时,也可以充能灵珠 - 进入地下城时,灵珠能量填充200 [青丘灵珠][装备主动技能] - 发动时,消耗能量充满的所有灵珠,激活增益效果 - 每消耗1个灵珠,技能伤害 +10% - 增益效果持续时间30秒 - 冷却时间30秒 [青丘灵珠开关][装备主动技能] - 灵珠全部填满时,自动使用青丘灵珠增益效果(冷却时间1秒) - 再次使用时,关闭自动使用功能 - # rarity: 史诗 - suit_205(char) - pass - - -@register -def suit_208(char: CharacterProperty): - # DCALC_REMOVE: suit_208 - 耀眼的青丘灵珠 - # level: 4 - # value: 借用青丘狐的灵珠之力,瞬间变强。 [青丘灵珠]激活 - 攻击时,灵珠能量 +8(冷却时间1秒) - 每秒灵珠能量 +3 - 灵珠最多可填充3个 - 青丘灵珠增益效果生效时,也可以充能灵珠 - 进入地下城时,灵珠能量填充200 [青丘灵珠][装备主动技能] - 发动时,消耗能量充满的所有灵珠,激活增益效果 - 每消耗1个灵珠,技能伤害 +10% - 增益效果持续时间30秒 - 冷却时间30秒 [青丘灵珠开关][装备主动技能] - 灵珠全部填满时,自动使用青丘灵珠增益效果(冷却时间1秒) - 再次使用时,关闭自动使用功能 - # rarity: 史诗 - suit_205(char) - pass - - -@register -def suit_209(char: CharacterProperty): - # DCALC_REMOVE: suit_209 - 耀眼的青丘灵珠 - # level: 5 - # value: 借用青丘狐的灵珠之力,瞬间变强。 [青丘灵珠]激活 - 攻击时,灵珠能量 +8(冷却时间1秒) - 每秒灵珠能量 +3 - 灵珠最多可填充3个 - 青丘灵珠增益效果生效时,也可以充能灵珠 - 进入地下城时,灵珠能量填充200 [青丘灵珠][装备主动技能] - 发动时,消耗能量充满的所有灵珠,激活增益效果 - 每消耗1个灵珠,技能伤害 +10% - 增益效果持续时间30秒 - 冷却时间30秒 [青丘灵珠开关][装备主动技能] - 灵珠全部填满时,自动使用青丘灵珠增益效果(冷却时间1秒) - 再次使用时,关闭自动使用功能 - # rarity: 史诗 - suit_205(char) - pass - - @register def suit_210(char: CharacterProperty): # DCALC_REMOVE: suit_210 - 梦幻的青丘灵珠 @@ -2339,214 +704,58 @@ def suit_211(char: CharacterProperty): pass -@register -def suit_212(char: CharacterProperty): - # DCALC_REMOVE: suit_212 - 群猎之风 - # level: 2 - # value: - - # rarity: 稀有 - pass - - -@register -def suit_213(char: CharacterProperty): - # DCALC_REMOVE: suit_213 - 群猎之风 - # level: 3 - # value: - - # rarity: 稀有 - pass - - -@register -def suit_214(char: CharacterProperty): - # DCALC_REMOVE: suit_214 - 群猎之风 - # level: 4 - # value: - - # rarity: 稀有 - pass - - -@register -def suit_215(char: CharacterProperty): - # DCALC_REMOVE: suit_215 - 群猎之风 - # level: 5 - # value: - - # rarity: 稀有 - pass - - @register def suit_216(char: CharacterProperty): # DCALC_REMOVE: suit_216 - 群猎之林 # level: 1 # value: 与同伴在一起时,会变得更强。 [组队挑战时适用] [群猎之力] 给队员赋予光环,获得以下效果。 (最多叠加1次) - 所有速度 +10% [酣畅狩猎][装备主动技能] 发出吼叫震慑敌人。 - 伤害量:3,825% - 使被命中的敌人进入崩裂状态,持续30秒 - 冷却时间10秒 (敌人进入崩裂状态时,所受伤害根据叠加层数(1/2/3)增加(5/7/8)%) ([群猎之力]、[酣畅狩猎]效果对辅助职业无效) [单人挑战时适用] - 技能伤害 +7.4% - 适用[群猎之力]效果 - 不适用[酣畅狩猎]效果 # rarity: 神器 - if char.equ_options.get('3',0) == 0: + if char.equ_options.get('3', 0) == 0: char.SetStatus(SkillAttack=0.074) else: - char.SetStatus(SkillAttack=0.08,SpeedA=0.1,SpeedM=0.1,SpeedR=0.1) + char.SetStatus(SkillAttack=0.08, SpeedA=0.1, SpeedM=0.1, SpeedR=0.1) char.equ_effect.append(EquEffect(name='酣畅狩猎', icon='/equipment/skill/15.png', cd=10, data=3825)) pass -@register -def suit_217(char: CharacterProperty): - # DCALC_REMOVE: suit_217 - 群猎之林 - # level: 2 - # value: 与同伴在一起时,会变得更强。 [组队挑战时适用] [群猎之力] 给队员赋予光环,获得以下效果。 (最多叠加1次) - 所有速度 +10% [酣畅狩猎][装备主动技能] 发出吼叫震慑敌人。 - 伤害量:3,825% - 使被命中的敌人进入崩裂状态,持续30秒 - 冷却时间10秒 (敌人进入崩裂状态时,所受伤害根据叠加层数(1/2/3)增加(5/7/8)%) ([群猎之力]、[酣畅狩猎]效果对辅助职业无效) [单人挑战时适用] - 技能伤害 +7.4% - 适用[群猎之力]效果 - 不适用[酣畅狩猎]效果 - # rarity: 神器 - suit_216(char) - pass - - -@register -def suit_218(char: CharacterProperty): - # DCALC_REMOVE: suit_218 - 群猎之林 - # level: 3 - # value: 与同伴在一起时,会变得更强。 [组队挑战时适用] [群猎之力] 给队员赋予光环,获得以下效果。 (最多叠加1次) - 所有速度 +10% [酣畅狩猎][装备主动技能] 发出吼叫震慑敌人。 - 伤害量:3,825% - 使被命中的敌人进入崩裂状态,持续30秒 - 冷却时间10秒 (敌人进入崩裂状态时,所受伤害根据叠加层数(1/2/3)增加(5/7/8)%) ([群猎之力]、[酣畅狩猎]效果对辅助职业无效) [单人挑战时适用] - 技能伤害 +7.4% - 适用[群猎之力]效果 - 不适用[酣畅狩猎]效果 - # rarity: 神器 - suit_216(char) - pass - - -@register -def suit_219(char: CharacterProperty): - # DCALC_REMOVE: suit_219 - 群猎之林 - # level: 4 - # value: 与同伴在一起时,会变得更强。 [组队挑战时适用] [群猎之力] 给队员赋予光环,获得以下效果。 (最多叠加1次) - 所有速度 +10% [酣畅狩猎][装备主动技能] 发出吼叫震慑敌人。 - 伤害量:3,825% - 使被命中的敌人进入崩裂状态,持续30秒 - 冷却时间10秒 (敌人进入崩裂状态时,所受伤害根据叠加层数(1/2/3)增加(5/7/8)%) ([群猎之力]、[酣畅狩猎]效果对辅助职业无效) [单人挑战时适用] - 技能伤害 +7.4% - 适用[群猎之力]效果 - 不适用[酣畅狩猎]效果 - # rarity: 神器 - suit_216(char) - pass - - -@register -def suit_220(char: CharacterProperty): - # DCALC_REMOVE: suit_220 - 群猎之林 - # level: 5 - # value: 与同伴在一起时,会变得更强。 [组队挑战时适用] [群猎之力] 给队员赋予光环,获得以下效果。 (最多叠加1次) - 所有速度 +10% [酣畅狩猎][装备主动技能] 发出吼叫震慑敌人。 - 伤害量:3,825% - 使被命中的敌人进入崩裂状态,持续30秒 - 冷却时间10秒 (敌人进入崩裂状态时,所受伤害根据叠加层数(1/2/3)增加(5/7/8)%) ([群猎之力]、[酣畅狩猎]效果对辅助职业无效) [单人挑战时适用] - 技能伤害 +7.4% - 适用[群猎之力]效果 - 不适用[酣畅狩猎]效果 - # rarity: 神器 - suit_216(char) - pass - - @register def suit_221(char: CharacterProperty): # DCALC_REMOVE: suit_221 - 群猎之光 # level: 1 # value: 与同伴在一起时,会变得更强。 [组队挑战时适用] [群猎之力] 给队员赋予光环,获得以下效果。(最多叠加1次) - 所有速度 +15% - 每10秒恢复10000点的生命值和魔法值,持续10秒 [酣畅狩猎][装备主动技能] 发出吼叫震慑敌人。 - 伤害量:5,738% - 使被命中的敌人进入崩裂状态,持续45秒 - 冷却时间10秒 (敌人进入崩裂状态时,所受伤害根据叠加层数(1/2/3)增加(5/7/8)%) ([群猎之力]、[酣畅狩猎]效果对辅助职业无效) [单人挑战时适用] - 技能伤害 +14.4% - 适用[群猎之力]效果 - 不适用[酣畅狩猎]效果 # rarity: 传说 - if char.equ_options.get('3',0) == 0: + if char.equ_options.get('3', 0) == 0: char.SetStatus(SkillAttack=0.144) else: - char.SetStatus(SkillAttack=0.08,SpeedA=0.15,SpeedM=0.15,SpeedR=0.15) + char.SetStatus(SkillAttack=0.08, SpeedA=0.15, SpeedM=0.15, SpeedR=0.15) char.equ_effect.append(EquEffect(name='酣畅狩猎', icon='/equipment/skill/15.png', cd=10, data=5738)) pass -@register -def suit_222(char: CharacterProperty): - # DCALC_REMOVE: suit_222 - 群猎之光 - # level: 2 - # value: 与同伴在一起时,会变得更强。 [组队挑战时适用] [群猎之力] 给队员赋予光环,获得以下效果。(最多叠加1次) - 所有速度 +15% - 每10秒恢复10000点的生命值和魔法值,持续10秒 [酣畅狩猎][装备主动技能] 发出吼叫震慑敌人。 - 伤害量:5,738% - 使被命中的敌人进入崩裂状态,持续45秒 - 冷却时间10秒 (敌人进入崩裂状态时,所受伤害根据叠加层数(1/2/3)增加(5/7/8)%) ([群猎之力]、[酣畅狩猎]效果对辅助职业无效) [单人挑战时适用] - 技能伤害 +14.4% - 适用[群猎之力]效果 - 不适用[酣畅狩猎]效果 - # rarity: 传说 - suit_221(char) - pass - - -@register -def suit_223(char: CharacterProperty): - # DCALC_REMOVE: suit_223 - 群猎之光 - # level: 3 - # value: 与同伴在一起时,会变得更强。 [组队挑战时适用] [群猎之力] 给队员赋予光环,获得以下效果。(最多叠加1次) - 所有速度 +15% - 每10秒恢复10000点的生命值和魔法值,持续10秒 [酣畅狩猎][装备主动技能] 发出吼叫震慑敌人。 - 伤害量:5,738% - 使被命中的敌人进入崩裂状态,持续45秒 - 冷却时间10秒 (敌人进入崩裂状态时,所受伤害根据叠加层数(1/2/3)增加(5/7/8)%) ([群猎之力]、[酣畅狩猎]效果对辅助职业无效) [单人挑战时适用] - 技能伤害 +14.4% - 适用[群猎之力]效果 - 不适用[酣畅狩猎]效果 - # rarity: 传说 - suit_221(char) - pass - - -@register -def suit_224(char: CharacterProperty): - # DCALC_REMOVE: suit_224 - 群猎之光 - # level: 4 - # value: 与同伴在一起时,会变得更强。 [组队挑战时适用] [群猎之力] 给队员赋予光环,获得以下效果。(最多叠加1次) - 所有速度 +15% - 每10秒恢复10000点的生命值和魔法值,持续10秒 [酣畅狩猎][装备主动技能] 发出吼叫震慑敌人。 - 伤害量:5,738% - 使被命中的敌人进入崩裂状态,持续45秒 - 冷却时间10秒 (敌人进入崩裂状态时,所受伤害根据叠加层数(1/2/3)增加(5/7/8)%) ([群猎之力]、[酣畅狩猎]效果对辅助职业无效) [单人挑战时适用] - 技能伤害 +14.4% - 适用[群猎之力]效果 - 不适用[酣畅狩猎]效果 - # rarity: 传说 - suit_221(char) - pass - - -@register -def suit_225(char: CharacterProperty): - # DCALC_REMOVE: suit_225 - 群猎之光 - # level: 5 - # value: 与同伴在一起时,会变得更强。 [组队挑战时适用] [群猎之力] 给队员赋予光环,获得以下效果。(最多叠加1次) - 所有速度 +15% - 每10秒恢复10000点的生命值和魔法值,持续10秒 [酣畅狩猎][装备主动技能] 发出吼叫震慑敌人。 - 伤害量:5,738% - 使被命中的敌人进入崩裂状态,持续45秒 - 冷却时间10秒 (敌人进入崩裂状态时,所受伤害根据叠加层数(1/2/3)增加(5/7/8)%) ([群猎之力]、[酣畅狩猎]效果对辅助职业无效) [单人挑战时适用] - 技能伤害 +14.4% - 适用[群猎之力]效果 - 不适用[酣畅狩猎]效果 - # rarity: 传说 - suit_221(char) - pass - - @register def suit_226(char: CharacterProperty): # DCALC_REMOVE: suit_226 - 群猎之星 # level: 1 # value: 与同伴在一起时,会变得更强。 [组队挑战时适用] [群猎之力] 给队员赋予光环,获得以下效果。(最多叠加1次) - 所有速度 +20% - 所受物理/魔法伤害- 10% - 每10秒恢复10000点的生命值和魔法值,持续10秒 [酣畅狩猎][装备主动技能] 发出吼叫震慑敌人。 - 伤害量:6,750% - 使被命中的敌人进入最大层数的崩裂状态,持续60秒 - 冷却时间30秒 (敌人进入崩裂状态时,所受伤害根据叠加层数(1/2/3)增加(5/7/8)%) ([群猎之力]、[酣畅狩猎]效果对辅助职业无效) [单人挑战时适用] - 技能伤害 +14.4% - 适用[群猎之力]效果 - 不适用[酣畅狩猎]效果 # rarity: 史诗 - if char.equ_options.get('3',0) == 0: + if char.equ_options.get('3', 0) == 0: char.SetStatus(SkillAttack=0.144) else: - char.SetStatus(SkillAttack=0.08,SpeedA=0.2,SpeedM=0.0,SpeedR=0.0) + char.SetStatus(SkillAttack=0.08, SpeedA=0.2, SpeedM=0.0, SpeedR=0.0) char.equ_effect.append(EquEffect(name='酣畅狩猎', icon='/equipment/skill/15.png', cd=30, data=6750)) pass -@register -def suit_227(char: CharacterProperty): - # DCALC_REMOVE: suit_227 - 群猎之星 - # level: 2 - # value: 与同伴在一起时,会变得更强。 [组队挑战时适用] [群猎之力] 给队员赋予光环,获得以下效果。(最多叠加1次) - 所有速度 +20% - 所受物理/魔法伤害- 10% - 每10秒恢复10000点的生命值和魔法值,持续10秒 [酣畅狩猎][装备主动技能] 发出吼叫震慑敌人。 - 伤害量:6,750% - 使被命中的敌人进入最大层数的崩裂状态,持续60秒 - 冷却时间30秒 (敌人进入崩裂状态时,所受伤害根据叠加层数(1/2/3)增加(5/7/8)%) ([群猎之力]、[酣畅狩猎]效果对辅助职业无效) [单人挑战时适用] - 技能伤害 +14.4% - 适用[群猎之力]效果 - 不适用[酣畅狩猎]效果 - # rarity: 史诗 - suit_226(char) - pass - - -@register -def suit_228(char: CharacterProperty): - # DCALC_REMOVE: suit_228 - 群猎之星 - # level: 3 - # value: 与同伴在一起时,会变得更强。 [组队挑战时适用] [群猎之力] 给队员赋予光环,获得以下效果。(最多叠加1次) - 所有速度 +20% - 所受物理/魔法伤害- 10% - 每10秒恢复10000点的生命值和魔法值,持续10秒 [酣畅狩猎][装备主动技能] 发出吼叫震慑敌人。 - 伤害量:6,750% - 使被命中的敌人进入最大层数的崩裂状态,持续60秒 - 冷却时间30秒 (敌人进入崩裂状态时,所受伤害根据叠加层数(1/2/3)增加(5/7/8)%) ([群猎之力]、[酣畅狩猎]效果对辅助职业无效) [单人挑战时适用] - 技能伤害 +14.4% - 适用[群猎之力]效果 - 不适用[酣畅狩猎]效果 - # rarity: 史诗 - suit_226(char) - pass - - -@register -def suit_229(char: CharacterProperty): - # DCALC_REMOVE: suit_229 - 群猎之星 - # level: 4 - # value: 与同伴在一起时,会变得更强。 [组队挑战时适用] [群猎之力] 给队员赋予光环,获得以下效果。(最多叠加1次) - 所有速度 +20% - 所受物理/魔法伤害- 10% - 每10秒恢复10000点的生命值和魔法值,持续10秒 [酣畅狩猎][装备主动技能] 发出吼叫震慑敌人。 - 伤害量:6,750% - 使被命中的敌人进入最大层数的崩裂状态,持续60秒 - 冷却时间30秒 (敌人进入崩裂状态时,所受伤害根据叠加层数(1/2/3)增加(5/7/8)%) ([群猎之力]、[酣畅狩猎]效果对辅助职业无效) [单人挑战时适用] - 技能伤害 +14.4% - 适用[群猎之力]效果 - 不适用[酣畅狩猎]效果 - # rarity: 史诗 - suit_226(char) - pass - - -@register -def suit_230(char: CharacterProperty): - # DCALC_REMOVE: suit_230 - 群猎之星 - # level: 5 - # value: 与同伴在一起时,会变得更强。 [组队挑战时适用] [群猎之力] 给队员赋予光环,获得以下效果。(最多叠加1次) - 所有速度 +20% - 所受物理/魔法伤害- 10% - 每10秒恢复10000点的生命值和魔法值,持续10秒 [酣畅狩猎][装备主动技能] 发出吼叫震慑敌人。 - 伤害量:6,750% - 使被命中的敌人进入最大层数的崩裂状态,持续60秒 - 冷却时间30秒 (敌人进入崩裂状态时,所受伤害根据叠加层数(1/2/3)增加(5/7/8)%) ([群猎之力]、[酣畅狩猎]效果对辅助职业无效) [单人挑战时适用] - 技能伤害 +14.4% - 适用[群猎之力]效果 - 不适用[酣畅狩猎]效果 - # rarity: 史诗 - suit_226(char) - pass - - @register def suit_231(char: CharacterProperty): # DCALC_REMOVE: suit_231 - 群猎之神 # level: 1 # value: 与同伴在一起时,会变得更强。 [组队挑战时适用] [群猎之力] 给队员赋予光环,获得以下效果。(最多叠加1次) - 所有速度 +30% - 所受物理/魔法伤害- 15% - 每10秒恢复10,000点的生命值和魔法值,持续10秒 [酣畅狩猎][装备主动技能] 散发出威慑敌人的气势。 - 施放时,每秒使500px范围内的敌人进入最大层数的崩裂状态,持续60秒 - 再次施放时,不再使敌人进入崩裂状态 - 冷却时间10秒 (敌人进入崩裂状态时,所受伤害根据叠加层数(1/2/3)增加(5/7/8)%) ([群猎之力]、[酣畅狩猎]效果对辅助职业无效) [单人挑战时适用] - 技能伤害 +18.1% - 适用[群猎之力]效果 - 不适用[酣畅狩猎]效果 [太初的记忆] 套装积分达到2550后,每增加70点套装积分,可以获得以下效果。 - 技能伤害 增加 1% - 增益量 +100 # rarity: 太初 - if char.equ_options.get('3',0) == 0: + if char.equ_options.get('3', 0) == 0: char.SetStatus(SkillAttack=0.181) else: - char.SetStatus(SkillAttack=0.08,SpeedA=0.3,SpeedM=0.3,SpeedR=0.3) + char.SetStatus(SkillAttack=0.08, SpeedA=0.3, SpeedM=0.3, SpeedR=0.3) pass @@ -2563,146 +772,30 @@ def suit_232(char: CharacterProperty): pass -@register -def suit_233(char: CharacterProperty): - # DCALC_REMOVE: suit_233 - 魔力领域 - 初始 - # level: 2 - # value: - - # rarity: 稀有 - pass - - -@register -def suit_234(char: CharacterProperty): - # DCALC_REMOVE: suit_234 - 魔力领域 - 初始 - # level: 3 - # value: - - # rarity: 稀有 - pass - - -@register -def suit_235(char: CharacterProperty): - # DCALC_REMOVE: suit_235 - 魔力领域 - 初始 - # level: 4 - # value: - - # rarity: 稀有 - pass - - -@register -def suit_236(char: CharacterProperty): - # DCALC_REMOVE: suit_236 - 魔力领域 - 初始 - # level: 5 - # value: - - # rarity: 稀有 - pass - - @register def suit_237(char: CharacterProperty): # DCALC_REMOVE: suit_237 - 魔力领域 - 入静 # level: 1 # value: 操控魔攻核攻击敌人。 [魔攻核] 进入地下城时,召唤普通模式魔攻核。 [命令:转换][装备主动技能] 转换魔攻核的攻击模式。 - 普通模式/追击模式 - 冷却时间:5秒 [魔攻核:普通模式] 每秒发射魔力波动。 - 魔力波动伤害量:19200% - 魔力波动范围:150px [魔攻核:追击模式] 追击最强的敌人,每秒发射魔力波动。 - 魔力波动伤害量:13714% - 魔力波动范围:150px # rarity: 神器 - if char.equ_options.get('4',0) == 0: + if char.equ_options.get('4', 0) == 0: char.equ_effect.append(EquEffect(name='普通模式', icon='/equipment/skill/57.png', cd=1, data=19200)) else: char.equ_effect.append(EquEffect(name='追击模式', icon='/equipment/skill/57.png', cd=1, data=13714)) pass -@register -def suit_238(char: CharacterProperty): - # DCALC_REMOVE: suit_238 - 魔力领域 - 入静 - # level: 2 - # value: 操控魔攻核攻击敌人。 [魔攻核] 进入地下城时,召唤普通模式魔攻核。 [命令:转换][装备主动技能] 转换魔攻核的攻击模式。 - 普通模式/追击模式 - 冷却时间:5秒 [魔攻核:普通模式] 每秒发射魔力波动。 - 魔力波动伤害量:19200% - 魔力波动范围:150px [魔攻核:追击模式] 追击最强的敌人,每秒发射魔力波动。 - 魔力波动伤害量:13714% - 魔力波动范围:150px - # rarity: 神器 - suit_237(char) - pass - - -@register -def suit_239(char: CharacterProperty): - # DCALC_REMOVE: suit_239 - 魔力领域 - 入静 - # level: 3 - # value: 操控魔攻核攻击敌人。 [魔攻核] 进入地下城时,召唤普通模式魔攻核。 [命令:转换][装备主动技能] 转换魔攻核的攻击模式。 - 普通模式/追击模式 - 冷却时间:5秒 [魔攻核:普通模式] 每秒发射魔力波动。 - 魔力波动伤害量:19200% - 魔力波动范围:150px [魔攻核:追击模式] 追击最强的敌人,每秒发射魔力波动。 - 魔力波动伤害量:13714% - 魔力波动范围:150px - # rarity: 神器 - suit_237(char) - pass - - -@register -def suit_240(char: CharacterProperty): - # DCALC_REMOVE: suit_240 - 魔力领域 - 入静 - # level: 4 - # value: 操控魔攻核攻击敌人。 [魔攻核] 进入地下城时,召唤普通模式魔攻核。 [命令:转换][装备主动技能] 转换魔攻核的攻击模式。 - 普通模式/追击模式 - 冷却时间:5秒 [魔攻核:普通模式] 每秒发射魔力波动。 - 魔力波动伤害量:19200% - 魔力波动范围:150px [魔攻核:追击模式] 追击最强的敌人,每秒发射魔力波动。 - 魔力波动伤害量:13714% - 魔力波动范围:150px - # rarity: 神器 - suit_237(char) - pass - - -@register -def suit_241(char: CharacterProperty): - # DCALC_REMOVE: suit_241 - 魔力领域 - 入静 - # level: 5 - # value: 操控魔攻核攻击敌人。 [魔攻核] 进入地下城时,召唤普通模式魔攻核。 [命令:转换][装备主动技能] 转换魔攻核的攻击模式。 - 普通模式/追击模式 - 冷却时间:5秒 [魔攻核:普通模式] 每秒发射魔力波动。 - 魔力波动伤害量:19200% - 魔力波动范围:150px [魔攻核:追击模式] 追击最强的敌人,每秒发射魔力波动。 - 魔力波动伤害量:13714% - 魔力波动范围:150px - # rarity: 神器 - suit_237(char) - pass - - @register def suit_242(char: CharacterProperty): # DCALC_REMOVE: suit_242 - 魔力领域 - 入真 # level: 1 # value: 操控魔攻核攻击敌人。 [魔攻核] 进入地下城时, 召唤普通模式魔攻核。 [命令 : 转换] [装备主动技能] 转换魔攻核的攻击模式。 - 普通模式 / 追击模式 - 删除[追踪印记] - 冷却时间 : 5秒 [魔攻核 : 普通模式] 每秒发射魔力波动。 - 魔力波动伤害量 : 35000% - 魔力波动范围 : 150px - 移动速度 +25% - 进入霸体状态 [魔攻核 : 追击模式] 追击最强的敌人, 每秒发射魔力波动。 - 魔力波动伤害量 : 21000% - 魔力波动范围 : 150px - 对追踪目标赋予[追踪印记] [魔攻弹 : 追击模式] 攻击时, 对赋予[追踪印记]的敌人发射魔力飞弹。 - 魔力飞弹伤害量 : 7000% - 冷却时间 : 1秒 # rarity: 传说 - if char.equ_options.get('4',0) == 0: + if char.equ_options.get('4', 0) == 0: char.equ_effect.append(EquEffect(name='普通模式', icon='/equipment/skill/57.png', cd=1, data=35000)) char.SetStatus(SpeedM=0.25) else: - char.equ_effect.append(EquEffect(name='追击模式', icon='/equipment/skill/57.png', cd=1, data=21000+7000)) - pass - - -@register -def suit_243(char: CharacterProperty): - # DCALC_REMOVE: suit_243 - 魔力领域 - 入真 - # level: 2 - # value: 操控魔攻核攻击敌人。 [魔攻核] 进入地下城时, 召唤普通模式魔攻核。 [命令 : 转换] [装备主动技能] 转换魔攻核的攻击模式。 - 普通模式 / 追击模式 - 删除[追踪印记] - 冷却时间 : 5秒 [魔攻核 : 普通模式] 每秒发射魔力波动。 - 魔力波动伤害量 : 35000% - 魔力波动范围 : 150px - 移动速度 +25% - 进入霸体状态 [魔攻核 : 追击模式] 追击最强的敌人, 每秒发射魔力波动。 - 魔力波动伤害量 : 21000% - 魔力波动范围 : 150px - 对追踪目标赋予[追踪印记] [魔攻弹 : 追击模式] 攻击时, 对赋予[追踪印记]的敌人发射魔力飞弹。 - 魔力飞弹伤害量 : 7000% - 冷却时间 : 1秒 - # rarity: 传说 - suit_242(char) - pass - - -@register -def suit_244(char: CharacterProperty): - # DCALC_REMOVE: suit_244 - 魔力领域 - 入真 - # level: 3 - # value: 操控魔攻核攻击敌人。 [魔攻核] 进入地下城时, 召唤普通模式魔攻核。 [命令 : 转换] [装备主动技能] 转换魔攻核的攻击模式。 - 普通模式 / 追击模式 - 删除[追踪印记] - 冷却时间 : 5秒 [魔攻核 : 普通模式] 每秒发射魔力波动。 - 魔力波动伤害量 : 35000% - 魔力波动范围 : 150px - 移动速度 +25% - 进入霸体状态 [魔攻核 : 追击模式] 追击最强的敌人, 每秒发射魔力波动。 - 魔力波动伤害量 : 21000% - 魔力波动范围 : 150px - 对追踪目标赋予[追踪印记] [魔攻弹 : 追击模式] 攻击时, 对赋予[追踪印记]的敌人发射魔力飞弹。 - 魔力飞弹伤害量 : 7000% - 冷却时间 : 1秒 - # rarity: 传说 - suit_242(char) - pass - - -@register -def suit_245(char: CharacterProperty): - # DCALC_REMOVE: suit_245 - 魔力领域 - 入真 - # level: 4 - # value: 操控魔攻核攻击敌人。 [魔攻核] 进入地下城时, 召唤普通模式魔攻核。 [命令 : 转换] [装备主动技能] 转换魔攻核的攻击模式。 - 普通模式 / 追击模式 - 删除[追踪印记] - 冷却时间 : 5秒 [魔攻核 : 普通模式] 每秒发射魔力波动。 - 魔力波动伤害量 : 35000% - 魔力波动范围 : 150px - 移动速度 +25% - 进入霸体状态 [魔攻核 : 追击模式] 追击最强的敌人, 每秒发射魔力波动。 - 魔力波动伤害量 : 21000% - 魔力波动范围 : 150px - 对追踪目标赋予[追踪印记] [魔攻弹 : 追击模式] 攻击时, 对赋予[追踪印记]的敌人发射魔力飞弹。 - 魔力飞弹伤害量 : 7000% - 冷却时间 : 1秒 - # rarity: 传说 - suit_242(char) - pass - - -@register -def suit_246(char: CharacterProperty): - # DCALC_REMOVE: suit_246 - 魔力领域 - 入真 - # level: 5 - # value: 操控魔攻核攻击敌人。 [魔攻核] 进入地下城时, 召唤普通模式魔攻核。 [命令 : 转换] [装备主动技能] 转换魔攻核的攻击模式。 - 普通模式 / 追击模式 - 删除[追踪印记] - 冷却时间 : 5秒 [魔攻核 : 普通模式] 每秒发射魔力波动。 - 魔力波动伤害量 : 35000% - 魔力波动范围 : 150px - 移动速度 +25% - 进入霸体状态 [魔攻核 : 追击模式] 追击最强的敌人, 每秒发射魔力波动。 - 魔力波动伤害量 : 21000% - 魔力波动范围 : 150px - 对追踪目标赋予[追踪印记] [魔攻弹 : 追击模式] 攻击时, 对赋予[追踪印记]的敌人发射魔力飞弹。 - 魔力飞弹伤害量 : 7000% - 冷却时间 : 1秒 - # rarity: 传说 - suit_242(char) + char.equ_effect.append(EquEffect(name='追击模式', icon='/equipment/skill/57.png', cd=1, data=21000 + 7000)) pass @@ -2712,51 +805,11 @@ def suit_247(char: CharacterProperty): # level: 1 # value: 操控魔攻核攻击敌人。 [魔攻核] 进入地下城时, 召唤普通模式魔攻核。 [命令 : 转换] [装备主动技能] 转换魔攻核的攻击模式。 - 普通模式 / 追击模式 - 删除[追踪印记] - 冷却时间 : 5秒 [魔攻核 : 普通模式] 每秒发射魔力波动。 - 魔力波动伤害量 : 52500% - 魔力波动范围 : 200px - 移动速度 +25% - 进入霸体状态 [魔攻核 : 追击模式] 追击最强的敌人, 每秒发射魔力波动。 - 魔力波动伤害量 : 31000% - 魔力波动范围 : 200px - 对追踪目标赋予[追踪印记] [魔攻弹 : 追击模式] 攻击时, 对赋予[追踪印记]的敌人发射魔力飞弹。 - 魔力飞弹伤害量 : 11000% - 冷却时间 : 1秒 # rarity: 史诗 - if char.equ_options.get('4',0) == 0: + if char.equ_options.get('4', 0) == 0: char.equ_effect.append(EquEffect(name='普通模式', icon='/equipment/skill/57.png', cd=1, data=52500)) char.SetStatus(SpeedM=0.25) else: - char.equ_effect.append(EquEffect(name='追击模式', icon='/equipment/skill/57.png', cd=1, data=31000+11000)) - pass - - -@register -def suit_248(char: CharacterProperty): - # DCALC_REMOVE: suit_248 - 魔力领域 - 入定 - # level: 2 - # value: 操控魔攻核攻击敌人。 [魔攻核] 进入地下城时, 召唤普通模式魔攻核。 [命令 : 转换] [装备主动技能] 转换魔攻核的攻击模式。 - 普通模式 / 追击模式 - 删除[追踪印记] - 冷却时间 : 5秒 [魔攻核 : 普通模式] 每秒发射魔力波动。 - 魔力波动伤害量 : 52500% - 魔力波动范围 : 200px - 移动速度 +25% - 进入霸体状态 [魔攻核 : 追击模式] 追击最强的敌人, 每秒发射魔力波动。 - 魔力波动伤害量 : 31000% - 魔力波动范围 : 200px - 对追踪目标赋予[追踪印记] [魔攻弹 : 追击模式] 攻击时, 对赋予[追踪印记]的敌人发射魔力飞弹。 - 魔力飞弹伤害量 : 11000% - 冷却时间 : 1秒 - # rarity: 史诗 - suit_247(char) - pass - - -@register -def suit_249(char: CharacterProperty): - # DCALC_REMOVE: suit_249 - 魔力领域 - 入定 - # level: 3 - # value: 操控魔攻核攻击敌人。 [魔攻核] 进入地下城时, 召唤普通模式魔攻核。 [命令 : 转换] [装备主动技能] 转换魔攻核的攻击模式。 - 普通模式 / 追击模式 - 删除[追踪印记] - 冷却时间 : 5秒 [魔攻核 : 普通模式] 每秒发射魔力波动。 - 魔力波动伤害量 : 52500% - 魔力波动范围 : 200px - 移动速度 +25% - 进入霸体状态 [魔攻核 : 追击模式] 追击最强的敌人, 每秒发射魔力波动。 - 魔力波动伤害量 : 31000% - 魔力波动范围 : 200px - 对追踪目标赋予[追踪印记] [魔攻弹 : 追击模式] 攻击时, 对赋予[追踪印记]的敌人发射魔力飞弹。 - 魔力飞弹伤害量 : 11000% - 冷却时间 : 1秒 - # rarity: 史诗 - suit_247(char) - pass - - -@register -def suit_250(char: CharacterProperty): - # DCALC_REMOVE: suit_250 - 魔力领域 - 入定 - # level: 4 - # value: 操控魔攻核攻击敌人。 [魔攻核] 进入地下城时, 召唤普通模式魔攻核。 [命令 : 转换] [装备主动技能] 转换魔攻核的攻击模式。 - 普通模式 / 追击模式 - 删除[追踪印记] - 冷却时间 : 5秒 [魔攻核 : 普通模式] 每秒发射魔力波动。 - 魔力波动伤害量 : 52500% - 魔力波动范围 : 200px - 移动速度 +25% - 进入霸体状态 [魔攻核 : 追击模式] 追击最强的敌人, 每秒发射魔力波动。 - 魔力波动伤害量 : 31000% - 魔力波动范围 : 200px - 对追踪目标赋予[追踪印记] [魔攻弹 : 追击模式] 攻击时, 对赋予[追踪印记]的敌人发射魔力飞弹。 - 魔力飞弹伤害量 : 11000% - 冷却时间 : 1秒 - # rarity: 史诗 - suit_247(char) - pass - - -@register -def suit_251(char: CharacterProperty): - # DCALC_REMOVE: suit_251 - 魔力领域 - 入定 - # level: 5 - # value: 操控魔攻核攻击敌人。 [魔攻核] 进入地下城时, 召唤普通模式魔攻核。 [命令 : 转换] [装备主动技能] 转换魔攻核的攻击模式。 - 普通模式 / 追击模式 - 删除[追踪印记] - 冷却时间 : 5秒 [魔攻核 : 普通模式] 每秒发射魔力波动。 - 魔力波动伤害量 : 52500% - 魔力波动范围 : 200px - 移动速度 +25% - 进入霸体状态 [魔攻核 : 追击模式] 追击最强的敌人, 每秒发射魔力波动。 - 魔力波动伤害量 : 31000% - 魔力波动范围 : 200px - 对追踪目标赋予[追踪印记] [魔攻弹 : 追击模式] 攻击时, 对赋予[追踪印记]的敌人发射魔力飞弹。 - 魔力飞弹伤害量 : 11000% - 冷却时间 : 1秒 - # rarity: 史诗 - suit_247(char) + char.equ_effect.append(EquEffect(name='追击模式', icon='/equipment/skill/57.png', cd=1, data=31000 + 11000)) pass @@ -2766,11 +819,11 @@ def suit_252(char: CharacterProperty): # level: 1 # value: 操控魔攻核攻击敌人。 [魔攻核] 进入地下城时, 召唤普通模式魔攻核。 [命令 : 转换] [装备主动技能] 转换魔攻核的攻击模式。 - 普通模式 / 追击模式 - 删除[追踪印记] - 冷却时间 : 5秒 [魔攻核 : 普通模式] 每秒发射魔力波动。 - 魔力波动伤害量 : 67000% - 魔力波动范围 : 300px - 移动速度 +25% - 进入霸体状态 - 所受物理/魔法伤害 -10% [魔攻核 : 追击模式] 追击最强的敌人, 每秒发射魔力波动。 - 魔力波动伤害量 : 40000% - 魔力波动范围 : 200px - 对追踪目标赋予[追踪印记] [魔攻弹 : 追击模式] 攻击时, 对赋予[追踪印记]的敌人发射魔力飞弹。 - 魔力飞弹伤害量 : 13600% - 冷却时间 : 1秒 [太初的记忆] 套装积分达到2550后,每增加70点套装积分,可以获得以下效果。 - 技能伤害 增加 1% - 增益量 +100 # rarity: 太初 - if char.equ_options.get('4',0) == 0: + if char.equ_options.get('4', 0) == 0: char.equ_effect.append(EquEffect(name='普通模式', icon='/equipment/skill/57.png', cd=1, data=67000)) char.SetStatus(SpeedM=0.25) else: - char.equ_effect.append(EquEffect(name='追击模式', icon='/equipment/skill/57.png', cd=1, data=40000+13600)) + char.equ_effect.append(EquEffect(name='追击模式', icon='/equipment/skill/57.png', cd=1, data=40000 + 13600)) pass diff --git a/backend/core/open/helper.py b/backend/core/open/helper.py index 01359612..a8c62fee 100644 --- a/backend/core/open/helper.py +++ b/backend/core/open/helper.py @@ -79,12 +79,12 @@ job_mapping = { async def get_user_info_by_id(user_id: str, alter: AltersDep): if alter is None: - raise ResponseException("登录过期或无效Token,请刷新后重试") + raise ResponseException('登录过期或无效Token,请刷新后重试') name = next((k for k, v in job_mapping.items() if v == alter.origin), '') # 通过OCR助手获取用户信息 helper_info = await get_main_user_info_by_id(user_id, name) if helper_info is None: - raise ResponseException("当前助手ID不存在或已隐藏,请确认后重试") + raise ResponseException('当前助手ID不存在或已隐藏,请确认后重试') else: return trans_to_dcalc_set(helper_info, alter) pass @@ -93,7 +93,7 @@ async def get_user_info_by_id(user_id: str, alter: AltersDep): def trans_to_dcalc_set(detail, alter: AltersDep): job = job_mapping.get(detail.get('job', ''), '') if job != alter.origin: - raise ResponseException("未能匹配到当前职业对应的角色信息,请确认后重试") + raise ResponseException('未能匹配到当前职业对应的角色信息,请确认后重试') basic = get_equipment('0') basicAvatars = basic.funs.get_dress_list([]) equs = detail.get('equs', []) @@ -126,9 +126,9 @@ def trans_to_dcalc_set(detail, alter: AltersDep): # 贴膜 if dcalcEqu: info['id'] = dcalcEqu.id - dcalcEquFusion = next((item for item in basic.stones if item.name == equ.get('upgrade', '')), None) - if dcalcEquFusion: - info['fusion'] = dcalcEquFusion.id + # dcalcEquFusion = next((item for item in basic.stones if item.name == equ.get('upgrade', '')), None) + # if dcalcEquFusion: + # info['fusion'] = dcalcEquFusion.id info['enchant'] = getEnchatIdByName(equ.get('enchant', ''), equ.get('posName', ''), basic.enchants) emblems = [getEmblemIdByName(i.get('detail', ''), i.get('categorize', ''), i.get('rarity', ''), basic.emblems) for i in equ.get('emblems', [])] info['emblem_0'] = emblems[0] if len(emblems) > 0 else 0 @@ -167,7 +167,7 @@ def trans_to_dcalc_set(detail, alter: AltersDep): if item.get('posName', '') == '皮肤': match = re.search(r'\[(\d+)级\]', item.get('name', '')) lv = int(match.group(1)) if match else None - if lv : + if lv: item['enchant'] = f'Lv{lv}主动+1|全属强(12)|四维(55)' if item.get('posName', '') == '光环': # 先默认这个了 不管了 @@ -182,11 +182,14 @@ def trans_to_dcalc_set(detail, alter: AltersDep): 'equips': equips, 'avatars': avatar, 'avatarLink': detail.get('avatarLink', ''), - 'dressInfo': [{ - 'dress': i.get('name', ''), - 'clone': i.get('clone', ''), - 'part': i.get('posName', ''), - } for i in detail.get('avatars', [])] + 'dressInfo': [ + { + 'dress': i.get('name', ''), + 'clone': i.get('clone', ''), + 'part': i.get('posName', ''), + } + for i in detail.get('avatars', []) + ], } # 处理装备 # 处理时装 diff --git a/backend/dataFiles/dcalc_0.db b/backend/dataFiles/dcalc_0.db index 04374e7b..32cfc0fc 100644 Binary files a/backend/dataFiles/dcalc_0.db and b/backend/dataFiles/dcalc_0.db differ diff --git a/backend/database/models.py b/backend/database/models.py index 639afed3..bddce708 100644 --- a/backend/database/models.py +++ b/backend/database/models.py @@ -2,7 +2,7 @@ # import sys from sqlalchemy import Column, Integer, Text, Float from sqlalchemy import create_engine -from sqlalchemy.orm import Session,declarative_base +from sqlalchemy.orm import Session, declarative_base Base = declarative_base() metadata = Base.metadata @@ -16,17 +16,17 @@ class SuitData(Base): suitName = Column(Text) rarity = Column(Text) name = Column(Text) - point = Column(Integer) - level = Column(Integer) + point = Column(Text) count = Column(Integer) - SkillAttack = Column(Float) - Attack = Column(Float) - Buffer = Column(Float) + SkillAttack = Column(Text) + Attack = Column(Text) + Buffer = Column(Text) imageUrl = Column(Text) value = Column(Text) bufferValue = Column(Text) fame = Column(Integer) + class EquData(Base): """ 装备属性映射 @@ -57,6 +57,7 @@ class EquData(Base): Buffer = Column(Text) suit = Column(Text) + class StoneData(Base): """ 装备属性映射 @@ -87,6 +88,7 @@ class StoneData(Base): Buffer = Column(Text) suit = Column(Text) + class EnchantData(Base): __tablename__ = 'enchant' @@ -97,15 +99,18 @@ class EnchantData(Base): fame = Column(Integer) rarity = Column(Text) + class EmblemData(Base): __tablename__ = 'emblem' id = Column(Integer, primary_key=True) - detail = Column(Text) - categorize = Column(Integer) - itemType = Column(Text) - fame = Column(Integer) + rarityId = Column(Integer) rarity = Column(Text) + typeId = Column(Integer) + type = Column(Text) + value = Column(Text) + fame = Column(Integer) + class JadeData(Base): __tablename__ = 'jade' @@ -117,11 +122,13 @@ class JadeData(Base): unit = Column(Text) pre = Column(Float) + class OathData(Base): """ 誓约属性映射 首字母大写的属性为调适可能会影响到的属性 """ + __tablename__ = 'oath' id = Column(Integer, primary_key=True) @@ -129,6 +136,8 @@ class OathData(Base): rarity = Column(Text) position = Column(Text) Point = Column(Integer) + itemType = Column(Text) + itemDetailType = Column(Text) categorize = Column(Text) imageUrl = Column(Text) detail = Column(Text) @@ -146,17 +155,21 @@ class OathData(Base): suit = Column(Text) wearUrl = Column(Text) + class PrimerData(Base): """ 誓约属性映射 首字母大写的属性为调适可能会影响到的属性 """ + __tablename__ = 'primer' id = Column(Integer, primary_key=True) name = Column(Text) rarity = Column(Text) position = Column(Text) + itemType = Column(Text) + itemDetailType = Column(Text) Point = Column(Integer) categorize = Column(Text) imageUrl = Column(Text) @@ -175,6 +188,7 @@ class PrimerData(Base): suit = Column(Text) wearUrl = Column(Text) + class OathSuitData(Base): __tablename__ = 'oathSuit' @@ -191,6 +205,7 @@ class OathSuitData(Base): Attack = Column(Text) Buffer = Column(Text) + class OathSuitSkillData(Base): __tablename__ = 'oathSuitSkill' @@ -205,4 +220,4 @@ class OathSuitSkillData(Base): Attack = Column(Float) Buffer = Column(Float) value = Column(Text) - bufferValue = Column(Text) \ No newline at end of file + bufferValue = Column(Text) diff --git a/backend/generate/equ.py b/backend/generate/equ.py index e46b1dca..6b8a0bcc 100644 --- a/backend/generate/equ.py +++ b/backend/generate/equ.py @@ -1,5 +1,5 @@ from database.connect import get_db_engine as get_engine -from database.models import Session, EquData, SuitData +from database.models import Session, EquData engine = get_engine('0') diff --git a/backend/go/README.md b/backend/go/README.md new file mode 100644 index 00000000..6d7e37dc --- /dev/null +++ b/backend/go/README.md @@ -0,0 +1,53 @@ +# dcalc Go 重构骨架 + +这个目录是对现有 Python 后端的并行 Go 重构,不直接替换原服务。 + +当前已迁移: + +- 通用响应结构与 HTTP 入口 +- CORS、压缩、中间件基础设施 +- 冒险团职业列表与 token 生成 +- openapi 静态数据读取接口 +- 基于 alter_token 的技能详情接口 +- colg 金价查询接口 +- /api/character 静态职业与装备目录信息 +- /api/skillTree/ 编码解码逻辑(Go 实现) +- Python 适配层(职业工厂依赖收口) + +兼容性说明: + +- jobInfo 接口保持与 Python 一致,返回目录名风格的 jobId 和 jobGrowId +- skills 和 skillDetail 路由同时兼容目录名参数与 Neople UUID 参数 + +当前未迁移: + +- 角色构建与伤害计算公式本体 +- DNFHelper 集成 +- MCP 服务 + +当前架构: + +- skillTree 的 base64/zlib/binary 解码已经迁移到 Go +- createCharacter 依赖通过 go/python_bridge.py 适配层收口 +- calc 域已拆出 CharacterFactory 与 EquipmentCatalogRepository 边界,便于后续逐步替换 Python 依赖 + +运行: + +```bash +cd go +go run ./cmd/dcalc +``` + +可选环境变量: + +- PORT +- DEBUG_MODE +- COLG_TOKEN +- HELPER_TOKEN +- HELPER_ID + +建议迁移顺序: + +1. 先把 createCharacter 工厂后的领域模型拆成 Go interface 和 package。 +2. 再迁装备/套装/技能数据库读取层。 +3. 最后逐职业迁技能公式与计算逻辑。 diff --git a/backend/go/cmd/dcalc/main.go b/backend/go/cmd/dcalc/main.go new file mode 100644 index 00000000..1ca45b94 --- /dev/null +++ b/backend/go/cmd/dcalc/main.go @@ -0,0 +1,52 @@ +package main + +import ( + "log" + "net/http" + + "dcalc-go/internal/config" + "dcalc-go/internal/httpserver" + "dcalc-go/internal/service" +) + +func main() { + cfg, err := config.Load() + if err != nil { + log.Fatalf("load config: %v", err) + } + + cache := service.NewCache() + adventureService, err := service.NewAdventureService(cfg.ProjectRoot, cache) + if err != nil { + log.Fatalf("load adventure data: %v", err) + } + + openAPIService := service.NewOpenAPIService(cfg.ProjectRoot, cache, adventureService) + colgService := service.NewColgService(cache, cfg) + tokenService := service.NewTokenService(adventureService) + characterFactory := service.NewPythonCharacterFactory(cfg) + characterService := service.NewCharacterService(cache, characterFactory) + skillTreeService, err := service.NewSkillTreeService(cfg.ProjectRoot, adventureService, characterFactory) + if err != nil { + log.Fatalf("load skill tree service: %v", err) + } + equipmentRepository := service.NewSQLiteEquipmentCatalogRepository(cfg.ProjectRoot) + calcService := service.NewCalcService(characterFactory, equipmentRepository) + + router := httpserver.NewRouter(httpserver.Dependencies{ + Config: cfg, + AdventureService: adventureService, + OpenAPIService: openAPIService, + ColgService: colgService, + TokenService: tokenService, + CharacterService: characterService, + SkillTreeService: skillTreeService, + CalcService: calcService, + }) + + addr := ":" + cfg.Port + log.Printf("dcalc go server listening on %s", addr) + if err := http.ListenAndServe(addr, router); err != nil { + log.Fatalf("listen and serve: %v", err) + } +} diff --git a/backend/go/go.mod b/backend/go/go.mod new file mode 100644 index 00000000..f73c8732 --- /dev/null +++ b/backend/go/go.mod @@ -0,0 +1,20 @@ +module dcalc-go + +go 1.25.0 + +require ( + github.com/go-chi/chi/v5 v5.2.3 + modernc.org/sqlite v1.48.0 +) + +require ( + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/ncruces/go-strftime v1.0.0 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect + golang.org/x/sys v0.42.0 // indirect + modernc.org/libc v1.70.0 // indirect + modernc.org/mathutil v1.7.1 // indirect + modernc.org/memory v1.11.0 // indirect +) diff --git a/backend/go/go.sum b/backend/go/go.sum new file mode 100644 index 00000000..3a9318dc --- /dev/null +++ b/backend/go/go.sum @@ -0,0 +1,53 @@ +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/go-chi/chi/v5 v5.2.3 h1:WQIt9uxdsAbgIYgid+BpYc+liqQZGMHRaUwp0JUcvdE= +github.com/go-chi/chi/v5 v5.2.3/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops= +github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs= +github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w= +github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= +golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= +golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= +golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= +modernc.org/cc/v4 v4.27.1 h1:9W30zRlYrefrDV2JE2O8VDtJ1yPGownxciz5rrbQZis= +modernc.org/cc/v4 v4.27.1/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0= +modernc.org/ccgo/v4 v4.32.0 h1:hjG66bI/kqIPX1b2yT6fr/jt+QedtP2fqojG2VrFuVw= +modernc.org/ccgo/v4 v4.32.0/go.mod h1:6F08EBCx5uQc38kMGl+0Nm0oWczoo1c7cgpzEry7Uc0= +modernc.org/fileutil v1.4.0 h1:j6ZzNTftVS054gi281TyLjHPp6CPHr2KCxEXjEbD6SM= +modernc.org/fileutil v1.4.0/go.mod h1:EqdKFDxiByqxLk8ozOxObDSfcVOv/54xDs/DUHdvCUU= +modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI= +modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito= +modernc.org/gc/v3 v3.1.2 h1:ZtDCnhonXSZexk/AYsegNRV1lJGgaNZJuKjJSWKyEqo= +modernc.org/gc/v3 v3.1.2/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY= +modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks= +modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI= +modernc.org/libc v1.70.0 h1:U58NawXqXbgpZ/dcdS9kMshu08aiA6b7gusEusqzNkw= +modernc.org/libc v1.70.0/go.mod h1:OVmxFGP1CI/Z4L3E0Q3Mf1PDE0BucwMkcXjjLntvHJo= +modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU= +modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg= +modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI= +modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw= +modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8= +modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns= +modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w= +modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE= +modernc.org/sqlite v1.48.0 h1:ElZyLop3Q2mHYk5IFPPXADejZrlHu7APbpB0sF78bq4= +modernc.org/sqlite v1.48.0/go.mod h1:hWjRO6Tj/5Ik8ieqxQybiEOUXy0NJFNp2tpvVpKlvig= +modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0= +modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A= +modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= +modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= diff --git a/backend/go/internal/config/config.go b/backend/go/internal/config/config.go new file mode 100644 index 00000000..4d9d881c --- /dev/null +++ b/backend/go/internal/config/config.go @@ -0,0 +1,90 @@ +package config + +import ( + "fmt" + "os" + "path/filepath" + "strconv" +) + +type Config struct { + Port string + DebugMode bool + ColgToken string + HelperToken string + HelperID string + PythonExec string + ProjectRoot string +} + +func Load() (Config, error) { + projectRoot, err := detectProjectRoot() + if err != nil { + return Config{}, err + } + + return Config{ + Port: envOrDefault("PORT", "27173"), + DebugMode: envBoolOrDefault("DEBUG_MODE", true), + ColgToken: os.Getenv("COLG_TOKEN"), + HelperToken: os.Getenv("HELPER_TOKEN"), + HelperID: os.Getenv("HELPER_ID"), + PythonExec: pythonExecOrDefault(projectRoot), + ProjectRoot: projectRoot, + }, nil +} + +func pythonExecOrDefault(projectRoot string) string { + if value := os.Getenv("PYTHON_EXEC"); value != "" { + return value + } + venvPython := filepath.Join(projectRoot, ".venv", "bin", "python") + if fileExists(venvPython) { + return venvPython + } + return "python3" +} + +func detectProjectRoot() (string, error) { + wd, err := os.Getwd() + if err != nil { + return "", err + } + + current := wd + for { + if fileExists(filepath.Join(current, "openapi", "jobs.json")) { + return current, nil + } + + parent := filepath.Dir(current) + if parent == current { + return "", fmt.Errorf("unable to locate project root from %s", wd) + } + current = parent + } +} + +func fileExists(path string) bool { + _, err := os.Stat(path) + return err == nil +} + +func envOrDefault(key, fallback string) string { + if value := os.Getenv(key); value != "" { + return value + } + return fallback +} + +func envBoolOrDefault(key string, fallback bool) bool { + value := os.Getenv(key) + if value == "" { + return fallback + } + parsed, err := strconv.ParseBool(value) + if err != nil { + return fallback + } + return parsed +} diff --git a/backend/go/internal/httpserver/router.go b/backend/go/internal/httpserver/router.go new file mode 100644 index 00000000..22312201 --- /dev/null +++ b/backend/go/internal/httpserver/router.go @@ -0,0 +1,301 @@ +package httpserver + +import ( + "encoding/json" + "errors" + "io" + "net/http" + "strconv" + "strings" + + "github.com/go-chi/chi/v5" + "github.com/go-chi/chi/v5/middleware" + + "dcalc-go/internal/config" + "dcalc-go/internal/model" + "dcalc-go/internal/service" +) + +type Dependencies struct { + Config config.Config + AdventureService *service.AdventureService + OpenAPIService *service.OpenAPIService + ColgService *service.ColgService + TokenService *service.TokenService + CharacterService *service.CharacterService + SkillTreeService *service.SkillTreeService + CalcService *service.CalcService +} + +func NewRouter(dep Dependencies) http.Handler { + r := chi.NewRouter() + r.Use(middleware.RequestID) + r.Use(middleware.RealIP) + r.Use(middleware.Logger) + r.Use(middleware.Recoverer) + r.Use(middleware.Compress(5, "application/json")) + r.Use(cors) + + r.Get("/healthz", func(w http.ResponseWriter, _ *http.Request) { + writeJSON(w, http.StatusOK, model.Success(map[string]any{"service": "dcalc-go", "debug": dep.Config.DebugMode})) + }) + + r.Route("/api", func(r chi.Router) { + r.Get("/adventure", func(w http.ResponseWriter, r *http.Request) { + data, err := dep.AdventureService.AdventureList() + if err != nil { + writeError(w, http.StatusInternalServerError, err) + return + } + writeJSON(w, http.StatusOK, model.Success(data)) + }) + + r.Get("/token/get/{alter}", func(w http.ResponseWriter, r *http.Request) { + token, err := dep.TokenService.Create(chi.URLParam(r, "alter"), r.URL.Query().Get("equVersion")) + if err != nil { + writeJSON(w, http.StatusBadRequest, model.Error(400, err.Error(), nil)) + return + } + writeJSON(w, http.StatusOK, model.Success(token)) + }) + + r.Get("/character", func(w http.ResponseWriter, r *http.Request) { + payload, ok := requireAlterToken(w, r, dep.TokenService) + if !ok { + return + } + data, err := dep.CharacterService.StaticInfo(payload.Alter, payload.EquVersion) + if err != nil { + writeError(w, http.StatusInternalServerError, err) + return + } + writeJSON(w, http.StatusOK, model.Success(data)) + }) + + r.Post("/calc", func(w http.ResponseWriter, r *http.Request) { + payload, ok := requireAlterToken(w, r, dep.TokenService) + if !ok { + return + } + + var body map[string]any + if err := json.NewDecoder(r.Body).Decode(&body); err != nil && !errors.Is(err, io.EOF) && !errors.Is(err, http.ErrBodyNotAllowed) { + writeJSON(w, http.StatusBadRequest, model.Error(400, "invalid request body", nil)) + return + } + + data, err := dep.CalcService.Calculate(payload.Alter, payload.EquVersion, body) + if err != nil { + writeNotImplemented(w, err) + return + } + writeJSON(w, http.StatusOK, model.Success(data)) + }) + + r.Get("/skill/{skillId}/{level}", func(w http.ResponseWriter, r *http.Request) { + payload, ok := requireAlterToken(w, r, dep.TokenService) + if !ok { + return + } + level, err := strconv.Atoi(chi.URLParam(r, "level")) + if err != nil { + writeJSON(w, http.StatusBadRequest, model.Error(400, "level must be an integer", nil)) + return + } + data, err := dep.OpenAPIService.SkillDetailByAlter(payload.Alter, chi.URLParam(r, "skillId"), level) + if err != nil { + writeJSON(w, http.StatusNotFound, model.Error(404, err.Error(), nil)) + return + } + writeJSON(w, http.StatusOK, model.Success(data)) + }) + + r.Get("/dnfhelper/{uid}/", func(w http.ResponseWriter, _ *http.Request) { + writeJSON(w, http.StatusNotImplemented, model.Error(501, "dnfhelper integration is pending migration", nil)) + }) + + r.Post("/skillTree/", func(w http.ResponseWriter, r *http.Request) { + payload, ok := requireAlterToken(w, r, dep.TokenService) + if !ok { + return + } + + var body map[string]any + if err := json.NewDecoder(r.Body).Decode(&body); err != nil && !errors.Is(err, io.EOF) { + writeJSON(w, http.StatusBadRequest, model.Error(400, "invalid request body", nil)) + return + } + code, _ := body["code"].(string) + result, err := dep.SkillTreeService.Parse(code, payload.EquVersion) + if err != nil { + writeJSON(w, http.StatusInternalServerError, model.Error(500, "解析技能加点失败", nil)) + return + } + if result.Job["class"] != payload.Alter { + writeJSON(w, http.StatusInternalServerError, model.Error(500, "技能加点代码职业与登录职业不匹配", nil)) + return + } + writeJSON(w, http.StatusOK, model.Success(result)) + }) + + r.Route("/open", func(r chi.Router) { + r.Get("/skills/", func(w http.ResponseWriter, r *http.Request) { + data, err := dep.OpenAPIService.SearchSkills(r.URL.Query().Get("skillName")) + if err != nil { + writeError(w, http.StatusInternalServerError, err) + return + } + writeJSON(w, http.StatusOK, model.Success(data)) + }) + + r.Get("/jobInfo/", func(w http.ResponseWriter, r *http.Request) { + data, err := dep.OpenAPIService.JobsInfo(r.URL.Query().Get("jobName")) + if err != nil { + writeError(w, http.StatusInternalServerError, err) + return + } + writeJSON(w, http.StatusOK, model.Success(data)) + }) + + r.Get("/skillData/summary/", func(w http.ResponseWriter, r *http.Request) { + data, err := dep.OpenAPIService.SkillDataSummary( + r.URL.Query().Get("job"), + splitCSV(r.URL.Query().Get("skills")), + splitCSV(r.URL.Query().Get("weapons")), + ) + if err != nil { + writeError(w, http.StatusInternalServerError, err) + return + } + writeJSON(w, http.StatusOK, model.Success(data)) + }) + + r.Get("/gold/realtime/", func(w http.ResponseWriter, r *http.Request) { + data, err := dep.ColgService.RealTimeGold(r.Context()) + if err != nil { + writeError(w, http.StatusBadGateway, err) + return + } + writeJSON(w, http.StatusOK, model.Success(data)) + }) + + r.Get("/gold/history/", func(w http.ResponseWriter, r *http.Request) { + region, err := strconv.Atoi(r.URL.Query().Get("region")) + if err != nil { + writeJSON(w, http.StatusBadRequest, model.Error(400, "region must be an integer", nil)) + return + } + timeRange := 7 + if raw := r.URL.Query().Get("timeRange"); raw != "" { + parsed, err := strconv.Atoi(raw) + if err != nil { + writeJSON(w, http.StatusBadRequest, model.Error(400, "timeRange must be an integer", nil)) + return + } + timeRange = parsed + } + + data, err := dep.ColgService.HistoryGold(r.Context(), region, timeRange) + if err != nil { + writeJSON(w, http.StatusBadRequest, model.Error(404, err.Error(), nil)) + return + } + writeJSON(w, http.StatusOK, model.Success(data)) + }) + + r.Get("/gold/official/", func(w http.ResponseWriter, r *http.Request) { + data, err := dep.ColgService.OfficialGold(r.Context()) + if err != nil { + writeError(w, http.StatusBadGateway, err) + return + } + writeJSON(w, http.StatusOK, model.Success(data)) + }) + + r.Get("/{jobId}/{jobGrowId}/skills/", func(w http.ResponseWriter, r *http.Request) { + data, err := dep.OpenAPIService.SkillsByJob(chi.URLParam(r, "jobId"), chi.URLParam(r, "jobGrowId")) + if err != nil { + writeError(w, http.StatusNotFound, err) + return + } + writeJSON(w, http.StatusOK, model.Success(data)) + }) + + r.Get("/{jobId}/{jobGrowId}/{skillId}/", func(w http.ResponseWriter, r *http.Request) { + var level *int + if raw := r.URL.Query().Get("level"); raw != "" { + parsed, err := strconv.Atoi(raw) + if err != nil { + writeJSON(w, http.StatusBadRequest, model.Error(400, "level must be an integer", nil)) + return + } + level = &parsed + } + data, err := dep.OpenAPIService.SkillDetail(chi.URLParam(r, "jobId"), chi.URLParam(r, "jobGrowId"), chi.URLParam(r, "skillId"), level) + if err != nil { + writeJSON(w, http.StatusNotFound, model.Error(404, err.Error(), nil)) + return + } + writeJSON(w, http.StatusOK, model.Success(data)) + }) + }) + }) + + return r +} + +func requireAlterToken(w http.ResponseWriter, r *http.Request, tokens *service.TokenService) (service.AlterTokenPayload, bool) { + token := r.Header.Get("alter_token") + if token == "" { + writeJSON(w, http.StatusUnauthorized, model.Error(401, "missing alter_token header", nil)) + return service.AlterTokenPayload{}, false + } + payload, err := tokens.Parse(token) + if err != nil { + writeJSON(w, http.StatusUnauthorized, model.Error(401, "invalid alter_token header", nil)) + return service.AlterTokenPayload{}, false + } + return payload, true +} + +func writeNotImplemented(w http.ResponseWriter, err error) { + writeJSON(w, http.StatusNotImplemented, model.Error(501, err.Error(), nil)) +} + +func writeError(w http.ResponseWriter, status int, err error) { + writeJSON(w, status, model.Error(status, err.Error(), nil)) +} + +func writeJSON(w http.ResponseWriter, status int, payload model.Envelope) { + w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.WriteHeader(status) + _ = json.NewEncoder(w).Encode(payload) +} + +func cors(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Access-Control-Allow-Origin", "*") + w.Header().Set("Access-Control-Allow-Headers", "Content-Type, alter_token") + w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS") + if r.Method == http.MethodOptions { + w.WriteHeader(http.StatusNoContent) + return + } + next.ServeHTTP(w, r) + }) +} + +func splitCSV(value string) []string { + if value == "" { + return nil + } + parts := strings.Split(value, ",") + result := make([]string, 0, len(parts)) + for _, part := range parts { + trimmed := strings.TrimSpace(part) + if trimmed != "" { + result = append(result, trimmed) + } + } + return result +} diff --git a/backend/go/internal/model/response.go b/backend/go/internal/model/response.go new file mode 100644 index 00000000..d7529c16 --- /dev/null +++ b/backend/go/internal/model/response.go @@ -0,0 +1,15 @@ +package model + +type Envelope struct { + Code int `json:"code"` + Message string `json:"message"` + Data any `json:"data"` +} + +func Success(data any) Envelope { + return Envelope{Code: 200, Message: "Success", Data: data} +} + +func Error(code int, message string, data any) Envelope { + return Envelope{Code: code, Message: message, Data: data} +} diff --git a/backend/go/internal/service/adventure.go b/backend/go/internal/service/adventure.go new file mode 100644 index 00000000..036c6bf7 --- /dev/null +++ b/backend/go/internal/service/adventure.go @@ -0,0 +1,137 @@ +package service + +import ( + "encoding/base64" + "encoding/json" + "fmt" + "os" + "path/filepath" + "strings" + "time" +) + +type AdventureService struct { + projectRoot string + cache *Cache + jobs []Job + tokenToJob map[string]string +} + +type Job struct { + Name string `json:"name"` + JobID string `json:"jobId"` + Title string `json:"title"` + Children []JobChild `json:"children"` +} + +type JobChild struct { + Name string `json:"name"` + JobGrowID string `json:"jobGrowId"` + Title string `json:"title"` +} + +type AdventureParent struct { + ID int `json:"id"` + Name string `json:"name"` + Title string `json:"title"` + Children []AdventureChild `json:"children"` +} + +type AdventureChild struct { + ID int `json:"id"` + Name string `json:"name"` + Title string `json:"title"` + Open bool `json:"open"` + Value string `json:"value"` +} + +func NewAdventureService(projectRoot string, cache *Cache) (*AdventureService, error) { + jobsPath := filepath.Join(projectRoot, "openapi", "jobs.json") + content, err := os.ReadFile(jobsPath) + if err != nil { + return nil, err + } + + var jobs []Job + if err := json.Unmarshal(content, &jobs); err != nil { + return nil, err + } + + svc := &AdventureService{ + projectRoot: projectRoot, + cache: cache, + jobs: jobs, + tokenToJob: make(map[string]string), + } + + for parentIndex, parent := range jobs { + for childIndex, child := range parent.Children { + token := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%02d%02d00", parentIndex, childIndex))) + svc.tokenToJob[token] = "GF." + parent.Name + "." + child.Name + } + } + + return svc, nil +} + +func (s *AdventureService) Jobs() []Job { + jobs := make([]Job, len(s.jobs)) + copy(jobs, s.jobs) + return jobs +} + +func (s *AdventureService) AdventureList() ([]AdventureParent, error) { + return GetOrLoad(s.cache, "adventure:list", 10*time.Minute, func() ([]AdventureParent, error) { + result := make([]AdventureParent, 0, len(s.jobs)) + for parentIndex, parent := range s.jobs { + children := make([]AdventureChild, 0, len(parent.Children)) + for childIndex, child := range parent.Children { + children = append(children, AdventureChild{ + ID: childIndex, + Name: child.Name, + Title: child.Title, + Open: true, + Value: base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%02d%02d00", parentIndex, childIndex))), + }) + } + result = append(result, AdventureParent{ + ID: parentIndex, + Name: parent.Name, + Title: parent.Title, + Children: children, + }) + } + return result, nil + }) +} + +func (s *AdventureService) AlterByToken(token string) (string, error) { + alter, ok := s.tokenToJob[token] + if !ok { + return "", fmt.Errorf("invalid adventure token") + } + return alter, nil +} + +func (s *AdventureService) ResolveDirectories(jobIdentifier string, jobGrowIdentifier string) (string, string, error) { + for _, job := range s.jobs { + jobMatched := jobIdentifier == job.Name || jobIdentifier == job.JobID + if !jobMatched { + continue + } + for _, child := range job.Children { + if jobGrowIdentifier == child.Name || jobGrowIdentifier == child.JobGrowID { + return job.Name, child.Name, nil + } + } + } + return "", "", fmt.Errorf("unknown job path: %s/%s", jobIdentifier, jobGrowIdentifier) +} + +func (s *AdventureService) DirectoriesFromAlter(alter string) (string, string, error) { + parts := strings.Split(alter, ".") + if len(parts) != 3 || parts[0] != "GF" { + return "", "", fmt.Errorf("invalid alter value: %s", alter) + } + return parts[1], parts[2], nil +} diff --git a/backend/go/internal/service/cache.go b/backend/go/internal/service/cache.go new file mode 100644 index 00000000..0e0ce5d7 --- /dev/null +++ b/backend/go/internal/service/cache.go @@ -0,0 +1,44 @@ +package service + +import ( + "sync" + "time" +) + +type Cache struct { + mu sync.RWMutex + items map[string]cacheItem +} + +type cacheItem struct { + value any + expiresAt time.Time +} + +func NewCache() *Cache { + return &Cache{items: make(map[string]cacheItem)} +} + +func GetOrLoad[T any](cache *Cache, key string, ttl time.Duration, loader func() (T, error)) (T, error) { + var zero T + + cache.mu.RLock() + item, ok := cache.items[key] + cache.mu.RUnlock() + if ok && (item.expiresAt.IsZero() || item.expiresAt.After(time.Now())) { + if value, castOK := item.value.(T); castOK { + return value, nil + } + } + + value, err := loader() + if err != nil { + return zero, err + } + + cache.mu.Lock() + cache.items[key] = cacheItem{value: value, expiresAt: time.Now().Add(ttl)} + cache.mu.Unlock() + + return value, nil +} diff --git a/backend/go/internal/service/calc.go b/backend/go/internal/service/calc.go new file mode 100644 index 00000000..c5e981dd --- /dev/null +++ b/backend/go/internal/service/calc.go @@ -0,0 +1,34 @@ +package service + +import "errors" + +var ErrNotImplemented = errors.New("calculation domain has not been migrated to Go yet") + +type EquipmentCatalogRepository interface { + Catalog(alter string, equVersion string) (map[string]any, error) +} + +type CalcService struct { + factory CharacterFactory + equipment EquipmentCatalogRepository +} + +func NewCalcService(factory CharacterFactory, equipment EquipmentCatalogRepository) *CalcService { + return &CalcService{factory: factory, equipment: equipment} +} + +func (s *CalcService) CharacterInfo(alter string, equVersion string) (any, error) { + return s.factory.CharacterInfo(alter, equVersion) +} + +func (s *CalcService) Calculate(_ string, _ string, _ map[string]any) (any, error) { + return nil, ErrNotImplemented +} + +func (s *CalcService) SkillTree(_ string, _ string) (any, error) { + return nil, ErrNotImplemented +} + +func (s *CalcService) DNFHelper(_ string, _ string) (any, error) { + return nil, ErrNotImplemented +} diff --git a/backend/go/internal/service/character.go b/backend/go/internal/service/character.go new file mode 100644 index 00000000..64dc0151 --- /dev/null +++ b/backend/go/internal/service/character.go @@ -0,0 +1,21 @@ +package service + +import ( + "time" +) + +type CharacterService struct { + cache *Cache + factory CharacterFactory +} + +func NewCharacterService(cache *Cache, factory CharacterFactory) *CharacterService { + return &CharacterService{cache: cache, factory: factory} +} + +func (s *CharacterService) StaticInfo(alter string, equVersion string) (map[string]any, error) { + key := "character:static:" + alter + ":" + equVersion + return GetOrLoad(s.cache, key, 15*time.Minute, func() (map[string]any, error) { + return s.factory.CharacterInfo(alter, equVersion) + }) +} diff --git a/backend/go/internal/service/colg.go b/backend/go/internal/service/colg.go new file mode 100644 index 00000000..30dad321 --- /dev/null +++ b/backend/go/internal/service/colg.go @@ -0,0 +1,304 @@ +package service + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "net/url" + "strconv" + "strings" + "time" + + "dcalc-go/internal/config" +) + +type ColgService struct { + cache *Cache + config config.Config + client *http.Client +} + +var regionMap = map[string]int{ + "跨1": 1, + "跨2": 2, + "跨3A": 3, + "跨3B": 4, + "跨4": 5, + "跨5": 6, + "跨6": 7, + "跨7": 8, +} + +func NewColgService(cache *Cache, cfg config.Config) *ColgService { + return &ColgService{ + cache: cache, + config: cfg, + client: &http.Client{Timeout: 12 * time.Second}, + } +} + +func (s *ColgService) RealTimeGold(ctx context.Context) ([]map[string]any, error) { + if s.config.ColgToken == "" { + return nil, fmt.Errorf("COLG_TOKEN is required") + } + + return GetOrLoad(s.cache, "colg:realtime", 30*time.Minute, func() ([]map[string]any, error) { + result := make([]map[string]any, 0, len(regionMap)) + now := time.Now().Format("2006-01-02") + for regionName, regionID := range regionMap { + data, err := s.requestTrendData(ctx, regionID, now, now) + if err != nil { + return nil, err + } + xValues, _ := data["x"].([]any) + yValues, _ := data["y"].([]any) + if len(xValues) == 0 || len(yValues) == 0 { + continue + } + result = append(result, map[string]any{ + "updataTime": formatBeijingTime(int64FromAny(xValues[len(xValues)-1])), + "region": regionName, + "goldPrice": float64FromAny(yValues[len(yValues)-1]), + }) + } + return result, nil + }) +} + +func (s *ColgService) HistoryGold(ctx context.Context, region int, timeRange int) (map[string]any, error) { + if s.config.ColgToken == "" { + return nil, fmt.Errorf("COLG_TOKEN is required") + } + if timeRange <= 0 { + timeRange = 7 + } + + regionName := "" + for name, id := range regionMap { + if id == region { + regionName = name + break + } + } + if regionName == "" { + return nil, fmt.Errorf("invalid region") + } + + endDate := time.Now() + startDate := endDate.AddDate(0, 0, -(timeRange - 1)) + trend, err := s.requestTrendData(ctx, region, startDate.Format("2006-01-02"), endDate.Format("2006-01-02")) + if err != nil { + return nil, err + } + + xValues, _ := trend["x"].([]any) + yValues, _ := trend["y"].([]any) + y1Values, _ := trend["y1"].([]any) + rows := make([]map[string]any, 0, len(xValues)) + minValue := 0.0 + maxValue := 0.0 + for index := range xValues { + avg := float64FromAny(yValues[index]) + zero := float64FromAny(y1Values[index]) + if index == 0 || avg < minValue { + minValue = avg + } + if zero < minValue { + minValue = zero + } + if index == 0 || avg > maxValue { + maxValue = avg + } + if zero > maxValue { + maxValue = zero + } + rows = append(rows, map[string]any{ + "date": strings.Split(formatBeijingTime(int64FromAny(xValues[index])), " ")[0], + "avg": avg, + "zero": zero, + }) + } + + title := fmt.Sprintf("DNF%s近%d天金币价格趋势分析", regionName, timeRange) + echarts := map[string]any{ + "title": map[string]any{"text": title, "left": "center"}, + "toolbox": map[string]any{"feature": map[string]any{"saveAsImage": map[string]any{}, "dataView": map[string]any{"readOnly": true}, "magicType": map[string]any{"type": []string{"line", "bar"}}}}, + "tooltip": map[string]any{"trigger": "axis", "axisPointer": map[string]any{"type": "cross", "label": map[string]any{"backgroundColor": "#6a7985"}}}, + "legend": map[string]any{"data": []string{"平均金价", "12时金价"}, "bottom": 0}, + "xAxis": map[string]any{"type": "category", "name": "日期", "boundaryGap": false, "data": extractField(rows, "date")}, + "yAxis": map[string]any{"type": "value", "name": "价格 (万金币/1人民币)", "min": floorToFive(minValue), "max": floorToFive(maxValue) + 5, "axisLabel": map[string]any{"formatter": "{value} 万金币"}}, + "series": []map[string]any{ + {"name": "平均金价", "type": "line", "smooth": true, "data": extractField(rows, "avg"), "markPoint": map[string]any{"data": []map[string]any{{"type": "max", "name": "最大值"}, {"type": "min", "name": "最小值"}}}}, + {"name": "12时金价", "type": "line", "smooth": true, "data": extractField(rows, "zero"), "markLine": map[string]any{"data": []map[string]any{{"type": "average", "name": "平均值"}}}}, + }, + } + + return map[string]any{"region": regionName, "data": rows, "echartsData": echarts}, nil +} + +func (s *ColgService) OfficialGold(ctx context.Context) ([]map[string]any, error) { + if s.config.HelperToken == "" || s.config.HelperID == "" { + return nil, fmt.Errorf("HELPER_TOKEN and HELPER_ID are required") + } + + return GetOrLoad(s.cache, "colg:official", 30*time.Minute, func() ([]map[string]any, error) { + servers := []string{"1", "2", "3A", "3B", "4", "5", "6", "7"} + result := make([]map[string]any, 0, len(servers)) + for _, server := range servers { + data, err := s.requestOfficialGold(ctx, server) + if err != nil { + return nil, err + } + result = append(result, data) + } + return result, nil + }) +} + +func (s *ColgService) requestTrendData(ctx context.Context, region int, startTime string, endTime string) (map[string]any, error) { + payload := map[string]any{ + "token": s.config.ColgToken, + "area": region, + "time_type": "other", + "start_time": startTime, + "end_time": endTime, + } + body, err := json.Marshal(payload) + if err != nil { + return nil, err + } + + req, err := http.NewRequestWithContext(ctx, http.MethodPost, "https://poservice.colg.cn/api/v1/trend/getCoinTrendDataKol", bytes.NewReader(body)) + if err != nil { + return nil, err + } + req.Header.Set("Content-Type", "application/json") + + resp, err := s.client.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + content, err := io.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + var payloadResp map[string]any + if err := json.Unmarshal(content, &payloadResp); err != nil { + return nil, err + } + data, _ := payloadResp["data"].(map[string]any) + return data, nil +} + +func (s *ColgService) requestOfficialGold(ctx context.Context, server string) (map[string]any, error) { + form := url.Values{} + form.Set("r", "godRank/godDealRank") + form.Set("userId", s.config.HelperID) + form.Set("token", s.config.HelperToken) + form.Set("serverNo", server) + + req, err := http.NewRequestWithContext(ctx, http.MethodPost, "https://dzhu.qq.com/zangyi/activity/app", strings.NewReader(form.Encode())) + if err != nil { + return nil, err + } + req.Header.Set("Content-Type", "application/x-www-form-urlencoded") + + resp, err := s.client.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + content, err := io.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + var payloadResp map[string]any + if err := json.Unmarshal(content, &payloadResp); err != nil { + return nil, err + } + data, _ := payloadResp["data"].(map[string]any) + return map[string]any{ + "updataTime": time.Now().Format("2006-01-02 15:04:05"), + "region": "跨" + server, + "goldDealRank": extractPrices(data["godDealRank"]), + "goldTopDealRank": extractPrices(data["godTopDealRank"]), + }, nil +} + +func extractPrices(value any) []int { + rows, _ := value.([]any) + result := make([]int, 0, len(rows)) + for _, row := range rows { + rowMap, _ := row.(map[string]any) + result = append(result, intFromAnyString(rowMap["price"])) + } + return result +} + +func extractField(rows []map[string]any, key string) []any { + result := make([]any, 0, len(rows)) + for _, row := range rows { + result = append(result, row[key]) + } + return result +} + +func formatBeijingTime(ts int64) string { + return time.Unix(ts, 0).UTC().Add(8 * time.Hour).Format("2006-01-02 15:04:05") +} + +func floorToFive(value float64) float64 { + return float64(int(value/5) * 5) +} + +func float64FromAny(value any) float64 { + switch typed := value.(type) { + case float64: + return typed + case float32: + return float64(typed) + case int: + return float64(typed) + case int64: + return float64(typed) + case json.Number: + parsed, _ := typed.Float64() + return parsed + default: + return 0 + } +} + +func int64FromAny(value any) int64 { + switch typed := value.(type) { + case int64: + return typed + case int: + return int64(typed) + case float64: + return int64(typed) + case json.Number: + parsed, _ := typed.Int64() + return parsed + default: + return 0 + } +} + +func intFromAnyString(value any) int { + switch typed := value.(type) { + case string: + parsed, _ := strconv.Atoi(typed) + return parsed + default: + return int(float64FromAny(value)) + } +} diff --git a/backend/go/internal/service/equipment_catalog_sqlite.go b/backend/go/internal/service/equipment_catalog_sqlite.go new file mode 100644 index 00000000..6f204cd1 --- /dev/null +++ b/backend/go/internal/service/equipment_catalog_sqlite.go @@ -0,0 +1,295 @@ +package service + +import ( + "database/sql" + "fmt" + "path/filepath" + "strconv" + "strings" + + _ "modernc.org/sqlite" +) + +type SQLiteEquipmentCatalogRepository struct { + projectRoot string +} + +func NewSQLiteEquipmentCatalogRepository(projectRoot string) *SQLiteEquipmentCatalogRepository { + return &SQLiteEquipmentCatalogRepository{projectRoot: projectRoot} +} + +func (r *SQLiteEquipmentCatalogRepository) Catalog(_ string, equVersion string) (map[string]any, error) { + if equVersion == "" { + equVersion = "0" + } + + dbPath := filepath.Join(r.projectRoot, "dataFiles", fmt.Sprintf("dcalc_%s.db", equVersion)) + db, err := sql.Open("sqlite", dbPath) + if err != nil { + return nil, err + } + defer db.Close() + + equips, err := queryEquipRows(db, "equ") + if err != nil { + return nil, err + } + stones, err := queryEquipRows(db, "stone") + if err != nil { + return nil, err + } + suits, err := querySuitRows(db) + if err != nil { + return nil, err + } + enchants, err := queryEnchantRows(db, "enchant") + if err != nil { + return nil, err + } + emblems, err := queryEnchantRows(db, "emblem") + if err != nil { + return nil, err + } + jades, err := queryJadeRows(db) + if err != nil { + return nil, err + } + + return map[string]any{ + "equips": equips, + "suits": suits, + "stones": stones, + "enchants": enchants, + "emblems": emblems, + "jades": jades, + "avatar": map[string]any{}, + "options": map[string]any{}, + "sundry": []any{}, + }, nil +} + +func queryEquipRows(db *sql.DB, table string) ([]map[string]any, error) { + query := fmt.Sprintf("SELECT id,name,rarity,itemType,itemDetailType,Point,categorize,imageUrl,detail,bufferDetail,STR,INT,Vitality,Spirit,AtkP,AtkM,AtkI,SkillAttack,Attack,Buffer,suit FROM %s", table) + rows, err := db.Query(query) + if err != nil { + return nil, err + } + defer rows.Close() + + result := make([]map[string]any, 0) + for rows.Next() { + var ( + id, name, rarity, itemType, itemDetailType, point, categorize, imageURL, detail, bufferDetail sql.NullString + strV, intV, vitV, spiV, atkPV, atkMV, atkIV, skillAttackV, attackV, bufferV, suitV sql.NullString + ) + if err := rows.Scan(&id, &name, &rarity, &itemType, &itemDetailType, &point, &categorize, &imageURL, &detail, &bufferDetail, &strV, &intV, &vitV, &spiV, &atkPV, &atkMV, &atkIV, &skillAttackV, &attackV, &bufferV, &suitV); err != nil { + return nil, err + } + + entry := map[string]any{ + "id": nullString(id), + "name": nullString(name), + "rarity": nullString(rarity), + "itemType": nullString(itemType), + "itemDetailType": nullString(itemDetailType), + "categorize": nullString(categorize), + "imageUrl": nullString(imageURL), + "detail": nullString(detail), + "bufferDetail": nullString(bufferDetail), + "Point": numberListOrDefault(nullString(point)), + "STR": numberListOrDefault(nullString(strV)), + "INT": numberListOrDefault(nullString(intV)), + "Vitality": numberListOrDefault(nullString(vitV)), + "Spirit": numberListOrDefault(nullString(spiV)), + "AtkP": numberListOrDefault(nullString(atkPV)), + "AtkM": numberListOrDefault(nullString(atkMV)), + "AtkI": numberListOrDefault(nullString(atkIV)), + "SkillAttack": numberListOrDefault(nullString(skillAttackV)), + "Attack": numberListOrDefault(nullString(attackV)), + "Buffer": numberListOrDefault(nullString(bufferV)), + "suit": suitListOrDefault(nullString(suitV)), + } + + maxAdaptation := 0 + for _, key := range []string{"Point", "STR", "INT", "Vitality", "Spirit", "AtkP", "AtkM", "AtkI", "SkillAttack", "Attack", "Buffer"} { + if values, ok := entry[key].([]float64); ok && len(values)-1 > maxAdaptation { + maxAdaptation = len(values) - 1 + } + } + entry["max_adaptation"] = maxAdaptation + result = append(result, entry) + } + return result, rows.Err() +} + +func querySuitRows(db *sql.DB) ([]map[string]any, error) { + rows, err := db.Query("SELECT id,suitId,suitName,rarity,name,point,level,count,SkillAttack,Attack,Buffer,imageUrl,value,bufferValue,fame FROM suit") + if err != nil { + return nil, err + } + defer rows.Close() + + result := make([]map[string]any, 0) + for rows.Next() { + var ( + id, suitID, point, level, count, fame sql.NullInt64 + suitName, rarity, name, imageURL, value, bufferValue sql.NullString + skillAttack, attack, buffer sql.NullFloat64 + ) + if err := rows.Scan(&id, &suitID, &suitName, &rarity, &name, &point, &level, &count, &skillAttack, &attack, &buffer, &imageURL, &value, &bufferValue, &fame); err != nil { + return nil, err + } + result = append(result, map[string]any{ + "id": nullInt64(id), + "suitId": nullInt64(suitID), + "suitName": nullString(suitName), + "rarity": nullString(rarity), + "name": nullString(name), + "point": nullInt64(point), + "level": nullInt64(level), + "count": nullInt64(count), + "SkillAttack": nullFloat64(skillAttack), + "Attack": nullFloat64(attack), + "Buffer": nullFloat64(buffer), + "imageUrl": nullString(imageURL), + "value": nullString(value), + "bufferValue": nullString(bufferValue), + "fame": nullInt64(fame), + }) + } + return result, rows.Err() +} + +func queryEnchantRows(db *sql.DB, table string) ([]map[string]any, error) { + query := fmt.Sprintf("SELECT id,detail,categorize,itemType,fame,rarity FROM %s", table) + rows, err := db.Query(query) + if err != nil { + return nil, err + } + defer rows.Close() + + result := make([]map[string]any, 0) + for rows.Next() { + var id, fame sql.NullInt64 + var detail, categorize, itemType, rarity sql.NullString + if err := rows.Scan(&id, &detail, &categorize, &itemType, &fame, &rarity); err != nil { + return nil, err + } + result = append(result, map[string]any{ + "id": nullInt64(id), + "detail": nullString(detail), + "categorize": splitCSV(nullString(categorize)), + "position": splitCSV(nullString(itemType)), + "fame": nullInt64(fame), + "rarity": nullString(rarity), + }) + } + return result, rows.Err() +} + +func queryJadeRows(db *sql.DB) ([]map[string]any, error) { + rows, err := db.Query("SELECT id,name,min,max,unit,pre FROM jade") + if err != nil { + return nil, err + } + defer rows.Close() + + result := make([]map[string]any, 0) + for rows.Next() { + var id, minV, maxV sql.NullInt64 + var name, unit sql.NullString + var pre sql.NullFloat64 + if err := rows.Scan(&id, &name, &minV, &maxV, &unit, &pre); err != nil { + return nil, err + } + result = append(result, map[string]any{ + "id": nullInt64(id), + "name": nullString(name), + "min": nullInt64(minV), + "max": nullInt64(maxV), + "unit": nullString(unit), + "pre": nullFloat64(pre), + }) + } + return result, rows.Err() +} + +func numberListOrDefault(raw string) []float64 { + raw = strings.TrimSpace(raw) + if raw == "" { + return []float64{0} + } + parts := strings.Split(raw, ",") + result := make([]float64, 0, len(parts)) + for _, part := range parts { + value, err := strconv.ParseFloat(strings.TrimSpace(part), 64) + if err != nil { + result = append(result, 0) + continue + } + result = append(result, value) + } + if len(result) == 0 { + return []float64{0} + } + return result +} + +func suitListOrDefault(raw string) []string { + raw = strings.TrimSpace(raw) + if raw == "" { + return []string{} + } + parts := strings.Split(raw, ",") + result := make([]string, 0, len(parts)) + for _, part := range parts { + part = strings.TrimSpace(part) + if part == "" { + continue + } + value, err := strconv.ParseFloat(part, 64) + if err != nil { + result = append(result, part) + continue + } + result = append(result, strconv.Itoa(int(value))) + } + return result +} + +func splitCSV(raw string) []string { + raw = strings.TrimSpace(raw) + if raw == "" { + return []string{} + } + parts := strings.Split(raw, ",") + result := make([]string, 0, len(parts)) + for _, part := range parts { + part = strings.TrimSpace(part) + if part != "" { + result = append(result, part) + } + } + return result +} + +func nullString(value sql.NullString) string { + if !value.Valid { + return "" + } + return value.String +} + +func nullInt64(value sql.NullInt64) int64 { + if !value.Valid { + return 0 + } + return value.Int64 +} + +func nullFloat64(value sql.NullFloat64) float64 { + if !value.Valid { + return 0 + } + return value.Float64 +} diff --git a/backend/go/internal/service/openapi.go b/backend/go/internal/service/openapi.go new file mode 100644 index 00000000..3db1a75b --- /dev/null +++ b/backend/go/internal/service/openapi.go @@ -0,0 +1,264 @@ +package service + +import ( + "encoding/json" + "fmt" + "os" + "path/filepath" + "regexp" + "strings" + "time" +) + +var placeholderPattern = regexp.MustCompile(`<(?:(?:int)|(?:float\d*))>`) +var filenameJobPrefix = regexp.MustCompile(`^\d+(?:-\d+){0,2}`) + +type OpenAPIService struct { + projectRoot string + cache *Cache + adventure *AdventureService +} + +func NewOpenAPIService(projectRoot string, cache *Cache, adventure *AdventureService) *OpenAPIService { + return &OpenAPIService{projectRoot: projectRoot, cache: cache, adventure: adventure} +} + +func (s *OpenAPIService) SearchSkills(skillName string) ([]map[string]any, error) { + skills, err := GetOrLoad(s.cache, "openapi:skills", 30*time.Minute, func() ([]map[string]any, error) { + var data []map[string]any + if err := s.readJSON(filepath.Join(s.projectRoot, "openapi", "data", "skills.json"), &data); err != nil { + return nil, err + } + return data, nil + }) + if err != nil { + return nil, err + } + + normalized := normalizeWhitespace(skillName) + if normalized == "" { + return skills, nil + } + + filtered := make([]map[string]any, 0) + for _, skill := range skills { + name, _ := skill["skillName"].(string) + if strings.Contains(normalizeWhitespace(name), normalized) { + filtered = append(filtered, skill) + } + } + return filtered, nil +} + +func (s *OpenAPIService) JobsInfo(jobName string) ([]map[string]string, error) { + jobName = strings.NewReplacer("(", "(", ")", ")").Replace(jobName) + result := make([]map[string]string, 0) + for _, job := range s.adventure.Jobs() { + for _, child := range job.Children { + if jobName == "" || strings.Contains(child.Title, jobName) || strings.Contains(child.Name, jobName) { + result = append(result, map[string]string{ + "jobId": job.Name, + "jobName": job.Title, + "jobGrowId": child.Name, + "jobGrowName": child.Title, + }) + } + } + } + return result, nil +} + +func (s *OpenAPIService) SkillsByJob(jobID string, jobGrowID string) (any, error) { + jobDir, jobGrowDir, err := s.adventure.ResolveDirectories(jobID, jobGrowID) + if err != nil { + return nil, err + } + + var data any + path := filepath.Join(s.projectRoot, "openapi", "data", jobDir, jobGrowDir, "cn", "skill_tree.json") + if err := s.readJSON(path, &data); err != nil { + return nil, err + } + return data, nil +} + +func (s *OpenAPIService) SkillDetail(jobID string, jobGrowID string, skillID string, level *int) (any, error) { + jobDir, jobGrowDir, err := s.adventure.ResolveDirectories(jobID, jobGrowID) + if err != nil { + return nil, err + } + + var skillInfo map[string]any + path := filepath.Join(s.projectRoot, "openapi", "data", jobDir, jobGrowDir, "cn", "skillDetail", skillID+".json") + if err := s.readJSON(path, &skillInfo); err != nil { + return nil, err + } + + if levelInfo, ok := skillInfo["levelInfo"].(map[string]any); ok { + if optionDesc, ok := levelInfo["optionDesc"].(string); ok { + levelInfo["optionDesc"] = replacePlaceholders(optionDesc) + } + } + + if level == nil { + return skillInfo, nil + } + + maxLevel := intFromAny(skillInfo["maxLevel"]) + bounded := *level + if bounded < 0 { + bounded = 0 + } + if maxLevel > 0 && bounded > maxLevel { + bounded = maxLevel + } + + levelInfo, ok := skillInfo["levelInfo"].(map[string]any) + if !ok { + return skillInfo, nil + } + rows, ok := levelInfo["rows"].([]any) + if !ok { + return skillInfo, nil + } + + for _, row := range rows { + rowMap, ok := row.(map[string]any) + if !ok || intFromAny(rowMap["level"]) != bounded { + continue + } + + for key, value := range rowMap { + levelInfo[key] = value + } + detail, _ := levelInfo["optionDesc"].(string) + if optionValue, ok := levelInfo["optionValue"].(map[string]any); ok { + for key, value := range optionValue { + detail = strings.ReplaceAll(detail, "{"+key+"}", fmt.Sprint(value)) + } + } + levelInfo["detail"] = detail + delete(levelInfo, "rows") + skillInfo["attribute"] = levelInfo + delete(skillInfo, "levelInfo") + break + } + + return skillInfo, nil +} + +func (s *OpenAPIService) SkillDetailByAlter(alter string, skillID string, level int) (any, error) { + jobDir, jobGrowDir, err := s.adventure.DirectoriesFromAlter(alter) + if err != nil { + return nil, err + } + return s.SkillDetail(jobDir, jobGrowDir, skillID, &level) +} + +func (s *OpenAPIService) SkillDataSummary(job string, skills []string, weapons []string) ([]map[string]any, error) { + job = strings.NewReplacer("(", "(", ")", ")").Replace(job) + entries, err := os.ReadDir(filepath.Join(s.projectRoot, "openapi", "summary")) + if err != nil { + return nil, err + } + + skillFilter := make(map[string]struct{}) + for _, skill := range skills { + if skill != "" { + skillFilter[skill] = struct{}{} + } + } + weaponFilter := make(map[string]struct{}) + for _, weapon := range weapons { + if weapon != "" { + weaponFilter[weapon] = struct{}{} + } + } + + result := make([]map[string]any, 0) + for _, entry := range entries { + if entry.IsDir() || !strings.HasSuffix(entry.Name(), ".json") || !strings.Contains(entry.Name(), job) { + continue + } + + parts := strings.Split(strings.TrimSuffix(entry.Name(), ".json"), "_") + weapon := "通用" + if len(parts) > 1 && parts[len(parts)-1] != "" { + weapon = parts[len(parts)-1] + } + if len(weaponFilter) > 0 { + if _, ok := weaponFilter[weapon]; !ok { + continue + } + } + + var rows []map[string]any + if err := s.readJSON(filepath.Join(s.projectRoot, "openapi", "summary", entry.Name()), &rows); err != nil { + return nil, err + } + + jobTitle := strings.TrimPrefix(parts[0], filenameJobPrefix.FindString(parts[0])) + for _, row := range rows { + if len(skillFilter) > 0 { + skillName, _ := row["技能名称"].(string) + if _, ok := skillFilter[skillName]; !ok { + continue + } + } + copied := cloneMap(row) + copied["武器类型"] = weapon + copied["职业"] = jobTitle + result = append(result, copied) + } + } + + return result, nil +} + +func (s *OpenAPIService) readJSON(path string, dest any) error { + content, err := os.ReadFile(path) + if err != nil { + return err + } + if err := json.Unmarshal(content, dest); err != nil { + return fmt.Errorf("unmarshal %s: %w", path, err) + } + return nil +} + +func replacePlaceholders(template string) string { + count := 0 + return placeholderPattern.ReplaceAllStringFunc(template, func(_ string) string { + count++ + return fmt.Sprintf("{value%d}", count) + }) +} + +func normalizeWhitespace(value string) string { + return strings.Join(strings.Fields(value), "") +} + +func intFromAny(value any) int { + switch typed := value.(type) { + case int: + return typed + case int32: + return int(typed) + case int64: + return int(typed) + case float64: + return int(typed) + case float32: + return int(typed) + default: + return 0 + } +} + +func cloneMap(source map[string]any) map[string]any { + cloned := make(map[string]any, len(source)) + for key, value := range source { + cloned[key] = value + } + return cloned +} diff --git a/backend/go/internal/service/python_adapter.go b/backend/go/internal/service/python_adapter.go new file mode 100644 index 00000000..70c9858f --- /dev/null +++ b/backend/go/internal/service/python_adapter.go @@ -0,0 +1,83 @@ +package service + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "os/exec" + "path/filepath" + "time" + + "dcalc-go/internal/config" +) + +type CharacterSkillMeta struct { + ID string `json:"id"` + Name string `json:"name"` + Type string `json:"type"` + LearnLv int `json:"learnLv"` + MaxLearnLv int `json:"maxLearnLv"` + HasVP bool `json:"hasVP"` + HasUP bool `json:"hasUP"` + UUID string `json:"uuid"` +} + +type CharacterFactory interface { + CharacterInfo(alter string, equVersion string) (map[string]any, error) + CharacterSkills(alter string, equVersion string) ([]CharacterSkillMeta, error) +} + +type PythonCharacterFactory struct { + pythonExec string + projectRoot string + scriptPath string +} + +func NewPythonCharacterFactory(cfg config.Config) *PythonCharacterFactory { + return &PythonCharacterFactory{ + pythonExec: cfg.PythonExec, + projectRoot: cfg.ProjectRoot, + scriptPath: filepath.Join(cfg.ProjectRoot, "go", "python_bridge.py"), + } +} + +func (p *PythonCharacterFactory) CharacterInfo(alter string, equVersion string) (map[string]any, error) { + result := map[string]any{} + if err := p.invoke("character-info", alter, equVersion, &result); err != nil { + return nil, err + } + return result, nil +} + +func (p *PythonCharacterFactory) CharacterSkills(alter string, equVersion string) ([]CharacterSkillMeta, error) { + var result []CharacterSkillMeta + if err := p.invoke("character-skills", alter, equVersion, &result); err != nil { + return nil, err + } + return result, nil +} + +func (p *PythonCharacterFactory) invoke(command string, alter string, equVersion string, out any) error { + if equVersion == "" { + equVersion = "0" + } + + ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) + defer cancel() + + cmd := exec.CommandContext(ctx, p.pythonExec, p.scriptPath, p.projectRoot, command, alter, equVersion) + var stdout bytes.Buffer + var stderr bytes.Buffer + cmd.Stdout = &stdout + cmd.Stderr = &stderr + + if err := cmd.Run(); err != nil { + return fmt.Errorf("python bridge failed: %w, stdout=%s, stderr=%s", err, stdout.String(), stderr.String()) + } + + if err := json.Unmarshal(stdout.Bytes(), out); err != nil { + return fmt.Errorf("unmarshal python bridge output: %w, raw=%s", err, stdout.String()) + } + return nil +} diff --git a/backend/go/internal/service/skilltree.go b/backend/go/internal/service/skilltree.go new file mode 100644 index 00000000..6e9ff251 --- /dev/null +++ b/backend/go/internal/service/skilltree.go @@ -0,0 +1,376 @@ +package service + +import ( + "bytes" + "compress/zlib" + "encoding/base64" + "encoding/binary" + "encoding/json" + "fmt" + "io" + "os" + "path/filepath" + "strings" + "unicode/utf16" +) + +type SkillTreeService struct { + adventure *AdventureService + factory CharacterFactory + indexToUID map[int][]string +} + +type decodedSkillCode struct { + Header skillCodeHeader + Skills []skillLearnItem + Evolutions []skillChoice + Enhancements []skillChoice +} + +type skillCodeHeader struct { + Name string + Level int + JobBytes [2]int +} + +type skillLearnItem struct { + SkillIndex int + Level int + SkillType int +} + +type skillChoice struct { + SkillIndex int + Type int +} + +type LearnedSkill struct { + Lv int `json:"lv"` + Up int `json:"up"` + VP int `json:"vp"` + Name string `json:"name"` +} + +type SkillTreeResult struct { + Name string `json:"name"` + Level int `json:"level"` + Job map[string]string `json:"job"` + Skills map[string]LearnedSkill `json:"skills"` +} + +var roleMap = map[int]int{ + 0: 0, + 1: 3, + 2: 4, + 3: 7, + 4: 8, + 5: 5, + 6: 10, + 7: 2, + 8: 6, + 9: 15, + 10: 15, + 11: 1, + 12: 11, + 13: 12, + 14: 9, + 15: 13, + 16: 14, +} + +func NewSkillTreeService(projectRoot string, adventure *AdventureService, factory CharacterFactory) (*SkillTreeService, error) { + indexToUID, err := loadSkillIndexMap(filepath.Join(projectRoot, "dataFiles", "skillMap.json")) + if err != nil { + return nil, err + } + return &SkillTreeService{adventure: adventure, factory: factory, indexToUID: indexToUID}, nil +} + +func (s *SkillTreeService) Parse(code string, equVersion string) (SkillTreeResult, error) { + decoded, err := decodeSkillCode(code) + if err != nil { + return SkillTreeResult{}, err + } + + alter, err := alterFromJobBytes(decoded.Header.JobBytes[0], decoded.Header.JobBytes[1], s.adventure) + if err != nil { + return SkillTreeResult{}, err + } + + skills, err := s.factory.CharacterSkills(alter, equVersion) + if err != nil { + return SkillTreeResult{}, err + } + + skillByUUID := make(map[string][]CharacterSkillMeta) + for _, skill := range skills { + skillByUUID[skill.UUID] = append(skillByUUID[skill.UUID], skill) + } + + indexCandidates := make(map[int][]CharacterSkillMeta) + for _, item := range decoded.Skills { + if _, exists := indexCandidates[item.SkillIndex]; exists { + continue + } + indexCandidates[item.SkillIndex] = s.buildCandidates(item.SkillIndex, skillByUUID) + } + + learned := make(map[string]LearnedSkill) + for _, item := range decoded.Skills { + candidates := indexCandidates[item.SkillIndex] + chosen := chooseSkillCandidate(candidates, item.SkillType) + if chosen == nil { + continue + } + current, exists := learned[chosen.ID] + if !exists || current.Lv < item.Level { + learned[chosen.ID] = LearnedSkill{Lv: item.Level, Up: 0, VP: 0, Name: chosen.Name} + } + } + + for _, evo := range decoded.Evolutions { + for _, skill := range indexCandidates[evo.SkillIndex] { + if !skill.HasVP { + continue + } + if learnedSkill, ok := learned[skill.ID]; ok { + learnedSkill.VP = evo.Type + learned[skill.ID] = learnedSkill + } + } + } + + for _, up := range decoded.Enhancements { + for _, skill := range indexCandidates[up.SkillIndex] { + if !skill.HasUP { + continue + } + if learnedSkill, ok := learned[skill.ID]; ok { + learnedSkill.Up = up.Type + learned[skill.ID] = learnedSkill + } + } + } + + for _, skill := range skills { + if _, exists := learned[skill.ID]; exists { + continue + } + level := 0 + if skill.LearnLv == 50 || skill.LearnLv == 85 || skill.Name == "基础精通" { + level = skill.MaxLearnLv + } + learned[skill.ID] = LearnedSkill{Lv: level, Up: 0, VP: 0, Name: skill.Name} + } + + return SkillTreeResult{ + Name: decoded.Header.Name, + Level: decoded.Header.Level, + Job: map[string]string{"class": alter}, + Skills: learned, + }, nil +} + +func (s *SkillTreeService) buildCandidates(index int, skillByUUID map[string][]CharacterSkillMeta) []CharacterSkillMeta { + uuids := s.indexToUID[index] + seen := make(map[string]struct{}) + candidates := make([]CharacterSkillMeta, 0) + for _, uuid := range uuids { + for _, skill := range skillByUUID[uuid] { + if _, exists := seen[skill.ID]; exists { + continue + } + seen[skill.ID] = struct{}{} + candidates = append(candidates, skill) + } + } + if len(candidates) > 1 { + filtered := make([]CharacterSkillMeta, 0) + for _, skill := range candidates { + if skill.LearnLv == 50 || skill.LearnLv == 85 { + continue + } + filtered = append(filtered, skill) + } + if len(filtered) > 0 { + return filtered + } + } + return candidates +} + +func chooseSkillCandidate(candidates []CharacterSkillMeta, skillType int) *CharacterSkillMeta { + if len(candidates) == 0 { + return nil + } + if len(candidates) == 1 { + return &candidates[0] + } + wantedType := "passive" + if skillType == 1 { + wantedType = "active" + } + for i := range candidates { + if candidates[i].Type == wantedType { + return &candidates[i] + } + } + return &candidates[0] +} + +func loadSkillIndexMap(path string) (map[int][]string, error) { + content, err := os.ReadFile(path) + if err != nil { + return nil, err + } + + uuidToIndexes := map[string][]int{} + if err := json.Unmarshal(content, &uuidToIndexes); err != nil { + return nil, err + } + + indexToUUID := make(map[int][]string) + for uuid, indexes := range uuidToIndexes { + for _, idx := range indexes { + indexToUUID[idx] = append(indexToUUID[idx], uuid) + } + } + return indexToUUID, nil +} + +func alterFromJobBytes(roleByte int, jobByte int, adventure *AdventureService) (string, error) { + parent, ok := roleMap[roleByte] + if !ok { + return "", fmt.Errorf("unsupported role byte: %d", roleByte) + } + + jobID := jobByte - 1 + if roleByte == 9 { + jobID = 1 + } + if roleByte == 10 { + jobID = 0 + } + + token := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%02d%02d00", parent, jobID))) + return adventure.AlterByToken(token) +} + +func decodeSkillCode(encoded string) (decodedSkillCode, error) { + result := decodedSkillCode{} + + compressed, err := base64.StdEncoding.DecodeString(encoded) + if err != nil { + return result, fmt.Errorf("decode base64: %w", err) + } + + r, err := zlib.NewReader(bytes.NewReader(compressed)) + if err != nil { + return result, fmt.Errorf("create zlib reader: %w", err) + } + defer r.Close() + + raw, err := io.ReadAll(r) + if err != nil { + return result, fmt.Errorf("read zlib stream: %w", err) + } + if len(raw) < 14 { + return result, fmt.Errorf("invalid skill code payload") + } + + nameLen := int(raw[13]) + if 14+nameLen > len(raw) { + return result, fmt.Errorf("invalid name length in skill code") + } + + result.Header = skillCodeHeader{ + Name: decodeUTF16LE(raw[14 : 14+nameLen]), + Level: int(raw[5]), + JobBytes: [2]int{int(raw[2]), int(raw[3])}, + } + + data := raw[14+nameLen:] + if len(data)%2 == 1 { + data = append(data, 0) + } + + uint16s := make([]uint16, 0, len(data)/2) + for i := 0; i < len(data); i += 2 { + uint16s = append(uint16s, binary.LittleEndian.Uint16(data[i:i+2])) + } + if len(uint16s) == 0 { + return result, nil + } + + high := make([]byte, len(uint16s)) + low := make([]byte, len(uint16s)) + for i, value := range uint16s { + high[i] = byte(value >> 8) + low[i] = byte(value & 0xFF) + } + + pairCount := int(high[0]) + for i := 0; i < pairCount; i++ { + base := 1 + i*2 + if base+1 >= len(high) { + break + } + result.Skills = append(result.Skills, skillLearnItem{ + SkillIndex: int(high[base]), + Level: int(high[base+1]), + SkillType: int(low[base+1]), + }) + } + + sectionStart := (1 + pairCount*2) * 2 + if sectionStart >= len(data) { + return result, nil + } + sec2 := data[sectionStart:] + if len(sec2) < 2 { + return result, nil + } + + offset := 1 + evoCount := int(sec2[offset]) + offset++ + for i := 0; i < evoCount; i++ { + if offset+3 > len(sec2) { + break + } + result.Evolutions = append(result.Evolutions, skillChoice{ + SkillIndex: int(sec2[offset]), + Type: int(sec2[offset+2]) + 1, + }) + offset += 3 + } + + if offset >= len(sec2) { + return result, nil + } + enhCount := int(sec2[offset]) + offset++ + for i := 0; i < enhCount; i++ { + if offset+3 > len(sec2) { + break + } + result.Enhancements = append(result.Enhancements, skillChoice{ + SkillIndex: int(sec2[offset]), + Type: int(sec2[offset+2]) + 1, + }) + offset += 3 + } + + return result, nil +} + +func decodeUTF16LE(value []byte) string { + if len(value)%2 == 1 { + value = append(value, 0) + } + words := make([]uint16, 0, len(value)/2) + for i := 0; i < len(value); i += 2 { + words = append(words, binary.LittleEndian.Uint16(value[i:i+2])) + } + return strings.TrimSpace(string(utf16.Decode(words))) +} diff --git a/backend/go/internal/service/token.go b/backend/go/internal/service/token.go new file mode 100644 index 00000000..d3df0753 --- /dev/null +++ b/backend/go/internal/service/token.go @@ -0,0 +1,62 @@ +package service + +import ( + "encoding/base64" + "encoding/json" + "fmt" + "time" +) + +const tokenTTL = 6 * time.Hour + +type TokenService struct { + adventure *AdventureService +} + +type AlterTokenPayload struct { + Alter string `json:"alter"` + EquVersion string `json:"equVersion"` + Time int64 `json:"time"` +} + +func NewTokenService(adventure *AdventureService) *TokenService { + return &TokenService{adventure: adventure} +} + +func (s *TokenService) Create(alterToken string, equVersion string) (string, error) { + if equVersion == "" { + equVersion = "0" + } + + alter, err := s.adventure.AlterByToken(alterToken) + if err != nil { + return "", err + } + + payload := AlterTokenPayload{ + Alter: alter, + EquVersion: equVersion, + Time: time.Now().UnixMilli(), + } + content, err := json.Marshal(payload) + if err != nil { + return "", err + } + + return base64.RawURLEncoding.EncodeToString(content), nil +} + +func (s *TokenService) Parse(token string) (AlterTokenPayload, error) { + var payload AlterTokenPayload + content, err := base64.RawURLEncoding.DecodeString(token) + if err != nil { + return payload, fmt.Errorf("decode token: %w", err) + } + if err := json.Unmarshal(content, &payload); err != nil { + return payload, fmt.Errorf("unmarshal token: %w", err) + } + if payload.Time <= 0 || time.Since(time.UnixMilli(payload.Time)) > tokenTTL { + return AlterTokenPayload{}, fmt.Errorf("token expired") + } + return payload, nil +} diff --git a/backend/go/python_bridge.py b/backend/go/python_bridge.py new file mode 100644 index 00000000..7088324b --- /dev/null +++ b/backend/go/python_bridge.py @@ -0,0 +1,77 @@ +import json +import os +import sys + + +def _fail(message: str) -> None: + print(json.dumps({'error': message}, ensure_ascii=False)) + sys.exit(1) + + +def _parse_args() -> tuple[str, str, str, str]: + if len(sys.argv) < 5: + _fail('usage: python_bridge.py ') + project_root = sys.argv[1] + command = sys.argv[2] + alter = sys.argv[3] + equ_version = sys.argv[4] + return project_root, command, alter, equ_version + + +def _ensure_path(project_root: str) -> None: + if project_root not in sys.path: + sys.path.insert(0, project_root) + sys.argv[0] = os.path.join(project_root, 'main.py') + os.chdir(project_root) + + +def _load_character(alter: str, equ_version: str): + from core.basic.character import createCharacter + + character = createCharacter(alter, equ_version or '0') + if character is None: + raise RuntimeError(f'failed to create character for {alter}') + return character + + +def _character_info(alter: str, equ_version: str): + character = _load_character(alter, equ_version) + return character.getInfo() + + +def _character_skills(alter: str, equ_version: str): + info = _character_info(alter, equ_version) + skills = info.get('skills', []) + return [ + { + 'id': str(skill.get('id', '')), + 'name': skill.get('name', ''), + 'type': skill.get('type', ''), + 'learnLv': int(skill.get('learnLv', 0)), + 'maxLearnLv': int(skill.get('maxLearnLv', 0)), + 'hasVP': bool(skill.get('hasVP', False)), + 'hasUP': bool(skill.get('hasUP', False)), + 'uuid': skill.get('uuid', ''), + } + for skill in skills + ] + + +def main() -> None: + project_root, command, alter, equ_version = _parse_args() + _ensure_path(project_root) + + try: + if command == 'character-info': + data = _character_info(alter, equ_version) + elif command == 'character-skills': + data = _character_skills(alter, equ_version) + else: + _fail(f'unknown command: {command}') + print(json.dumps(data, ensure_ascii=False)) + except Exception as ex: + _fail(str(ex)) + + +if __name__ == '__main__': + main() diff --git a/backend/openapi b/backend/openapi index 03f3bbf0..680ed85d 160000 --- a/backend/openapi +++ b/backend/openapi @@ -1 +1 @@ -Subproject commit 03f3bbf037b53d7c0dfbee7be52a1989464c5103 +Subproject commit 680ed85d6e8646ad98afe7208a7381dc366bc4f8 diff --git a/backend/test.py b/backend/test.py index e50ff94a..c8337630 100644 --- a/backend/test.py +++ b/backend/test.py @@ -2,8 +2,30 @@ from core.basic.character import createCharacter char = createCharacter('GF.gunner_female.spitfire_female') -char.calc_init({'oaths': {'0': {'id': '2010201', 'adaptation': 3}, '11': {'id': '2050200', 'adaptation': 0}}, 'equips': {}}) +setInfo = { + 'oaths': {'0': {'id': '2030201', 'adaptation': 3}, '1': {'id': '2030201', 'adaptation': 3}, '2': {'id': '2030201', 'adaptation': 3}, '3': {'id': '2030201', 'adaptation': 3}, '4': {'id': '2030201', 'adaptation': 3}, '11': {'id': '2030200', 'adaptation': 0}}, + 'oathSkill': 1, + 'equips': { + '武器': {'id': '88', 'reinforce': 14, 'reinforceType': 1, 'enchant': 512, 'fusion': 0, 'refine': 8, 'adaptation': 3, 'precision': 100}, + '称号': {'id': '3017', 'reinforce': 0, 'reinforceType': 0, 'enchant': 1201, 'fusion': 0, 'refine': 0, 'adaptation': 3, 'precision': 100}, + '上衣': {'id': '999', 'reinforce': 13, 'reinforceType': 1, 'enchant': 105, 'fusion': '26', 'refine': 0, 'adaptation': 3, 'precision': 100}, + '头肩': {'id': '1001', 'reinforce': 14, 'reinforceType': 1, 'enchant': 5, 'fusion': '28', 'refine': 0, 'adaptation': 3, 'precision': 100}, + '下装': {'id': '1000', 'reinforce': 14, 'reinforceType': 1, 'enchant': 202, 'fusion': '27', 'refine': 0, 'adaptation': 3, 'precision': 100}, + '鞋': {'id': '1003', 'reinforce': 14, 'reinforceType': 1, 'enchant': 309, 'fusion': '30', 'refine': 0, 'adaptation': 3, 'precision': 100}, + '腰带': {'id': '1002', 'reinforce': 14, 'reinforceType': 1, 'enchant': 309, 'fusion': '29', 'refine': 0, 'adaptation': 3, 'precision': 100}, + '项链': {'id': '477', 'reinforce': 13, 'reinforceType': 1, 'enchant': 609, 'fusion': '180', 'refine': 0, 'adaptation': 3, 'precision': 100}, + '手镯': {'id': '483', 'reinforce': 14, 'reinforceType': 1, 'enchant': 609, 'fusion': '302', 'refine': 0, 'adaptation': 3, 'precision': 100}, + '戒指': {'id': '489', 'reinforce': 14, 'reinforceType': 1, 'enchant': 609, 'fusion': '304', 'refine': 0, 'adaptation': 3, 'precision': 100}, + '辅助装备': {'id': '492', 'reinforce': 14, 'reinforceType': 1, 'enchant': 905, 'fusion': '182', 'refine': 3, 'adaptation': 3, 'precision': 100}, + '魔法石': {'id': '495', 'reinforce': 14, 'reinforceType': 1, 'enchant': 1003, 'fusion': '184', 'refine': 3, 'adaptation': 3, 'precision': 100}, + '耳环': {'id': '498', 'reinforce': 14, 'reinforceType': 1, 'enchant': 1104, 'fusion': '186', 'refine': 0, 'adaptation': 3, 'precision': 100}, + '宠物': {'id': '4022', 'reinforce': 0, 'reinforceType': 0, 'enchant': 1304, 'fusion': 0, 'refine': 0, 'adaptation': 3, 'precision': 100}, + }, + 'emblems': {'彩色': {'lv': 1, 'items': ['4401', '4401', '4401', '4401', '4401', '4401']}, '红色': {'lv': 2, 'items': ['4101', '4101', '4101', '4101']}, '蓝色': {'lv': 2, 'items': []}, '绿色': {'lv': 3, 'items': []}, '黄色': {'lv': 4, 'items': []}}, +} -for oath in char.charOathInfo: - print(oath.id, oath.adaptation, oath.oathInfo.position, oath.oathInfo.max_adaptation, oath.oathInfo.Point) +char.calc(setInfo) + +# for oath in char.charOathInfo: +# print(oath.id, oath.adaptation, oath.oathInfo.position, oath.oathInfo.max_adaptation, oath.oathInfo.Point) diff --git a/frontend/src/api/calc/type.ts b/frontend/src/api/calc/type.ts index 7bdd486a..5b13f368 100644 --- a/frontend/src/api/calc/type.ts +++ b/frontend/src/api/calc/type.ts @@ -21,6 +21,7 @@ export interface IResultSkill { } export interface IResultUserInfo { + id: number name: string value: string | number } diff --git a/frontend/src/api/info/index.ts b/frontend/src/api/info/index.ts index 88b3717c..03978e0b 100644 --- a/frontend/src/api/info/index.ts +++ b/frontend/src/api/info/index.ts @@ -26,6 +26,10 @@ export default defineRequest((request) => { async getSkillFromCode(code: string) { const res = await request.post(`/skillTree/`, { code }) return res.data - } + }, + async getOathInfo(suitId: string, skillId: string, rarity: string) { + const res = await request.get(`/info/oath/${suitId}/${skillId}`, { params: { rarity } }) + return res.data + }, } }) diff --git a/frontend/src/api/info/type.ts b/frontend/src/api/info/type.ts index 3f92cd14..6db332da 100644 --- a/frontend/src/api/info/type.ts +++ b/frontend/src/api/info/type.ts @@ -31,6 +31,7 @@ export interface ICharacterInfo { stones: IEquipment[] enchants: IEnchantingInfo[] emblems: IEnchantingInfo[] + oaths: IEquipment[] weapons: string[] subweapons: string[] skills: ISkill[] @@ -39,6 +40,19 @@ export interface ICharacterInfo { jades: IJade[] sundry: Record options: { id: number; name: string; options: string[] }[] + oaths_skills: Record< + string, + { + suitInfo: { + name: string + rarity: string + SkillAttack: number + Buffer: number + Attack: number + }[] + skills: { skillId: string; name: string; icon: string }[] + } + > } export interface ISundry { @@ -71,6 +85,10 @@ export interface IEquipment { Buffer: number[] detail: string bufferDetail: string + position: string[] + wearUrl: string[] + oathPos: string + displayUrl?: string } export interface ISkill { @@ -91,7 +109,7 @@ export interface ISkill { desc: string }[] uuid: string - upType:'damage' |'heal' + upType: 'damage' | 'heal' } export interface ISuit { diff --git a/frontend/src/components/calc/autocomplete/index.vue b/frontend/src/components/calc/autocomplete/index.vue index a8a85915..f3d3bd3b 100644 --- a/frontend/src/components/calc/autocomplete/index.vue +++ b/frontend/src/components/calc/autocomplete/index.vue @@ -11,6 +11,7 @@ import { renderList, watch, } from 'vue' +import { getElementZoom } from '@/utils/position' type HandleChangeFunction = (value: string | number) => string[] | Promise @@ -55,10 +56,12 @@ export default defineComponent({ function onResize() { if (triggerRef.value) { const { width, height, left, top } = triggerRef.value.getBoundingClientRect() + const zoom = getElementZoom('body') + dropdownPosition.value = { - w: width, - x: left, - y: top + height + 2, + w: width / zoom, + x: left / zoom, + y: (top + height + 2) / zoom, } } } diff --git a/frontend/src/components/calc/cascader/index.vue b/frontend/src/components/calc/cascader/index.vue index 492ddd63..f5f59345 100644 --- a/frontend/src/components/calc/cascader/index.vue +++ b/frontend/src/components/calc/cascader/index.vue @@ -4,6 +4,7 @@ import type { CSSProperties, PropType } from 'vue' import { Teleport, Transition, computed, defineComponent, onDeactivated, ref, watch } from 'vue' import { onClickOutside, useVModel } from '@vueuse/core' +import { getElementZoom } from '@/utils/position' interface ICascaderItem { label: string id?: string | number @@ -74,18 +75,19 @@ export default defineComponent({ function onResize() { if (triggerRef.value) { const { width, height, left, top } = triggerRef.value.getBoundingClientRect() + const zoom = getElementZoom('body') if (window.innerHeight - top > 160) { dropdownPosition.value = { - w: width, - x: left, - y: top + height + 2, + w: width / zoom, + x: left / zoom, + y: (top + height + 2) / zoom, z: 0, } } else { dropdownPosition.value = { - w: width, - x: left, - z: window.innerHeight - top + 2, + w: width / zoom, + x: left / zoom, + z: (window.innerHeight - top + 2) / zoom, y: 0, } } diff --git a/frontend/src/components/calc/iconselect/index.vue b/frontend/src/components/calc/iconselect/index.vue index 7452f786..1c6c66d2 100644 --- a/frontend/src/components/calc/iconselect/index.vue +++ b/frontend/src/components/calc/iconselect/index.vue @@ -13,6 +13,7 @@ import { } from 'vue' import { onClickOutside } from '@vueuse/core' +import { getElementZoom } from '@/utils/position' export default defineComponent({ name: 'IIconselect', @@ -72,20 +73,24 @@ export default defineComponent({ const dropdownPosition = ref({ x: 0, y: 0, w: 0 }) // 下拉框位置 const dropdownStyle = computed(() => { + const zoom = getElementZoom(appendToRef.value) + return { left: `${dropdownPosition.value.x}px`, top: `${dropdownPosition.value.y}px`, - width: `${columnNum.value * 32 + 11}px`, + width: `${(columnNum.value * 32 + 11) / zoom}px`, } }) function onResize() { if (triggerRef.value) { const { width, height, left, top } = triggerRef.value.getBoundingClientRect() + const zoom = getElementZoom(appendToRef.value) + dropdownPosition.value = { - w: width, - x: left - 2, - y: (top + height + 2), + w: width / zoom, + x: (left - 2) / zoom, + y: (top + height + 2) / zoom, } } } diff --git a/frontend/src/components/calc/select/index.vue b/frontend/src/components/calc/select/index.vue index 777f31f7..89aef50e 100644 --- a/frontend/src/components/calc/select/index.vue +++ b/frontend/src/components/calc/select/index.vue @@ -15,6 +15,7 @@ import { import { onClickOutside, useVModel } from '@vueuse/core' import { classPropType, labelPropType } from '@/components/hooks/types' +import { getElementZoom } from '@/utils/position' export default defineComponent({ name: 'ISelect', @@ -98,18 +99,19 @@ export default defineComponent({ function onResize() { if (triggerRef.value) { const { width, height, left, top } = triggerRef.value.getBoundingClientRect() + const zoom = getElementZoom(appendToRef.value) if (window.innerHeight - top > 160) { dropdownPosition.value = { - w: width, - x: left, - y: (top + height + 2), + w: width / zoom, + x: left / zoom, + y: (top + height + 2) / zoom, z: 0, } } else { dropdownPosition.value = { - w: width, - x: left, - z: (window.innerHeight - top + 2), + w: width / zoom, + x: left / zoom, + z: (window.innerHeight - top + 2) / zoom, y: 0, } } diff --git a/frontend/src/components/dnf/Avatar/List/index.vue b/frontend/src/components/dnf/Avatar/List/index.vue index 489998e6..f90e74ec 100644 --- a/frontend/src/components/dnf/Avatar/List/index.vue +++ b/frontend/src/components/dnf/Avatar/List/index.vue @@ -13,9 +13,8 @@ + + diff --git a/frontend/src/components/dnf/Equipment/Icon/index.vue b/frontend/src/components/dnf/Equipment/Icon/index.vue index ec52e5cf..ec22fd50 100644 --- a/frontend/src/components/dnf/Equipment/Icon/index.vue +++ b/frontend/src/components/dnf/Equipment/Icon/index.vue @@ -3,7 +3,9 @@
@@ -21,6 +23,7 @@ import { getImageURL } from '@/utils/images' const props = defineProps<{ equipment?: IEquipment inactive?: boolean + useDisplayUrl?: boolean }>() const rarity = computed(() => { diff --git a/frontend/src/components/dnf/Equipment/Info/index.vue b/frontend/src/components/dnf/Equipment/Info/index.vue index ee635072..c5e056a5 100644 --- a/frontend/src/components/dnf/Equipment/Info/index.vue +++ b/frontend/src/components/dnf/Equipment/Info/index.vue @@ -38,16 +38,12 @@
-
+
-
- -
+
{ return infoStore.equips.find((e) => e.id == id) } -const stones = (id: string) => { - return infoStore.stones.find((e) => e.id == id) -} +// const oaths = (id: string) => { +// return infoStore.oaths.find((e) => e.id == id) +// } const infoStyle = (part: string) => { let x = 10 - let y = 5 + let y = 10 let index = infoStore.parts.findIndex((p) => p == part) if (index == 13) { index -= 7 @@ -117,30 +117,30 @@ const infoStyle = (part: string) => { return style } -const fusionStyle = (part: string) => { - let x = 0 - let y = 15 - let index = infoStore.parts.findIndex((p) => p == part) +// const fusionStyle = (part: string) => { +// let x = 0 +// let y = 15 +// let index = infoStore.parts.findIndex((p) => p == part) - if (index >= 5 && index <= 12) { - x += 179 - index -= 5 - } +// if (index >= 5 && index <= 12) { +// x += 179 +// index -= 5 +// } - if (index == 13) { - index = 5 - } +// if (index == 13) { +// index = 5 +// } - x += (index % 2) * 39 - y += Math.floor(index / 2) * 34 +// x += (index % 2) * 39 +// y += Math.floor(index / 2) * 34 - return { - left: `${x}px`, - top: `${y}px`, - zIndex: 7, - transform: 'scale(0.6)', - } -} +// return { +// left: `${x}px`, +// top: `${y}px`, +// zIndex: 7, +// transform: 'scale(0.6)', +// } +// } const choosePart = (part: string) => { partModelValue.value = part } diff --git a/frontend/src/components/dnf/Equipment/Oath/index.vue b/frontend/src/components/dnf/Equipment/Oath/index.vue new file mode 100644 index 00000000..3eb50ed2 --- /dev/null +++ b/frontend/src/components/dnf/Equipment/Oath/index.vue @@ -0,0 +1,182 @@ + + + + + diff --git a/frontend/src/components/dnf/Equipment/Oath/info.vue b/frontend/src/components/dnf/Equipment/Oath/info.vue new file mode 100644 index 00000000..e69de29b diff --git a/frontend/src/pages/Character/Equipment/Index.vue b/frontend/src/pages/Character/Equipment/Index.vue index 55c71165..9f6679ef 100644 --- a/frontend/src/pages/Character/Equipment/Index.vue +++ b/frontend/src/pages/Character/Equipment/Index.vue @@ -18,7 +18,7 @@ - + 套装 通宝 diff --git a/frontend/src/pages/Character/Equipment/components/StoneOld.vue b/frontend/src/pages/Character/Equipment/components/StoneOld.vue deleted file mode 100644 index dfc22836..00000000 --- a/frontend/src/pages/Character/Equipment/components/StoneOld.vue +++ /dev/null @@ -1,60 +0,0 @@ -` - - - - -` diff --git a/frontend/src/pages/Character/Equipment/components/Weapon.vue b/frontend/src/pages/Character/Equipment/components/Weapon.vue index 2d163861..9b7d8227 100644 --- a/frontend/src/pages/Character/Equipment/components/Weapon.vue +++ b/frontend/src/pages/Character/Equipment/components/Weapon.vue @@ -15,7 +15,6 @@ @@ -323,4 +480,8 @@ const chooseEqu = (item?: IEquipment) => { border-bottom: 1px solid #211d15; text-align: center; } + +.unActive { + filter: grayscale(100%); +} diff --git a/frontend/src/pages/Character/EquipmentDictionary/formatData.ts b/frontend/src/pages/Character/EquipmentDictionary/formatData.ts index e4f091f1..c8eaab0c 100644 --- a/frontend/src/pages/Character/EquipmentDictionary/formatData.ts +++ b/frontend/src/pages/Character/EquipmentDictionary/formatData.ts @@ -7,23 +7,25 @@ export const formatEqu = (total: IEquipment[], subweapons?: string[], curSuit?: const item_weapon = total.filter((a) => a.itemType == '武器') ?? [] const weapons: (IEquipment | undefined)[] = [] if (item_weapon.length > 0) { - Array.from(new Set(item_weapon.map((item) => item.rarity))).filter(a=>!['稀有','神器'].includes(a)).forEach((rarity) => { - const weapon = item_weapon - .filter((item) => item.rarity === rarity) - .sort((a, b) => { - if (a.categorize == b.categorize) { - return a.itemDetailType.localeCompare(b.itemDetailType) - } - return b.categorize.localeCompare(a.categorize) - }) - weapons.push( - ...weapon.filter((a) => !['传世武器升级', '狄瑞吉传世武器'].includes(a.categorize)), - ) - const remind = weapons.length % rowCount - if (remind > 0) { - weapons.push(...Array(rowCount - remind).fill(undefined)) - } - }) + Array.from(new Set(item_weapon.map((item) => item.rarity))) + .filter((a) => !['稀有', '神器'].includes(a)) + .forEach((rarity) => { + const weapon = item_weapon + .filter((item) => item.rarity === rarity) + .sort((a, b) => { + if (a.categorize == b.categorize) { + return a.itemDetailType.localeCompare(b.itemDetailType) + } + return b.categorize.localeCompare(a.categorize) + }) + weapons.push( + ...weapon.filter((a) => !['传世武器升级', '狄瑞吉传世武器'].includes(a.categorize)), + ) + const remind = weapons.length % rowCount + if (remind > 0) { + weapons.push(...Array(rowCount - remind).fill(undefined)) + } + }) if (item_weapon.some((a) => a.categorize === '传世武器升级')) { const length = item_weapon.filter((a) => a.categorize === '传世武器升级').length weapons.push(...Array(length).fill(undefined)) @@ -88,9 +90,13 @@ export const formatEqu = (total: IEquipment[], subweapons?: string[], curSuit?: (equip) => equip.categorize.includes('套装') || equip.categorize.includes('通宝'), ) const suits: (IEquipment | undefined)[] = [] - const raritiyList = Array.from(new Set(item_suits.map((item) => item.rarity))).filter(a=>!['稀有','神器'].includes(a)) + const raritiyList = Array.from(new Set(item_suits.map((item) => item.rarity))).filter( + (a) => !['稀有', '神器'].includes(a), + ) raritiyList.forEach((rarity) => { - const armor = item_suits.filter((item) => item.rarity === rarity && item.itemType === '防具' && !item.name.includes("侵蚀")) + const armor = item_suits.filter( + (item) => item.rarity === rarity && item.itemType === '防具' && !item.name.includes('侵蚀'), + ) if (armor.length > 0) { suits.push(...armor, undefined) } @@ -119,7 +125,9 @@ export const formatEqu = (total: IEquipment[], subweapons?: string[], curSuit?: suits.push(...Array(rowCount - (suits.length % rowCount)).fill(undefined)) } - const armorUpgrade = item_suits.filter((item) => item.rarity === rarity && item.itemType === '防具' && item.name.includes("侵蚀")) + const armorUpgrade = item_suits.filter( + (item) => item.rarity === rarity && item.itemType === '防具' && item.name.includes('侵蚀'), + ) if (armorUpgrade.length > 0) { suits.push(...armorUpgrade) } @@ -283,3 +291,32 @@ export const formatStone = (total: IEquipment[], curSuit?: string) => { // }, ] } + +export const formatOath = ( + total: IEquipment[], + curSuit?: { name: string; value: number; imageUrl: string }, +) => { + // oath + const oath = total.filter((equip) => equip.itemDetailType == '誓约') + oath.push(...Array(rowCount - (oath.length % rowCount)).fill(undefined)) + // primer + const primer = [] + const primerItem = total.filter((equip) => equip.itemDetailType == '星蕴石') + for (let i = 0; i < 11; i++) { + const temp = primerItem.filter((a) => a.oathPos == i.toString()) + primer.push( + ...temp, + ...Array(temp.length == 0 ? rowCount : rowCount - (temp.length % rowCount)).fill(undefined), + ) + } + return [ + { + name: `${curSuit?.name} 誓约`, + equs: oath, + }, + { + name: `${curSuit?.name} 星蕴石`, + equs: primer, + }, + ] +} diff --git a/frontend/src/pages/Character/Forge/components/Avatars.vue b/frontend/src/pages/Character/Forge/components/Avatars.vue index 10b7d4cf..cbf9ee43 100644 --- a/frontend/src/pages/Character/Forge/components/Avatars.vue +++ b/frontend/src/pages/Character/Forge/components/Avatars.vue @@ -5,14 +5,12 @@ import { useInfoStore, useConfigStore } from '@/stores' import ClothList from '@/components/dnf/Avatar/List/index.vue' export default defineComponent({ name: 'Clothes', - setup(props) { + setup() { const configStore = useConfigStore() const part = ref('武器装扮') // const globalStore = useGlobalStore() - /** 是否有徽章 */ - const has_socket = computed(() => ['武器装扮', '光环', '皮肤'].includes(part.value as string)) const basicInfoStore = useInfoStore() const has_enchant = computed(() => { return !['头部', '帽子', '脸部', '胸部', '上衣', '腰带', '下装', '鞋'].includes( @@ -26,9 +24,9 @@ export default defineComponent({ .sort((a, b) => (b.fame ?? 0) - (a.fame ?? 0)) }) - const emblem_list = computed(() => { - return basicInfoStore.emblems.filter((item) => item.position.includes(part.value)) - }) + // const emblem_list = computed(() => { + // return basicInfoStore.emblems.filter((item) => item.position.includes(part.value)) + // }) const currentInfo = function (name: string, defaultValue?: T) { return computed({ @@ -36,7 +34,7 @@ export default defineComponent({ let key: 'avatar' | 'equips' = 'avatar' if (part.value == '宠物') key = 'equips' return ( - (configStore.config[key]?.[part.value] as Record)?.[name] ?? + (configStore.config[key]?.[part.value] as Record)?.[name] ?? defaultValue ?? 0 ) @@ -48,10 +46,13 @@ export default defineComponent({ let key: 'avatar' | 'equips' = 'avatar' if (part.value == '宠物') key = 'equips' if (!configStore.config[key][part.value]) { - configStore.config[key][part.value] = key === 'avatar' ? { ...configStore.defaultAvatarConfig } : { ...configStore.defaultEqusConfig } + configStore.config[key][part.value] = + key === 'avatar' + ? { ...configStore.defaultAvatarConfig } + : { ...configStore.defaultEqusConfig } } if (configStore.config[key][part.value]) { - ;(configStore.config[key][part.value] as Record)[name] = val + ;(configStore.config[key][part.value] as Record)[name] = val } }, }) @@ -60,11 +61,11 @@ export default defineComponent({ // 附魔 const enchant = currentInfo('enchant') - // 镶嵌栏1 - const emblem_0 = currentInfo('emblem_0', 0) + // // 镶嵌栏1 + // const emblem_0 = currentInfo('emblem_0', 0) - // 镶嵌栏2 - const emblem_1 = currentInfo('emblem_1') + // // 镶嵌栏2 + // const emblem_1 = currentInfo('emblem_1') // 品级 const id = currentInfo('id') @@ -76,9 +77,9 @@ export default defineComponent({ * 同步徽章1到徽章2 * @param val */ - function changeSocket(val: number) { - emblem_1.value = val - } + // function changeSocket(val: number) { + // emblem_1.value = val + // } return () => { return ( @@ -127,33 +128,6 @@ export default defineComponent({
)} - {has_socket.value ? ( -
-
徽章
- - 无 - {renderList(emblem_list.value ?? [], (item) => ( - {`${item.rarity}${item.categorize}徽章[${item.detail}]`} - ))} - - - 无 - {renderList(emblem_list.value ?? [], (item) => ( - {`${item.rarity}${item.categorize}徽章[${item.detail}]`} - ))} - -
- ) : ( -
- )} ) diff --git a/frontend/src/pages/Character/Forge/components/Emblems.vue b/frontend/src/pages/Character/Forge/components/Emblems.vue new file mode 100644 index 00000000..223a8c9b --- /dev/null +++ b/frontend/src/pages/Character/Forge/components/Emblems.vue @@ -0,0 +1,156 @@ + + + diff --git a/frontend/src/pages/Character/Forge/components/Equipments.vue b/frontend/src/pages/Character/Forge/components/Equipments.vue index 18f5e7ea..c33d47bc 100644 --- a/frontend/src/pages/Character/Forge/components/Equipments.vue +++ b/frontend/src/pages/Character/Forge/components/Equipments.vue @@ -6,7 +6,7 @@ import EquList from '@/components/dnf/Equipment/List/index.vue' import { getImageURL } from '@/utils/images' export default defineComponent({ name: 'Equip', - setup(props) { + setup() { const configStore = useConfigStore() const part = ref('头肩') const can_upgrade = computed(() => { @@ -15,14 +15,6 @@ export default defineComponent({ // const globalStore = useGlobalStore() - /** 是否有徽章 */ - const has_socket = computed( - () => !['称号', '宠物', '耳环', '武器'].includes(part.value as string), - ) - /** 是否有右侧徽章 */ - const has_emblem_1 = computed( - () => has_socket.value && !['辅助装备', '魔法石'].includes(part.value as string), - ) /** 是否可以设置秘宝精度 */ const can_set_secret = computed(() => { return ['武器', '辅助装备', '魔法石', '耳环'].includes(part.value as string) @@ -40,9 +32,9 @@ export default defineComponent({ .sort((a, b) => (b.fame ?? 0) - (a.fame ?? 0)) }) - const emblem_list = computed(() => { - return basicInfoStore.emblems.filter((item) => item.position.includes(part.value)) - }) + // const emblem_list = computed(() => { + // return basicInfoStore.emblems.filter((item) => item.position.includes(part.value)) + // }) const global_change = ref(false) @@ -50,6 +42,7 @@ export default defineComponent({ return computed({ get() { return ( + // eslint-disable-next-line @typescript-eslint/no-explicit-any (configStore.config.equips?.[part.value] as Record)?.[name] ?? defaultValue ?? 0 @@ -59,10 +52,10 @@ export default defineComponent({ if (val == undefined && name !== 'weaponFusion') { return } - if (name == 'emblem_1' && !has_emblem_1.value) { - // configStore.setForge(part.value, name, 0) - return - } + // if (name == 'emblem_1' && !has_emblem_1.value) { + // // configStore.setForge(part.value, name, 0) + // return + // } let parts: string[] = [] @@ -75,16 +68,16 @@ export default defineComponent({ parts = enchant.position } } - if (['emblem_0', 'emblem_1'].includes(name)) { - const emblem = basicInfoStore?.emblems?.find( - (item) => item.id.toString() == val.toString(), - ) as IEnchantingInfo | undefined - if (emblem?.position) { - parts = emblem.position.filter( - (item) => !['皮肤', '武器装扮', '光环'].includes(item), - ) - } - } + // if (['emblem_0', 'emblem_1'].includes(name)) { + // const emblem = basicInfoStore?.emblems?.find( + // (item) => item.id.toString() == val.toString(), + // ) as IEnchantingInfo | undefined + // if (emblem?.position) { + // parts = emblem.position.filter( + // (item) => !['皮肤', '武器装扮', '光环'].includes(item), + // ) + // } + // } if (['reinforceType', 'reinforce', 'adaptation'].includes(name)) { parts = basicInfoStore.parts.filter((e) => !['称号', '宠物'].includes(e)) } @@ -96,6 +89,7 @@ export default defineComponent({ configStore.config.equips[part] = { ...configStore.defaultEqusConfig } } if (configStore.config.equips[part]) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any ;(configStore.config.equips[part] as Record)[name] = val } } @@ -106,11 +100,11 @@ export default defineComponent({ // 附魔 const enchant = currentInfo('enchant') - // 镶嵌栏1 - const emblem_0 = currentInfo('emblem_0', 0) + // // 镶嵌栏1 + // const emblem_0 = currentInfo('emblem_0', 0) - // 镶嵌栏2 - const emblem_1 = currentInfo('emblem_1') + // // 镶嵌栏2 + // const emblem_1 = currentInfo('emblem_1') // 增幅 const reinforce_type = currentInfo('reinforceType', 1) @@ -133,11 +127,11 @@ export default defineComponent({ * 同步徽章1到徽章2 * @param val */ - function changeSocket(val: number) { - if (has_emblem_1.value) { - emblem_1.value = val - } - } + // function changeSocket(val: number) { + // if (has_emblem_1.value) { + // emblem_1.value = val + // } + // } const setWeaponFusion = (val: number) => { if (val == weaponFusion.value) { @@ -240,37 +234,6 @@ export default defineComponent({ ))} - {has_socket.value ? ( -
-
徽章
- - 无 - {renderList(emblem_list.value ?? [], (item) => ( - {`${item.rarity}${item.categorize}徽章[${item.detail}]`} - ))} - - {has_emblem_1.value && ( - - 无 - {renderList(emblem_list.value ?? [], (item) => ( - {`${item.rarity}${item.categorize}徽章[${item.detail}]`} - ))} - - )} -
- ) : ( -
- )} {can_upgrade.value ? (
diff --git a/frontend/src/pages/Character/Forge/components/Jades.vue b/frontend/src/pages/Character/Forge/components/Jades.vue index eff4a795..952f63b1 100644 --- a/frontend/src/pages/Character/Forge/components/Jades.vue +++ b/frontend/src/pages/Character/Forge/components/Jades.vue @@ -4,7 +4,7 @@
无 - + {{ item.name }} @@ -17,7 +17,7 @@ > --> @@ -38,26 +38,25 @@ import { getFloat } from '@/utils' const configStore = useConfigStore() const infoStore = useInfoStore() -const currentJade = computed(() => { - return function (id: number = -1) { - if (id == -1) { - return undefined - } else { - const res = [] - const cur = infoStore.jades?.find((e) => e.id == id) as IJade - return cur - } - } -}) +// const currentJade = computed(() => { +// return function (id: number = -1) { +// if (id == -1) { +// return undefined +// } else { +// const cur = infoStore.jades?.find((e) => e.id == id) as IJade +// return cur +// } +// } +// }) -const formatValue = (id: number) => { - return (value: number) => { - if (currentJade.value(id)?.unit.includes('等级')) { - return `$等级 +${value}` - } - return `${getFloat(value, 1)}${currentJade.value(id)?.unit}` - } -} +// const formatValue = (id: number) => { +// return (value: number) => { +// if (currentJade.value(id)?.unit.includes('等级')) { +// return `$等级 +${value}` +// } +// return `${getFloat(value, 1)}${currentJade.value(id)?.unit}` +// } +// } const valueList = computed(() => { return function (id: number = -1) { diff --git a/frontend/src/pages/Character/Forge/components/Oaths.vue b/frontend/src/pages/Character/Forge/components/Oaths.vue new file mode 100644 index 00000000..5aada1ce --- /dev/null +++ b/frontend/src/pages/Character/Forge/components/Oaths.vue @@ -0,0 +1,77 @@ + + + diff --git a/frontend/src/pages/Character/Forge/components/Sundry.vue b/frontend/src/pages/Character/Forge/components/Sundry.vue index 938643ad..161fdfb7 100644 --- a/frontend/src/pages/Character/Forge/components/Sundry.vue +++ b/frontend/src/pages/Character/Forge/components/Sundry.vue @@ -12,7 +12,7 @@ class="flex-1 !h-20px" />
-
+
冒险团
- + - 装备栏 - 时装栏 + 装备 + 誓约 + 时装 + 徽章 + + @@ -19,6 +23,8 @@ - + diff --git a/frontend/src/pages/Character/Result/components/Info.vue b/frontend/src/pages/Character/Result/components/Info.vue index 7ccf1155..be4d0411 100644 --- a/frontend/src/pages/Character/Result/components/Info.vue +++ b/frontend/src/pages/Character/Result/components/Info.vue @@ -5,7 +5,9 @@ :detail="props.equs" :with-sub-weapon="(infoStore.infos?.subweapons?.length ?? 0) > 0" :avatar="props.avatar" + v-show="display == 'equ'" > +