Files
bl/logic/service/fight/input.go
昔念 937f97fe83 ```
feat(go): 升级 Go 版本至 1.20

统一将所有模块的 Go 版本从 1.18 或 1.19 升级到 1.20,以使用最新的语言特性和性能改进。

feat(service): 新增乱斗服务默认宠物生成逻辑

在 fight 模块中调用新的 MELEEService.Def() 方法来生成初始对战宠物,
并根据配置
2025-12-15 14:26:24 +08:00

401 lines
9.3 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/data/xmlres"
"blazing/common/socket/errorcode"
"blazing/common/utils"
"blazing/cool"
"blazing/modules/blazing/model"
"blazing/modules/blazing/service"
"fmt"
"blazing/logic/service/common"
"blazing/logic/service/fight/action"
"blazing/logic/service/fight/info"
"blazing/logic/service/fight/input"
"blazing/logic/service/player"
"blazing/logic/service/user"
"math/rand"
"sync"
"time"
"github.com/gogf/gf/v2/util/grand"
"github.com/jinzhu/copier"
)
type FightC struct {
//准备战斗信息
ReadyInfo info.NoteReadyToFightInfo
//开始战斗信息
info.FightStartOutboundInfo
Info info.Fightinfo
IsReady bool
ownerID uint32 // 战斗发起者ID
Our *input.Input //始终等于房主ID
Opp *input.Input //对手ID
Switch map[uint32]*action.ActiveSwitchAction
startl sync.Once
rand *rand.Rand
StartTime time.Time
actionChan chan action.BattleActionI // 所有操作统一从这里进入
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) Chat(c common.PlayerI, msg string) {
f.GetInputByPlayer(c, true).Player.SendPackCmd(50002, &user.ChatOutboundInfo{
SenderId: c.GetInfo().UserID,
SenderNickname: c.GetInfo().Nick,
Message: utils.RemoveLast(msg),
})
}
// 加载进度
func (f *FightC) LoadPercent(c common.PlayerI, percent int32) {
if f.Info.Mode == info.BattleMode.PET_MELEE {
return
}
if f.Info.Status == info.BattleMode.FIGHT_WITH_NPC {
return
}
f.GetInputByPlayer(c, true).Player.SendPackCmd(2441, &info.LoadPercentOutboundInfo{
Id: c.GetInfo().UserID,
Percent: uint32(percent),
})
}
var meetpet = make(map[int]model.PetInfo)
func initmeetpet() {
meetpet = make(map[int]model.PetInfo)
for i, v := range xmlres.PetMAP {
if v.EvolvesTo != 0 {
continue
}
if v.EvolvFlag != 0 {
continue
}
if v.ID > 2000 {
continue
}
r := model.GenPetInfo(int(v.ID), 24, -1, -1, 100, nil)
meetpet[i] = *r
}
}
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)
if len(meetpet) == 0 {
initmeetpet()
}
r := service.NewMELEEService().Def()
for i, v := range r {
if v.Lv == 0 {
v.Lv = 100
}
// var effect int
// if len(v.Effect) > 0 {
// effect = int(v.Effect[0])
// }
pet := model.GenPetInfo(int(v.MonID), 24, int(v.Nature), int(v.Effect[0]), int(v.Lv), nil)
if v.Color != nil {
pet.ShinyInfo = append(pet.ShinyInfo, *v.Color)
}
if len(v.Prop) == 5 {
pet.Prop = [5]uint32(v.Prop)
}
if len(v.SKill) != 0 {
for i := 0; i < 4; i++ {
if v.SKill[i] != 0 {
pet.SkillList[i].ID = v.SKill[i]
}
}
}
pet.CatchTime = c.GetInfo().UserID + uint32(i)*1000000
pet.Cure()
in.AllPet = append(in.AllPet, info.CreateBattlePetEntity(*pet, f.rand))
}
// for i, v := range meetpet {
// v1 := v
// if len(in.AllPet) > 2 {
// break
// }
// v1.CatchTime = c.GetInfo().UserID + uint32(i)*1000000
// v1.Cure()
// in.AllPet = append(in.AllPet, info.CreateBattlePetEntity(v1, 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 := grand.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
// 1. 构建战斗开始信息(整理双方初始宠物信息)
f.Switch = make(map[uint32]*action.ActiveSwitchAction)
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
f.Broadcast(func(ff *input.Input) {
ff.SetOPP(f.GetInputByPlayer(ff.Player, true))
})
f.FightStartOutboundInfo = f.buildFightStartInfo()
if f.Info.Status == info.BattleMode.FIGHT_WITH_NPC {
f.Opp.Finished = true //PVE 默认boss数据直接加载完成
loadtime = 60 * time.Second
//f.handleNPCFightSpecial(&fightStartInfo)
if f.Opp.Player.(*player.AI_player).CanCapture > 0 {
f.Opp.CanCapture = f.Opp.Player.(*player.AI_player).CanCapture
f.FightStartOutboundInfo.Info2.Catchable = 1 //可以捕捉就置1
}
f.Opp.AttackValue.Prop = f.Opp.Player.(*player.AI_player).Prop
f.FightStartOutboundInfo.Info2.Prop = f.Opp.AttackValue.Prop
}
f.Broadcast(func(ff *input.Input) {
fmt.Println("战斗开始信息", ff.UserID)
ff.Player.SendPackCmd(2503, &f.ReadyInfo)
})
cool.Cron.AfterFunc(loadtime, func() {
fmt.Println(f.Our.UserID, "战斗超时结算")
if !f.Our.Finished || !f.Opp.Finished { //如果有任一没有加载完成
f.closefight = true //阻止继续添加action
f.Reason = info.BattleOverReason.PlayerOffline
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
}
func (f *FightC) GetOverInfo() info.FightOverInfo {
return f.FightOverInfo
}