refactor(field): 重构驻场光环数据结构,分离元数据与数值

1.  新增FieldEntry类型,将驻场词条的uuid与生效数值分离
2.  重构FieldSkillSet,移除各档位重复配置,仅保留基础元数据
3.  更新所有使用驻场词条的业务代码,适配新的数据结构
4.  修复数值渲染逻辑,使用词条携带的实际数值而非配置固化值
This commit is contained in:
panFD
2026-08-11 22:36:28 +08:00
parent e328892679
commit 450a8b81e5
13 changed files with 196 additions and 228 deletions

View File

@@ -1,4 +1,4 @@
/**
/**
* @file HeroSkillDesc.ts
* @description 英雄技能/能力描述的【唯一文字表达标准层】
*
@@ -28,7 +28,7 @@
* - SkillDescSet:结构化描述模板
* - FieldSkillSet驻场技能、BuffList计时 buff 默认值兜底、Attrs属性枚举
*/
import { SkillTriggerName, SkillTriggerType, TriggerGrouped, LvTriggerEntry, LvFieldEntry, LvReviveEntry, LvBonusEntry, resolveTriggerByLv, resolveFieldByLv, resolveReviveByLv, getTriggerSkillName, HGrowType, calcGrowBonus } from "./heroSet";
import { SkillTriggerName, SkillTriggerType, TriggerGrouped, LvTriggerEntry, LvFieldEntry, LvReviveEntry, LvBonusEntry, FieldEntry, resolveTriggerByLv, resolveFieldByLv, resolveReviveByLv, getTriggerSkillName, HGrowType, calcGrowBonus } from "./heroSet";
import { FieldSkillSet, mergeSkillParams, SkillConfig, SkillKind, SkillOverrides, SkillSet, TGroup } from "./SkillSet";
import { FieldDescSet, FieldValueFmt, SkillDescSet } from "./SkillDescSet";
import { BuffList } from "./BuffSet";
@@ -242,26 +242,26 @@ function buildEffectLine(head: string, skill: SkillConfig): ISkillLine {
* @param showName 是否在行中包含「技能名」片段(英雄面板需要,装备商店不需要)
* @param nameOverride 技能名覆盖(英雄语境传入 heroSet 语境专属命名,缺省用 FieldSkillSet 通用名)
*/
function buildFieldLine(head: string, uuid: number, showName: boolean = true, nameOverride?: string): ISkillLine | null {
const fs = FieldSkillSet[uuid];
function buildFieldLine(head: string, entry: FieldEntry, showName: boolean = true, nameOverride?: string): ISkillLine | null {
const fs = FieldSkillSet[entry.uuid];
if (!fs) return null;
const desc = FieldDescSet[fs.type];
const nameSeg = showName ? `${nameOverride ?? fs.name}` : "";
// 未入表类型回退基础备注 info整行不高亮
if (!desc) return { prefix: `${head}${nameSeg}${fs.info}`, value: "", suffix: "" };
// 数值按格式渲染为高亮片段
// 数值按格式渲染为高亮片段(数值取自词条自身 value
let valueText: string;
switch (desc.fmt) {
case FieldValueFmt.Percent:
valueText = `+${Math.round(fs.value * 100)}%`;
valueText = `+${Math.round(entry.value * 100)}%`;
break;
case FieldValueFmt.IntMinus:
valueText = `-${fs.value}`;
valueText = `-${entry.value}`;
break;
case FieldValueFmt.Int:
default:
valueText = `+${fs.value}`;
valueText = `+${entry.value}`;
break;
}
return { prefix: `${head}${nameSeg}${desc.verb}`, value: valueText, suffix: "" };
@@ -433,8 +433,8 @@ function buildSkillLines(source: ISkillDescSource, showName: boolean = true, sho
if (fieldEntries?.length) {
const tpl = SkillTriggerName[SkillTriggerType.Field] ?? "光环";
if (!showLocked) {
for (const uuid of resolveFieldByLv(fieldEntries, lv)) {
const line = buildFieldLine(`${tpl}:`, uuid, showName);
for (const entry of resolveFieldByLv(fieldEntries, lv)) {
const line = buildFieldLine(`${tpl}:`, entry, showName);
if (line) lines.push(line);
}
} else {
@@ -444,15 +444,15 @@ function buildSkillLines(source: ISkillDescSource, showName: boolean = true, sho
let activeTier: LvFieldEntry | undefined;
for (const tier of sorted) { if (tier.lv <= lv) activeTier = tier; }
if (activeTier) {
for (const uuid of activeTier.uuids) {
const line = buildFieldLine(`Lv${activeTier.lv}: ${tpl} `, uuid, showName);
for (const entry of activeTier.uuids) {
const line = buildFieldLine(`Lv${activeTier.lv}: ${tpl} `, entry, showName);
if (line) lines.push(line);
}
}
for (const tier of sorted) {
if (tier.lv <= lv) continue;
for (const uuid of tier.uuids) {
const line = buildFieldLine(`Lv${tier.lv}: ${tpl} `, uuid, showName);
for (const entry of tier.uuids) {
const line = buildFieldLine(`Lv${tier.lv}: ${tpl} `, entry, showName);
if (!line) continue;
line.locked = true;
lines.push(line);
@@ -525,15 +525,15 @@ export function buildSingleSkillRich(skillUuid: number, overrides?: SkillOverrid
/**
* 装备/驻场光环详情富文本:展示全部词条,数值绿色高亮。
* @param fieldUuids FieldSkillSet 驻场光环 UUID 数组
* @param showName 是否包含「技能名」片段(英雄面板 true装备商店 false
* @returns 多行富文本串,每行一个词条
* @param entries 驻场光环词条数组uuid 指向 FieldSkillSet 底座value 为生效数值)
* @param showName 是否包含「技能名」片段(英雄面板 true装备商店 false
* @returns 多行富文本串,每行一个词条
*/
export function buildEquipRich(fieldUuids: number[], showName: boolean = false): string {
if (!fieldUuids?.length) return "无词条";
export function buildEquipRich(entries: FieldEntry[], showName: boolean = false): string {
if (!entries?.length) return "无词条";
const lines: string[] = [];
for (const uuid of fieldUuids) {
const line = buildFieldLine("", uuid, showName);
for (const entry of entries) {
const line = buildFieldLine("", entry, showName);
if (!line) continue;
const prefix = line.prefix.replace(SKILL_NAME_PATTERN, (m, g1) => skillNameRich(g1));
const text = line.value
@@ -604,14 +604,18 @@ export function buildSkillDescMoreRich(source: ISkillDescSource): string {
}
}
// 驻场光环field技能名档位数字后缀(如 [攻击光环1]/[攻击光环2]),便于玩家识别成长
// 驻场光环field技能名档位数字后缀(按 lv 档升序1 起始),便于玩家识别成长
const fieldEntries = source[SkillTriggerType.Field] as LvFieldEntry[] | undefined;
if (fieldEntries?.length) {
for (const uuid of resolveFieldByLv(fieldEntries, lv)) {
// uuid 百位编码档位7002 基础(0)=1、7202 +(2)=2、7402 ++(4)=3
const tier = Math.floor((uuid % 1000) / 100) / 2 + 1;
const baseName = getTriggerSkillName(SkillTriggerType.Field, uuid);
const line = buildFieldLine("", uuid, true, `${baseName}${tier}`);
// 按 lv 升序确定当前生效档的序号1 起始),作为技能名后缀
const sorted = [...fieldEntries].sort((a, b) => a.lv - b.lv);
let tier = 1;
for (let i = 0; i < sorted.length; i++) {
if (sorted[i].lv <= lv) tier = i + 1;
}
for (const entry of resolveFieldByLv(fieldEntries, lv)) {
const baseName = getTriggerSkillName(SkillTriggerType.Field, entry.uuid);
const line = buildFieldLine("", entry, true, `${baseName}${tier}`);
if (line) lines.push(effectRich(line));
}
}