392 lines
9.6 KiB
Go
392 lines
9.6 KiB
Go
package fight
|
||
|
||
import (
|
||
"blazing/common/data/xmlres"
|
||
"blazing/cool"
|
||
"context"
|
||
|
||
"blazing/logic/service/common"
|
||
"blazing/logic/service/fight/action"
|
||
"blazing/logic/service/fight/info"
|
||
"blazing/logic/service/fight/input"
|
||
"blazing/logic/service/player"
|
||
|
||
"fmt"
|
||
"time"
|
||
|
||
"github.com/alpacahq/alpacadecimal"
|
||
"github.com/gogf/gf/v2/util/gconv"
|
||
)
|
||
|
||
func (f *FightC) battleLoop() {
|
||
|
||
f.actionChan = make(chan action.BattleActionI, 2)
|
||
//fmt.Println("战斗开始精灵", f.Our.Player.GetInfo().PetList[0].CatchTime)
|
||
|
||
ourID := f.Our.Player.GetInfo().UserID
|
||
oppID := f.Opp.Player.GetInfo().UserID
|
||
|
||
for !f.closefight {
|
||
|
||
f.Round++
|
||
//fmt.Printf("—— 第 %d 回合开始 ——\n", f.Round)
|
||
|
||
actions := f.collectPlayerActions(ourID, oppID)
|
||
if f.closefight {
|
||
|
||
break
|
||
}
|
||
f.resolveRound(actions[ourID], actions[oppID])
|
||
|
||
}
|
||
|
||
f.Broadcast(func(ff *input.Input) {
|
||
|
||
//todo 将血量和技能pp传回enterturn
|
||
ff.Exec(func(tt input.Effect) bool {
|
||
tt.OnBattleEnd()
|
||
tt.Alive(false) //将所有属性变化失效掉
|
||
return true
|
||
})
|
||
if f.Info.Mode != info.BattleMode.PET_MELEE { //不是乱斗,传回血量
|
||
for i := 0; i < len(ff.AllPet); i++ {
|
||
for j := 0; j < len(ff.Player.GetInfo().PetList); j++ {
|
||
if ff.Player.GetInfo().PetList[j].CatchTime == ff.AllPet[i].Info.CatchTime {
|
||
|
||
if ff.UserID == f.WinnerId {
|
||
if ff.CurrentPet.Info.CatchTime == ff.Player.GetInfo().PetList[j].CatchTime {
|
||
f.Winpet = &ff.Player.GetInfo().PetList[j]
|
||
}
|
||
|
||
}
|
||
|
||
ff.Player.GetInfo().PetList[j].Hp = ff.AllPet[i].Info.Hp
|
||
ff.Player.GetInfo().PetList[j].SkillList = ff.AllPet[i].Info.SkillList
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
})
|
||
|
||
if f.Reason == info.BattleOverReason.Cacthok {
|
||
f.WinnerId = f.ownerID
|
||
f.Our.Player.(*player.Player).Service.Pet.PetAdd(&f.Opp.Player.GetInfo().PetList[0])
|
||
|
||
f.Our.Player.SendPackCmd(2409, &info.CatchMonsterOutboundInfo{
|
||
CatchTime: uint32(f.Opp.Player.GetInfo().PetList[0].CatchTime),
|
||
PetId: uint32(f.Opp.CurrentPet.ID),
|
||
})
|
||
//f.Reason = 0 //清空
|
||
}
|
||
|
||
//f.Reason = info.BattleOverReason.PlayerCaptureSuccess
|
||
//f.WinnerId = 0 //捕捉成功不算胜利
|
||
if f.callback != nil {
|
||
|
||
f.callback(&f.FightOverInfo) //先执行回调,再执行返回信息,在回调内修改战斗判断
|
||
|
||
}
|
||
//大乱斗,给个延迟
|
||
//<-time.After(1000)
|
||
f.Broadcast(func(ff *input.Input) {
|
||
|
||
ff.Player.SendPackCmd(2506, &f.FightOverInfo)
|
||
|
||
ff.Player.QuitFight()
|
||
|
||
//待退出玩家战斗状态
|
||
})
|
||
|
||
// close(f.actionChan)
|
||
fmt.Println(f.ownerID, "战斗循环结束")
|
||
close(f.over)
|
||
|
||
}
|
||
|
||
// 收集玩家动作(含超时判定)
|
||
func (f *FightC) collectPlayerActions(ourID, oppID uint32) map[uint32]action.BattleActionI {
|
||
actions := make(map[uint32]action.BattleActionI)
|
||
|
||
waitr := time.Duration(f.waittime)*time.Millisecond*10 + 60*time.Second
|
||
//fmt.Println("开始收集玩家动作", waitr)
|
||
timeout := time.After(waitr)
|
||
for len(actions) < 2 {
|
||
|
||
select {
|
||
case <-f.quit:
|
||
f.closefight = true
|
||
return actions
|
||
|
||
case paction, ok := <-f.actionChan:
|
||
if !ok {
|
||
f.closefight = true
|
||
return actions
|
||
}
|
||
if paction == nil {
|
||
continue
|
||
}
|
||
|
||
pid := paction.GetPlayerID()
|
||
if pid != ourID && pid != oppID {
|
||
continue
|
||
}
|
||
|
||
// // 避免重复提交
|
||
// if _, exists := actions[pid]; exists {
|
||
// fmt.Printf("玩家%d 已经提交过动作,忽略重复\n", pid)
|
||
// continue
|
||
// }
|
||
selfinput := f.GetInputByAction(paction, false)
|
||
if ret, ok := paction.(*action.ActiveSwitchAction); ok {
|
||
//正常结束可以切换,以及死切后还能再切一次
|
||
if selfinput.CanChange == 0 {
|
||
if selfinput.CurrentPet.Info.Hp > 0 { //非死亡切换
|
||
selfinput.CanChange = 1
|
||
} else {
|
||
|
||
selfinput.CanChange = 2
|
||
|
||
}
|
||
|
||
selfinput.CurrentPet, ret.Reason = selfinput.GetPet(ret.Cid)
|
||
selfinput.Player.SendPackCmd(2407, &ret.Reason)
|
||
InitAttackValue := *selfinput.AttackValue
|
||
oldpet := selfinput.CurrentPet
|
||
f.Switch[selfinput.UserID] = ret
|
||
|
||
selfinput.InitAttackValue() //切换精灵消除能力提升
|
||
//这时候精灵已经切换过了,可以直接给新精灵加效果
|
||
|
||
f.Broadcast(func(ff *input.Input) {
|
||
|
||
ff.Exec(func(t input.Effect) bool {
|
||
|
||
t.Switch(selfinput, InitAttackValue, oldpet)
|
||
|
||
return true
|
||
})
|
||
})
|
||
if selfinput.CanChange == 2 {
|
||
selfinput.CanChange = 0
|
||
continue
|
||
}
|
||
}
|
||
|
||
} else {
|
||
|
||
if selfinput.CurrentPet.Info.Hp <= 0 { //0血执行非切换动作
|
||
//todo 记录异常操作
|
||
continue
|
||
}
|
||
if selfinput.CanChange == 1 { //非被动死亡情况下,不能执行额外动作,0允许切,2是死亡,可以额外动作
|
||
continue
|
||
}
|
||
// if selfinput.CanChange == 2 {
|
||
// selfinput.CanChange--
|
||
// }
|
||
}
|
||
// AI自动技能
|
||
if pid != 0 && (f.Info.Status == info.BattleMode.FIGHT_WITH_NPC) {
|
||
f.GetInputByAction(paction, true).GetAction(f.Our)
|
||
//panic("AI自动技能")
|
||
}
|
||
|
||
actions[pid] = paction
|
||
//fmt.Println("玩家执行动作:", pid, paction.Priority())
|
||
|
||
case <-timeout:
|
||
f.handleTimeout(ourID, oppID, actions)
|
||
return actions
|
||
}
|
||
}
|
||
return actions
|
||
}
|
||
|
||
// 超时处理逻辑
|
||
func (f *FightC) handleTimeout(ourID, oppID uint32, actions map[uint32]action.BattleActionI) {
|
||
for _, pid := range []uint32{ourID, oppID} {
|
||
if _, exists := actions[pid]; exists {
|
||
continue
|
||
}
|
||
cool.Loger.Debug(context.Background(), "玩家超时", pid)
|
||
|
||
f.Reason = info.BattleOverReason.PlayerOVerTime
|
||
f.closefight = true
|
||
//对方赢
|
||
if f.Info.Status == info.BattleMode.FIGHT_WITH_NPC {
|
||
f.WinnerId = f.GetInputByPlayer(f.getPlayerByID(pid), true).Player.GetInfo().UserID
|
||
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
// 根据动作类型执行一回合结算
|
||
func (f *FightC) resolveRound(p1Action, p2Action action.BattleActionI) {
|
||
if p1Action == nil || p2Action == nil {
|
||
cool.Loger.Debug(context.Background(), "某方未选择动作,自动跳过结算")
|
||
return
|
||
}
|
||
|
||
// fmt.Println("开始结算回合")
|
||
|
||
// 动作优先级排序
|
||
b1, b2 := f.Compare(p1Action, p2Action)
|
||
|
||
switch a := b1.(type) {
|
||
|
||
case *action.ActiveSwitchAction:
|
||
|
||
if f.GetInputByAction(a, false).CurrentPet.Info.Hp <= 0 {
|
||
f.GetInputByAction(a, false).CurrentPet.Info.Hp = 1
|
||
}
|
||
if b2k, ok := b2.(*action.SelectSkillAction); ok {
|
||
if b2k.SkillEntity != nil {
|
||
if b2k.CD != nil {
|
||
f.waittime = *b2k.CD
|
||
}
|
||
}
|
||
f.enterturn(b2.(*action.SelectSkillAction), nil)
|
||
} else {
|
||
|
||
f.enterturn(nil, nil)
|
||
}
|
||
|
||
case *action.UseItemAction:
|
||
f.handleItemAction(a)
|
||
if f.GetInputByAction(a, false).CurrentPet.Info.Hp <= 0 {
|
||
f.GetInputByAction(a, false).CurrentPet.Info.Hp = 1
|
||
}
|
||
if b2k, ok := b2.(*action.SelectSkillAction); ok {
|
||
if b2k.SkillEntity != nil {
|
||
if b2k.CD != nil {
|
||
f.waittime = *b2k.CD
|
||
}
|
||
}
|
||
|
||
f.enterturn(b2.(*action.SelectSkillAction), nil)
|
||
} else {
|
||
if a1, ok := b2.(*action.UseItemAction); ok {
|
||
f.handleItemAction(a1)
|
||
|
||
}
|
||
f.enterturn(nil, nil)
|
||
}
|
||
|
||
default:
|
||
f.handleSkillActions(b1, b2)
|
||
}
|
||
}
|
||
|
||
// 使用道具的逻辑封装
|
||
func (f *FightC) handleItemAction(a *action.UseItemAction) {
|
||
|
||
item, ok := xmlres.ItemsMAP[int(a.ItemID)]
|
||
if !ok {
|
||
return
|
||
}
|
||
r := f.GetInputByAction(a, false).Player.(*player.Player).Service.Item.CheakItem(a.ItemID)
|
||
if r < 1 {
|
||
return
|
||
}
|
||
f.GetInputByAction(a, false).Player.(*player.Player).Service.Item.SubItem(a.ItemID, 1)
|
||
|
||
switch {
|
||
case gconv.Int(item.Bonus) != 0:
|
||
|
||
if f.Opp.CanCapture > 0 { //可以捕捉
|
||
f.Opp.CurrentPet.CatchRate = f.Opp.CanCapture
|
||
ok, _ := f.Our.Capture(f.Opp.CurrentPet, a.ItemID, -1)
|
||
our := f.Our.Player.(*player.Player)
|
||
if ok {
|
||
f.Reason = info.BattleOverReason.Cacthok
|
||
f.closefight = true
|
||
} else {
|
||
our.SendPack(common.NewTomeeHeader(2409, f.ownerID).Pack(&info.CatchMonsterOutboundInfo{}))
|
||
|
||
}
|
||
}
|
||
case gconv.Int(item.HP) != 0:
|
||
addhp := item.HP
|
||
f.GetInputByAction(a, false).Exec(func(rr input.Effect) bool {
|
||
rr.Heal_Pre(a, &addhp)
|
||
|
||
return true
|
||
})
|
||
|
||
f.GetInputByAction(a, false).Heal(f.GetInputByAction(a, false), a, alpacadecimal.NewFromInt(int64(addhp)))
|
||
f.Broadcast(func(ff *input.Input) {
|
||
ff.Player.SendPackCmd(2406, &info.UsePetIteminfo{
|
||
UserID: f.GetInputByAction(a, false).UserID,
|
||
ChangeHp: int32(addhp),
|
||
ItemID: uint32(item.ID),
|
||
UserHp: uint32(f.GetInputByAction(a, false).CurrentPet.Info.Hp),
|
||
})
|
||
|
||
})
|
||
case gconv.Int(item.PP) != 0:
|
||
f.GetInputByAction(a, false).HealPP(item.PP)
|
||
f.Broadcast(func(ff *input.Input) {
|
||
ff.Player.SendPackCmd(2406, &info.UsePetIteminfo{
|
||
UserID: f.GetInputByAction(a, false).UserID,
|
||
|
||
ItemID: uint32(item.ID),
|
||
UserHp: uint32(f.GetInputByAction(a, false).CurrentPet.Info.Hp),
|
||
})
|
||
|
||
})
|
||
|
||
default:
|
||
|
||
fmt.Println(a.ItemID, "ItemID 不在指定范围内")
|
||
}
|
||
|
||
}
|
||
|
||
// 双方都是技能时的结算逻辑
|
||
func (f *FightC) handleSkillActions(a1, a2 action.BattleActionI) {
|
||
s1, _ := a1.(*action.SelectSkillAction)
|
||
s2, _ := a2.(*action.SelectSkillAction)
|
||
|
||
switch {
|
||
case s1 == nil || s1.SkillEntity == nil:
|
||
if s2.SkillEntity != nil {
|
||
if s2.CD != nil {
|
||
f.waittime = *s2.CD
|
||
}
|
||
}
|
||
|
||
f.enterturn(s2, nil)
|
||
// fmt.Println("1 空过 2玩家执行技能:", s2.PlayerID, s2.Info.ID)
|
||
case s2 == nil || s2.SkillEntity == nil:
|
||
if s1.SkillEntity != nil {
|
||
if s1.CD != nil {
|
||
f.waittime = *s1.CD
|
||
}
|
||
}
|
||
f.enterturn(s1, nil)
|
||
//fmt.Println("2 空过 玩家执行技能:", s1.PlayerID, s1.Info.ID)
|
||
default:
|
||
if s1.CD != nil {
|
||
f.waittime = *s1.CD
|
||
}
|
||
if s2.CD != nil {
|
||
f.waittime += *s2.CD
|
||
}
|
||
|
||
f.enterturn(s1, s2)
|
||
fmt.Println("玩家执行技能:", s1.PlayerID, s1.Info.ID, s2.PlayerID, s2.Info.ID)
|
||
}
|
||
}
|
||
|
||
// 根据玩家ID返回对应对象
|
||
func (f *FightC) getPlayerByID(id uint32) common.PlayerI {
|
||
if id == f.Our.Player.GetInfo().UserID {
|
||
return f.Our.Player
|
||
}
|
||
return f.Opp.Player
|
||
}
|