package effect import ( "fmt" "sort" "github.com/badu/bus" "github.com/tnnmigga/enum" ) // ======================== // BattleMode 枚举 // ======================== type EnumBattleMode string var BattleMode = enum.New[struct { PVE EnumBattleMode `enum:"3"` PVP EnumBattleMode `enum:"1"` }]() // ======================== // Effect 框架 // ======================== type ContextType interface { SourceID() string } type EffectContext struct { Parent ContextType Trigger EnumEffectTrigger Container *EffectContainer Effect *Effect Available bool Success bool Done bool } func (c *EffectContext) Stop() { c.Done = true } func (c *EffectContext) SourceID() string { if c.Container != nil { return c.Container.ID } return "unknown" } type EffectFunc func(ctx *EffectContext, next func()) type Effect struct { ID string Priority int Triggers []EnumEffectTrigger Condition func(*EffectContext) bool Apply EffectFunc } 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) } // ======================== // Battle // ======================== type Battle struct { Turn int topics map[EnumEffectTrigger]*bus.Topic[*EffectContext] } func NewBattle() *Battle { allTriggers := []EnumEffectTrigger{ EffectTrigger.OnBattleStart, EffectTrigger.BeforeSort, EffectTrigger.BeforeUseSkillCheck, EffectTrigger.AfterUseSkillCheck, EffectTrigger.BeforeMultiHit, EffectTrigger.BeforeHit, EffectTrigger.OnCritPreDamage, EffectTrigger.PreDamage, EffectTrigger.OnHit, EffectTrigger.OnMiss, EffectTrigger.AfterAttacked, EffectTrigger.OnDefeat, EffectTrigger.SkillUseEnd, EffectTrigger.OnBeforeCalculateDamage, EffectTrigger.OnDamage, EffectTrigger.Shield, EffectTrigger.PostDamage, EffectTrigger.OnCritPostDamage, EffectTrigger.OnTransform, EffectTrigger.OnTransformEnd, EffectTrigger.BeforeTransform, EffectTrigger.AfterTransform, EffectTrigger.TurnStart, EffectTrigger.TurnEnd, EffectTrigger.OnBeforeAddMark, EffectTrigger.OnAnyMarkAdded, EffectTrigger.OnRemoveMark, EffectTrigger.OnMarkCreated, EffectTrigger.OnMarkDestroy, EffectTrigger.OnMarkDurationEnd, EffectTrigger.OnStackBefore, EffectTrigger.OnStack, EffectTrigger.OnBeforeConsumeStack, EffectTrigger.OnConsumeStack, EffectTrigger.OnBeforeHeal, EffectTrigger.OnHeal, EffectTrigger.BeforeRageGain, EffectTrigger.BeforeRageLoss, EffectTrigger.OnRageGain, EffectTrigger.OnRageLoss, EffectTrigger.OnSwitchIn, EffectTrigger.OnSwitchOut, EffectTrigger.OnOwnerSwitchIn, EffectTrigger.OnOwnerSwitchOut, EffectTrigger.BeforeEffect, EffectTrigger.AfterEffect, } topics := make(map[EnumEffectTrigger]*bus.Topic[*EffectContext]) for _, trig := range allTriggers { topics[trig] = bus.NewTopic[*EffectContext]() } return &Battle{Turn: 0, topics: topics} } func (b *Battle) GetTopic(trig EnumEffectTrigger) *bus.Topic[*EffectContext] { return b.topics[trig] } func (b *Battle) NextTurn(containers []*EffectContainer) { b.Turn++ fmt.Printf("=== 回合 %d 开始 ===\n", b.Turn) b.PublishTrigger(EffectTrigger.TurnStart, containers) fmt.Println("=== 玩家操作阶段 ===") b.PublishTrigger(EffectTrigger.TurnEnd, containers) fmt.Printf("=== 回合 %d 结束 ===\n\n", b.Turn) } func (b *Battle) PublishTrigger(trigger EnumEffectTrigger, containers []*EffectContainer) { for _, c := range containers { for _, e := range c.Effects { for _, t := range e.Triggers { if t == trigger { ctx := &EffectContext{ Parent: c.Parent, Trigger: trigger, Container: c, Effect: e, Available: true, } b.GetTopic(trigger).Pub(ctx) } } } } } // ======================== // 示例 // ======================== type Player struct { ID string } func (p *Player) SourceID() string { return p.ID }