# 英雄专属武器系统设计 - 日期:2026-08-21 - 状态:已评审(brainstorming 阶段用户逐节确认) - 涉及文件:`HeroWeaponSet.ts`(新增)、`heroSet.ts`、`HeroAttrs.ts`、`HeroAttrsComp.ts`、`SingletonModuleComp.ts`、`GameEvent.ts`、`GameSet.ts`、`EquipSet.ts`(改名 TalentSet) ## 1. 背景与目标 现有"装备"(`EquipSet.ts`,8701~8820 段)是**全体驻场光环卡**:购买后全队加属性,经 `EquipBoxComp → FieldSkillHelper` 全局聚合。 本设计新增**英雄专属武器**:每个英雄天生绑定一件专属武器,不可卸下、不可更换;词条只作用于该英雄本身;与现有光环卡**并存**,光环卡在表述上改名为**战队天赋**。 核心特性: - 武器通过**锻造**成长:每次锻造 = 等级 +1,并从词条池加权随机获得 1 条词条(暗黑式:数值在区间内随机)。 - 抽中**已有词条则数值累加**,新词条则新增一条。 - 等级上限 **16 级**;**特定里程碑等级必得该英雄专属词条**(数值随机,合并到同 attr)。 - 0 级白板武器自带 1 条**初始专属词条**。 - **品质按等级阶梯跃升**,与词条数脱钩。 - **重铸**:看广告将武器归零(0 级 0 随机词条),已投入材料全部返还,初始专属词条重新 roll。 - 武器是**局外资产**,随云存档持久化;局内只有战斗,不产生、不修改武器,开局快照生效。 ## 2. 数据结构(HeroWeaponSet.ts,新增) 位置:`assets/script/game/common/config/HeroWeaponSet.ts`,与 `EquipSet.ts`(将改名 `TalentSet.ts`)平级。 ```typescript import { Attrs } from "./HeroAttrs"; /** 武器品质(按等级阶梯推导,不存储) */ export enum WeaponQuality { Fine = 1, // 优秀(绿)0~3 级 Superior = 2, // 精良(蓝)4~7 级 Epic = 3, // 史诗(紫)8~11 级 Legend = 4, // 传说(橙)12~15 级 Unique = 5, // 唯一(红)16 级满级 } /** 词条池条目:attr 指向 Attrs 枚举,roll 时 value 在 [min, max] 内随机 */ export interface AffixPoolEntry { attr: Attrs; min: number; // 数值型=整数下限;概率型=百分点下限 max: number; weight: number; // 抽取权重 } /** 专属词条里程碑:到达 level 必得,value 在 [min, max] 内随机后合并到同 attr */ export interface ExclusiveAffix { level: number; // 0=初始自带;1~16=锻造到达解锁 attr: Attrs; min: number; max: number; } /** 武器底座:key=英雄模板 uuid(段位 9001-9099),只定义规则不含实例 */ export interface HeroWeaponBase { hero_uuid: number; name: string; icon: string; affix_pool: AffixPoolEntry[]; // 随机词条池(attr 白名单见第 4.4 节) exclusive: ExclusiveAffix[]; // 专属词条里程碑,按 level 升序,必含 1 条 level=0 forge_cost: { item_id: number; count: number }[]; // 单次锻造材料(各级同价) } /** 武器状态:挂在英雄存档上,局外持久化;同 attr 词条已合并 */ export interface HeroWeaponState { level: number; // = 已锻造次数,0=未锻造白板,上限 16 affixes: { attr: Attrs; value: number }[]; // 随机词条+专属词条,同 attr 已累加合并 invested: { item_id: number; count: number }[]; // 累计已投入材料(重铸全量返还用) } ``` ### 品质阶梯 | 等级 | 品质 | 颜色 | |------|------|------| | 0~3 | 优秀(Fine) | 绿 | | 4~7 | 精良(Superior) | 蓝 | | 8~11 | 史诗(Epic) | 紫 | | 12~15 | 传说(Legend) | 橙 | | 16 | 唯一(Unique) | 红 | ```typescript /** 按武器等级推导品质(不存储,实时推导) */ export function getWeaponQuality(level: number): WeaponQuality ``` ### 词条口径(与现有百分比口径一致) - **数值型**(仅 `ap` / `hp_max` / `defense`):Flat 数值,roll 取**整数**。 - **概率型**(其余全部):百分点,roll 取 **1 位小数**。 - 词条池与专属词条仅允许出现第 4.4 节白名单中的 attr,配置加载时校验。 ## 3. 锻造与重铸 ### 3.1 核心纯函数(HeroWeaponSet.ts) ```typescript /** * 锻造一次:等级+1 → 从 affix_pool 加权抽 1 条词条合并(已有 attr 数值累加,新 attr 新增) * → 若新等级命中 exclusive 里程碑,roll 专属词条数值并合并到同 attr * @param base 武器底座 * @param state 当前武器状态(level < 16) * @returns 新状态;base 非法或已满级返回 null 并 mLogger.warn */ export function forgeWeapon(base: HeroWeaponBase, state: HeroWeaponState): HeroWeaponState | null /** * 初始化武器:0 级白板 + roll level=0 的初始专属词条(获得英雄/懒初始化时调用) */ export function initWeapon(base: HeroWeaponBase): HeroWeaponState /** * 重铸:等级与随机词条清零,invested 全量返还,初始专属词条(level=0)重新 roll * @returns 新状态 + 应返还材料列表(= 原 invested 全量) */ export function reforgeWeapon(base: HeroWeaponBase, state: HeroWeaponState): { state: HeroWeaponState; refund: { item_id: number; count: number }[]; } ``` 锻造流程: 1. `level+1`。 2. 从 `affix_pool` 按 weight 加权抽 1 条 attr;在 `[min, max]` 内随机(数值型取整,概率型 1 位小数)。 3. 该 attr 已存在于 `affixes` → 数值累加;否则新增一条。 4. 若 `exclusive` 中存在 `level == 新等级` 的条目 → 每条在 `[min, max]` 内随机并累加到同 attr(不存在则新增)。 5. `invested` 累加本次 `forge_cost`。 ### 3.2 可调参数(GameSet.ts) ```typescript MAX_WEAPON_LEVEL = 16, // 武器锻造等级上限 ``` ### 3.3 材料与货币 - 锻造材料为通用道具(如"精铁"),走现有道具库存;`forge_cost` 各级同价(递增为后续扩展,见 YAGNI)。 - 重铸不消耗材料,改为**看激励视频广告**:广告播放完成回调成功后才执行 `reforgeWeapon`;`invested` 中材料全量返还道具库存。 ## 4. 局内集成(HeroAttrsComp) **原则:局内快照,只读生效。** 开战创建英雄实体时快照武器词条,局内不参与武器增删改。 ### 4.1 快照字段 ```typescript // HeroAttrsComp 新增 /** 武器词条加成缓存(局外武器在开局时快照;数值型=flat,概率型=百分点) */ equip_mods: Partial> = {}; ``` - 不存 `HeroWeaponState`,只存"每条属性加了多少"的聚合结果(`affixes` 已同 attr 合并,直接遍历即可)。 - `reset()` 中清空。 - 局内 UI 若要显示武器名,从 `hero_weapons` 反查,不影响战斗数据。 ### 4.2 快照时机 英雄实体初始化(读 `HeroInfo` 填充属性的同一入口处)追加: ```typescript const weapon = smc.getHeroWeapon(hero_uuid); attrsComp.equip_mods = aggregateWeaponAffixes(weapon); // HeroWeaponSet.ts 纯函数,UI 属性预览可复用 ``` ### 4.3 结算接入(最小侵入,每个 getFinal 加一项) **数值型**:武器 flat **先进基础值,再吃驻场光环百分比**(乘算放大,武器更值钱): ```typescript public getFinalAp(): number { const equipFlat = this.equip_mods[Attrs.ap] ?? 0; const runtimeAp = this.getRuntimeAp(this.ap + equipFlat); const mods = this.aggregateTimedMods(Attrs.ap); return (runtimeAp + mods.flatSum) * (1 + mods.pctSum / 100); } ``` 顺序:武器 flat → 驻场光环 % → 计时 buff。同理 `getFinalHpMax`、`getFinalDefense`。 **概率型**:百分点直接累加(`base + weapon + timed`): ```typescript public getFinalCritical(): number { const base = this.getRuntimeCritical() + (this.equip_mods[Attrs.critical] ?? 0); const mods = this.aggregateTimedMods(Attrs.critical); return base + mods.flatSum + mods.pctSum; } ``` ### 4.4 接入清单(词条池 attr 白名单) | getFinal 方法 | 词条类型 | |---|---| | getFinalAp / getFinalHpMax / getFinalDefense | 数值型 | | getFinalCritical / getFinalCritDamage | 概率型 | | getFinalFreezeChance / getFinalStunChance / getFinalParalyzeChance | 概率型 | | getFinalPunctureChance / getFinalPunctureDmgBonus / getFinalWindFury | 概率型 | | getFinalCriticalRes / getFinalFreezeRes / getFinalStunRes | 概率型 | | getFinalKnockbackChance / getFinalKnockbackDistance / getFinalKnockbackRes | 概率型 | | getFinalVulnerableRes / getFinalParalyzePower | 概率型 | | getEffectiveSkillCd(speed 词条 → 攻速) | 概率型 | ## 5. 局外数据持久化(SingletonModuleComp.data) ```typescript data: any = { // ...现有字段 /** 英雄武器状态:key=英雄模板 uuid;局外资产随云存档持久化,懒初始化 */ hero_weapons: {} as Record, } ``` `GameDate` 接口同步补充上述可选字段。 **数据量评估**:每件武器 JSON 约 40~60 字节(只存 `level/affixes/invested`);50 英雄 ≈ 3KB,远低于微信云存储 1MB 单记录上限。品质不存储(= `getWeaponQuality(level)` 实时推导)。 ### 数据操作方法(封装在 SingletonModuleComp,UI 不直改数据) ```typescript getHeroWeapon(heroUuid: number): HeroWeaponState // 懒初始化:无记录时按底座 initWeapon 生成 0 级白板 forgeHeroWeapon(heroUuid: number): boolean // 校验满级/材料 → 扣材料 → forgeWeapon → 累加 invested → markDataDirty + HeroWeapon_Update reforgeHeroWeapon(heroUuid: number): boolean // 广告成功回调内调用 → 返还 invested 全量 → reforgeWeapon → markDataDirty + HeroWeapon_Update ``` 每个方法内部 `gameDataSync.markDataDirty()` + `oops.message.dispatchEvent(GameEvent.HeroWeapon_Update)`。 ### 新增事件(GameEvent.ts) ```typescript static HeroWeapon_Update = "HeroWeapon_Update"; // 武器锻造/重铸变更(英雄界面刷新) ``` 监听方必须在 `onDestroy`/`onDisable` 注销(oops 规范)。 ## 6. UI 与交互 ### 6.1 英雄界面 · 武器页签(唯一操作入口) - 英雄详情面板新增**武器页签**:武器图标 + 品质边框(按等级变色)+ 等级(x/16)+ 当前词条列表(attr 名 + 数值)。 - 【锻造】按钮:显示本次材料消耗;材料不足或满级(16 级)置灰;点击 → 扣材料锻造 → 弹出结果浮层,高亮本次新增/累加的词条变化与品质跃升提示。 - 【重铸】按钮:弹确认框(说明"观看广告重置武器,全部锻造材料返还")→ 调激励视频广告 → 播放完成回调成功后执行重铸并展示返还材料。 ### 6.2 不做独立武器背包 武器与英雄强绑定,无装备网格列表、无穿戴选择层;武器信息只在英雄界面展示。 ## 7. 现有光环卡改名"战队天赋" - `EquipSet.ts` → `TalentSet.ts`(文件改名);`EquipPoolList` → `TalentPoolList`;`drawEquipCards` → `drawTalentCards`;`findEquipByUuid` → `findTalentByUuid`。 - UI 文案"装备"→"战队天赋";`tip_done.equip` 字段名不变(避免存档兼容问题),语义指向天赋面板。 - 局内组件 `EquipBoxComp` / `MissEquipComp` / `EquipListComp` 等**逻辑不变**,仅引用路径与显示文案调整。 ## 8. 错误处理与边界 - `forgeWeapon` 对未知 `hero_uuid` 底座或已满级(16 级)返回 `null` 并 `mLogger.warn`;`forgeHeroWeapon` 材料不足返回 false,不扣材料。 - 存档中 `hero_weapons[hero_uuid]` 存在但底座表无对应配置(云端数据异常)→ 快照时按 0 级白板处理(`equip_mods = {}`)。 - 词条池 / 专属词条 attr 不在白名单 → 配置加载时 `mLogger.warn` 并跳过该词条。 - 旧存档无 `hero_weapons` 字段 → `Object.assign` 合并后由 `getHeroWeapon` 懒初始化兜底(参照 `getHeroGrowth` 的懒初始化模式)。 - 重铸广告播放失败/中途关闭 → 不执行重铸,数据不变。 - `invested` 与 `level × forge_cost` 不一致(异常数据)→ 重铸以 `invested` 记录为准。 ## 9. 不做的事(YAGNI) - 武器卸下/更换/交易;多武器槽位。 - 词条锁定(洗单词条保留其他词条)。 - 锻造材料随等级递增(初版各级同价)。 - 词条重 roll(洗练)——重铸全洗已覆盖该需求。 - 局内掉落/换武器。