1. 重构天赋系统为一阶基础/二阶专精/三阶超强三阶结构,移除前置天赋要求改为阶位累计点数解锁 2. 新增阶位解锁校验逻辑与天赋点投入统计 3. 重做天赋UI为三阶Tab页签+迷你升级卡样式,支持状态展示与一键升级 4. 补充新的天赋配置与属性加成,更新天赋系统文档 5. 修复属性计算问题,新增暴击伤害与穿刺伤害加成支持
434 lines
19 KiB
TypeScript
434 lines
19 KiB
TypeScript
import { Attrs } from "./HeroAttrs";
|
||
import { HRole } from "./heroSet";
|
||
|
||
/**
|
||
* 天赋系统配置(局外成长:升级即激活,战斗中对英雄属性常驻加成)。
|
||
*
|
||
* 三阶结构(阶位逐级解锁,门槛见 TALENT_TIER_UNLOCK_THRESHOLD):
|
||
* - 一阶·基础天赋(9001-9099):全局生效,对所有英雄叠加;
|
||
* - 二阶·专精天赋(9101-9199):按 HRole 职业过滤,仅对匹配职业的英雄生效;
|
||
* - 三阶·超强天赋(9201-9219):全局(9201-9209)+ 职业(9211-9219)混合,数值幅度约为前两阶的 2 倍。
|
||
*
|
||
* 解锁规则:一阶恒可升级;二阶需一阶累计投入 ≥10 点;三阶需二阶累计投入 ≥10 点。
|
||
* 专精/超强职业天赋不再有独立前置天赋,仅受阶位解锁约束。
|
||
*
|
||
* 结算口径(与项目 buff 规范一致):
|
||
* - percent 模式:按英雄基础值(base_ap/base_hp/hero.def)相对放大;
|
||
* - flat 模式:概率/抗性类按百分点累加,defense 按固定点数累加。
|
||
*/
|
||
|
||
/** 天赋数值模式:percent=按基础值百分比放大;flat=固定值/百分点累加 */
|
||
export enum TalentValueMode {
|
||
Percent = 0,
|
||
Flat = 1,
|
||
}
|
||
|
||
/** 天赋阶位:一阶基础 / 二阶专精 / 三阶超强 */
|
||
export enum TalentTier {
|
||
/** 一阶:基础天赋,全局生效 */
|
||
Basic = 1,
|
||
/** 二阶:专精天赋,按职业过滤 */
|
||
Specialized = 2,
|
||
/** 三阶:超强天赋,全局 + 职业混合 */
|
||
Super = 3,
|
||
}
|
||
|
||
/** 单条属性加成词条 */
|
||
export interface TalentAttrBonus {
|
||
/** 目标属性(Attrs 枚举键) */
|
||
attr: Attrs;
|
||
/** 数值模式 */
|
||
mode: TalentValueMode;
|
||
/** 每级数值(percent 模式为百分比;flat 模式为百分点/固定值) */
|
||
per_lv: number;
|
||
}
|
||
|
||
/** 天赋配置 */
|
||
export interface TalentConfig {
|
||
/** 天赋 uuid(段位见 TalentSet 注释) */
|
||
uuid: number;
|
||
/** 所属阶位(升级校验:升下一阶天赋需前一阶累计投入点数达标) */
|
||
tier: TalentTier;
|
||
/** 天赋名称 */
|
||
name: string;
|
||
/** 描述(UI 展示,{value}/{value2} 为按当前等级计算后的数值占位) */
|
||
info: string;
|
||
/** 图标(uiconsAtlas 帧名,缺省时 UI 端按资源目录回退) */
|
||
icon?: string;
|
||
/** 属性加成词条列表(每级叠加) */
|
||
bonuses: TalentAttrBonus[];
|
||
/** 最大等级 */
|
||
max_lv: number;
|
||
/** 专精/超强职业天赋:仅对该职业英雄生效;全局天赋省略此字段 */
|
||
role?: HRole;
|
||
}
|
||
|
||
/** 单条已解析的加成(等级已乘算) */
|
||
export interface TalentResolvedBonus {
|
||
attr: Attrs;
|
||
mode: TalentValueMode;
|
||
/** 总值 = per_lv × 天赋等级 */
|
||
value: number;
|
||
}
|
||
|
||
/**
|
||
* 天赋加成作用目标的最小结构接口(TS 结构化类型,HeroAttrsComp 天然满足)。
|
||
* Why: 用结构化接口替代直接 import HeroAttrsComp,避免 config → hero → SingletonModuleComp → config 的循环依赖。
|
||
*/
|
||
export interface ITalentTarget {
|
||
ap: number;
|
||
hp: number;
|
||
hp_max: number;
|
||
defense: number;
|
||
/** 基础攻击快照(percent 模式的基数) */
|
||
base_ap: number;
|
||
/** 基础血量快照(percent 模式的基数) */
|
||
base_hp: number;
|
||
/** 防御基础值(percent 模式的基数,等于 hero.def) */
|
||
[key: string]: any;
|
||
}
|
||
|
||
/**
|
||
* 天赋配置表。
|
||
* uuid 段位:9001-9099 一阶基础(全局);9101-9199 二阶专精(按职业);
|
||
* 9201-9209 三阶超强·全局;9211-9219 三阶超强·职业。
|
||
* icon 复用 SkillSet/uiconsAtlas 既有帧名,后续可在编辑器侧替换为专属图标。
|
||
*/
|
||
export const TalentSet: Record<number, TalentConfig> = {
|
||
// ==================== 一阶·基础天赋(9001-9099,全局生效) ====================
|
||
9001: {
|
||
uuid: 9001, tier: TalentTier.Basic, name: "攻击强化", info: "所有英雄攻击 +{value}%", icon: "Stat_Attack_03",
|
||
bonuses: [{ attr: Attrs.ap, mode: TalentValueMode.Percent, per_lv: 3 }],
|
||
max_lv: 5,
|
||
},
|
||
9002: {
|
||
uuid: 9002, tier: TalentTier.Basic, name: "生命强化", info: "所有英雄生命 +{value}%", icon: "Stat_Hp_02",
|
||
bonuses: [{ attr: Attrs.hp_max, mode: TalentValueMode.Percent, per_lv: 5 }],
|
||
max_lv: 5,
|
||
},
|
||
9003: {
|
||
uuid: 9003, tier: TalentTier.Basic, name: "防御强化", info: "所有英雄防御 +{value} 点", icon: "Stat_Defense",
|
||
bonuses: [{ attr: Attrs.defense, mode: TalentValueMode.Flat, per_lv: 8 }],
|
||
max_lv: 5,
|
||
},
|
||
9004: {
|
||
uuid: 9004, tier: TalentTier.Basic, name: "暴击强化", info: "所有英雄暴击率 +{value}%", icon: "Stat_CriticalChance_02",
|
||
bonuses: [{ attr: Attrs.critical, mode: TalentValueMode.Flat, per_lv: 2 }],
|
||
max_lv: 5,
|
||
},
|
||
9005: {
|
||
uuid: 9005, tier: TalentTier.Basic, name: "击晕强化", info: "所有英雄击晕率 +{value}%", icon: "Stat_Stun_01",
|
||
bonuses: [{ attr: Attrs.stun_chance, mode: TalentValueMode.Flat, per_lv: 2 }],
|
||
max_lv: 5,
|
||
},
|
||
9006: {
|
||
uuid: 9006, tier: TalentTier.Basic, name: "冰冻强化", info: "所有英雄冰冻率 +{value}%", icon: "Stat_Freeze",
|
||
bonuses: [{ attr: Attrs.freeze_chance, mode: TalentValueMode.Flat, per_lv: 2 }],
|
||
max_lv: 5,
|
||
},
|
||
9007: {
|
||
uuid: 9007, tier: TalentTier.Basic, name: "击退强化", info: "所有英雄击退距离 +{value}", icon: "Stat_Stun_01",
|
||
bonuses: [{ attr: Attrs.knockback_distance, mode: TalentValueMode.Flat, per_lv: 10 }],
|
||
max_lv: 5,
|
||
},
|
||
// 风怒机制已停用: 9008 风怒强化天赋已移除
|
||
/*
|
||
9008: {
|
||
uuid: 9008, tier: TalentTier.Basic, name: "风怒强化", info: "所有英雄风怒率 +{value}%", icon: "Stat_CriticalComboChance",
|
||
bonuses: [{ attr: Attrs.wfuny, mode: TalentValueMode.Flat, per_lv: 2 }],
|
||
max_lv: 5,
|
||
},
|
||
*/
|
||
|
||
// ==================== 二阶·专精天赋(9101-9199,按职业过滤;一阶投入 10 点解锁) ====================
|
||
9101: {
|
||
uuid: 9101, tier: TalentTier.Specialized, name: "坦克专精", info: "坦克防御 +{value}%、生命 +{value2}%", icon: "Stat_Armor_01",
|
||
bonuses: [
|
||
{ attr: Attrs.defense, mode: TalentValueMode.Percent, per_lv: 30 },
|
||
{ attr: Attrs.hp_max, mode: TalentValueMode.Percent, per_lv: 5 },
|
||
],
|
||
max_lv: 5, role: HRole.Tank,
|
||
},
|
||
9102: {
|
||
uuid: 9102, tier: TalentTier.Specialized, name: "战士专精", info: "战士生命 +{value}%", icon: "Sword-FA_WP_Main_Sword_003_PurpleSilver",
|
||
bonuses: [{ attr: Attrs.hp_max, mode: TalentValueMode.Percent, per_lv: 12 }],
|
||
max_lv: 5, role: HRole.Warrior,
|
||
},
|
||
9103: {
|
||
uuid: 9103, tier: TalentTier.Specialized, name: "刺客专精", info: "刺客攻击 +{value}%、暴击率 +{value2}%", icon: "Sword-FA_WP_Main_Sword_019_WoodSilver",
|
||
bonuses: [
|
||
{ attr: Attrs.ap, mode: TalentValueMode.Percent, per_lv: 8 },
|
||
{ attr: Attrs.critical, mode: TalentValueMode.Flat, per_lv: 2 },
|
||
],
|
||
max_lv: 5, role: HRole.Assassin,
|
||
},
|
||
9104: {
|
||
uuid: 9104, tier: TalentTier.Specialized, name: "射手专精", info: "射手攻击 +{value}%、穿透率 +{value2}%", icon: "Stat_RangedAttack",
|
||
bonuses: [
|
||
{ attr: Attrs.ap, mode: TalentValueMode.Percent, per_lv: 8 },
|
||
{ attr: Attrs.puncture_chance, mode: TalentValueMode.Flat, per_lv: 2 },
|
||
],
|
||
max_lv: 5, role: HRole.Archer,
|
||
},
|
||
9105: {
|
||
uuid: 9105, tier: TalentTier.Specialized, name: "法师专精", info: "法师攻击 +{value}%、冰冻率 +{value2}%", icon: "Stat_Mana",
|
||
bonuses: [
|
||
{ attr: Attrs.ap, mode: TalentValueMode.Percent, per_lv: 8 },
|
||
{ attr: Attrs.freeze_chance, mode: TalentValueMode.Flat, per_lv: 2 },
|
||
],
|
||
max_lv: 5, role: HRole.Mage,
|
||
},
|
||
9106: {
|
||
uuid: 9106, tier: TalentTier.Specialized, name: "辅助专精", info: "辅助治疗量 +{value}%、施加的增益效果 +{value2}%", icon: "Stat_PotionBoost",
|
||
bonuses: [
|
||
{ attr: Attrs.heal_power, mode: TalentValueMode.Flat, per_lv: 10 },
|
||
{ attr: Attrs.buff_power, mode: TalentValueMode.Flat, per_lv: 8 },
|
||
],
|
||
max_lv: 5, role: HRole.Support,
|
||
},
|
||
|
||
// ==================== 三阶·超强天赋(9201-9219,二阶投入 10 点解锁;幅度约为前两阶 2 倍) ====================
|
||
// ---- 全局超强(9201-9209) ----
|
||
9201: {
|
||
uuid: 9201, tier: TalentTier.Super, name: "神威降临", info: "所有英雄攻击 +{value}%、生命 +{value2}%", icon: "Stat_HolyDamage",
|
||
bonuses: [
|
||
{ attr: Attrs.ap, mode: TalentValueMode.Percent, per_lv: 8 },
|
||
{ attr: Attrs.hp_max, mode: TalentValueMode.Percent, per_lv: 8 },
|
||
],
|
||
max_lv: 5,
|
||
},
|
||
9202: {
|
||
uuid: 9202, tier: TalentTier.Super, name: "致命终结", info: "所有英雄暴击率 +{value}%、暴击伤害 +{value2}%", icon: "Stat_Critical_01",
|
||
bonuses: [
|
||
{ attr: Attrs.critical, mode: TalentValueMode.Flat, per_lv: 3 },
|
||
{ attr: Attrs.critical_damage, mode: TalentValueMode.Flat, per_lv: 15 },
|
||
],
|
||
max_lv: 5,
|
||
},
|
||
9203: {
|
||
uuid: 9203, tier: TalentTier.Super, name: "破甲重创", info: "所有英雄穿透率 +{value}%、穿透伤害 +{value2}%", icon: "Stat_Tripleshot",
|
||
bonuses: [
|
||
{ attr: Attrs.puncture_chance, mode: TalentValueMode.Flat, per_lv: 3 },
|
||
{ attr: Attrs.puncture_dmg_bonus, mode: TalentValueMode.Flat, per_lv: 10 },
|
||
],
|
||
max_lv: 5,
|
||
},
|
||
9204: {
|
||
uuid: 9204, tier: TalentTier.Super, name: "钢铁之躯", info: "所有英雄防御 +{value}%、生命 +{value2}%", icon: "Stat_Defense",
|
||
bonuses: [
|
||
{ attr: Attrs.defense, mode: TalentValueMode.Percent, per_lv: 20 },
|
||
{ attr: Attrs.hp_max, mode: TalentValueMode.Percent, per_lv: 6 },
|
||
],
|
||
max_lv: 5,
|
||
},
|
||
// ---- 职业超强(9211-9219,按 HRole 过滤) ----
|
||
9211: {
|
||
uuid: 9211, tier: TalentTier.Super, name: "不朽壁垒", info: "坦克防御 +{value}%、生命 +{value2}%", icon: "Stat_Armor_01",
|
||
bonuses: [
|
||
{ attr: Attrs.defense, mode: TalentValueMode.Percent, per_lv: 40 },
|
||
{ attr: Attrs.hp_max, mode: TalentValueMode.Percent, per_lv: 8 },
|
||
],
|
||
max_lv: 5, role: HRole.Tank,
|
||
},
|
||
9212: {
|
||
uuid: 9212, tier: TalentTier.Super, name: "狂血战魂", info: "战士攻击 +{value}%、生命 +{value2}%", icon: "Stat_Attack_03",
|
||
bonuses: [
|
||
{ attr: Attrs.ap, mode: TalentValueMode.Percent, per_lv: 10 },
|
||
{ attr: Attrs.hp_max, mode: TalentValueMode.Percent, per_lv: 8 },
|
||
],
|
||
max_lv: 5, role: HRole.Warrior,
|
||
},
|
||
9213: {
|
||
uuid: 9213, tier: TalentTier.Super, name: "影刃绝杀", info: "刺客攻击 +{value}%、暴击伤害 +{value2}%", icon: "Sword-FA_WP_Main_Sword_019_WoodSilver",
|
||
bonuses: [
|
||
{ attr: Attrs.ap, mode: TalentValueMode.Percent, per_lv: 12 },
|
||
{ attr: Attrs.critical_damage, mode: TalentValueMode.Flat, per_lv: 12 },
|
||
],
|
||
max_lv: 5, role: HRole.Assassin,
|
||
},
|
||
9214: {
|
||
uuid: 9214, tier: TalentTier.Super, name: "穿云贯日", info: "射手攻击 +{value}%、穿透伤害 +{value2}%", icon: "Stat_RangedAttack",
|
||
bonuses: [
|
||
{ attr: Attrs.ap, mode: TalentValueMode.Percent, per_lv: 12 },
|
||
{ attr: Attrs.puncture_dmg_bonus, mode: TalentValueMode.Flat, per_lv: 8 },
|
||
],
|
||
max_lv: 5, role: HRole.Archer,
|
||
},
|
||
9215: {
|
||
uuid: 9215, tier: TalentTier.Super, name: "元素主宰", info: "法师攻击 +{value}%、冰冻率 +{value2}%", icon: "Sub_Item-FA_WP_Sub_MagicBall_001_Blue",
|
||
bonuses: [
|
||
{ attr: Attrs.ap, mode: TalentValueMode.Percent, per_lv: 12 },
|
||
{ attr: Attrs.freeze_chance, mode: TalentValueMode.Flat, per_lv: 3 },
|
||
],
|
||
max_lv: 5, role: HRole.Mage,
|
||
},
|
||
9216: {
|
||
uuid: 9216, tier: TalentTier.Super, name: "圣光普照", info: "辅助治疗量 +{value}%、施加的增益效果 +{value2}%", icon: "Stat_HolyDamage",
|
||
bonuses: [
|
||
{ attr: Attrs.heal_power, mode: TalentValueMode.Flat, per_lv: 15 },
|
||
{ attr: Attrs.buff_power, mode: TalentValueMode.Flat, per_lv: 12 },
|
||
],
|
||
max_lv: 5, role: HRole.Support,
|
||
},
|
||
};
|
||
|
||
/** 天赋升级消耗:索引为当前等级(0 表示升到 1 级),返回所需天赋点数 */
|
||
export const TALENT_UPGRADE_COST: number[] = [1, 1, 2, 2, 3];
|
||
|
||
/**
|
||
* 查询升级所需天赋点数
|
||
* @param curLv 当前等级
|
||
* @returns 升到下一级所需点数;已满级返回 -1
|
||
*/
|
||
export function getTalentUpgradeCost(curLv: number): number {
|
||
if (curLv < 0 || curLv >= TALENT_UPGRADE_COST.length) return -1;
|
||
return TALENT_UPGRADE_COST[curLv];
|
||
}
|
||
|
||
/** 阶位解锁门槛:前一阶累计投入 ≥ 该点数才能升级下一阶天赋 */
|
||
export const TALENT_TIER_UNLOCK_THRESHOLD = 10;
|
||
|
||
/**
|
||
* 计算指定阶位已投入的天赋点数(按升级消耗表逐级累加)。
|
||
* Why: 阶位解锁按"实际消耗点数"而非"等级总和"口径——与玩家直觉(投入了多少点)
|
||
* 及重置退款口径(resetTalents 同表对账)保持一致。
|
||
* @param levels 天赋等级表(key 为天赋 uuid,value 为当前等级)
|
||
* @param tier 目标阶位
|
||
* @returns 该阶位全部天赋已投入的点数总和
|
||
*/
|
||
export function getTalentTierInvestedPoints(levels: Record<number, number>, tier: TalentTier): number {
|
||
if (!levels) return 0;
|
||
let invested = 0;
|
||
for (const key in levels) {
|
||
const cfg = TalentSet[key];
|
||
if (!cfg || cfg.tier !== tier) continue;
|
||
for (let i = 0; i < levels[key]; i++) {
|
||
const c = getTalentUpgradeCost(i);
|
||
if (c > 0) invested += c;
|
||
}
|
||
}
|
||
return invested;
|
||
}
|
||
|
||
/**
|
||
* 判断指定阶位是否已解锁(加点入口校验用;战斗结算无需关心阶位——已投入的等级恒生效)。
|
||
* 规则:一阶恒解锁;二阶要求一阶累计投入 ≥ TALENT_TIER_UNLOCK_THRESHOLD;三阶要求二阶累计投入达标。
|
||
* @param levels 天赋等级表
|
||
* @param tier 目标阶位
|
||
*/
|
||
export function isTalentTierUnlocked(levels: Record<number, number>, tier: TalentTier): boolean {
|
||
if (tier === TalentTier.Basic) return true;
|
||
const prevTier = (tier - 1) as TalentTier;
|
||
return getTalentTierInvestedPoints(levels, prevTier) >= TALENT_TIER_UNLOCK_THRESHOLD;
|
||
}
|
||
|
||
/** 天赋属性的卡面显示名(迷你卡空间有限,用短标签) */
|
||
const TALENT_ATTR_LABELS: Partial<Record<Attrs, string>> = {
|
||
[Attrs.ap]: "攻击",
|
||
[Attrs.hp_max]: "生命",
|
||
[Attrs.defense]: "防御",
|
||
[Attrs.critical]: "暴击",
|
||
[Attrs.critical_damage]: "暴伤",
|
||
[Attrs.stun_chance]: "击晕",
|
||
[Attrs.freeze_chance]: "冰冻",
|
||
[Attrs.knockback_distance]: "击退",
|
||
[Attrs.puncture_chance]: "穿透",
|
||
[Attrs.puncture_dmg_bonus]: "穿透伤",
|
||
[Attrs.heal_power]: "治疗",
|
||
[Attrs.buff_power]: "增益",
|
||
};
|
||
|
||
/** 天赋属性的单位后缀:概率/治疗/增益类为百分点(%),防御为"点",击退距离为纯数值 */
|
||
const TALENT_ATTR_SUFFIX: Partial<Record<Attrs, string>> = {
|
||
[Attrs.defense]: "点",
|
||
[Attrs.knockback_distance]: "",
|
||
};
|
||
|
||
/**
|
||
* 生成天赋迷你卡的卡面文案(自包含:不显示满级效果)。
|
||
* 规则:已加点(lv>0)显示当前已生效数值,如「攻击 +9%」;
|
||
* 未加点(lv=0)显示每级数值引导,如「攻击 +3%/级」。
|
||
* Why: 迷你点选卡没有二级详情入口,文案必须一眼看懂当前收益。
|
||
* @param cfg 天赋配置
|
||
* @param lv 当前等级
|
||
*/
|
||
export function getTalentDisplayText(cfg: TalentConfig, lv: number): string {
|
||
const mult = lv > 0 ? lv : 1;
|
||
const parts: string[] = [];
|
||
for (const b of cfg.bonuses) {
|
||
const label = TALENT_ATTR_LABELS[b.attr] ?? String(b.attr);
|
||
const suffix = TALENT_ATTR_SUFFIX[b.attr] ?? "%";
|
||
parts.push(`${label} +${b.per_lv * mult}${suffix}`);
|
||
}
|
||
const text = parts.join("、");
|
||
return lv > 0 ? text : `${text}/级`;
|
||
}
|
||
|
||
/**
|
||
* 聚合指定职业英雄生效的全部天赋加成。
|
||
* Why: 基础/超强全局天赋全局生效,专精与超强职业天赋按 role 过滤;
|
||
* 阶位解锁只约束加点阶段,战斗加载时(Hero.load / applyHeroLevel)按当前等级直接取加成。
|
||
* @param levels 天赋等级表(key 为天赋 uuid,value 为当前等级)
|
||
* @param role 英雄职业(职业过滤依据;无 role 时只应用全局天赋)
|
||
* @returns 已解析的加成列表(等级已乘算进 value)
|
||
*/
|
||
export function getTalentBonusesForRole(levels: Record<number, number>, role?: HRole): TalentResolvedBonus[] {
|
||
const result: TalentResolvedBonus[] = [];
|
||
if (!levels) return result;
|
||
for (const key in levels) {
|
||
const lv = levels[key];
|
||
if (lv <= 0) continue;
|
||
const cfg = TalentSet[key];
|
||
if (!cfg) continue;
|
||
// 职业天赋:职业不匹配则跳过
|
||
if (cfg.role !== undefined && cfg.role !== role) continue;
|
||
for (const b of cfg.bonuses) {
|
||
result.push({ attr: b.attr, mode: b.mode, value: b.per_lv * lv });
|
||
}
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* 将天赋加成写入英雄属性模型(在 Hero.load / MissionCardComp.applyHeroLevel 的属性组装段调用)。
|
||
*
|
||
* 结算规则:
|
||
* - Percent 模式:以基础快照为基数(ap→base_ap,hp_max→base_hp,defense→def_base),按百分比放大后累加;
|
||
* - Flat 模式:直接按属性名动态累加(概率/抗性类为百分点,defense 为固定点数)。
|
||
*
|
||
* Why: percent 必须用基础快照而非当前 ap/hp_max 作基数——当前值已含驻场光环与成长增量,
|
||
* 若以当前值为基数会与光环乘区叠加成乘法,导致数值膨胀失控。
|
||
*
|
||
* @param model 英雄属性模型(满足 ITalentTarget 结构)
|
||
* @param levels 天赋等级表(smc.getTalentLevels())
|
||
* @param role 英雄职业(职业过滤;无 role 的怪物由调用方跳过)
|
||
*/
|
||
export function applyTalentBonuses(model: ITalentTarget, levels: Record<number, number>, role?: HRole): void {
|
||
const bonuses = getTalentBonusesForRole(levels, role);
|
||
if (bonuses.length === 0) return;
|
||
// percent 模式的 defense 基数:取调用方传入的当前 defense(Hero.load/applyHeroLevel 已在调用前重置为 hero.def)
|
||
const defBase = model.defense;
|
||
for (const b of bonuses) {
|
||
if (b.mode === TalentValueMode.Percent) {
|
||
switch (b.attr) {
|
||
case Attrs.ap:
|
||
model.ap += Math.floor(model.base_ap * b.value / 100);
|
||
break;
|
||
case Attrs.hp_max:
|
||
model.hp_max += Math.floor(model.base_hp * b.value / 100);
|
||
model.hp += Math.floor(model.base_hp * b.value / 100);
|
||
break;
|
||
case Attrs.defense:
|
||
model.defense += Math.floor(defBase * b.value / 100);
|
||
break;
|
||
default:
|
||
model[b.attr] = (typeof model[b.attr] === "number" ? model[b.attr] : 0) + b.value;
|
||
break;
|
||
}
|
||
} else {
|
||
// flat:概率/抗性类百分点累加,defense 固定点数累加
|
||
model[b.attr] = (typeof model[b.attr] === "number" ? model[b.attr] : 0) + b.value;
|
||
}
|
||
}
|
||
}
|