refactor(fight): 重构随机数生成器模块并优化战斗技能PP管理
This commit is contained in:
@@ -1,140 +0,0 @@
|
|||||||
package node
|
|
||||||
|
|
||||||
import "fmt"
|
|
||||||
|
|
||||||
// 基础上下文
|
|
||||||
type EffectContext struct {
|
|
||||||
Turn int // 当前回合数
|
|
||||||
Actor string // 当前行动者(谁在出手)
|
|
||||||
Target string // 当前目标(技能攻击对象)
|
|
||||||
Skill string // 使用的技能
|
|
||||||
Extra map[string]interface{} // 临时附加信息(状态、标记、计算中间值等)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 节点类型
|
|
||||||
type NodeFunc func(ctx *EffectContext, next func())
|
|
||||||
|
|
||||||
type EffectNode struct {
|
|
||||||
Name string
|
|
||||||
Exec NodeFunc
|
|
||||||
}
|
|
||||||
|
|
||||||
// 节点管理器
|
|
||||||
type NodeRunner struct {
|
|
||||||
nodes []*EffectNode
|
|
||||||
index int
|
|
||||||
ctx *EffectContext
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewNodeRunner(ctx *EffectContext, nodes []*EffectNode) *NodeRunner {
|
|
||||||
return &NodeRunner{
|
|
||||||
nodes: nodes,
|
|
||||||
index: 0,
|
|
||||||
ctx: ctx,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 执行下一个节点
|
|
||||||
func (r *NodeRunner) Run() {
|
|
||||||
if r.index >= len(r.nodes) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
current := r.nodes[r.index]
|
|
||||||
r.index++
|
|
||||||
current.Exec(r.ctx, r.Run)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 跳过当前节点
|
|
||||||
func (r *NodeRunner) Skip() {
|
|
||||||
r.index++
|
|
||||||
r.Run()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------
|
|
||||||
// 定义战斗流程节点
|
|
||||||
// ------------------------
|
|
||||||
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()
|
|
||||||
}},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------
|
|
||||||
// 测试运行
|
|
||||||
// ------------------------
|
|
||||||
func TestBattleFlow() {
|
|
||||||
ctx := &EffectContext{
|
|
||||||
Turn: 1,
|
|
||||||
Actor: "PlayerA",
|
|
||||||
Target: "PlayerB",
|
|
||||||
Skill: "火球",
|
|
||||||
Extra: map[string]interface{}{},
|
|
||||||
}
|
|
||||||
|
|
||||||
nodes := BuildBattleNodes()
|
|
||||||
runner := NewNodeRunner(ctx, nodes)
|
|
||||||
runner.Run()
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
package node
|
|
||||||
|
|
||||||
import "github.com/tnnmigga/enum"
|
|
||||||
|
|
||||||
// ================= BaseEvent =================
|
|
||||||
// EnumBaseEvent 定义了战斗中可能触发的基础事件类型。
|
|
||||||
// 这些事件通常作为 Effect 的触发点,例如攻击前、受到伤害后等。
|
|
||||||
type EnumBaseEvent string
|
|
||||||
|
|
||||||
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"` // 永久存在(如种族特性/被动)
|
|
||||||
}]()
|
|
||||||
@@ -1,233 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
package over
|
|
||||||
|
|
||||||
import "sync"
|
|
||||||
|
|
||||||
// 战斗结束原因池,用于管理战斗结束的各种原因数据
|
|
||||||
type BattleOverPool struct {
|
|
||||||
dataMap map[EnumBattleOverReason]BattleOverData
|
|
||||||
size int
|
|
||||||
value BattleOverData
|
|
||||||
mutex sync.RWMutex // 用于并发安全
|
|
||||||
}
|
|
||||||
|
|
||||||
// 初始化战斗结束原因池
|
|
||||||
func NewBattleOverPool() *BattleOverPool {
|
|
||||||
return &BattleOverPool{
|
|
||||||
dataMap: make(map[EnumBattleOverReason]BattleOverData),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加战斗结束原因
|
|
||||||
func (p *BattleOverPool) PushReason(reason EnumBattleOverReason, data BattleOverData) {
|
|
||||||
p.mutex.Lock()
|
|
||||||
defer p.mutex.Unlock()
|
|
||||||
|
|
||||||
p.dataMap[reason] = data
|
|
||||||
p.value = data
|
|
||||||
p.size++
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取并移除指定的战斗结束原因
|
|
||||||
func (p *BattleOverPool) PopReason(reason EnumBattleOverReason) BattleOverData {
|
|
||||||
p.mutex.Lock()
|
|
||||||
defer p.mutex.Unlock()
|
|
||||||
|
|
||||||
data, exists := p.dataMap[reason]
|
|
||||||
if exists {
|
|
||||||
delete(p.dataMap, reason)
|
|
||||||
p.size--
|
|
||||||
}
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取并移除所有战斗结束原因
|
|
||||||
func (p *BattleOverPool) PopReasons() []BattleOverData {
|
|
||||||
p.mutex.Lock()
|
|
||||||
defer p.mutex.Unlock()
|
|
||||||
|
|
||||||
reasons := make([]BattleOverData, 0, p.size)
|
|
||||||
for _, data := range p.dataMap {
|
|
||||||
reasons = append(reasons, data)
|
|
||||||
}
|
|
||||||
p.dataMap = make(map[EnumBattleOverReason]BattleOverData)
|
|
||||||
p.size = 0
|
|
||||||
p.value = nil
|
|
||||||
return reasons
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取最后添加的战斗结束原因
|
|
||||||
func (p *BattleOverPool) PopReasonLast() BattleOverData {
|
|
||||||
p.mutex.Lock()
|
|
||||||
defer p.mutex.Unlock()
|
|
||||||
|
|
||||||
data := p.value
|
|
||||||
p.value = nil
|
|
||||||
if p.size > 0 {
|
|
||||||
p.size--
|
|
||||||
}
|
|
||||||
// 清空map
|
|
||||||
if p.size == 0 {
|
|
||||||
p.dataMap = make(map[EnumBattleOverReason]BattleOverData)
|
|
||||||
}
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
|
|
||||||
// 判断战斗是否应该结束
|
|
||||||
func (p *BattleOverPool) IsShouldOver() bool {
|
|
||||||
p.mutex.RLock()
|
|
||||||
defer p.mutex.RUnlock()
|
|
||||||
return p.size > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取当前战斗结束原因的数量
|
|
||||||
func (p *BattleOverPool) Size() int {
|
|
||||||
p.mutex.RLock()
|
|
||||||
defer p.mutex.RUnlock()
|
|
||||||
return p.size
|
|
||||||
}
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
package over
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/tnnmigga/enum"
|
|
||||||
)
|
|
||||||
|
|
||||||
// 战斗结束原因数据接口
|
|
||||||
type BattleOverData interface{}
|
|
||||||
|
|
||||||
// 玩家离线数据
|
|
||||||
type PlayerOfflineData struct {
|
|
||||||
// 可以根据需要添加字段
|
|
||||||
PlayerID int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// 玩家逃脱数据
|
|
||||||
type PlayerEscapeData struct {
|
|
||||||
// 可以根据需要添加字段
|
|
||||||
PlayerID int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// 玩家捕获成功数据
|
|
||||||
type PlayerCaptureSuccessData struct {
|
|
||||||
// 可以根据需要添加字段
|
|
||||||
CaptorID int64
|
|
||||||
TargetID int64
|
|
||||||
CaptureTime int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// 默认结束数据
|
|
||||||
type DefaultEndData struct {
|
|
||||||
// 可以根据需要添加字段
|
|
||||||
Reason string
|
|
||||||
}
|
|
||||||
|
|
||||||
// 战斗结束原因枚举
|
|
||||||
type EnumBattleOverReason int
|
|
||||||
|
|
||||||
var BattleOverReason = enum.New[struct {
|
|
||||||
PlayerOffline EnumBattleOverReason `enum:"1"` //掉线
|
|
||||||
PlayerEscape EnumBattleOverReason `enum:"2"` //逃跑
|
|
||||||
PlayerCaptureSuccess EnumBattleOverReason `enum:"3"` //捕捉成功
|
|
||||||
DefaultEnd EnumBattleOverReason `enum:"4"` //默认结束
|
|
||||||
}]()
|
|
||||||
|
|
||||||
// 获取对应的类型
|
|
||||||
func (e EnumBattleOverReason) DataType() interface{} {
|
|
||||||
switch e {
|
|
||||||
case BattleOverReason.PlayerOffline:
|
|
||||||
return PlayerOfflineData{}
|
|
||||||
case BattleOverReason.PlayerEscape:
|
|
||||||
return PlayerEscapeData{}
|
|
||||||
case BattleOverReason.PlayerCaptureSuccess:
|
|
||||||
return PlayerCaptureSuccessData{}
|
|
||||||
case BattleOverReason.DefaultEnd:
|
|
||||||
return DefaultEndData{}
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,148 +0,0 @@
|
|||||||
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 实际上全局就是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) 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
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
package base
|
|
||||||
|
|
||||||
import (
|
|
||||||
"blazing/logic/service/fight/battle/node"
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
type BurnEffect struct {
|
|
||||||
life LifeCycle
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewBurnEffect(turns int) *BurnEffect {
|
|
||||||
return &BurnEffect{life: NewTurnLife(turns)}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *BurnEffect) Trigger() node.EnumEffectTrigger {
|
|
||||||
return node.EffectTrigger.TurnEnd // 每回合结束触发掉血
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *BurnEffect) Apply(ctx *node.EffectContext, next func()) {
|
|
||||||
fmt.Printf("[%s] 在回合结束时受灼烧伤害!\n", ctx.Target)
|
|
||||||
b.life.Use() // 消耗一次触发次数(如果你定义为按次数存活)
|
|
||||||
next()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *BurnEffect) Tick() {
|
|
||||||
b.life.Tick()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *BurnEffect) Alive() bool {
|
|
||||||
return b.life.Alive()
|
|
||||||
}
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
package effect
|
|
||||||
|
|
||||||
import (
|
|
||||||
"blazing/logic/service/fight/battle/node"
|
|
||||||
|
|
||||||
"github.com/tnnmigga/enum"
|
|
||||||
)
|
|
||||||
|
|
||||||
type EffectManager struct {
|
|
||||||
containers map[string]*EffectContainer
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewEffectManager() *EffectManager {
|
|
||||||
return &EffectManager{
|
|
||||||
containers: make(map[string]*EffectContainer),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加效果
|
|
||||||
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) 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()
|
|
||||||
container.Cleanup()
|
|
||||||
}
|
|
||||||
|
|
||||||
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"`
|
|
||||||
}]()
|
|
||||||
@@ -3,7 +3,8 @@ package info
|
|||||||
import (
|
import (
|
||||||
element "blazing/common/data/Element"
|
element "blazing/common/data/Element"
|
||||||
"blazing/common/data/xml/skill"
|
"blazing/common/data/xml/skill"
|
||||||
"blazing/logic/service/fight/battle/random"
|
"blazing/common/utils/random"
|
||||||
|
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -103,41 +104,6 @@ func (s *BattleSkillEntity) Type() element.ElementType {
|
|||||||
return element.ElementType(s.Move.Type)
|
return element.ElementType(s.Move.Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UseOnce 使用一次技能(消耗1点PP)
|
|
||||||
func (s *BattleSkillEntity) UseOnce() *BattleSkillEntity {
|
|
||||||
if !s.InfinityPP {
|
|
||||||
s.PP--
|
|
||||||
s.correctPP()
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddPP 增加PP值
|
|
||||||
func (s *BattleSkillEntity) AddPP(value int) *BattleSkillEntity {
|
|
||||||
if !s.InfinityPP {
|
|
||||||
s.PP += value
|
|
||||||
s.correctPP()
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
// MinusPP 减少PP值
|
|
||||||
func (s *BattleSkillEntity) MinusPP(value int) *BattleSkillEntity {
|
|
||||||
if !s.InfinityPP {
|
|
||||||
s.PP -= value
|
|
||||||
s.correctPP()
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
// 修正PP值,确保在0到MaxPP之间
|
|
||||||
func (s *BattleSkillEntity) correctPP() {
|
|
||||||
if s.PP < 0 {
|
|
||||||
s.PP = 0
|
|
||||||
} else if s.PP > s.MaxPP {
|
|
||||||
s.PP = s.MaxPP
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func (u *BattleSkillEntity) NewBattleAction(ctx context.Context) {
|
func (u *BattleSkillEntity) NewBattleAction(ctx context.Context) {
|
||||||
|
|
||||||
ret := BattleAction{}
|
ret := BattleAction{}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package info
|
package info
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"blazing/logic/service/fight/battle/random"
|
"blazing/common/utils/random"
|
||||||
|
|
||||||
"github.com/tnnmigga/enum"
|
"github.com/tnnmigga/enum"
|
||||||
)
|
)
|
||||||
@@ -21,3 +21,39 @@ var BattleMode = enum.New[struct {
|
|||||||
PVE EnumBattleMode `enum:"3"`
|
PVE EnumBattleMode `enum:"3"`
|
||||||
PVP EnumBattleMode `enum:"1"`
|
PVP EnumBattleMode `enum:"1"`
|
||||||
}]()
|
}]()
|
||||||
|
|
||||||
|
// 玩家离线数据
|
||||||
|
type PlayerOfflineData struct {
|
||||||
|
// 可以根据需要添加字段
|
||||||
|
PlayerID int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// 玩家逃脱数据
|
||||||
|
type PlayerEscapeData struct {
|
||||||
|
// 可以根据需要添加字段
|
||||||
|
PlayerID int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// 玩家捕获成功数据
|
||||||
|
type PlayerCaptureSuccessData struct {
|
||||||
|
// 可以根据需要添加字段
|
||||||
|
CaptorID int64
|
||||||
|
TargetID int64
|
||||||
|
CaptureTime int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// 默认结束数据
|
||||||
|
type DefaultEndData struct {
|
||||||
|
// 可以根据需要添加字段
|
||||||
|
Reason string
|
||||||
|
}
|
||||||
|
|
||||||
|
// 战斗结束原因枚举
|
||||||
|
type EnumBattleOverReason int
|
||||||
|
|
||||||
|
var BattleOverReason = enum.New[struct {
|
||||||
|
PlayerOffline EnumBattleOverReason `enum:"1"` //掉线
|
||||||
|
PlayerEscape EnumBattleOverReason `enum:"2"` //逃跑
|
||||||
|
PlayerCaptureSuccess EnumBattleOverReason `enum:"3"` //捕捉成功
|
||||||
|
DefaultEnd EnumBattleOverReason `enum:"4"` //默认结束
|
||||||
|
}]()
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package start
|
package fight
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
Reference in New Issue
Block a user