docs: add skill template refactor design and migration plan docs
新增技能基座重构的设计文档和完整迁移计划文档,包含新的接口定义、配置结构、运行时参数解析逻辑以及分步迁移验证方案,为后续技能系统重构提供完整的设计指导。
This commit is contained in:
385
docs/superpowers/specs/2026-05-22-skill-migration-plan.md
Normal file
385
docs/superpowers/specs/2026-05-22-skill-migration-plan.md
Normal file
@@ -0,0 +1,385 @@
|
||||
# 技能基座重构 — 迁移计划
|
||||
|
||||
基于 spec: `docs/superpowers/specs/2026-05-22-skill-template-refactor-design.md`
|
||||
|
||||
## 迁移原则
|
||||
|
||||
- 每个步骤是**最小功能单元**,完成后可独立验证
|
||||
- 使用**兼容层**过渡:新旧接口并存期间,代码同时读取两个位置
|
||||
- 验证方式:每步完成后运行游戏,确认技能系统行为不变
|
||||
|
||||
---
|
||||
|
||||
## Phase 1:类型定义(零风险,不改行为)
|
||||
|
||||
### Step 1.1:新增 SkillTemplate/SkillDefaults/HeroOverrides 接口
|
||||
|
||||
**文件**:`SkillSet.ts`
|
||||
|
||||
**改动**:
|
||||
- 在现有 `SkillConfig` 下方新增 `SkillTemplate`、`SkillDefaults`、`HeroOverrides` 接口定义
|
||||
- 新增 `TriggerSkillConf` 接口
|
||||
- 更新 `BuffConf`:新增 `attr` 字段,保留旧 `buff` 字段(标注 `@deprecated`)
|
||||
- 不删除任何旧代码
|
||||
|
||||
**验证**:编译通过,游戏行为不变(新接口尚未被使用)
|
||||
|
||||
### Step 1.2:新增 resolveSkillParams 工具函数
|
||||
|
||||
**文件**:`SkillSet.ts` 或新建 `SkillResolve.ts`
|
||||
|
||||
**改动**:
|
||||
```typescript
|
||||
export function resolveSkillParams(
|
||||
template: SkillTemplate,
|
||||
heroSkill?: HSkillInfo,
|
||||
triggerConf?: TriggerSkillConf
|
||||
): { kind: SkillKind } & SkillDefaults {
|
||||
return {
|
||||
kind: template.kind,
|
||||
...template.defaults,
|
||||
...heroSkill?.overrides,
|
||||
...triggerConf?.overrides,
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
**验证**:编译通过,写一个简单的测试用例验证三级覆盖逻辑
|
||||
|
||||
---
|
||||
|
||||
## Phase 2:兼容层(数据迁移的安全网)
|
||||
|
||||
### Step 2.1:新增兼容读取函数
|
||||
|
||||
**文件**:`SkillSet.ts`
|
||||
|
||||
**改动**:新增辅助函数,从旧 `SkillConfig` 构造 `SkillTemplate` + `SkillDefaults`:
|
||||
|
||||
```typescript
|
||||
/** 从旧 SkillConfig 提取 defaults 字段(过渡期使用) */
|
||||
export function legacyDefaults(config: SkillConfig): SkillDefaults {
|
||||
return {
|
||||
TGroup: config.TGroup,
|
||||
ap: config.ap,
|
||||
t_num: 1, // 旧配置无此字段,使用默认值
|
||||
hit_count: config.hit_count,
|
||||
hitcd: config.hitcd,
|
||||
crt: config.crt,
|
||||
frz: config.frz,
|
||||
bck: config.bck,
|
||||
buffs: config.buffs,
|
||||
};
|
||||
}
|
||||
|
||||
/** 从旧 SkillConfig 提取 template 字段 */
|
||||
export function legacyTemplate(config: SkillConfig): SkillTemplate {
|
||||
return {
|
||||
uuid: config.uuid,
|
||||
name: config.name,
|
||||
sp_name: config.sp_name,
|
||||
icon: config.icon,
|
||||
kind: config.kind ?? SkillKind.Damage,
|
||||
act: config.act,
|
||||
readyAnm: config.readyAnm,
|
||||
endAnm: config.endAnm,
|
||||
EAnm: config.EAnm,
|
||||
DAnm: config.DAnm,
|
||||
ready: config.ready,
|
||||
IType: config.IType,
|
||||
RType: config.RType,
|
||||
EType: config.EType,
|
||||
speed: config.speed,
|
||||
DTType: config.DTType,
|
||||
with: config.with,
|
||||
bezier_start_y: config.bezier_start_y,
|
||||
bezier_mid_y: config.bezier_mid_y,
|
||||
bezier_arc: config.bezier_arc,
|
||||
time: config.time,
|
||||
defaults: legacyDefaults(config),
|
||||
info: config.info,
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
**验证**:编译通过,可写测试验证提取结果与原配置一致
|
||||
|
||||
---
|
||||
|
||||
## Phase 3:数据迁移(逐个技能类型)
|
||||
|
||||
### Step 3.1:迁移 buff 技能数据(6401-6406, 6501)
|
||||
|
||||
**文件**:`SkillSet.ts`
|
||||
|
||||
**改动**:将 6401-6406、6501 从 `SkillConfig` 格式改为 `SkillTemplate` 格式:
|
||||
- 顶层数值字段 → `defaults`
|
||||
- 显式添加 `kind: SkillKind.Support`
|
||||
- `buffs` 中的 `buff:` → `attr:`
|
||||
|
||||
**存储方式**:新增 `BuffSkillTemplates: Record<number, SkillTemplate>`,旧数据保留在 `SkillSet` 中
|
||||
|
||||
**验证**:游戏运行,确认卡牌释放 buff 技能效果不变
|
||||
|
||||
### Step 3.2:迁移辅助技能数据(6301-6305)
|
||||
|
||||
**文件**:`SkillSet.ts`
|
||||
|
||||
**改动**:将护盾/治疗技能从旧格式改为 `SkillTemplate` 格式
|
||||
- 护盾类:`kind: SkillKind.Shield`
|
||||
- 治疗类:`kind: SkillKind.Heal`
|
||||
|
||||
**存储方式**:新增 `SupportSkillTemplates: Record<number, SkillTemplate>`,旧数据保留
|
||||
|
||||
**验证**:游戏运行,确认护盾和治疗技能效果不变
|
||||
|
||||
### Step 3.3:迁移必杀技数据(6104-6107)
|
||||
|
||||
**文件**:`SkillSet.ts`
|
||||
|
||||
**改动**:将必杀技从旧格式改为 `SkillTemplate` 格式
|
||||
- 全部 `kind: SkillKind.Damage`
|
||||
- `crt`/`frz` 移入 defaults
|
||||
|
||||
**验证**:游戏运行,确认必杀技伤害和特效不变
|
||||
|
||||
### Step 3.4:迁移基础攻击技能数据(6001-6103)
|
||||
|
||||
**文件**:`SkillSet.ts`
|
||||
|
||||
**改动**:将所有攻击技能从旧格式改为 `SkillTemplate` 格式
|
||||
- 全部 `kind: SkillKind.Damage`
|
||||
|
||||
**验证**:游戏运行,确认所有英雄和怪物的普攻、远程攻击正常
|
||||
|
||||
### Step 3.5:合并为新表
|
||||
|
||||
**文件**:`SkillSet.ts`
|
||||
|
||||
**改动**:将分散的 `BuffSkillTemplates`、`SupportSkillTemplates` 等合并为一个:
|
||||
```typescript
|
||||
export const SkillTemplates: Record<number, SkillTemplate> = { ... 所有已迁移的技能 ... }
|
||||
```
|
||||
|
||||
**验证**:通过所有新模板创建技能,确认与旧 `SkillSet` 行为一致
|
||||
|
||||
---
|
||||
|
||||
## Phase 4:消费者适配(逐文件)
|
||||
|
||||
### Step 4.1:适配 Skill.ts(技能实体创建)
|
||||
|
||||
**文件**:`assets/script/game/skill/Skill.ts`
|
||||
|
||||
**改动**:
|
||||
- `skill.load()` 参数从 `config: SkillConfig` 改为 `template: SkillTemplate`
|
||||
- 内部读取 `template.sp_name`(表现字段,未变)
|
||||
- 传递给 SMoveSystem/STimeComp 的 config 改为 template
|
||||
- `ap`/`crt`/`frz`/`hit_count` 从 `template.defaults` 读取(通过兼容函数)
|
||||
|
||||
**关键行**:
|
||||
- ~112: `config.sp_name` → `template.sp_name`
|
||||
- ~153: `config.EType` → `template.EType`
|
||||
- ~181: `config.RType` → `template.RType`
|
||||
- ~183-185: `config.bezier_*` → `template.bezier_*`
|
||||
- ~195: `config.time` → `template.time`
|
||||
- ~196: `config.hitcd` → `template.hitcd`
|
||||
- ~211-214: `config.crt`/`config.frz`/`config.ap`/`config.hit_count` → `template.defaults.*`
|
||||
|
||||
**验证**:释放各种技能,确认弹道动画和伤害数值正确
|
||||
|
||||
### Step 4.2:适配 SMoveSystem.ts(技能移动)
|
||||
|
||||
**文件**:`assets/script/game/skill/SMoveSystem.ts`
|
||||
|
||||
**改动**:
|
||||
- 类型引用 `SkillConfig` → `SkillTemplate`
|
||||
- 读取的字段(speed、RType、EType、bezier_*)均在模板顶层,无需改逻辑
|
||||
|
||||
**验证**:确认弹道轨迹(直线/贝塞尔/固定)正常
|
||||
|
||||
### Step 4.3:适配 STimeComp.ts(技能时间控制)
|
||||
|
||||
**文件**:`assets/script/game/skill/STimeComp.ts`
|
||||
|
||||
**改动**:
|
||||
- 类型引用 `SkillConfig` → `SkillTemplate`
|
||||
- 只读 `EType`(模板顶层字段),逻辑不变
|
||||
|
||||
**验证**:确认技能持续时间、碰撞消失逻辑正常
|
||||
|
||||
### Step 4.4:适配 SkillView.ts(技能视图)
|
||||
|
||||
**文件**:`assets/script/game/skill/SkillView.ts`
|
||||
|
||||
**改动**:
|
||||
- 类型引用 `SkillConfig` → `SkillTemplate`
|
||||
- 只读 `EType`(模板顶层字段),逻辑不变
|
||||
|
||||
**验证**:确认技能特效显示正常
|
||||
|
||||
### Step 4.5:适配 HeroViewComp.ts(命中动画)
|
||||
|
||||
**文件**:`assets/script/game/hero/HeroViewComp.ts`
|
||||
|
||||
**改动**:
|
||||
- ~507: `SConf?.DAnm` → `template?.DAnm`(字段仍在顶层,只改引用名)
|
||||
|
||||
**验证**:确认受击动画(普通/冰/火/风)显示正确
|
||||
|
||||
### Step 4.6:适配 SCastSystem.ts(施法系统 — 核心)
|
||||
|
||||
**文件**:`assets/script/game/hero/SCastSystem.ts`
|
||||
|
||||
**改动**:
|
||||
- 引入 `resolveSkillParams()` 和 `legacyTemplate()`
|
||||
- `forceCastSkill()` 中 `SkillSet[s_uuid]` → `SkillTemplates[s_uuid]`,通过 `resolveSkillParams(template, undefined, undefined)` 获取参数
|
||||
- `applyFriendlySkillEffects()` 改为接收 resolved params
|
||||
- `applyActualFriendlyEffect()` 中:
|
||||
- `config.buffs` → `resolved.buffs`
|
||||
- `buffConf.buff` → `buffConf.attr`(同时兼容旧 `buff` 字段)
|
||||
- 伤害技能路径中 `config.ap`/`config.crt`/`config.frz`/`config.hit_count` → 从 resolved params 读取
|
||||
- `config.TGroup` → `resolved.TGroup`
|
||||
- `config.kind` → `template.kind`(模板固定)
|
||||
|
||||
**验证**:
|
||||
1. 英雄普攻伤害正确
|
||||
2. 必杀技伤害和特效正确
|
||||
3. 护盾/治疗/buff 效果正确
|
||||
4. 卡牌技能效果正确
|
||||
|
||||
### Step 4.7:适配 HeroAtkSystem.ts(伤害系统)
|
||||
|
||||
**文件**:`assets/script/game/hero/HeroAtkSystem.ts`
|
||||
|
||||
**改动**:
|
||||
- ~292: `sConf.ap` → 从 resolved defaults 读取
|
||||
- ~221: `reviveSkillConf.ap` → 从 resolved defaults 读取
|
||||
- ~236: `reviveSkillConf.readyAnm` → 从 template 读取(模板顶层字段)
|
||||
|
||||
**验证**:
|
||||
1. 英雄伤害数值正确
|
||||
2. 复活技能恢复血量正确
|
||||
|
||||
### Step 4.8:适配 SkillTriggerHelper.ts(触发技能)
|
||||
|
||||
**文件**:`assets/script/game/hero/SkillTriggerHelper.ts`
|
||||
|
||||
**改动**:
|
||||
- 触发技能时,将 `triggerConf.overrides` 传递给 `resolveSkillParams()`
|
||||
|
||||
**验证**:确认受击触发护盾、普攻触发治疗等触发技能正常
|
||||
|
||||
### Step 4.9:适配 Hero.ts + Mon.ts(初始化)
|
||||
|
||||
**文件**:`Hero.ts`、`Mon.ts`
|
||||
|
||||
**改动**:
|
||||
- 英雄/怪物初始化时,将 `heroInfo.atking`/`atked` 等配置传入 HeroAttrsComp
|
||||
- HeroAttrsComp 中的类型同步更新为 `TriggerSkillConf[]`
|
||||
|
||||
**验证**:英雄和怪物的触发技能正常工作
|
||||
|
||||
### Step 4.10:适配显示层文件
|
||||
|
||||
**文件**:`CardComp.ts`、`IBoxComp.ts`、`TooltipCom.ts`、`SIconComp.ts`、`SkillBoxComp.ts`、`HlistComp.ts`
|
||||
|
||||
**改动**:
|
||||
- 仅引用名变更(`SkillConfig` → `SkillTemplate`)
|
||||
- 读取的字段(name、icon、IType、info)均在模板顶层,无需改逻辑
|
||||
|
||||
**验证**:卡牌显示、信息面板、技能图标显示正常
|
||||
|
||||
---
|
||||
|
||||
## Phase 5:角色定制(新功能启用)
|
||||
|
||||
### Step 5.1:更新 heroSet.ts 触发配置类型
|
||||
|
||||
**文件**:`heroSet.ts`
|
||||
|
||||
**改动**:
|
||||
- `atking`/`atked` 等类型从 `{s_uuid, t_num}` 内联 → `TriggerSkillConf[]`
|
||||
- 向后兼容:`overrides` 可选,旧配置无需修改
|
||||
|
||||
**验证**:编译通过,游戏行为不变(尚未添加 overrides)
|
||||
|
||||
### Step 5.2:为首个角色添加 overrides
|
||||
|
||||
**文件**:`heroSet.ts`
|
||||
|
||||
**改动**:选一个典型角色(如盾骑士 5002)作为试点,为其触发技能添加 overrides:
|
||||
|
||||
```typescript
|
||||
5002: {
|
||||
...,
|
||||
atked: [{ s_uuid: 6301, t_num: 2,
|
||||
overrides: { TGroup: TGroup.Team, ap: 2, t_num: 5, hit_count: 3 }
|
||||
}],
|
||||
},
|
||||
```
|
||||
|
||||
**验证**:盾骑士受击后给全队加盾,而非只给自己加。对比修改前后行为确认覆盖生效
|
||||
|
||||
### Step 5.3:逐步为其他角色添加 overrides
|
||||
|
||||
**文件**:`heroSet.ts`
|
||||
|
||||
**改动**:逐个角色添加 overrides,每添加一个验证一次
|
||||
|
||||
**验证**:每个角色的技能行为符合设计意图
|
||||
|
||||
---
|
||||
|
||||
## Phase 6:清理
|
||||
|
||||
### Step 6.1:删除旧 SkillConfig 接口和 SkillSet 数据
|
||||
|
||||
**文件**:`SkillSet.ts`
|
||||
|
||||
**改动**:
|
||||
- 删除 `SkillConfig` 接口
|
||||
- 删除旧 `SkillSet` 数据(已被 `SkillTemplates` 替代)
|
||||
- 删除 `legacyTemplate()`/`legacyDefaults()` 兼容函数
|
||||
- `SkillTemplates` 重命名回 `SkillSet`(或保持新名,全局替换引用)
|
||||
|
||||
**验证**:全面回归测试
|
||||
|
||||
### Step 6.2:BuffConf 清理
|
||||
|
||||
**文件**:`SkillSet.ts`、`SCastSystem.ts`
|
||||
|
||||
**改动**:
|
||||
- 删除 `BuffConf.buff` 字段,只保留 `attr`
|
||||
- 所有配置数据中 `buff:` → `attr:`
|
||||
|
||||
**验证**:buff 技能效果正确
|
||||
|
||||
### Step 6.3:删除 kind 回退逻辑
|
||||
|
||||
**文件**:`SCastSystem.ts`
|
||||
|
||||
**改动**:
|
||||
- 移除 `config.kind ?? SkillKind.Damage` 和 `config.kind ?? SkillKind.Support` 回退
|
||||
- 全部使用 `template.kind`
|
||||
|
||||
**验证**:所有技能类型判定正确
|
||||
|
||||
---
|
||||
|
||||
## 验证检查清单
|
||||
|
||||
每个 Step 完成后,运行以下检查:
|
||||
|
||||
| 检查项 | 方法 |
|
||||
|--------|------|
|
||||
| 编译通过 | 无 TypeScript 错误 |
|
||||
| 普攻正常 | 放置近战/远程英雄,观察普攻弹道和伤害 |
|
||||
| 必杀技正常 | 触发必杀技,确认特效和伤害 |
|
||||
| 护盾正常 | 触发护盾技能,确认护盾层数和显示 |
|
||||
| 治疗正常 | 触发治疗技能,确认血量恢复 |
|
||||
| Buff 正常 | 触发 buff 技能,确认属性变化 |
|
||||
| 卡牌技能正常 | 使用卡牌释放各种技能 |
|
||||
| 触发技能正常 | 受击/攻击/死亡/开始触发链正常 |
|
||||
| 怪物行为正常 | 怪物攻击和技能释放正常 |
|
||||
| 无控制台报错 | 检查浏览器控制台无 JS 错误 |
|
||||
@@ -0,0 +1,409 @@
|
||||
# 技能基座 + 角色定制 重构设计
|
||||
|
||||
## 背景
|
||||
|
||||
当前技能系统存在以下问题:
|
||||
|
||||
1. **所有技能类型混在一张表** — 攻击、治疗、护盾、buff 共用 `SkillConfig` 接口,字段复用导致每个技能配置含义不同(如 `ap` 在攻击技能是百分比,在护盾是次数,在 buff 是 0)
|
||||
2. **字段语义混乱** — `hit_count` 在攻击技能是"命中次数",在 buff 技能是"持续次数"
|
||||
3. **buff 技能包含大量无用字段** — speed、with、EType、RType 等 buff 完全不需要
|
||||
4. **同技能不同角色无法差异化** — 所有使用同一技能的角色效果完全相同
|
||||
5. **扩展困难** — 新增 buff 属性类型需要改 SCastSystem 的 switch 代码
|
||||
|
||||
## 设计目标
|
||||
|
||||
- SkillSet 作为**基座模板**,定义技能类型分类(伤害/治疗/护盾/buff)+ 表现层(动画、弹道、特效)+ 默认数值
|
||||
- `kind`(技能类型)由模板固定,角色不可覆盖
|
||||
- heroSet 负责定义**实际效果值**(伤害、治疗量、目标数量、buff 效果)
|
||||
- 同一个技能 UUID,不同角色可以有完全不同的数值行为
|
||||
- 触发技能(atking/atked/fstart/fend)也支持角色定制
|
||||
- 卡牌技能通过基座 defaults 正常工作
|
||||
|
||||
## 配置结构
|
||||
|
||||
### SkillTemplate — 基座模板
|
||||
|
||||
```typescript
|
||||
/** 技能基座模板 — 定义技能的类型、表现方式和默认数值 */
|
||||
interface SkillTemplate {
|
||||
uuid: number;
|
||||
name: string;
|
||||
sp_name: string; // 特效名
|
||||
icon: string;
|
||||
|
||||
// 技能类型分类 — 由模板固定,角色不可覆盖
|
||||
kind: SkillKind; // Damage | Heal | Shield | Support
|
||||
|
||||
// 动画表现
|
||||
act: string; // 角色动画
|
||||
readyAnm: string; // 前摇动画
|
||||
endAnm: string;
|
||||
EAnm: number; // 结束动画 ID
|
||||
DAnm: string; // 命中后动画名(如 "atked_ice"、"atked_fire")
|
||||
ready: number; // 前摇时间
|
||||
|
||||
// 弹道/表现行为(技能"怎么飞")
|
||||
IType: IType; // 近战/远程/辅助
|
||||
RType: RType; // 直线/贝塞尔/固定
|
||||
EType: EType; // 结束条件
|
||||
speed: number; // 移动速度
|
||||
DTType: DTType; // 单体/范围(影响碰撞体)
|
||||
with: number; // 宽度
|
||||
bezier_start_y?: number;
|
||||
bezier_mid_y?: number;
|
||||
bezier_arc?: number;
|
||||
time?: number; // timeEnd 持续时间
|
||||
|
||||
// 基座默认值(卡牌技能等无角色主体时使用)
|
||||
defaults: SkillDefaults;
|
||||
|
||||
info: string;
|
||||
}
|
||||
```
|
||||
|
||||
### SkillDefaults — 可覆盖的逻辑参数
|
||||
|
||||
```typescript
|
||||
/** 技能逻辑参数 — 可被角色 overrides 覆盖 */
|
||||
interface SkillDefaults {
|
||||
TGroup: TGroup; // 目标群体(敌方/友方/自身等)
|
||||
ap: number; // 伤害百分比 / 治疗百分比 / 护盾次数 / buff 固定为 0
|
||||
t_num: number; // 目标数量上限
|
||||
hit_count: number; // 命中/持续次数
|
||||
hitcd: number; // 间隔
|
||||
crt?: number; // 额外暴击率
|
||||
frz?: number; // 额外冰冻概率
|
||||
bck?: number; // 额外击退概率
|
||||
buffs?: BuffConf[]; // buff 效果列表(仅 kind=Support 时使用)
|
||||
}
|
||||
```
|
||||
|
||||
### HeroOverrides — 角色定义的技能参数
|
||||
|
||||
```typescript
|
||||
/** 角色技能参数覆盖 — 与 SkillDefaults 结构一致,不含 kind */
|
||||
interface HeroOverrides {
|
||||
TGroup?: TGroup; // 覆盖目标群体
|
||||
ap?: number; // 覆盖效果值
|
||||
t_num?: number; // 覆盖目标数量上限
|
||||
hit_count?: number; // 覆盖命中/持续次数
|
||||
hitcd?: number; // 覆盖间隔
|
||||
crt?: number; // 覆盖暴击率
|
||||
frz?: number; // 覆盖冰冻概率
|
||||
bck?: number; // 覆盖击退概率
|
||||
buffs?: BuffConf[]; // 覆盖 buff 效果列表
|
||||
}
|
||||
```
|
||||
|
||||
所有字段可选 — 只覆盖需要定制的参数,其余继承基座 defaults。**kind 不可覆盖**。
|
||||
|
||||
### HSkillInfo — 角色技能信息
|
||||
|
||||
```typescript
|
||||
interface HSkillInfo {
|
||||
uuid: number;
|
||||
lv: number;
|
||||
cd: number;
|
||||
ccd: number;
|
||||
/** 角色专属技能参数,覆盖基座 defaults */
|
||||
overrides?: HeroOverrides;
|
||||
}
|
||||
```
|
||||
|
||||
### TriggerSkillConf — 触发技能配置
|
||||
|
||||
```typescript
|
||||
/** 触发技能配置 */
|
||||
interface TriggerSkillConf {
|
||||
s_uuid: number; // 触发的技能 UUID
|
||||
t_num: number; // 激活阈值(攻击/受击多少次后触发),与 SkillDefaults.t_num 无关
|
||||
/** 角色定制参数,覆盖基座 defaults */
|
||||
overrides?: HeroOverrides;
|
||||
}
|
||||
```
|
||||
|
||||
> **语义区分**:`TriggerSkillConf.t_num` = 激活阈值("打几下触发"),`SkillDefaults.t_num` = 目标数量上限("打几个人")。两者同名但语义完全不同,代码中不会交叉使用。
|
||||
|
||||
### heroInfo 触发字段类型更新
|
||||
|
||||
```typescript
|
||||
interface heroInfo {
|
||||
// ... 现有字段不变
|
||||
skills: Record<number, HSkillInfo>;
|
||||
call?: TriggerSkillConf[];
|
||||
dead?: TriggerSkillConf[];
|
||||
fstart?: TriggerSkillConf[];
|
||||
fend?: TriggerSkillConf[];
|
||||
atking?: TriggerSkillConf[];
|
||||
atked?: TriggerSkillConf[];
|
||||
revive?: { s_uuid: number; r_num: number; upr: number };
|
||||
}
|
||||
```
|
||||
|
||||
向后兼容:旧格式 `{s_uuid, t_num}` 仍然有效,`overrides` 为可选字段。现有代码遍历这些数组时,`overrides` 不存在则跳过,`s_uuid` 和 `t_num` 仍在顶层。
|
||||
|
||||
## BuffConf 接口更新
|
||||
|
||||
```typescript
|
||||
// 旧
|
||||
interface BuffConf {
|
||||
buff: Attrs;
|
||||
value: number;
|
||||
}
|
||||
|
||||
// 新 — 字段名更清晰
|
||||
interface BuffConf {
|
||||
attr: Attrs; // 修改哪个属性
|
||||
value: number; // 效果值
|
||||
}
|
||||
```
|
||||
|
||||
重命名范围:SCastSystem.ts:433 的 `switch (buffConf.buff)` → `switch (buffConf.attr)`,以及 SkillSet.ts 中 6401-6406 配置数据中的 `buff:` → `attr:`。
|
||||
|
||||
## 运行时参数解析
|
||||
|
||||
### resolveSkillParams — 三级覆盖
|
||||
|
||||
优先级:**基座 defaults → 角色技能 overrides → 触发配置 overrides**
|
||||
|
||||
```typescript
|
||||
function resolveSkillParams(
|
||||
template: SkillTemplate,
|
||||
heroSkill?: HSkillInfo,
|
||||
triggerConf?: TriggerSkillConf
|
||||
): { kind: SkillKind } & Required<SkillDefaults> {
|
||||
return {
|
||||
// kind 由模板固定,不参与覆盖
|
||||
kind: template.kind,
|
||||
// 数值参数三级覆盖
|
||||
...template.defaults,
|
||||
...heroSkill?.overrides,
|
||||
...triggerConf?.overrides,
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
`kind` 始终取自 `template.kind`,即使 overrides 中误写了 kind 也不会生效。
|
||||
|
||||
### SkillUpList 升级加成
|
||||
|
||||
SkillUpList 升级加成作用于 **resolved 之后的参数**,而非直接从 config 读取。调用方式:
|
||||
|
||||
```typescript
|
||||
const resolved = resolveSkillParams(template, heroSkill, triggerConf);
|
||||
const sUp = SkillUpList[s_uuid] ?? SkillUpList[1001];
|
||||
const finalAp = resolved.ap + sUp.ap * skillLv;
|
||||
const finalHitCount = resolved.hit_count + sUp.hit_count * skillLv;
|
||||
const finalCrt = (resolved.crt ?? 0) + sUp.crt * skillLv;
|
||||
```
|
||||
|
||||
在 SCastSystem.ts 和 Skill.ts 中,所有当前直接读取 `config.ap` + `sUp.ap` 的地方,统一改为先 resolve 再应用 sUp。
|
||||
|
||||
### 卡牌技能路径
|
||||
|
||||
卡牌技能无角色上下文,调用 `resolveSkillParams(template, undefined, undefined)` 返回 `template.defaults`。在 `forceCastCardSkill()` 中使用此方式获取参数。
|
||||
|
||||
## 迁移注意事项
|
||||
|
||||
### 攻击技能必须显式设置 kind
|
||||
|
||||
当前攻击技能(6001-6107)的 `SkillConfig` 没有设置 `kind`,运行时通过 `config.kind ?? SkillKind.Damage` 回退。迁移时,所有攻击技能必须显式添加 `kind: SkillKind.Damage`,`?? SkillKind.Damage` 回退逻辑可在迁移完成后移除。
|
||||
|
||||
### call_hero 字段处置
|
||||
|
||||
`SkillConfig` 中存在 `call_hero?: number` 字段(召唤技能召唤英雄 ID)。当前无技能配置使用此字段。在 `SkillTemplate` 中暂不保留,如后续需要可通过 `defaults` 扩展或单独处理。
|
||||
|
||||
## 配置示例
|
||||
|
||||
### 基座配置(SkillSet.ts)— 伤害类
|
||||
|
||||
```typescript
|
||||
// 普通攻击 — 伤害类基座
|
||||
6001: {
|
||||
uuid: 6001, name: "普通攻击", sp_name: "atk", icon: "1026",
|
||||
kind: SkillKind.Damage,
|
||||
act: "atk", readyAnm: "", endAnm: "", EAnm: 0, DAnm: "", ready: 0.2,
|
||||
IType: IType.Melee, RType: RType.linear, EType: EType.collision,
|
||||
speed: 720, DTType: DTType.single, with: 0,
|
||||
defaults: {
|
||||
TGroup: TGroup.Enemy, ap: 100, t_num: 1, hit_count: 1, hitcd: 0.2,
|
||||
},
|
||||
info: "造成攻击力100%的伤害",
|
||||
},
|
||||
|
||||
// 火球 — 伤害类基座,带暴击
|
||||
6101: {
|
||||
uuid: 6101, name: "火球", sp_name: "ball_fire", icon: "1126",
|
||||
kind: SkillKind.Damage,
|
||||
act: "atk", readyAnm: "", endAnm: "", EAnm: 0, DAnm: "", ready: 0.2,
|
||||
IType: IType.remote, RType: RType.linear, EType: EType.collision,
|
||||
speed: 720, DTType: DTType.single, with: 90,
|
||||
defaults: {
|
||||
TGroup: TGroup.Enemy, ap: 100, t_num: 1, hit_count: 1, hitcd: 0.3, crt: 20,
|
||||
},
|
||||
info: "火球攻击",
|
||||
},
|
||||
```
|
||||
|
||||
### 基座配置 — 治疗类
|
||||
|
||||
```typescript
|
||||
// 群体治疗 — 治疗类基座
|
||||
6302: {
|
||||
uuid: 6302, name: "群体治疗", sp_name: "buff_wind", icon: "1292",
|
||||
kind: SkillKind.Heal,
|
||||
act: "atk", readyAnm: "up_green", endAnm: "", EAnm: 0, DAnm: "", ready: 0.2,
|
||||
IType: IType.support, RType: RType.fixed, EType: EType.animationEnd,
|
||||
speed: 720, DTType: DTType.single, with: 0,
|
||||
defaults: {
|
||||
TGroup: TGroup.Team, ap: 300, t_num: 5, hit_count: 1, hitcd: 0.2,
|
||||
},
|
||||
info: "治疗基座",
|
||||
},
|
||||
|
||||
// 持续恢复 — 治疗类基座
|
||||
6304: {
|
||||
uuid: 6304, name: "持续恢复", sp_name: "buff_wind", icon: "1292",
|
||||
kind: SkillKind.Heal,
|
||||
act: "atk", readyAnm: "up_green", endAnm: "", EAnm: 0, DAnm: "", ready: 0.2,
|
||||
IType: IType.support, RType: RType.fixed, EType: EType.animationEnd,
|
||||
speed: 720, DTType: DTType.single, with: 0,
|
||||
defaults: {
|
||||
TGroup: TGroup.Team, ap: 200, t_num: 5, hit_count: 3, hitcd: 0.2,
|
||||
},
|
||||
info: "持续恢复基座",
|
||||
},
|
||||
```
|
||||
|
||||
### 基座配置 — 护盾类
|
||||
|
||||
```typescript
|
||||
// 护盾 — 护盾类基座
|
||||
6301: {
|
||||
uuid: 6301, name: "护盾", sp_name: "buff_wind", icon: "1255",
|
||||
kind: SkillKind.Shield,
|
||||
act: "atk", readyAnm: "up_blue", endAnm: "", EAnm: 0, DAnm: "", ready: 0.2,
|
||||
IType: IType.support, RType: RType.fixed, EType: EType.animationEnd,
|
||||
speed: 720, DTType: DTType.single, with: 0,
|
||||
defaults: {
|
||||
TGroup: TGroup.Self, ap: 3, t_num: 1, hit_count: 1, hitcd: 0.2,
|
||||
},
|
||||
info: "护盾基座",
|
||||
},
|
||||
```
|
||||
|
||||
### 基座配置 — Buff 类
|
||||
|
||||
```typescript
|
||||
// 攻击强化 — buff 类基座
|
||||
6401: {
|
||||
uuid: 6401, name: "攻击强化", sp_name: "buff_wind", icon: "1255",
|
||||
kind: SkillKind.Support,
|
||||
act: "atk", readyAnm: "up_ap", endAnm: "", EAnm: 0, DAnm: "", ready: 0.2,
|
||||
IType: IType.support, RType: RType.fixed, EType: EType.animationEnd,
|
||||
speed: 720, DTType: DTType.single, with: 0,
|
||||
defaults: {
|
||||
TGroup: TGroup.Team, ap: 0, t_num: 5, hit_count: 1, hitcd: 0.2,
|
||||
buffs: [{ attr: Attrs.ap, value: 5 }],
|
||||
},
|
||||
info: "攻击力强化",
|
||||
},
|
||||
```
|
||||
|
||||
### 角色配置(heroSet.ts)— 同技能不同角色差异化
|
||||
|
||||
```typescript
|
||||
// 见习战士:受击2次触发护盾 → 自己加3层盾
|
||||
5001: {
|
||||
uuid: 5001, name: "见习战士", ...,
|
||||
skills: { 6002: { uuid: 6002, lv: 1, cd: 1.5, ccd: 0 } },
|
||||
atked: [{ s_uuid: 6301, t_num: 2 }],
|
||||
// 6301 基座 defaults: TGroup.Self, ap:3, t_num:1
|
||||
// → 使用基座默认值,给自己加3次盾
|
||||
},
|
||||
|
||||
// 盾骑士:受击2次触发护盾 → 全队加2层盾(覆盖 TGroup 和 ap)
|
||||
5002: {
|
||||
uuid: 5002, name: "盾骑士", ...,
|
||||
skills: { 6002: { uuid: 6002, lv: 1, cd: 1.5, ccd: 0 } },
|
||||
atked: [{ s_uuid: 6301, t_num: 2,
|
||||
overrides: { TGroup: TGroup.Team, ap: 2, t_num: 5, hit_count: 3 }
|
||||
}],
|
||||
// → kind=Shield 由基座固定,TGroup/ap/t_num 由角色覆盖
|
||||
},
|
||||
|
||||
// 牧师:普攻2次触发群体治疗 → 恢复 300%(使用基座默认值)
|
||||
5301: {
|
||||
uuid: 5301, name: "牧师", ...,
|
||||
skills: { 6004: { uuid: 6004, lv: 1, cd: 1.2, ccd: 0 } },
|
||||
atking: [{ s_uuid: 6302, t_num: 2 }],
|
||||
// → 6302 基座 defaults: TGroup.Team, ap:300, t_num:5, hit_count:1
|
||||
},
|
||||
|
||||
// 医师:普攻2次触发持续治疗 → 共3次每次200%(覆盖 hit_count)
|
||||
5302: {
|
||||
uuid: 5302, name: "医师", ...,
|
||||
skills: { 6004: { uuid: 6004, lv: 1, cd: 1.2, ccd: 0 } },
|
||||
atking: [{ s_uuid: 6304, t_num: 2,
|
||||
overrides: { hit_count: 3 }
|
||||
}],
|
||||
// → 6304 基座 defaults: ap:200, t_num:5, hit_count:3 → 只覆盖了 hit_count
|
||||
},
|
||||
```
|
||||
|
||||
## SCastSystem 改动要点
|
||||
|
||||
1. 所有读取 `config.ap`、`config.TGroup`、`config.hit_count` 等逻辑参数的地方,改为从 `resolveSkillParams()` 获取
|
||||
2. `kind` 始终从 `template.kind` 获取,不参与覆盖
|
||||
3. `applyFriendlySkillEffects` 和 `applyActualFriendlyEffect` 的参数从 `config: SkillConfig` 调整为接收 `SkillTemplate` + resolved 后的 `SkillDefaults`
|
||||
4. buff 应用逻辑的 `switch` 分支扩展时只需改一处
|
||||
5. 卡牌技能路径:调用 `resolveSkillParams(template, undefined, undefined)` 获取参数
|
||||
6. SkillUpList 升级加成统一应用于 resolved 之后的参数
|
||||
|
||||
## HeroAtkSystem 改动要点
|
||||
|
||||
`HeroAtkSystem.ts` 直接读取 `config.ap` 用于伤害计算和复活技能。必须同步适配:
|
||||
- 伤害计算路径(~第 287-292 行):从 resolved defaults 获取 `ap`
|
||||
- 复活技能路径(~第 220-236 行):从 resolved defaults 获取 `ap` 和 `readyAnm`
|
||||
|
||||
## 兼容性
|
||||
|
||||
- 现有攻击技能(6001-6107):数值从顶层字段移入 `defaults`,必须显式添加 `kind: SkillKind.Damage`
|
||||
- 触发技能配置(atking/atked 等):旧格式 `{s_uuid, t_num}` 通过类型兼容继续工作,`overrides` 为可选,现有代码无需改动即可兼容
|
||||
- 卡牌技能:使用 `template.defaults`,无需角色上下文
|
||||
- SkillUpList:升级加成作用于最终 resolved 后的参数,调用位置不变
|
||||
|
||||
## 迁移策略
|
||||
|
||||
分步进行,每步可独立验证:
|
||||
|
||||
1. **Step 1:新增接口** — 添加 `SkillTemplate`、`SkillDefaults`、`HeroOverrides`、`TriggerSkillConf` 类型定义,与旧 `SkillConfig` 并存
|
||||
2. **Step 2:迁移 SkillSet 数据** — 逐个将现有技能配置从旧格式转为新格式。注意:所有攻击技能(6001-6107)必须显式添加 `kind: SkillKind.Damage`;`DAnm`/`EAnm` 保留在模板顶层
|
||||
3. **Step 3:迁移 heroSet 数据** — 为需要差异化的角色添加 overrides;同步更新 `HeroAttrsComp.ts` 中 atking/atked 的内联类型定义为 `TriggerSkillConf[]`
|
||||
4. **Step 4:重构 SCastSystem + HeroAtkSystem** — 引入 `resolveSkillParams()`,替换所有直接读取 config 字段的逻辑,SkillUpList 统一应用于 resolved 参数
|
||||
5. **Step 5:适配引用文件** — 逐个更新 Skill.ts、SkillView.ts、SMoveSystem.ts、HeroViewComp.ts、CardComp.ts 等消费者
|
||||
6. **Step 6:清理** — 删除旧 `SkillConfig` 接口,全局 `BuffConf.buff` → `BuffConf.attr` 重命名(配置数据 + 运行时代码),移除 `?? SkillKind.Damage` 回退逻辑
|
||||
|
||||
## 涉及文件
|
||||
|
||||
| 文件 | 改动级别 | 改动内容 |
|
||||
|------|----------|----------|
|
||||
| `assets/script/game/common/config/SkillSet.ts` | 高 | 重构接口,新增 SkillTemplate/SkillDefaults,数据迁移 |
|
||||
| `assets/script/game/common/config/heroSet.ts` | 中 | HSkillInfo 增加 overrides,触发配置类型更新 |
|
||||
| `assets/script/game/common/config/HeroAttrs.ts` | 低 | BuffConf 字段名 buff → attr |
|
||||
| `assets/script/game/hero/SCastSystem.ts` | 高 | 参数解析逻辑重构,引入 resolveSkillParams,SkillUpList 适配 |
|
||||
| `assets/script/game/hero/HeroAtkSystem.ts` | 高 | 伤害计算和复活技能读取 ap/readyAnm 适配新接口 |
|
||||
| `assets/script/game/hero/SkillTriggerHelper.ts` | 中 | 触发技能传参适配,传递 overrides |
|
||||
| `assets/script/game/hero/HeroAttrsComp.ts` | 中 | atking/atked 内联类型更新为 TriggerSkillConf[] |
|
||||
| `assets/script/game/hero/HeroViewComp.ts` | 低 | 读取 DAnm 字段,接口名变更 |
|
||||
| `assets/script/game/skill/Skill.ts` | 高 | skill.load() 适配新接口,区分模板字段和逻辑参数 |
|
||||
| `assets/script/game/skill/SkillView.ts` | 低 | SkillConfig 引用改为 SkillTemplate |
|
||||
| `assets/script/game/skill/SMoveSystem.ts` | 低 | 读取 speed/RType 等表现字段,接口名变更 |
|
||||
| `assets/script/game/skill/STimeComp.ts` | 低 | 读取 EType/time,接口名变更 |
|
||||
| `assets/script/game/hero/Hero.ts` | 中 | 英雄初始化,传递 overrides |
|
||||
| `assets/script/game/hero/Mon.ts` | 中 | 怪物初始化,传递 overrides |
|
||||
| `assets/script/game/map/CardComp.ts` | 低 | SkillSet 引用适配 |
|
||||
| `assets/script/game/map/IBoxComp.ts` | 低 | SkillSet 引用适配 |
|
||||
|
||||
以下文件仅读取 SkillTemplate 中保留顶层的字段(name、icon、IType 等),改动级别极低或无需改动:
|
||||
`TooltipCom.ts`、`SIconComp.ts`、`SkillBoxComp.ts`、`HlistComp.ts`、`HInfoComp.ts`、`MissionHeroComp.ts`、`MissionEconomy.ts`、`MissionComp.ts`
|
||||
Reference in New Issue
Block a user