2025-09-14 03:36:26 +08:00
|
|
|
|
package fight
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"blazing/logic/service/common"
|
2025-09-28 08:13:42 +00:00
|
|
|
|
"blazing/logic/service/fight/action"
|
2025-09-14 03:36:26 +08:00
|
|
|
|
"blazing/logic/service/fight/info"
|
2025-09-24 20:17:44 +00:00
|
|
|
|
"blazing/logic/service/fight/input"
|
2026-03-04 22:47:21 +08:00
|
|
|
|
"blazing/modules/player/model"
|
2025-09-14 03:36:26 +08:00
|
|
|
|
|
|
|
|
|
|
"github.com/jinzhu/copier"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
2025-09-28 08:13:42 +00:00
|
|
|
|
// Compare 比较两个1v1战斗动作的执行优先级(核心逻辑)
|
2026-01-25 03:40:29 +08:00
|
|
|
|
func (*FightC) Compare(a, b action.BattleActionI) (action.BattleActionI, action.BattleActionI) {
|
2025-09-28 08:13:42 +00:00
|
|
|
|
// 动作本身的优先级比较
|
|
|
|
|
|
p1 := b.Priority() - a.Priority()
|
|
|
|
|
|
if p1 > 0 { // 对手优先级更高
|
|
|
|
|
|
return b, a
|
|
|
|
|
|
} else if p1 < 0 {
|
|
|
|
|
|
return a, b
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return a, b // 速度相同时,发起方优先
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-02 23:05:18 +08:00
|
|
|
|
const maxPendingActionsPerPlayer = 2
|
|
|
|
|
|
|
|
|
|
|
|
func (f *FightC) openActionWindow() {
|
|
|
|
|
|
f.actionMu.Lock()
|
|
|
|
|
|
f.acceptActions = true
|
|
|
|
|
|
f.pendingActions = f.pendingActions[:0]
|
2026-04-03 00:02:51 +08:00
|
|
|
|
f.actionRound.Store(uint32(f.Round))
|
2026-04-02 23:05:18 +08:00
|
|
|
|
f.actionMu.Unlock()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (f *FightC) closeActionWindow() {
|
|
|
|
|
|
f.actionMu.Lock()
|
|
|
|
|
|
f.acceptActions = false
|
|
|
|
|
|
f.pendingActions = f.pendingActions[:0]
|
2026-04-03 00:02:51 +08:00
|
|
|
|
f.actionRound.Store(0)
|
2026-04-02 23:05:18 +08:00
|
|
|
|
f.actionMu.Unlock()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (f *FightC) submitAction(act action.BattleActionI) {
|
|
|
|
|
|
if act == nil || f.closefight {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-03 00:02:34 +08:00
|
|
|
|
round := f.actionRound.Load()
|
|
|
|
|
|
if round == 0 {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
act.SetRound(round)
|
|
|
|
|
|
|
2026-04-02 23:05:18 +08:00
|
|
|
|
f.actionMu.Lock()
|
2026-04-03 00:02:51 +08:00
|
|
|
|
if !f.acceptActions || act.GetRound() != f.actionRound.Load() {
|
2026-04-02 23:05:18 +08:00
|
|
|
|
f.actionMu.Unlock()
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
count := 0
|
|
|
|
|
|
replaceIndex := -1
|
|
|
|
|
|
for i, pending := range f.pendingActions {
|
|
|
|
|
|
if pending == nil || pending.GetPlayerID() != act.GetPlayerID() {
|
|
|
|
|
|
continue
|
|
|
|
|
|
}
|
|
|
|
|
|
count++
|
|
|
|
|
|
replaceIndex = i
|
|
|
|
|
|
}
|
|
|
|
|
|
if count >= maxPendingActionsPerPlayer && replaceIndex >= 0 {
|
|
|
|
|
|
f.pendingActions[replaceIndex] = act
|
|
|
|
|
|
} else {
|
|
|
|
|
|
f.pendingActions = append(f.pendingActions, act)
|
|
|
|
|
|
}
|
|
|
|
|
|
notify := f.actionNotify
|
|
|
|
|
|
f.actionMu.Unlock()
|
|
|
|
|
|
|
|
|
|
|
|
if notify == nil {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
select {
|
|
|
|
|
|
case notify <- struct{}{}:
|
|
|
|
|
|
default:
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (f *FightC) nextAction() action.BattleActionI {
|
|
|
|
|
|
f.actionMu.Lock()
|
|
|
|
|
|
if len(f.pendingActions) == 0 {
|
|
|
|
|
|
f.actionMu.Unlock()
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
act := f.pendingActions[0]
|
|
|
|
|
|
copy(f.pendingActions, f.pendingActions[1:])
|
|
|
|
|
|
f.pendingActions = f.pendingActions[:len(f.pendingActions)-1]
|
|
|
|
|
|
hasMore := len(f.pendingActions) > 0
|
|
|
|
|
|
notify := f.actionNotify
|
|
|
|
|
|
f.actionMu.Unlock()
|
|
|
|
|
|
|
|
|
|
|
|
if hasMore && notify != nil {
|
|
|
|
|
|
select {
|
|
|
|
|
|
case notify <- struct{}{}:
|
|
|
|
|
|
default:
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return act
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 16:42:10 +00:00
|
|
|
|
// 玩家逃跑/无响应/掉线
|
2026-03-04 22:47:21 +08:00
|
|
|
|
func (f *FightC) Over(c common.PlayerI, res model.EnumBattleOverReason) {
|
2025-11-09 04:37:15 +00:00
|
|
|
|
if f.closefight {
|
2026-02-02 18:32:41 +08:00
|
|
|
|
|
2025-11-09 04:37:15 +00:00
|
|
|
|
return
|
|
|
|
|
|
}
|
2026-03-04 22:47:21 +08:00
|
|
|
|
if f.Info.Status != info.BattleMode.FIGHT_WITH_NPC && res == model.BattleOverReason.PlayerEscape {
|
2025-12-31 21:00:29 +08:00
|
|
|
|
return
|
|
|
|
|
|
}
|
2025-11-11 11:45:09 +00:00
|
|
|
|
// case *action.EscapeAction:
|
|
|
|
|
|
// f.FightOverInfo.WinnerId = b2.GetPlayerID() //对方胜利
|
|
|
|
|
|
// f.FightOverInfo.Reason = a.Reason
|
|
|
|
|
|
|
|
|
|
|
|
// f.closefight = true
|
|
|
|
|
|
// ret := &action.EscapeAction{
|
|
|
|
|
|
// BaseAction: action.NewBaseAction(c.GetInfo().UserID),
|
|
|
|
|
|
// Reason: res,
|
|
|
|
|
|
// }
|
2025-09-14 03:36:26 +08:00
|
|
|
|
|
2025-11-11 15:21:45 +00:00
|
|
|
|
f.overl.Do(func() {
|
|
|
|
|
|
f.Reason = res
|
2026-02-14 23:14:43 +08:00
|
|
|
|
if f.GetInputByPlayer(c, true) != nil {
|
|
|
|
|
|
f.WinnerId = f.GetInputByPlayer(c, true).UserID
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-11 15:21:45 +00:00
|
|
|
|
close(f.quit)
|
2025-11-11 11:45:09 +00:00
|
|
|
|
|
2025-11-11 15:21:45 +00:00
|
|
|
|
})
|
|
|
|
|
|
|
2025-09-14 03:36:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 切换精灵 主动和被驱逐
|
|
|
|
|
|
func (f *FightC) ChangePet(c common.PlayerI, id uint32) {
|
2025-11-13 02:43:00 +08:00
|
|
|
|
|
2025-11-09 04:37:15 +00:00
|
|
|
|
if f.closefight {
|
2026-02-02 18:32:41 +08:00
|
|
|
|
|
2025-11-09 04:37:15 +00:00
|
|
|
|
return
|
|
|
|
|
|
}
|
2026-02-05 23:44:07 +08:00
|
|
|
|
|
|
|
|
|
|
ii, _ := f.GetInputByPlayer(c, false).GetPet(id)
|
|
|
|
|
|
if ii == nil {
|
|
|
|
|
|
//无法切换不允许切换的精灵
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
2025-11-29 19:26:56 +08:00
|
|
|
|
//todo 待实现无法切精灵的情况
|
2025-09-28 08:13:42 +00:00
|
|
|
|
ret := &action.ActiveSwitchAction{
|
|
|
|
|
|
BaseAction: action.NewBaseAction(c.GetInfo().UserID),
|
2025-12-11 12:16:32 +08:00
|
|
|
|
Cid: id,
|
2025-09-14 03:36:26 +08:00
|
|
|
|
}
|
2026-04-02 23:05:18 +08:00
|
|
|
|
f.submitAction(ret)
|
2026-01-20 04:40:36 +08:00
|
|
|
|
|
2025-09-14 03:36:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 玩家使用技能
|
2025-11-23 23:42:16 +00:00
|
|
|
|
func (f *FightC) UseSkill(c common.PlayerI, id uint32) {
|
2025-11-09 04:37:15 +00:00
|
|
|
|
if f.closefight {
|
2026-02-02 18:32:41 +08:00
|
|
|
|
|
2025-11-09 04:37:15 +00:00
|
|
|
|
return
|
|
|
|
|
|
}
|
2025-09-28 08:13:42 +00:00
|
|
|
|
ret := &action.SelectSkillAction{
|
2025-10-05 00:29:22 +08:00
|
|
|
|
BaseAction: action.NewBaseAction(c.GetInfo().UserID),
|
2025-09-14 03:36:26 +08:00
|
|
|
|
}
|
2026-01-20 02:25:02 +08:00
|
|
|
|
|
2025-11-11 08:28:18 +00:00
|
|
|
|
if f.GetInputByPlayer(c, false).CurrentPet == nil {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
if f.GetInputByPlayer(c, false).CurrentPet.Info.Hp <= 0 {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
2026-02-20 00:46:48 +08:00
|
|
|
|
// t, ok := f.GetInputByPlayer(c, false).CurrentPet.Skills[id]
|
|
|
|
|
|
// if ok {
|
|
|
|
|
|
// ret.SkillEntity = t
|
|
|
|
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
for _, v := range f.GetInputByPlayer(c, false).CurrentPet.Skills {
|
2026-03-09 18:49:51 +08:00
|
|
|
|
if v.XML.ID == int(id) {
|
2026-02-20 00:46:48 +08:00
|
|
|
|
ret.SkillEntity = v
|
2026-02-20 21:34:27 +08:00
|
|
|
|
|
2026-02-20 00:46:48 +08:00
|
|
|
|
break
|
|
|
|
|
|
}
|
2025-09-14 03:36:26 +08:00
|
|
|
|
|
|
|
|
|
|
}
|
2026-04-02 23:05:18 +08:00
|
|
|
|
f.submitAction(ret)
|
2025-09-14 03:36:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 玩家使用技能
|
|
|
|
|
|
func (f *FightC) Capture(c common.PlayerI, id uint32) {
|
2025-11-09 04:37:15 +00:00
|
|
|
|
if f.closefight {
|
2026-02-02 18:32:41 +08:00
|
|
|
|
|
2025-11-09 04:37:15 +00:00
|
|
|
|
return
|
|
|
|
|
|
}
|
2026-04-02 23:05:18 +08:00
|
|
|
|
f.submitAction(&action.UseItemAction{BaseAction: action.NewBaseAction(c.GetInfo().UserID), ItemID: id})
|
2026-02-22 00:49:50 +08:00
|
|
|
|
|
2025-09-14 03:36:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-08 01:30:53 +08:00
|
|
|
|
func (f *FightC) UseItem(c common.PlayerI, cacthid, itemid uint32) {
|
2025-11-09 04:37:15 +00:00
|
|
|
|
if f.closefight {
|
2026-02-02 18:32:41 +08:00
|
|
|
|
|
2025-11-09 04:37:15 +00:00
|
|
|
|
return
|
|
|
|
|
|
}
|
2026-04-02 23:05:18 +08:00
|
|
|
|
if f.Info.Mode == info.BattleMode.PET_MELEE {
|
|
|
|
|
|
go f.UseSkill(c, 0)
|
|
|
|
|
|
return
|
2026-02-22 00:49:50 +08:00
|
|
|
|
}
|
2026-04-02 23:05:18 +08:00
|
|
|
|
f.submitAction(&action.UseItemAction{BaseAction: action.NewBaseAction(c.GetInfo().UserID), ItemID: itemid, CacthTime: cacthid})
|
2025-11-08 01:30:53 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-14 23:09:16 +08:00
|
|
|
|
// ReadyFight 处理玩家战斗准备逻辑,当满足条件时启动战斗循环
|
2025-09-14 03:36:26 +08:00
|
|
|
|
func (f *FightC) ReadyFight(c common.PlayerI) {
|
2025-11-30 01:54:46 +08:00
|
|
|
|
f.Broadcast(func(ff *input.Input) {
|
2025-11-01 18:36:21 +08:00
|
|
|
|
|
2025-11-30 01:54:46 +08:00
|
|
|
|
ff.Player.SendPackCmd(2404, &info.S2C_2404{UserID: c.GetInfo().UserID})
|
|
|
|
|
|
})
|
2025-11-14 23:09:16 +08:00
|
|
|
|
// 2. 标记当前玩家已准备完成
|
|
|
|
|
|
input := f.GetInputByPlayer(c, false)
|
|
|
|
|
|
input.Finished = true
|
2025-11-29 19:26:56 +08:00
|
|
|
|
if f.checkBothPlayersReady(c) {
|
|
|
|
|
|
f.startBattle(f.FightStartOutboundInfo)
|
2025-11-14 23:09:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-14 03:36:26 +08:00
|
|
|
|
|
2025-11-14 23:09:16 +08:00
|
|
|
|
// buildFightStartInfo 构建战斗开始时需要发送给双方的信息
|
|
|
|
|
|
func (f *FightC) buildFightStartInfo() info.FightStartOutboundInfo {
|
|
|
|
|
|
var startInfo info.FightStartOutboundInfo
|
2025-11-13 02:43:00 +08:00
|
|
|
|
|
2025-11-14 23:09:16 +08:00
|
|
|
|
// 复制双方初始宠物信息(取列表第一个宠物)
|
2025-11-16 20:30:17 +00:00
|
|
|
|
if len(f.ReadyInfo.OurPetList) > 0 {
|
|
|
|
|
|
_ = copier.Copy(&startInfo.Info1, &f.ReadyInfo.OurPetList[0])
|
|
|
|
|
|
startInfo.Info1.UserID = f.ReadyInfo.OurInfo.UserID
|
2025-11-14 23:09:16 +08:00
|
|
|
|
}
|
2025-11-16 20:30:17 +00:00
|
|
|
|
if len(f.ReadyInfo.OpponentPetList) > 0 {
|
|
|
|
|
|
_ = copier.Copy(&startInfo.Info2, &f.ReadyInfo.OpponentPetList[0])
|
|
|
|
|
|
startInfo.Info2.UserID = f.ReadyInfo.OpponentInfo.UserID
|
2025-11-14 23:09:16 +08:00
|
|
|
|
}
|
2025-11-13 02:43:00 +08:00
|
|
|
|
|
2025-11-14 23:09:16 +08:00
|
|
|
|
return startInfo
|
|
|
|
|
|
}
|
2025-09-14 03:36:26 +08:00
|
|
|
|
|
2025-11-14 23:09:16 +08:00
|
|
|
|
// checkBothPlayersReady 检查PVP战斗中双方是否都已准备完成
|
|
|
|
|
|
// 参数c为当前准备的玩家,返回true表示双方均准备完成
|
|
|
|
|
|
func (f *FightC) checkBothPlayersReady(currentPlayer common.PlayerI) bool {
|
|
|
|
|
|
// 这里的第二个参数true含义需结合业务确认(推测为"检查对手"),建议用常量替代
|
|
|
|
|
|
opponentInput := f.GetInputByPlayer(currentPlayer, true)
|
|
|
|
|
|
return opponentInput.Finished
|
|
|
|
|
|
}
|
2025-11-13 02:43:00 +08:00
|
|
|
|
|
2025-11-14 23:09:16 +08:00
|
|
|
|
// startBattle 启动战斗核心逻辑:提交战斗循环任务并通知双方
|
|
|
|
|
|
func (f *FightC) startBattle(startInfo info.FightStartOutboundInfo) {
|
2025-09-14 03:36:26 +08:00
|
|
|
|
|
2025-11-20 15:19:13 +08:00
|
|
|
|
f.startl.Do(func() {
|
2025-11-26 15:25:10 +08:00
|
|
|
|
|
2025-11-20 15:19:13 +08:00
|
|
|
|
// 提交战斗循环到战斗池(处理战斗池容量问题)
|
2026-01-26 14:12:12 +00:00
|
|
|
|
// if err := Fightpool.Invoke(f); err != nil {
|
|
|
|
|
|
// log.Panic(context.Background(), "战斗循环提交失败", "error", err)
|
|
|
|
|
|
// }
|
|
|
|
|
|
go f.battleLoop()
|
2025-11-26 15:25:10 +08:00
|
|
|
|
|
2026-04-03 00:02:51 +08:00
|
|
|
|
// 向双方广播战斗开始信息
|
2025-11-20 15:19:13 +08:00
|
|
|
|
f.Broadcast(func(ff *input.Input) {
|
|
|
|
|
|
ff.Player.SendPackCmd(2504, &startInfo)
|
|
|
|
|
|
})
|
2025-11-18 20:52:04 +00:00
|
|
|
|
})
|
2025-09-14 03:36:26 +08:00
|
|
|
|
}
|