diff --git a/assets/script/game/common/config/GameEvent.ts b/assets/script/game/common/config/GameEvent.ts index 3029124b..62c21aba 100644 --- a/assets/script/game/common/config/GameEvent.ts +++ b/assets/script/game/common/config/GameEvent.ts @@ -76,4 +76,14 @@ export enum GameEvent { CardPoolUpgrade = "CardPoolUpgrade", TriggerSkill = "TriggerSkill", // 瞬间触发施法事件 RemoveSkillBox = "RemoveSkillBox", // 技能盒销毁事件 +} + +/** 触发技能类型枚举 */ +export enum SkillTriggerType { + Call = 'call', // 召唤时触发 + Dead = 'dead', // 死亡时触发 + FStart = 'fstart', // 战斗开始时触发 + FEnd = 'fend', // 战斗结束时触发 + Atking = 'atking', // 攻击时触发 + Atked = 'atked' // 受击时触发 } \ No newline at end of file diff --git a/assets/script/game/hero/Hero.ts b/assets/script/game/hero/Hero.ts index d8b2f068..733460dc 100644 --- a/assets/script/game/hero/Hero.ts +++ b/assets/script/game/hero/Hero.ts @@ -6,7 +6,8 @@ import { HeroAttrsComp } from "./HeroAttrsComp"; import { HeroViewComp } from "./HeroViewComp"; import { BoxSet, FacSet, FightSet, IndexSet } from "../common/config/GameSet"; import { HeroInfo, HeroPos, resolveFormationTargetX } from "../common/config/heroSet"; -import { GameEvent } from "../common/config/GameEvent"; +import { GameEvent, SkillTriggerType } from "../common/config/GameEvent"; +import { SkillTriggerHelper } from "./SkillTriggerHelper"; import { Attrs} from "../common/config/HeroAttrs"; import { MoveComp } from "./MoveComp"; import { mLogger } from "../common/Logger"; @@ -222,24 +223,7 @@ export class Hero extends ecs.Entity { } // 落地后触发 call 技能 - if (model && model.call && model.call.length > 0) { - let triggerCount = 1 + HeroAttrsComp.getFieldSkillTotalValue(FieldSkillType.SummonCount); - if (model.fac === FacSet.HERO) { - triggerCount += HeroAttrsComp.getTalentValue(TalentType.Summon); // 召唤强化额外次数 - } - triggerCount = Math.max(1, Math.floor(triggerCount)); - - for (let i = 0; i < triggerCount; i++) { - model.call.forEach(uuid => { - oops.message.dispatchEvent(GameEvent.TriggerSkill, { - s_uuid: uuid, - heroAttrs: model, - heroView: view, - triggerType: 'call' - }); - }); - } - } + SkillTriggerHelper.trigger(SkillTriggerType.Call, model, view); }) .start(); } diff --git a/assets/script/game/hero/HeroAtkSystem.ts b/assets/script/game/hero/HeroAtkSystem.ts index 1198b26f..4612c6b5 100644 --- a/assets/script/game/hero/HeroAtkSystem.ts +++ b/assets/script/game/hero/HeroAtkSystem.ts @@ -9,10 +9,11 @@ import { DamageQueueComp, DamageEvent } from "./DamageQueueComp"; import { smc } from "../common/SingletonModuleComp"; import { HeroInfo } from "../common/config/heroSet"; import { oops } from "db://oops-framework/core/Oops"; -import { GameEvent } from "../common/config/GameEvent"; +import { GameEvent, SkillTriggerType } from "../common/config/GameEvent"; import { FieldSkillType } from "../common/config/SkillSet"; import { mLogger } from "../common/Logger"; +import { SkillTriggerHelper } from "./SkillTriggerHelper"; /** 最终伤害数据接口 * 用于封装一次攻击计算的所有结果数据 @@ -94,18 +95,7 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd /** 检查并触发受击附加技能 (atked) */ private checkAndTriggerAtkedSkills(heroAttrs: HeroAttrsComp, heroView: HeroViewComp) { - if (!heroAttrs.atked || heroAttrs.atked.length === 0) return; - - heroAttrs.atked.forEach(atkConfig => { - if (heroAttrs.atked_count > 0 && heroAttrs.atked_count % atkConfig.t_num === 0) { - oops.message.dispatchEvent(GameEvent.TriggerSkill, { - s_uuid: atkConfig.s_uuid, - heroAttrs: heroAttrs, - heroView: heroView, - triggerType: 'atked' - }); - } - }); + SkillTriggerHelper.trigger(SkillTriggerType.Atked, heroAttrs, heroView); } /** @@ -319,27 +309,9 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd const TAttrsComp = entity.get(HeroAttrsComp); if (!TAttrsComp) return; - if (TAttrsComp.dead && TAttrsComp.dead.length > 0) { - const view = entity.get(HeroViewComp); - if (view) { - let triggerCount = 1 + HeroAttrsComp.getFieldSkillTotalValue(FieldSkillType.DeadCount); - triggerCount = Math.max(1, Math.floor(triggerCount)); - - for (let i = 0; i < triggerCount; i++) { - TAttrsComp.dead.forEach((uuid: number) => { - if (TAttrsComp.fac === FacSet.HERO) { - // 【评分系统 - 防御分】统计死亡触发技能的生效次数 - smc.vmdata.scores.dead_trigger_count++; - } - oops.message.dispatchEvent(GameEvent.TriggerSkill, { - s_uuid: uuid, - heroAttrs: TAttrsComp, - heroView: view, - triggerType: 'dead' - }); - }); - } - } + const view = entity.get(HeroViewComp); + if (view) { + SkillTriggerHelper.trigger(SkillTriggerType.Dead, TAttrsComp, view); } } diff --git a/assets/script/game/hero/Mon.ts b/assets/script/game/hero/Mon.ts index c12a2101..5c0c20c5 100644 --- a/assets/script/game/hero/Mon.ts +++ b/assets/script/game/hero/Mon.ts @@ -8,7 +8,8 @@ import { HeroAttrsComp } from "./HeroAttrsComp"; import { HeroViewComp } from "./HeroViewComp"; import { MoveComp } from "./MoveComp"; import { MonMoveComp } from "./MonMoveComp"; -import { GameEvent } from "../common/config/GameEvent"; +import { GameEvent, SkillTriggerType } from "../common/config/GameEvent"; +import { SkillTriggerHelper } from "./SkillTriggerHelper"; /** 怪物实体:负责怪物对象池复用、属性初始化、入场动画与回收 */ @ecs.register(`Monster`) export class Monster extends ecs.Entity { @@ -232,16 +233,7 @@ export class Monster extends ecs.Entity { } // 落地后触发 call 技能 - if (model.call && model.call.length > 0) { - model.call.forEach((uuid: number) => { - oops.message.dispatchEvent(GameEvent.TriggerSkill, { - s_uuid: uuid, - heroAttrs: model, - heroView: view, - triggerType: 'call' - }); - }); - } + SkillTriggerHelper.trigger(SkillTriggerType.Call, model, view); }) .start(); // 维护关卡内怪物数量统计 diff --git a/assets/script/game/hero/SCastSystem.ts b/assets/script/game/hero/SCastSystem.ts index c18da730..cf8d679e 100644 --- a/assets/script/game/hero/SCastSystem.ts +++ b/assets/script/game/hero/SCastSystem.ts @@ -9,7 +9,8 @@ import { HeroDisVal, HeroInfo, HType } from "../common/config/heroSet"; import { Attrs } from "../common/config/HeroAttrs"; import { BoxSet, FacSet, FightSet } from "../common/config/GameSet"; import { oops } from "db://oops-framework/core/Oops"; -import { GameEvent } from "../common/config/GameEvent"; +import { GameEvent, SkillTriggerType } from "../common/config/GameEvent"; +import { SkillTriggerHelper } from "./SkillTriggerHelper"; /** * ==================== 自动施法系统 ==================== @@ -338,18 +339,7 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate /** 检查并触发攻击附加技能 (atking) */ private checkAndTriggerAtkingSkills(heroAttrs: HeroAttrsComp, heroView: HeroViewComp) { - if (!heroAttrs.atking || heroAttrs.atking.length === 0) return; - - heroAttrs.atking.forEach(atkConfig => { - if (heroAttrs.atk_count > 0 && heroAttrs.atk_count % atkConfig.t_num === 0) { - oops.message.dispatchEvent(GameEvent.TriggerSkill, { - s_uuid: atkConfig.s_uuid, - heroAttrs: heroAttrs, - heroView: heroView, - triggerType: 'atking' - }); - } - }); + SkillTriggerHelper.trigger(SkillTriggerType.Atking, heroAttrs, heroView); } private resolveRepeatCastTargetPos(targetPos: Vec3 | null, castIndex: number): Vec3 | null { diff --git a/assets/script/game/hero/SkillTriggerHelper.ts b/assets/script/game/hero/SkillTriggerHelper.ts new file mode 100644 index 00000000..2026d9f1 --- /dev/null +++ b/assets/script/game/hero/SkillTriggerHelper.ts @@ -0,0 +1,153 @@ +import { oops } from "db://oops-framework/core/Oops"; +import { GameEvent, SkillTriggerType } from "../common/config/GameEvent"; +import { HeroAttrsComp } from "./HeroAttrsComp"; +import { HeroViewComp } from "./HeroViewComp"; +import { FacSet } from "../common/config/GameSet"; +import { FieldSkillType } from "../common/config/SkillSet"; +import { TalentType } from "../common/config/TalentSet"; +import { smc } from "../common/SingletonModuleComp"; + + +/** + * 特殊触发技能的统一中介者 (Mediator) + * + * 核心职责: + * 1. 统一管理英雄/怪物的各类生命周期触发技能(召唤、死亡、战前、战后、攻受击)。 + * 2. 集中处理触发次数的计算(如:局内羁绊加成、局外天赋加成)。 + * 3. 作为唯一出口,通过事件总线向 SCastSystem 派发 GameEvent.TriggerSkill 事件。 + * + * 优势: + * - 极大地解耦了具体业务组件(Hero/Mon/HeroAtkSystem/MissionComp)与技能系统。 + * - 避免了原先散落在各处的判定逻辑和冗余的事件派发代码。 + */ +export class SkillTriggerHelper { + /** + * 统一的技能触发入口 + * 根据传入的触发类型,自动分发到对应的处理函数中执行判定和加成逻辑。 + * + * @param type 触发类型枚举 (SkillTriggerType) + * @param model 施法者的属性数据组件 (HeroAttrsComp) + * @param view 施法者的视图表现组件 (HeroViewComp) + */ + public static trigger(type: SkillTriggerType, model: HeroAttrsComp, view: HeroViewComp) { + // 健壮性检查:若实体或节点已被销毁,直接阻断,防止空指针报错 + if (!model || !view || !view.node || !view.node.isValid) return; + + switch (type) { + case SkillTriggerType.Call: + this.handleCall(model, view); + break; + case SkillTriggerType.Dead: + this.handleDead(model, view); + break; + case SkillTriggerType.FStart: + this.handleArrayTrigger(model.fstart, model, view, type); + break; + case SkillTriggerType.FEnd: + this.handleArrayTrigger(model.fend, model, view, type); + break; + case SkillTriggerType.Atking: + this.handleAtking(model, view); + break; + case SkillTriggerType.Atked: + this.handleAtked(model, view); + break; + } + } + + /** + * 处理召唤(落地)触发技能 + * 支持受【召唤强化羁绊 (SummonCount)】和【召唤强化天赋 (TalentType.Summon)】的多次触发加成。 + */ + private static handleCall(model: HeroAttrsComp, view: HeroViewComp) { + if (!model.call || model.call.length === 0) return; + + let triggerCount = 1; + // 仅英雄享受加成,怪物始终只触发 1 次 + if (model.fac === FacSet.HERO) { + triggerCount += HeroAttrsComp.getFieldSkillTotalValue(FieldSkillType.SummonCount); + triggerCount += HeroAttrsComp.getTalentValue(TalentType.Summon); + } + triggerCount = Math.max(1, Math.floor(triggerCount)); // 确保最少触发 1 次 + + for (let i = 0; i < triggerCount; i++) { + this.dispatchArray(model.call, model, view, SkillTriggerType.Call); + } + } + + /** + * 处理死亡触发技能 + * 支持受【亡语强化羁绊 (DeadCount)】的多次触发加成。 + */ + private static handleDead(model: HeroAttrsComp, view: HeroViewComp) { + if (!model.dead || model.dead.length === 0) return; + + let triggerCount = 1; + if (model.fac === FacSet.HERO) { + triggerCount += HeroAttrsComp.getFieldSkillTotalValue(FieldSkillType.DeadCount); + // 【局内战绩评分系统】统计死亡触发技能生效次数(用于局后防守评分结算) + smc.vmdata.scores.dead_trigger_count += model.dead.length; + } + triggerCount = Math.max(1, Math.floor(triggerCount)); + + for (let i = 0; i < triggerCount; i++) { + this.dispatchArray(model.dead, model, view, SkillTriggerType.Dead); + } + } + + /** + * 处理攻击附加技能 + * 判定逻辑:依据配置中的 t_num(触发所需普攻次数),对比当前的普攻累计次数取模判定。 + */ + private static handleAtking(model: HeroAttrsComp, view: HeroViewComp) { + if (!model.atking || model.atking.length === 0) return; + model.atking.forEach(atkConfig => { + // atk_count 代表已进行的普攻次数。当其余数刚好整除配置阈值时触发。 + if (model.atk_count > 0 && model.atk_count % atkConfig.t_num === 0) { + this.dispatchSingle(atkConfig.s_uuid, model, view, SkillTriggerType.Atking); + } + }); + } + + /** + * 处理受击附加技能 + * 判定逻辑:依据配置中的 t_num(触发所需受击次数),对比当前的受击累计次数取模判定。 + */ + private static handleAtked(model: HeroAttrsComp, view: HeroViewComp) { + if (!model.atked || model.atked.length === 0) return; + model.atked.forEach(atkConfig => { + // atked_count 代表已承受的受击次数。当其余数刚好整除配置阈值时触发。 + if (model.atked_count > 0 && model.atked_count % atkConfig.t_num === 0) { + this.dispatchSingle(atkConfig.s_uuid, model, view, SkillTriggerType.Atked); + } + }); + } + + /** + * 通用的数组型触发器处理(适用于 FStart / FEnd 等无需额外判定的简单列表触发) + */ + private static handleArrayTrigger(uuids: number[] | undefined, model: HeroAttrsComp, view: HeroViewComp, type: SkillTriggerType) { + if (!uuids || uuids.length === 0) return; + this.dispatchArray(uuids, model, view, type); + } + + /** + * 批量派发技能事件 + */ + private static dispatchArray(uuids: number[], model: HeroAttrsComp, view: HeroViewComp, type: SkillTriggerType) { + uuids.forEach(uuid => this.dispatchSingle(uuid, model, view, type)); + } + + /** + * 单一技能事件派发底层接口 + * 事件发出后,将由 SCastSystem 的 forceCastTriggerSkill 监听拦截并执行无视CD的强制施法 + */ + private static dispatchSingle(s_uuid: number, model: HeroAttrsComp, view: HeroViewComp, type: SkillTriggerType) { + oops.message.dispatchEvent(GameEvent.TriggerSkill, { + s_uuid: s_uuid, + heroAttrs: model, + heroView: view, + triggerType: type + }); + } +} diff --git a/assets/script/game/hero/SkillTriggerHelper.ts.meta b/assets/script/game/hero/SkillTriggerHelper.ts.meta new file mode 100644 index 00000000..798f24e7 --- /dev/null +++ b/assets/script/game/hero/SkillTriggerHelper.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.24", + "importer": "typescript", + "imported": true, + "uuid": "7a37f6b6-1d1a-4f37-a390-9353253f3fac", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/script/game/map/MissionComp.ts b/assets/script/game/map/MissionComp.ts index db480de7..f01a9d45 100644 --- a/assets/script/game/map/MissionComp.ts +++ b/assets/script/game/map/MissionComp.ts @@ -33,8 +33,9 @@ import { CCComp } from "../../../../extensions/oops-plugin-framework/assets/modu import { smc } from "../common/SingletonModuleComp"; import { oops } from "../../../../extensions/oops-plugin-framework/assets/core/Oops"; import { HeroAttrsComp } from "../hero/HeroAttrsComp"; -import { GameEvent } from "../common/config/GameEvent"; +import { GameEvent, SkillTriggerType } from "../common/config/GameEvent"; import { HeroViewComp } from "../hero/HeroViewComp"; +import { SkillTriggerHelper } from "../hero/SkillTriggerHelper"; import { UIID } from "../common/config/GameUIConfig"; import { SkillView } from "../skill/SkillView"; import { FacSet, FightSet } from "../common/config/GameSet"; @@ -588,18 +589,9 @@ export class MissionComp extends CCComp { const attrs = entity.get(HeroAttrsComp); const view = entity.get(HeroViewComp); if (!attrs || !view || attrs.is_dead || attrs.fac !== FacSet.HERO) return; - const skillUuids = isStart ? attrs.fstart : attrs.fend; - if (skillUuids && skillUuids.length > 0) { - for (let i = 0; i < triggerCount; i++) { - skillUuids.forEach(uuid => { - oops.message.dispatchEvent(GameEvent.TriggerSkill, { - s_uuid: uuid, - heroAttrs: attrs, - heroView: view, - triggerType: isStart ? 'fstart' : 'fend' - }); - }); - } + // 触发战斗开始/结束技能 + for (let i = 0; i < triggerCount; i++) { + SkillTriggerHelper.trigger(isStart ? SkillTriggerType.FStart : SkillTriggerType.FEnd, attrs, view); } }); }