Files
bl/logic/service/fight/input.go
昔念 e54d4bacaa ```
feat(fight): 增加战斗模式枚举并重构战斗逻辑判断

- 引入完整的 BattleMode 枚举定义,替代原有的 BattleStatus,明确区分各类战斗场景
- 在多个控制器中替换对旧 Status 字段的依赖,统一使用 Mode 判断战斗状态
- 修复部分函数调用前未检查 FightC 是否为空的问题,增加 ErrBattleEnded 错误返回
- 调整
2025-11-21 02:40:27 +08:00

300 lines
7.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package fight
import (
"blazing/common/socket/errorcode"
"blazing/cool"
"fmt"
"blazing/logic/service/common"
"blazing/logic/service/fight/action"
"blazing/logic/service/fight/info"
"blazing/logic/service/fight/input"
"blazing/modules/blazing/model"
"math/rand"
"sync"
"time"
"github.com/jinzhu/copier"
)
type FightC struct {
ReadyInfo info.NoteReadyToFightInfo
Info info.Fightinfo
IsReady bool
ownerID uint32 // 战斗发起者ID
Our *input.Input //始终等于房主ID
Opp *input.Input //对手ID
Switch []*action.ActiveSwitchAction
startl sync.Once
rand *rand.Rand
StartTime time.Time
actionChan chan action.BattleActionI // 所有操作统一从这里进入
Round int //回合数
quit chan struct{}
over chan struct{}
First *input.Input
Second *input.Input
closefight bool
overl sync.Once
waittime int
info.FightOverInfo
//战斗结束的插装
callback func(*info.FightOverInfo)
}
func (f *FightC) Ownerid() uint32 {
return f.ownerID
}
func (f *FightC) GetInputByPlayer(c common.PlayerI, isOpposite bool) *input.Input {
// 判断当前玩家是否为我方玩家
isOurPlayer := c.GetInfo().UserID == f.ownerID
// 当isOurPlayer与isOpposite值不同时返回我方相同时返回对方
if isOurPlayer != isOpposite {
return f.Our
}
return f.Opp
}
func (f *FightC) GetInputByAction(c action.BattleActionI, isOpposite bool) *input.Input {
// 判断动作所属玩家是否为我方
isOurAction := c.GetPlayerID() == f.Our.Player.GetInfo().UserID
// 根据isOpposite决定是否返回相反方向的输入
if isOurAction == !isOpposite {
return f.Our
}
return f.Opp
}
// 玩家使用技能
func (f *FightC) GetCurrPET(c common.PlayerI) *info.BattlePetEntity {
if f.Our.Player.GetInfo().UserID == c.GetInfo().UserID {
return f.Our.CurrentPet
} else {
return f.Opp.CurrentPet
}
}
func (f *FightC) GetOpp(c common.PlayerI) *input.Input {
return f.GetInputByPlayer(c, true)
}
// 获取随机数
func (f *FightC) GetRand() *rand.Rand {
return f.rand
}
// 获取随机数
func (f *FightC) IsFirst(play common.PlayerI) bool {
return f.First.Player == play
}
// 加载进度
func (f *FightC) LoadPercent(c common.PlayerI, percent int32) {
f.GetInputByPlayer(c, true).Player.SendPackCmd(2441, &info.LoadPercentOutboundInfo{
Id: c.GetInfo().UserID,
Percent: uint32(percent),
})
}
func (f *FightC) initplayer(c common.PlayerI) (*input.Input, errorcode.ErrorCode) {
if !c.CanFight() {
return nil, errorcode.ErrorCodes.ErrNoEligiblePokemon
}
in := input.NewInput(f, c)
in.AllPet = make([]*info.BattlePetEntity, 0)
in.InitAttackValue()
for i := 0; i < len(c.GetInfo().PetList); i++ {
in.AllPet = append(in.AllPet, info.CreateBattlePetEntity(c.GetInfo().PetList[i], f.rand))
}
in.SortPet()
switch f.Info.Mode {
case info.BattleMode.SINGLE_MODE:
in.AllPet = in.AllPet[:1]
case info.BattleMode.PET_MELEE:
in.AllPet = make([]*info.BattlePetEntity, 0)
for _, v := range RandomElfIDs(3) {
p := model.GenPetInfo(v, 24, -1, -1, -1, 100)
//p.CatchTime = uint32(v)
p.Update()
p = model.GenPetInfo(int(p.ID), 24, -1, -1, -1, 100)
//p.CalculatePetPane()
p.CatchTime = uint32(v)
in.AllPet = append(in.AllPet, info.CreateBattlePetEntity(*p, f.rand))
}
//in.AllPet = in.AllPet[:3]
default:
}
in.CurrentPet = in.AllPet[0]
return in, 0
}
// RandomElfIDs 从1-2000中随机抽取n个不重复的精灵ID
func RandomElfIDs(n int) []int {
if n <= 0 || n > 2000 {
return nil
}
// 用map记录已抽取的ID避免重复
used := make(map[int]struct{}, n)
ids := make([]int, 0, n)
for len(ids) < n {
// 生成1-2000的随机数
id := rand.Intn(2000) + 1 // rand.Intn(2000)生成0-1999+1后为1-2000
// 检查是否已抽取
if _, exists := used[id]; !exists {
used[id] = struct{}{}
ids = append(ids, id)
}
}
return ids
}
func initfightready(in *input.Input) (info.FightUserInfo, []info.ReadyFightPetInfo) {
t := make([]info.ReadyFightPetInfo, len(in.AllPet))
userindo := info.FightUserInfo{
UserID: in.UserID,
Nick: in.Player.GetInfo().Nick,
}
for i := 0; i < len(in.AllPet); i++ {
err := copier.CopyWithOption(&t[i], &in.AllPet[i].Info, copier.Option{IgnoreEmpty: true, DeepCopy: true})
if err != nil {
panic(err)
}
}
return userindo, t
}
// 创建新战斗,邀请方和被邀请方,或者玩家和野怪方
func NewFight(p1, p2 common.PlayerI, fn func(*info.FightOverInfo)) (*FightC, errorcode.ErrorCode) {
fmt.Println("NewFight", p1.GetInfo().UserID)
f := &FightC{}
f.ownerID = p1.GetInfo().UserID
f.callback = fn //战斗结束的回调
f.quit = make(chan struct{})
f.over = make(chan struct{})
f.StartTime = time.Now()
seed := f.StartTime.UnixNano() ^ int64(p1.GetInfo().UserID) ^ int64(p2.GetInfo().UserID) // ^ int64(f.Round) // 用异或运算混合多维度信息
f.rand = rand.New(rand.NewSource(seed))
f.Info = p1.Getfightinfo()
//这里应该挪到玩家初始化执行
f.ReadyInfo.Status = f.Info.Status
var err errorcode.ErrorCode
f.Our, err = f.initplayer(p1)
if err > 0 {
return nil, err
}
f.Opp, err = f.initplayer(p2)
if err > 0 {
return nil, err
}
f.ReadyInfo.OurInfo, f.ReadyInfo.OurPetList = initfightready(f.Our)
f.ReadyInfo.OpponentInfo, f.ReadyInfo.OpponentPetList = initfightready(f.Opp)
var loadtime time.Duration = 120 * time.Second
//说明是PVE
if f.Info.Mode == info.BattleMode.FIGHT_WITH_NPC {
f.Opp.Finished = true //PVE 默认boss数据直接加载完成
loadtime = 60 * time.Second
}
f.Broadcast(func(ff *input.Input) {
ff.SetOPP(f.GetInputByPlayer(ff.Player, true))
})
f.Broadcast(func(ff *input.Input) {
ff.Player.SendPackCmd(2503, &f.ReadyInfo)
})
cool.Cron.AfterFunc(loadtime, func() {
if !f.Our.Finished || !f.Opp.Finished { //如果有任一没有加载完成
f.closefight = true //阻止继续添加action
f.Reason = info.BattleOverReason.PlayerOVerTime
switch {
case !f.Opp.Finished: //邀请方没加载完成 先判断邀请方,如果都没加载完成,就算做房主胜利
f.WinnerId = f.Our.Player.GetInfo().UserID
case !f.Our.Finished: //被邀请方没加载完成
f.WinnerId = f.Opp.Player.GetInfo().UserID
}
f.Broadcast(func(ff *input.Input) {
//todo 将血量和技能pp传回enterturn
ff.Player.SendPackCmd(2506, &f.FightOverInfo)
ff.Player.QuitFight()
})
}
})
return f, 0
}
// 被击败的ID
func (b *FightC) IsWin(c *input.Input, cache uint32) bool {
var tt []*info.BattlePetEntity
bbb := b.Our.AllPet
if c.Player.GetInfo().UserID == b.ownerID { //如果是房主
bbb = b.Opp.AllPet
}
for _, v := range bbb {
if v.Info.CatchTime == cache {
v.NotAlive = true
}
tt = append(tt, v)
}
for _, v := range tt {
if !v.NotAlive { //如果存活
return false
}
}
return true
}
// 广播,并是否结束回合
func (f *FightC) Broadcast(t func(ff *input.Input)) {
t(f.Our)
t(f.Opp)
}
func (f *FightC) GetOverChan() chan struct{} {
return f.over
}