refactor(field): 重构驻场光环数据结构,分离元数据与数值
1. 新增FieldEntry类型,将驻场词条的uuid与生效数值分离 2. 重构FieldSkillSet,移除各档位重复配置,仅保留基础元数据 3. 更新所有使用驻场词条的业务代码,适配新的数据结构 4. 修复数值渲染逻辑,使用词条携带的实际数值而非配置固化值
This commit is contained in:
@@ -258,14 +258,8 @@ export const TriggerSkillNameSet: Record<string, Record<number, string>> = {
|
||||
export function getTriggerSkillName(type: SkillTriggerType, s_uuid: number): string {
|
||||
const group = TriggerSkillNameSet[type];
|
||||
if (group) {
|
||||
// 直接命中
|
||||
const direct = group[s_uuid];
|
||||
if (direct) return direct;
|
||||
// 驻场光环 +/++ 档(如 7202/7402)回退到基础档命名(7002)
|
||||
if (type === SkillTriggerType.Field) {
|
||||
const base = group[7000 + (s_uuid % 100)];
|
||||
if (base) return base;
|
||||
}
|
||||
}
|
||||
// 驻场光环 uuid 存于 FieldSkillSet,触发技能存于 SkillSet,分别兜底
|
||||
if (type === SkillTriggerType.Field) {
|
||||
@@ -337,11 +331,20 @@ export interface LvTriggerEntry {
|
||||
export type TriggerGrouped = Record<number /*s_uuid*/, LvTriggerEntry[]>;
|
||||
|
||||
/**
|
||||
* 驻场光环按等级解锁:运行时取 ≤英雄等级 的最大 lv 档的 uuids。
|
||||
* 驻场光环词条:uuid 指向 FieldSkillSet 底座(类型/图标/名称元数据),
|
||||
* value 为该词条实际生效数值(由配置处按档位指定,不再随 uuid 分档)。
|
||||
*/
|
||||
export interface FieldEntry {
|
||||
uuid: number;
|
||||
value: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 驻场光环按等级解锁:运行时取 ≤英雄等级 的最大 lv 档的词条列表。
|
||||
*/
|
||||
export interface LvFieldEntry {
|
||||
lv: number;
|
||||
uuids: number[];
|
||||
uuids: FieldEntry[];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -430,9 +433,9 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
uuid: 5005, name: "战歌法师", path: "hm2", fac: FacSet.HERO, card_lv: 1, lv: 1, type: HType.Long, grow_type: HGrowType.Mage, hp: 143, ap: 40,
|
||||
skills: { 6013: { uuid: 6013, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Mid3].cd, ccd: 0 } },
|
||||
field: [
|
||||
{ lv: 1, uuids: [7002] },
|
||||
{ lv: 3, uuids: [7202] },
|
||||
{ lv: 5, uuids: [7402] },
|
||||
{ lv: 1, uuids: [{ uuid: 7002, value: 0.1 }] },
|
||||
{ lv: 3, uuids: [{ uuid: 7002, value: 0.2 }] },
|
||||
{ lv: 5, uuids: [{ uuid: 7002, value: 0.3 }] },
|
||||
],
|
||||
info: "",
|
||||
},
|
||||
@@ -496,9 +499,9 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
uuid: 5105, name: "风怒先知", path: "hm1", fac: FacSet.HERO, card_lv: 2, lv: 1, type: HType.Long, grow_type: HGrowType.Mage, hp: 287, ap: 80,
|
||||
skills: { 6013: { uuid: 6013, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Mid2].cd, ccd: 0 } },
|
||||
field: [
|
||||
{ lv: 1, uuids: [7006] },
|
||||
{ lv: 3, uuids: [7206] },
|
||||
{ lv: 5, uuids: [7406] },
|
||||
{ lv: 1, uuids: [{ uuid: 7006, value: 0.1 }] },
|
||||
{ lv: 3, uuids: [{ uuid: 7006, value: 0.2 }] },
|
||||
{ lv: 5, uuids: [{ uuid: 7006, value: 0.3 }] },
|
||||
],
|
||||
info: "",
|
||||
},
|
||||
@@ -575,9 +578,9 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
uuid: 5205, name: "精准术士", path: "hm3", fac: FacSet.HERO, card_lv: 3, lv: 1, type: HType.Long, grow_type: HGrowType.Mage, hp: 430, ap: 120,
|
||||
skills: { 6013: { uuid: 6013, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Mid2].cd, ccd: 0 } },
|
||||
field: [
|
||||
{ lv: 1, uuids: [7004] },
|
||||
{ lv: 3, uuids: [7204] },
|
||||
{ lv: 5, uuids: [7404] },
|
||||
{ lv: 1, uuids: [{ uuid: 7004, value: 0.1 }] },
|
||||
{ lv: 3, uuids: [{ uuid: 7004, value: 0.2 }] },
|
||||
{ lv: 5, uuids: [{ uuid: 7004, value: 0.3 }] },
|
||||
],
|
||||
info: "",
|
||||
},
|
||||
@@ -651,9 +654,9 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
uuid: 5305, name: "领域贤者", path: "hm2", fac: FacSet.HERO, card_lv: 4, lv: 1, type: HType.Long, grow_type: HGrowType.Mage, hp: 573, ap: 160,
|
||||
skills: { 6013: { uuid: 6013, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Mid2].cd, ccd: 0 } },
|
||||
field: [
|
||||
{ lv: 1, uuids: [7005, 7006] },
|
||||
{ lv: 3, uuids: [7205, 7206] },
|
||||
{ lv: 5, uuids: [7405, 7406] },
|
||||
{ lv: 1, uuids: [{ uuid: 7005, value: 0.2 }, { uuid: 7006, value: 0.1 }] },
|
||||
{ lv: 3, uuids: [{ uuid: 7005, value: 0.4 }, { uuid: 7006, value: 0.2 }] },
|
||||
{ lv: 5, uuids: [{ uuid: 7005, value: 0.6 }, { uuid: 7006, value: 0.3 }] },
|
||||
],
|
||||
info: "",
|
||||
},
|
||||
@@ -690,9 +693,9 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
],
|
||||
},
|
||||
field: [
|
||||
{ lv: 1, uuids: [7006] },
|
||||
{ lv: 3, uuids: [7206] },
|
||||
{ lv: 5, uuids: [7406] },
|
||||
{ lv: 1, uuids: [{ uuid: 7006, value: 0.1 }] },
|
||||
{ lv: 3, uuids: [{ uuid: 7006, value: 0.2 }] },
|
||||
{ lv: 5, uuids: [{ uuid: 7006, value: 0.3 }] },
|
||||
],
|
||||
info: "",
|
||||
},
|
||||
@@ -754,9 +757,9 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
],
|
||||
},
|
||||
field: [
|
||||
{ lv: 1, uuids: [7007] },
|
||||
{ lv: 3, uuids: [7207] },
|
||||
{ lv: 5, uuids: [7407] },
|
||||
{ lv: 1, uuids: [{ uuid: 7007, value: 0.1 }] },
|
||||
{ lv: 3, uuids: [{ uuid: 7007, value: 0.2 }] },
|
||||
{ lv: 5, uuids: [{ uuid: 7007, value: 0.3 }] },
|
||||
],
|
||||
info: "",
|
||||
},
|
||||
@@ -898,8 +901,8 @@ export function resolveTriggerByLv(grouped: TriggerGrouped | undefined, lv: numb
|
||||
return result;
|
||||
}
|
||||
|
||||
/** 解析驻场光环在目标等级下的有效 uuid 列表(取 ≤lv 的最大档) */
|
||||
export function resolveFieldByLv(field: LvFieldEntry[] | undefined, lv: number): number[] {
|
||||
/** 解析驻场光环在目标等级下的有效词条列表(取 ≤lv 的最大档) */
|
||||
export function resolveFieldByLv(field: LvFieldEntry[] | undefined, lv: number): FieldEntry[] {
|
||||
if (!field || field.length === 0) return [];
|
||||
let pick: LvFieldEntry | undefined;
|
||||
for (const e of field) {
|
||||
@@ -1184,35 +1187,35 @@ function calcTriggerPowerDetailed(
|
||||
return { total, items };
|
||||
}
|
||||
|
||||
/** 计算驻场光环技能在时间窗内的总价值 */
|
||||
function calcFieldSkillValue(field: FieldSkillConfig, hpEff: number, apEff: number, cd: number, scopeMul: number, seconds: number): number {
|
||||
/** 计算驻场光环技能在时间窗内的总价值(value 由词条携带,fs 提供类型元数据) */
|
||||
function calcFieldSkillValue(fs: FieldSkillConfig, value: number, hpEff: number, apEff: number, cd: number, scopeMul: number, seconds: number): number {
|
||||
const weights = HERO_POWER_WEIGHTS;
|
||||
const dps = apEff / cd;
|
||||
|
||||
switch (field.type) {
|
||||
switch (fs.type) {
|
||||
case FieldSkillType.HeroAtk:
|
||||
return field.value * dps * scopeMul * weights.W_DPS_PER_SEC * seconds;
|
||||
return value * dps * scopeMul * weights.W_DPS_PER_SEC * seconds;
|
||||
case FieldSkillType.HeroHp:
|
||||
return field.value * hpEff * scopeMul * weights.W_HP;
|
||||
return value * hpEff * scopeMul * weights.W_HP;
|
||||
case FieldSkillType.HeroSpeed:
|
||||
return field.value * dps * scopeMul * weights.W_DPS_PER_SEC * seconds;
|
||||
return value * dps * scopeMul * weights.W_DPS_PER_SEC * seconds;
|
||||
case FieldSkillType.HeroCrit:
|
||||
return field.value * dps * scopeMul * 0.5 * weights.W_DPS_PER_SEC * seconds;
|
||||
return value * dps * scopeMul * 0.5 * weights.W_DPS_PER_SEC * seconds;
|
||||
case FieldSkillType.HeroCritDamage:
|
||||
return field.value * dps * scopeMul * 0.05 * weights.W_DPS_PER_SEC * seconds;
|
||||
return value * dps * scopeMul * 0.05 * weights.W_DPS_PER_SEC * seconds;
|
||||
case FieldSkillType.HeroStun:
|
||||
case FieldSkillType.HeroWindFury:
|
||||
case FieldSkillType.HeroPuncture:
|
||||
case FieldSkillType.HeroPunctureDmg:
|
||||
return field.value * scopeMul * weights.W_control * 100;
|
||||
return value * scopeMul * weights.W_control * 100;
|
||||
default:
|
||||
return field.value * scopeMul * weights.W_control * 10;
|
||||
return value * scopeMul * weights.W_control * 10;
|
||||
}
|
||||
}
|
||||
|
||||
/** 计算驻场光环的详细价值 */
|
||||
function calcFieldPowerDetailed(fieldUuids: number[] | undefined, hero: heroInfo, targetLv: number, seconds: number): { total: number, items: FieldSkillEval[] } {
|
||||
if (!fieldUuids || fieldUuids.length === 0) return { total: 0, items: [] };
|
||||
function calcFieldPowerDetailed(entries: FieldEntry[] | undefined, hero: heroInfo, targetLv: number, seconds: number): { total: number, items: FieldSkillEval[] } {
|
||||
if (!entries || entries.length === 0) return { total: 0, items: [] };
|
||||
const weights = HERO_POWER_WEIGHTS;
|
||||
const { hp: hpEff, ap: apEff } = getEffectiveStats(hero, targetLv);
|
||||
const cd = getAttackCd(hero);
|
||||
@@ -1220,12 +1223,12 @@ function calcFieldPowerDetailed(fieldUuids: number[] | undefined, hero: heroInfo
|
||||
let total = 0;
|
||||
const items: FieldSkillEval[] = [];
|
||||
|
||||
for (const uuid of fieldUuids) {
|
||||
const field = FieldSkillSet[uuid];
|
||||
if (!field) continue;
|
||||
const value = calcFieldSkillValue(field, hpEff, apEff, cd, scopeMul, seconds) * weights.W_field_alive;
|
||||
for (const entry of entries) {
|
||||
const fs = FieldSkillSet[entry.uuid];
|
||||
if (!fs) continue;
|
||||
const value = calcFieldSkillValue(fs, entry.value, hpEff, apEff, cd, scopeMul, seconds) * weights.W_field_alive;
|
||||
total += value;
|
||||
items.push({ uuid, name: field.name, value });
|
||||
items.push({ uuid: entry.uuid, name: fs.name, value });
|
||||
}
|
||||
return { total, items };
|
||||
}
|
||||
@@ -1269,8 +1272,8 @@ export function calcHeroPowerDetailed(hero: heroInfo, targetLv: number = 1, seco
|
||||
const fstart = hero.fstart ? calcTriggerPowerDetailed(resolveTriggerByLv(hero.fstart, targetLv), hero, targetLv, SkillTriggerType.FStart, seconds) : { total: 0, items: [] as TriggerSkillEval[] };
|
||||
const fend = hero.fend ? calcTriggerPowerDetailed(resolveTriggerByLv(hero.fend, targetLv), hero, targetLv, SkillTriggerType.FEnd, seconds) : { total: 0, items: [] as TriggerSkillEval[] };
|
||||
const dead = hero.dead ? calcTriggerPowerDetailed(resolveTriggerByLv(hero.dead, targetLv), hero, targetLv, SkillTriggerType.Dead, seconds) : { total: 0, items: [] as TriggerSkillEval[] };
|
||||
const fieldUuids = resolveFieldByLv(hero.field, targetLv);
|
||||
const field = fieldUuids.length > 0 ? calcFieldPowerDetailed(fieldUuids, hero, targetLv, seconds) : { total: 0, items: [] as FieldSkillEval[] };
|
||||
const fieldEntries = resolveFieldByLv(hero.field, targetLv);
|
||||
const field = fieldEntries.length > 0 ? calcFieldPowerDetailed(fieldEntries, hero, targetLv, seconds) : { total: 0, items: [] as FieldSkillEval[] };
|
||||
|
||||
let reviveValue = 0;
|
||||
const revive = resolveReviveByLv(hero.revive, targetLv);
|
||||
|
||||
Reference in New Issue
Block a user