refactor(hero): 重构英雄数值系统,支持品质系数与12级职业属性加成
1. 调整英雄最大等级为99,实现近似无限升级 2. 新增防御属性加成系统,补充def_bonus相关配置与计算 3. 引入英雄品质系数机制,相邻品质基础属性相差5% 4. 新增12级职业属性专项加成:坦克加防、战士辅助加血、输出加攻 5. 更新英雄设计文档与配置示例,统一数值计算逻辑 6. 重构成长计算函数,支持防御属性成长与加成
This commit is contained in:
@@ -40,8 +40,8 @@ export enum FightSet {
|
||||
HEARTPOS = -320,//基地位置
|
||||
/** 场上英雄编制数:由开局 3 次三选一固定,玩家无法扩充 */
|
||||
HERO_FIELD_NUM = 3,
|
||||
/** 英雄可升级到的最高等级(通过升级卡提升) */
|
||||
HERO_MAX_LV = 6,
|
||||
/** 英雄可升级到的最高等级(通过升级卡提升),99 近似无限升级 */
|
||||
HERO_MAX_LV = 99,
|
||||
/** 英雄技能等级上限(无限升级下技能 5 级封顶,超出等级只长属性) */
|
||||
HERO_SKILL_MAX_LV = 5,
|
||||
/** 英雄属性随等级成长的倍率(ap/hp = base * MULTIPLIER^(lv-1)) */
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { v3 } from "cc"
|
||||
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"
|
||||
@@ -107,15 +107,37 @@ export enum HGrowType {
|
||||
}
|
||||
|
||||
/** 成长类型系数表(每级增量 = 英雄基础属性 × 对应系数) */
|
||||
export const HERO_GROW_COEF: Record<HGrowType, { hp: number; ap: number }> = {
|
||||
[HGrowType.Tank]: { hp: 1.5, ap: 0.6 },
|
||||
[HGrowType.Warrior]: { hp: 1.0, ap: 1.0 },
|
||||
[HGrowType.Assassin]: { hp: 0.7, ap: 1.4 },
|
||||
[HGrowType.Mage]: { hp: 0.9, ap: 1.3 },
|
||||
[HGrowType.Support]: { hp: 1.1, ap: 0.7 },
|
||||
[HGrowType.Archer]: { hp: 0.8, ap: 1.3 },
|
||||
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 },
|
||||
};
|
||||
|
||||
/**
|
||||
* 英雄品质系数步长:相邻品质(card_lv)基础属性相差 5%。
|
||||
* 系数 = 1 + HERO_QUALITY_STEP × (card_lv - 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(cardLv: number): number {
|
||||
return 1 + HERO_QUALITY_STEP * (Math.max(1, cardLv) - 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 仅驱动数值成长曲线,无法表达"这个英雄在阵容里干什么";
|
||||
@@ -139,6 +161,16 @@ export const HRoleName: Record<HRole, string> = {
|
||||
[HRole.Support]: "辅助",
|
||||
};
|
||||
|
||||
/** lv12 各职业专项属性映射(坦克堆防、战士/辅助堆血、输出位堆攻) */
|
||||
export const HERO_LV12_SPECIAL_ATTR: Record<HRole, "def" | "hp" | "ap"> = {
|
||||
[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 = 本模板值 + 该卡手动增量,模板保证同职业基准一致、增量表达个体差异。
|
||||
@@ -158,16 +190,17 @@ export const HERO_ROLE_BASE: Record<HRole, { hp: number; ap: number; def: number
|
||||
* 公式:累计 = 基础属性 × 类型系数 × (lv - 1)。
|
||||
* Why: 以英雄自身基础值为基数,自动适配低/高费卡的成长占比,避免全局固定值失衡;
|
||||
* 线性曲线在无限升级下不会指数爆炸,强度平滑可控。
|
||||
* @param hero 英雄配置(取 hp/ap 基础值与 grow_type)
|
||||
* @param hero 英雄配置(取 hp/ap/def 基础值与 grow_type)
|
||||
* @param targetLv 目标等级(≥1)
|
||||
* @returns 累计 hp/ap 增量(已取整)
|
||||
* @returns 累计 hp/ap/def 增量(已取整)
|
||||
*/
|
||||
export function calcGrowBonus(hero: Pick<heroInfo, "hp" | "ap" | "grow_type">, targetLv: number): { hp: number; ap: number } {
|
||||
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),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -295,6 +328,7 @@ export interface heroInfo {
|
||||
skills: Record<number, HSkillInfo>; // 携带技能ID列表
|
||||
ap_bonus?: LvBonusEntry[]; // 额外攻击加成(按 lv 升序,运行时累加 ≤英雄等级 的所有档)
|
||||
hp_bonus?: LvBonusEntry[]; // 额外生命加成(按 lv 升序,运行时累加 ≤英雄等级 的所有档)
|
||||
def_bonus?: LvBonusEntry[]; // 额外防御加成(按 lv 升序,运行时累加 ≤英雄等级 的所有档)
|
||||
info: string; // 描述文案
|
||||
/**
|
||||
* @deprecated 已废弃:无任何 UI/运行时读取。技能提升说明由 HeroSkillText 依据
|
||||
@@ -422,8 +456,10 @@ export interface LvBonusEntry {
|
||||
*=============英雄配置列表================
|
||||
* 几何王国复刻版 — 依据 英雄设计指引.md(A/B 级复刻英雄)配置
|
||||
*
|
||||
* 规则:lv3 解锁 atking/atked 触发技能,lv2 解锁 fstart,lv6/12 大招走 lv_entries 分档成长,
|
||||
* lv9 card_lv 4/5 配 field 光环,card_lv 3 配 ap_bonus/hp_bonus 基础属性+50%
|
||||
* 规则:lv1 激活 skills[0]/skills[1],lv6 解锁 atking/atked/fstart 触发技能,
|
||||
* 大招(skills[1])lv9/lv16 走 lv_entries 分档成长,lv12 按职业对单项基础属性 +50%(基数取 lv11 有效值),
|
||||
* lv9 card_lv 4/5 配 field 光环,card_lv 3 配 ap_bonus/hp_bonus 基础属性+50%,
|
||||
* 品质(card_lv)相邻基础属性差 5%(仅 lv1 初始 AP/HP/DEF)
|
||||
* 编号:本批复刻英雄集中于 5001~5009,card_lv 按配置(不遵循段位规则)
|
||||
*/
|
||||
|
||||
@@ -443,14 +479,14 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
overrides: { ap: 250, bck: 30, para: 40, summon_count: 1 },
|
||||
desc: "释放能量波,对{target}造成攻击力{ap}%伤害,击退{bck},{para}%概率麻痹",
|
||||
lv_entries: [
|
||||
{ lv: 6, s_lv: SkillLv.Lv2, overrides: { ap: 250, bck: 60, para: 40, summon_count: 1 } },
|
||||
{ lv: 12, s_lv: SkillLv.Lv3, overrides: { ap: 300, bck: 90, timed_buff_id: 7005, para: 50, summon_count: 2 }, desc: "释放能量波,对{target}造成攻击力{ap}%伤害,击退{bck},{para}%概率麻痹,额外释放1次,并使目标中毒(每0.5秒受到{buff_value}点毒伤,持续{dur}秒)" },
|
||||
{ lv: 9, s_lv: SkillLv.Lv2, overrides: { ap: 250, bck: 60, para: 40, summon_count: 1 } },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: { ap: 300, bck: 90, timed_buff_id: 7005, para: 50, summon_count: 2 }, desc: "释放能量波,对{target}造成攻击力{ap}%伤害,击退{bck},{para}%概率麻痹,额外释放1次,并使目标中毒(每0.5秒受到{buff_value}点毒伤,持续{dur}秒)" },
|
||||
],
|
||||
},
|
||||
},
|
||||
atking: {
|
||||
6010: [
|
||||
{ lv: 3, s_lv: SkillLv.Lv1, name: "雷霆万钧", t_num: 3, overrides: { para: 100 }, desc: "释放紫魔球轰击{target},{para}%概率麻痹目标" },
|
||||
{ lv: 6, s_lv: SkillLv.Lv1, name: "雷霆万钧", t_num: 3, overrides: { para: 100 }, desc: "释放紫魔球轰击{target},{para}%概率麻痹目标" },
|
||||
],
|
||||
},
|
||||
field: [
|
||||
@@ -469,14 +505,14 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
overrides: { ap: 150 },
|
||||
desc: "斩出光闪,对{target}造成攻击力{ap}%伤害",
|
||||
lv_entries: [
|
||||
{ lv: 6, s_lv: SkillLv.Lv2, overrides: { ap: 150, timed_buff_id: 7007 }, desc: "斩出光闪,对{target}造成攻击力{ap}%伤害,并使目标出血(每0.5秒受到{buff_value}点伤害,持续{dur}秒)" },
|
||||
{ lv: 12, s_lv: SkillLv.Lv3, overrides: { ap: 180, hit_count: 8, num: 1 }, desc: "斩出光闪,对{target}连击{hit_count}次,每次造成攻击力{ap}%伤害,并双发{num}次" },
|
||||
{ lv: 9, s_lv: SkillLv.Lv2, overrides: { ap: 150, timed_buff_id: 7007 }, desc: "斩出光闪,对{target}造成攻击力{ap}%伤害,并使目标出血(每0.5秒受到{buff_value}点伤害,持续{dur}秒)" },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: { ap: 180, hit_count: 8, num: 1 }, desc: "斩出光闪,对{target}连击{hit_count}次,每次造成攻击力{ap}%伤害,并双发{num}次" },
|
||||
],
|
||||
},
|
||||
},
|
||||
atking: {
|
||||
6004: [
|
||||
{ lv: 3, s_lv: SkillLv.Lv1, name: "致命节奏", t_num: 3, overrides: { crt: 30 }, desc: "释放斩击,{crt}%概率造成暴击" },
|
||||
{ lv: 6, s_lv: SkillLv.Lv1, name: "致命节奏", t_num: 3, overrides: { crt: 30 }, desc: "释放斩击,{crt}%概率造成暴击" },
|
||||
],
|
||||
},
|
||||
field: [
|
||||
@@ -495,19 +531,19 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
overrides: { ap: 150, para: 40, summon_count: 1 },
|
||||
desc: "召唤落雷斩击{target},造成攻击力{ap}%伤害,{para}%概率麻痹",
|
||||
lv_entries: [
|
||||
{ lv: 6, s_lv: SkillLv.Lv2, overrides: { ap: 150, timed_buff_id: 7006, para: 40, summon_count: 1 }, desc: "召唤落雷斩击{target},造成攻击力{ap}%伤害,{para}%概率麻痹,并使目标攻击力{buff_value}%(持续{dur}秒)" },
|
||||
{ lv: 12, s_lv: SkillLv.Lv3, overrides: { ap: 180, timed_buff_id: 7006, buff_value: -15, para: 50, summon_count: 2 } },
|
||||
{ lv: 9, s_lv: SkillLv.Lv2, overrides: { ap: 150, timed_buff_id: 7006, para: 40, summon_count: 1 }, desc: "召唤落雷斩击{target},造成攻击力{ap}%伤害,{para}%概率麻痹,并使目标攻击力{buff_value}%(持续{dur}秒)" },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: { ap: 180, timed_buff_id: 7006, buff_value: -15, para: 50, summon_count: 2 } },
|
||||
],
|
||||
},
|
||||
},
|
||||
atked: {
|
||||
6301: [
|
||||
{ lv: 3, s_lv: SkillLv.Lv1, name: "罗生门", t_num: 4, overrides: { TGroup: TGroup.Self, ap: 2 }, desc: "{target}获得{ap}次格挡护盾" },
|
||||
{ lv: 6, s_lv: SkillLv.Lv1, name: "罗生门", t_num: 4, overrides: { TGroup: TGroup.Self, ap: 2 }, desc: "{target}获得{ap}次格挡护盾" },
|
||||
],
|
||||
},
|
||||
fstart: {
|
||||
6200: [
|
||||
{ lv: 2, s_lv: SkillLv.Lv1, name: "三十六烦恼凤", t_num: 1, overrides: { ap: 500 }, desc: "入场释放剑气,对{target}造成攻击力{ap}%伤害" },
|
||||
{ lv: 6, s_lv: SkillLv.Lv1, name: "三十六烦恼凤", t_num: 1, overrides: { ap: 500 }, desc: "入场释放剑气,对{target}造成攻击力{ap}%伤害" },
|
||||
],
|
||||
},
|
||||
field: [
|
||||
@@ -526,14 +562,14 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
overrides: { ap: 150, summon_count: 1 },
|
||||
desc: "释放能量波,对{target}造成攻击力{ap}%伤害",
|
||||
lv_entries: [
|
||||
{ lv: 6, s_lv: SkillLv.Lv2, overrides: { ap: 150, frz: 15, summon_count: 1 }, desc: "释放能量波,对{target}造成攻击力{ap}%伤害,{frz}%概率冰冻" },
|
||||
{ lv: 12, s_lv: SkillLv.Lv3, overrides: { ap: 180, frz: 30, hit_count: 8, summon_count: 2 }, desc: "释放能量波,对{target}造成攻击力{ap}%伤害,{frz}%概率冰冻,命中{hit_count}次" },
|
||||
{ lv: 9, s_lv: SkillLv.Lv2, overrides: { ap: 150, frz: 15, summon_count: 1 }, desc: "释放能量波,对{target}造成攻击力{ap}%伤害,{frz}%概率冰冻" },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: { ap: 180, frz: 30, hit_count: 8, summon_count: 2 }, desc: "释放能量波,对{target}造成攻击力{ap}%伤害,{frz}%概率冰冻,命中{hit_count}次" },
|
||||
],
|
||||
},
|
||||
},
|
||||
atking: {
|
||||
6009: [
|
||||
{ lv: 3, s_lv: SkillLv.Lv1, name: "霜寒之触", t_num: 3, overrides: { timed_buff_id: 7003 }, desc: "释放寒气,冰冻{target}{dur}秒" },
|
||||
{ lv: 6, s_lv: SkillLv.Lv1, name: "霜寒之触", t_num: 3, overrides: { timed_buff_id: 7003 }, desc: "释放寒气,冰冻{target}{dur}秒" },
|
||||
],
|
||||
},
|
||||
field: [
|
||||
@@ -552,19 +588,19 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
overrides: { TGroup: TGroup.Self, ap: 3, summon_count: 1 },
|
||||
desc: "{target}获得{ap}次格挡护盾",
|
||||
lv_entries: [
|
||||
{ lv: 6, s_lv: SkillLv.Lv2, overrides: { TGroup: TGroup.Self, ap: 5, summon_count: 1 } },
|
||||
{ lv: 12, s_lv: SkillLv.Lv3, overrides: { TGroup: TGroup.Self, ap: 6, summon_count: 2 } },
|
||||
{ lv: 9, s_lv: SkillLv.Lv2, overrides: { TGroup: TGroup.Self, ap: 5, summon_count: 1 } },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: { TGroup: TGroup.Self, ap: 6, summon_count: 2 } },
|
||||
],
|
||||
},
|
||||
},
|
||||
atked: {
|
||||
6004: [
|
||||
{ lv: 3, s_lv: SkillLv.Lv1, name: "反击减攻", t_num: 4, overrides: { timed_buff_id: 7006 }, desc: "反击使攻击者攻击力{buff_value}%,持续{dur}秒" },
|
||||
{ lv: 6, s_lv: SkillLv.Lv1, name: "反击减攻", t_num: 4, overrides: { timed_buff_id: 7006 }, desc: "反击使攻击者攻击力{buff_value}%,持续{dur}秒" },
|
||||
],
|
||||
},
|
||||
fstart: {
|
||||
6412: [
|
||||
{ lv: 2, s_lv: SkillLv.Lv1, name: "铁壁壁垒", t_num: 1, overrides: { TGroup: TGroup.Team, ap: 50 }, desc: "{target}防御提升{ap}点" },
|
||||
{ lv: 6, s_lv: SkillLv.Lv1, name: "铁壁壁垒", t_num: 1, overrides: { TGroup: TGroup.Team, ap: 50 }, desc: "{target}防御提升{ap}点" },
|
||||
],
|
||||
},
|
||||
dead: {
|
||||
@@ -592,19 +628,19 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
overrides: { TGroup: TGroup.Team, ap: 300, summon_count: 1 },
|
||||
desc: "为{target}回复攻击力{ap}%生命",
|
||||
lv_entries: [
|
||||
{ lv: 6, s_lv: SkillLv.Lv2, overrides: { TGroup: TGroup.Team, ap: 400, summon_count: 1 } },
|
||||
{ lv: 12, s_lv: SkillLv.Lv3, overrides: { TGroup: TGroup.Team, ap: 450, summon_count: 2 } },
|
||||
{ lv: 9, s_lv: SkillLv.Lv2, overrides: { TGroup: TGroup.Team, ap: 400, summon_count: 1 } },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: { TGroup: TGroup.Team, ap: 450, summon_count: 2 } },
|
||||
],
|
||||
},
|
||||
},
|
||||
atking: {
|
||||
6302: [
|
||||
{ lv: 3, s_lv: SkillLv.Lv1, name: "圣洁之锤", t_num: 3, overrides: { TGroup: TGroup.Self, ap: 100 }, desc: "释放圣光,为{target}回复攻击力{ap}%生命" },
|
||||
{ lv: 6, s_lv: SkillLv.Lv1, name: "圣洁之锤", t_num: 3, overrides: { TGroup: TGroup.Self, ap: 100 }, desc: "释放圣光,为{target}回复攻击力{ap}%生命" },
|
||||
],
|
||||
},
|
||||
fstart: {
|
||||
6412: [
|
||||
{ lv: 2, s_lv: SkillLv.Lv1, name: "圣光庇佑", t_num: 1, overrides: { TGroup: TGroup.Team, ap: 30 }, desc: "{target}防御提升{ap}点" },
|
||||
{ lv: 6, s_lv: SkillLv.Lv1, name: "圣光庇佑", t_num: 1, overrides: { TGroup: TGroup.Team, ap: 30 }, desc: "{target}防御提升{ap}点" },
|
||||
],
|
||||
},
|
||||
field: [
|
||||
@@ -623,14 +659,14 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
overrides: { ap: 150, summon_count: 1 },
|
||||
desc: "斩出气刃,对{target}造成攻击力{ap}%伤害",
|
||||
lv_entries: [
|
||||
{ lv: 6, s_lv: SkillLv.Lv2, overrides: { ap: 150, timed_buff_id: 7002, summon_count: 1 }, desc: "斩出气刃,对{target}造成攻击力{ap}%伤害,并使目标易伤(受到伤害加深,持续{dur}秒)" },
|
||||
{ lv: 12, s_lv: SkillLv.Lv3, overrides: { ap: 180, bck: 60, timed_buff_id: 7002, buff_value: 20, summon_count: 2 }, desc: "斩出气刃,对{target}造成攻击力{ap}%伤害,击退{bck},并使目标易伤(持续{dur}秒)" },
|
||||
{ lv: 9, s_lv: SkillLv.Lv2, overrides: { ap: 150, timed_buff_id: 7002, summon_count: 1 }, desc: "斩出气刃,对{target}造成攻击力{ap}%伤害,并使目标易伤(受到伤害加深,持续{dur}秒)" },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: { ap: 180, bck: 60, timed_buff_id: 7002, buff_value: 20, summon_count: 2 }, desc: "斩出气刃,对{target}造成攻击力{ap}%伤害,击退{bck},并使目标易伤(持续{dur}秒)" },
|
||||
],
|
||||
},
|
||||
},
|
||||
atking: {
|
||||
6004: [
|
||||
{ lv: 3, s_lv: SkillLv.Lv1, name: "雷霆一击", t_num: 3, overrides: { bck: 40 }, desc: "重击{target},击退{bck}" },
|
||||
{ lv: 6, s_lv: SkillLv.Lv1, name: "雷霆一击", t_num: 3, overrides: { bck: 40 }, desc: "重击{target},击退{bck}" },
|
||||
],
|
||||
},
|
||||
// card_lv 3:lv9 无光环,改为基础属性+50%
|
||||
@@ -649,14 +685,14 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
overrides: { ap: 300, summon_count: 1 },
|
||||
desc: "劈出开山斧,对{target}造成攻击力{ap}%伤害",
|
||||
lv_entries: [
|
||||
{ lv: 6, s_lv: SkillLv.Lv2, overrides: { ap: 300, stun: 20, summon_count: 1 }, desc: "劈出开山斧,对{target}造成攻击力{ap}%伤害,{stun}%概率击晕" },
|
||||
{ lv: 12, s_lv: SkillLv.Lv3, overrides: { ap: 350, stun: 35, hit_count: 8, summon_count: 2 }, desc: "劈出开山斧,对{target}造成攻击力{ap}%伤害,{stun}%概率击晕,命中{hit_count}次" },
|
||||
{ lv: 9, s_lv: SkillLv.Lv2, overrides: { ap: 300, stun: 20, summon_count: 1 }, desc: "劈出开山斧,对{target}造成攻击力{ap}%伤害,{stun}%概率击晕" },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: { ap: 350, stun: 35, hit_count: 8, summon_count: 2 }, desc: "劈出开山斧,对{target}造成攻击力{ap}%伤害,{stun}%概率击晕,命中{hit_count}次" },
|
||||
],
|
||||
},
|
||||
},
|
||||
atking: {
|
||||
6004: [
|
||||
{ lv: 3, s_lv: SkillLv.Lv1, name: "火眼金睛", t_num: 3, overrides: { crt: 25 }, desc: "释放斩击,{crt}%概率造成暴击" },
|
||||
{ lv: 6, s_lv: SkillLv.Lv1, name: "火眼金睛", t_num: 3, overrides: { crt: 25 }, desc: "释放斩击,{crt}%概率造成暴击" },
|
||||
],
|
||||
},
|
||||
field: [
|
||||
@@ -675,20 +711,20 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
overrides: { ap: 150, summon_count: 1 },
|
||||
desc: "斩出气刃,对{target}造成攻击力{ap}%伤害",
|
||||
lv_entries: [
|
||||
{ lv: 6, s_lv: SkillLv.Lv2, overrides: { ap: 180, summon_count: 1 } },
|
||||
{ lv: 12, s_lv: SkillLv.Lv3, overrides: { ap: 200, summon_count: 2 } },
|
||||
{ lv: 9, s_lv: SkillLv.Lv2, overrides: { ap: 180, summon_count: 1 } },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: { ap: 200, summon_count: 2 } },
|
||||
],
|
||||
},
|
||||
},
|
||||
atking: {
|
||||
6302: [
|
||||
{ lv: 3, s_lv: SkillLv.Lv1, name: "嗜血战斧", t_num: 4, overrides: { TGroup: TGroup.Self, ap: 120 }, desc: "释放嗜血斩击,为{target}回复攻击力{ap}%生命" },
|
||||
{ lv: 6, s_lv: SkillLv.Lv1, name: "嗜血战斧", t_num: 4, overrides: { TGroup: TGroup.Self, ap: 120 }, desc: "释放嗜血斩击,为{target}回复攻击力{ap}%生命" },
|
||||
],
|
||||
},
|
||||
atked: {
|
||||
// 坚硬皮肤:借 6513 防御爆发底座注入 7023 防御强化(+50%,可无限叠层)
|
||||
6513: [
|
||||
{ lv: 3, s_lv: SkillLv.Lv1, name: "坚硬皮肤", t_num: 2, overrides: { TGroup: TGroup.Self, timed_buff_id: 7023, buff_duration: 10 }, desc: "{target}防御提升{buff_value}%,持续{dur}秒" },
|
||||
{ lv: 6, s_lv: SkillLv.Lv1, name: "坚硬皮肤", t_num: 2, overrides: { TGroup: TGroup.Self, timed_buff_id: 7023, buff_duration: 10 }, desc: "{target}防御提升{buff_value}%,持续{dur}秒" },
|
||||
],
|
||||
},
|
||||
// card_lv 3:lv9 无光环,改为基础属性+50%
|
||||
@@ -964,13 +1000,14 @@ export function resolveReviveByLv(revive: LvReviveEntry[] | undefined, lv: numbe
|
||||
return pick ? { s_uuid: pick.s_uuid, r_num: pick.r_num, upr: pick.upr } : undefined;
|
||||
}
|
||||
|
||||
/** 计算目标等级下额外属性加成(hp_bonus/ap_bonus 一次性奖励 + 成长类型每级递增) */
|
||||
function getEvolveBonuses(hero: heroInfo, targetLv: number): { hp: number, ap: number } {
|
||||
/** 计算目标等级下额外属性加成(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 };
|
||||
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;
|
||||
@@ -981,15 +1018,57 @@ function getEvolveBonuses(hero: heroInfo, targetLv: number): { hp: number, ap: n
|
||||
if (e.lv <= lv) ap += e.value;
|
||||
}
|
||||
}
|
||||
return { hp, ap };
|
||||
if (hero.def_bonus) {
|
||||
for (const e of hero.def_bonus) {
|
||||
if (e.lv <= lv) def += e.value;
|
||||
}
|
||||
}
|
||||
return { hp, ap, def };
|
||||
}
|
||||
|
||||
/** 计算目标等级下的有效 HP/AP(固定基础值 + 成长递增与一次性加成) */
|
||||
function getEffectiveStats(hero: heroInfo, targetLv: number): { hp: number, ap: number } {
|
||||
/** 计算目标等级下的有效 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.card_lv ?? 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.card_lv ?? 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),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,8 @@ revive[0]:无
|
||||
|
||||
**通用约束**:
|
||||
|
||||
- lv2 走 atking/atked/fstart 提升普攻能力;lv3/5/7 走 `skills[1].lv_entries` 提升大招;lv9 光环或属性补偿
|
||||
- 等级节奏:lv1 激活 skills[0]/skills[1];lv6 解锁 atking/atked/fstart 触发技能(1 个);大招(skills[1])lv9/lv16 走 `lv_entries` 分档提升;lv12 按职业对单项基础属性 +50%(基数取 lv11 当前等级有效值:坦克→def、战士/辅助→hp、刺客/射手/法师→ap);lv9 光环或属性补偿
|
||||
- 品质差异:相邻品质(card_lv)lv1 初始基础属性(AP/HP/DEF)相差 5%(系数 1+0.05×(card_lv-1)),其余配置参数完全一致
|
||||
- 能力只能从能力池(BuffList 7001\~7024 / FieldSkillSet 7001\~7020 / SkillSet 底座)引用 + `overrides` 数值覆盖,**禁止新增同义底座**
|
||||
|
||||
**大招召唤数约束**(`summon_count` 覆写规则):
|
||||
@@ -303,11 +304,13 @@ revive[0]:无
|
||||
## 配置检查清单
|
||||
|
||||
- [ ] `skills` 引用的 uuid 在 SkillSet 中存在,`overrides.ap` 显式写出
|
||||
- [ ] 大招(`skills[1]`)覆写 `summon_count`:lv1=1、lv3=1、lv5=2、lv7=3,通过 `lv_entries` 逐级覆写,不改动 SkillSet 底座
|
||||
- [ ] 大招(`skills[1]`)覆写 `summon_count`:lv1=1、lv9=1、lv16=2,通过 `lv_entries` 逐级覆写,不改动 SkillSet 底座
|
||||
- [ ] `timed_buff_id` 指向 BuffList 已存在条目(能力池 2.1/2.2 内)
|
||||
- [ ] debuff/buff 只通过 `overrides` 注入,未改动 SkillSet/BuffList 底座
|
||||
- [ ] `atking`/`atked`/`fstart`/`dead` 按 s\_uuid 分组、按 lv 升序
|
||||
- [ ] `atking`/`atked`/`fstart`/`dead` 按 s\_uuid 分组、按 lv 升序,触发技能统一 lv6 解锁
|
||||
- [ ] lv9:card\_lv 4/5 配 `field`;card\_lv 1/2/3 配 `ap_bonus`/`hp_bonus`(30/40/50%)
|
||||
- [ ] lv12:按职业注入单项属性 +50%(坦克 def、战士/辅助 hp、刺客/射手/法师 ap),基数取 lv11 有效值
|
||||
- [ ] 品质:card\_lv 相邻基础属性差 5%(运行时品质系数统一乘,配置保持裸值)
|
||||
- [ ] `t_num` 概率模拟符合预期(1=每次,3≈33%,4≈25%)
|
||||
- [ ] `infos` 分级说明与配置档位一一对应(面板逐条展示)
|
||||
- [ ] 近战/远程形态与 `type`/`dis` 匹配,美术资源 `path`/`icon` 就绪
|
||||
|
||||
@@ -5,7 +5,7 @@ import { smc } from "../common/SingletonModuleComp";
|
||||
import { HeroAttrsComp } from "./HeroAttrsComp";
|
||||
import { HeroViewComp } from "./HeroViewComp";
|
||||
import { BoxSet, FacSet, FightSet, IndexSet } from "../common/config/GameSet";
|
||||
import { HeroInfo, resolveFormationTargetX, resolveTriggerByLv, resolveFieldByLv, resolveReviveByLv, resolveSkillOverrides, calcGrowBonus, HeroDisVal } from "../common/config/heroSet";
|
||||
import { HeroInfo, resolveFormationTargetX, resolveTriggerByLv, resolveFieldByLv, resolveReviveByLv, resolveSkillOverrides, calcGrowBonus, HeroDisVal, getHeroQualityCoef, getEffectiveStats, HERO_LV12_SPECIAL_LV, HERO_LV12_BASE_LV, HERO_LV12_SPECIAL_ATTR } from "../common/config/heroSet";
|
||||
import { GameEvent } from "../common/config/GameEvent";
|
||||
import { SkillTriggerType, HType } from "../common/config/heroSet";
|
||||
import { SkillTriggerHelper } from "./SkillTriggerHelper";
|
||||
@@ -140,15 +140,18 @@ export class Hero extends ecs.Entity {
|
||||
model.revive = hero.revive;
|
||||
model.ap_bonus = hero.ap_bonus;
|
||||
model.hp_bonus = hero.hp_bonus;
|
||||
model.def_bonus = hero.def_bonus;
|
||||
|
||||
// 基础属性:固定基础值,成长完全由 grow_type 指数递增提供(替代旧 ×2^(lv-1) 翻倍)
|
||||
// 基础属性:固定基础值 × 品质系数(相邻品质差 5%),成长由 grow_type 线性递增提供
|
||||
// TODO: 局外升级机制落地后,此处基础值将与存档强化累加重算
|
||||
let base_ap = hero.ap;
|
||||
let base_hp = hero.hp;
|
||||
const qualityCoef = getHeroQualityCoef(hero.card_lv ?? 1);
|
||||
let base_ap = Math.round(hero.ap * qualityCoef);
|
||||
let base_hp = Math.round(hero.hp * qualityCoef);
|
||||
let base_def = Math.round(hero.def * qualityCoef);
|
||||
|
||||
model.base_ap = base_ap;
|
||||
model.base_hp = base_hp;
|
||||
model.defense = hero.def;
|
||||
model.defense = base_def;
|
||||
|
||||
// 英雄享受驻场百分比加成,怪物保持基础值
|
||||
if (model.fac === FacSet.HERO) {
|
||||
@@ -179,11 +182,12 @@ export class Hero extends ecs.Entity {
|
||||
model.runtime_field = resolveFieldByLv(model.field, hero_lv);
|
||||
model.runtime_revive = resolveReviveByLv(model.revive, hero_lv);
|
||||
|
||||
// 应用额外属性加成(成长类型每级递增 + hp_bonus/ap_bonus 一次性奖励累加)
|
||||
// 应用额外属性加成(成长类型每级递增 + hp/ap/def_bonus 一次性奖励累加)
|
||||
// 成长增量:仅英雄生效(model.fac 已为 HERO),按 grow_type 递增曲线累计
|
||||
const grow = calcGrowBonus(hero, hero_lv);
|
||||
model.hp += grow.hp; model.hp_max += grow.hp;
|
||||
model.ap += grow.ap;
|
||||
model.defense += grow.def;
|
||||
if (model.hp_bonus) {
|
||||
let hpExtra = 0;
|
||||
for (const e of model.hp_bonus) { if (e.lv <= hero_lv) hpExtra += e.value; }
|
||||
@@ -194,6 +198,21 @@ export class Hero extends ecs.Entity {
|
||||
for (const e of model.ap_bonus) { if (e.lv <= hero_lv) apExtra += e.value; }
|
||||
model.ap += apExtra;
|
||||
}
|
||||
if (model.def_bonus) {
|
||||
let defExtra = 0;
|
||||
for (const e of model.def_bonus) { if (e.lv <= hero_lv) defExtra += e.value; }
|
||||
model.defense += defExtra;
|
||||
}
|
||||
|
||||
// lv12 职业属性专项:达到 12 级时按职业对单项基础属性 +50%
|
||||
// 基数为 lv11 当前等级有效值(基础 + 成长 + lv9 bonus,不含 lv12 自身),仅英雄生效
|
||||
if (model.fac === FacSet.HERO && hero_lv >= HERO_LV12_SPECIAL_LV && model.role !== undefined) {
|
||||
const lv11 = getEffectiveStats(hero, HERO_LV12_BASE_LV);
|
||||
const attr = HERO_LV12_SPECIAL_ATTR[model.role];
|
||||
if (attr === "def") model.defense += Math.round(lv11.def * 0.5);
|
||||
else if (attr === "hp") { const add = Math.round(lv11.hp * 0.5); model.hp += add; model.hp_max += add; }
|
||||
else if (attr === "ap") model.ap += Math.round(lv11.ap * 0.5);
|
||||
}
|
||||
|
||||
// 天赋加成层:全局天赋(一阶基础/三阶超强全局)全局生效,职业天赋(二阶专精/三阶超强职业)按 role 过滤(仅英雄生效,怪物跳过)
|
||||
// Why: 放在成长/bonus 之后、光环乘区之后,以基础快照为基数叠加,避免与乘区叠加成乘法膨胀
|
||||
|
||||
@@ -54,9 +54,10 @@ export class HeroAttrsComp extends ecs.Comp {
|
||||
/** 驻场光环(按 lv 解锁,存活期间全局生效) */
|
||||
[SkillTriggerType.Field]?: LvFieldEntry[];
|
||||
[SkillTriggerType.Revive]?: LvReviveEntry[];
|
||||
/** 额外攻击/生命加成(按 lv 累加) */
|
||||
/** 额外攻击/生命/防御加成(按 lv 累加) */
|
||||
ap_bonus?: LvBonusEntry[];
|
||||
hp_bonus?: LvBonusEntry[];
|
||||
def_bonus?: LvBonusEntry[];
|
||||
|
||||
// ==================== 运行时解析缓存(按当前等级 resolve 后的有效列表) ====================
|
||||
/** 当前等级下生效的攻击触发条目(供 SkillTriggerHelper 消费) */
|
||||
@@ -633,6 +634,7 @@ export class HeroAttrsComp extends ecs.Comp {
|
||||
this.revive = undefined;
|
||||
this.ap_bonus = undefined;
|
||||
this.hp_bonus = undefined;
|
||||
this.def_bonus = undefined;
|
||||
this.runtime_atking = undefined;
|
||||
this.runtime_atked = undefined;
|
||||
this.runtime_call = undefined;
|
||||
|
||||
@@ -54,7 +54,7 @@ import { MissSkillsComp } from "./MissSkillsComp";
|
||||
import { oops } from "db://oops-framework/core/Oops";
|
||||
import { HeroAttrsComp } from "../hero/HeroAttrsComp";
|
||||
import { smc } from "../common/SingletonModuleComp";
|
||||
import { HeroInfo, HType, resolveTriggerByLv, resolveFieldByLv, resolveReviveByLv, resolveSkillOverrides, calcGrowBonus } from "../common/config/heroSet";
|
||||
import { HeroInfo, HType, resolveTriggerByLv, resolveFieldByLv, resolveReviveByLv, resolveSkillOverrides, calcGrowBonus, getHeroQualityCoef, getEffectiveStats, HERO_LV12_SPECIAL_LV, HERO_LV12_BASE_LV, HERO_LV12_SPECIAL_ATTR } from "../common/config/heroSet";
|
||||
import { applyTalentBonuses } from "../common/config/TalentSet";
|
||||
import { HeroViewComp } from "../hero/HeroViewComp";
|
||||
import { FacSet, FightSet } from "../common/config/GameSet";
|
||||
@@ -2151,9 +2151,10 @@ export class MissionCardComp extends CCComp {
|
||||
const hpRate = model.hp_max > 0 ? model.hp / model.hp_max : 1;
|
||||
model.lv = nextLv;
|
||||
|
||||
// 同步 base 快照(与 Hero.load 同公式:固定基础值,成长由 grow_type 指数递增提供)
|
||||
const base_ap = hero.ap;
|
||||
const base_hp = hero.hp;
|
||||
// 同步 base 快照(与 Hero.load 同公式:固定基础值 × 品质系数,成长由 grow_type 线性递增提供)
|
||||
const qualityCoef = getHeroQualityCoef(hero.card_lv ?? 1);
|
||||
const base_ap = Math.round(hero.ap * qualityCoef);
|
||||
const base_hp = Math.round(hero.hp * qualityCoef);
|
||||
model.base_ap = base_ap;
|
||||
model.base_hp = base_hp;
|
||||
|
||||
@@ -2166,7 +2167,7 @@ export class MissionCardComp extends CCComp {
|
||||
model.hp_max = base_hp;
|
||||
}
|
||||
|
||||
// 按 ≤nextLv 累加:成长类型每级递增 + hp_bonus/ap_bonus 一次性奖励(沿用 Hero.load 的加法区规则)
|
||||
// 按 ≤nextLv 累加:成长类型每级递增 + hp/ap/def_bonus 一次性奖励(沿用 Hero.load 的加法区规则)
|
||||
const grow = calcGrowBonus(hero, nextLv);
|
||||
model.hp_max += grow.hp;
|
||||
model.ap += grow.ap;
|
||||
@@ -2184,7 +2185,20 @@ export class MissionCardComp extends CCComp {
|
||||
// 天赋加成层(与 Hero.load 对齐):先重置天赋可能修改的字段,避免升级重算时重复叠加
|
||||
// Why: ap/hp_max 已由上方公式从 base 重算(天然幂等),但 defense 与概率类字段是累加语义,必须先归零再注入
|
||||
if (model.fac === FacSet.HERO) {
|
||||
model.defense = hero.def;
|
||||
// defense 从品质系数后的基础值重算,叠加 def 成长 + def_bonus + lv12 专项,幂等
|
||||
let base_def = Math.round(hero.def * qualityCoef) + grow.def;
|
||||
if (model.def_bonus) {
|
||||
for (const e of model.def_bonus) { if (e.lv <= nextLv) base_def += e.value; }
|
||||
}
|
||||
// lv12 职业属性专项:达到 12 级时按职业对单项基础属性 +50%(基数为 lv11 有效值)
|
||||
if (nextLv >= HERO_LV12_SPECIAL_LV && model.role !== undefined) {
|
||||
const lv11 = getEffectiveStats(hero, HERO_LV12_BASE_LV);
|
||||
const attr = HERO_LV12_SPECIAL_ATTR[model.role];
|
||||
if (attr === "def") base_def += Math.round(lv11.def * 0.5);
|
||||
else if (attr === "hp") model.hp_max += Math.round(lv11.hp * 0.5);
|
||||
else if (attr === "ap") model.ap += Math.round(lv11.ap * 0.5);
|
||||
}
|
||||
model.defense = base_def;
|
||||
model.critical = 0;
|
||||
model.critical_damage = 0;
|
||||
model.stun_chance = 0;
|
||||
|
||||
Reference in New Issue
Block a user