feat(hero/skill): add skill level override resolution logic
1. 新增resolveSkillOverrides工具函数实现技能等级分档覆盖逻辑 2. 为所有英雄/怪物技能模块添加运行时overrides分档处理 3. 扩展技能描述系统以展示分档后的技能等级 4. 新增技能分档配置类型定义与注释
This commit is contained in:
@@ -28,7 +28,7 @@
|
||||
* - SkillDescSet:结构化描述模板
|
||||
* - FieldSkillSet(驻场技能)、BuffList(计时 buff 默认值兜底)、Attrs(属性枚举)
|
||||
*/
|
||||
import { SkillTriggerName, SkillTriggerType, TriggerGrouped, LvTriggerEntry, LvFieldEntry, LvReviveEntry, LvBonusEntry, FieldEntry, resolveTriggerByLv, resolveFieldByLv, resolveReviveByLv, getTriggerSkillName, HGrowType, calcGrowBonus } from "./heroSet";
|
||||
import { SkillTriggerName, SkillTriggerType, TriggerGrouped, LvTriggerEntry, LvFieldEntry, LvReviveEntry, LvBonusEntry, FieldEntry, resolveTriggerByLv, resolveFieldByLv, resolveReviveByLv, resolveSkillOverrides, getTriggerSkillName, HGrowType, calcGrowBonus, HSkillInfo } from "./heroSet";
|
||||
import { FieldSkillSet, mergeSkillParams, SkillConfig, SkillKind, SkillOverrides, SkillSet, TGroup } from "./SkillSet";
|
||||
import { FieldDescSet, FieldValueFmt, SkillDescSet } from "./SkillDescSet";
|
||||
import { BuffList } from "./BuffSet";
|
||||
@@ -42,6 +42,8 @@ import { CardConfig } from "./CardSet";
|
||||
export interface ISkillDescSource {
|
||||
/** 当前等级(用于 resolve 触发技能/光环/复活取档;静态 heroInfo 恒为 1) */
|
||||
lv?: number;
|
||||
/** 携带技能(普攻技能,支持 lv_entries 按等级分档 resolve) */
|
||||
skills?: Record<number, HSkillInfo>;
|
||||
call?: TriggerGrouped;
|
||||
dead?: TriggerGrouped;
|
||||
fstart?: TriggerGrouped;
|
||||
@@ -368,6 +370,24 @@ function buildSkillLines(source: ISkillDescSource, showName: boolean = true, sho
|
||||
const lines: ISkillLine[] = [];
|
||||
const lv = Math.max(1, source.lv ?? 1);
|
||||
|
||||
// ---- 普攻技能(skills):按英雄等级 resolve 分档 overrides ----
|
||||
if (source.skills) {
|
||||
for (const key in source.skills) {
|
||||
const hSkill = source.skills[key];
|
||||
if (!hSkill) continue;
|
||||
const base = SkillSet[hSkill.uuid];
|
||||
if (!base) continue;
|
||||
const overrides = resolveSkillOverrides(hSkill, lv);
|
||||
const skill = mergeSkillParams(base, overrides);
|
||||
// 技能等级展示:lv_entries 有档时取档位 s_lv,否则用运行时 lv
|
||||
const sLv = hSkill.lv_entries?.length
|
||||
? (hSkill.lv_entries.filter(e => e.lv <= lv).pop()?.s_lv ?? hSkill.lv)
|
||||
: hSkill.lv;
|
||||
const nameSeg = showName ? `「${base.name}」 ` : "";
|
||||
lines.push(buildEffectLine(`Lv${sLv}: ${nameSeg}`, skill));
|
||||
}
|
||||
}
|
||||
|
||||
// ---- 6 种标准触发技能 ----
|
||||
for (const key of TRIGGER_KEYS) {
|
||||
const grouped = source[key] as TriggerGrouped | undefined;
|
||||
@@ -569,6 +589,24 @@ export function buildSkillDescMoreRich(source: ISkillDescSource, showName: boole
|
||||
return highlightDuration(text);
|
||||
};
|
||||
|
||||
// ---- 普攻技能(skills):按英雄等级 resolve 分档 overrides,展示当前生效档 ----
|
||||
if (source.skills) {
|
||||
for (const key in source.skills) {
|
||||
const hSkill = source.skills[key];
|
||||
if (!hSkill) continue;
|
||||
const base = SkillSet[hSkill.uuid];
|
||||
if (!base) continue;
|
||||
const overrides = resolveSkillOverrides(hSkill, lv);
|
||||
const skill = mergeSkillParams(base, overrides);
|
||||
// 技能等级展示:lv_entries 有档时取档位 s_lv,否则用运行时 lv
|
||||
const sLv = hSkill.lv_entries?.length
|
||||
? (hSkill.lv_entries.filter(e => e.lv <= lv).pop()?.s_lv ?? hSkill.lv)
|
||||
: hSkill.lv;
|
||||
const head = showName ? `「${base.name}」 Lv.${sLv}: ` : `Lv.${sLv}: `;
|
||||
lines.push(effectRich(buildEffectLine(head, skill)));
|
||||
}
|
||||
}
|
||||
|
||||
for (const key of TRIGGER_KEYS) {
|
||||
const grouped = source[key] as TriggerGrouped | undefined;
|
||||
if (!grouped) continue;
|
||||
|
||||
@@ -316,7 +316,18 @@ export interface HSkillInfo {
|
||||
lv: number; // 技能等级
|
||||
cd: number; // 技能cd
|
||||
ccd: number; // 占位当前cd,用于cd计时
|
||||
overrides?: SkillOverrides; // 角色专属参数覆盖
|
||||
overrides?: SkillOverrides; // 角色专属参数覆盖(全等级生效,作为底)
|
||||
lv_entries?: LvSkillEntry[]; // 按英雄等级分档(按 lv 升序,运行时取 ≤英雄等级 的最大档)
|
||||
}
|
||||
|
||||
/**
|
||||
* 普攻技能分档配置:达到 lv 级英雄时此档 overrides 生效(与基础 overrides 浅合并,档位优先)。
|
||||
* s_lv 标注此档对应的技能等级(SkillLv 枚举),便于面板显示"技能Lv.x"。
|
||||
*/
|
||||
export interface LvSkillEntry {
|
||||
lv: number; // 达到该英雄等级时此档生效
|
||||
s_lv?: SkillLv; // 此档对应的技能等级(标注用)
|
||||
overrides: SkillOverrides; // 此档注入的效果
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -974,6 +985,21 @@ export function resolveTriggerByLv(grouped: TriggerGrouped | undefined, lv: numb
|
||||
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 [];
|
||||
|
||||
@@ -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, calcGrowBonus, HeroDisVal } from "../common/config/heroSet";
|
||||
import { HeroInfo, resolveFormationTargetX, resolveTriggerByLv, resolveFieldByLv, resolveReviveByLv, resolveSkillOverrides, calcGrowBonus, HeroDisVal } from "../common/config/heroSet";
|
||||
import { GameEvent } from "../common/config/GameEvent";
|
||||
import { SkillTriggerType, HType } from "../common/config/heroSet";
|
||||
import { SkillTriggerHelper } from "./SkillTriggerHelper";
|
||||
@@ -158,13 +158,13 @@ export class Hero extends ecs.Entity {
|
||||
|
||||
model.speed = hero.speed ?? 200;
|
||||
|
||||
// 构建技能表并注入运行时冷却字段 ccd
|
||||
// 构建技能表并注入运行时冷却字段 ccd;overrides 按英雄等级 resolve 分档(下游无感知)
|
||||
model.skills = {};
|
||||
for (const key in hero.skills) {
|
||||
const skill = hero.skills[key];
|
||||
if (!skill) continue;
|
||||
// 最终技能等级 = 初始技能等级 + 英雄等级增量,下限 0、上限封顶(无限升级下技能不涨过上限)
|
||||
model.skills[skill.uuid] = { ...skill, lv: Math.min(FightSet.HERO_SKILL_MAX_LV, Math.max(0, skill.lv + hero_lv - 2)), ccd: 0 };
|
||||
model.skills[skill.uuid] = { ...skill, lv: Math.min(FightSet.HERO_SKILL_MAX_LV, Math.max(0, skill.lv + hero_lv - 2)), ccd: 0, overrides: resolveSkillOverrides(skill, hero_lv) };
|
||||
}
|
||||
|
||||
// 按当前英雄等级 resolve 触发技能/光环/复活到运行时缓存,供 SkillTriggerHelper 消费
|
||||
|
||||
@@ -3,7 +3,7 @@ import { oops } from "../../../../extensions/oops-plugin-framework/assets/core/O
|
||||
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
|
||||
import { smc } from "../common/SingletonModuleComp";
|
||||
import { BoxSet, FacSet, FightSet, IndexSet } from "../common/config/GameSet";
|
||||
import { HeroInfo, resolveTriggerByLv, resolveReviveByLv, HeroDisVal } from "../common/config/heroSet";
|
||||
import { HeroInfo, resolveTriggerByLv, resolveReviveByLv, resolveSkillOverrides, HeroDisVal } from "../common/config/heroSet";
|
||||
import { HeroAttrsComp } from "./HeroAttrsComp";
|
||||
import { HeroViewComp } from "./HeroViewComp";
|
||||
import { MoveComp } from "./MoveComp";
|
||||
@@ -201,8 +201,8 @@ export class Monster extends ecs.Entity {
|
||||
for (const key in hero.skills) {
|
||||
const skill = hero.skills[key];
|
||||
if (!skill) continue;
|
||||
// 最终技能等级 = 初始技能等级 + 怪物等级增量,且下限为 0
|
||||
model.skills[skill.uuid] = { ...skill, lv: Math.max(0, skill.lv + mon_lv - 2), ccd: 0 };
|
||||
// 最终技能等级 = 初始技能等级 + 怪物等级增量,且下限为 0;overrides 按怪物等级 resolve 分档
|
||||
model.skills[skill.uuid] = { ...skill, lv: Math.max(0, skill.lv + mon_lv - 2), ccd: 0, overrides: resolveSkillOverrides(skill, mon_lv) };
|
||||
}
|
||||
// 【测试模式专属】如果有覆盖技能配置则应用
|
||||
const testSkills = (this as any)._testSkills;
|
||||
|
||||
@@ -475,6 +475,7 @@ export class CHeroComp extends CCComp {
|
||||
private buildHeroDescSource(hero: typeof HeroInfo[number]): ISkillDescSource {
|
||||
return {
|
||||
lv: 5,
|
||||
skills: hero.skills,
|
||||
call: hero.call,
|
||||
dead: hero.dead,
|
||||
fstart: hero.fstart,
|
||||
|
||||
@@ -214,6 +214,7 @@ export class HeroBoxComp extends CCComp {
|
||||
|
||||
const buildSource = (lv: number): ISkillDescSource => ({
|
||||
lv: lv,
|
||||
skills: hero.skills,
|
||||
call: hero.call,
|
||||
dead: hero.dead,
|
||||
fstart: hero.fstart,
|
||||
|
||||
@@ -52,7 +52,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, calcGrowBonus } from "../common/config/heroSet";
|
||||
import { HeroInfo, HType, resolveTriggerByLv, resolveFieldByLv, resolveReviveByLv, resolveSkillOverrides, calcGrowBonus } from "../common/config/heroSet";
|
||||
import { HeroViewComp } from "../hero/HeroViewComp";
|
||||
import { FacSet, FightSet } from "../common/config/GameSet";
|
||||
import { MissionEconomy } from "./MissionEconomy";
|
||||
@@ -2273,7 +2273,8 @@ export class MissionCardComp extends CCComp {
|
||||
for (const key in hero.skills) {
|
||||
const skill = hero.skills[key];
|
||||
if (!skill) continue;
|
||||
model.skills[skill.uuid] = { ...skill, lv: Math.min(FightSet.HERO_SKILL_MAX_LV, Math.max(0, skill.lv + nextLv - 2)), ccd: 0 };
|
||||
// 升级后按 nextLv 重新 resolve 分档 overrides(与 Hero.load 对齐)
|
||||
model.skills[skill.uuid] = { ...skill, lv: Math.min(FightSet.HERO_SKILL_MAX_LV, Math.max(0, skill.lv + nextLv - 2)), ccd: 0, overrides: resolveSkillOverrides(skill, nextLv) };
|
||||
}
|
||||
model.updateSkillDistanceCache();
|
||||
model.dirty_hp = true;
|
||||
|
||||
Reference in New Issue
Block a user