Files
bl/logic/service/fight/input.go

430 lines
9.3 KiB
Go
Raw Normal View History

2025-11-11 05:54:24 +00:00
package fight
import (
"blazing/common/socket/errorcode"
"blazing/common/utils"
"blazing/modules/player/model"
2025-11-15 22:17:43 +00:00
2025-11-11 05:54:24 +00:00
"blazing/logic/service/common"
"blazing/logic/service/fight/action"
"blazing/logic/service/fight/info"
"blazing/logic/service/fight/input"
"blazing/logic/service/user"
"sync"
"sync/atomic"
2025-11-11 05:54:24 +00:00
"time"
2025-11-23 23:38:03 +00:00
"github.com/gogf/gf/v2/util/grand"
2025-11-11 05:54:24 +00:00
"github.com/jinzhu/copier"
)
type FightC struct {
//准备战斗信息
ReadyInfo model.NoteReadyToFightInfo
//开始战斗信息
info.FightStartOutboundInfo
2026-04-04 04:28:04 +08:00
Info info.Fightinfo
IsReady bool
ownerID uint32 // 战斗发起者ID
Our []*input.Input // 我方战斗位
Opp []*input.Input // 敌方战斗位
OurPlayers []common.PlayerI // 我方操作者
OppPlayers []common.PlayerI // 敌方操作者
Switch map[actionSlotKey]*action.ActiveSwitchAction
startl sync.Once
StartTime time.Time
actionMu sync.Mutex
actionNotify chan struct{}
acceptActions bool
pendingActions []action.BattleActionI // 待处理动作队列,同一战斗位最多保留一个动作
actionRound atomic.Uint32
quit chan struct{}
over chan struct{}
First *input.Input
TrueFirst *input.Input
2025-11-11 05:54:24 +00:00
Second *input.Input
closefight bool
overl sync.Once
waittime int
model.FightOverInfo
2025-11-15 23:02:46 +00:00
//战斗结束的插装
callback func(model.FightOverInfo)
2025-11-11 05:54:24 +00:00
}
type actionSlotKey struct {
PlayerID uint32
ActorIndex int
}
func newActionSlotKey(playerID uint32, actorIndex int) actionSlotKey {
return actionSlotKey{
PlayerID: playerID,
ActorIndex: actorIndex,
}
}
func actionSlotKeyFromAction(act action.BattleActionI) actionSlotKey {
if act == nil {
return actionSlotKey{}
}
return newActionSlotKey(act.GetPlayerID(), act.GetActorIndex())
}
2026-04-04 04:28:04 +08:00
func (f *FightC) primaryOur() *input.Input {
if len(f.Our) == 0 {
return nil
}
return f.Our[0]
}
func (f *FightC) primaryOpp() *input.Input {
if len(f.Opp) == 0 {
return nil
}
return f.Opp[0]
}
func (f *FightC) primaryOurPlayer() common.PlayerI {
if len(f.OurPlayers) == 0 {
return nil
}
return f.OurPlayers[0]
}
func (f *FightC) primaryOppPlayer() common.PlayerI {
if len(f.OppPlayers) == 0 {
return nil
}
return f.OppPlayers[0]
}
func (f *FightC) selectInput(inputs []*input.Input, index int) *input.Input {
if len(inputs) == 0 {
return nil
}
if index >= 0 && index < len(inputs) && inputs[index] != nil {
return inputs[index]
}
for _, in := range inputs {
if in != nil {
return in
}
}
return nil
}
func (f *FightC) isPlayerInSide(players []common.PlayerI, userID uint32) bool {
for _, player := range players {
if player != nil && player.GetInfo().UserID == userID {
return true
}
}
return false
}
func (f *FightC) isOurPlayerID(userID uint32) bool {
if f.isPlayerInSide(f.OurPlayers, userID) {
return true
}
if f.isPlayerInSide(f.OppPlayers, userID) {
return false
}
return userID == f.ownerID
}
2026-04-04 06:11:01 +08:00
func (f *FightC) bindInputFightContext(inputs []*input.Input) {
for _, fighter := range inputs {
if fighter == nil {
continue
}
fighter.FightC = f
if fighter.Player != nil {
fighter.Player.SetFightC(f)
}
}
}
func (f *FightC) linkOppInputs() {
for actorIndex, fighter := range f.Our {
if fighter == nil {
continue
}
fighter.SetOPP(f.selectInput(f.Opp, actorIndex))
}
for actorIndex, fighter := range f.Opp {
if fighter == nil {
continue
}
fighter.SetOPP(f.selectInput(f.Our, actorIndex))
}
}
func (f *FightC) getSideInputs(userID uint32, isOpposite bool) []*input.Input {
isOur := f.isOurPlayerID(userID)
if isOpposite {
if isOur {
return f.Opp
}
return f.Our
}
if isOur {
return f.Our
}
return f.Opp
}
2026-04-04 04:28:04 +08:00
func (f *FightC) findInputByUserID(userID uint32) (*input.Input, bool) {
isOur := f.isOurPlayerID(userID)
if isOur {
if in := f.selectInput(f.Our, 0); in != nil {
return in, true
}
return nil, true
}
if in := f.selectInput(f.Opp, 0); in != nil {
return in, false
}
return nil, false
}
func (f *FightC) getInputByUserID(userID uint32, index int, isOpposite bool) *input.Input {
return f.selectInput(f.getSideInputs(userID, isOpposite), index)
}
func (f *FightC) expectedActionSlots() map[actionSlotKey]struct{} {
slots := make(map[actionSlotKey]struct{}, len(f.Our)+len(f.Opp))
for actorIndex, fighter := range f.Our {
if fighter == nil || fighter.Player == nil {
continue
2026-04-04 04:28:04 +08:00
}
slots[newActionSlotKey(fighter.Player.GetInfo().UserID, actorIndex)] = struct{}{}
2026-04-04 04:28:04 +08:00
}
for actorIndex, fighter := range f.Opp {
if fighter == nil || fighter.Player == nil {
continue
}
slots[newActionSlotKey(fighter.Player.GetInfo().UserID, actorIndex)] = struct{}{}
}
return slots
}
func (f *FightC) setActionAttackValue(act action.BattleActionI) {
if act == nil {
return
}
attacker := f.GetInputByAction(act, false)
if attacker == nil || attacker.AttackValue == nil {
return
2026-04-04 04:28:04 +08:00
}
attacker.AttackValue.ActorIndex = uint32(act.GetActorIndex())
attacker.AttackValue.TargetIndex = uint32(act.GetTargetIndex())
2026-04-04 04:28:04 +08:00
}
2025-11-11 05:54:24 +00:00
func (f *FightC) Ownerid() uint32 {
return f.ownerID
}
func (f *FightC) GetInputByPlayer(c common.PlayerI, isOpposite bool) *input.Input {
2026-04-04 04:28:04 +08:00
if c == nil {
if isOpposite {
return f.primaryOpp()
}
return f.primaryOur()
2025-11-11 05:54:24 +00:00
}
2026-04-04 04:28:04 +08:00
return f.getInputByUserID(c.GetInfo().UserID, 0, isOpposite)
2025-11-11 05:54:24 +00:00
}
func (f *FightC) GetInputByAction(c action.BattleActionI, isOpposite bool) *input.Input {
2026-04-04 04:28:04 +08:00
if c == nil {
if isOpposite {
return f.primaryOpp()
}
return f.primaryOur()
}
index := c.GetActorIndex()
if isOpposite {
index = c.GetTargetIndex()
2025-11-11 05:54:24 +00:00
}
2026-04-04 04:28:04 +08:00
return f.getInputByUserID(c.GetPlayerID(), index, isOpposite)
2025-11-11 05:54:24 +00:00
}
// 玩家使用技能
func (f *FightC) GetCurrPET(c common.PlayerI) *info.BattlePetEntity {
return f.GetCurrPETAt(c, 0)
}
func (f *FightC) GetCurrPETAt(c common.PlayerI, actorIndex int) *info.BattlePetEntity {
if c == nil {
return nil
}
in := f.getInputByUserID(c.GetInfo().UserID, actorIndex, false)
2026-04-04 04:28:04 +08:00
if in == nil {
return nil
2025-11-11 05:54:24 +00:00
}
2026-04-04 04:34:43 +08:00
return in.PrimaryCurPet()
2025-11-11 05:54:24 +00:00
}
func (f *FightC) GetOpp(c common.PlayerI) *input.Input {
return f.GetInputByPlayer(c, true)
}
// // 获取随机数
2025-11-11 05:54:24 +00:00
func (f *FightC) IsFirst(play common.PlayerI) bool {
return f.TrueFirst.Player == play
}
2026-04-04 04:28:04 +08:00
func (f *FightC) GetRound() uint32 {
return f.Round
}
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),
})
}
2025-11-11 05:54:24 +00:00
// 加载进度
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{
2025-11-11 05:54:24 +00:00
Id: c.GetInfo().UserID,
Percent: uint32(percent),
})
2025-11-18 20:52:04 +00:00
2025-11-11 05:54:24 +00:00
}
func (f *FightC) initplayer(c common.PlayerI, b []model.PetInfo) (*input.Input, errorcode.ErrorCode) {
r := c.CanFight()
if c.CanFight() != 0 {
return nil, r
2025-11-11 05:54:24 +00:00
}
in := input.NewInput(f, c)
in.AllPet = make([]*info.BattlePetEntity, 0)
in.InitAttackValue()
for i := 0; i < len(b); i++ {
2026-02-17 22:36:18 +08:00
//玩家精灵重置到100等级
pet := b[i]
2026-04-04 04:28:04 +08:00
entity := info.CreateBattlePetEntity(pet)
entity.BindController(c.GetInfo().UserID)
in.AllPet = append(in.AllPet, entity)
2025-11-11 05:54:24 +00:00
}
in.SortPet()
if len(in.AllPet) == 0 {
return nil, errorcode.ErrorCodes.ErrNoEligiblePokemon
}
switch f.Info.Mode {
case info.BattleMode.SINGLE_MODE:
in.AllPet = in.AllPet[:1]
default:
}
2025-11-11 05:54:24 +00:00
2026-04-04 04:34:43 +08:00
in.SetCurPetAt(0, in.AllPet[0])
return in, 0
}
2025-11-11 05:54:24 +00:00
// RandomElfIDs 从1-2000中随机抽取n个不重复的精灵ID
func RandomElfIDs(n int) []int {
if n <= 0 || n > 2000 {
return nil
}
2025-11-11 05:54:24 +00:00
// 用map记录已抽取的ID避免重复
used := make(map[int]struct{}, n)
ids := make([]int, 0, n)
2025-11-11 05:54:24 +00:00
for len(ids) < n {
// 生成1-2000的随机数
2025-11-23 23:38:03 +00:00
id := grand.Intn(2000) + 1 // rand.Intn(2000)生成0-1999+1后为1-2000
2025-11-11 05:54:24 +00:00
// 检查是否已抽取
if _, exists := used[id]; !exists {
used[id] = struct{}{}
ids = append(ids, id)
2025-11-11 05:54:24 +00:00
}
}
return ids
}
func initfightready(in *input.Input) (model.FightUserInfo, []model.ReadyFightPetInfo) {
t := make([]model.ReadyFightPetInfo, len(in.AllPet))
userindo := model.FightUserInfo{
UserID: in.UserID,
Nick: in.Player.GetInfo().Nick,
}
2025-11-11 05:54:24 +00:00
for i := 0; i < len(in.AllPet); i++ {
2025-11-11 05:54:24 +00:00
err := copier.CopyWithOption(&t[i], &in.AllPet[i].Info, copier.Option{IgnoreEmpty: true, DeepCopy: true})
if err != nil {
panic(err)
}
2025-11-11 05:54:24 +00:00
}
return userindo, t
2025-11-11 05:54:24 +00:00
}
// 被击败的ID
func (f *FightC) IsWin(c *input.Input) bool {
if c == nil || c.Player == nil {
return false
}
for _, sideInput := range f.getSideInputs(c.Player.GetInfo().UserID, true) {
if sideInput == nil {
continue
}
for _, v := range sideInput.AllPet {
if v.Alive() {
return false
}
2025-11-11 05:54:24 +00:00
}
}
return true
}
// 广播,并是否结束回合
func (f *FightC) Broadcast(t func(ff *input.Input)) {
2026-04-04 04:28:04 +08:00
for _, ff := range f.Our {
if ff != nil {
t(ff)
}
}
for _, ff := range f.Opp {
if ff != nil {
t(ff)
}
}
2025-11-11 05:54:24 +00:00
}
func (f *FightC) GetOverChan() chan struct{} {
return f.over
}
func (f *FightC) GetOverInfo() model.FightOverInfo {
return f.FightOverInfo
}
func (f *FightC) GetAttackValue(b bool) *model.AttackValue {
2026-04-04 04:28:04 +08:00
our := f.primaryOur()
if our == nil {
return nil
}
return f.GetInputByPlayer(our.Player, b).AttackValue
}