feat(fight): 添加旧组队协议支持并优化战斗系统 - 实现了旧组队协议相关功能,包括GroupReadyFightFinish、GroupUseSkill、 GroupUseItem、GroupChangePet和GroupEscape方法 - 新增组队战斗相关的入站信息结构体定义 - 实现了组队BOSS战斗逻辑,添加groupBossSlotLimit常量 - 重构宠物技能设置逻辑,调整金币消耗时机 - 优化战斗循环逻辑,添加对无行动槽位的处理 - 改进AI行动逻辑,增加多位置目标选择机制 - 完善捕获系统上下文处理,修复空指针问题 - 添加战斗状态更新和数据同步机制 fix(pet-skill): 修复宠物技能设置中的金币扣除逻辑错误 - 将金币扣除逻辑移到验证之后 - 修正宠物技能数量限制检查的顺序 - 防止重复添加已有技能的情况 refactor(fight): 重构战斗系统代码结构 - 分离新旧组队协议的战斗创建逻辑 - 优化战斗输入验证和处理流程 - 改进战斗循环中的错误处理机制 ```
This commit is contained in:
@@ -43,7 +43,8 @@ func (h Controller) GroupUseSkill(data *GroupUseSkillInboundInfo, c *player.Play
|
|||||||
targetRelation = fight.SkillTargetAlly
|
targetRelation = fight.SkillTargetAlly
|
||||||
}
|
}
|
||||||
h.dispatchFightActionEnvelope(c, fight.NewSkillActionEnvelope(data.SkillId, int(data.ActorIndex), int(data.TargetPos), targetRelation, 0))
|
h.dispatchFightActionEnvelope(c, fight.NewSkillActionEnvelope(data.SkillId, int(data.ActorIndex), int(data.TargetPos), targetRelation, 0))
|
||||||
return nil, 0
|
c.SendPackCmd(7558, nil)
|
||||||
|
return nil, -1
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h Controller) GroupUseItem(data *GroupUseItemInboundInfo, c *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
|
func (h Controller) GroupUseItem(data *GroupUseItemInboundInfo, c *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
|
||||||
|
|||||||
@@ -75,54 +75,13 @@ func startMapBossFight(
|
|||||||
ourPets := p.GetPetInfo(100)
|
ourPets := p.GetPetInfo(100)
|
||||||
oppPets := ai.GetPetInfo(0)
|
oppPets := ai.GetPetInfo(0)
|
||||||
if mapNode != nil && mapNode.IsGroupBoss != 0 {
|
if mapNode != nil && mapNode.IsGroupBoss != 0 {
|
||||||
ourSlots := buildGroupBossPetSlots(ourPets, groupBossSlotLimit)
|
if len(ourPets) > 0 && len(oppPets) > 0 {
|
||||||
oppSlots := buildGroupBossPetSlots(oppPets, groupBossSlotLimit)
|
return fight.NewLegacyGroupFightSingleController(p, ai, ourPets, oppPets, groupBossSlotLimit, fn)
|
||||||
if len(ourSlots) > 0 && len(oppSlots) > 0 {
|
|
||||||
return fight.NewLegacyGroupFightSingleControllerN(p, ai, ourSlots, oppSlots, fn)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return fight.NewFight(p, ai, ourPets, oppPets, fn)
|
return fight.NewFight(p, ai, ourPets, oppPets, fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildGroupBossPetSlots(pets []model.PetInfo, slotLimit int) [][]model.PetInfo {
|
|
||||||
if len(pets) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
slots := make([][]model.PetInfo, 0, slotLimit)
|
|
||||||
for _, pet := range pets {
|
|
||||||
if pet.Hp == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if slotLimit <= 0 {
|
|
||||||
slotLimit = 3
|
|
||||||
}
|
|
||||||
if len(slots) < slotLimit {
|
|
||||||
slots = append(slots, []model.PetInfo{pet})
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if len(slots) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
var idx int = 0
|
|
||||||
for _, pet := range pets[len(slots):] {
|
|
||||||
if pet.Hp == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
for step := 0; step < len(slots); step++ {
|
|
||||||
slotIdx := (idx + step) % len(slots)
|
|
||||||
if len(slots[slotIdx]) < 6 {
|
|
||||||
slots[slotIdx] = append(slots[slotIdx], pet)
|
|
||||||
idx = (slotIdx + 1) % len(slots)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return slots
|
|
||||||
}
|
|
||||||
|
|
||||||
// OnPlayerFightNpcMonster 战斗野怪
|
// OnPlayerFightNpcMonster 战斗野怪
|
||||||
func (Controller) OnPlayerFightNpcMonster(req *FightNpcMonsterInboundInfo, p *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
|
func (Controller) OnPlayerFightNpcMonster(req *FightNpcMonsterInboundInfo, p *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
|
||||||
if err = p.CanFight(); err != 0 {
|
if err = p.CanFight(); err != 0 {
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ func (h *Controller) SwitchFlying(data *SwitchFlyingInboundInfo, c *player.Playe
|
|||||||
// PlayerPetCure 处理控制器请求。
|
// PlayerPetCure 处理控制器请求。
|
||||||
func (h *Controller) PlayerPetCure(data *PetCureInboundInfo, c *player.Player) (result *nono.PetCureOutboundEmpty, err errorcode.ErrorCode) { //这个时候player应该是空的
|
func (h *Controller) PlayerPetCure(data *PetCureInboundInfo, c *player.Player) (result *nono.PetCureOutboundEmpty, err errorcode.ErrorCode) { //这个时候player应该是空的
|
||||||
_ = data
|
_ = data
|
||||||
|
result = &nono.PetCureOutboundEmpty{}
|
||||||
if c.IsArenaHealLocked() {
|
if c.IsArenaHealLocked() {
|
||||||
return result, errorcode.ErrorCodes.ErrChampionCannotHeal
|
return result, errorcode.ErrorCodes.ErrChampionCannotHeal
|
||||||
}
|
}
|
||||||
@@ -73,6 +74,9 @@ func (h *Controller) PlayerPetCure(data *PetCureInboundInfo, c *player.Player) (
|
|||||||
for i := range c.Info.PetList {
|
for i := range c.Info.PetList {
|
||||||
c.Info.PetList[i].Cure()
|
c.Info.PetList[i].Cure()
|
||||||
}
|
}
|
||||||
|
for i := range c.Info.BackupPetList {
|
||||||
|
c.Info.BackupPetList[i].Cure()
|
||||||
|
}
|
||||||
c.Info.Coins -= nonoPetCureCost
|
c.Info.Coins -= nonoPetCureCost
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,6 +82,10 @@ func (f *FightC) submitAction(act action.BattleActionI) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
if replaceIndex >= 0 {
|
if replaceIndex >= 0 {
|
||||||
|
if f.LegacyGroupProtocol {
|
||||||
|
f.actionMu.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
f.pendingActions[replaceIndex] = act
|
f.pendingActions[replaceIndex] = act
|
||||||
} else {
|
} else {
|
||||||
f.pendingActions = append(f.pendingActions, act)
|
f.pendingActions = append(f.pendingActions, act)
|
||||||
@@ -295,9 +299,8 @@ func (f *FightC) ReadyFight(c common.PlayerI) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
f.Broadcast(func(ff *input.Input) {
|
f.BroadcastPlayers(func(p common.PlayerI) {
|
||||||
|
p.SendPackCmd(2404, &info.S2C_2404{UserID: c.GetInfo().UserID})
|
||||||
ff.Player.SendPackCmd(2404, &info.S2C_2404{UserID: c.GetInfo().UserID})
|
|
||||||
})
|
})
|
||||||
// 2. 标记当前玩家已准备完成
|
// 2. 标记当前玩家已准备完成
|
||||||
input := f.GetInputByPlayer(c, false)
|
input := f.GetInputByPlayer(c, false)
|
||||||
@@ -369,8 +372,12 @@ func (f *FightC) startBattle(startInfo info.FightStartOutboundInfo) {
|
|||||||
go f.battleLoop()
|
go f.battleLoop()
|
||||||
|
|
||||||
// 向双方广播战斗开始信息
|
// 向双方广播战斗开始信息
|
||||||
f.Broadcast(func(ff *input.Input) {
|
f.BroadcastPlayers(func(p common.PlayerI) {
|
||||||
f.sendFightPacket(ff.Player, fightPacketStart, &startInfo)
|
if f.LegacyGroupProtocol {
|
||||||
|
f.sendLegacyGroupStart(p)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
f.sendFightPacket(p, fightPacketStart, &startInfo)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package fight
|
|||||||
import (
|
import (
|
||||||
"blazing/common/utils"
|
"blazing/common/utils"
|
||||||
|
|
||||||
|
"blazing/logic/service/common"
|
||||||
"blazing/logic/service/fight/action"
|
"blazing/logic/service/fight/action"
|
||||||
"blazing/logic/service/fight/info"
|
"blazing/logic/service/fight/info"
|
||||||
"blazing/logic/service/fight/input"
|
"blazing/logic/service/fight/input"
|
||||||
@@ -422,11 +423,19 @@ func (f *FightC) enterturn(firstAttack, secondAttack *action.SelectSkillAction)
|
|||||||
|
|
||||||
attackValueResult := f.buildNoteUseSkillOutboundInfo()
|
attackValueResult := f.buildNoteUseSkillOutboundInfo()
|
||||||
//因为切完才能广播,所以必须和回合结束分开结算
|
//因为切完才能广播,所以必须和回合结束分开结算
|
||||||
f.Broadcast(func(fighter *input.Input) {
|
f.BroadcastPlayers(func(p common.PlayerI) {
|
||||||
for _, switchAction := range f.Switch {
|
for _, switchAction := range f.Switch {
|
||||||
if fighter.Player.GetInfo().UserID != switchAction.Reason.UserId {
|
if p.GetInfo().UserID != switchAction.Reason.UserId {
|
||||||
// println("切精灵", switchAction.Reason.UserId, switchAction.Reason.ID)
|
// println("切精灵", switchAction.Reason.UserId, switchAction.Reason.ID)
|
||||||
f.sendFightPacket(fighter.Player, fightPacketChangePetSuccess, &switchAction.Reason)
|
if f.LegacyGroupProtocol {
|
||||||
|
switchedInput := f.getInputByUserID(switchAction.Reason.UserId, int(switchAction.Reason.ActorIndex), false)
|
||||||
|
if switchedInput == nil {
|
||||||
|
switchedInput = f.getInputByUserID(switchAction.Reason.UserId, int(switchAction.ActorIndex), false)
|
||||||
|
}
|
||||||
|
f.sendLegacyGroupChangePetSuccess(p, switchedInput, &switchAction.Reason)
|
||||||
|
} else {
|
||||||
|
f.sendFightPacket(p, fightPacketChangePetSuccess, &switchAction.Reason)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -440,8 +449,12 @@ func (f *FightC) enterturn(firstAttack, secondAttack *action.SelectSkillAction)
|
|||||||
// })
|
// })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
f.BroadcastPlayers(func(p common.PlayerI) {
|
||||||
|
if !f.LegacyGroupProtocol {
|
||||||
|
f.sendFightPacket(p, fightPacketSkillResult, &attackValueResult)
|
||||||
|
}
|
||||||
|
})
|
||||||
f.Broadcast(func(fighter *input.Input) {
|
f.Broadcast(func(fighter *input.Input) {
|
||||||
f.sendFightPacket(fighter.Player, fightPacketSkillResult, &attackValueResult)
|
|
||||||
fighter.CanChange = 0
|
fighter.CanChange = 0
|
||||||
})
|
})
|
||||||
if f.closefight {
|
if f.closefight {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package fight
|
|||||||
import (
|
import (
|
||||||
"blazing/logic/service/common"
|
"blazing/logic/service/common"
|
||||||
"blazing/logic/service/fight/action"
|
"blazing/logic/service/fight/action"
|
||||||
|
"blazing/logic/service/fight/info"
|
||||||
"blazing/logic/service/fight/input"
|
"blazing/logic/service/fight/input"
|
||||||
"blazing/modules/player/model"
|
"blazing/modules/player/model"
|
||||||
)
|
)
|
||||||
@@ -38,6 +39,17 @@ const (
|
|||||||
|
|
||||||
type fightPacketKind uint8
|
type fightPacketKind uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
fightPacketReady fightPacketKind = iota
|
||||||
|
fightPacketStart
|
||||||
|
fightPacketSkillResult
|
||||||
|
fightPacketOver
|
||||||
|
fightPacketChangePetSuccess
|
||||||
|
fightPacketUseItem
|
||||||
|
fightPacketChat
|
||||||
|
fightPacketLoadPercentNotice
|
||||||
|
)
|
||||||
|
|
||||||
type legacyEscapeSuccessInfo struct {
|
type legacyEscapeSuccessInfo struct {
|
||||||
UserID uint32 `struc:"uint32"`
|
UserID uint32 `struc:"uint32"`
|
||||||
Nick string `struc:"[16]byte"`
|
Nick string `struc:"[16]byte"`
|
||||||
@@ -50,6 +62,14 @@ type legacyBoutDoneInfo struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type legacySpriteDieInfo struct {
|
type legacySpriteDieInfo struct {
|
||||||
|
Count uint8 `struc:"uint8"`
|
||||||
|
Side uint8 `struc:"uint8"`
|
||||||
|
ActorIndex uint8 `struc:"uint8"`
|
||||||
|
Flag uint8 `struc:"uint8"`
|
||||||
|
HasBackup uint32 `struc:"uint32"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type legacyLegacySpriteDieItem struct {
|
||||||
Flag uint8 `struc:"uint8"`
|
Flag uint8 `struc:"uint8"`
|
||||||
Side uint8 `struc:"uint8"`
|
Side uint8 `struc:"uint8"`
|
||||||
ActorIndex uint8 `struc:"uint8"`
|
ActorIndex uint8 `struc:"uint8"`
|
||||||
@@ -57,16 +77,132 @@ type legacySpriteDieInfo struct {
|
|||||||
HasBackup uint32 `struc:"uint32"`
|
HasBackup uint32 `struc:"uint32"`
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
type legacyGroupReadyToFightInfo struct {
|
||||||
fightPacketReady fightPacketKind = iota
|
Model uint32 `struc:"uint32"`
|
||||||
fightPacketStart
|
GroupOneInfo legacyReadyToFightTeam `struc:""`
|
||||||
fightPacketSkillResult
|
GroupTwoInfo legacyReadyToFightTeam `struc:""`
|
||||||
fightPacketOver
|
}
|
||||||
fightPacketChangePetSuccess
|
|
||||||
fightPacketUseItem
|
type legacyReadyToFightTeam struct {
|
||||||
fightPacketChat
|
InvitorID uint8 `struc:"uint8"`
|
||||||
fightPacketLoadPercentNotice
|
LeaderID uint32 `struc:"uint32"`
|
||||||
)
|
GroupMembCnt uint8 `struc:"sizeof=GroupList"`
|
||||||
|
GroupList []legacyReadyFightUser `struc:""`
|
||||||
|
}
|
||||||
|
|
||||||
|
type legacyReadyFightUser struct {
|
||||||
|
UserID uint32 `struc:"uint32"`
|
||||||
|
Nick string `struc:"[16]byte"`
|
||||||
|
MonCnt uint32 `struc:"sizeof=MonList"`
|
||||||
|
MonList []legacyReadyFightPet `struc:""`
|
||||||
|
}
|
||||||
|
|
||||||
|
type legacyReadyFightPet struct {
|
||||||
|
ID uint32 `struc:"uint32"`
|
||||||
|
MoveCnt uint32 `struc:"sizeof=MoveList"`
|
||||||
|
MoveList []uint32 `struc:"[]uint32"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type legacyGroupStartInfo struct {
|
||||||
|
IsGank uint8 `struc:"uint8"`
|
||||||
|
GroupOneN uint8 `struc:"sizeof=GroupOne"`
|
||||||
|
GroupOne []legacyGroupStartPet `struc:""`
|
||||||
|
GroupTwoN uint8 `struc:"sizeof=GroupTwo"`
|
||||||
|
GroupTwo []legacyGroupStartPet `struc:""`
|
||||||
|
}
|
||||||
|
|
||||||
|
type legacyGroupStartPet struct {
|
||||||
|
Side uint8 `struc:"uint8"`
|
||||||
|
Pos uint8 `struc:"uint8"`
|
||||||
|
UserID uint32 `struc:"uint32"`
|
||||||
|
IsChange uint8 `struc:"uint8"`
|
||||||
|
PetID uint32 `struc:"uint32"`
|
||||||
|
CatchTime uint32 `struc:"uint32"`
|
||||||
|
Hp uint32 `struc:"uint32"`
|
||||||
|
MaxHp uint32 `struc:"uint32"`
|
||||||
|
Level uint32 `struc:"uint32"`
|
||||||
|
Reserve uint32 `struc:"uint32"`
|
||||||
|
Flag uint32 `struc:"uint32"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type legacyGroupSkillHurtPacket struct {
|
||||||
|
IsGank uint8 `struc:"uint8"`
|
||||||
|
Attack legacyGroupSkillAttackInfo `struc:""`
|
||||||
|
Attacked legacyGroupSkillDefendInfo `struc:""`
|
||||||
|
}
|
||||||
|
|
||||||
|
type legacyGroupSkillAttackInfo struct {
|
||||||
|
IsAttackor uint8 `struc:"uint8"`
|
||||||
|
Side uint8 `struc:"uint8"`
|
||||||
|
Pos uint8 `struc:"uint8"`
|
||||||
|
UserID uint32 `struc:"uint32"`
|
||||||
|
StatusList [20]uint8 `struc:"[20]byte"`
|
||||||
|
Reserve1 uint8 `struc:"uint8"`
|
||||||
|
Reserve2 uint8 `struc:"uint8"`
|
||||||
|
BatLvList [6]uint8 `struc:"[6]byte"`
|
||||||
|
PetID uint32 `struc:"uint32"`
|
||||||
|
MoveID uint32 `struc:"uint32"`
|
||||||
|
Hp uint32 `struc:"uint32"`
|
||||||
|
MaxHp uint32 `struc:"uint32"`
|
||||||
|
MoveCnt uint32 `struc:"sizeof=MoveMap"`
|
||||||
|
MoveMap []legacyGroupSkillMoveInfo `struc:""`
|
||||||
|
Flag uint32 `struc:"uint32"`
|
||||||
|
IsCrit uint32 `struc:"uint32"`
|
||||||
|
EffectName uint32 `struc:"uint32"`
|
||||||
|
AtkTimes uint32 `struc:"uint32"`
|
||||||
|
Dmg int32 `struc:"int32"`
|
||||||
|
ChgHp int32 `struc:"int32"`
|
||||||
|
SideEffectLen uint32 `struc:"uint32"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type legacyGroupSkillDefendInfo struct {
|
||||||
|
IsAttackor uint8 `struc:"uint8"`
|
||||||
|
Side uint8 `struc:"uint8"`
|
||||||
|
Pos uint8 `struc:"uint8"`
|
||||||
|
UserID uint32 `struc:"uint32"`
|
||||||
|
StatusList [20]uint8 `struc:"[20]byte"`
|
||||||
|
Reserve1 uint8 `struc:"uint8"`
|
||||||
|
Reserve2 uint8 `struc:"uint8"`
|
||||||
|
BatLvList [6]uint8 `struc:"[6]byte"`
|
||||||
|
PetID uint32 `struc:"uint32"`
|
||||||
|
MoveID uint32 `struc:"uint32"`
|
||||||
|
Hp uint32 `struc:"uint32"`
|
||||||
|
MaxHp uint32 `struc:"uint32"`
|
||||||
|
MoveCnt uint32 `struc:"sizeof=MoveMap"`
|
||||||
|
MoveMap []legacyGroupSkillMoveInfo `struc:""`
|
||||||
|
Flag uint32 `struc:"uint32"`
|
||||||
|
SideEffectLen uint32 `struc:"uint32"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type legacyGroupSkillMoveInfo struct {
|
||||||
|
MoveID uint32 `struc:"uint32"`
|
||||||
|
PP uint32 `struc:"uint32"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type legacyGroupFightOverInfo struct {
|
||||||
|
IsGank uint8 `struc:"uint8"`
|
||||||
|
Reason uint32 `struc:"uint32"`
|
||||||
|
WinnerID uint32 `struc:"uint32"`
|
||||||
|
Reserve uint32 `struc:"uint32"`
|
||||||
|
TwoTimes uint32 `struc:"uint32"`
|
||||||
|
ThreeTimes uint32 `struc:"uint32"`
|
||||||
|
AutoFightTime uint32 `struc:"uint32"`
|
||||||
|
Reserve2 uint32 `struc:"uint32"`
|
||||||
|
EnergyTime uint32 `struc:"uint32"`
|
||||||
|
LearnTimes uint32 `struc:"uint32"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type legacyGroupChangePetSuccessInfo struct {
|
||||||
|
Side uint8 `struc:"uint8"`
|
||||||
|
Pos uint8 `struc:"uint8"`
|
||||||
|
UserID uint32 `struc:"uint32"`
|
||||||
|
PetID uint32 `struc:"uint32"`
|
||||||
|
CatchTime uint32 `struc:"uint32"`
|
||||||
|
Level uint32 `struc:"uint32"`
|
||||||
|
Hp uint32 `struc:"uint32"`
|
||||||
|
MaxHp uint32 `struc:"uint32"`
|
||||||
|
SkinID uint32 `struc:"uint32"`
|
||||||
|
}
|
||||||
|
|
||||||
func groupModelByFight(f *FightC) uint32 {
|
func groupModelByFight(f *FightC) uint32 {
|
||||||
if f == nil {
|
if f == nil {
|
||||||
@@ -84,37 +220,15 @@ func groupModelByFight(f *FightC) uint32 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FightC) sendLegacyGroupOver(player common.PlayerI, over *model.FightOverInfo) {
|
|
||||||
if player == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if over == nil {
|
|
||||||
over = &model.FightOverInfo{}
|
|
||||||
}
|
|
||||||
f.sendFightPacket(player, fightPacketOver, over)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FightC) fightPacketCmd(kind fightPacketKind) uint32 {
|
func (f *FightC) fightPacketCmd(kind fightPacketKind) uint32 {
|
||||||
switch kind {
|
switch kind {
|
||||||
case fightPacketReady:
|
case fightPacketReady:
|
||||||
if f != nil && f.LegacyGroupProtocol {
|
|
||||||
return groupCmdReadyToFight
|
|
||||||
}
|
|
||||||
return 2503
|
return 2503
|
||||||
case fightPacketStart:
|
case fightPacketStart:
|
||||||
if f != nil && f.LegacyGroupProtocol {
|
|
||||||
return groupCmdStartFight
|
|
||||||
}
|
|
||||||
return 2504
|
return 2504
|
||||||
case fightPacketSkillResult:
|
case fightPacketSkillResult:
|
||||||
if f != nil && f.LegacyGroupProtocol {
|
|
||||||
return groupCmdSkillHurt
|
|
||||||
}
|
|
||||||
return 2505
|
return 2505
|
||||||
case fightPacketOver:
|
case fightPacketOver:
|
||||||
if f != nil && f.LegacyGroupProtocol {
|
|
||||||
return groupCmdFightOver
|
|
||||||
}
|
|
||||||
return 2506
|
return 2506
|
||||||
case fightPacketChangePetSuccess:
|
case fightPacketChangePetSuccess:
|
||||||
if f != nil && f.LegacyGroupProtocol {
|
if f != nil && f.LegacyGroupProtocol {
|
||||||
@@ -152,6 +266,232 @@ func (f *FightC) sendFightPacket(player common.PlayerI, kind fightPacketKind, pa
|
|||||||
player.SendPackCmd(cmd, payload)
|
player.SendPackCmd(cmd, payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *FightC) sendLegacyGroupReady(player common.PlayerI) {
|
||||||
|
if f == nil || !f.LegacyGroupProtocol || player == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
player.SendPackCmd(groupCmdReadyToFight, f.buildLegacyGroupReadyInfo())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FightC) buildLegacyGroupReadyInfo() *legacyGroupReadyToFightInfo {
|
||||||
|
return &legacyGroupReadyToFightInfo{
|
||||||
|
Model: groupModelByFight(f),
|
||||||
|
GroupOneInfo: f.buildLegacyReadyTeam(f.OurPlayers, f.Our),
|
||||||
|
GroupTwoInfo: f.buildLegacyReadyTeam(f.OppPlayers, f.Opp),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FightC) buildLegacyReadyTeam(players []common.PlayerI, inputs []*input.Input) legacyReadyToFightTeam {
|
||||||
|
team := legacyReadyToFightTeam{InvitorID: 1}
|
||||||
|
users := make([]legacyReadyFightUser, 0, len(players))
|
||||||
|
for _, p := range players {
|
||||||
|
if p == nil || p.GetInfo() == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
users = append(users, legacyReadyFightUser{
|
||||||
|
UserID: p.GetInfo().UserID,
|
||||||
|
Nick: p.GetInfo().Nick,
|
||||||
|
MonList: collectLegacyReadyPetsByController(inputs, p.GetInfo().UserID),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if len(users) == 0 {
|
||||||
|
if fallback := firstNonNilInput(inputs); fallback != nil && fallback.Player != nil && fallback.Player.GetInfo() != nil {
|
||||||
|
info := fallback.Player.GetInfo()
|
||||||
|
users = append(users, legacyReadyFightUser{
|
||||||
|
UserID: info.UserID,
|
||||||
|
Nick: info.Nick,
|
||||||
|
MonList: collectLegacyReadyPetsByController(inputs, info.UserID),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for idx := range users {
|
||||||
|
users[idx].MonCnt = uint32(len(users[idx].MonList))
|
||||||
|
}
|
||||||
|
if len(users) > 0 {
|
||||||
|
team.LeaderID = users[0].UserID
|
||||||
|
}
|
||||||
|
team.GroupList = users
|
||||||
|
return team
|
||||||
|
}
|
||||||
|
|
||||||
|
func collectLegacyReadyPetsByController(inputs []*input.Input, controllerID uint32) []legacyReadyFightPet {
|
||||||
|
pets := make([]legacyReadyFightPet, 0, 6)
|
||||||
|
for _, in := range inputs {
|
||||||
|
if in == nil || !in.ControlledBy(controllerID) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
currentPet := in.CurrentPet()
|
||||||
|
if currentPet == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
pets = append(pets, buildLegacyReadyFightPet(currentPet))
|
||||||
|
}
|
||||||
|
return pets
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildLegacyReadyFightPet(pet *info.BattlePetEntity) legacyReadyFightPet {
|
||||||
|
result := legacyReadyFightPet{}
|
||||||
|
if pet == nil {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
moves := make([]uint32, 0, len(pet.Info.SkillList))
|
||||||
|
for _, skill := range pet.Info.SkillList {
|
||||||
|
if skill.ID == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
moves = append(moves, skill.ID)
|
||||||
|
}
|
||||||
|
result.ID = pet.Info.ID
|
||||||
|
result.MoveList = moves
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func firstNonNilInput(inputs []*input.Input) *input.Input {
|
||||||
|
for _, in := range inputs {
|
||||||
|
if in != nil {
|
||||||
|
return in
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FightC) sendLegacyGroupStart(player common.PlayerI) {
|
||||||
|
if f == nil || !f.LegacyGroupProtocol || player == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
player.SendPackCmd(groupCmdStartFight, f.buildLegacyGroupStartInfo())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FightC) buildLegacyGroupStartInfo() *legacyGroupStartInfo {
|
||||||
|
return &legacyGroupStartInfo{
|
||||||
|
IsGank: 0,
|
||||||
|
GroupOne: f.collectLegacyGroupStartPets(f.Our, 1),
|
||||||
|
GroupTwo: f.collectLegacyGroupStartPets(f.Opp, 2),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FightC) collectLegacyGroupStartPets(inputs []*input.Input, side uint8) []legacyGroupStartPet {
|
||||||
|
ret := make([]legacyGroupStartPet, 0, len(inputs))
|
||||||
|
for pos, in := range inputs {
|
||||||
|
if in == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
currentPet := in.CurrentPet()
|
||||||
|
if currentPet == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
userID := uint32(0)
|
||||||
|
if in.Player != nil && in.Player.GetInfo() != nil {
|
||||||
|
userID = in.Player.GetInfo().UserID
|
||||||
|
}
|
||||||
|
ret = append(ret, legacyGroupStartPet{
|
||||||
|
Side: side,
|
||||||
|
Pos: uint8(pos),
|
||||||
|
UserID: userID,
|
||||||
|
IsChange: 0,
|
||||||
|
PetID: currentPet.Info.ID,
|
||||||
|
CatchTime: currentPet.Info.CatchTime,
|
||||||
|
Hp: currentPet.Info.Hp,
|
||||||
|
MaxHp: currentPet.Info.MaxHp,
|
||||||
|
Level: currentPet.Info.Level,
|
||||||
|
Reserve: 0,
|
||||||
|
Flag: 1,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FightC) sendLegacyGroupOver(player common.PlayerI, over *model.FightOverInfo) {
|
||||||
|
if f == nil || !f.LegacyGroupProtocol || player == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
player.SendPackCmd(groupCmdFightOver, f.buildLegacyGroupOverInfo(over))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FightC) buildLegacyGroupOverInfo(over *model.FightOverInfo) *legacyGroupFightOverInfo {
|
||||||
|
result := &legacyGroupFightOverInfo{}
|
||||||
|
if over != nil {
|
||||||
|
result.Reason = resolveLegacyGroupFightOverReason(over)
|
||||||
|
result.WinnerID = over.WinnerId
|
||||||
|
}
|
||||||
|
if our := f.primaryOurPlayer(); our != nil && our.GetInfo() != nil {
|
||||||
|
playerInfo := our.GetInfo()
|
||||||
|
result.TwoTimes = uint32(playerInfo.TwoTimes)
|
||||||
|
result.ThreeTimes = uint32(playerInfo.ThreeTimes)
|
||||||
|
result.AutoFightTime = playerInfo.AutoFightTime
|
||||||
|
result.EnergyTime = uint32(playerInfo.EnergyTime)
|
||||||
|
result.LearnTimes = playerInfo.LearnTimes
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func mapLegacyGroupFightOverReason(reason model.EnumBattleOverReason) uint32 {
|
||||||
|
switch reason {
|
||||||
|
case model.BattleOverReason.PlayerOffline:
|
||||||
|
return 2
|
||||||
|
case model.BattleOverReason.PlayerOVerTime:
|
||||||
|
return 3
|
||||||
|
case model.BattleOverReason.NOTwind:
|
||||||
|
return 4
|
||||||
|
case model.BattleOverReason.DefaultEnd:
|
||||||
|
return 1
|
||||||
|
case model.BattleOverReason.PlayerEscape:
|
||||||
|
return 6
|
||||||
|
default:
|
||||||
|
return 5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resolveLegacyGroupFightOverReason(over *model.FightOverInfo) uint32 {
|
||||||
|
if over == nil {
|
||||||
|
return 5
|
||||||
|
}
|
||||||
|
switch over.Reason {
|
||||||
|
case model.BattleOverReason.PlayerOffline:
|
||||||
|
return 2
|
||||||
|
case model.BattleOverReason.PlayerOVerTime:
|
||||||
|
return 3
|
||||||
|
case model.BattleOverReason.PlayerEscape:
|
||||||
|
return 6
|
||||||
|
case model.BattleOverReason.NOTwind:
|
||||||
|
return 4
|
||||||
|
}
|
||||||
|
if over.WinnerId != 0 {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return mapLegacyGroupFightOverReason(over.Reason)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FightC) sendLegacyGroupChangePetSuccess(player common.PlayerI, in *input.Input, reason *info.ChangePetInfo) {
|
||||||
|
if f == nil || !f.LegacyGroupProtocol || player == nil || in == nil || reason == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
player.SendPackCmd(groupCmdChangePetSuc, f.buildLegacyGroupChangePetSuccessInfo(in, reason))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FightC) buildLegacyGroupChangePetSuccessInfo(in *input.Input, reason *info.ChangePetInfo) *legacyGroupChangePetSuccessInfo {
|
||||||
|
result := &legacyGroupChangePetSuccessInfo{}
|
||||||
|
if in == nil || reason == nil {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
if !f.isOurPlayerID(in.UserID) {
|
||||||
|
result.Side = 2
|
||||||
|
} else {
|
||||||
|
result.Side = 1
|
||||||
|
}
|
||||||
|
result.Pos = uint8(in.TeamSlotIndex())
|
||||||
|
result.UserID = reason.UserId
|
||||||
|
result.PetID = reason.ID
|
||||||
|
result.CatchTime = reason.CatchTime
|
||||||
|
result.Level = reason.Level
|
||||||
|
result.Hp = reason.Hp
|
||||||
|
result.MaxHp = reason.MaxHp
|
||||||
|
if currentPet := in.CurrentPet(); currentPet != nil {
|
||||||
|
result.SkinID = currentPet.Info.SkinID
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
func (f *FightC) SendLegacyEscapeSuccess(player common.PlayerI, actorIndex int) {
|
func (f *FightC) SendLegacyEscapeSuccess(player common.PlayerI, actorIndex int) {
|
||||||
if f == nil || !f.LegacyGroupProtocol || player == nil {
|
if f == nil || !f.LegacyGroupProtocol || player == nil {
|
||||||
return
|
return
|
||||||
@@ -166,11 +506,8 @@ func (f *FightC) SendLegacyEscapeSuccess(player common.PlayerI, actorIndex int)
|
|||||||
Side: side,
|
Side: side,
|
||||||
ActorIndex: uint8(actorIndex),
|
ActorIndex: uint8(actorIndex),
|
||||||
}
|
}
|
||||||
f.Broadcast(func(ff *input.Input) {
|
f.BroadcastPlayers(func(p common.PlayerI) {
|
||||||
if ff == nil || ff.Player == nil {
|
p.SendPackCmd(groupCmdEscapeSuc, &payload)
|
||||||
return
|
|
||||||
}
|
|
||||||
ff.Player.SendPackCmd(groupCmdEscapeSuc, &payload)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,19 +515,147 @@ func (f *FightC) sendLegacyRoundBroadcast(firstAttack, secondAttack *action.Sele
|
|||||||
if f == nil || !f.LegacyGroupProtocol {
|
if f == nil || !f.LegacyGroupProtocol {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if firstAttack != nil {
|
||||||
|
f.sendLegacyGroupSkillHurt(firstAttack)
|
||||||
|
}
|
||||||
|
if secondAttack != nil {
|
||||||
|
f.sendLegacyGroupSkillHurt(secondAttack)
|
||||||
|
}
|
||||||
f.sendLegacyGroupBoutDone()
|
f.sendLegacyGroupBoutDone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *FightC) sendLegacyGroupSkillHurt(skillAction *action.SelectSkillAction) {
|
||||||
|
if f == nil || !f.LegacyGroupProtocol || skillAction == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
packet := f.buildLegacyGroupSkillHurtPacket(skillAction)
|
||||||
|
if packet == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
f.BroadcastPlayers(func(p common.PlayerI) {
|
||||||
|
p.SendPackCmd(groupCmdSkillHurt, packet)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FightC) buildLegacyGroupSkillHurtPacket(skillAction *action.SelectSkillAction) *legacyGroupSkillHurtPacket {
|
||||||
|
attacker := f.GetInputByAction(skillAction, false)
|
||||||
|
defender := f.GetInputByAction(skillAction, true)
|
||||||
|
if attacker == nil || defender == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &legacyGroupSkillHurtPacket{
|
||||||
|
IsGank: 0,
|
||||||
|
Attack: f.buildLegacyGroupSkillAttackInfo(skillAction, attacker),
|
||||||
|
Attacked: f.buildLegacyGroupSkillDefendInfo(defender),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FightC) fillLegacyGroupSkillCommonFields(
|
||||||
|
self *input.Input,
|
||||||
|
isAttackor uint8,
|
||||||
|
statusList *[20]uint8,
|
||||||
|
batLvList *[6]uint8,
|
||||||
|
) (side uint8, pos uint8, userID uint32, petID uint32, hp uint32, maxHP uint32, moveMap []legacyGroupSkillMoveInfo, flag uint32) {
|
||||||
|
if self == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !f.isOurPlayerID(self.UserID) {
|
||||||
|
side = 2
|
||||||
|
} else {
|
||||||
|
side = 1
|
||||||
|
}
|
||||||
|
pos = uint8(self.TeamSlotIndex())
|
||||||
|
userID = self.UserID
|
||||||
|
attackValue := self.AttackValue
|
||||||
|
if attackValue == nil {
|
||||||
|
attackValue = info.NewAttackValue(self.UserID)
|
||||||
|
}
|
||||||
|
for i := 0; i < len(attackValue.Status) && i < 20; i++ {
|
||||||
|
statusList[i] = uint8(attackValue.Status[i])
|
||||||
|
}
|
||||||
|
for i := 0; i < len(attackValue.Prop) && i < len(batLvList); i++ {
|
||||||
|
batLvList[i] = uint8(attackValue.Prop[i])
|
||||||
|
}
|
||||||
|
currentPet := self.CurrentPet()
|
||||||
|
if currentPet != nil {
|
||||||
|
petID = currentPet.Info.ID
|
||||||
|
hp = currentPet.Info.Hp
|
||||||
|
maxHP = currentPet.Info.MaxHp
|
||||||
|
moveMap = collectLegacyGroupSkillMoves(currentPet.Info.SkillList)
|
||||||
|
} else {
|
||||||
|
hp = clampLegacyInt32ToUint32(attackValue.RemainHp)
|
||||||
|
maxHP = attackValue.MaxHp
|
||||||
|
moveMap = collectLegacyGroupSkillMoves(attackValue.SkillList)
|
||||||
|
}
|
||||||
|
flag = attackValue.State
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FightC) buildLegacyGroupSkillAttackInfo(skillAction *action.SelectSkillAction, self *input.Input) legacyGroupSkillAttackInfo {
|
||||||
|
result := legacyGroupSkillAttackInfo{}
|
||||||
|
if self == nil {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
result.IsAttackor = 0
|
||||||
|
result.Side, result.Pos, result.UserID, result.PetID, result.Hp, result.MaxHp, result.MoveMap, result.Flag =
|
||||||
|
f.fillLegacyGroupSkillCommonFields(self, result.IsAttackor, &result.StatusList, &result.BatLvList)
|
||||||
|
attackValue := self.AttackValue
|
||||||
|
if attackValue == nil {
|
||||||
|
attackValue = info.NewAttackValue(self.UserID)
|
||||||
|
}
|
||||||
|
if skillAction != nil && skillAction.SkillEntity != nil {
|
||||||
|
result.MoveID = uint32(skillAction.SkillEntity.XML.ID)
|
||||||
|
} else {
|
||||||
|
result.MoveID = attackValue.SkillID
|
||||||
|
}
|
||||||
|
result.IsCrit = attackValue.IsCritical
|
||||||
|
result.EffectName = attackValue.State
|
||||||
|
result.AtkTimes = 1
|
||||||
|
result.Dmg = int32(attackValue.LostHp)
|
||||||
|
result.ChgHp = attackValue.GainHp
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FightC) buildLegacyGroupSkillDefendInfo(self *input.Input) legacyGroupSkillDefendInfo {
|
||||||
|
result := legacyGroupSkillDefendInfo{}
|
||||||
|
if self == nil {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
result.IsAttackor = 1
|
||||||
|
result.Side, result.Pos, result.UserID, result.PetID, result.Hp, result.MaxHp, result.MoveMap, result.Flag =
|
||||||
|
f.fillLegacyGroupSkillCommonFields(self, result.IsAttackor, &result.StatusList, &result.BatLvList)
|
||||||
|
result.MoveID = 0
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func collectLegacyGroupSkillMoves(skills []model.SkillInfo) []legacyGroupSkillMoveInfo {
|
||||||
|
moves := make([]legacyGroupSkillMoveInfo, 0, len(skills))
|
||||||
|
for _, skill := range skills {
|
||||||
|
if skill.ID == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
moves = append(moves, legacyGroupSkillMoveInfo{
|
||||||
|
MoveID: skill.ID,
|
||||||
|
PP: skill.PP,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return moves
|
||||||
|
}
|
||||||
|
|
||||||
|
func clampLegacyInt32ToUint32(v int32) uint32 {
|
||||||
|
if v < 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return uint32(v)
|
||||||
|
}
|
||||||
|
|
||||||
func (f *FightC) sendLegacyGroupBoutDone() {
|
func (f *FightC) sendLegacyGroupBoutDone() {
|
||||||
if f == nil || !f.LegacyGroupProtocol {
|
if f == nil || !f.LegacyGroupProtocol {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
payload := legacyBoutDoneInfo{Round: f.Round}
|
payload := legacyBoutDoneInfo{Round: f.Round}
|
||||||
f.Broadcast(func(ff *input.Input) {
|
f.BroadcastPlayers(func(p common.PlayerI) {
|
||||||
if ff == nil || ff.Player == nil {
|
p.SendPackCmd(groupCmdBoutDone, &payload)
|
||||||
return
|
|
||||||
}
|
|
||||||
ff.Player.SendPackCmd(groupCmdBoutDone, &payload)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,16 +672,13 @@ func (f *FightC) sendLegacySpriteDie(in *input.Input, hasBackup bool) {
|
|||||||
data = 1
|
data = 1
|
||||||
}
|
}
|
||||||
payload := legacySpriteDieInfo{
|
payload := legacySpriteDieInfo{
|
||||||
Flag: 1,
|
Count: 1,
|
||||||
Side: side,
|
Side: side,
|
||||||
ActorIndex: uint8(in.TeamSlotIndex()),
|
ActorIndex: uint8(in.TeamSlotIndex()),
|
||||||
Reserve: 1,
|
Flag: 1,
|
||||||
HasBackup: data,
|
HasBackup: data,
|
||||||
}
|
}
|
||||||
f.Broadcast(func(ff *input.Input) {
|
f.BroadcastPlayers(func(p common.PlayerI) {
|
||||||
if ff == nil || ff.Player == nil {
|
p.SendPackCmd(groupCmdSpriteDie, &payload)
|
||||||
return
|
|
||||||
}
|
|
||||||
ff.Player.SendPackCmd(groupCmdSpriteDie, &payload)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -528,6 +528,27 @@ func (f *FightC) Broadcast(t func(ff *input.Input)) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *FightC) BroadcastPlayers(t func(common.PlayerI)) {
|
||||||
|
if f == nil || t == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
seen := make(map[uint32]struct{}, len(f.OurPlayers)+len(f.OppPlayers))
|
||||||
|
visit := func(players []common.PlayerI) {
|
||||||
|
for _, p := range players {
|
||||||
|
if p == nil || p.GetInfo() == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if _, ok := seen[p.GetInfo().UserID]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
seen[p.GetInfo().UserID] = struct{}{}
|
||||||
|
t(p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
visit(f.OurPlayers)
|
||||||
|
visit(f.OppPlayers)
|
||||||
|
}
|
||||||
|
|
||||||
func (f *FightC) GetOverChan() chan struct{} {
|
func (f *FightC) GetOverChan() chan struct{} {
|
||||||
return f.over
|
return f.over
|
||||||
|
|
||||||
|
|||||||
@@ -173,10 +173,14 @@ func (f *FightC) battleLoop() {
|
|||||||
|
|
||||||
//大乱斗,给个延迟
|
//大乱斗,给个延迟
|
||||||
//<-time.After(1000)
|
//<-time.After(1000)
|
||||||
f.Broadcast(func(ff *input.Input) {
|
f.BroadcastPlayers(func(p common.PlayerI) {
|
||||||
f.sendFightPacket(ff.Player, fightPacketOver, &f.FightOverInfo)
|
if f.LegacyGroupProtocol {
|
||||||
|
f.sendLegacyGroupOver(p, &f.FightOverInfo)
|
||||||
|
} else {
|
||||||
|
f.sendFightPacket(p, fightPacketOver, &f.FightOverInfo)
|
||||||
|
}
|
||||||
|
|
||||||
ff.Player.QuitFight()
|
p.QuitFight()
|
||||||
|
|
||||||
//待退出玩家战斗状态
|
//待退出玩家战斗状态
|
||||||
})
|
})
|
||||||
@@ -260,7 +264,11 @@ func (f *FightC) collectPlayerActions(expectedSlots map[actionSlotKey]struct{})
|
|||||||
ret.Reason = reason
|
ret.Reason = reason
|
||||||
ret.Reason.ActorIndex = uint32(ret.ActorIndex)
|
ret.Reason.ActorIndex = uint32(ret.ActorIndex)
|
||||||
|
|
||||||
f.sendFightPacket(selfinput.Player, fightPacketChangePetSuccess, &ret.Reason)
|
if f.LegacyGroupProtocol {
|
||||||
|
f.sendLegacyGroupChangePetSuccess(selfinput.Player, selfinput, &ret.Reason)
|
||||||
|
} else {
|
||||||
|
f.sendFightPacket(selfinput.Player, fightPacketChangePetSuccess, &ret.Reason)
|
||||||
|
}
|
||||||
|
|
||||||
f.Switch[key] = ret
|
f.Switch[key] = ret
|
||||||
|
|
||||||
@@ -281,7 +289,11 @@ func (f *FightC) collectPlayerActions(expectedSlots map[actionSlotKey]struct{})
|
|||||||
selfinput.CanChange = 0
|
selfinput.CanChange = 0
|
||||||
if f.Info.Status == info.BattleMode.FIGHT_WITH_NPC && paction.GetPlayerID() == 0 {
|
if f.Info.Status == info.BattleMode.FIGHT_WITH_NPC && paction.GetPlayerID() == 0 {
|
||||||
f.Switch = make(map[actionSlotKey]*action.ActiveSwitchAction)
|
f.Switch = make(map[actionSlotKey]*action.ActiveSwitchAction)
|
||||||
f.sendFightPacket(f.Our[0].Player, fightPacketChangePetSuccess, &ret.Reason)
|
if f.LegacyGroupProtocol {
|
||||||
|
f.sendLegacyGroupChangePetSuccess(f.Our[0].Player, selfinput, &ret.Reason)
|
||||||
|
} else {
|
||||||
|
f.sendFightPacket(f.Our[0].Player, fightPacketChangePetSuccess, &ret.Reason)
|
||||||
|
}
|
||||||
//println("AI出手死切")
|
//println("AI出手死切")
|
||||||
f.triggerNPCActions() // boss出手后获取出招
|
f.triggerNPCActions() // boss出手后获取出招
|
||||||
|
|
||||||
@@ -597,12 +609,12 @@ func (f *FightC) handleItemAction(a *action.UseItemAction) {
|
|||||||
case gconv.Int(item.HP) != 0:
|
case gconv.Int(item.HP) != 0:
|
||||||
addhp := item.HP
|
addhp := item.HP
|
||||||
source.Heal(source, a, alpacadecimal.NewFromInt(int64(addhp)))
|
source.Heal(source, a, alpacadecimal.NewFromInt(int64(addhp)))
|
||||||
f.Broadcast(func(ff *input.Input) {
|
f.BroadcastPlayers(func(p common.PlayerI) {
|
||||||
currentPet := source.PrimaryCurPet()
|
currentPet := source.PrimaryCurPet()
|
||||||
if currentPet == nil {
|
if currentPet == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
f.sendFightPacket(ff.Player, fightPacketUseItem, &info.UsePetIteminfo{
|
f.sendFightPacket(p, fightPacketUseItem, &info.UsePetIteminfo{
|
||||||
UserID: source.UserID,
|
UserID: source.UserID,
|
||||||
ChangeHp: int32(addhp),
|
ChangeHp: int32(addhp),
|
||||||
ItemID: uint32(item.ID),
|
ItemID: uint32(item.ID),
|
||||||
@@ -612,12 +624,12 @@ func (f *FightC) handleItemAction(a *action.UseItemAction) {
|
|||||||
})
|
})
|
||||||
case gconv.Int(item.PP) != 0:
|
case gconv.Int(item.PP) != 0:
|
||||||
source.HealPP(item.PP)
|
source.HealPP(item.PP)
|
||||||
f.Broadcast(func(ff *input.Input) {
|
f.BroadcastPlayers(func(p common.PlayerI) {
|
||||||
currentPet := source.PrimaryCurPet()
|
currentPet := source.PrimaryCurPet()
|
||||||
if currentPet == nil {
|
if currentPet == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
f.sendFightPacket(ff.Player, fightPacketUseItem, &info.UsePetIteminfo{
|
f.sendFightPacket(p, fightPacketUseItem, &info.UsePetIteminfo{
|
||||||
UserID: source.UserID,
|
UserID: source.UserID,
|
||||||
|
|
||||||
ItemID: uint32(item.ID),
|
ItemID: uint32(item.ID),
|
||||||
|
|||||||
@@ -47,6 +47,100 @@ func NewFightSingleControllerN(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ArrangePetsBySlotLimit 按站位上限切分宠物。
|
||||||
|
// 规则:
|
||||||
|
// 1. 前 slotLimit 只存活宠物优先占据出战位。
|
||||||
|
// 2. 其余宠物按 1..slotLimit 轮转挂到对应站位作为后备。
|
||||||
|
// 3. 每个站位最多保留 6 只宠物。
|
||||||
|
func ArrangePetsBySlotLimit(pets []model.PetInfo, slotLimit int) [][]model.PetInfo {
|
||||||
|
var (
|
||||||
|
alivePets []model.PetInfo
|
||||||
|
slots [][]model.PetInfo
|
||||||
|
idx int
|
||||||
|
)
|
||||||
|
for _, pet := range pets {
|
||||||
|
if pet.Hp == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
alivePets = append(alivePets, pet)
|
||||||
|
}
|
||||||
|
if len(alivePets) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if slotLimit <= 0 {
|
||||||
|
slotLimit = 1
|
||||||
|
}
|
||||||
|
if slotLimit > len(alivePets) {
|
||||||
|
slotLimit = len(alivePets)
|
||||||
|
}
|
||||||
|
slots = make([][]model.PetInfo, 0, slotLimit)
|
||||||
|
for i := 0; i < slotLimit; i++ {
|
||||||
|
slots = append(slots, []model.PetInfo{alivePets[i]})
|
||||||
|
}
|
||||||
|
for _, pet := range alivePets[slotLimit:] {
|
||||||
|
for step := 0; step < len(slots); step++ {
|
||||||
|
slotIdx := (idx + step) % len(slots)
|
||||||
|
if len(slots[slotIdx]) >= 6 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
slots[slotIdx] = append(slots[slotIdx], pet)
|
||||||
|
idx = (slotIdx + 1) % len(slots)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return slots
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExpandPlayersWithSlotLimit 将“每位玩家的宠物列表”按站位限制展开为扁平站位列表。
|
||||||
|
// 例如:
|
||||||
|
// 1. slotLimit=1: 每位玩家占 1 个站位,其余为该站位后备。
|
||||||
|
// 2. slotLimit=3: 每位玩家最多展开 3 个站位,每个站位带各自后备。
|
||||||
|
func ExpandPlayersWithSlotLimit(
|
||||||
|
players []common.PlayerI,
|
||||||
|
petsByPlayer [][]model.PetInfo,
|
||||||
|
slotLimit int,
|
||||||
|
) ([]common.PlayerI, [][]model.PetInfo, errorcode.ErrorCode) {
|
||||||
|
var (
|
||||||
|
flatPlayers []common.PlayerI
|
||||||
|
flatSlots [][]model.PetInfo
|
||||||
|
)
|
||||||
|
if len(players) == 0 || len(players) != len(petsByPlayer) {
|
||||||
|
return nil, nil, errorcode.ErrorCodes.ErrSystemBusyTryLater
|
||||||
|
}
|
||||||
|
for idx, p := range players {
|
||||||
|
if p == nil {
|
||||||
|
return nil, nil, errorcode.ErrorCodes.ErrSystemBusyTryLater
|
||||||
|
}
|
||||||
|
slots := ArrangePetsBySlotLimit(petsByPlayer[idx], slotLimit)
|
||||||
|
for _, slotPets := range slots {
|
||||||
|
flatPlayers = append(flatPlayers, p)
|
||||||
|
flatSlots = append(flatSlots, slotPets)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(flatPlayers) == 0 || len(flatPlayers) != len(flatSlots) {
|
||||||
|
return nil, nil, errorcode.ErrorCodes.ErrSystemBusyTryLater
|
||||||
|
}
|
||||||
|
return flatPlayers, flatSlots, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFightSingleController 使用站位限制规则创建单人控制多站位战斗。
|
||||||
|
func NewFightSingleController(
|
||||||
|
ourController common.PlayerI,
|
||||||
|
oppController common.PlayerI,
|
||||||
|
ourPets []model.PetInfo,
|
||||||
|
oppPets []model.PetInfo,
|
||||||
|
slotLimit int,
|
||||||
|
fn func(model.FightOverInfo),
|
||||||
|
) (*FightC, errorcode.ErrorCode) {
|
||||||
|
return NewFightSingleControllerN(
|
||||||
|
ourController,
|
||||||
|
oppController,
|
||||||
|
ArrangePetsBySlotLimit(ourPets, slotLimit),
|
||||||
|
ArrangePetsBySlotLimit(oppPets, slotLimit),
|
||||||
|
fn,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// NewLegacyGroupFightSingleControllerN 创建旧组队协议的单人控制多站位战斗。
|
// NewLegacyGroupFightSingleControllerN 创建旧组队协议的单人控制多站位战斗。
|
||||||
func NewLegacyGroupFightSingleControllerN(
|
func NewLegacyGroupFightSingleControllerN(
|
||||||
ourController common.PlayerI,
|
ourController common.PlayerI,
|
||||||
@@ -82,6 +176,24 @@ func NewLegacyGroupFightSingleControllerN(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewLegacyGroupFightSingleController 使用站位限制规则创建旧组队协议战斗。
|
||||||
|
func NewLegacyGroupFightSingleController(
|
||||||
|
ourController common.PlayerI,
|
||||||
|
oppController common.PlayerI,
|
||||||
|
ourPets []model.PetInfo,
|
||||||
|
oppPets []model.PetInfo,
|
||||||
|
slotLimit int,
|
||||||
|
fn func(model.FightOverInfo),
|
||||||
|
) (*FightC, errorcode.ErrorCode) {
|
||||||
|
return NewLegacyGroupFightSingleControllerN(
|
||||||
|
ourController,
|
||||||
|
oppController,
|
||||||
|
ArrangePetsBySlotLimit(ourPets, slotLimit),
|
||||||
|
ArrangePetsBySlotLimit(oppPets, slotLimit),
|
||||||
|
fn,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// NewFightPerSlotControllerN 创建 N 打战斗(多人各控制一个站位)。
|
// NewFightPerSlotControllerN 创建 N 打战斗(多人各控制一个站位)。
|
||||||
// ourPlayers/oppPlayers 与 ourPetsBySlot/oppPetsBySlot 按站位一一对应。
|
// ourPlayers/oppPlayers 与 ourPetsBySlot/oppPetsBySlot 按站位一一对应。
|
||||||
func NewFightPerSlotControllerN(
|
func NewFightPerSlotControllerN(
|
||||||
@@ -117,25 +229,32 @@ func NewFightPerSlotControllerN(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewFightPerPlayerControllers 使用“每位玩家 + 站位限制”创建多人战斗。
|
||||||
|
func NewFightPerPlayerControllers(
|
||||||
|
ourPlayers []common.PlayerI,
|
||||||
|
oppPlayers []common.PlayerI,
|
||||||
|
ourPetsByPlayer [][]model.PetInfo,
|
||||||
|
oppPetsByPlayer [][]model.PetInfo,
|
||||||
|
slotLimit int,
|
||||||
|
fn func(model.FightOverInfo),
|
||||||
|
) (*FightC, errorcode.ErrorCode) {
|
||||||
|
flatOurPlayers, flatOurSlots, err := ExpandPlayersWithSlotLimit(ourPlayers, ourPetsByPlayer, slotLimit)
|
||||||
|
if err > 0 {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
flatOppPlayers, flatOppSlots, err := ExpandPlayersWithSlotLimit(oppPlayers, oppPetsByPlayer, slotLimit)
|
||||||
|
if err > 0 {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return NewFightPerSlotControllerN(flatOurPlayers, flatOppPlayers, flatOurSlots, flatOppSlots, fn)
|
||||||
|
}
|
||||||
|
|
||||||
// 创建新战斗,邀请方和被邀请方,或者玩家和野怪方
|
// 创建新战斗,邀请方和被邀请方,或者玩家和野怪方
|
||||||
func NewFight(p1, p2 common.PlayerI, b1, b2 []model.PetInfo, fn func(model.FightOverInfo)) (*FightC, errorcode.ErrorCode) {
|
func NewFight(p1, p2 common.PlayerI, b1, b2 []model.PetInfo, fn func(model.FightOverInfo)) (*FightC, errorcode.ErrorCode) {
|
||||||
if p1 == nil || p2 == nil {
|
if p1 == nil || p2 == nil {
|
||||||
return nil, errorcode.ErrorCodes.ErrSystemBusyTryLater
|
return nil, errorcode.ErrorCodes.ErrSystemBusyTryLater
|
||||||
}
|
}
|
||||||
fightInfo := p1.Getfightinfo()
|
return NewFightSingleController(p1, p2, b1, b2, 1, fn)
|
||||||
ourInput, err := buildInputFromPets(p1, b1, fightInfo.Mode)
|
|
||||||
if err > 0 {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
oppInput, err := buildInputFromPets(p2, b2, fightInfo.Mode)
|
|
||||||
if err > 0 {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return NewFightWithOptions(
|
|
||||||
WithFightInputs([]*input.Input{ourInput}, []*input.Input{oppInput}),
|
|
||||||
WithFightCallback(fn),
|
|
||||||
WithFightInfo(fightInfo),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// buildFight 基于已准备好的双方 Inputs 构建战斗实例。
|
// buildFight 基于已准备好的双方 Inputs 构建战斗实例。
|
||||||
@@ -196,8 +315,12 @@ func buildFight(opts *fightBuildOptions) (*FightC, errorcode.ErrorCode) {
|
|||||||
}
|
}
|
||||||
f.FightStartOutboundInfo = f.buildFightStartInfo()
|
f.FightStartOutboundInfo = f.buildFightStartInfo()
|
||||||
|
|
||||||
f.Broadcast(func(ff *input.Input) {
|
f.BroadcastPlayers(func(p common.PlayerI) {
|
||||||
f.sendFightPacket(ff.Player, fightPacketReady, &f.ReadyInfo)
|
if f.LegacyGroupProtocol {
|
||||||
|
f.sendLegacyGroupReady(p)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
f.sendFightPacket(p, fightPacketReady, &f.ReadyInfo)
|
||||||
})
|
})
|
||||||
|
|
||||||
cool.Cron.AfterFunc(loadtime, func() {
|
cool.Cron.AfterFunc(loadtime, func() {
|
||||||
@@ -215,9 +338,13 @@ func buildFight(opts *fightBuildOptions) (*FightC, errorcode.ErrorCode) {
|
|||||||
case !our.Finished:
|
case !our.Finished:
|
||||||
f.WinnerId = opp.Player.GetInfo().UserID
|
f.WinnerId = opp.Player.GetInfo().UserID
|
||||||
}
|
}
|
||||||
f.Broadcast(func(ff *input.Input) {
|
f.BroadcastPlayers(func(p common.PlayerI) {
|
||||||
f.sendFightPacket(ff.Player, fightPacketOver, &f.FightOverInfo)
|
if f.LegacyGroupProtocol {
|
||||||
ff.Player.QuitFight()
|
f.sendLegacyGroupOver(p, &f.FightOverInfo)
|
||||||
|
} else {
|
||||||
|
f.sendFightPacket(p, fightPacketOver, &f.FightOverInfo)
|
||||||
|
}
|
||||||
|
p.QuitFight()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
60
logic/service/fight/slot_alloc_test.go
Normal file
60
logic/service/fight/slot_alloc_test.go
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
package fight
|
||||||
|
|
||||||
|
import (
|
||||||
|
"blazing/logic/service/common"
|
||||||
|
"blazing/modules/player/model"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestArrangePetsBySlotLimit(t *testing.T) {
|
||||||
|
pets := []model.PetInfo{
|
||||||
|
{ID: 1, Hp: 10},
|
||||||
|
{ID: 2, Hp: 10},
|
||||||
|
{ID: 3, Hp: 10},
|
||||||
|
{ID: 4, Hp: 10},
|
||||||
|
{ID: 5, Hp: 10},
|
||||||
|
{ID: 6, Hp: 10},
|
||||||
|
}
|
||||||
|
|
||||||
|
slots := ArrangePetsBySlotLimit(pets, 3)
|
||||||
|
if len(slots) != 3 {
|
||||||
|
t.Fatalf("expected 3 slots, got %d", len(slots))
|
||||||
|
}
|
||||||
|
if len(slots[0]) != 2 || slots[0][0].ID != 1 || slots[0][1].ID != 4 {
|
||||||
|
t.Fatalf("slot 0 mismatch: %+v", slots[0])
|
||||||
|
}
|
||||||
|
if len(slots[1]) != 2 || slots[1][0].ID != 2 || slots[1][1].ID != 5 {
|
||||||
|
t.Fatalf("slot 1 mismatch: %+v", slots[1])
|
||||||
|
}
|
||||||
|
if len(slots[2]) != 2 || slots[2][0].ID != 3 || slots[2][1].ID != 6 {
|
||||||
|
t.Fatalf("slot 2 mismatch: %+v", slots[2])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExpandPlayersWithSlotLimit(t *testing.T) {
|
||||||
|
players := []common.PlayerI{&stubPlayer{}, &stubPlayer{}}
|
||||||
|
petsByPlayer := [][]model.PetInfo{
|
||||||
|
{
|
||||||
|
{ID: 1, Hp: 10},
|
||||||
|
{ID: 2, Hp: 10},
|
||||||
|
{ID: 3, Hp: 10},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{ID: 11, Hp: 10},
|
||||||
|
{ID: 12, Hp: 10},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
flatPlayers, flatSlots, err := ExpandPlayersWithSlotLimit(players, petsByPlayer, 1)
|
||||||
|
if err != 0 {
|
||||||
|
t.Fatalf("unexpected err: %v", err)
|
||||||
|
}
|
||||||
|
if len(flatPlayers) != 2 || len(flatSlots) != 2 {
|
||||||
|
t.Fatalf("unexpected flatten result: players=%d slots=%d", len(flatPlayers), len(flatSlots))
|
||||||
|
}
|
||||||
|
if len(flatSlots[0]) != 3 || flatSlots[0][0].ID != 1 || flatSlots[0][1].ID != 2 || flatSlots[0][2].ID != 3 {
|
||||||
|
t.Fatalf("player0 slot mismatch: %+v", flatSlots[0])
|
||||||
|
}
|
||||||
|
if len(flatSlots[1]) != 2 || flatSlots[1][0].ID != 11 || flatSlots[1][1].ID != 12 {
|
||||||
|
t.Fatalf("player1 slot mismatch: %+v", flatSlots[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user