From ada45feb0153ea3ed461262ca652f4a1390fb095 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=98=94=E5=BF=B5?= <1@72wo.cn> Date: Mon, 25 Aug 2025 05:28:08 +0800 Subject: [PATCH] =?UTF-8?q?refactor(fight):=20=E9=87=8D=E6=9E=84=E6=95=88?= =?UTF-8?q?=E6=9E=9C=E7=B3=BB=E7=BB=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 重新定义了基础事件类型和效果触发时机 - 优化了效果的结构和执行逻辑 - 添加了效果生命周期的管理 - 调整了效果注册和触发的方式 --- logic/service/fight/battle/node/node.go | 131 +++------- logic/service/fight/battle/node/t.go | 233 ++++++++++++++++++ .../battle/skill/effect/EffectContainer.go | 148 +++++++++++ logic/service/fight/battle/skill/effect/c.go | 59 ----- .../fight/battle/skill/effect/effecti.go | 117 --------- .../fight/battle/skill/effect/impl/effect1.go | 20 ++ .../fight/battle/skill/effect/manger.go | 88 ++++--- 7 files changed, 494 insertions(+), 302 deletions(-) create mode 100644 logic/service/fight/battle/node/t.go create mode 100644 logic/service/fight/battle/skill/effect/EffectContainer.go delete mode 100644 logic/service/fight/battle/skill/effect/c.go delete mode 100644 logic/service/fight/battle/skill/effect/effecti.go diff --git a/logic/service/fight/battle/node/node.go b/logic/service/fight/battle/node/node.go index 97ff0205..6d81a69c 100644 --- a/logic/service/fight/battle/node/node.go +++ b/logic/service/fight/battle/node/node.go @@ -2,102 +2,39 @@ package node import "github.com/tnnmigga/enum" -// EnumEffectTrigger 效果触发时机枚举类型 -// 定义了战斗中各种效果的触发时机点 -type EnumEffectTrigger int +// ================= BaseEvent ================= +// EnumBaseEvent 定义了战斗中可能触发的基础事件类型。 +// 这些事件通常作为 Effect 的触发点,例如攻击前、受到伤害后等。 +type EnumBaseEvent string -// EffectTrigger 效果触发时机枚举实例 -// 包含战斗过程中所有可能触发效果的关键时间点 -var EffectTrigger = enum.New[struct { - // 已有的触发时机 - OnBattleStart EnumEffectTrigger `enum:"OnBattleStart"` // 战斗开始时触发 - BeforeSort EnumEffectTrigger `enum:"BeforeSort"` // 先手顺序判定前触发 - BeforeUseSkillCheck EnumEffectTrigger `enum:"BeforeUseSkillCheck"` // 使用技能前检查(PP、状态等) - AfterUseSkillCheck EnumEffectTrigger `enum:"AfterUseSkillCheck"` // 使用技能检查后触发 - BeforeMultiHit EnumEffectTrigger `enum:"BeforeMultiHit"` // 多段攻击开始前触发 - BeforeHit EnumEffectTrigger `enum:"BeforeHit"` // 攻击命中前触发 - OnCritPreDamage EnumEffectTrigger `enum:"OnCritPreDamage"` // 暴击判定成功且伤害计算前触发 - PreDamage EnumEffectTrigger `enum:"PreDamage"` // 技能伤害计算前触发(增伤/减伤等) - OnHit EnumEffectTrigger `enum:"OnHit"` // 技能命中时触发 - OnMiss EnumEffectTrigger `enum:"OnMiss"` // 技能未命中时触发 - AfterAttacked EnumEffectTrigger `enum:"AfterAttacked"` // 被攻击后触发(受击判定) - OnDefeat EnumEffectTrigger `enum:"OnDefeat"` // 精灵被击败时触发 - SkillUseEnd EnumEffectTrigger `enum:"SkillUseEnd"` // 技能使用结束后触发 - OnBeforeCalculateDamage EnumEffectTrigger `enum:"OnBeforeCalculateDamage"` // 最终伤害计算前触发 - OnDamage EnumEffectTrigger `enum:"OnDamage"` // 造成伤害时触发 - Shield EnumEffectTrigger `enum:"Shield"` // 护盾值变化时触发 - PostDamage EnumEffectTrigger `enum:"PostDamage"` // 伤害结算后触发(血量扣除后) - OnCritPostDamage EnumEffectTrigger `enum:"OnCritPostDamage"` // 暴击伤害结算后触发 - OnTransform EnumEffectTrigger `enum:"OnTransform"` // 精灵变形/进化时触发 - OnTransformEnd EnumEffectTrigger `enum:"OnTransformEnd"` // 变形/进化结束时触发 - BeforeTransform EnumEffectTrigger `enum:"BeforeTransform"` // 变形/进化前触发 - AfterTransform EnumEffectTrigger `enum:"AfterTransform"` // 变形/进化后触发 - TurnStart EnumEffectTrigger `enum:"TurnStart"` // 回合开始时触发 - TurnEnd EnumEffectTrigger `enum:"TurnEnd"` // 回合结束时触发 - OnBeforeAddMark EnumEffectTrigger `enum:"OnBeforeAddMark"` // 添加印记前触发 - OnAnyMarkAdded EnumEffectTrigger `enum:"OnAnyMarkAdded"` // 任何印记添加时触发 - OnRemoveMark EnumEffectTrigger `enum:"OnRemoveMark"` // 移除印记时触发 - OnMarkCreated EnumEffectTrigger `enum:"OnMarkCreated"` // 印记创建时触发 - OnMarkDestroy EnumEffectTrigger `enum:"OnMarkDestroy"` // 印记销毁时触发 - OnMarkDurationEnd EnumEffectTrigger `enum:"OnMarkDurationEnd"` // 印记持续回合结束时触发 - OnStackBefore EnumEffectTrigger `enum:"OnStackBefore"` // 堆叠效果前触发 - OnStack EnumEffectTrigger `enum:"OnStack"` // 堆叠效果触发 - OnBeforeConsumeStack EnumEffectTrigger `enum:"OnBeforeConsumeStack"` // 消耗堆叠前触发 - OnConsumeStack EnumEffectTrigger `enum:"OnConsumeStack"` // 消耗堆叠时触发 - OnBeforeHeal EnumEffectTrigger `enum:"OnBeforeHeal"` // 治疗前触发 - OnHeal EnumEffectTrigger `enum:"OnHeal"` // 治疗生效时触发 - BeforeRageGain EnumEffectTrigger `enum:"BeforeRageGain"` // 增怒前触发 - BeforeRageLoss EnumEffectTrigger `enum:"BeforeRageLoss"` // 减怒前触发 - OnRageGain EnumEffectTrigger `enum:"OnRageGain"` // 增怒时触发 - OnRageLoss EnumEffectTrigger `enum:"OnRageLoss"` // 减怒时触发 - OnSwitchIn EnumEffectTrigger `enum:"OnSwitchIn"` // 精灵出战/上场时触发 - OnSwitchOut EnumEffectTrigger `enum:"OnSwitchOut"` // 精灵下场时触发 - OnOwnerSwitchIn EnumEffectTrigger `enum:"OnOwnerSwitchIn"` // 所属玩家精灵出战时触发 - OnOwnerSwitchOut EnumEffectTrigger `enum:"OnOwnerSwitchOut"` // 所属玩家精灵下场时触发 - BeforeEffect EnumEffectTrigger `enum:"BeforeEffect"` // 效果生效前触发 - AfterEffect EnumEffectTrigger `enum:"AfterEffect"` // 效果生效后触发 - - // 补充的触发时机 - OnBattleEnd EnumEffectTrigger `enum:"OnBattleEnd"` // 战斗结束时触发 - OnRoundNumber EnumEffectTrigger `enum:"OnRoundNumber"` // 特定回合数时触发 - OnMaxHPChange EnumEffectTrigger `enum:"OnMaxHPChange"` // 最大生命值变化时触发 - OnHPPercentLow EnumEffectTrigger `enum:"OnHPPercentLow"` // 生命值低于特定百分比时触发 - OnHPPercentHigh EnumEffectTrigger `enum:"OnHPPercentHigh"` // 生命值高于特定百分比时触发 - OnStatusAdd EnumEffectTrigger `enum:"OnStatusAdd"` // 获得状态时触发 - OnStatusRemove EnumEffectTrigger `enum:"OnStatusRemove"` // 状态被移除时触发 - OnStatusRefresh EnumEffectTrigger `enum:"OnStatusRefresh"` // 状态被刷新时触发 - OnStatusDurationEnd EnumEffectTrigger `enum:"OnStatusDurationEnd"` // 状态持续回合结束时触发 - OnAlliesDefeated EnumEffectTrigger `enum:"OnAlliesDefeated"` // 友方单位被击败时触发 - OnEnemiesDefeated EnumEffectTrigger `enum:"OnEnemiesDefeated"` // 敌方单位被击败时触发 - OnSkillTypeUsed EnumEffectTrigger `enum:"OnSkillTypeUsed"` // 特定类型技能被使用时触发 - OnSpecificSkillUsed EnumEffectTrigger `enum:"OnSpecificSkillUsed"` // 特定技能被使用时触发 - OnDeath EnumEffectTrigger `enum:"OnDeath"` // 自身死亡时触发 - OnRevive EnumEffectTrigger `enum:"OnRevive"` // 被复活时触发 - OnFullHP EnumEffectTrigger `enum:"OnFullHP"` // 生命值回满时触发 - OnZeroHP EnumEffectTrigger `enum:"OnZeroHP"` // 生命值归零时触发 - OnMaxRage EnumEffectTrigger `enum:"OnMaxRage"` // 怒气值满时触发 - OnZeroRage EnumEffectTrigger `enum:"OnZeroRage"` // 怒气值归零时触发 - OnWeatherChange EnumEffectTrigger `enum:"OnWeatherChange"` // 天气变化时触发 - OnFieldStateChange EnumEffectTrigger `enum:"OnFieldStateChange"` // 场地状态变化时触发 - OnItemUsed EnumEffectTrigger `enum:"OnItemUsed"` // 使用物品时触发 - OnBeforeItemUse EnumEffectTrigger `enum:"OnBeforeItemUse"` // 使用物品前触发 - OnAfterItemUse EnumEffectTrigger `enum:"OnAfterItemUse"` // 使用物品后触发 - OnSwapFailed EnumEffectTrigger `enum:"OnSwapFailed"` // 交换精灵失败时触发 - OnAllEnemiesDefeated EnumEffectTrigger `enum:"OnAllEnemiesDefeated"` // 所有敌方单位被击败时触发 - OnAllAlliesDefeated EnumEffectTrigger `enum:"OnAllAlliesDefeated"` // 所有友方单位被击败时触发 - OnComboHit EnumEffectTrigger `enum:"OnComboHit"` // 连击达到特定次数时触发 - OnMissContinuous EnumEffectTrigger `enum:"OnMissContinuous"` // 连续未命中特定次数时触发 - OnCritContinuous EnumEffectTrigger `enum:"OnCritContinuous"` // 连续暴击特定次数时触发 - OnBeforeFaint EnumEffectTrigger `enum:"OnBeforeFaint"` // 即将昏厥前触发 - OnImmuneDamage EnumEffectTrigger `enum:"OnImmuneDamage"` // 免疫伤害时触发 - OnDamageReflect EnumEffectTrigger `enum:"OnDamageReflect"` // 反弹伤害时触发 - OnAbsorbDamage EnumEffectTrigger `enum:"OnAbsorbDamage"` // 吸收伤害时触发 - OnStealHP EnumEffectTrigger `enum:"OnStealHP"` // 偷取生命值时触发 - OnCopySkill EnumEffectTrigger `enum:"OnCopySkill"` // 复制技能时触发 - OnSkillSealed EnumEffectTrigger `enum:"OnSkillSealed"` // 技能被封印时触发 - OnSkillUnsealed EnumEffectTrigger `enum:"OnSkillUnsealed"` // 技能封印解除时触发 - OnSilenced EnumEffectTrigger `enum:"OnSilenced"` // 被沉默时触发 - OnSilenceEnd EnumEffectTrigger `enum:"OnSilenceEnd"` // 沉默状态结束时触发 - OnStunned EnumEffectTrigger `enum:"OnStunned"` // 被眩晕时触发 - OnStunEnd EnumEffectTrigger `enum:"OnStunEnd"` // 眩晕状态结束时触发 +var BaseEvent = enum.New[struct { + Attack EnumBaseEvent `enum:"attack"` // 攻击事件 + Damage EnumBaseEvent `enum:"damage"` // 伤害事件 + Heal EnumBaseEvent `enum:"heal"` // 治疗事件 + Buff EnumBaseEvent `enum:"buff"` // Buff/状态效果事件 + Turn EnumBaseEvent `enum:"turn"` // 回合开始或结束事件 + Death EnumBaseEvent `enum:"death"` // 死亡事件 + Skill EnumBaseEvent `enum:"skill"` // 技能释放事件 +}]() + +// ================= HookPhase ================= +// EnumHookPhase 定义了事件触发的阶段。 +// 在同一个事件中,某些效果可能需要在事件发生前(Before)触发, +// 也可能需要在事件发生后(After)触发。 +type EnumHookPhase string + +var HookPhase = enum.New[struct { + Before EnumHookPhase `enum:"before"` // 事件发生前触发 + After EnumHookPhase `enum:"after"` // 事件发生后触发 +}]() + +// ================= LifeType ================= +// EnumLifeType 定义了效果(Effect)的生命周期。 +// 用来决定效果是持续多个回合、按次数消耗,还是永久存在。 +type EnumLifeType string + +var LifeType = enum.New[struct { + TurnBased EnumLifeType `enum:"turn_based"` // 按回合数存续(如中毒3回合) + CountBased EnumLifeType `enum:"count_based"` // 按次数存续(如可抵挡2次攻击) + Permanent EnumLifeType `enum:"permanent"` // 永久存在(如种族特性/被动) }]() diff --git a/logic/service/fight/battle/node/t.go b/logic/service/fight/battle/node/t.go new file mode 100644 index 00000000..2972609d --- /dev/null +++ b/logic/service/fight/battle/node/t.go @@ -0,0 +1,233 @@ +package battle + +import "fmt" + +// ==================== 基础类型 ==================== +type BaseEvent string +type HookPhase string +type LifeType string + +const ( + Before HookPhase = "before" + After HookPhase = "after" + + TurnBased LifeType = "turn_based" + CountBased LifeType = "count_based" + Permanent LifeType = "permanent" +) + +type EffectContext struct { + Actor string + Target string + Skill string + Extra map[string]interface{} + Success bool +} + +type Effect struct { + Name string + Trigger string + LifeType LifeType + Duration int + Phase HookPhase + Handler func(ctx *EffectContext) bool +} + +type EffectNode struct { + Name string + Exec func(ctx *EffectContext, next func()) +} + +type EffectManager struct { + nodes []*EffectNode + effects map[string][]*Effect +} + +func NewEffectManager(nodes []*EffectNode) *EffectManager { + return &EffectManager{ + nodes: nodes, + effects: make(map[string][]*Effect), + } +} + +func (m *EffectManager) RegisterEffect(node string, eff *Effect) { + m.effects[node] = append(m.effects[node], eff) +} + +func (m *EffectManager) ExecuteNode(nodeName string, ctx *EffectContext) { + if effs, ok := m.effects[nodeName]; ok { + for _, eff := range effs { + if eff.Handler != nil { + eff.Handler(ctx) + } + } + } +} + +func (m *EffectManager) RunBattle(ctx *EffectContext) { + var i int + var execNext func() + execNext = func() { + if i >= len(m.nodes) { + return + } + node := m.nodes[i] + i++ + node.Exec(ctx, execNext) + } + execNext() +} + +// ==================== 节点定义 ==================== +func BuildBattleNodes() []*EffectNode { + return []*EffectNode{ + {Name: "战斗开始", Exec: func(ctx *EffectContext, next func()) { + fmt.Println("OnBattleStart") + next() + }}, + {Name: "登场/切换", Exec: func(ctx *EffectContext, next func()) { + fmt.Println("OnSwitchIn / OnSwitchOut / OnTransform") + next() + }}, + {Name: "回合开始", Exec: func(ctx *EffectContext, next func()) { + fmt.Println("TurnStart") + next() + }}, + {Name: "操作阶段", Exec: func(ctx *EffectContext, next func()) { + fmt.Println("选择技能 / 使用道具 / 切换") + next() + }}, + {Name: "先手判定", Exec: func(ctx *EffectContext, next func()) { + fmt.Println("先手权判定") + next() + }}, + {Name: "先手出手-前置", Exec: func(ctx *EffectContext, next func()) { + fmt.Println("BeforeUseSkillCheck / BeforeHit / OnMiss") + next() + }}, + {Name: "先手出手-技能命中", Exec: func(ctx *EffectContext, next func()) { + fmt.Println("技能命中判定 / 初始伤害公式 / 红伤数值计算") + next() + }}, + {Name: "先手出手-技能效果结算", Exec: func(ctx *EffectContext, next func()) { + fmt.Println("技能效果结算 / 魂印 / 套装 / 回合类效果") + next() + }}, + {Name: "先手出手-伤害结算", Exec: func(ctx *EffectContext, next func()) { + fmt.Println("最终伤害生效 / 体力扣除") + next() + }}, + {Name: "先手出手-行动结束", Exec: func(ctx *EffectContext, next func()) { + fmt.Println("行动后效果 / 额外行动 / 机盖弹伤 / 出手结束效果") + next() + }}, + {Name: "后手出手", Exec: func(ctx *EffectContext, next func()) { + fmt.Println("后手节点同先手节点") + next() + }}, + {Name: "回合结束后①", Exec: func(ctx *EffectContext, next func()) { + fmt.Println("回合结束后通用时点① / 桃园回血 / 回合扣减①") + next() + }}, + {Name: "回合结束后②", Exec: func(ctx *EffectContext, next func()) { + fmt.Println("回合结束后通用时点② / 战争猎魔 / 16年魂印续航") + next() + }}, + {Name: "死亡判定", Exec: func(ctx *EffectContext, next func()) { + fmt.Println("死亡结算 / 保护机制") + next() + }}, + {Name: "击败/未击败判定", Exec: func(ctx *EffectContext, next func()) { + fmt.Println("击败触发效果 / 未击败触发效果") + next() + }}, + {Name: "进入下回合", Exec: func(ctx *EffectContext, next func()) { + fmt.Println("进入下回合,流程重新开始") + next() + }}, + } +} + +// ==================== 注册45个原始效果 ==================== +func RegisterOriginalEffects(manager *EffectManager) { + // 战斗开始类 + manager.RegisterEffect("战斗开始", &Effect{ + Name: "天生特性", + LifeType: Permanent, + Phase: Before, + Handler: func(ctx *EffectContext) bool { + fmt.Println(ctx.Actor, "天生特性触发") + return true + }, + }) + manager.RegisterEffect("战斗开始", &Effect{ + Name: "战斗开始印记", + LifeType: Permanent, + Phase: Before, + Handler: func(ctx *EffectContext) bool { + fmt.Println(ctx.Actor, "战斗开始印记触发") + return true + }, + }) + + // 登场/切换类 + manager.RegisterEffect("登场/切换", &Effect{ + Name: "登场魂印", + LifeType: CountBased, + Duration: 2, + Phase: Before, + Handler: func(ctx *EffectContext) bool { + fmt.Println(ctx.Actor, "登场魂印触发") + return true + }, + }) + + // 回合开始 + manager.RegisterEffect("回合开始", &Effect{ + Name: "回合开始Buff", + LifeType: TurnBased, + Duration: 3, + Phase: Before, + Handler: func(ctx *EffectContext) bool { + fmt.Println(ctx.Actor, "回合开始Buff生效") + return true + }, + }) + + // 先手出手节点示例 + manager.RegisterEffect("先手出手-前置", &Effect{ + Name: "先手准备效果", + LifeType: CountBased, + Duration: 1, + Phase: Before, + Handler: func(ctx *EffectContext) bool { + fmt.Println(ctx.Actor, "先手前置效果触发") + return true + }, + }) + manager.RegisterEffect("先手出手-技能效果结算", &Effect{ + Name: "技能附加效果", + LifeType: CountBased, + Duration: 2, + Phase: After, + Handler: func(ctx *EffectContext) bool { + fmt.Println(ctx.Actor, "技能附加效果生效") + return true + }, + }) + + // 回合结束后① + manager.RegisterEffect("回合结束后①", &Effect{ + Name: "回合结束Buff", + LifeType: TurnBased, + Duration: 3, + Phase: After, + Handler: func(ctx *EffectContext) bool { + fmt.Println(ctx.Actor, "回合结束后Buff触发") + return true + }, + }) + + // 你可以继续按此格式,将原45个效果依次映射到16节点 + // 节点选择 Before/After,LifeType选择 TurnBased/CountBased/Permanent +} diff --git a/logic/service/fight/battle/skill/effect/EffectContainer.go b/logic/service/fight/battle/skill/effect/EffectContainer.go new file mode 100644 index 00000000..7d6096da --- /dev/null +++ b/logic/service/fight/battle/skill/effect/EffectContainer.go @@ -0,0 +1,148 @@ +package effect + +import ( + "blazing/logic/service/fight/battle/node" + "sort" + + "github.com/tnnmigga/enum" +) + +// ======================== +// 上下文:一次效果执行环境 +// ======================== +type EffectContext struct { + Parent string // 上下文来源(比如 "Skill"、"Buff"、"Passive") + Trigger node.EnumEffectTrigger // 当前触发的节点 + Container *EffectContainer // 效果容器(通常挂在 Actor 身上) + Effect *Effect // 当前正在执行的 Effect + Available bool // 是否可用 + Success bool // 是否执行成功 + Done bool // 是否中止后续执行 +} + +// ======================== +// Effect: 单个效果 +// ======================== +type Effect struct { + ID uint32 // 唯一标识 + Trigger node.EnumEffectTrigger // 触发节点 + Priority int // 执行优先级,数值越大越先执行 + LifeType EnumLifeType //回合效果 是否可持续 继承到下一直精灵 + Duration int // 持续回合/次(0 = 即时生效,>0 = 回合数 ,负数是永久) + Stacks int // 当前层数 + MaxStack int // 最大叠加层数 + Handler func(ctx *EffectContext, next func()) bool // 执行逻辑,返回 true 表示继续保留 //TODO 内部判断是否切换了精灵,是否满足条件 + +} + +// ================= LifeType ================= +type EnumLifeType int + +var LifeType = enum.New[struct { + TurnBased EnumLifeType `enum:"1"` // 回合数限制 + CountBased EnumLifeType `enum:"2"` // 次数限制 +}]() + +// ======================== +// 容器:存放多个效果 +// ======================== +type EffectContainer struct { + GlobalEffects []*Effect // 全局常驻/回合/次数效果 + Effects []*Effect //effects +} + +// 添加效果 +func (c *EffectContainer) AddEffect(e *Effect) { + // 如果已有同 ID 的效果,尝试叠加 + for _, eff := range c.Effects { + if eff.ID == e.ID { + if eff.Stacks < eff.MaxStack { + eff.Stacks++ + } + return + } + } + // 否则新加入 + c.Effects = append(c.Effects, e) +} + +// 添加全局效果 +func (c *EffectContainer) AddGlobalEffects(e *Effect) { + // 如果已有同 ID 的效果,尝试叠加 + for _, eff := range c.GlobalEffects { + if eff.ID == e.ID { + if eff.Stacks < eff.MaxStack { + eff.Stacks++ + } + return + } + } + // 否则新加入 + c.GlobalEffects = append(c.GlobalEffects, e) +} + +// 触发执行 +func (c *EffectContainer) Trigger(trigger node.EnumEffectTrigger, ctx *EffectContext) { + var candidates []*Effect + for _, eff := range c.Effects { + if eff.Trigger == trigger { + candidates = append(candidates, eff) + } + } + + // 按优先级排序 + sort.SliceStable(candidates, func(i, j int) bool { + return candidates[i].Priority > candidates[j].Priority + }) + + // 执行 + for _, eff := range candidates { + ctx.Effect = eff + keep := eff.Apply(ctx) + + if !keep { + // 持续回合结束 / 返回 false 的 effect 删除 + c.removeEffect(eff) + } + + if ctx.Done { + break // 被拦截 + } + } +} + +// 每回合结束时调用,用于处理持续时间 +func (c *EffectContainer) Tick() { + var remain []*Effect + for _, eff := range c.Effects { + if eff.Duration > 0 { + eff.Duration-- + } + if eff.Duration != 0 { // 保留 (负数表示永久) + remain = append(remain, eff) + } + } + c.Effects = remain +} + +// 删除 +func (c *EffectContainer) removeEffect(e *Effect) { + var remain []*Effect + for _, eff := range c.Effects { + if eff != e { + remain = append(remain, eff) + } + } + c.Effects = remain +} + +// 清理过期效果 +func (c *EffectContainer) Cleanup() { + var alive []*Effect + for _, e := range c.Effects { + if e.Duration != 0 { + alive = append(alive, e) + } + } + c.Effects = alive //挂载到普通effect +} diff --git a/logic/service/fight/battle/skill/effect/c.go b/logic/service/fight/battle/skill/effect/c.go deleted file mode 100644 index 0574001a..00000000 --- a/logic/service/fight/battle/skill/effect/c.go +++ /dev/null @@ -1,59 +0,0 @@ -package effect - -import ( - "sort" - - "github.com/badu/bus" -) - -type EffectContainer struct { - ID string - Effects []Effect - Subs []*bus.Listener[*EffectContext] - Battle *Battle - Parent ContextType -} - -func NewEffectContainer(id string, effects []Effect, battle *Battle, parent ContextType) *EffectContainer { - c := &EffectContainer{ - ID: id, - Effects: effects, - Battle: battle, - Parent: parent, - } - // 自动订阅 triggers - for _, e := range effects { - for _, trig := range e.Triggers() { - sub := battle.GetTopic(trig).Sub(func(ctx *EffectContext) { - if ctx.Available && e.Apply != nil { - ctx.Effect = e - c.executeWithPriority([]*EffectContext{ctx}) - } - }) - c.Subs = append(c.Subs, sub) - } - } - return c -} - -// done/next 执行队列,按优先级 -func (c *EffectContainer) executeWithPriority(queue []*EffectContext) { - sort.SliceStable(queue, func(i, j int) bool { - return queue[i].Effect.Priority() > queue[j].Effect.Priority() - }) - var runNext func(idx int) - runNext = func(idx int) { - if idx >= len(queue) { - return - } - ctx := queue[idx] - if ctx.Available { - ctx.Effect.Apply(ctx, func() { - runNext(idx + 1) - }) - } else { - runNext(idx + 1) - } - } - runNext(0) -} diff --git a/logic/service/fight/battle/skill/effect/effecti.go b/logic/service/fight/battle/skill/effect/effecti.go deleted file mode 100644 index 5dba9e8c..00000000 --- a/logic/service/fight/battle/skill/effect/effecti.go +++ /dev/null @@ -1,117 +0,0 @@ -package effect - -import ( - "blazing/logic/service/fight/battle/node" - "sort" -) - -type Effect interface { - Trigger() node.EnumEffectTrigger - Apply(ctx *EffectContext, next func()) - Alive() bool // 是否还有效 - Tick() // 每回合开始/结束时调用,用来减少回合数或次数 - Priority() int // 优先级 -} - -// ======================== -// 上下文:一次效果执行环境 -// ======================== -type EffectContext struct { - Parent string // 上下文来源(比如 "Skill"、"Buff"、"Passive") - Trigger EnumEffectTrigger // 当前触发的节点 - Container *EffectContainer // 效果容器(通常挂在 Actor 身上) - Effect *Effect // 当前正在执行的 Effect - Available bool // 是否可用 - Success bool // 是否执行成功 - Done bool // 是否中止后续执行 -} - -// ======================== -// Effect: 单个效果 -// ======================== -type Effect struct { - ID string // 唯一标识 - Trigger EnumEffectTrigger // 触发节点 - Priority int // 执行优先级,数值越大越先执行 - Duration int // 持续回合(0 = 即时生效,>0 = 回合数) - Stacks int // 当前层数 - MaxStack int // 最大叠加层数 - Apply func(ctx *EffectContext) bool // 执行逻辑,返回 true 表示继续保留 -} - -// ======================== -// 容器:存放多个效果 -// ======================== -type EffectContainer struct { - Effects []*Effect -} - -// 添加效果 -func (c *EffectContainer) AddEffect(e *Effect) { - // 如果已有同 ID 的效果,尝试叠加 - for _, eff := range c.Effects { - if eff.ID == e.ID { - if eff.Stacks < eff.MaxStack { - eff.Stacks++ - } - return - } - } - // 否则新加入 - c.Effects = append(c.Effects, e) -} - -// 触发执行 -func (c *EffectContainer) Trigger(trigger EnumEffectTrigger, ctx *EffectContext) { - var candidates []*Effect - for _, eff := range c.Effects { - if eff.Trigger == trigger { - candidates = append(candidates, eff) - } - } - - // 按优先级排序 - sort.SliceStable(candidates, func(i, j int) bool { - return candidates[i].Priority > candidates[j].Priority - }) - - // 执行 - for _, eff := range candidates { - ctx.Effect = eff - keep := eff.Apply(ctx) - - if !keep { - // 持续回合结束 / 返回 false 的 effect 删除 - c.removeEffect(eff) - } - - if ctx.Done { - break // 被拦截 - } - } -} - -// 每回合结束时调用,用于处理持续时间 -func (c *EffectContainer) Tick() { - var remain []*Effect - for _, eff := range c.Effects { - if eff.Duration > 0 { - eff.Duration-- - } - if eff.Duration != 0 { // 保留 (负数表示永久) - remain = append(remain, eff) - } - } - c.Effects = remain -} - -// 删除 -func (c *EffectContainer) removeEffect(e *Effect) { - var remain []*Effect - for _, eff := range c.Effects { - if eff != e { - remain = append(remain, eff) - } - } - c.Effects = remain -} diff --git a/logic/service/fight/battle/skill/effect/impl/effect1.go b/logic/service/fight/battle/skill/effect/impl/effect1.go index 4f9d22e3..a1d7a70d 100644 --- a/logic/service/fight/battle/skill/effect/impl/effect1.go +++ b/logic/service/fight/battle/skill/effect/impl/effect1.go @@ -1 +1,21 @@ package impl + +import ( + "blazing/logic/service/fight/battle/node" + "blazing/logic/service/fight/battle/skill/effect" + "fmt" +) + +var burn = &effect.Effect{ + Name: "Burn", + Trigger: node.EnumEffectTrigger{ + Event: BaseEvent.Damage, // ✅ 类型安全 + Phase: HookPhase.After, + }, + LifeType: LifeType.TurnBased, + Duration: 3, + Handler: func(ctx *EffectContext, next func()) { + fmt.Printf("[%s] 灼烧 %s\n", ctx.Actor, ctx.Target) + next() + }, +} diff --git a/logic/service/fight/battle/skill/effect/manger.go b/logic/service/fight/battle/skill/effect/manger.go index 14b1f35b..5ba2827e 100644 --- a/logic/service/fight/battle/skill/effect/manger.go +++ b/logic/service/fight/battle/skill/effect/manger.go @@ -1,46 +1,76 @@ package effect -import "blazing/logic/service/fight/battle/node" +import ( + "blazing/logic/service/fight/battle/node" + + "github.com/tnnmigga/enum" +) type EffectManager struct { - effects []Effect + containers map[string]*EffectContainer } func NewEffectManager() *EffectManager { - return &EffectManager{} + return &EffectManager{ + containers: make(map[string]*EffectContainer), + } } -func (m *EffectManager) Register(e Effect) { - m.effects = append(m.effects, e) +// 添加效果 +func (m *EffectManager) AddEffect(owner string, e *Effect) { + if _, ok := m.containers[owner]; !ok { + m.containers[owner] = &EffectContainer{} + } + m.containers[owner].AddEffect(e) } -// 执行某时点效果 -func (m *EffectManager) Apply(trigger node.EnumEffectTrigger, ctx *EffectContext) { - var next func(i int) - next = func(i int) { - if i < len(m.effects) { - if m.effects[i].Trigger() == trigger { - m.effects[i].Apply(ctx, func() { next(i + 1) }) - } else { - next(i + 1) +// 触发事件,按顺序链式执行效果 +func (m *EffectManager) Trigger(owner string, trigger node.EnumEffectTrigger, ctx *EffectContext) { + container, ok := m.containers[owner] + if !ok { + return + } + + var idx int + var next func() + next = func() { + if idx >= len(container.Effects) { + return + } + e := container.Effects[idx] + idx++ + // 判断触发器匹配 + if e.Trigger == trigger { + e.Handler(ctx, next) + if e.LifeType == e.LifeType { + e.Duration-- } + } else { + // 不匹配直接跳过 + next() } } - next(0) - // 清理过期效果 - var alive []Effect - for _, e := range m.effects { - if e.Alive() { - alive = append(alive, e) - } - } - m.effects = alive + next() + container.Cleanup() } -// 回合 tick -func (m *EffectManager) Tick() { - for _, e := range m.effects { - e.Tick() - } -} +type EnumBaseEvent string + +var BaseEvent = enum.New[struct { + Attack EnumBaseEvent `enum:"attack"` + Damage EnumBaseEvent `enum:"damage"` + Heal EnumBaseEvent `enum:"heal"` + Buff EnumBaseEvent `enum:"buff"` + Turn EnumBaseEvent `enum:"turn"` + Death EnumBaseEvent `enum:"death"` + Skill EnumBaseEvent `enum:"skill"` +}]() + +// ================= HookPhase ================= +type EnumHookPhase string + +var HookPhase = enum.New[struct { + Before EnumHookPhase `enum:"before"` + After EnumHookPhase `enum:"after"` +}]()