1. 更新多个技能的debuff_value数值为正向加成值 2. 将技能描述中的"前方达人"改为"前方敌人",并补充攻击力占位符 3. 同步更新代码配置中的技能参数与json配置一致
1783 lines
92 KiB
TypeScript
1783 lines
92 KiB
TypeScript
import { v3 } from "cc"
|
||
import { BoxSet, FacSet, FightSet } from "./GameSet"
|
||
import { SkillOverrides, TGroup, SkillSet, FieldSkillSet, SkillConfig, SkillKind, FieldSkillConfig, FieldSkillType, mergeSkillParams, BuffTarget } 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<number, string> = {
|
||
[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 },
|
||
};
|
||
|
||
/**
|
||
* 英雄大招(skills[1])CD 分级配置(5 档,与 AtkSpeedLv 五档结构对齐)。
|
||
* 分档规则:VeryFast=单体爆发/高频压制,Normal=群体伤害/控制,VerySlow=全体增益/治疗/护盾,
|
||
* Fast/Slow 为中间档,供同类技能内细分释放节奏。
|
||
* Why: 大招 CD 曾 18/19 英雄统一 8s,场上大招齐发成"脉冲",玩家难以感知单次大招释放;
|
||
* 按技能效果类型分档交错 CD(6~10s),形成持续鼓点节奏,拉开"高频小爆发 vs 稀有大回报"的感知差。
|
||
* TODO: CD 档位与数值联动补偿(短 CD 单次数值下调、长 CD 上调)待观察实战强度后统一调整。
|
||
*/
|
||
export enum UltCdLv {
|
||
VeryFast = 1, // 单体爆发/高频压制
|
||
Fast = 2, // 频繁压制(中间档)
|
||
Normal = 3, // 群体伤害/控制
|
||
Slow = 4, // 中度团队增益(中间档)
|
||
VerySlow = 5, // 全体增益/治疗/护盾
|
||
}
|
||
|
||
export const UltCdSet = {
|
||
[UltCdLv.VeryFast]: { name: "极频", cd: 6 },
|
||
[UltCdLv.Fast]: { name: "高频", cd: 7 },
|
||
[UltCdLv.Normal]: { name: "标准", cd: 8 },
|
||
[UltCdLv.Slow]: { name: "低频", cd: 9 },
|
||
[UltCdLv.VerySlow]: { name: "稀有", cd: 10 },
|
||
};
|
||
|
||
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 | HType.Mid | HType.Long, number> = {
|
||
[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, { hp: number; ap: number; def: number }> = {
|
||
[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 职业属性专项已移除:单项属性强化统一由英雄配置的 bonus 档位注入
|
||
* (如 { lv: 12, attrs: { ap: 50 } }),机制与展示口径保持一致。
|
||
*/
|
||
|
||
/** 英雄位置类型(职业定位)。
|
||
* 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, string> = {
|
||
[HRole.Tank]: "坦克",
|
||
[HRole.Warrior]: "战士",
|
||
[HRole.Assassin]: "刺客",
|
||
[HRole.Archer]: "射手",
|
||
[HRole.Mage]: "法师",
|
||
[HRole.Support]: "辅助",
|
||
};
|
||
|
||
/** lv12 职业专项已移除:单项强化由 bonus 配置接管,此处不再保留职业→属性映射 */
|
||
|
||
/**
|
||
* 职业基础属性模板(仅英雄使用,怪物无 role 直接手写 hp/ap/def)。
|
||
* 英雄配置处的 hp/ap/def = 本模板值 + 该卡手动增量,模板保证同职业基准一致、增量表达个体差异。
|
||
* Why: 局外升级机制将在加载时(Hero.ts / Mon.ts)统一重算属性,配置表只承担"基准+增量"的静态表达。
|
||
*/
|
||
export const HERO_ROLE_BASE: Record<HRole, { hp: number; ap: number; def: number }> = {
|
||
[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<heroInfo, "hp" | "ap" | "def" | "grow_type">, 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", // 战斗开始 先手
|
||
FEnd = "fend", // 回合结束 收官
|
||
Field = "field", // 驻场 光环
|
||
Atking = "atking", // 攻击后触发 追击
|
||
Atked = "atked", // 受击后触发 反击
|
||
Revive = "revive", // 复活触发 涅槃
|
||
}
|
||
|
||
export const SkillTriggerName = {
|
||
[SkillTriggerType.Call]: "召唤",
|
||
[SkillTriggerType.Dead]: "死亡后",
|
||
[SkillTriggerType.FStart]: "回合开始",
|
||
[SkillTriggerType.FEnd]: "回合结束",
|
||
[SkillTriggerType.Field]: "光环",
|
||
[SkillTriggerType.Atking]: "攻击",
|
||
[SkillTriggerType.Atked]: "受伤",
|
||
[SkillTriggerType.Revive]: "复活",
|
||
}
|
||
|
||
export const SkillTriggerDesc = {
|
||
[SkillTriggerType.Call]: "召唤时",
|
||
[SkillTriggerType.Dead]: "死亡时",
|
||
[SkillTriggerType.FStart]: "战斗开始时",
|
||
[SkillTriggerType.FEnd]: "回合结束时",
|
||
[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.FEnd, 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.FEnd]?: TriggerGrouped; // 回合结束时释放的技能配置
|
||
[SkillTriggerType.Field]?: LvFieldEntry[]; // 驻场光环(按 lv 升序,运行时取 ≤英雄等级 的最大档)
|
||
[SkillTriggerType.Atking]?: TriggerGrouped; // 普通攻击后触发的技能配置,s_uuid: 技能id, t_num: 触发所需的普攻次数, t_chance: 触发概率(%),pity_add: 未触发时下次概率增量
|
||
[SkillTriggerType.Atked]?: TriggerGrouped; // 受击后触发的技能配置,s_uuid: 技能id, t_num: 触发所需的受击次数, t_chance: 触发概率(%),pity_add: 未触发时下次概率增量
|
||
dis?: number; // 攻击距离(像素)
|
||
speed?: number; // 移动速度(像素/秒)
|
||
dodge?: number; // 闪避率(百分点,缺省由初始化处兜底为全局默认值)
|
||
accuracy?: number; // 命中率(百分点,缺省由初始化处兜底为全局默认值)
|
||
skills: Record<number, HSkillInfo>; // 携带技能ID列表
|
||
bonus?: LvBonusAttrsEntry[]; // 额外属性加成(按 lv 升序,运行时累加所有 lv ≤ 英雄等级 的档位 attrs;hp/ap/def 按"基础×品质+成长"快照百分比加成,crt/frz/stun/para 为固定百分点累加)
|
||
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;
|
||
/** 触发概率(百分点 0~100,缺省 100 必触发;仅 Atking/Atked 攻受击触发生效) */
|
||
t_chance?: number;
|
||
/** 保底叠加:判定未触发时,为该 s_uuid 累积下次概率增量(百分点)。
|
||
* 缺省/0 = 不叠加;触发成功后清零,最终概率封顶 100 */
|
||
pity_add?: number;
|
||
overrides?: SkillOverrides;
|
||
/** 此档描述模板:缺省回退该组第 1 档 desc;由 HeroSkillText 渲染合并后实时数值。
|
||
* 显式配置后弹窗提升档(slv2+)直接展示该模板渲染结果,优先于自动 diff */
|
||
desc?: string;
|
||
}
|
||
|
||
/**
|
||
* 触发技能按 s_uuid 分组的配置:每个 s_uuid 下按 lv 升序排列。
|
||
* 运行时取每个 s_uuid 中 ≤英雄等级 的最大 lv 档。
|
||
*/
|
||
export type TriggerGrouped = Record<number /*s_uuid*/, LvTriggerEntry[]>;
|
||
|
||
/**
|
||
* 运行时生效的触发条目(resolveTriggerByLv 产出):
|
||
* 每个 s_uuid 取 ≤lv 最大档的扁平结果,供触发器/评分/文案消费。
|
||
*/
|
||
export interface ResolvedTriggerEntry {
|
||
s_uuid: number;
|
||
t_num: number;
|
||
/** 触发概率(百分点,缺省 100 必触发;仅 Atking/Atked 生效) */
|
||
t_chance?: number;
|
||
/** 保底叠加:未触发时累积的下次概率增量(百分点,触发成功后清零) */
|
||
pity_add?: number;
|
||
overrides?: SkillOverrides;
|
||
}
|
||
|
||
/**
|
||
* 驻场光环词条: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;
|
||
}
|
||
|
||
/**
|
||
* 额外属性加成按等级叠加:运行时累加所有 ≤英雄等级 的档位 attrs。
|
||
* 口径约定:hp/ap/def 为百分比(基数取"基础×品质+成长"快照,多档同键加法叠加不滚雪球);
|
||
* crt/frz/stun/para 为固定百分点(直接累加到对应概率属性)。
|
||
*/
|
||
export type BonusAttrKey = 'hp' | 'ap' | 'def' | 'crt' | 'frz' | 'stun' | 'para';
|
||
|
||
export interface LvBonusAttrsEntry {
|
||
lv: number;
|
||
attrs: Partial<Record<BonusAttrKey, number>>;
|
||
/** 展示名(图鉴技能图标/弹窗用,如「钢铁壁垒」);缺省不出图标 */
|
||
name?: string;
|
||
/** 图标帧名(gui/ui7 图集);缺省该档不在图鉴出图标 */
|
||
icon?: string;
|
||
/** 自定义描述模板(可选);缺省由 attrs 自动生成效果文案 */
|
||
info?: string;
|
||
}
|
||
/*
|
||
*=============英雄配置列表================
|
||
* 几何王国复刻版 — 依据 英雄设计指引.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<number, heroInfo> = {
|
||
// @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}, desc: "挥剑对{target}造成攻击力{ap}%伤害",
|
||
lv_entries: [
|
||
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"ap":120}, desc: "普通攻击 造成 120% 伤害" },
|
||
],
|
||
},
|
||
6301: { uuid: 6301, name: "魔法盾", lv: 1, cd: UltCdSet[UltCdLv.VerySlow].cd, 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: {
|
||
6412: [
|
||
{ lv: 4, s_lv: SkillLv.Lv1, t_num: 3, t_chance: 50, pity_add: 20, overrides: {"ap":1} },
|
||
],
|
||
},
|
||
bonus: [
|
||
{ lv: 12, attrs: {"def":50}, name: "钢铁壁垒", icon: "46-Iron-Clad", },
|
||
],
|
||
info: "自身强护盾+防御强化",
|
||
},
|
||
// 5002 易伤剑仙 — CSV导入:击退压场+易伤放大;复刻酒仙
|
||
5002: {
|
||
uuid: 5002, 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: {"ap":120}, desc: "普通攻击造成 120% 攻击伤害" },
|
||
],
|
||
},
|
||
6101: { uuid: 6101, name: "气斩", lv: 1, cd: UltCdSet[UltCdLv.Normal].cd, ccd: 0, overrides: {"ap":150,"timed_debuff_id":7002,"debuff_value":30,"debuff_chance":100,"debuff_duration":5}, desc: "斩出气刃,对{target}造成攻击力{ap}%伤害,并使目标易伤(受到伤害加深,持续{dur}秒)",
|
||
lv_entries: [
|
||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":200,"timed_debuff_id":7002,"debuff_value":70,"debuff_chance":100,"debuff_duration":5} },
|
||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":250,"timed_debuff_id":7002,"debuff_value":150,"debuff_chance":100,"debuff_duration":7} },
|
||
],
|
||
},
|
||
},
|
||
atking: {
|
||
6001: [
|
||
{ lv: 4, s_lv: SkillLv.Lv1, t_num: 3, t_chance: 50, pity_add: 20, overrides: {"timed_debuff_id":7002,"debuff_value":10,"debuff_chance":100,"debuff_duration":5} },
|
||
],
|
||
},
|
||
bonus: [
|
||
{ lv: 12, attrs: {"hp":50}, name: "不屈战意", icon: "29-Endure", },
|
||
],
|
||
info: "易伤,近战 dps",
|
||
},
|
||
// 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: "普通攻击有{stun}%概率击晕敌人" },
|
||
],
|
||
},
|
||
6104: { uuid: 6104, name: "开山斧", lv: 1, cd: UltCdSet[UltCdLv.Normal].cd, ccd: 0, overrides: {"ap":250,"stun":100}, desc: "劈出开山斧,对{target}造成攻击力{ap}%伤害,必定击晕",
|
||
lv_entries: [
|
||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":300,"stun":100} },
|
||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":350,"stun":100} },
|
||
],
|
||
},
|
||
},
|
||
atking: {
|
||
6504: [
|
||
{ lv: 4, s_lv: SkillLv.Lv1, t_num: 3, t_chance: 50, pity_add: 20, overrides: {"buff_value":30}, desc: "{t_chance}% 概率提升普通攻击 30%暴击率5秒" },
|
||
],
|
||
},
|
||
bonus: [
|
||
{ lv: 12, attrs: {"hp":50}, name: "不屈战意", icon: "29-Endure", },
|
||
],
|
||
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: "普通攻击有{crt}%概率暴击" },
|
||
],
|
||
},
|
||
6150: { uuid: 6150, name: "剑刃风暴", lv: 1, cd: UltCdSet[UltCdLv.VeryFast].cd, ccd: 0, overrides: {"ap":150,"crt":50}, desc: "对{target}造成攻击力{ap}%伤害,有50% 概率暴击",
|
||
lv_entries: [
|
||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":200,"crt":60} },
|
||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":250,"crt":70} },
|
||
],
|
||
},
|
||
},
|
||
atking: {
|
||
6504: [
|
||
{ lv: 4, s_lv: SkillLv.Lv1, t_num: 3, t_chance: 50, pity_add: 20, overrides: {"timed_buff_id":7012,"buff_value":10,"buff_chance":100,"buff_duration":5}, desc: "{t_chance}% 概率,普通攻击获得 10% 的暴击率" },
|
||
],
|
||
},
|
||
bonus: [
|
||
{ lv: 12, attrs: {"ap":50}, name: "致命本能", icon: "36-Guardian-Stance", },
|
||
],
|
||
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_debuff_id":7007,"debuff_value":-30,"debuff_chance":50}, desc: "普通攻击有{debuff_chance}%概率使目标出血(每0.5秒受到{debuff_value}点伤害,持续{dur}秒)" },
|
||
],
|
||
},
|
||
6150: { uuid: 6150, name: "血刃风暴", lv: 1, cd: UltCdSet[UltCdLv.VeryFast].cd, ccd: 0, overrides: {"ap":200,"timed_debuff_id":7007,"debuff_value":-20,"debuff_chance":100,"debuff_duration":5}, desc: "高速斩击{target},造成攻击力{ap}%伤害",
|
||
lv_entries: [
|
||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":250,"timed_debuff_id":7007,"debuff_value":-30,"debuff_chance":100,"debuff_duration":7}, desc: "高速斩击{target},造成攻击力{ap}%,并使目标出血(每0.5秒受到{debuff_value}点伤害,持续{dur}秒)" },
|
||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":300,"timed_debuff_id":7007,"debuff_value":-50,"debuff_chance":100,"debuff_duration":9}, desc: "高速斩击{target},造成攻击力{ap}%,附带 50% 概率麻痹,并使目标出血(每0.5秒受到{debuff_value}点伤害,持续{dur}秒)" },
|
||
],
|
||
},
|
||
},
|
||
atking: {
|
||
6401: [
|
||
{ lv: 4, s_lv: SkillLv.Lv1, t_num: 3, t_chance: 50, pity_add: 20, overrides: {"buff_value":2} },
|
||
],
|
||
},
|
||
bonus: [
|
||
{ lv: 12, attrs: {"ap":50}, name: "致命本能", icon: "36-Guardian-Stance", },
|
||
],
|
||
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: {"frz":10}, desc: "普通攻击有{frz}%概率 冰冻敌人" },
|
||
],
|
||
},
|
||
6150: { uuid: 6150, name: "寒冰箭", lv: 1, cd: UltCdSet[UltCdLv.Normal].cd, ccd: 0, overrides: {"ap":150,"frz":30,"icon":"Stat_AttackRangeIncrease_02"}, desc: "射出 6 支寒冰箭,对{target}造成攻击力{ap}%伤害,每支箭有{frz}%概率冰冻敌人",
|
||
lv_entries: [
|
||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":200,"frz":30} },
|
||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":250,"frz":30} },
|
||
],
|
||
},
|
||
},
|
||
atking: {
|
||
6401: [
|
||
{ lv: 4, s_lv: SkillLv.Lv1, t_num: 3, t_chance: 50, pity_add: 20, overrides: {"buff_value":2,"TGroup": TGroup.Ally}, desc: "{t_chance}%概率,永久提升全队 2% 攻击力" },
|
||
],
|
||
},
|
||
bonus: [
|
||
{ lv: 12, attrs: {"ap":50}, name: "鹰眼锁定", icon: "27-Hawkeye", },
|
||
],
|
||
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}, desc: "掷出紫魔球,对{target}造成攻击力{ap}%伤害",
|
||
lv_entries: [
|
||
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"bck_chance":20}, desc: "普通攻击有{bck_chance}%概率击退敌人" },
|
||
],
|
||
},
|
||
6200: { uuid: 6200, name: "火焰喷射", lv: 1, cd: UltCdSet[UltCdLv.Normal].cd, ccd: 0, overrides: {"ap":250,"crt":50}, desc: "喷出烈焰风暴,对{target}造成攻击力{ap}%伤害,击退{bck}",
|
||
lv_entries: [
|
||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":350,"crt":0} },
|
||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":450,"crt":0,"summon_count":4} },
|
||
],
|
||
},
|
||
},
|
||
field: [
|
||
{ lv: 4, uuids: [{ uuid: 7002, value: 0.15, name: "攻击光环" }] },
|
||
],
|
||
bonus: [
|
||
{ lv: 12, attrs: {"ap":50}, name: "奥术共鸣", icon: "100-Enchant-Magic", },
|
||
],
|
||
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: {"ap":120}, desc: "普通攻击造成 120% 攻击伤害" },
|
||
],
|
||
},
|
||
6302: { uuid: 6302, name: "治疗", lv: 1, cd: UltCdSet[UltCdLv.VerySlow].cd, ccd: 0, overrides: {"ap":30,"TGroup": TGroup.Ally}, desc: "为{target}回复攻击力{ap}%生命",
|
||
lv_entries: [
|
||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":40,"TGroup": TGroup.Ally} },
|
||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":50,"TGroup": TGroup.Ally,"timed_buff_id":7024,"buff_value":20,"buff_chance":100,"buff_duration":5} },
|
||
],
|
||
},
|
||
},
|
||
field: [
|
||
{ lv: 4, uuids: [{ uuid: 7001, value: 20 }], desc: "每回合结束 休整恢复的血量值提升 20%" },
|
||
],
|
||
bonus: [
|
||
{ lv: 12, attrs: {"hp":50}, name: "守护之心", icon: "29-Endure", },
|
||
],
|
||
info: "全体治疗+攻击附盾,团队续航",
|
||
},
|
||
// 5009 甲虫领主
|
||
5009: {
|
||
uuid: 5009, name: "甲虫领主", path: "hk3", fac: FacSet.HERO, rarity: 1, 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: {"ap":120}, desc: "普通攻击造成的伤害提升 20%" },
|
||
],
|
||
},
|
||
6102: { uuid: 6102, lv: 1, cd: UltCdSet[UltCdLv.Normal].cd, ccd: 0, overrides: {"ap":250,"proc_skill":{"s_uuid":6302,"chance":100,"overrides":{"TGroup": TGroup.Self,"buff_value":10}}},
|
||
lv_entries: [
|
||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":300,"proc_skill":{"s_uuid":6302,"chance":100,"overrides":{"TGroup": TGroup.Self,"buff_value":15}}} },
|
||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":350,"proc_skill":{"s_uuid":6302,"chance":100,"overrides":{"TGroup": TGroup.Self,"buff_value":20}}} },
|
||
],
|
||
},
|
||
},
|
||
atked: {
|
||
6302: [
|
||
{ lv: 4, s_lv: SkillLv.Lv1, t_num: 3, t_chance: 30, pity_add: 20, overrides: {"ap":5}, desc: "{t_chance}%概率,恢复{ap}%生命值" },
|
||
],
|
||
},
|
||
bonus: [
|
||
{ lv: 12, attrs: {"def":50}, name: "钢铁壁垒", icon: "46-Iron-Clad", },
|
||
],
|
||
info: "受击自疗+击退,自愈坦克",
|
||
},
|
||
// 5010 火箭哥
|
||
5010: {
|
||
uuid: 5010, name: "火箭哥", path: "ha2", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Mid, grow_type: HGrowType.Archer, role: HRole.Archer, hp: HERO_ROLE_BASE[HRole.Archer].hp, ap: HERO_ROLE_BASE[HRole.Archer].ap, def: HERO_ROLE_BASE[HRole.Archer].def,
|
||
skills: {
|
||
6006: { uuid: 6006, name: "强化普攻", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Fast].cd, ccd: 0,
|
||
lv_entries: [
|
||
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"crt":10} },
|
||
],
|
||
},
|
||
6151: { uuid: 6151, lv: 1, cd: UltCdSet[UltCdLv.VeryFast].cd, ccd: 0, overrides: {"ap":70,"summon_count":5,"timed_debuff_id":7006,"debuff_value":-10,"debuff_chance":100,"debuff_duration":5},
|
||
lv_entries: [
|
||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":80,"timed_debuff_id":7006,"debuff_value":-20,"debuff_chance":100,"debuff_duration":5} },
|
||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":100,"timed_debuff_id":7006,"debuff_value":-30,"debuff_chance":100,"debuff_duration":5} },
|
||
],
|
||
},
|
||
},
|
||
atking: {
|
||
6008: [
|
||
{ lv: 4, s_lv: SkillLv.Lv1, t_num: 3, t_chance: 50, pity_add: 20, overrides: {"ap":120} },
|
||
],
|
||
},
|
||
bonus: [
|
||
{ lv: 12, attrs: {"ap":50}, name: "鹰眼锁定", icon: "27-Hawkeye", },
|
||
],
|
||
info: "暴击",
|
||
},
|
||
// 5011 控血大师
|
||
5011: {
|
||
uuid: 5011, name: "控血大师", path: "hk2", fac: FacSet.HERO, rarity: 1, 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.Normal].cd, ccd: 0,
|
||
lv_entries: [
|
||
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"proc_skill":{"s_uuid":6502,"chance":10,"overrides":{"ap":5,"TGroup": TGroup.Self}}}, desc: "普攻有 10% 概率,对自己释放回春(5 秒回复5% 生命)" },
|
||
],
|
||
},
|
||
6103: { uuid: 6103, name: "闪电战", lv: 1, cd: UltCdSet[UltCdLv.VerySlow].cd, ccd: 0, overrides: {"ap":200,"timed_buff_id":7029,"buff_value":30,"buff_chance":100,"buff_duration":5,"buff_target": BuffTarget.Self}, desc: "对前方敌人造成攻击力{ap}%伤害,并提升自己最大生命值{buff_value}%,持续{dur}秒",
|
||
lv_entries: [
|
||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":250,"timed_buff_id":7029,"buff_value":40,"buff_chance":100,"buff_duration":5,"buff_target": BuffTarget.Self} },
|
||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":300,"timed_buff_id":7029,"buff_value":50,"buff_chance":100,"buff_duration":5,"buff_target": BuffTarget.Self} },
|
||
],
|
||
},
|
||
},
|
||
atked: {
|
||
6402: [
|
||
{ lv: 4, s_lv: SkillLv.Lv1, t_num: 5, t_chance: 30, pity_add: 15, overrides: {"ap":1,"TGroup": TGroup.Ally,"hit_count":3}, desc: "全队永久增加 1% 生命最大值" },
|
||
],
|
||
},
|
||
bonus: [
|
||
{ lv: 12, attrs: {"def":50}, name: "钢铁壁垒", icon: "46-Iron-Clad", },
|
||
],
|
||
info: "永久和计时生命最大值,控血大师",
|
||
},
|
||
// 5012 疾风法师
|
||
5012: {
|
||
uuid: 5012, name: "疾风法师", path: "hm2", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Long, grow_type: HGrowType.Mage, role: HRole.Mage, hp: HERO_ROLE_BASE[HRole.Mage].hp, ap: HERO_ROLE_BASE[HRole.Mage].ap, def: HERO_ROLE_BASE[HRole.Mage].def,
|
||
skills: {
|
||
6009: { uuid: 6009, name: "普攻强化", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Normal].cd, ccd: 0,
|
||
lv_entries: [
|
||
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"proc_skill":{"s_uuid":6507,"chance":10,"overrides":{"buff_value":30,"TGroup": TGroup.Self}}} },
|
||
],
|
||
},
|
||
6201: { uuid: 6201, name: "飓风", lv: 1, cd: UltCdSet[UltCdLv.Normal].cd, ccd: 0, overrides: {"ap":100,"summon_count":2,"proc_skill":{"s_uuid":6507,"chance":20,"overrides":{"buff_value":20,"TGroup": TGroup.Ally}}}, desc: "召唤 {summon_count} 道飓风攻击前方敌人,每道飓风造成 {ap}%伤害,每道飓风释放时有<color=#3CE66E>20</color>% 概率增加全体队友<color=#3CE66E>20</color>% 攻速",
|
||
lv_entries: [
|
||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":100,"summon_count":3,"proc_skill":{"s_uuid":6507,"chance":25,"overrides":{"buff_value":25,"TGroup": TGroup.Ally}}}, desc: "召唤 {summon_count} 道飓风攻击前方敌人,每道飓风造成 {ap}%伤害,每道飓风释放时有<color=#3CE66E>20</color>% 概率增加全体队友<color=#3CE66E>20</color>% 攻速" },
|
||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":100,"summon_count":4,"proc_skill":{"s_uuid":6507,"chance":30,"overrides":{"buff_value":30,"TGroup": TGroup.Ally}}}, desc: "召唤 {summon_count} 道飓风攻击前方敌人,每道飓风造成 {ap}%伤害,每道飓风释放时有<color=#3CE66E>20</color>% 概率增加全体队友<color=#3CE66E>20</color>% 攻速" },
|
||
],
|
||
},
|
||
},
|
||
field: [
|
||
{ lv: 4, uuids: [{ uuid: 7006, value: 10 }] },
|
||
],
|
||
bonus: [
|
||
{ lv: 12, attrs: {"ap":50}, name: "奥术共鸣", icon: "100-Enchant-Magic", },
|
||
],
|
||
info: "普攻 大招加速 buff+加速光环,加速大师",
|
||
},
|
||
// 5013 生命哥
|
||
5013: {
|
||
uuid: 5013, name: "生命哥", path: "hh2", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Long, grow_type: HGrowType.Support, role: HRole.Support, hp: HERO_ROLE_BASE[HRole.Support].hp, ap: HERO_ROLE_BASE[HRole.Support].ap, def: HERO_ROLE_BASE[HRole.Support].def,
|
||
skills: {
|
||
6004: { uuid: 6004, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Normal].cd, ccd: 0,
|
||
lv_entries: [
|
||
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"ap":120} },
|
||
],
|
||
},
|
||
6517: { uuid: 6517, name: "生命护盾", lv: 1, cd: UltCdSet[UltCdLv.VerySlow].cd, ccd: 0, overrides: {"buff_value":20,"TGroup": TGroup.Ally,"hit_count":3,"buff_duration":5},
|
||
lv_entries: [
|
||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"buff_value":25,"TGroup": TGroup.Ally,"hit_count":3,"buff_duration":10} },
|
||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"buff_value":30,"buff_duration":10,"hit_count":3,"TGroup": TGroup.Ally} },
|
||
],
|
||
},
|
||
},
|
||
atking: {
|
||
6414: [
|
||
{ lv: 4, s_lv: SkillLv.Lv1, t_num: 3, t_chance: 30, pity_add: 15, overrides: {"buff_value":10,"TGroup": TGroup.Ally} },
|
||
],
|
||
},
|
||
bonus: [
|
||
{ lv: 12, attrs: {"hp":50}, name: "守护之心", icon: "29-Endure", },
|
||
],
|
||
info: "大招全体生命最大值+概率全体+反伤护盾",
|
||
},
|
||
// 5014 闪避哥
|
||
5014: {
|
||
uuid: 5014, name: "闪避哥", path: "hk4", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Melee, grow_type: HGrowType.Warrior, role: HRole.Warrior, hp: HERO_ROLE_BASE[HRole.Warrior].hp, ap: HERO_ROLE_BASE[HRole.Warrior].ap, def: HERO_ROLE_BASE[HRole.Warrior].def,
|
||
skills: {
|
||
6004: { uuid: 6004, name: "普攻强化", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Normal].cd, ccd: 0,
|
||
lv_entries: [
|
||
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"crt":10} },
|
||
],
|
||
},
|
||
6100: { uuid: 6100, name: "寒冰斩", lv: 1, cd: UltCdSet[UltCdLv.Normal].cd, ccd: 0, overrides: {"ap":200,"timed_buff_id":7030,"buff_value":50},
|
||
lv_entries: [
|
||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":250,"timed_buff_id":7030,"buff_value":50} },
|
||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":350,"timed_buff_id":7030,"buff_value":80} },
|
||
],
|
||
},
|
||
},
|
||
field: [
|
||
{ lv: 4, uuids: [{ uuid: 7023, value: 10 }] },
|
||
],
|
||
bonus: [
|
||
{ lv: 12, attrs: {"hp":50}, name: "不屈战意", icon: "29-Endure", },
|
||
],
|
||
info: "强闪避",
|
||
},
|
||
// 5015 毒箭猎手 — 毒伤持续流:普攻淬毒叠层+毒雨铺DoT+攻击光环喂养毒伤
|
||
5015: {
|
||
uuid: 5015, name: "毒箭猎手", path: "ha3", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Long, grow_type: HGrowType.Archer, role: HRole.Archer, hp: HERO_ROLE_BASE[HRole.Archer].hp + 10, ap: HERO_ROLE_BASE[HRole.Archer].ap, def: HERO_ROLE_BASE[HRole.Archer].def,
|
||
skills: {
|
||
6007: { uuid: 6007, 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_chance":10}, desc: "普通攻击有{bck_chance}%概率击退敌人" },
|
||
],
|
||
},
|
||
6150: { uuid: 6150, name: "万箭齐发·毒", lv: 1, cd: UltCdSet[UltCdLv.Normal].cd, ccd: 0, overrides: {"ap":150,"timed_debuff_id":7005,"debuff_value":-30,"debuff_chance":50,"icon":"4-Apply-Poison"}, desc: "毒箭如雨,对{target}造成攻击力{ap}%伤害,{debuff_chance}%概率使目标中毒(每0.5秒受到{debuff_value}点伤害,持续{dur}秒)",
|
||
lv_entries: [
|
||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":200,"timed_debuff_id":7005,"debuff_value":-60,"debuff_chance":100,"debuff_duration":5} },
|
||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":250,"timed_debuff_id":7005,"debuff_value":-100,"debuff_chance":100,"debuff_duration":7} },
|
||
],
|
||
},
|
||
},
|
||
atking: {
|
||
6007: [
|
||
{ lv: 4, s_lv: SkillLv.Lv1, name: "蚀骨毒箭", t_num: 3, t_chance: 50, pity_add: 20, overrides: {"ap":80,"timed_debuff_id":7005,"debuff_value":40,"debuff_chance":100}, desc: "追加射出蚀骨毒箭,对{target}造成攻击力{ap}%伤害,必定使目标中毒(每0.5秒受到{debuff_value}点伤害,持续{dur}秒)" },
|
||
],
|
||
},
|
||
bonus: [
|
||
{ lv: 12, attrs: {"ap":50}, name: "剧毒淬炼", icon: "27-Hawkeye", },
|
||
],
|
||
info: "淬毒普攻+毒雨叠层,持续消耗型远程毒C",
|
||
},
|
||
// 5016 连珠神射 — 暴击连射爆发流:VeryFast极速普攻+概率追射必暴箭+开局团队暴击爆发
|
||
5016: {
|
||
uuid: 5016, name: "连珠神射", path: "ha4", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Mid, grow_type: HGrowType.Archer, role: HRole.Archer, hp: HERO_ROLE_BASE[HRole.Archer].hp, ap: HERO_ROLE_BASE[HRole.Archer].ap + 10, def: HERO_ROLE_BASE[HRole.Archer].def,
|
||
skills: {
|
||
6008: { uuid: 6008, name: "连珠箭", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.VeryFast].cd, ccd: 0, overrides: {"ap":100}, desc: "极速连射,对{target}造成攻击力{ap}%伤害",
|
||
lv_entries: [
|
||
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"proc_skill":{"s_uuid":6007,"chance":20,"overrides":{"TGroup": TGroup.Enemy,"ap":80}}}, desc: "有 20%额外射击,造成 80% 伤害" },
|
||
],
|
||
},
|
||
6151: { uuid: 6151, name: "裂空箭雨", lv: 1, cd: UltCdSet[UltCdLv.VeryFast].cd, ccd: 0, overrides: {"ap":150,"crt":30,"summon_count":5}, desc: "箭雨倾泻,对{target}造成攻击力{ap}%伤害,{crt}%概率暴击",
|
||
lv_entries: [
|
||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":200,"crt":50} },
|
||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":250,"crt":70,"summon_count":6}, desc: "箭雨倾泻,对{target}造成攻击力{ap}%伤害,{crt}%概率暴击,每支箭可命中{hit_count}个目标" },
|
||
],
|
||
},
|
||
},
|
||
field: [
|
||
{ lv: 4, uuids: [{ uuid: 7004, value: 0.1, name: "猎手集结" }] },
|
||
],
|
||
bonus: [
|
||
{ lv: 12, attrs: {"ap":50}, name: "猎杀直觉", icon: "27-Hawkeye", },
|
||
],
|
||
info: "极速连射+暴击追射+开局团队暴击,爆发型射手主C",
|
||
},
|
||
// 5017 碎甲术士 — 破甲减防法师:fstart先手/普攻概率/大招必定三通道施加破甲7008+穿透光环,团队物理增伤位
|
||
5017: {
|
||
uuid: 5017, name: "碎甲术士", path: "hm3", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Long, grow_type: HGrowType.Mage, role: HRole.Mage, hp: HERO_ROLE_BASE[HRole.Mage].hp, ap: HERO_ROLE_BASE[HRole.Mage].ap + 10, def: HERO_ROLE_BASE[HRole.Mage].def,
|
||
skills: {
|
||
6012: { uuid: 6012, 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: {"timed_debuff_id":7008,"debuff_chance":30}, desc: "普通攻击有{debuff_chance}%概率使目标破甲(防御降低,持续{dur}秒)" },
|
||
],
|
||
},
|
||
6203: { uuid: 6203, name: "碎甲能量波", lv: 1, cd: UltCdSet[UltCdLv.Normal].cd, ccd: 0, overrides: {"ap":150,"timed_debuff_id":7008,"debuff_value":-30,"debuff_chance":100,"debuff_duration":5}, desc: "释放碎甲能量波,对{target}造成攻击力{ap}%伤害,并使目标破甲(防御降低,持续{dur}秒)",
|
||
lv_entries: [
|
||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":200,"timed_debuff_id":7008,"debuff_value":-50,"debuff_chance":100,"debuff_duration":5} },
|
||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":250,"timed_debuff_id":7008,"debuff_value":-70,"debuff_chance":100,"debuff_duration":7}, desc: "释放碎甲能量波,对{target}造成攻击力{ap}%伤害,并使目标破甲加深(防御大幅降低,持续{dur}秒)" },
|
||
],
|
||
},
|
||
},
|
||
field: [
|
||
{ lv: 4, uuids: [{ uuid: 7009, value: 0.1, name: "锐矛之赐" }] },
|
||
],
|
||
bonus: [
|
||
{ lv: 12, attrs: {"ap":50}, name: "奥术共鸣", icon: "100-Enchant-Magic", },
|
||
],
|
||
info: "先手破甲+概率蚀甲+穿透光环,物理队核心增伤位",
|
||
},
|
||
// 5018 雷暴领主 — 雷暴AOE爆发+麻痹控场:先手雷击+高倍率能量波
|
||
5018: {
|
||
uuid: 5018, name: "雷暴领主", path: "hm4", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Long, grow_type: HGrowType.Mage, role: HRole.Mage, hp: HERO_ROLE_BASE[HRole.Mage].hp - 10, ap: HERO_ROLE_BASE[HRole.Mage].ap + 20, def: HERO_ROLE_BASE[HRole.Mage].def,
|
||
skills: {
|
||
6013: { uuid: 6013, 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: {"para":15}, desc: "普通攻击有{para}%概率麻痹敌人,减缓其技能冷却恢复" },
|
||
],
|
||
},
|
||
6204: { uuid: 6204, name: "雷霆裂空", lv: 1, cd: UltCdSet[UltCdLv.Normal].cd, ccd: 0, overrides: {"ap":150,"para":50}, desc: "释放多束闪电,对{target}造成攻击力{ap}%伤害,{para}%概率麻痹敌人",
|
||
lv_entries: [
|
||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":200,"para":70}, desc: "释放雷霆裂空波,对{target}造成攻击力{ap}%伤害,{para}%概率麻痹敌人" },
|
||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":250,"para":100}, desc: "释放雷霆裂空波,对{target}造成攻击力{ap}%伤害,可多次命中,{para}%概率麻痹敌人" },
|
||
],
|
||
},
|
||
},
|
||
field: [
|
||
{ lv: 4, uuids: [{ uuid: 7024, value: 10, name: "雷电精准" }] },
|
||
],
|
||
bonus: [
|
||
{ lv: 12, attrs: {"ap":50}, name: "奥术共鸣", icon: "100-Enchant-Magic", },
|
||
],
|
||
info: "雷暴爆发+麻痹控场,法系主C",
|
||
},
|
||
// @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_debuff_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[] = [
|
||
// 编辑器导出自动同步(共 18 个)
|
||
5001, 5002, 5003, 5004, 5005, 5006, 5007, 5008, 5009, 5010,
|
||
5011, 5012, 5013, 5014, 5015, 5016, 5017, 5018,
|
||
];
|
||
// @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~5018 英雄实际技能组)。
|
||
* 设计原则:
|
||
* 1. 铁三角结构:heroes[0] 固定为近战前排(坦克/战士),其余按站位从近到远
|
||
* 2. 乘区分散:攻击/攻速/暴击/穿透各占独立乘区,组合优先覆盖不同乘区避免稀释
|
||
* 3. 主题唯一:每套阵容围绕一个流派关键词(暴击/控制/续航/破甲/光环/消耗)组队
|
||
*/
|
||
export const HeroComboSet: Record<number, HeroComboInfo> = {
|
||
// 8001 暴击爆发流 — 连珠神射暴击光环喂养双物理C,成型最强
|
||
8001: {
|
||
uuid: 8001, name: "暴击爆发流",
|
||
heroes: [5001, 5016, 5004],
|
||
desc: "叠甲骑士前排抗伤+受击叠防,连珠神射暴击光环覆盖全队并以极速箭雨压场,刀刀暴击近战收割残局。",
|
||
},
|
||
// 8002 冰雷控制流 — 击晕+冰冻+麻痹三控链,敌人出不了手
|
||
8002: {
|
||
uuid: 8002, name: "冰雷控制流",
|
||
heroes: [5003, 5006, 5018],
|
||
desc: "眩晕暴击哥前排开山斧必晕压阵,冻箭哥寒冰箭冰冻链,雷暴领主雷霆麻痹迟滞技能,三控交替敌人难以出手。",
|
||
},
|
||
// 8003 铁桶续航流 — 双坦克承伤+治疗保血,最稳
|
||
8003: {
|
||
uuid: 8003, name: "铁桶续航流",
|
||
heroes: [5009, 5011, 5008],
|
||
desc: "甲虫领主受击自疗顶前排,控血大师受击全队永久生命成长+大招生命爆发,团疗奶爸全体治疗+战后回复光环,专打持久战。",
|
||
},
|
||
// 8004 破甲压制流 — 破甲+减攻双减益,克制高防高攻阵容
|
||
8004: {
|
||
uuid: 8004, name: "破甲压制流",
|
||
heroes: [5001, 5017, 5010],
|
||
desc: "碎甲术士普攻/大招双通道破甲+穿透光环放大物理伤害,火箭哥五箭弹幕必挂减攻削弱敌方输出,叠甲骑士前排兜底。",
|
||
},
|
||
// 8005 光环覆盖流 — 闪避/攻击/攻速三光环全覆盖
|
||
8005: {
|
||
uuid: 8005, name: "光环覆盖流",
|
||
heroes: [5014, 5007, 5012],
|
||
desc: "闪避哥前排+闪避光环提升全队生存,击退火女攻击光环、疾风法师攻速光环持续放大全队输出,三光环增益拉满。",
|
||
},
|
||
// 8006 易伤消耗流 — 易伤放大出血DoT,磨血收割
|
||
8006: {
|
||
uuid: 8006, name: "易伤消耗流",
|
||
heroes: [5002, 5005, 5008],
|
||
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<number, number> = {
|
||
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_fend: 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): ResolvedTriggerEntry[] {
|
||
if (!grouped) return [];
|
||
const result: ResolvedTriggerEntry[] = [];
|
||
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, t_chance: pick.t_chance, pity_add: pick.pity_add, 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 : [];
|
||
}
|
||
|
||
/** 计算目标等级下额外属性加成(成长类型每级递增 + 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 基准但不影响平衡,因怪物通常不填)
|
||
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.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 };
|
||
}
|
||
|
||
/** 计算目标等级下的有效 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,
|
||
};
|
||
}
|
||
|
||
/**
|
||
* 计算英雄展示用最终属性(含品质系数),供 UI 面板与运行时对齐口径。
|
||
* 公式:基础值 × 品质系数 + 成长 + bonus(lv12 专项已移除,由 bonus 配置接管)。
|
||
* @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);
|
||
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:
|
||
case SkillTriggerType.FEnd:
|
||
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;
|
||
case Attrs.dodge:
|
||
case Attrs.accuracy:
|
||
value += modValue * weights.W_control;
|
||
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:
|
||
case Attrs.dodge:
|
||
case Attrs.accuracy:
|
||
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;
|
||
fend: 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: ResolvedTriggerEntry[],
|
||
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.FEnd:
|
||
weight = weights.W_fend;
|
||
break;
|
||
case SkillTriggerType.Dead:
|
||
weight = weights.W_dead;
|
||
break;
|
||
}
|
||
|
||
const triggerCount = getTriggerCount(type, tNum, hero, seconds);
|
||
// 期望折算:按基础触发概率缩放(保底叠加提升的是方差体验,不影响长期期望)
|
||
const chanceMul = (trig.t_chance ?? 100) / 100;
|
||
const value = effectValue * triggerCount * scopeMul * weight * chanceMul;
|
||
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 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 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 + fend.total + dead.total + field.total + reviveValue;
|
||
|
||
return {
|
||
total,
|
||
breakdown: {
|
||
hp: hpValue,
|
||
dps: dpsValue,
|
||
atking: atking.total,
|
||
atked: atked.total,
|
||
fstart: fstart.total,
|
||
fend: fend.total,
|
||
dead: dead.total,
|
||
field: field.total,
|
||
revive: reviveValue,
|
||
},
|
||
triggerSkills: [...atking.items, ...atked.items, ...fstart.items, ...fend.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;
|
||
}
|