refactor(fight): 重构效果系统

- 重新定义了基础事件类型和效果触发时机
- 优化了效果的结构和执行逻辑
- 添加了效果生命周期的管理
- 调整了效果注册和触发的方式
This commit is contained in:
2025-08-25 05:28:08 +08:00
parent 5ba81e2f90
commit ada45feb01
7 changed files with 494 additions and 302 deletions

View File

@@ -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"` // 永久存在(如种族特性/被动)
}]()

View File

@@ -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/AfterLifeType选择 TurnBased/CountBased/Permanent
}

View File

@@ -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
}

View File

@@ -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)
}

View File

@@ -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
}

View File

@@ -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()
},
}

View File

@@ -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"`
}]()