2025-11-11 05:54:24 +00:00
|
|
|
|
package fight
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
2025-11-19 16:11:02 +08:00
|
|
|
|
"blazing/common/socket/errorcode"
|
2025-11-25 16:36:55 +08:00
|
|
|
|
"blazing/common/utils"
|
2026-01-19 18:51:56 +08:00
|
|
|
|
"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"
|
2025-11-25 16:36:55 +08:00
|
|
|
|
"blazing/logic/service/user"
|
2025-11-11 15:21:45 +00:00
|
|
|
|
"sync"
|
2026-04-03 00:02:51 +08:00
|
|
|
|
"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 {
|
2025-11-29 19:26:56 +08:00
|
|
|
|
//准备战斗信息
|
2026-03-04 22:47:21 +08:00
|
|
|
|
ReadyInfo model.NoteReadyToFightInfo
|
2025-11-29 19:26:56 +08:00
|
|
|
|
//开始战斗信息
|
|
|
|
|
|
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 // 敌方操作者
|
2026-04-04 05:44:02 +08:00
|
|
|
|
Switch map[actionSlotKey]*action.ActiveSwitchAction
|
2026-03-22 23:41:51 +08:00
|
|
|
|
|
2026-04-02 23:05:18 +08:00
|
|
|
|
startl sync.Once
|
|
|
|
|
|
StartTime time.Time
|
|
|
|
|
|
actionMu sync.Mutex
|
|
|
|
|
|
actionNotify chan struct{}
|
|
|
|
|
|
acceptActions bool
|
2026-04-04 05:44:02 +08:00
|
|
|
|
pendingActions []action.BattleActionI // 待处理动作队列,同一战斗位最多保留一个动作
|
2026-04-03 00:02:51 +08:00
|
|
|
|
actionRound atomic.Uint32
|
2025-12-10 18:37:32 +00:00
|
|
|
|
|
2026-03-09 12:28:37 +08:00
|
|
|
|
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
|
2025-11-11 15:21:45 +00:00
|
|
|
|
overl sync.Once
|
2025-11-13 02:43:00 +08:00
|
|
|
|
waittime int
|
2026-03-04 22:47:21 +08:00
|
|
|
|
model.FightOverInfo
|
2025-11-15 23:02:46 +00:00
|
|
|
|
//战斗结束的插装
|
2026-03-04 22:47:21 +08:00
|
|
|
|
callback func(model.FightOverInfo)
|
2025-11-11 05:54:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-04 05:44:02 +08: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-05 00:03:32 +08:00
|
|
|
|
// bindInputFightContext 为输入站位绑定战斗上下文与玩家战斗容器。
|
|
|
|
|
|
// 支持一次传入多组输入(如 Our/Opp)。
|
|
|
|
|
|
func (f *FightC) bindInputFightContext(inputGroups ...[]*input.Input) {
|
|
|
|
|
|
for _, inputs := range inputGroups {
|
|
|
|
|
|
for _, fighter := range inputs {
|
|
|
|
|
|
if fighter == nil {
|
|
|
|
|
|
continue
|
|
|
|
|
|
}
|
|
|
|
|
|
fighter.FightC = f
|
|
|
|
|
|
if fighter.Player != nil {
|
|
|
|
|
|
fighter.Player.SetFightC(f)
|
|
|
|
|
|
}
|
2026-04-04 06:11:01 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-05 00:03:32 +08:00
|
|
|
|
// linkTeamViews 建立每个输入的同阵营/对阵营视图(Team/OppTeam)。
|
2026-04-04 22:13:42 +08:00
|
|
|
|
func (f *FightC) linkTeamViews() {
|
|
|
|
|
|
for _, fighter := range f.Our {
|
|
|
|
|
|
if fighter == nil {
|
|
|
|
|
|
continue
|
|
|
|
|
|
}
|
|
|
|
|
|
fighter.Team = f.Our
|
|
|
|
|
|
fighter.OppTeam = f.Opp
|
|
|
|
|
|
}
|
|
|
|
|
|
for _, fighter := range f.Opp {
|
|
|
|
|
|
if fighter == nil {
|
|
|
|
|
|
continue
|
|
|
|
|
|
}
|
|
|
|
|
|
fighter.Team = f.Opp
|
|
|
|
|
|
fighter.OppTeam = f.Our
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-05 00:03:32 +08:00
|
|
|
|
// getSideInputs 按 userID 判定所属阵营后返回目标侧输入集合。
|
2026-04-04 05:44:02 +08:00
|
|
|
|
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-05 00:03:32 +08:00
|
|
|
|
// findInputByUserID 在双方站位中按控制者查找任一输入,并返回是否属于我方。
|
2026-04-04 04:28:04 +08:00
|
|
|
|
func (f *FightC) findInputByUserID(userID uint32) (*input.Input, bool) {
|
2026-04-04 22:13:42 +08:00
|
|
|
|
for _, in := range f.Our {
|
|
|
|
|
|
if in != nil && in.ControlledBy(userID) {
|
2026-04-04 04:28:04 +08:00
|
|
|
|
return in, true
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-04-04 22:13:42 +08:00
|
|
|
|
for _, in := range f.Opp {
|
|
|
|
|
|
if in != nil && in.ControlledBy(userID) {
|
|
|
|
|
|
return in, false
|
|
|
|
|
|
}
|
2026-04-04 04:28:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
return nil, false
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-05 00:03:32 +08:00
|
|
|
|
// getInputByUserID 按 userID + 站位下标获取输入。
|
|
|
|
|
|
// 当查询本侧站位时,要求该站位必须由 userID 控制。
|
2026-04-04 04:28:04 +08:00
|
|
|
|
func (f *FightC) getInputByUserID(userID uint32, index int, isOpposite bool) *input.Input {
|
2026-04-04 22:13:42 +08:00
|
|
|
|
selected := f.selectInput(f.getSideInputs(userID, isOpposite), index)
|
|
|
|
|
|
if selected == nil {
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
// 操作自身站位时,必须由该站位控制者发起。
|
|
|
|
|
|
if !isOpposite && !selected.ControlledBy(userID) {
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
return selected
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-05 00:03:32 +08:00
|
|
|
|
// getInputByController 按控制者获取其首个可操作站位(常用于兼容单站位接口)。
|
2026-04-04 22:13:42 +08:00
|
|
|
|
func (f *FightC) getInputByController(userID uint32, isOpposite bool) *input.Input {
|
|
|
|
|
|
sideInputs := f.getSideInputs(userID, isOpposite)
|
|
|
|
|
|
for _, in := range sideInputs {
|
|
|
|
|
|
if in != nil && in.ControlledBy(userID) {
|
|
|
|
|
|
return in
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return f.selectInput(sideInputs, 0)
|
2026-04-04 05:44:02 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (f *FightC) expectedActionSlots() map[actionSlotKey]struct{} {
|
|
|
|
|
|
slots := make(map[actionSlotKey]struct{}, len(f.Our)+len(f.Opp))
|
2026-04-04 22:13:42 +08:00
|
|
|
|
for _, slot := range f.SideSlots(SideOur) {
|
|
|
|
|
|
slots[newActionSlotKey(slot.ControllerUserID, slot.SlotIndex)] = struct{}{}
|
2026-04-04 04:28:04 +08:00
|
|
|
|
}
|
2026-04-04 22:13:42 +08:00
|
|
|
|
for _, slot := range f.SideSlots(SideOpp) {
|
|
|
|
|
|
slots[newActionSlotKey(slot.ControllerUserID, slot.SlotIndex)] = struct{}{}
|
2026-04-04 05:44:02 +08:00
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
}
|
2026-04-04 05:44:02 +08:00
|
|
|
|
attacker.AttackValue.ActorIndex = uint32(act.GetActorIndex())
|
2026-04-05 02:25:44 +08:00
|
|
|
|
targetIndex, _ := DecodeTargetIndex(act.GetTargetIndex())
|
|
|
|
|
|
attacker.AttackValue.TargetIndex = uint32(targetIndex)
|
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 22:13:42 +08:00
|
|
|
|
return f.getInputByController(c.GetInfo().UserID, isOpposite)
|
2025-11-11 05:54:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-05 00:03:32 +08:00
|
|
|
|
// GetInputsByPlayer 返回玩家在指定侧的全部可控站位。
|
|
|
|
|
|
func (f *FightC) GetInputsByPlayer(c common.PlayerI, isOpposite bool) []*input.Input {
|
|
|
|
|
|
if c == nil {
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
sideInputs := f.getSideInputs(c.GetInfo().UserID, isOpposite)
|
|
|
|
|
|
result := make([]*input.Input, 0, len(sideInputs))
|
|
|
|
|
|
for _, in := range sideInputs {
|
|
|
|
|
|
if in != nil && in.ControlledBy(c.GetInfo().UserID) {
|
|
|
|
|
|
result = append(result, in)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return result
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GetInputByPlayerAt 按玩家+站位下标获取输入。
|
|
|
|
|
|
func (f *FightC) GetInputByPlayerAt(c common.PlayerI, actorIndex int, isOpposite bool) *input.Input {
|
|
|
|
|
|
if c == nil {
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
return f.getInputByUserID(c.GetInfo().UserID, actorIndex, 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()
|
2026-04-05 02:25:44 +08:00
|
|
|
|
if !isOpposite {
|
|
|
|
|
|
return f.getInputByUserID(c.GetPlayerID(), index, false)
|
2025-11-11 05:54:24 +00:00
|
|
|
|
}
|
2026-04-05 02:25:44 +08:00
|
|
|
|
targetIndex, targetIsOpposite := DecodeTargetIndex(c.GetTargetIndex())
|
|
|
|
|
|
return f.getInputByUserID(c.GetPlayerID(), targetIndex, targetIsOpposite)
|
2025-11-11 05:54:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 玩家使用技能
|
|
|
|
|
|
func (f *FightC) GetCurrPET(c common.PlayerI) *info.BattlePetEntity {
|
2026-04-04 05:44:02 +08:00
|
|
|
|
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
|
|
|
|
}
|
2026-04-04 22:13:42 +08:00
|
|
|
|
|
|
|
|
|
|
func (f *FightC) GetCurrPETByAction(c action.BattleActionI, isOpposite bool) *info.BattlePetEntity {
|
|
|
|
|
|
in := f.GetInputByAction(c, isOpposite)
|
|
|
|
|
|
if in == nil {
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
return in.CurrentPet()
|
|
|
|
|
|
}
|
2025-11-11 05:54:24 +00:00
|
|
|
|
func (f *FightC) GetOpp(c common.PlayerI) *input.Input {
|
|
|
|
|
|
return f.GetInputByPlayer(c, true)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-09 12:28:37 +08:00
|
|
|
|
// // 获取随机数
|
2025-11-11 05:54:24 +00:00
|
|
|
|
func (f *FightC) IsFirst(play common.PlayerI) bool {
|
|
|
|
|
|
|
2026-03-17 19:41:07 +08:00
|
|
|
|
return f.TrueFirst.Player == play
|
|
|
|
|
|
}
|
2026-04-04 04:28:04 +08:00
|
|
|
|
func (f *FightC) GetRound() uint32 {
|
|
|
|
|
|
|
|
|
|
|
|
return f.Round
|
|
|
|
|
|
}
|
2025-11-25 16:36:55 +08:00
|
|
|
|
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) {
|
2025-11-25 16:36:55 +08:00
|
|
|
|
if f.Info.Mode == info.BattleMode.PET_MELEE {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
if f.Info.Status == info.BattleMode.FIGHT_WITH_NPC {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
2025-11-19 16:11:02 +08:00
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-22 23:41:51 +08:00
|
|
|
|
func (f *FightC) initplayer(c common.PlayerI, b []model.PetInfo) (*input.Input, errorcode.ErrorCode) {
|
2026-02-25 16:18:10 +08:00
|
|
|
|
r := c.CanFight()
|
|
|
|
|
|
if c.CanFight() != 0 {
|
|
|
|
|
|
return nil, r
|
2025-11-11 05:54:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-15 01:53:51 +08:00
|
|
|
|
in := input.NewInput(f, c)
|
|
|
|
|
|
in.AllPet = make([]*info.BattlePetEntity, 0)
|
|
|
|
|
|
in.InitAttackValue()
|
2026-03-22 23:41:51 +08:00
|
|
|
|
for i := 0; i < len(b); i++ {
|
2026-02-17 22:36:18 +08:00
|
|
|
|
//玩家精灵重置到100等级
|
2026-03-22 23:41:51 +08:00
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-15 01:53:51 +08:00
|
|
|
|
in.SortPet()
|
2025-12-16 06:54:27 +00:00
|
|
|
|
if len(in.AllPet) == 0 {
|
|
|
|
|
|
return nil, errorcode.ErrorCodes.ErrNoEligiblePokemon
|
|
|
|
|
|
}
|
2026-03-24 01:38:02 +08:00
|
|
|
|
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])
|
2025-11-20 05:57:29 +08:00
|
|
|
|
return in, 0
|
2025-11-15 01:53:51 +08:00
|
|
|
|
}
|
2025-11-11 05:54:24 +00:00
|
|
|
|
|
2025-11-15 01:53:51 +08: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
|
|
|
|
|
2025-11-15 01:53:51 +08:00
|
|
|
|
// 用map记录已抽取的ID,避免重复
|
|
|
|
|
|
used := make(map[int]struct{}, n)
|
|
|
|
|
|
ids := make([]int, 0, n)
|
2025-11-11 05:54:24 +00:00
|
|
|
|
|
2025-11-15 01:53:51 +08: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
|
|
|
|
|
2025-11-15 01:53:51 +08:00
|
|
|
|
// 检查是否已抽取
|
|
|
|
|
|
if _, exists := used[id]; !exists {
|
|
|
|
|
|
used[id] = struct{}{}
|
|
|
|
|
|
ids = append(ids, id)
|
2025-11-11 05:54:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-15 01:53:51 +08:00
|
|
|
|
return ids
|
|
|
|
|
|
}
|
2026-03-04 22:47:21 +08:00
|
|
|
|
func initfightready(in *input.Input) (model.FightUserInfo, []model.ReadyFightPetInfo) {
|
|
|
|
|
|
t := make([]model.ReadyFightPetInfo, len(in.AllPet))
|
|
|
|
|
|
userindo := model.FightUserInfo{
|
2025-11-15 01:53:51 +08:00
|
|
|
|
UserID: in.UserID,
|
|
|
|
|
|
Nick: in.Player.GetInfo().Nick,
|
|
|
|
|
|
}
|
2025-11-11 05:54:24 +00:00
|
|
|
|
|
2025-11-15 01:53:51 +08:00
|
|
|
|
for i := 0; i < len(in.AllPet); i++ {
|
2025-11-11 05:54:24 +00:00
|
|
|
|
|
2025-11-15 01:53:51 +08: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
|
|
|
|
}
|
2025-11-12 01:19:24 +08:00
|
|
|
|
|
2025-11-15 01:53:51 +08:00
|
|
|
|
return userindo, t
|
2025-11-11 05:54:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 被击败的ID
|
2025-12-23 13:53:34 +00:00
|
|
|
|
func (f *FightC) IsWin(c *input.Input) bool {
|
2026-04-04 05:44:02 +08:00
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
}
|
2025-11-12 01:19:24 +08:00
|
|
|
|
|
|
|
|
|
|
func (f *FightC) GetOverChan() chan struct{} {
|
|
|
|
|
|
return f.over
|
|
|
|
|
|
|
|
|
|
|
|
}
|
2026-03-04 22:47:21 +08:00
|
|
|
|
func (f *FightC) GetOverInfo() model.FightOverInfo {
|
2025-12-10 18:37:32 +00:00
|
|
|
|
return f.FightOverInfo
|
|
|
|
|
|
|
|
|
|
|
|
}
|
2026-03-07 00:26:05 +08:00
|
|
|
|
|
|
|
|
|
|
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
|
2026-03-07 00:26:05 +08:00
|
|
|
|
|
|
|
|
|
|
}
|