import { v3 } from "cc" import { BoxSet, FacSet, FightSet } from "./GameSet" import { SkillOverrides, TGroup, SkillSet, FieldSkillSet, SkillConfig, SkillKind, FieldSkillConfig, FieldSkillType, mergeSkillParams } from "./SkillSet" import { BuffList, BuffConfig, ModOp } from "./BuffSet" import { Attrs } from "./HeroAttrs" export enum HType { Melee = 0, Mid = 1, Long = 2, } export const HTypeName = { 0: "近战", 1: "中程", 2: "远程", } export enum MonType { Melee = 0, Heavy = 1, Long = 2, Support = 3, Summoner = 5, Assassin = 6, MeleeBoss = 8, LongBoss = 9, } export const MonTypeName: Record = { [MonType.Melee]: "近战", [MonType.Heavy]: "重型", [MonType.Long]: "远程", [MonType.Support]: "辅助", [MonType.Summoner]: "召唤师", [MonType.Assassin]: "刺客", [MonType.MeleeBoss]: "近战Boss", [MonType.LongBoss]: "远程Boss", } /** * 英雄攻击速度分级配置 (数值为攻击间隔cd,越小越快) * 5 档速度:最快 VeryFast 0.75s → 最慢 VerySlow 1.50s */ export enum AtkSpeedLv { VeryFast = 1, Fast = 2, Normal = 3, Slow = 4, VerySlow = 5, } export const AtkSpeedSet = { [AtkSpeedLv.VeryFast]: { name: "极速", cd: 0.75 }, [AtkSpeedLv.Fast]: { name: "快速", cd: 0.90 }, [AtkSpeedLv.Normal]: { name: "中速", cd: 1.05 }, [AtkSpeedLv.Slow]: { name: "慢速", cd: 1.20 }, [AtkSpeedLv.VerySlow]: { name: "极慢", cd: 1.50 }, }; export const HeroPos = { 0: { pos: v3(-320, BoxSet.GAME_LINE, 0) }, 1: { pos: v3(0, BoxSet.GAME_LINE, 0) }, 2: { pos: v3(0, BoxSet.GAME_LINE, 0) }, } export const FormationPointX = { [HType.Melee]: -20, [HType.Mid]: 100, [HType.Long]: 100, } as const; /** 各攻击定位的默认攻击距离(像素):近战100 / 中程300 / 远程450;英雄配置了 dis 时优先取配置值 */ export const HeroDisVal: Record = { [HType.Melee]: 100, [HType.Mid]: 300, [HType.Long]: 450, } export const resolveFormationTargetX = (fac: FacSet, type: HType): number => { const resolvedRangeType = type as HType.Melee | HType.Mid | HType.Long; const side = fac === FacSet.MON ? 1 : -1; return FormationPointX[resolvedRangeType] * side; } export enum MonStart { SLINE_1 = 140, //上线y SLINE_2 = 100, //下线y SLINE_3 = 180, //下线y SLINE_4 = 60, //y起始点 START_X = 320, //x起始点 START_I = 90, //x轴间隔 } /** * 英雄成长类型(决定每级 hp/ap 标准增量系数)。 * Why: 不同定位英雄的成长曲线差异化,避免"一刀切"导致坦克/刺客同强度。 */ export enum HGrowType { Tank = 0, // 坦克:高 hp 低 ap Warrior = 1, // 战士:均衡 Assassin = 2, // 刺客:低 hp 高 ap Mage = 3, // 法师:中 hp 高 ap Support = 4, // 辅助:中 hp 低 ap Archer = 5, // 射手:中低 hp 高 ap(持续物理输出) } /** 成长类型系数表(每级增量 = 英雄基础属性 × 对应系数) */ export const HERO_GROW_COEF: Record = { [HGrowType.Tank]: { hp: 1.5, ap: 0.6, def: 1.5 }, [HGrowType.Warrior]: { hp: 1.0, ap: 1.0, def: 1.0 }, [HGrowType.Assassin]: { hp: 0.7, ap: 1.4, def: 0.5 }, [HGrowType.Mage]: { hp: 0.9, ap: 1.3, def: 0.5 }, [HGrowType.Support]: { hp: 1.1, ap: 0.7, def: 1.0 }, [HGrowType.Archer]: { hp: 0.8, ap: 1.3, def: 0.5 }, }; /** * 英雄品质系数步长:相邻品质(rarity)基础属性相差 5%。 * 系数 = 1 + HERO_QUALITY_STEP × (rarity - 1),lv1~lv5 → 1.00/1.05/1.10/1.15/1.20。 * 仅作用于 lv1 初始基础属性(AP/HP/DEF),成长与等级 bonus 不随品质缩放。 */ export const HERO_QUALITY_STEP = 0.05; /** 计算英雄品质系数(相邻品质基础属性差 5%) */ export function getHeroQualityCoef(rarity: number): number { return 1 + HERO_QUALITY_STEP * (Math.max(1, rarity) - 1); } /** * lv12 职业属性专项:英雄等级达到 12 级时,按职业对单项基础属性 +50%。 * 基数为 lv11 当前等级有效值(基础 + 成长 + lv9 bonus,不含 lv12 自身)。 * Why: 坦克堆防、战士/辅助堆血、输出位堆攻,强化职业特色。 */ export const HERO_LV12_SPECIAL_LV = 12; /** lv12 专项提升的档位等级(基数取 LV12 - 1 = 11 级有效值) */ export const HERO_LV12_BASE_LV = HERO_LV12_SPECIAL_LV - 1; /** * 英雄位置类型(职业定位)。 * Why: grow_type 仅驱动数值成长曲线,无法表达"这个英雄在阵容里干什么"; * role 面向 UI 展示与阵容推荐(如 HeroComboSet 的铁三角校验),与成长解耦。 */ export enum HRole { Tank = 0, // 坦克:前排承伤,受击发动机 Warrior = 1, // 战士:前排输出/献祭位 Assassin = 2, // 刺客:近战爆发主C Archer = 3, // 射手:远程物理主C Mage = 4, // 法师:远程先手增益 Support = 5, // 辅助:光环/治疗 } export const HRoleName: Record = { [HRole.Tank]: "坦克", [HRole.Warrior]: "战士", [HRole.Assassin]: "刺客", [HRole.Archer]: "射手", [HRole.Mage]: "法师", [HRole.Support]: "辅助", }; /** lv12 各职业专项属性映射(坦克堆防、战士/辅助堆血、输出位堆攻) */ export const HERO_LV12_SPECIAL_ATTR: Record = { [HRole.Tank]: "def", [HRole.Warrior]: "hp", [HRole.Assassin]: "ap", [HRole.Archer]: "ap", [HRole.Mage]: "ap", [HRole.Support]: "hp", }; /** * 职业基础属性模板(仅英雄使用,怪物无 role 直接手写 hp/ap/def)。 * 英雄配置处的 hp/ap/def = 本模板值 + 该卡手动增量,模板保证同职业基准一致、增量表达个体差异。 * Why: 局外升级机制将在加载时(Hero.ts / Mon.ts)统一重算属性,配置表只承担"基准+增量"的静态表达。 */ export const HERO_ROLE_BASE: Record = { [HRole.Tank]: { hp: 600, ap: 20, def: 50 }, // 坦克:高防高血,前排承伤 [HRole.Warrior]: { hp: 560, ap: 22, def: 30 }, // 战士:均衡 [HRole.Assassin]: { hp: 560, ap: 22, def: 10 }, // 刺客:低防,近战爆发 [HRole.Archer]: { hp: 280, ap: 32, def: 10 }, // 射手:低防,远程物理主C [HRole.Mage]: { hp: 280, ap: 32, def: 10 }, // 法师:低防,远程增益 [HRole.Support]: { hp: 280, ap: 32, def: 15 }, // 辅助:低防,光环/治疗 }; /** * 计算英雄在目标等级下的累计属性成长增量(线性:每级加一份"基础属性×系数")。 * 公式:累计 = 基础属性 × 类型系数 × (lv - 1)。 * Why: 以英雄自身基础值为基数,自动适配低/高费卡的成长占比,避免全局固定值失衡; * 线性曲线在无限升级下不会指数爆炸,强度平滑可控。 * @param hero 英雄配置(取 hp/ap/def 基础值与 grow_type) * @param targetLv 目标等级(≥1) * @returns 累计 hp/ap/def 增量(已取整) */ export function calcGrowBonus(hero: Pick, targetLv: number): { hp: number; ap: number; def: number } { const coef = HERO_GROW_COEF[hero.grow_type ?? HGrowType.Warrior]; const steps = Math.max(0, Math.floor(targetLv) - 1); return { hp: Math.floor(hero.hp * coef.hp * steps), ap: Math.floor(hero.ap * coef.ap * steps), def: Math.floor(hero.def * coef.def * steps), }; } /** * 特殊触发技能类型 */ export enum SkillTriggerType { Call = "call", // 召唤后触发 降临 Dead = "dead", // 死亡后触发 遗志 FStart = "fstart", // 战斗开始 先手 Field = "field", // 驻场 光环 Atking = "atking", // 攻击后触发 追击 Atked = "atked", // 受击后触发 反击 Revive = "revive", // 复活触发 涅槃 } export const SkillTriggerName = { [SkillTriggerType.Call]: "召唤", [SkillTriggerType.Dead]: "死亡后", [SkillTriggerType.FStart]: "回合开始", [SkillTriggerType.Field]: "光环", [SkillTriggerType.Atking]: "攻击", [SkillTriggerType.Atked]: "受伤", [SkillTriggerType.Revive]: "复活", } export const SkillTriggerDesc = { [SkillTriggerType.Call]: "召唤时", [SkillTriggerType.Dead]: "死亡时", [SkillTriggerType.FStart]: "战斗开始时", [SkillTriggerType.Field]: "光环", [SkillTriggerType.Atking]: "攻击n次", [SkillTriggerType.Atked]: "受伤n次", [SkillTriggerType.Revive]: "复活时", } /** * 技能等级枚举(与英雄等级同标尺 1~5)。 * 配置触发技能档位时填入,表达"英雄升到 lv 级 → 该技能提升到 s_lv 级"的成长节奏, * 与 LvTriggerEntry.lv 并列展示,便于 UI 面板显示"技能Lv.x"。 */ export enum SkillLv { Lv1 = 1, Lv2 = 2, Lv3 = 3, Lv4 = 4, Lv5 = 5, } /** * 触发技能对外命名规则: * 英雄除普攻外的技能(call/atked/atking/dead/fstart)命名统一收敛进各英雄 HeroInfo 配置 * (HSkillInfo.name 给普攻/主技能命名;LvTriggerEntry.name 给触发技能组命名,写在该组第 1 档)。 * UI 层将每个触发槽位(atking/dead/fstart/atked/call/field)整组视为一个技能: * 组内多个 s_uuid / 光环词条合并为一个名称与一套说明统一展示,组名取组内首个自定义名。 * 天赋由 TalentSet 自行命名;SkillSet.name 仅作内部底座代号,不直接对外展示。 */ /** * 查询触发技能组的对外展示名(英雄语境,来自 HeroInfo 配置)。 * @param grouped 触发技能分组配置(某英雄某触发类型的 TriggerGrouped) * @param s_uuid 技能ID * @returns 该组第 1 档 name;未配置时回退 SkillSet 内部名 */ export function getGroupedTriggerName(grouped: TriggerGrouped | undefined, s_uuid: number): string { const entries = grouped?.[s_uuid]; if (entries?.length && entries[0].name) return entries[0].name; return SkillSet[s_uuid]?.name ?? ""; } /** * 查询驻场光环词条的对外展示名(英雄语境,FieldEntry.name 优先,缺省回退 FieldSkillSet 底座名)。 * Why: 名称收敛进 heroSet 英雄配置,同一光环词条(如 7002 攻击光环)在不同英雄下可有特色名。 * @param hero 英雄配置(含 field 词条的 heroInfo) * @param uuid 光环 uuid(指向 FieldSkillSet 底座) */ export function getFieldSkillName(hero: heroInfo | undefined, uuid: number): string { for (const e of hero?.field ?? []) { const entry = e.uuids.find(u => u.uuid === uuid); if (entry?.name) return entry.name; } return FieldSkillSet[uuid]?.name ?? ""; } /** * 查询触发技能组(整个触发槽位)的对外统一展示名(英雄语境)。 * Why: 每个触发槽位整组视为一个技能,组内多个 s_uuid 合并展示,需要统一组名。 * @param hero 英雄配置 * @param type 触发槽位(call/dead/fstart/atking/atked) * @returns 组内首个配置了 name 的条目名(按 s_uuid 与档位配置顺序扫描); * 均未配置时回退组内首个 s_uuid 的 SkillSet 底座名;组不存在返回 "" */ export function getTriggerGroupName(hero: heroInfo | undefined, type: SkillTriggerType): string { const grouped = hero?.[type] as TriggerGrouped | undefined; if (!grouped) return ""; let firstUuid = 0; for (const key in grouped) { if (!firstUuid) firstUuid = Number(key); const name = grouped[key]?.[0]?.name; if (name) return name; } return firstUuid ? (SkillSet[firstUuid]?.name ?? "") : ""; } /** * 查询驻场光环组(hero.field 整体)的对外统一展示名(英雄语境)。 * Why: field 槽位同样整组视为一个技能,组内多个词条合并展示,组名取首个自定义名。 * @param hero 英雄配置(含 field 词条档位) * @returns 全部档位词条中首个配置 name 的(按档位 lv 与词条顺序扫描); * 均未配置时回退首个词条的 FieldSkillSet 底座名;无光环返回 "" */ export function getFieldGroupName(hero: heroInfo | undefined): string { let firstUuid = 0; for (const tier of hero?.field ?? []) { for (const entry of tier.uuids) { if (!firstUuid) firstUuid = entry.uuid; if (entry.name) return entry.name; } } return firstUuid ? (FieldSkillSet[firstUuid]?.name ?? "") : ""; } /** * 解析技能的对外展示图标(英雄语境):英雄/触发引用侧通过 overrides.icon 覆写时优先, * 缺省回退 SkillSet 底座 icon;驻场光环词条统一取 FieldSkillSet 底座 icon。 * Why: 图标是"对外展示"维度(与数值覆写同一套注入机制),实现同一底座不同英雄/档位不同外观。 * @param hero 英雄配置 * @param skillUuid 技能 uuid(skills key / 触发组 s_uuid / FieldSkillSet uuid) * @param slot 技能所属槽位(可空):指定时仅在该槽位查找;缺省按 普攻/大招→触发组 顺序定位 * @param isGroup 整组模式:true 时取组内首个 s_uuid 的图标(slot 必填,光环取首个词条) * @returns 图标ID;未找到返回 undefined */ export function getHeroSkillIcon(hero: heroInfo | undefined, skillUuid: number, slot?: SkillTriggerType, isGroup: boolean = false): string | undefined { if (!hero) return undefined; // 整组模式:组内首个 s_uuid/词条的图标 if (isGroup && slot !== undefined) { if (slot === SkillTriggerType.Field) { const firstEntry = hero.field?.[0]?.uuids?.[0]; return firstEntry ? FieldSkillSet[firstEntry.uuid]?.icon : undefined; } const grouped = hero[slot] as TriggerGrouped | undefined; if (!grouped) return undefined; for (const key in grouped) { const icon = resolveTriggerSkillIcon(grouped[Number(key)]?.[0], Number(key)); if (icon) return icon; } return undefined; } // 普攻/大招(slot 缺省时优先定位):lv_entries 首档 icon > 基础 overrides.icon > 底座 const hSkill = hero.skills?.[skillUuid]; if (hSkill && slot === undefined) { return hSkill.lv_entries?.[0]?.overrides?.icon ?? hSkill.overrides?.icon ?? SkillSet[skillUuid]?.icon; } // 指定触发槽位:该组首个 s_uuid 首档 icon if (slot !== undefined && slot !== SkillTriggerType.Field) { const grouped = hero[slot] as TriggerGrouped | undefined; const entry = grouped?.[skillUuid]?.[0]; if (entry) return resolveTriggerSkillIcon(entry, skillUuid); return undefined; } // 自动定位:再各触发组,最后光环 for (const type of [SkillTriggerType.Call, SkillTriggerType.Dead, SkillTriggerType.FStart, SkillTriggerType.Atking, SkillTriggerType.Atked]) { const grouped = hero[type] as TriggerGrouped | undefined; const entry = grouped?.[skillUuid]?.[0]; if (entry) return resolveTriggerSkillIcon(entry, skillUuid); } if (hero.field?.some(t => t.uuids.some(u => u.uuid === skillUuid))) { return FieldSkillSet[skillUuid]?.icon; } return undefined; } /** 触发技能档位图标:档位 overrides.icon 优先,缺省回退该 s_uuid 的底座 icon */ function resolveTriggerSkillIcon(entry: LvTriggerEntry | undefined, skillUuid: number): string | undefined { if (!entry) return undefined; return entry.overrides?.icon ?? SkillSet[skillUuid]?.icon; } /** * 复活已纳入 dead 触发组:通过 SkillOverrides.revive_hp / revive_count 配置, * 不再需要独立的 revive 字段和解析函数。 */ /** * 英雄/怪物基础信息接口 */ export interface heroInfo { uuid: number; // 唯一标识(英雄5000段,怪物5200段) name: string; // 显示名称 icon?: string; // 图标名称(对应美术资源名) path: string; // 资源路径(对应美术资源名) fac: FacSet; // 阵营(FacSet.HERO 或 FacSet.MON) kind?: number; // 未使用 lv: number; // 英雄等级 rarity?: number; // 卡牌等级(驱动 bg_node 颜色:1=green 2=blue 3=purple 4=red 5=yellow) type: HType; // 攻击定位(近战/中程/远程) grow_type?: HGrowType; // 成长类型(决定每级 hp/ap 标准增量,默认 Warrior) role?: HRole; // 位置类型/职业定位(英雄专用,怪物用 monType 表达) monType?: MonType; // 怪物专属类型 hp: number; // 生命值上限(英雄 = HERO_ROLE_BASE[role].hp + 手动增量) ap: number; // 攻击力(英雄 = HERO_ROLE_BASE[role].ap + 手动增量) def: number; // 防御(英雄 = HERO_ROLE_BASE[role].def + 手动增量;怪物手写,减伤走除法递减模型) [SkillTriggerType.Call]?: TriggerGrouped; // 召唤后触发的技能配置(按 s_uuid 分组,每组按 lv 升序) [SkillTriggerType.Dead]?: TriggerGrouped; // 死亡后触发的技能配置 [SkillTriggerType.FStart]?: TriggerGrouped; // 战斗开始时释放的技能配置 [SkillTriggerType.Field]?: LvFieldEntry[]; // 驻场光环(按 lv 升序,运行时取 ≤英雄等级 的最大档) [SkillTriggerType.Atking]?: TriggerGrouped; // 普通攻击后触发的技能配置,s_uuid: 技能id, t_num: 触发所需的普攻次数 [SkillTriggerType.Atked]?: TriggerGrouped; // 受击后触发的技能配置,s_uuid: 技能id, t_num: 触发所需的受击次数 dis?: number; // 攻击距离(像素) speed?: number; // 移动速度(像素/秒) skills: Record; // 携带技能ID列表 ap_bonus?: LvBonusEntry[]; // 额外攻击加成(按 lv 升序,运行时累加 ≤英雄等级 的所有档) hp_bonus?: LvBonusEntry[]; // 额外生命加成(按 lv 升序,运行时累加 ≤英雄等级 的所有档) def_bonus?: LvBonusEntry[]; // 额外防御加成(按 lv 升序,运行时累加 ≤英雄等级 的所有档) info: string; // 描述文案 /** * @deprecated 已废弃:无任何 UI/运行时读取。技能提升说明由 HeroSkillText 依据 * 结构化配置动态生成(含数值漂移与新功能),请勿再填充此字段。 */ infos?: string[]; } /** * 英雄卡配置(CHeroComp 专用,从 CardConfig 精简) * 仅保留英雄卡渲染和交互必需的字段 */ export interface HeroCardConfig { uuid: number; name?: string; info?: string; cost: number; rarity: number; base_rarity?: number; } /** * 英雄卡池条目(含费用和权重,用于 MissionCardComp 抽卡) */ export interface HeroCardPoolEntry { uuid: number; cost: number; weight: number; rarity: number; } /** 英雄卡池:由 HeroList 动态生成(见文件末尾初始化代码) */ export const HeroCardPoolList: HeroCardPoolEntry[] = []; /** * 技能基础信息接口 */ export interface HSkillInfo { uuid: number; // 唯一标识(技能6000段等) name?: string; // 对外展示的技能名(普攻/主技能);缺省时回退 SkillSet 内部名 lv: number; // 技能等级 cd: number; // 技能cd ccd: number; // 占位当前cd,用于cd计时 overrides?: SkillOverrides; // 角色专属参数覆盖(全等级生效,作为底) /** 技能描述模板(基础档):占位符 {target}/{dur}/{技能字段名},由 HeroSkillText 渲染合并后实时数值 */ desc?: string; lv_entries?: LvSkillEntry[]; // 按英雄等级分档(按 lv 升序,运行时取 ≤英雄等级 的最大档) } /** * 普攻技能分档配置:达到 lv 级英雄时此档 overrides 生效(与基础 overrides 浅合并,档位优先)。 * s_lv 标注此档对应的技能等级(SkillLv 枚举),便于面板显示"技能Lv.x"。 */ export interface LvSkillEntry { lv: number; // 达到该英雄等级时此档生效 s_lv?: SkillLv; // 此档对应的技能等级(标注用) overrides: SkillOverrides; // 此档注入的效果 /** 此档描述模板:缺省继承上一档模板;新增机制的档位(如附加中毒)需单独配置。 * 显式配置后弹窗提升档(slv2+)直接展示该模板渲染结果,优先于自动 diff * (护盾/治疗等 ap 含义非伤害的技能必须配置,避免 diff 标签语义错位) */ desc?: string; } /** * 触发技能单档配置:达到 lv 级时此档参数生效(t_num/overrides 可随等级变化)。 * s_lv 标注此档对应的技能等级(SkillLv 枚举),表达"英雄 lv 级 → 技能 s_lv 级"的成长节奏。 */ export interface LvTriggerEntry { lv: number; // 达到该英雄等级时解锁此档 s_lv?: SkillLv; // 此档对应的技能等级(标注用,便于面板显示"技能Lv.x") name?: string; // 该 s_uuid 触发技能组的对外展示名(写在第 1 档,作为组名) t_num: number; overrides?: SkillOverrides; /** 此档描述模板:缺省回退该组第 1 档 desc;由 HeroSkillText 渲染合并后实时数值。 * 显式配置后弹窗提升档(slv2+)直接展示该模板渲染结果,优先于自动 diff */ desc?: string; } /** * 触发技能按 s_uuid 分组的配置:每个 s_uuid 下按 lv 升序排列。 * 运行时取每个 s_uuid 中 ≤英雄等级 的最大 lv 档。 */ export type TriggerGrouped = Record; /** * 驻场光环词条:uuid 指向 FieldSkillSet 底座(类型/图标/元数据), * value 为该词条实际生效数值(由配置处按档位指定,不再随 uuid 分档)。 * name 为该词条在英雄语境下的对外展示名(写在首次出现的档位),缺省回退 FieldSkillSet 底座名。 */ export interface FieldEntry { uuid: number; value: number; name?: string; // 英雄语境对外展示名(写在该词条首次出现的档位) } /** * 驻场光环按等级解锁:运行时取 ≤英雄等级 的最大 lv 档的词条列表。 */ export interface LvFieldEntry { lv: number; uuids: FieldEntry[]; /** 档位描述(可选,缺省由 HeroSkillText 按 FieldDescSet 自动生成) */ desc?: string; } /** * 额外属性加成按等级叠加:运行时累加所有 ≤英雄等级 的档位。 */ export interface LvBonusEntry { lv: number; value: number; } /* *=============英雄配置列表================ * 几何王国复刻版 — 依据 英雄设计指引.md(A/B 级复刻英雄)配置 * * 规则:lv1 激活 skills[0]/skills[1],lv6 解锁 atking/atked/fstart/dead/field 触发技能(触发类统一 lv6 激活,无品质门槛), * 大招(skills[1])lv9/lv16 走 lv_entries 分档成长,lv12 按职业对单项基础属性 +50%(基数取 lv11 有效值), * revive[0] 与 skills[1] 互斥二选一(配置 revive 时按 lv1/lv9/lv16 走 lv_entries 3 级成长), * 品质(rarity)仅影响 lv1 初始基础属性(相邻差 5%,仅 lv1 初始 AP/HP/DEF),不影响 uuid 段位/光环/技能解锁/属性补偿 * 编号:本批复刻英雄集中于 5001~5009,rarity 按配置(不遵循段位规则) */ // @hero-setup:region-begin export const HeroInfo: Record = { // @hero-setup:heroes-begin // 5001 叠甲骑士 — CSV导入:自身护盾+全体护盾 5001: { uuid: 5001, name: "叠甲骑士", path: "hk1", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Melee, grow_type: HGrowType.Tank, role: HRole.Tank, hp: HERO_ROLE_BASE[HRole.Tank].hp + 20, ap: HERO_ROLE_BASE[HRole.Tank].ap, def: HERO_ROLE_BASE[HRole.Tank].def + 10, skills: { 6004: { uuid: 6004, name: "强化普攻", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow].cd, ccd: 0, overrides: {"ap":100,"proc_skill":{"s_uuid":6001,"chance":100,"overrides":{"crt":100}}}, desc: "挥剑对{target}造成攻击力{ap}%伤害", lv_entries: [ { lv: 2, s_lv: SkillLv.Lv2, overrides: {"ap":120} }, ], }, 6301: { uuid: 6301, name: "魔法盾", lv: 1, cd: 8, ccd: 0, overrides: {"ap":30}, desc: "{target}获得生命最大值{ap}%的护盾", lv_entries: [ { lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":60}, desc: "{target}获得生命最大值{ap}%的护盾" }, { lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":120}, desc: "{target}获得生命最大值{ap}%的护盾" }, ], }, }, atked: { 6301: [ { lv: 4, s_lv: SkillLv.Lv1, name: "全体圣盾", t_num: 3, overrides: {"TGroup":null,"ap":10,"icon":"Stat_UnitSummonIncrease_01"}, desc: "全队获得本英雄生命最大值{ap}%的护盾" }, ], }, info: "", }, // 5002 易伤剑仙 — CSV导入:击退压场+易伤放大;复刻酒仙 5002: { uuid: 5002, name: "易伤剑仙", path: "hk3", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Melee, grow_type: HGrowType.Warrior, role: HRole.Warrior, hp: HERO_ROLE_BASE[HRole.Warrior].hp + 5, ap: HERO_ROLE_BASE[HRole.Warrior].ap + 20, def: HERO_ROLE_BASE[HRole.Warrior].def + 5, skills: { 6004: { uuid: 6004, name: "强化普攻", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow].cd, ccd: 0, overrides: {"ap":100}, desc: "对{target}造成攻击力{ap}%伤害", lv_entries: [ { lv: 2, s_lv: SkillLv.Lv2, overrides: {"ap":120} }, ], }, 6101: { uuid: 6101, name: "气斩", lv: 1, cd: 8, ccd: 0, overrides: {"ap":150,"timed_buff_id":7002,"icon":"Stat_AttackSpeed_02"}, desc: "斩出气刃,对{target}造成攻击力{ap}%伤害,并使目标易伤(受到伤害加深,持续{dur}秒)", lv_entries: [ { lv: 8, s_lv: SkillLv.Lv2, overrides: {"buff_value":20} }, { lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":180,"bck":60,"buff_value":40}, desc: "斩出气刃,对{target}造成攻击力{ap}%伤害,击退{bck},并使目标易伤(持续{dur}秒)" }, ], }, }, atking: { 6004: [ { lv: 4, s_lv: SkillLv.Lv1, name: "风暴打击", t_num: 3, overrides: {"ap":300,"icon":"Stat_AllUnitAttack"}, desc: "立刻打击{target},造成攻击力{ap}%伤害" }, ], }, info: "", }, // 5003 眩晕暴击哥 — CSV导入:高爆发+击晕收割;复刻齐天大圣 5003: { uuid: 5003, name: "眩晕暴击哥", path: "hk5", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Melee, grow_type: HGrowType.Warrior, role: HRole.Warrior, hp: HERO_ROLE_BASE[HRole.Warrior].hp + 5, ap: HERO_ROLE_BASE[HRole.Warrior].ap + 20, def: HERO_ROLE_BASE[HRole.Warrior].def + 5, skills: { 6004: { uuid: 6004, name: "强化普攻", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow].cd, ccd: 0, overrides: {"ap":100}, desc: "挥斧对{target}造成攻击力{ap}%伤害", lv_entries: [ { lv: 2, s_lv: SkillLv.Lv2, overrides: {"stun":10}, desc: "挥斧对{target}造成攻击力{ap}%伤害,{stun}%概率击晕" }, ], }, 6104: { uuid: 6104, name: "开山斧", lv: 1, cd: 8, ccd: 0, overrides: {"ap":300,"stun":100}, desc: "劈出开山斧,对{target}造成攻击力{ap}%伤害,必定击晕", lv_entries: [ { lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":450,"stun":100} }, { lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":450,"stun":100} }, ], }, }, field: [ { lv: 4, uuids: [{ uuid: 7005, value: 0.25, name: "大圣神威" }] }, ], info: "", }, // 5004 刀刀暴击 — CSV导入:暴击/暴伤双光环乘区;复刻剑圣 5004: { uuid: 5004, name: "刀刀暴击", path: "hc1", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Mid, grow_type: HGrowType.Assassin, role: HRole.Assassin, hp: HERO_ROLE_BASE[HRole.Assassin].hp, ap: HERO_ROLE_BASE[HRole.Assassin].ap + 30, def: HERO_ROLE_BASE[HRole.Assassin].def, skills: { 6002: { uuid: 6002, name: "强化普攻", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Fast].cd, ccd: 0, overrides: {"ap":100}, desc: "挥刀对{target}造成攻击力{ap}%伤害", lv_entries: [ { lv: 2, s_lv: SkillLv.Lv2, overrides: {"crt":10}, desc: "挥刀对{target}造成攻击力{ap}%伤害,{crt}%概率暴击" }, ], }, 6100: { uuid: 6100, name: "光闪", lv: 1, cd: 8, ccd: 0, overrides: {"ap":150}, desc: "斩出光闪,对{target}造成攻击力{ap}%伤害", lv_entries: [ { lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":250} }, { lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":350} }, ], }, }, field: [ { lv: 4, uuids: [{ uuid: 7004, value: 0.12, name: "剑刃风暴" }, { uuid: 7005, value: 0.2, name: "斩魂利刃" }] }, ], info: "", }, // 5005 出血贼 — CSV导入:入场先手+受击格挡;复刻剑豪 5005: { uuid: 5005, name: "出血贼", path: "hc2", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Mid, grow_type: HGrowType.Assassin, role: HRole.Assassin, hp: HERO_ROLE_BASE[HRole.Assassin].hp, ap: HERO_ROLE_BASE[HRole.Assassin].ap + 30, def: HERO_ROLE_BASE[HRole.Assassin].def, skills: { 6002: { uuid: 6002, name: "强化普攻", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Fast].cd, ccd: 0, overrides: {"ap":100}, desc: "挥刀对{target}造成攻击力{ap}%伤害", lv_entries: [ { lv: 2, s_lv: SkillLv.Lv2, overrides: {"timed_buff_id":7007,"buff_value":30,"buff_chance":30}, desc: "挥刀对{target}造成攻击力{ap}%伤害,{buff_chance}%概率使目标出血(每0.5秒受到{buff_value}点伤害,持续{dur}秒)" }, ], }, 6103: { uuid: 6103, name: "闪电斩", lv: 1, cd: 8, ccd: 0, overrides: {"ap":150}, desc: "召唤落雷斩击{target},造成攻击力{ap}%伤害", lv_entries: [ { lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":250,"timed_buff_id":7007}, desc: "召唤落雷斩击{target},造成攻击力{ap}%伤害,并使目标出血(每0.5秒受到{buff_value}点伤害,持续{dur}秒)" }, { lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":350,"para":50,"timed_buff_id":7007,"buff_value":60}, desc: "召唤落雷斩击{target},造成攻击力{ap}%伤害,{para}%概率麻痹,并使目标出血(每0.5秒受到{buff_value}点伤害,持续{dur}秒)" }, ], }, }, field: [ { lv: 4, uuids: [{ uuid: 7018, value: 1, name: "连击光环" }] }, ], info: "", }, // 5006 冻箭哥 — CSV导入:多重单体箭,带冰冻 5006: { uuid: 5006, name: "冻箭哥", path: "ha1", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Long, grow_type: HGrowType.Archer, role: HRole.Archer, hp: HERO_ROLE_BASE[HRole.Archer].hp, ap: HERO_ROLE_BASE[HRole.Archer].ap + 30, def: HERO_ROLE_BASE[HRole.Archer].def, skills: { 6006: { uuid: 6006, name: "强化普攻", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Normal].cd, ccd: 0, overrides: {"ap":100}, desc: "射出箭矢,对{target}造成攻击力{ap}%伤害", lv_entries: [ { lv: 2, s_lv: SkillLv.Lv2, overrides: {"bck":10}, desc: "射出箭矢,对{target}造成攻击力{ap}%伤害,击退{bck}" }, ], }, 6150: { uuid: 6150, name: "万箭齐发·冰", lv: 1, cd: 8, ccd: 0, overrides: {"ap":150,"frz":30,"icon":"Stat_AttackRangeIncrease_02"}, desc: "万箭齐发,对{target}造成攻击力{ap}%伤害,{frz}%概率冰冻", lv_entries: [ { lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":200,"frz":50} }, { lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":250,"frz":70} }, ], }, }, field: [ { lv: 4, uuids: [{ uuid: 7006, value: 0.15 }] }, ], info: "", }, // 5007 击退火女 — CSV导入:群体击退/麻痹压场;复刻深渊女王 5007: { uuid: 5007, name: "击退火女", path: "hm1", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Long, grow_type: HGrowType.Mage, role: HRole.Mage, hp: HERO_ROLE_BASE[HRole.Mage].hp - 5, ap: HERO_ROLE_BASE[HRole.Mage].ap + 10, def: HERO_ROLE_BASE[HRole.Mage].def, skills: { 6010: { uuid: 6010, name: "强化普攻", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow].cd, ccd: 0, overrides: {"ap":100,"bck":30}, desc: "掷出紫魔球,对{target}造成攻击力{ap}%伤害,击退{bck}", lv_entries: [ { lv: 2, s_lv: SkillLv.Lv2, overrides: {"bck":40} }, ], }, 6200: { uuid: 6200, name: "火焰喷射", lv: 1, cd: 8, ccd: 0, overrides: {"ap":250,"bck":100,"summon_count":1}, desc: "喷出烈焰风暴,对{target}造成攻击力{ap}%伤害,击退{bck}", lv_entries: [ { lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":350,"bck":100,"summon_count":1} }, { lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":450,"bck":100,"summon_count":2} }, ], }, }, field: [ { lv: 4, uuids: [{ uuid: 7002, value: 0.15, name: "深渊威压" }] }, ], info: "", }, // 5008 团疗奶爸 — CSV导入:全体治疗续航+自身护盾 5008: { uuid: 5008, name: "团疗奶爸", path: "hh1", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Long, grow_type: HGrowType.Support, role: HRole.Support, hp: HERO_ROLE_BASE[HRole.Support].hp + 10, ap: HERO_ROLE_BASE[HRole.Support].ap + 20, def: HERO_ROLE_BASE[HRole.Support].def, skills: { 6011: { uuid: 6011, name: "强化普攻", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Normal].cd, ccd: 0, overrides: {"ap":100}, desc: "挥杖对{target}造成攻击力{ap}%伤害", lv_entries: [ { lv: 2, s_lv: SkillLv.Lv2, overrides: {"bck":10}, desc: "挥杖对{target}造成攻击力{ap}%伤害,击退{bck}" }, ], }, 6302: { uuid: 6302, name: "治疗", lv: 1, cd: 8, ccd: 0, overrides: {"ap":30}, desc: "为{target}回复攻击力{ap}%生命", lv_entries: [ { lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":40} }, { lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":50} }, ], }, }, atking: { 6301: [ { lv: 4, s_lv: SkillLv.Lv1, name: "圣愈之盾", t_num: 3, overrides: {"ap":30,"summon_count":1}, desc: "{target}获得生命最大值{ap}%的护盾" }, ], }, info: "", }, // 5009 回血坦克 5009: { uuid: 5009, name: "回血坦克", path: "hk2", fac: FacSet.HERO, rarity: 2, lv: 1, type: HType.Melee, grow_type: HGrowType.Tank, role: HRole.Tank, hp: HERO_ROLE_BASE[HRole.Tank].hp, ap: HERO_ROLE_BASE[HRole.Tank].ap, def: HERO_ROLE_BASE[HRole.Tank].def, skills: { 6004: { uuid: 6004, name: "普攻强化", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow].cd, ccd: 0, lv_entries: [ { lv: 2, s_lv: SkillLv.Lv2, overrides: {"proc_skill":{"s_uuid":6502,"chance":10,"overrides":{"ap":10}}} }, ], }, 6102: { uuid: 6102, lv: 1, cd: 8, ccd: 0, overrides: {"ap":250,"bck":30}, lv_entries: [ { lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":300,"bck":50} }, { lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":350,"bck":70} }, ], }, }, atked: { 6302: [ { lv: 4, s_lv: SkillLv.Lv1, t_num: 3, overrides: {"ap":10} }, ], }, info: "", }, // @hero-setup:heroes-end /* *=============怪物配置列表================ * 怪物与英雄采用同一套设定体系:基础值 = HERO_ROLE_BASE[role],品质(rarity) * 相邻基础属性差 5%,成长系数走 HERO_GROW_COEF[grow_type]。 * 怪物普攻统一使用 SkillSet 基础单体攻击(6001~6012 段), * 并通过 overrides.ap=100 显式声明伤害为攻击力的 100%。 * 怪物按等级成长由后续肉鸽配置驱动,当前配置承担"职业基准 + 品质差异"的静态表达。 */ // 基础怪物 (全部固定点位站桩攻击,HType仅决定是前排还是后排) // 前排怪物 — 战士系基准(Warrior 模板),变体按品质微分定位 6001: { uuid: 6001, name: "兽人战士", path: "m1", fac: FacSet.MON, lv: 1, rarity: 1, type: HType.Melee, grow_type: HGrowType.Warrior, role: HRole.Warrior, monType: MonType.Melee, hp: HERO_ROLE_BASE[HRole.Warrior].hp, ap: HERO_ROLE_BASE[HRole.Warrior].ap, def: HERO_ROLE_BASE[HRole.Warrior].def, speed: 70, skills: { 6004: { uuid: 6004, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow].cd, ccd: 0, overrides: { ap: 100 } } }, info: "基础前排怪, 战士系基准" }, 6002: { uuid: 6002, name: "兽人精锐战士", path: "m2", fac: FacSet.MON, lv: 1, rarity: 2, type: HType.Melee, grow_type: HGrowType.Warrior, role: HRole.Warrior, monType: MonType.Melee, hp: HERO_ROLE_BASE[HRole.Warrior].hp, ap: HERO_ROLE_BASE[HRole.Warrior].ap, def: HERO_ROLE_BASE[HRole.Warrior].def, speed: 110, skills: { 6004: { uuid: 6004, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow].cd, ccd: 0 } }, info: "进阶前排怪, 品质2更快更痛" }, 6003: { uuid: 6003, name: "兽人重装兵", path: "m3", fac: FacSet.MON, lv: 1, rarity: 2, type: HType.Melee, grow_type: HGrowType.Tank, role: HRole.Tank, monType: MonType.Heavy, hp: HERO_ROLE_BASE[HRole.Tank].hp, ap: HERO_ROLE_BASE[HRole.Tank].ap, def: HERO_ROLE_BASE[HRole.Tank].def, speed: 50, skills: { 6004: { uuid: 6004, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.VerySlow].cd, ccd: 0, overrides: { ap: 100 } } }, info: "重型坦克怪, 高HP低攻承伤位" }, // 后排怪物 — 射手/刺客/法系基准,变体按品质微分定位 6004: { uuid: 6004, name: "兽人射手", path: "m4", fac: FacSet.MON, lv: 1, rarity: 1, type: HType.Long, grow_type: HGrowType.Archer, role: HRole.Archer, monType: MonType.Long, hp: HERO_ROLE_BASE[HRole.Archer].hp, ap: HERO_ROLE_BASE[HRole.Archer].ap, def: HERO_ROLE_BASE[HRole.Archer].def, speed: 70, skills: { 6006: { uuid: 6006, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow].cd, ccd: 0, overrides: { ap: 100 } } }, info: "后排输出怪, 射手系基准" }, 6005: { uuid: 6005, name: "兽人刺客", path: "m5", fac: FacSet.MON, lv: 1, rarity: 1, type: HType.Long, grow_type: HGrowType.Assassin, role: HRole.Assassin, monType: MonType.Assassin, hp: HERO_ROLE_BASE[HRole.Assassin].hp, ap: HERO_ROLE_BASE[HRole.Assassin].ap, def: HERO_ROLE_BASE[HRole.Assassin].def, speed: 130, skills: { 6002: { uuid: 6002, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Normal].cd, ccd: 0, overrides: { ap: 100, hit_count: 2 } } }, info: "高攻速低HP刺客" }, // 特殊位怪物 6006: { uuid: 6006, name: "骷髅领主", path: "m6", fac: FacSet.MON, lv: 1, rarity: 3, type: HType.Melee, grow_type: HGrowType.Tank, role: HRole.Tank, monType: MonType.MeleeBoss, hp: HERO_ROLE_BASE[HRole.Tank].hp, ap: HERO_ROLE_BASE[HRole.Tank].ap, def: HERO_ROLE_BASE[HRole.Tank].def, speed: 60, skills: { 6004: { uuid: 6004, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.VerySlow].cd, ccd: 0, overrides: { ap: 100 } } }, info: "前排MiniBoss级坦克" }, 6007: { uuid: 6007, name: "兽人术士", path: "m7", fac: FacSet.MON, lv: 1, rarity: 1, type: HType.Long, grow_type: HGrowType.Support, role: HRole.Support, monType: MonType.Support, hp: HERO_ROLE_BASE[HRole.Support].hp, ap: HERO_ROLE_BASE[HRole.Support].ap, def: HERO_ROLE_BASE[HRole.Support].def, speed: 70, skills: { 6009: { uuid: 6009, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow].cd, ccd: 0, overrides: { ap: 100, hit_count: 2 } } }, info: "后排辅助法师怪" }, 6008: { uuid: 6008, name: "兽人火法", path: "m8", fac: FacSet.MON, lv: 1, rarity: 1, type: HType.Long, grow_type: HGrowType.Mage, role: HRole.Mage, monType: MonType.Summoner, hp: HERO_ROLE_BASE[HRole.Mage].hp, ap: HERO_ROLE_BASE[HRole.Mage].ap, def: HERO_ROLE_BASE[HRole.Mage].def, speed: 70, skills: { 6010: { uuid: 6010, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow].cd, ccd: 0, overrides: { ap: 100, hit_count: 2 } } }, info: "后排召唤系法师怪" }, // BOSS怪物 — 与英雄同一套设定(role 模板 + 品质系数),高品质承伤/输出位 6101: { uuid: 6101, name: "兽人首领-双刀战士", path: "mb1", fac: FacSet.MON, lv: 6, rarity: 4, type: HType.Melee, grow_type: HGrowType.Warrior, role: HRole.Warrior, monType: MonType.MeleeBoss, hp: HERO_ROLE_BASE[HRole.Warrior].hp, ap: HERO_ROLE_BASE[HRole.Warrior].ap, def: HERO_ROLE_BASE[HRole.Warrior].def, speed: 120, skills: { 6004: { uuid: 6004, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow].cd, ccd: 0, overrides: { ap: 100 } } }, info: "前排Boss, 攻速型" }, 6102: { uuid: 6102, name: "兽人首领-斧头战士", path: "mb2", fac: FacSet.MON, lv: 6, rarity: 5, type: HType.Melee, grow_type: HGrowType.Tank, role: HRole.Tank, monType: MonType.MeleeBoss, hp: HERO_ROLE_BASE[HRole.Tank].hp, ap: HERO_ROLE_BASE[HRole.Tank].ap, def: HERO_ROLE_BASE[HRole.Tank].def, speed: 60, skills: { 6004: { uuid: 6004, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.VerySlow].cd, ccd: 0, overrides: { ap: 100 } } }, info: "前排Boss, 超高HP" }, 6103: { uuid: 6103, name: "兽人首领-魔法师", path: "mb3", fac: FacSet.MON, lv: 6, rarity: 4, type: HType.Long, grow_type: HGrowType.Mage, role: HRole.Mage, monType: MonType.LongBoss, hp: HERO_ROLE_BASE[HRole.Mage].hp, ap: HERO_ROLE_BASE[HRole.Mage].ap, def: HERO_ROLE_BASE[HRole.Mage].def, speed: 110, skills: { 6009: { uuid: 6009, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow].cd, ccd: 0, overrides: { ap: 100, hit_count: 2 } } }, info: "后排法系Boss" }, 6104: { uuid: 6104, name: "兽人首领-射手", path: "mb4", fac: FacSet.MON, lv: 6, rarity: 4, type: HType.Long, grow_type: HGrowType.Archer, role: HRole.Archer, monType: MonType.LongBoss, hp: HERO_ROLE_BASE[HRole.Archer].hp, ap: HERO_ROLE_BASE[HRole.Archer].ap, def: HERO_ROLE_BASE[HRole.Archer].def, speed: 70, skills: { 6004: { uuid: 6004, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow].cd, ccd: 0, overrides: { ap: 100 } } }, info: "后排位Boss, 均衡型" }, 6105: { uuid: 6105, name: "亡灵首领-法师", path: "mb5", fac: FacSet.MON, lv: 6, rarity: 5, type: HType.Long, grow_type: HGrowType.Mage, role: HRole.Mage, monType: MonType.LongBoss, hp: HERO_ROLE_BASE[HRole.Mage].hp, ap: HERO_ROLE_BASE[HRole.Mage].ap, def: HERO_ROLE_BASE[HRole.Mage].def, speed: 110, skills: { 6011: { uuid: 6011, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow].cd, ccd: 0, overrides: { ap: 100, hit_count: 2, timed_buff_id: 7002 } } }, info: "后排高AP Boss" }, 6106: { uuid: 6106, name: "亡灵首领-骑马战士", path: "mb6", fac: FacSet.MON, lv: 6, rarity: 5, type: HType.Melee, grow_type: HGrowType.Tank, role: HRole.Tank, monType: MonType.MeleeBoss, hp: HERO_ROLE_BASE[HRole.Tank].hp, ap: HERO_ROLE_BASE[HRole.Tank].ap, def: HERO_ROLE_BASE[HRole.Tank].def, speed: 130, skills: { 6004: { uuid: 6004, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.VerySlow].cd, ccd: 0, overrides: { ap: 100 } } }, info: "前排终极Boss, 最高HP+高速" }, }; export const HeroList: number[] = [ // 几何王国复刻英雄(5001~5009) 5001, 5002, 5003, 5004, 5005, 5006, 5007, 5008, 5009, ]; // @hero-setup:region-end // ==================== 英雄推荐阵容配置 ==================== /** * 推荐阵容条目。 * Why: 场上固定 3 个英雄(FightSet.HERO_FIELD_NUM),围绕"发动机 → 增益 → 主C"铁三角结构 * 预置官方配合组合,供抽卡引导、阵容推荐 UI 与 AI 自动布阵消费。 */ export interface HeroComboInfo { uuid: number; // 阵容唯一标识(8000 段) name: string; // 阵容名称(体现流派) heroes: number[]; // 英雄 uuid 列表,固定 3 个;索引 0=前排,其余按站位从近到远 desc: string; // 配合思路说明(信息面板展示) low_heroes?: number[]; // 低配替代阵容(rarity 1~2,供新手期引导) } /** * 推荐阵容表(几何王国复刻版 5001~5009)。 * 设计原则: * 1. 铁三角结构:1 前排(坦克)+ 1 增益(光环/先手)+ 1 主C * 2. 乘区分散:攻击/暴击/暴伤各占独立乘区,组合优先覆盖不同乘区避免稀释 * 3. 发动机冗余:前排挨打/死亡触发增益,叠甲骑士(5005)死亡缠绕负责献祭点火 */ export const HeroComboSet: Record = { // 8001 暴击爆发流 — 暴击率与暴伤双乘区互不稀释,成型最强 8001: { uuid: 8001, name: "暴击爆发流", heroes: [5005, 5008, 5002], desc: "叠甲骑士前排抗伤叠甲,刀刀暴击的暴击光环与眩晕暴击哥的暴伤光环组成双乘区,双近战暴击爆发收割。", }, // 8002 冰雷控制流 — 冰冻+击晕双控场,敌人出不了手 8002: { uuid: 8002, name: "冰雷控制流", heroes: [5007, 5004, 5001], desc: "微醺战神前排击退压场,冻住不谢冰冻链配合紫电魔女能量波击退击晕,击晕光环叠加,全场控制。", }, // 8003 铁桶续航流 — 双防御前排+双治疗保血,最稳 8003: { uuid: 8003, name: "铁桶续航流", heroes: [5005, 5009, 5006], desc: "叠甲骑士与铁壳斧弟双前排叠甲叠防,光明奶爸治疗+生命光环抬全队血线,专打持久消耗战。", }, // 8004 先手爆发流 — 入场剑气先手+能量波跟进,短回合最强 8004: { uuid: 8004, name: "先手爆发流", heroes: [5003, 5001, 5008], desc: "格挡反杀入场500%剑气先手压血线,紫电魔女能量波击退跟进,眩晕暴击哥开山斧收割残局。", }, // 8005 破甲推进流 — 易伤放大全队伤害,克制高血Boss 8005: { uuid: 8005, name: "破甲推进流", heroes: [5007, 5006, 5002], desc: "微醺战神气斩易伤放大全队伤害,光明奶爸治疗保前排,刀刀暴击吃满易伤与自身暴击完成推进。", }, // 8006 光环覆盖流 — 攻击/暴击/暴伤/生命光环全覆盖 8006: { uuid: 8006, name: "光环覆盖流", heroes: [5002, 5006, 5001], desc: "刀刀暴击暴击+暴伤双光环、紫电魔女攻击光环、光明奶爸生命光环,四光环全覆盖持续放大全队输出。", }, }; /** 推荐阵容 id 列表(按品质/成型难度排序,供 UI 顺序展示) */ export const HeroComboList: number[] = [8001, 8002, 8003, 8004, 8005, 8006]; // ==================== 英雄卡池初始化(必须在 HeroList 定义之后执行) ==================== /** * 英雄卡费用规则 * lv1=5, lv2=10, lv3+=15 */ function getHeroCost(rarity: number): number { if (rarity === 1) return 5; if (rarity === 2) return 10; return 15; } /** * 英雄卡按 rarity 分配抽取权重(几何递减,高等级越稀有) * 梯度:lv1=40, lv2=25, lv3=15, lv4=8, lv5=3 */ const HERO_WEIGHT_BY_LV: Record = { 1: 40, 2: 25, 3: 15, 4: 8, 5: 3, }; function getHeroWeight(rarity: number): number { return HERO_WEIGHT_BY_LV[rarity] ?? HERO_WEIGHT_BY_LV[1]; } // 动态生成英雄卡池:所有英雄统一生成 lv1 卡牌 HeroList.forEach(uuid => { const hero = HeroInfo[uuid]; if (!hero) return; HeroCardPoolList.push({ uuid: hero.uuid, cost: getHeroCost(hero.rarity ?? 1), weight: getHeroWeight(hero.rarity ?? 1), rarity: hero.rarity ?? 1, }); }); // ==================== 英雄强度评分公式 ==================== /** 英雄强度公式调参权重(可在编辑器或运行时热调) * 说明: * - W_HP: 每 1 点生命值折算 1 分(生命值不随时间变化) * - W_DPS_PER_SEC: 每 1 点 DPS 持续 1 秒折算 0.5 分 * (默认 60 秒评估窗下,1 DPS ≈ 30 分,与旧版 W_DPS=30 等效) * - WAVE_DURATION / HITS_PER_WAVE: 回合参数,用于估算 atked/fstart/dead 触发次数 * - DEFAULT_EVAL_SECONDS: calcHeroPower 默认使用的评估时间窗 */ export const HERO_POWER_WEIGHTS = { W_HP: 1.0, W_DPS_PER_SEC: 0.5, W_atking: 1.0, W_atked: 0.8, W_fstart: 1.0, W_dead: 0.6, W_field_alive: 1.0, W_revive: 1.0, W_heal: 0.8, W_shield: 1.0, W_control: 0.5, expectedEnemyDmg: 20, WAVE_DURATION: 30, HITS_PER_WAVE: 10, DEFAULT_EVAL_SECONDS: 60, }; /** * 解析触发技能在目标等级下的有效条目列表。 * 每个 s_uuid 取 ≤lv 的最大档;返回扁平数组供评分/触发器消费。 */ export function resolveTriggerByLv(grouped: TriggerGrouped | undefined, lv: number): { s_uuid: number; t_num: number; overrides?: SkillOverrides }[] { if (!grouped) return []; const result: { s_uuid: number; t_num: number; overrides?: SkillOverrides }[] = []; for (const key in grouped) { const entries = grouped[key]; if (!entries || entries.length === 0) continue; let pick: LvTriggerEntry | undefined; for (const e of entries) { if (e.lv <= lv && (!pick || e.lv > pick.lv)) pick = e; } if (pick) result.push({ s_uuid: Number(key), t_num: pick.t_num, overrides: pick.overrides }); } return result; } /** * 解析普攻技能在目标英雄等级下的有效 overrides。 * 取 lv_entries 中 ≤hero_lv 的最大档,与基础 overrides 浅合并(档位字段优先)。 * Why: 普攻技能与触发技能对齐"英雄等级驱动成长"语义,且下游读取 skills[uuid].overrides 无需感知分档。 */ export function resolveSkillOverrides(skill: HSkillInfo, hero_lv: number): SkillOverrides | undefined { if (!skill.lv_entries || skill.lv_entries.length === 0) return skill.overrides; let pick: LvSkillEntry | undefined; for (const e of skill.lv_entries) { if (e.lv <= hero_lv && (!pick || e.lv > pick.lv)) pick = e; } if (!pick) return skill.overrides; return { ...skill.overrides, ...pick.overrides }; } /** 解析驻场光环在目标等级下的有效词条列表(取 ≤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) { if (e.lv <= lv && (!pick || e.lv > pick.lv)) pick = e; } return pick ? pick.uuids : []; } /** 计算目标等级下额外属性加成(hp/ap/def_bonus 一次性奖励 + 成长类型每级递增) */ function getEvolveBonuses(hero: heroInfo, targetLv: number): { hp: number, ap: number, def: number } { const lv = Math.max(1, targetLv); // 成长类型线性增量(仅英雄生效,怪物无 grow_type 时走 Warrior 基准但不影响平衡,因怪物通常不填) const grow = hero.fac === FacSet.HERO ? calcGrowBonus(hero, lv) : { hp: 0, ap: 0, def: 0 }; 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; } } return { hp, ap, def }; } /** 计算目标等级下的有效 HP/AP/DEF(固定基础值 + 成长递增与一次性加成) */ export function getEffectiveStats(hero: heroInfo, targetLv: number): { hp: number, ap: number, def: number } { const bonuses = getEvolveBonuses(hero, targetLv); return { hp: hero.hp + bonuses.hp, ap: hero.ap + bonuses.ap, def: hero.def + bonuses.def, }; } /** * 计算英雄展示用最终属性(含品质系数与 lv12 职业专项),供 UI 面板与运行时对齐口径。 * 公式:基础值 × 品质系数 + 成长 + bonus,再叠加 lv12 专项(基数取 lv11 有效值)。 * @param hero 英雄配置 * @param targetLv 目标等级(≥1) * @returns 含品质与专项的最终 hp/ap/def(已取整) */ export function getHeroDisplayStats(hero: heroInfo, targetLv: number): { hp: number, ap: number, def: number } { const lv = Math.max(1, Math.floor(targetLv)); const coef = getHeroQualityCoef(hero.rarity ?? 1); const eff = getEffectiveStats(hero, lv); const stats = { hp: Math.round(hero.hp * coef) + (eff.hp - hero.hp), ap: Math.round(hero.ap * coef) + (eff.ap - hero.ap), def: Math.round(hero.def * coef) + (eff.def - hero.def), }; // lv12 职业专项:基数为 lv11 展示有效值 if (lv >= HERO_LV12_SPECIAL_LV && hero.role !== undefined) { const base11 = getHeroDisplayStatsBase(hero, HERO_LV12_BASE_LV); const attr = HERO_LV12_SPECIAL_ATTR[hero.role]; stats[attr] += Math.round(base11[attr] * 0.5); } return stats; } /** 内部:lv12 专项基数(不含 lv12 自身)的展示有效值 */ function getHeroDisplayStatsBase(hero: heroInfo, targetLv: number): { hp: number, ap: number, def: number } { const coef = getHeroQualityCoef(hero.rarity ?? 1); const eff = getEffectiveStats(hero, targetLv); return { hp: Math.round(hero.hp * coef) + (eff.hp - hero.hp), ap: Math.round(hero.ap * coef) + (eff.ap - hero.ap), def: Math.round(hero.def * coef) + (eff.def - hero.def), }; } /** 获取英雄普通攻击间隔(取 skills[0] 的 cd) */ function getAttackCd(hero: heroInfo): number { const skillIds = Object.keys(hero.skills); if (skillIds.length === 0) return 1.0; const firstKey = Number(skillIds[0]); const skill = hero.skills[firstKey]; return skill?.cd || 1.0; } /** 计算目标群体范围系数 */ function calcScopeMul(group: TGroup): number { return (group === TGroup.Ally || group === TGroup.Team) ? FightSet.HERO_FIELD_NUM : 1; } /** 计算目标时间窗内的普攻次数 */ function getAttackCount(hero: heroInfo, seconds: number): number { return seconds / getAttackCd(hero); } /** 计算目标时间窗内的受击次数 */ function getHitCount(seconds: number): number { const weights = HERO_POWER_WEIGHTS; return (seconds / weights.WAVE_DURATION) * weights.HITS_PER_WAVE; } /** 计算目标时间窗内的回合数 */ function getWaveCount(seconds: number): number { return seconds / HERO_POWER_WEIGHTS.WAVE_DURATION; } /** * 从 dead 触发配置中解析最大复活次数(revive_count)。 * 遍历所有 dead 技能的 overrides,取 revive_count 最大值。 * @param dead 死亡触发配置 * @param lv 英雄等级 * @returns 最大复活次数,无复活配置时返回 0 */ export function resolveMaxReviveCount(dead: TriggerGrouped | undefined, lv: number): number { const triggers = resolveTriggerByLv(dead, lv); let maxRevive = 0; for (const t of triggers) { const count = t.overrides?.revive_count ?? 0; if (count > maxRevive) maxRevive = count; } return maxRevive; } /** 计算触发技在目标时间窗内的触发次数 */ function getTriggerCount( type: SkillTriggerType, t_num: number, hero: heroInfo, seconds: number ): number { switch (type) { case SkillTriggerType.Atking: return getAttackCount(hero, seconds) / t_num; case SkillTriggerType.Atked: return getHitCount(seconds) / t_num; case SkillTriggerType.FStart: return getWaveCount(seconds); case SkillTriggerType.Dead: // 死亡触发次数 = 回合数 × (1 + 最大复活次数),复活从 dead 配置中提取 const maxRevive = resolveMaxReviveCount(hero.dead, FightSet.HERO_MAX_LV); return getWaveCount(seconds) * (1 + maxRevive); } return 1; } /** 将计时 buff 折算为“在整个时间窗内持续生效”的等效价值 */ function calcBuffPermanentEquivalent(buff: BuffConfig, apEff: number, cd: number, seconds: number, buffValueOverride?: number): number { const weights = HERO_POWER_WEIGHTS; let value = 0; if (buff.modifiers) { for (const mod of buff.modifiers) { const dps = apEff / cd; const modValue = buffValueOverride ?? mod.value; switch (mod.attr) { case Attrs.ap: if (mod.op === ModOp.Flat) { value += (modValue / cd) * weights.W_DPS_PER_SEC * seconds; } else if (mod.op === ModOp.PercentAdd) { value += (modValue / 100) * dps * weights.W_DPS_PER_SEC * seconds; } break; case Attrs.hp: case Attrs.hp_max: value += modValue * weights.W_HP; break; case Attrs.critical: value += (modValue / 100) * dps * 0.5 * weights.W_DPS_PER_SEC * seconds; break; case Attrs.critical_damage: value += (modValue / 100) * dps * 0.05 * weights.W_DPS_PER_SEC * seconds; break; case Attrs.speed: value += (modValue / 100) * dps * weights.W_DPS_PER_SEC * seconds; break; } } } if (buff.tick) { const ticks = Math.max(1, buff.duration / buff.tick.interval); const totalHeal = ticks * (buff.tick.damage_or_heal + (buff.tick.scale_by_ap_pct / 100) * apEff); value += Math.max(0, totalHeal) * weights.W_heal; } return value; } /** 计算 Support 类技能单次触发的效果价值 */ function calcSupportEffectValue(config: SkillConfig, hpEff: number, apEff: number, cd: number, seconds: number): number { const weights = HERO_POWER_WEIGHTS; const value = config.ap || 0; // 计时 buff:先算整个时间窗的永久等效,再按覆盖率折算 if (config.timed_buff_id) { const buff = BuffList[config.timed_buff_id]; if (buff) { const permanentEquivalent = calcBuffPermanentEquivalent(buff, apEff, cd, seconds, config.buff_value); const duration = config.buff_duration ?? buff.duration; const uptime = seconds > 0 ? Math.min(duration / seconds, 1) : 0; return permanentEquivalent * uptime; } } switch (config.buff_type) { case Attrs.ap: // 永久 buff 已改为百分比口径:value 是百分比,需先换算为基础 ap 的绝对增量 return ((value / 100) * apEff / cd) * weights.W_DPS_PER_SEC * seconds; case Attrs.hp_max: case Attrs.hp: // 永久 buff 已改为百分比口径:value 是百分比,需先换算为基础 hp 的绝对增量 return (value / 100) * hpEff * weights.W_HP; case Attrs.critical: return (value / 100) * (apEff / cd) * 0.5 * weights.W_DPS_PER_SEC * seconds; case Attrs.critical_damage: return (value / 100) * (apEff / cd) * 0.05 * weights.W_DPS_PER_SEC * seconds; case Attrs.stun_chance: case Attrs.freeze_chance: return value * weights.W_control; case Attrs.knockback_chance: // 击退强化已改为击退距离增量,按距离价值折算 return value * weights.W_control; case Attrs.speed: return (value / 100) * (apEff / cd) * weights.W_DPS_PER_SEC * seconds; default: return value * weights.W_control; } } /** 计算单条技能配置单次触发的效果价值 */ function calcSkillEffectValue(skill: SkillConfig, overrides: SkillOverrides | undefined, hero: heroInfo, targetLv: number, seconds: number): number { const { hp: hpEff, ap: apEff } = getEffectiveStats(hero, targetLv); const cd = getAttackCd(hero); const config = overrides ? mergeSkillParams(skill, overrides) : skill; const weights = HERO_POWER_WEIGHTS; switch (config.kind) { case SkillKind.Damage: return ((config.ap || 0) / 100) * apEff * weights.W_DPS_PER_SEC; case SkillKind.Heal: return ((config.ap || 0) / 100) * apEff * weights.W_heal; case SkillKind.Shield: // 护盾为数值减免型:1 点护盾 ≈ 1 点预期伤害减免 return (config.ap || 0) * weights.W_shield; case SkillKind.Support: return calcSupportEffectValue(config, hpEff, apEff, cd, seconds); default: return 0; } } /** 触发技评估项 */ export interface TriggerSkillEval { type: SkillTriggerType; s_uuid: number; name: string; t_num: number; value: number; } /** 驻场光环评估项 */ export interface FieldSkillEval { uuid: number; name: string; value: number; } /** 英雄强度分数构成 */ export interface HeroPowerBreakdown { hp: number; dps: number; atking: number; atked: number; fstart: number; dead: number; field: number; revive: number; } /** 英雄强度详细评估结果 */ export interface HeroPowerDetailed { total: number; breakdown: HeroPowerBreakdown; triggerSkills: TriggerSkillEval[]; fieldSkills: FieldSkillEval[]; normalAttack: { s_uuid: number, name: string, cd: number, dps: number, value: number }; } /** 计算普通触发类技能(atking/atked/fstart/dead)的详细价值 */ function calcTriggerPowerDetailed( triggerConfigs: { s_uuid: number, t_num?: number, overrides?: SkillOverrides }[], hero: heroInfo, targetLv: number, type: SkillTriggerType, seconds: number ): { total: number, items: TriggerSkillEval[] } { if (!triggerConfigs || triggerConfigs.length === 0) return { total: 0, items: [] }; const weights = HERO_POWER_WEIGHTS; let total = 0; const items: TriggerSkillEval[] = []; for (const trig of triggerConfigs) { const skill = SkillSet[trig.s_uuid]; if (!skill) continue; const effectValue = calcSkillEffectValue(skill, trig.overrides, hero, targetLv, seconds); const overrides = trig.overrides || {}; const group = overrides.TGroup ?? skill.TGroup; const scopeMul = calcScopeMul(group); const tNum = trig.t_num || 1; let weight = 1; switch (type) { case SkillTriggerType.Atking: weight = weights.W_atking; break; case SkillTriggerType.Atked: weight = weights.W_atked; break; case SkillTriggerType.FStart: weight = weights.W_fstart; break; case SkillTriggerType.Dead: weight = weights.W_dead; break; } const triggerCount = getTriggerCount(type, tNum, hero, seconds); const value = effectValue * triggerCount * scopeMul * weight; total += value; items.push({ type, s_uuid: trig.s_uuid, name: skill.name, t_num: tNum, value }); } return { total, items }; } /** 计算驻场光环技能在时间窗内的总价值(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 (fs.type) { case FieldSkillType.HeroAtk: return value * dps * scopeMul * weights.W_DPS_PER_SEC * seconds; case FieldSkillType.HeroHp: return value * hpEff * scopeMul * weights.W_HP; case FieldSkillType.HeroSpeed: return value * dps * scopeMul * weights.W_DPS_PER_SEC * seconds; case FieldSkillType.HeroCrit: return value * dps * scopeMul * 0.5 * weights.W_DPS_PER_SEC * seconds; case FieldSkillType.HeroCritDamage: 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 value * scopeMul * weights.W_control * 100; default: return value * scopeMul * weights.W_control * 10; } } /** 计算驻场光环的详细价值 */ 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); const scopeMul = FightSet.HERO_FIELD_NUM; let total = 0; const items: FieldSkillEval[] = []; 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: entry.uuid, name: fs.name, value }); } return { total, items }; } /** 获取普通攻击信息 */ function getNormalAttackInfo(hero: heroInfo, targetLv: number = 1, seconds: number = HERO_POWER_WEIGHTS.DEFAULT_EVAL_SECONDS): { s_uuid: number, name: string, cd: number, dps: number, value: number } { const weights = HERO_POWER_WEIGHTS; const { ap: apEff } = getEffectiveStats(hero, targetLv); const cd = getAttackCd(hero); const skillIds = Object.keys(hero.skills); const firstKey = skillIds.length > 0 ? Number(skillIds[0]) : 0; const skill = firstKey ? SkillSet[firstKey] : undefined; const dps = apEff / cd; return { s_uuid: firstKey, name: skill?.name ?? '普攻', cd, dps, value: dps * weights.W_DPS_PER_SEC * seconds, }; } /** * 计算英雄强度详细评估(含分数构成与每个技能价值)。 * @param hero 英雄/怪物配置 * @param targetLv 目标等级,默认 1 * @param seconds 评估时间窗(秒),默认 HERO_POWER_WEIGHTS.DEFAULT_EVAL_SECONDS * @returns 详细强度评估结果 */ export function calcHeroPowerDetailed(hero: heroInfo, targetLv: number = 1, seconds: number = HERO_POWER_WEIGHTS.DEFAULT_EVAL_SECONDS): HeroPowerDetailed { const weights = HERO_POWER_WEIGHTS; const { hp: hpEff, ap: apEff } = getEffectiveStats(hero, targetLv); const cd = getAttackCd(hero); const hpValue = hpEff * weights.W_HP; const dpsValue = (apEff / cd) * weights.W_DPS_PER_SEC * seconds; const normalAttack = getNormalAttackInfo(hero, targetLv, seconds); const atking = hero.atking ? calcTriggerPowerDetailed(resolveTriggerByLv(hero.atking, targetLv), hero, targetLv, SkillTriggerType.Atking, seconds) : { total: 0, items: [] as TriggerSkillEval[] }; const atked = hero.atked ? calcTriggerPowerDetailed(resolveTriggerByLv(hero.atked, targetLv), hero, targetLv, SkillTriggerType.Atked, seconds) : { total: 0, items: [] as TriggerSkillEval[] }; const fstart = hero.fstart ? calcTriggerPowerDetailed(resolveTriggerByLv(hero.fstart, targetLv), hero, targetLv, SkillTriggerType.FStart, 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 fieldEntries = resolveFieldByLv(hero.field, targetLv); const field = fieldEntries.length > 0 ? calcFieldPowerDetailed(fieldEntries, hero, targetLv, seconds) : { total: 0, items: [] as FieldSkillEval[] }; let reviveValue = 0; // 复活价值从 dead 触发配置中提取(revive_hp / revive_count) const deadTriggers = resolveTriggerByLv(hero.dead, targetLv); for (const t of deadTriggers) { const reviveHp = t.overrides?.revive_hp; const reviveCount = t.overrides?.revive_count ?? 0; if (reviveHp !== undefined && reviveCount > 0) { reviveValue = hpEff * (reviveHp / 100) * reviveCount * weights.W_revive * getWaveCount(seconds); } } const total = hpValue + dpsValue + atking.total + atked.total + fstart.total + dead.total + field.total + reviveValue; return { total, breakdown: { hp: hpValue, dps: dpsValue, atking: atking.total, atked: atked.total, fstart: fstart.total, dead: dead.total, field: field.total, revive: reviveValue, }, triggerSkills: [...atking.items, ...atked.items, ...fstart.items, ...dead.items], fieldSkills: field.items, normalAttack, }; } /** * 计算指定时间窗内的英雄强度评分。 * @param hero 英雄/怪物配置 * @param targetLv 目标等级,默认 1 * @param seconds 评估时间窗(秒) * @returns 无量纲强度分,数值越大越强 */ export function calcHeroPowerOverTime(hero: heroInfo, targetLv: number = 1, seconds: number = HERO_POWER_WEIGHTS.DEFAULT_EVAL_SECONDS): number { return calcHeroPowerDetailed(hero, targetLv, seconds).total; } /** * 计算英雄强度评分(默认时间窗)。 * @param hero 英雄/怪物配置 * @param targetLv 目标等级,默认 1 * @returns 无量纲强度分,数值越大越强 */ export function calcHeroPower(hero: heroInfo, targetLv: number = 1): number { return calcHeroPowerOverTime(hero, targetLv); } /** * 归一化英雄强度评分。 * @param hero 英雄配置 * @param targetLv 目标等级 * @param baseHeroId 基准英雄 uuid * @param baseScore 基准分 * @returns 以基准英雄为 baseScore 的相对分数 */ export function calcHeroPowerNormalized(hero: heroInfo, targetLv: number = 1, baseHeroId: number = 5001, baseScore: number = 100): number { const baseHero = HeroInfo[baseHeroId]; if (!baseHero) return 0; const basePower = calcHeroPower(baseHero, targetLv); if (basePower === 0) return 0; return calcHeroPower(hero, targetLv) / basePower * baseScore; }