feat(skill-system): 新增计时debuff机制,支持技能命中敌方附加减益效果

本次提交完整实现了技能对敌附加debuff的完整流程:
1.  新增TimedDebuffSnapshot数据结构,用于透传debuff配置
2.  在SkillConfig和SkillOverrides中新增debuff相关配置项
3.  实现HeroAtkSystem中debuff的判定与施加逻辑
4.  完善后台配置、前端编辑器的debuff配置支持
5.  调整了buff目标判定逻辑,修复了原有默认目标的语义混淆问题
6.  优化了BuffSystem的调试日志,新增了debuff分类标识
7.  批量更新了现有英雄技能的debuff配置示例
This commit is contained in:
pan
2026-09-08 16:37:13 +08:00
parent f5908a9adf
commit be17d18ff3
16 changed files with 214 additions and 124 deletions

View File

@@ -279,7 +279,8 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpda
}
}
// 命中附带 buff:仅普攻路径;buff_target 缺省挂被命中者,显式配置可改为挂施法者/全体友方/全体敌方
// 命中附带 buff:仅普攻路径;buff 语义为增益,缺省挂施法者自身(如吸血/攻击后强化),
// 显式配置 buff_target 可改为全体友方等;buff 也可挂自身 debuff 类(如自残出血)
// 施法者 ap/完整属性快照取自伤害事件,供 BuffSystem tick 缩放与暴击/冰冻/击晕判定
if (!isDot && skillConf.timed_buff_id) {
const buffChance = skillConf.buff_chance ?? 100;
@@ -298,6 +299,30 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpda
}
}
// 命中附带 debuff:仅普攻路径;debuff 语义为对敌减益,目标固定为被命中者(不可覆写)
// 优先取伤害事件透传的合并后快照(heroSet overrides/lv_entries 注入),缺省回退 SkillSet 底座配置
// debuff_value/debuff_duration 覆写 BuffList 默认数值与持续时间
// 注:DoT 事件无 SkillSet 配置(skillConf 可能为 undefined),必须在 !isDot 保护内读取
if (!isDot && skillConf) {
const snapDebuff = damageEvent.timed_debuff;
const debuffId = snapDebuff?.id ?? skillConf.timed_debuff_id;
if (debuffId) {
const debuffChance = snapDebuff?.chance ?? skillConf.debuff_chance ?? 100;
const debuffRand = debuffChance >= 100 ? 0 : Math.random() * 100;
if (debuffChance >= 100 || debuffRand < debuffChance) {
const debuffOverrides: BuffApplyOverrides = { source_attrs: damageEvent.Attrs };
const debuffValue = snapDebuff?.value ?? skillConf.debuff_value;
const debuffDuration = snapDebuff?.duration ?? skillConf.debuff_duration;
if (debuffValue !== undefined) debuffOverrides.value = debuffValue;
if (debuffDuration !== undefined) debuffOverrides.duration = debuffDuration;
mLogger.log(this.debugMode, 'HeroAtkSystem', `[概率判定] 附带debuff「${BuffList[debuffId]?.name ?? "?"}」 概率:${debuffChance.toFixed(1)}% 随机:${debuffRand.toFixed(1)} -> ✔成功(技能「${skillConf.name}」命中 ${TAttrsComp.hero_name})`);
buffManager.applyBuff(target, debuffId, casterEid, damageEvent.Attrs[Attrs.ap] || 0, debuffOverrides);
} else {
mLogger.log(this.debugMode, 'HeroAtkSystem', `[概率判定] 附带debuff「${BuffList[debuffId]?.name ?? "?"}」 概率:${debuffChance.toFixed(1)}% 随机:${debuffRand.toFixed(1)} -> ✘失败(技能「${skillConf.name}」命中 ${TAttrsComp.hero_name})`);
}
}
}
// 命中概率触发额外技能(proc_skill):配置由施法技能实体快照自合并后配置(含 heroSet overrides/lv_entries),
// 触发走 SkillTriggerHelper/forceCastTriggerSkill 通道(无视 CD、无施法前摇),与 atking 同一通道。
// 防递归:被触发的技能经 forceCastTriggerSkill 不再产生 proc_skill 伤害事件之外的新事件,且不会累加 atk_count。
@@ -636,20 +661,21 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpda
/**
* 解析 timed_buff_id 的施加目标实体列表。
* 缺省(undefined / BuffTarget.Hit)返回被命中者;显式配置可切换到施法者自身、全体友方或全体敌方。
* 缺省(undefined / BuffTarget.Self)返回施法者自身(buff 为增益语义,如吸血/攻击后强化);
* 显式配置可切换到被命中者、全体友方或全体敌方。
* @param hitTarget 被命中实体(伤害事件的 target)
* @param casterEid 施法者 eid
* @param targetFac 被命中者阵营(用于推导敌我网格)
* @param buffTarget 技能配置上的目标覆写
*/
private resolveBuffTargets(hitTarget: ecs.Entity, casterEid: number, targetFac: number, buffTarget?: BuffTarget): ecs.Entity[] {
if (buffTarget === undefined || buffTarget === BuffTarget.Hit) {
return [hitTarget];
}
if (buffTarget === BuffTarget.Self) {
if (buffTarget === undefined || buffTarget === BuffTarget.Self) {
const caster = ecs.getEntityByEid(casterEid);
return caster ? [caster] : [];
}
if (buffTarget === BuffTarget.Hit) {
return [hitTarget];
}
// 全体友方/敌方:以施法者阵营为基准(命中者必为敌方,施法方网格即友方)
const casterFac = targetFac === FacSet.HERO ? FacSet.MON : FacSet.HERO;
const grid = buffTarget === BuffTarget.Ally