# HeroBox 当前等级技能信息面板设计(方案 B:独立 SkillDescSet 表) ## 背景与目标 HeroBoxComp 当前只展示数值属性(AP/HP/暴击/攻速…),没有技能信息区。需要在面板中加入**当前英雄当前等级**的技能描述。 关键诉求(用户已确认): - 抛弃 `heroSet` 的手写 `infos[]` 文案,改用**结构化字段 + overrides 动态拼描述**,杜绝"数值改了忘改文案"的漂移。 - 描述必须反映**运行时当前等级**(evolve 已应用的最终配置),而非 1 级静态配置。 - 数据与展示分离,不侵入战斗配置(SkillSet/FieldSkillSet 一行不动)。 ## 现状分析(已验证) - `HeroSkillDesc.buildSkillDesc(hero)` 已存在,且**触发框架已通用**:按触发类型遍历 → 查 `SkillSet` → `mergeSkillParams` 合并 overrides → 拼行。 - 其 `buildEffectDesc` 按 `SkillKind` 硬编码 if-else,且 Support 类直接复用 `skill.info` 写死的数值文案 → **这是唯一不通用的点,也是漂移根因**。 - `HeroAttrsComp` 运行时持有**应用 evolve 后的当前等级最终触发配置**(Hero.ts 中 base → 逐级 evolve 覆盖),字段结构与 `heroInfo` 完全一致。 - `buildSkillDesc` 现有 2 个调用方(HersListComp:205、HInfoComp:448)都传静态 `heroInfo`(卡池/商店场景,无运行时 model)。**签名不能粗暴改成只收 model**。 ## 方案 B 总体形态 三层都通用,纯配置驱动: 1. **触发框架**:不动(已通用)。 2. **技能数值**:不动(SkillSet + overrides)。 3. **效果文案**:新增 `SkillDescSet` 独立表,把硬编码 if-else 变成"结构化配置 + 占位符模板"。 结果:`buildSkillDesc(source)` 成为纯渲染器。**新增英雄 = 纯配置,零代码**;新增技能 = 补一行 SkillDescSet 配置。 ## 设计细节 ### 1. 生成器入参抽象(兼容两种数据源) 抽取窄接口,`heroInfo` 与 `HeroAttrsComp` 天然都满足(字段名、结构一致): ```ts export interface ISkillDescSource { call?: { s_uuid: number; t_num: number; overrides?: SkillOverrides }[]; dead?: { s_uuid: number; t_num: number; overrides?: SkillOverrides }[]; fstart?: { s_uuid: number; t_num: number; overrides?: SkillOverrides }[]; fend?: { s_uuid: number; t_num: number; overrides?: SkillOverrides }[]; atking?: { s_uuid: number; t_num: number; overrides?: SkillOverrides }[]; atked?: { s_uuid: number; t_num: number; overrides?: SkillOverrides }[]; field?: number[]; revive?: { s_uuid: number; r_num: number; upr: number }; } // buildSkillDesc(source: ISkillDescSource): string ``` - HeroBoxComp 传 `this.model` → 显示当前等级。 - 卡池/商店传 `heroInfo` → 显示 1 级(无 model 场景),老调用方零改动。 ### 2. SkillDescSet 结构化描述表(核心) 新文件 `assets/script/game/common/config/SkillDescSet.ts`,与 SkillSet 同 key、纯 UI 用,只覆盖需要描述的触发技能(普攻/怪物技能跳过): ```ts export interface SkillDescConfig { /** 效果动词,如 "攻击力"/"暴击率"/"护盾" */ verb: string; /** 单位,如 ""/"%"/"次" */ unit: string; /** 永久模式取值字段(overrides 直接改写),通常 "ap" */ permField: keyof SkillOverrides; /** 计时模式取值字段(overrides 走 timed_buff_id),通常 "buff_value" */ timedField?: keyof SkillOverrides; /** 永久模式文案模板 */ templPerm: string; /** 计时模式文案模板(含 {dur}),不填则该技能不支持计时模式 */ templTimed?: string; } ``` 模板占位符:`{target}` `{value}` `{unit}` `{verb}` `{dur}`。 渲染逻辑(生成器内统一处理): - `target`:TGroup.Self→"自身";Team+hit_count>1→"随机{hit_count}名队友";Team/Ally→"全体友方";Enemy→"敌方"。 - 计时判定:合并后 skill 存在 `timed_buff_id` → 用 `templTimed`+`timedField`;否则 `templPerm`+`permField`。 - `value`:从合并后 skill 对应字段取值;`dur`:`buff_duration` 值。 - 查不到 SkillDescSet 条目 → 回退旧 `skill.info`(保证未迁移技能不报错、渐进迁移)。 ### 3. HeroSkillDesc 改造 - 入参从 `heroInfo` 改为 `ISkillDescSource`。 - 删除 `buildEffectDesc` 的 SkillKind 硬编码分支,改为查 `SkillDescSet[uuid]` 渲染。 - `field`(驻场)继续直接读 `FieldSkillSet[uuid].info`(已结构化 type+value,无需改造)。 - `revive` 用 6501 的模板渲染复活血量百分比。 ### 4. HeroBoxComp 集成 + 迁移范围 **HeroBoxComp 改动**: - 新增 `@property(Label)` 技能描述节点(单 Label 多行,与 HInfoComp 一致;放属性栏下方)。 - `refresh()` 追加:`skill_label.string = buildSkillDesc(this.model)`。 - `applyEmpty()` 清空该 label。 - **展示范围**:仅触发技能(atking/atked/dead/fstart/fend/field/revive)。普攻不展示——AP/攻速已由数值栏体现,触发技能才是英雄身份核心。 **迁移范围(首批)**: - SkillDescSet 首批覆盖现役英雄涉及的 ~10 个触发技能:6301/6302/6401/6402/6403/6404/6405/6501 + fstart 用的 7111(计时)。 - `infos[]` 字段保留但不再在面板使用(卡池/详情页后续统一迁移,本次不动)。 ## UI 取向(默认,可覆盖) - 格式:单个多行 Label(最省改动,与 HInfoComp 一致)。 - 范围:仅触发技能,不含普攻。 ## 涉及文件 | 文件 | 动作 | |------|------| | `assets/script/game/common/config/SkillDescSet.ts` | 新建 | | `assets/script/game/common/config/HeroSkillDesc.ts` | 改造(入参抽象 + 查表渲染) | | `assets/script/game/map/HeroBoxComp.ts` | 集成技能描述 Label | ## 非目标(YAGNI) - 不改造 SkillSet/FieldSkillSet 结构。 - 不做图标/富文本富 UI(本次纯文本)。 - 不迁移卡池/详情页的 `infos[]` 展示。 - 普攻技能不做描述。