feat(skill): 添加计时buff目标覆写功能

1. 新增BuffTarget枚举定义计时buff的四种施加目标类型
2. 扩展SkillOverrides接口添加buff_target配置项
3. 实现resolveBuffTargets方法解析buff实际施加目标
4. 调整普攻buff施加逻辑适配新的目标配置规则
5. 修复伤害技能误给敌方挂友方buff的问题
6. 清理英雄技能配置中多余的summon_count参数
This commit is contained in:
panFD
2026-09-05 12:22:18 +08:00
parent 7949f7d1d7
commit 071afc8fa2
4 changed files with 63 additions and 14 deletions

View File

@@ -20,6 +20,18 @@ export enum DTType {
range = 1, range = 1,
} }
/**
* 计时 buff(timed_buff_id)的施加目标。
* 缺省(undefined)时按技能主效果推导:伤害技能挂被命中者,辅助技能挂友方目标。
* 显式配置后打破 TGroup 默认绑定,实现"伤害技能命中后给自己回血"等跨阵营效果。
*/
export enum BuffTarget {
Hit = 0, // 被命中者(敌方技能的默认行为)
Self = 1, // 施法者自身
Ally = 2, // 全体友方(含施法者)
Enemy = 3, // 全体敌方(辅助技能给敌人挂 debuff 用)
}
export enum SkillKind { export enum SkillKind {
Damage = 0, Damage = 0,
Heal = 1, Heal = 1,
@@ -178,6 +190,8 @@ export interface SkillOverrides {
buff_value?: number; buff_value?: number;
buff_duration?: number; buff_duration?: number;
buff_chance?: number; buff_chance?: number;
/** 计时 buff 施加目标覆写:缺省按技能主效果推导(伤害→被命中者,辅助→友方) */
buff_target?: BuffTarget;
call_hero?: number; call_hero?: number;
/** 单次施法召唤的技能实体个数(覆盖 prefab 上 SkillView.summon_count;>1 视为召唤类,不再参与风怒等额外触发) */ /** 单次施法召唤的技能实体个数(覆盖 prefab 上 SkillView.summon_count;>1 视为召唤类,不再参与风怒等额外触发) */
summon_count?: number; summon_count?: number;

View File

@@ -599,10 +599,10 @@ export const HeroInfo: Record<number, heroInfo> = {
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"stun":10}, desc: "挥斧对{target}造成攻击力{ap}%伤害,{stun}%概率击晕" }, { lv: 2, s_lv: SkillLv.Lv2, overrides: {"stun":10}, desc: "挥斧对{target}造成攻击力{ap}%伤害,{stun}%概率击晕" },
], ],
}, },
6104: { uuid: 6104, name: "开山斧", lv: 1, cd: 8, ccd: 0, overrides: {"ap":300,"stun":100,"summon_count":1}, desc: "劈出开山斧,对{target}造成攻击力{ap}%伤害,必定击晕", 6104: { uuid: 6104, name: "开山斧", lv: 1, cd: 8, ccd: 0, overrides: {"ap":300,"stun":100}, desc: "劈出开山斧,对{target}造成攻击力{ap}%伤害,必定击晕",
lv_entries: [ lv_entries: [
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":450,"stun":100,"summon_count":1} }, { lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":450,"stun":100} },
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":450,"stun":100,"summon_count":2} }, { lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":450,"stun":100} },
], ],
}, },
}, },
@@ -620,10 +620,10 @@ export const HeroInfo: Record<number, heroInfo> = {
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"crt":10}, desc: "挥刀对{target}造成攻击力{ap}%伤害,{crt}%概率暴击" }, { lv: 2, s_lv: SkillLv.Lv2, overrides: {"crt":10}, desc: "挥刀对{target}造成攻击力{ap}%伤害,{crt}%概率暴击" },
], ],
}, },
6100: { uuid: 6100, name: "光闪", lv: 1, cd: 8, ccd: 0, overrides: {"ap":150,"summon_count":1}, desc: "斩出光闪,对{target}造成攻击力{ap}%伤害", 6100: { uuid: 6100, name: "光闪", lv: 1, cd: 8, ccd: 0, overrides: {"ap":150}, desc: "斩出光闪,对{target}造成攻击力{ap}%伤害",
lv_entries: [ lv_entries: [
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":250,"summon_count":1} }, { lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":250} },
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":350,"summon_count":2} }, { lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":350} },
], ],
}, },
}, },
@@ -641,10 +641,10 @@ export const HeroInfo: Record<number, heroInfo> = {
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"timed_buff_id":7007,"buff_value":30,"buff_chance":30}, desc: "挥刀对{target}造成攻击力{ap}%伤害,{buff_chance}%概率使目标出血(每0.5秒受到{buff_value}点伤害,持续{dur}秒)" }, { lv: 2, s_lv: SkillLv.Lv2, overrides: {"timed_buff_id":7007,"buff_value":30,"buff_chance":30}, desc: "挥刀对{target}造成攻击力{ap}%伤害,{buff_chance}%概率使目标出血(每0.5秒受到{buff_value}点伤害,持续{dur}秒)" },
], ],
}, },
6103: { uuid: 6103, name: "闪电斩", lv: 1, cd: 8, ccd: 0, overrides: {"ap":150,"summon_count":1}, desc: "召唤落雷斩击{target},造成攻击力{ap}%伤害", 6103: { uuid: 6103, name: "闪电斩", lv: 1, cd: 8, ccd: 0, overrides: {"ap":150}, desc: "召唤落雷斩击{target},造成攻击力{ap}%伤害",
lv_entries: [ lv_entries: [
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":250,"timed_buff_id":7007,"summon_count":1}, desc: "召唤落雷斩击{target},造成攻击力{ap}%伤害,并使目标出血(每0.5秒受到{buff_value}点伤害,持续{dur}秒)" }, { lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":250,"timed_buff_id":7007}, desc: "召唤落雷斩击{target},造成攻击力{ap}%伤害,并使目标出血(每0.5秒受到{buff_value}点伤害,持续{dur}秒)" },
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":350,"para":50,"timed_buff_id":7007,"buff_value":60,"summon_count":2}, desc: "召唤落雷斩击{target},造成攻击力{ap}%伤害,{para}%概率麻痹,并使目标出血(每0.5秒受到{buff_value}点伤害,持续{dur}秒)" }, { lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":350,"para":50,"timed_buff_id":7007,"buff_value":60}, desc: "召唤落雷斩击{target},造成攻击力{ap}%伤害,{para}%概率麻痹,并使目标出血(每0.5秒受到{buff_value}点伤害,持续{dur}秒)" },
], ],
}, },
}, },

