refactor(hero): 重构额外属性加成系统,统一为bonus字段

1.  将原ap_bonus/hp_bonus/def_bonus三个字段合并为通用的bonus数组结构
2.  新增多属性同时配置能力,支持hp/ap/def百分比加成与crt/frz/stun/para固定百分点加成
3.  更新所有前端编辑器、服务端渲染与游戏运行时逻辑适配新配置格式
4.  添加数据兼容迁移逻辑,自动处理旧版英雄配置数据
This commit is contained in:
panFD
2026-09-07 23:05:30 +08:00
parent a1c8f46c50
commit ed738d2e30
10 changed files with 180 additions and 94 deletions

View File

@@ -417,9 +417,7 @@ export interface heroInfo {
dodge?: number; // 闪避率(百分点,缺省由初始化处兜底为全局默认值)
accuracy?: number; // 命中率(百分点,缺省由初始化处兜底为全局默认值)
skills: Record<number, HSkillInfo>; // 携带技能ID列表
ap_bonus?: LvBonusEntry[]; // 额外攻击加成(按 lv 升序,运行时累加 ≤英雄等级 的所有档)
hp_bonus?: LvBonusEntry[]; // 额外生命加成(按 lv 升序,运行时累加 ≤英雄等级 的所有档)
def_bonus?: LvBonusEntry[]; // 额外防御加成(按 lv 升序,运行时累加 ≤英雄等级 的所有档)
bonus?: LvBonusAttrsEntry[]; // 额外属性加成(按 lv 升序,运行时累加所有 lv ≤ 英雄等级 的档位 attrs;hp/ap/def 按"基础×品质+成长"快照百分比加成,crt/frz/stun/para 为固定百分点累加)
info: string; // 描述文案
/**
* @deprecated 已废弃:无任何 UI/运行时读取。技能提升说明由 HeroSkillText 依据
@@ -526,11 +524,15 @@ export interface LvFieldEntry {
}
/**
* 额外属性加成按等级叠加:运行时累加所有 ≤英雄等级 的档位。
* 额外属性加成按等级叠加:运行时累加所有 ≤英雄等级 的档位 attrs。
* 口径约定:hp/ap/def 为百分比(基数取"基础×品质+成长"快照,多档同键加法叠加不滚雪球);
* crt/frz/stun/para 为固定百分点(直接累加到对应概率属性)。
*/
export interface LvBonusEntry {
export type BonusAttrKey = 'hp' | 'ap' | 'def' | 'crt' | 'frz' | 'stun' | 'para';
export interface LvBonusAttrsEntry {
lv: number;
value: number;
attrs: Partial<Record<BonusAttrKey, number>>;
}
/*
*=============英雄配置列表================
@@ -1089,7 +1091,7 @@ export function resolveFieldByLv(field: LvFieldEntry[] | undefined, lv: number):
return pick ? pick.uuids : [];
}
/** 计算目标等级下额外属性加成(hp/ap/def_bonus 一次性奖励 + 成长类型每级递增) */
/** 计算目标等级下额外属性加成(成长类型每级递增 + bonus 档位累加;bonus 中 hp/ap/def 为百分比,基数取"基础+成长"快照,多档加法叠加) */
function getEvolveBonuses(hero: heroInfo, targetLv: number): { hp: number, ap: number, def: number } {
const lv = Math.max(1, targetLv);
// 成长类型线性增量(仅英雄生效,怪物无 grow_type 时走 Warrior 基准但不影响平衡,因怪物通常不填)
@@ -1097,20 +1099,22 @@ function getEvolveBonuses(hero: heroInfo, targetLv: number): { hp: number, ap: n
let hp = grow.hp;
let ap = grow.ap;
let def = grow.def;
if (hero.hp_bonus) {
for (const e of hero.hp_bonus) {
if (e.lv <= lv) hp += e.value;
}
}
if (hero.ap_bonus) {
for (const e of hero.ap_bonus) {
if (e.lv <= lv) ap += e.value;
}
}
if (hero.def_bonus) {
for (const e of hero.def_bonus) {
if (e.lv <= lv) def += e.value;
if (hero.bonus) {
// 百分比基数:基础值 + 成长快照(不含 bonus 自身,避免滚雪球)
const snapHp = hero.hp + grow.hp;
const snapAp = hero.ap + grow.ap;
const snapDef = hero.def + grow.def;
let hpP = 0, apP = 0, defP = 0;
for (const e of hero.bonus) {
if (e.lv > lv) continue;
hpP += e.attrs.hp ?? 0;
apP += e.attrs.ap ?? 0;
defP += e.attrs.def ?? 0;
// crt/frz/stun/para 为固定百分点,由运行时直接累加到概率属性,此处不结算
}
hp += Math.round(snapHp * hpP / 100);
ap += Math.round(snapAp * apP / 100);
def += Math.round(snapDef * defP / 100);
}
return { hp, ap, def };
}