feat:优化职业技能关联实现
This commit was merged in pull request #11.
This commit is contained in:
@@ -3,6 +3,16 @@
|
||||
技能关联由 `core/basic/skill_effects.py` 的 `SkillEffectEngine` 统一处理。
|
||||
`lv`、VP 等输入变化不再通过历史倍率乘除更新目标,而是重新解析最终状态并汇总本次关联贡献。
|
||||
|
||||
## 技能身份与引用维护
|
||||
|
||||
职业模块导入自己的 Ref;技能类声明 `ref = Ref.XXX`,`code` 从 ref 派生,name 只负责显示。
|
||||
角色初始化根据技能数据 prefix 校验职业范围,并创建独立的 ref/code 索引;输出圣骑士等职业变体复用数据来源范围。
|
||||
SkillEffect.skills、except_skills、Read.skill、level_source 统一接受 Ref,旧名称字符串继续兼容。
|
||||
公共技能引用只匹配当前角色实际绑定的技能实例。GetSkill(Ref.XXX) 查询引用,GetSkillByCode 查询原始 code;
|
||||
字符串不会隐式当作 code。重复绑定、跨职业引用直接报错;新增规则应使用 Ref,旧失配名称继续保留 SKIP 诊断。
|
||||
引用生成、公共分组、编辑器中文提示的维护说明见 core/character/refs/base.py。
|
||||
SkillRef.name 只影响提示,不参与相等性和哈希;技能名称变更不会改变引用身份。
|
||||
|
||||
## 计算阶段
|
||||
|
||||
1. `SetSkills` 批量读取基础等级、VP、UP。传入的等级是基础等级,不含关联技能提供的等级;重复传入同一配置不会重复加级。
|
||||
@@ -186,6 +196,7 @@ backend/.venv/bin/pytest backend/tests/smoke/test_calc_availability.py -k config
|
||||
|
||||
第二项验证技能配置顺序(包括搭配武器的场景),不验证装备执行顺序。修改公共引擎后再运行完整 `backend/tests` 回归。
|
||||
"""
|
||||
from core.character.refs.base import resolve_skill
|
||||
from collections import defaultdict
|
||||
from contextlib import contextmanager
|
||||
from dataclasses import dataclass
|
||||
@@ -331,14 +342,16 @@ class SkillEffectEngine:
|
||||
for name in declaration.skills:
|
||||
if name in declaration.except_skills:
|
||||
continue
|
||||
target = self.character.GetSkillByName(name)
|
||||
target = resolve_skill(self.character, name)
|
||||
if target is None:
|
||||
if declaration.missing_target == MissingTargetPolicy.ERROR:
|
||||
raise ValueError(f'类型化效果目标不存在: {source.name} -> {name}')
|
||||
self.missing_target(source, name)
|
||||
else:
|
||||
targets.append(target)
|
||||
targets = [target for target in targets if target.name not in declaration.except_skills]
|
||||
excluded = {id(target) for ref in declaration.except_skills
|
||||
if (target := resolve_skill(self.character, ref)) is not None}
|
||||
targets = [target for target in targets if id(target) not in excluded]
|
||||
for target in targets:
|
||||
if attribute in STATE_ATTRIBUTES - {'lv'} and (target, attribute) not in self._state_base:
|
||||
raise ValueError(f'类型化效果状态缺少默认值: {source.name} -> {target.name}.{attribute}')
|
||||
@@ -428,7 +441,7 @@ class SkillEffectEngine:
|
||||
graph = {skill: set() for skill in self.skills}
|
||||
for skill in self.skills:
|
||||
if skill.level_source is not None:
|
||||
source = self.character.GetSkillByName(skill.level_source)
|
||||
source = resolve_skill(self.character, skill.level_source)
|
||||
if source is None:
|
||||
raise ValueError(f'共享等级源技能不存在: {skill.name} -> {skill.level_source}')
|
||||
graph[skill].add(source)
|
||||
@@ -447,7 +460,7 @@ class SkillEffectEngine:
|
||||
for skill in order:
|
||||
# All upstream level/parameter contributions are ready now.
|
||||
if skill.level_source is not None:
|
||||
skill._lv = self.character.GetSkillByName(skill.level_source).lv
|
||||
skill._lv = resolve_skill(self.character, skill.level_source).lv
|
||||
contributions, reads = self._collect(skill)
|
||||
if not reads.issubset(graph[skill]):
|
||||
raise ValueError(f'技能关联状态依赖随计算改变: {skill.name}')
|
||||
|
||||
Reference in New Issue
Block a user