View File

@@ -11,7 +11,7 @@ import { HeroInfo } from "../common/config/heroSet";
import { oops } from "db://oops-framework/core/Oops"; import { oops } from "db://oops-framework/core/Oops";
import { GameEvent } from "../common/config/GameEvent"; import { GameEvent } from "../common/config/GameEvent";
import { SkillTriggerType } from "../common/config/heroSet"; import { SkillTriggerType } from "../common/config/heroSet";
import { FieldSkillType } from "../common/config/SkillSet"; import { FieldSkillType, BuffTarget } from "../common/config/SkillSet";
import { mLogger } from "../common/Logger"; import { mLogger } from "../common/Logger";
import { SkillTriggerHelper } from "./SkillTriggerHelper"; import { SkillTriggerHelper } from "./SkillTriggerHelper";
@@ -257,7 +257,7 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpda
} }
} }
// 命中附带 debuff(如灼烧 DoT):仅普攻路径,复用友方 timed_buff_id 机制; // 命中附带 buff:仅普攻路径;buff_target 缺省挂被命中者,显式配置可改为挂施法者/全体友方/全体敌方
// 施法者 ap/完整属性快照取自伤害事件,供 BuffSystem tick 缩放与暴击/冰冻/击晕判定 // 施法者 ap/完整属性快照取自伤害事件,供 BuffSystem tick 缩放与暴击/冰冻/击晕判定
if (!isDot && skillConf.timed_buff_id) { if (!isDot && skillConf.timed_buff_id) {
const buffChance = skillConf.buff_chance ?? 100; const buffChance = skillConf.buff_chance ?? 100;
@@ -265,7 +265,9 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpda
const buffOverrides: BuffApplyOverrides = { source_attrs: damageEvent.Attrs }; const buffOverrides: BuffApplyOverrides = { source_attrs: damageEvent.Attrs };
if (skillConf.buff_value !== undefined) buffOverrides.value = skillConf.buff_value; if (skillConf.buff_value !== undefined) buffOverrides.value = skillConf.buff_value;
if (skillConf.buff_duration !== undefined) buffOverrides.duration = skillConf.buff_duration; if (skillConf.buff_duration !== undefined) buffOverrides.duration = skillConf.buff_duration;
buffManager.applyBuff(target, skillConf.timed_buff_id, casterEid, damageEvent.Attrs[Attrs.ap] || 0, buffOverrides); for (const buffTarget of this.resolveBuffTargets(target, casterEid, TAttrsComp.fac, skillConf.buff_target)) {
buffManager.applyBuff(buffTarget, skillConf.timed_buff_id, casterEid, damageEvent.Attrs[Attrs.ap] || 0, buffOverrides);
}
} }
} }
@@ -527,6 +529,38 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpda
return { remainingDamage: damage - absorbed, absorbedDamage: absorbed }; return { remainingDamage: damage - absorbed, absorbedDamage: absorbed };
} }
/**
* 解析 timed_buff_id 的施加目标实体列表。
* 缺省(undefined / BuffTarget.Hit)返回被命中者;显式配置可切换到施法者自身、全体友方或全体敌方。
* @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) {
const caster = ecs.getEntityByEid(casterEid);
return caster ? [caster] : [];
}
// 全体友方/敌方:以施法者阵营为基准(命中者必为敌方,施法方网格即友方)
const casterFac = targetFac === FacSet.HERO ? FacSet.MON : FacSet.HERO;
const grid = buffTarget === BuffTarget.Ally
? (casterFac === FacSet.HERO ? smc.mission.heroGrid : smc.mission.monGrid)
: (casterFac === FacSet.HERO ? smc.mission.monGrid : smc.mission.heroGrid);
const targets: ecs.Entity[] = [];
for (const eid of grid) {
if (eid < 0) continue;
const ent = ecs.getEntityByEid(eid);
if (!ent) continue;
const attrs = ent.get(HeroAttrsComp);
if (attrs && !attrs.is_dead && !attrs.is_reviving) targets.push(ent);
}
return targets;
}
/** /**
* 被攻击时触发的事件 * 被攻击时触发的事件
* *

View File

@@ -2,7 +2,7 @@ import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ec
import { Vec3, Prefab, instantiate, tween, Node } from "cc"; import { Vec3, Prefab, instantiate, tween, Node } from "cc";
import { HeroAttrsComp } from "./HeroAttrsComp"; import { HeroAttrsComp } from "./HeroAttrsComp";
import { HeroViewComp } from "./HeroViewComp"; import { HeroViewComp } from "./HeroViewComp";
import { DTType, RType, SkillConfig, SkillKind, SkillSet, TGroup, SkillOverrides, mergeSkillParams } from "../common/config/SkillSet"; import { DTType, RType, SkillConfig, SkillKind, SkillSet, TGroup, SkillOverrides, mergeSkillParams, BuffTarget } from "../common/config/SkillSet";
import { Skill } from "../skill/Skill"; import { Skill } from "../skill/Skill";
import { SkillView } from "../skill/SkillView"; import { SkillView } from "../skill/SkillView";
import { smc } from "../common/SingletonModuleComp"; import { smc } from "../common/SingletonModuleComp";
@@ -545,7 +545,8 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
if (config.buff_type !== undefined) { if (config.buff_type !== undefined) {
// 计时性 buff:配置了 timed_buff_id 时走 buffManager 限时路径, // 计时性 buff:配置了 timed_buff_id 时走 buffManager 限时路径,
// 同一技能不应既永久加成又限时加成,故提前 return 跳过下方永久 add_* 逻辑 // 同一技能不应既永久加成又限时加成,故提前 return 跳过下方永久 add_* 逻辑
if (config.timed_buff_id) { // buff_target=Enemy 时 timed_buff_id 已在 applyFriendlySkillEffects 入口分流到敌方网格,此处跳过避免误挂友方
if (config.timed_buff_id && config.buff_target !== BuffTarget.Enemy) {
// 汇总 buff 覆写参数:value 覆写修饰数值,duration 覆写持续时间 // 汇总 buff 覆写参数:value 覆写修饰数值,duration 覆写持续时间
const buffOverrides: { value?: number; duration?: number } = {}; const buffOverrides: { value?: number; duration?: number } = {};
if (config.buff_value !== undefined) buffOverrides.value = config.buff_value; if (config.buff_value !== undefined) buffOverrides.value = config.buff_value;