Files
pixelheros/assets/script/game/common/config/HeroSkillDesc.ts
walkpan 3fbaebbcc5 feat(map, skill): 新增HInfoComp的cd_node属性并统一技能描述分隔符
为HInfoComp组件新增cd_node序列化节点引用
修正HeroSkillDesc中的技能描述分隔符,将→替换为:以对齐文档与实际输出格式
2026-05-25 19:56:25 +08:00

143 lines
6.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* @file HeroSkillDesc.ts
* @description 英雄技能描述生成器
*
* 职责:
* 将英雄配置heroInfo中的特殊触发技能转换为可读的描述文本
* 供 HInfoComp 的 info_node 显示。每行一个技能,用换行符连接。
*
* 生成格式:
* {触发条件}:{技能名} {效果描述}
* 例: "受击2次:护盾 护盾2次"
* 例: "攻击1次:攻击强化 全体友方攻击力提升5点持续1次"
* 例: "场上存活:攻击加成 英雄攻击力+20%"
*
* 依赖:
* - heroSet :SkillTriggerDesc触发条件模板、SkillTriggerType触发类型枚举、heroInfo
* - SkillSet :SkillSet技能基础配置、mergeSkillParams合并覆盖参数、SkillKind技能类型枚举
* - FieldSkillSet驻场技能配置
*/
import { heroInfo, SkillTriggerDesc, SkillTriggerType } from "./heroSet";
import { FieldSkillSet, mergeSkillParams, SkillKind, SkillOverrides, SkillSet } from "./SkillSet";
/**
* 需要遍历的触发技能类型列表(不含 Field 和 Revive这两者结构不同需单独处理
* Field:number[](驻场技能 uuid 列表)
* Revive:{ s_uuid, r_num, upr }(单个对象)
*/
const TRIGGER_KEYS: SkillTriggerType[] = [
SkillTriggerType.Call, // 召唤时触发
SkillTriggerType.Dead, // 死亡时触发
SkillTriggerType.FStart, // 战斗开始时触发
SkillTriggerType.FEnd, // 战斗结束时触发
SkillTriggerType.Atking, // 攻击后触发
SkillTriggerType.Atked, // 受击后触发
];
/**
* 根据合并后的技能配置生成效果描述文本
*
* 按 SkillKind 分类输出:
* - Heal :"治疗伙伴{ap}"
* - Shield :"护盾{ap}次"ap 表示可抵挡次数)
* - Gold :"金币+{gold}"
* - Support :直接使用技能自身的 info 字段(如"全体友方攻击力提升5点持续1次"
* - Damage :"伤害{ap}%" + 可选的暴击/冰冻/击退/多段附加描述
*
* @param skill 经过 mergeSkillParams 合并 overrides 后的完整技能配置
* @returns 效果描述字符串,各部分用空格连接
*/
function buildEffectDesc(skill: ReturnType<typeof mergeSkillParams>): string {
const parts: string[] = [];
const kind = skill.kind;
if (kind === SkillKind.Heal) {
// 治疗类ap 为治疗量
parts.push(`治疗伙伴${skill.ap}`);
} else if (kind === SkillKind.Shield) {
// 护盾类ap 为可抵挡的攻击次数
parts.push(`护盾${skill.ap}`);
} else if (kind === SkillKind.Gold) {
// 金币类gold 为获取金币数
parts.push(`金币+${skill.gold ?? 0}`);
} else if (kind === SkillKind.Support) {
// 辅助类buff直接使用技能的 info 描述文案
parts.push(String(skill.info));
} else if (kind === SkillKind.Damage || kind === undefined) {
// 伤害类(含无 kind 的默认技能ap 为攻击力百分比
parts.push(`伤害${skill.ap}%`);
// 多段伤害
if (skill.hit_count > 1) parts.push(`${skill.hit_count}`);
// 附加暴击率
if (skill.crt) parts.push(`暴击+${skill.crt}%`);
// 附加冰冻概率
if (skill.frz) parts.push(`冰冻+${skill.frz}%`);
// 附加击退概率
if (skill.bck) parts.push(`击退+${skill.bck}%`);
}
return parts.join(" ");
}
/**
* 将英雄的特殊触发技能配置转换为可读描述文本
*
* 处理流程:
* 1. 遍历 6 种触发类型call/dead/fstart/fend/atking/atked从 hero[key] 取出
* {s_uuid, t_num, overrides?}[],通过 s_uuid 查 SkillSet 获取技能基础配置,
* 用 mergeSkillParams 合并 overrides 得到实际参数,再拼成一行描述。
* 2. 单独处理 field驻场技能从 FieldSkillSet 查找配置,输出光环效果。
* 3. 单独处理 revive复活技能结构与上述不同是单个对象而非数组。
*
* 输出示例5006 疾风刺客):
* "攻击1次:攻击强化 全体友方攻击力提升5点持续1次
* 死亡时:攻击强化 全体友方攻击力提升8点持续1次"
*
* @param hero 英雄静态配置HeroInfo 中的条目)
* @returns 多行技能描述文本,每行一个技能,用 \n 分隔
*/
export function buildSkillDesc(hero: heroInfo): string {
const lines: string[] = [];
// ---- 第一步:处理 6 种标准触发技能(结构均为 {s_uuid, t_num, overrides?}[] ----
for (const key of TRIGGER_KEYS) {
const arr = hero[key] as { s_uuid: number; t_num: number; overrides?: SkillOverrides }[] | undefined;
if (!arr?.length) continue;
// 从 SkillTriggerDesc 取模板,如 "攻击n次"、"受击n次"、"召唤时" 等
const tpl = SkillTriggerDesc[key] ?? key;
for (const item of arr) {
// 通过 s_uuid 查找技能基础配置
const base = SkillSet[item.s_uuid];
if (!base) continue;
// 合并 overrides 得到实际技能参数ap/hit_count/crt/frz/bck 等可能被覆盖)
const skill = mergeSkillParams(base, item.overrides);
// 将模板中的 "n" 替换为实际触发次数
const trigger = tpl.replace("n", String(item.t_num));
lines.push(`${trigger}:${base.name} ${buildEffectDesc(skill)}`);
}
}
// ---- 第二步处理驻场技能field—— 结构为 number[]uuid 指向 FieldSkillSet ----
const fieldUuids = hero[SkillTriggerType.Field] as number[] | undefined;
if (fieldUuids?.length) {
const tpl = SkillTriggerDesc[SkillTriggerType.Field] ?? "场上存活";
for (const uuid of fieldUuids) {
const fs = FieldSkillSet[uuid];
if (fs) lines.push(`${tpl}:${fs.name} ${fs.info}`);
}
}
// ---- 第三步处理复活技能revive—— 结构为 {s_uuid, r_num, upr} 单个对象 ----
const revive = hero[SkillTriggerType.Revive] as { s_uuid: number; r_num: number; upr: number } | undefined;
if (revive) {
const base = SkillSet[revive.s_uuid];
if (base) {
const skill = mergeSkillParams(base);
const tpl = SkillTriggerDesc[SkillTriggerType.Revive] ?? "复活时";
lines.push(`${tpl} : ${base.name} ${buildEffectDesc(skill)}`);
}
}
return lines.join("\n");
}