diff --git a/logic/controller/fight.go b/logic/controller/fight.go index 03d62cafc..20a8897bb 100644 --- a/logic/controller/fight.go +++ b/logic/controller/fight.go @@ -51,8 +51,9 @@ func (h Controller) OnPlayerFightNpcMonster(data *fight.FightNpcMonsterInboundIn if c.FightC != nil { return nil, errorcode.ErrorCodes.ErrOnlineOver6HoursCannotFight } - c.FightC = &service.FightC{} - c.FightC.NewFight(&ttt, c, mo) //把两个玩家都传进去 + ai := service.NewAI_player(*mo) + service.NewFight(ttt, c, ai) + c.FightC.OwnerID = c.Info.UserID return nil, -1 diff --git a/logic/service/ai.go b/logic/service/ai.go index d09136920..8b5c8c218 100644 --- a/logic/service/ai.go +++ b/logic/service/ai.go @@ -7,15 +7,24 @@ import ( ) type AI_player struct { - fightinfo info.NoteReadyToFightInfo - id uint32 //0 - FightC *FightC //绑定战斗标识 替代本身的是否战斗标记 //IsFighting bool - //petinfo []model.PlayerInfo //精灵信息 + FightC *FightC //绑定战斗标识 替代本身的是否战斗标记 //IsFighting bool + petinfo []model.PetInfo //精灵信息 } +func NewAI_player(m model.PetInfo) *AI_player { + ret := &AI_player{} + ret.petinfo = make([]model.PetInfo, 0) + ret.petinfo = append(ret.petinfo, m) + return ret + +} +func (f *AI_player) SetFightC(ff *FightC) { + f.FightC = ff +} + func (f *AI_player) ID() uint32 { - return f.id + return 0 } func (f *AI_player) MapID() uint32 { @@ -38,16 +47,16 @@ func (f *AI_player) SendReadyToFightInfo(gg info.FightStartOutboundInfo) { //这时候给个出招 } -func (f *AI_player) SendNoteReadyToFightInfo(_ info.NoteReadyToFightInfo) { - panic("not implemented") // TODO: Implement +func (f *AI_player) SendNoteReadyToFightInfo(fs info.NoteReadyToFightInfo) { + fmt.Println(fs) } func (f *AI_player) SendFightEndInfo(_ info.FightOverInfo) { - fmt.Println("战斗结束") + //fmt.Println("战斗结束") } func (f *AI_player) GetAction() { - f.FightC.UseSkill(f, int32(f.fightinfo.OpponentPetList[0].SkillList[0].ID)) //使用1#技能,实际上要按照四个技能权重去使用 + f.FightC.UseSkill(f, int32(f.FightC.Opp.CurrentPet.Skills[0].ID)) //使用1#技能,实际上要按照四个技能权重去使用 } func (p *AI_player) End() { p.FightC = nil @@ -55,9 +64,9 @@ func (p *AI_player) End() { return } -func (p *AI_player) GetPetInfo() []*model.PetInfo { +func (p *AI_player) GetPetInfo() []model.PetInfo { - return nil + return p.petinfo } func (p *AI_player) SendAttackValue(info.AttackValueS) { diff --git a/logic/service/fight/info/BattleAction.go b/logic/service/fight/info/BattleAction.go index 0075af7b0..a0abeddb9 100644 --- a/logic/service/fight/info/BattleAction.go +++ b/logic/service/fight/info/BattleAction.go @@ -11,13 +11,13 @@ type EnumPlayerOperation int // 定义读秒倒计时期间玩家可执行的操作枚举 var PlayerOperations = enum.New[struct { - SystemGiveUp EnumPlayerOperation `enum:"-1"` // 系统选择放弃出手(比如没有PP) - SelectSkill EnumPlayerOperation `enum:"0"` // 选择技能-6到6 - ActiveSwitch EnumPlayerOperation `enum:"2"` // 主动切换(中切) - UsePotion EnumPlayerOperation `enum:"3"` // 使用药剂(捕捉、逃跑等) - Escape EnumPlayerOperation `enum:"4"` // 逃跑(等级最高,以及掉线) - PlayerOffline EnumPlayerOperation `enum:"5"` // 玩家掉线 - BeExpelledSwitch EnumPlayerOperation `enum:"6"` // 被驱逐切换 + SystemGiveUp EnumPlayerOperation `enum:"-1"` // 系统选择放弃出手(比如没有PP) + SelectSkill EnumPlayerOperation `enum:"0"` // 选择技能-6到6 + ActiveSwitch EnumPlayerOperation `enum:"2"` // 主动切换(中切) + UsePotion EnumPlayerOperation `enum:"3"` // 使用药剂(捕捉、逃跑等) + Escape EnumPlayerOperation `enum:"4"` // 逃跑(等级最高,以及掉线) + PlayerOffline EnumPlayerOperation `enum:"5"` // 玩家掉线 + // BeExpelledSwitch EnumPlayerOperation `enum:"6"` // 被驱逐切换 }]() // Compare 比较两个1v1战斗动作的执行优先级(核心逻辑) @@ -84,8 +84,8 @@ func (s *SelectSkillAction) Priority() int { // ActiveSwitchAction 主动切换宠物的战斗动作 type ActiveSwitchAction struct { PlayerID uint32 // 玩家ID - Type bool //是否主动切换 - Reason ChangePetInfo + + Reason ChangePetInfo // CurrentPet BattlePetEntity // 当前在场宠物 // TargetPet BattlePetEntity // 要切换上场的宠物 // SwitchReason string // 切换原因 @@ -93,16 +93,7 @@ type ActiveSwitchAction struct { // Priority 返回动作优先级 func (a *ActiveSwitchAction) Priority() int { - if a.Type { - return int(PlayerOperations.ActiveSwitch) - } - return int(PlayerOperations.BeExpelledSwitch) -} - -// Broadcast 广播切换宠物的动作信息 -func (a *ActiveSwitchAction) Broadcast() { - // fmt.Printf("玩家[%d]主动切换宠物:从%s切换到%s(原因:%s)\n", - // // a.PlayerID, a.CurrentPet.Name, a.TargetPet.Name, a.SwitchReason) + return int(PlayerOperations.ActiveSwitch) } func (a *ActiveSwitchAction) GetPlayerID() uint32 { @@ -171,10 +162,9 @@ func (s *SystemGiveUpAction) Broadcast() { // PlayerOfflineAction 玩家掉线的战斗动作 type PlayerOfflineAction struct { - PlayerID uint32 // 掉线玩家ID - OfflineTime time.Time // 掉线时间 - CurrentPet BattlePetEntity // 掉线时在场的宠物 - IsReconnect bool // 是否后续重连(预留字段) + PlayerID uint32 // 掉线玩家ID + OfflineTime time.Time // 掉线时间 + Reason FightOverInfo } // Priority 返回动作优先级 @@ -182,6 +172,10 @@ func (p *PlayerOfflineAction) Priority() int { return int(PlayerOperations.PlayerOffline) } +func (p *PlayerOfflineAction) GetPlayerID() uint32 { + return p.PlayerID +} + // Broadcast 广播玩家掉线信息 func (p *PlayerOfflineAction) Broadcast() { // /status := "未重连" diff --git a/logic/service/fight/info/BattlePetEntity.go b/logic/service/fight/info/BattlePetEntity.go index df0df5771..c6ff776b2 100644 --- a/logic/service/fight/info/BattlePetEntity.go +++ b/logic/service/fight/info/BattlePetEntity.go @@ -73,11 +73,11 @@ type BattlePetEntity struct { } // 创建精灵实例 -func CreateBattlePetEntity(info *model.PetInfo, rand *rand.Rand) *BattlePetEntity { +func CreateBattlePetEntity(info model.PetInfo, rand *rand.Rand) *BattlePetEntity { ret := &BattlePetEntity{} ret.PetInfo = xmlres.PetMAP[int(info.ID)] //注入精灵信息 - ret.Info = *info + ret.Info = info for i := 0; i < 4; i++ { //todo 技能信息应该每回合进行深拷贝,保证每次的技能效果都是不一样的 ret.Skills[i] = CreateBattleSkillWithInfinity(&info.SkillList[i], rand, ret) diff --git a/logic/service/fight/info/BattleSkillEntity.go b/logic/service/fight/info/BattleSkillEntity.go index c57c2f109..e3ad66fd8 100644 --- a/logic/service/fight/info/BattleSkillEntity.go +++ b/logic/service/fight/info/BattleSkillEntity.go @@ -37,16 +37,11 @@ var Category = enum.New[struct { // 战斗中可以修改技能实体值,比如是否暴击,是否必中等 type BattleSkillEntity struct { xmlres.Move - // SideEffects []int - // SideEffectArgs []int PP int DamageZone map[EnumCategory]map[EnumsZoneType]map[EnumsZoneType][]float64 // 三维map 伤害类型-》增还是减-》加还是乘-》值 DamageValue decimal.Decimal // 伤害值 Rand *rand.Rand Pet *BattlePetEntity - // 技能类型属性 - //SkillType EnumCategory // 技能类型(物理/特殊/状态) - } // CreateBattleSkillWithInfinity 创建战斗技能实例(可指定是否无限PP) @@ -241,14 +236,14 @@ func (s *BattleSkillEntity) PutDamageZone(e EnumCategory, dtype EnumsZoneType, v // } // 暴击伤害 返回暴击率和是否暴击 -func (s *BattleSkillEntity) CriticalRate() (decimal.Decimal, uint32) { +func (s *BattleSkillEntity) IsCritical() (decimal.Decimal, bool) { - return decimal.NewFromFloat(1), 1 + return decimal.NewFromFloat(1), true } // 计算是否命中 -func (s *BattleSkillEntity) CriticalisCritical() uint32 { +func (s *BattleSkillEntity) AttackTime() uint32 { if int64(s.Pet.Accuracy(int64(s.Accuracy))) > s.Rand.Int63n(100) { return 1 @@ -343,8 +338,8 @@ func (s *BattleSkillEntity) CalculatePower(deftype int) uint32 { Mul(typeRate). // 克制系数 Mul(s.criticalrandom()) //随机波动 - v, ok := s.CriticalRate() - if ok == 1 { + v, ok := s.IsCritical() //获取暴击 + if ok { damage.Mul(v) } return uint32(damage.IntPart()) diff --git a/logic/service/fight/info/info.go b/logic/service/fight/info/info.go index 4825b75b7..2e1ddf019 100644 --- a/logic/service/fight/info/info.go +++ b/logic/service/fight/info/info.go @@ -52,6 +52,24 @@ type AttackValueS struct { SAttack AttackValue } +func NewAttackValue(userid uint32) *AttackValue { + return &AttackValue{ + userid, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + []model.SkillInfo{}, + 0, + StatusDict{}, + PropDict{}, + } +} + // AttackValue 战斗中的攻击数值信息 type AttackValue struct { UserID uint32 `json:"userId" fieldDescription:"玩家的米米号 与野怪对战userid = 0"` @@ -142,6 +160,7 @@ type FightUserInfo struct { // NoteReadyToFightInfo 战斗准备就绪消息结构体,NoteReadyToFightInfo type NoteReadyToFightInfo struct { + MAXPET uint32 `struc:"skip"` // 最大精灵数 struc:"skip"` // 战斗类型ID(与野怪战斗为3,与人战斗为1,前端似乎未使用) // @UInt long FightId EnumBattleMode `fieldDesc:"战斗类型ID 但前端好像没有用到 与野怪战斗为3,与人战斗似乎是1" ` diff --git a/logic/service/fightc.go b/logic/service/fightc.go index 9271725df..5bb47d0e1 100644 --- a/logic/service/fightc.go +++ b/logic/service/fightc.go @@ -19,32 +19,64 @@ type PlayerI interface { ID() uint32 MapID() uint32 GetAction() - GetPetInfo() []*model.PetInfo - End() //结束战斗 + GetPetInfo() []model.PetInfo SendPack(b []byte) error SendReadyToFightInfo(info.FightStartOutboundInfo) SendNoteReadyToFightInfo(info.NoteReadyToFightInfo) SendFightEndInfo(info.FightOverInfo) SendAttackValue(info.AttackValueS) SendChangePet(info.ChangePetInfo) + SetFightC(*FightC) +} +type Input struct { + CanChange bool //是否可以死亡切换CanChange + CurrentPet *info.BattlePetEntity //当前精灵 + AllPet []*info.BattlePetEntity + Player PlayerI + Finished bool //是否加载完成 +} + +func (i *Input) GetPetInfo() *info.BattlePetEntity { + + return i.CurrentPet + } type FightC struct { - Info *info.NoteReadyToFightInfo - Our PlayerI - OurCurrentPet *info.BattlePetEntity //我方精灵 - Opp PlayerI - OppCurrentPet *info.BattlePetEntity //对方当前精灵 + Info info.NoteReadyToFightInfo - MAXPET uint32 // 最大精灵数 OwnerID uint32 // 战斗发起者ID - AFinished bool - BFinished bool - random *rand.Rand //随机数种子 + Our *Input //始终等于房主ID + Opp *Input //对手ID + rand *rand.Rand StartTime time.Time actionChan chan info.BattleActionI // 所有操作统一从这里进入 Round int //回合数 EffectS info.NodeManager //effects容器 + First *BPET + Second *BPET +} + +func (f *FightC) GetInputByPlayer(c PlayerI, isOpposite bool) *Input { + // 判断当前玩家是否为我方玩家 + isOurPlayer := c == f.Our.Player + + // 逻辑简化:当"是否为我方玩家"与"是否需要对方"状态一致时,返回对方输入,否则返回我方输入 + if isOurPlayer == isOpposite { + return f.Opp + } + return f.Our +} + +func (f *FightC) GetInputByAction(c info.BattleActionI, isOpposite bool) *Input { + // 判断动作所属玩家是否为我方 + isOurAction := c.GetPlayerID() == f.Our.Player.ID() + + // 根据isOpposite决定是否返回相反方向的输入 + if isOurAction == !isOpposite { + return f.Our + } + return f.Opp } // 玩家逃跑 @@ -66,26 +98,20 @@ func (f *FightC) ChangePet(c PlayerI, id int32) { PlayerID: c.ID(), } - rett := func(t PlayerI) *info.BattlePetEntity { - for _, v := range t.GetPetInfo() { - if v.CatchTime == uint32(id) { - fs := info.CreateBattlePetEntity(v, f.Random()) //存入自己的精灵信息 + rett := func(t *Input) *info.BattlePetEntity { + for _, v := range t.AllPet { + if v.Info.CatchTime == uint32(id) { copier.Copy(&ret.Reason, &v) ret.Reason.UserId = c.ID() - return fs + return v } } return nil } - if c == f.Our { - f.OurCurrentPet = rett(f.Our) + f.GetInputByPlayer(c, false).CurrentPet = rett(f.GetInputByPlayer(c, false)) - } else { - - f.OppCurrentPet = rett(f.Opp) - } f.actionChan <- ret } @@ -94,14 +120,7 @@ func (f *FightC) UseSkill(c PlayerI, id int32) { ret := &info.SelectSkillAction{ PlayerID: c.ID(), } - - if c == f.Our { - ret.PetInfo = f.OurCurrentPet //存入自己的精灵信息 - - } else { - - ret.PetInfo = f.OppCurrentPet - } + ret.PetInfo = f.GetInputByPlayer(c, false).CurrentPet for _, v := range ret.PetInfo.Skills { @@ -124,27 +143,18 @@ func (f *FightC) ReadyFight(c PlayerI) { rrsult := func() { //传回函数 - f.Our.SendReadyToFightInfo(rett) - f.Opp.SendReadyToFightInfo(rett) + f.Our.Player.SendReadyToFightInfo(rett) + f.Opp.Player.SendReadyToFightInfo(rett) } switch f.Info.FightId { case 1: // 1v1 - if c == f.Our { - f.AFinished = true - if f.BFinished { - - rrsult() - } - } else { - f.Opp = c - f.OppCurrentPet = info.CreateBattlePetEntity(c.GetPetInfo()[0], f.Random()) - f.BFinished = true - if f.AFinished { - rrsult() - } + f.GetInputByPlayer(c, false).Finished = true + if f.GetInputByPlayer(c, true).Finished { + rrsult() } + case 3: // 野怪战斗 //判断捕捉率大于0 @@ -155,16 +165,6 @@ func (f *FightC) ReadyFight(c PlayerI) { rrsult() } } -func (f *FightC) Random() *rand.Rand { - //先产生战斗的随机数 - // 组合「时间戳(纳秒精度)+ 双方ID + 回合数」生成种子 - - seed := f.StartTime.UnixNano() ^ int64(f.OwnerID) ^ int64(f.Our.ID()) ^ int64(f.Round) // 用异或运算混合多维度信息 - ret := rand.New(rand.NewSource(seed)) - - return ret - -} var Fightpool *ants.Pool @@ -173,104 +173,67 @@ func init() { //defer p.Release() } -// 创建新战斗 -func (f *FightC) NewFight(i *info.NoteReadyToFightInfo, plays PlayerI, mo *model.PetInfo) { +// 创建新战斗,邀请方和被邀请方,或者玩家和野怪方 +func NewFight(i info.NoteReadyToFightInfo, p1 PlayerI, p2 PlayerI) *FightC { + f := &FightC{} + f.OwnerID = p1.ID() + f.Info = i //房主 + seed := f.StartTime.UnixNano() ^ int64(p1.ID()) ^ int64(p2.ID()) // ^ int64(f.Round) // 用异或运算混合多维度信息 + f.rand = rand.New(rand.NewSource(seed)) - f.Our = plays - f.Info = i - f.StartTime = time.Now() - f.actionChan = make(chan info.BattleActionI, 2) // 初始化全局操作通道 - fmt.Println("战斗开始精灵", plays.GetPetInfo()[0].CatchTime) + f.Our = &Input{ + CurrentPet: info.CreateBattlePetEntity(p1.GetPetInfo()[0], f.rand), + Player: p1, + } + for k, v := range p1.GetPetInfo() { + if k < int(i.MAXPET) { + f.Our.AllPet = append(f.Our.AllPet, info.CreateBattlePetEntity(v, f.rand)) + } - for _, v := range plays.GetPetInfo() { - if v.Hp > 0 { - f.OurCurrentPet = info.CreateBattlePetEntity(plays.GetPetInfo()[0], f.Random()) + } + + f.Opp = &Input{ + CurrentPet: info.CreateBattlePetEntity(p2.GetPetInfo()[0], f.rand), + Player: p2, + } + for k, v := range p2.GetPetInfo() { + if k < int(i.MAXPET) { + f.Opp.AllPet = append(f.Opp.AllPet, info.CreateBattlePetEntity(v, f.rand)) } } - // } - // f.OurCurrentPet = info.CreateBattlePetEntity(plays.GetPetInfo()[0], f.Random()) - if mo != nil { - f.OppCurrentPet = info.CreateBattlePetEntity(mo, f.Random()) - } - switch i.FightId { - case 1: - // 1v1,等双方进入 - case 3: // 野怪战斗 + p1.SetFightC(f) //给我方追加战斗容器 + p2.SetFightC(f) //给对方增加战斗容器 + defer func() { + rr := Fightpool.Submit(f.battleLoop) + if rr != nil { + panic(rr) + } + f.Broadcast(func(ff *Input) { - f.Opp = &AI_player{fightinfo: *i, FightC: f} // 创建虚拟对手 - plays.SendNoteReadyToFightInfo(*i) - } - - rr := Fightpool.Submit(f.battleLoop) - if rr != nil { - panic(rr) - } + ff.Player.SendNoteReadyToFightInfo(i) + }) + }() //go f.battleLoop() // 起战斗循环 + return f } // 广播,并是否结束回合 -func (f *FightC) Broadcast(t info.BattleActionI) bool { - switch ff := t.(type) { +func (f *FightC) Broadcast(t func(ff *Input)) { - case *info.EscapeAction: + t(f.Our) - f.Our.SendFightEndInfo(ff.Reason) - f.Opp.SendFightEndInfo(ff.Reason) - return true + t(f.Opp) - case *info.ActiveSwitchAction: //切换精灵 - - f.Our.SendChangePet(ff.Reason) - f.Opp.SendChangePet(ff.Reason) - - default: - } - - return false -} -func (f *FightC) BroadcastSkill(t info.AttackValueS) { - f.Our.SendAttackValue(t) - f.Opp.SendAttackValue(t) -} - -// 检查战斗是否结束 -func (f *FightC) CheakEnd(b uint32) bool { - fmt.Println(f.Round, "检查战斗是否结束") - var tt []info.ReadyFightPetInfo - for _, v := range f.Info.OurPetList { - if v.CatchTime == b { - v.NotAlive = true - - } - tt = append(tt, v) - } - f.Info.OurPetList = tt - var tt1 []info.ReadyFightPetInfo - for _, v := range f.Info.OpponentPetList { - if v.CatchTime == b { - v.NotAlive = true - - } - tt1 = append(tt1, v) - } - f.Info.OpponentPetList = tt1 - for _, v := range f.Info.OurPetList { - if !v.NotAlive { - return false - } - - } - for _, v := range f.Info.OpponentPetList { - if !v.NotAlive { - return false - } - } - return true } // 战斗回合循环 func (f *FightC) battleLoop() { + f.StartTime = time.Now() + f.actionChan = make(chan info.BattleActionI, 2) // 初始化全局操作通道 + fmt.Println("战斗开始精灵", f.Our.Player.GetPetInfo()[0].CatchTime) + //战斗开始前操作 + for { f.Round++ //回合数自增 @@ -284,23 +247,37 @@ func (f *FightC) battleLoop() { for len(actions) < 2 { select { case action := <-f.actionChan: - // 只接受有效玩家 ID - if action.GetPlayerID() != f.Our.ID() && action.GetPlayerID() != f.Opp.ID() { + // 只接受有效玩家 ID\ + if action == nil { continue } + + if action.GetPlayerID() != f.Our.Player.ID() && action.GetPlayerID() != f.Opp.Player.ID() { + continue + } + if a, isExpelled := action.(*info.ActiveSwitchAction); isExpelled { //fmt.Println("对方死亡切换") - f.Broadcast(a) - if !a.Type { + f.Broadcast(func(ff *Input) { + + ff.Player.SendChangePet(a.Reason) + }) + + if f.GetInputByAction(action, false).CanChange { + //如果是被动切换,不计入回合结算 + f.GetInputByAction(action, false).CanChange = false continue + } } - if action.GetPlayerID() == f.Our.ID() && f.Info.FightId == 3 { - go f.Opp.GetAction() //获取AI的动作 + if action.GetPlayerID() != 0 && f.Info.FightId == 3 { + + f.GetInputByAction(action, true).Player.GetAction() } + // 如果该玩家已经提交过,就忽略重复动作 if _, exists := actions[uint32(action.GetPlayerID())]; exists { fmt.Printf("玩家%d 已经提交过动作,忽略重复\n", action.GetPlayerID()) @@ -312,140 +289,241 @@ func (f *FightC) battleLoop() { case <-timeout: fmt.Println("回合操作超时") - if _, exists := actions[f.Our.ID()]; !exists { - actions[f.Our.ID()] = &info.SystemGiveUpAction{PlayerID: f.Our.ID()} //系统选择出手 + + if _, exists := actions[f.Our.Player.ID()]; !exists { + actions[f.Our.Player.ID()] = &info.SystemGiveUpAction{PlayerID: f.Our.Player.ID()} //系统选择出手 } - if _, exists := actions[f.Opp.ID()]; !exists { - actions[f.Opp.ID()] = &info.SystemGiveUpAction{PlayerID: f.Opp.ID()} //系统选择出手 + if _, exists := actions[f.Opp.Player.ID()]; !exists { + actions[f.Opp.Player.ID()] = &info.SystemGiveUpAction{PlayerID: f.Opp.Player.ID()} //系统选择出手 } } } // 双方动作齐了,取出来结算 - p1Action := actions[f.Our.ID()] - p2Action := actions[f.Opp.ID()] + p1Action := actions[f.Our.Player.ID()] + p2Action := actions[f.Opp.Player.ID()] fmt.Println("开始结算回合") var BattleActionI [2]info.BattleActionI BattleActionI[0], BattleActionI[1] = info.Compare(p1Action, p2Action) - if BattleActionI[0].Priority() > 0 { //如果优先级大于0,说明是在技能之上的 - t := f.Broadcast(BattleActionI[0]) - if t { + switch faction := BattleActionI[0].(type) { + case *info.EscapeAction: //优先逃跑 - break - } - } - - if BattleActionI[0].Priority() < 0 && BattleActionI[1].Priority() < 0 { //双方都空过 + f.Broadcast(func(ff *Input) { + ff.Player.SendFightEndInfo(faction.Reason) //广播逃跑原因 + }) break - } + case *info.PlayerOfflineAction: //单方掉线 - var p_skill [2]*info.SelectSkillAction - var currpet [2]*info.BattlePetEntity - var currpetvale [2]int // 伤害值 - if BattleActionI[0].GetPlayerID() == f.OwnerID { //先反转战斗属性 + f.Broadcast(func(ff *Input) { + ff.Player.SendFightEndInfo(faction.Reason) //广播逃跑原因 + }) + break + case *info.ActiveSwitchAction: //切换上场的 + f.enterturn(BattleActionI[1], nil) //切换,相当于后手直接出手 - currpet[0] = f.OurCurrentPet - currpet[1] = f.OppCurrentPet + case *info.SelectSkillAction: //选择技能 + //回合前操作,比如挂载buff + f.enterturn(BattleActionI[0], BattleActionI[1]) - } else { - currpet[0] = f.OppCurrentPet - currpet[1] = f.OurCurrentPet - } - fmt.Println("当前", currpet[0].Info.CatchTime, "敌方", currpet[1].Info.CatchTime) - for i := 0; i < 2; i++ { - - // TODO: 在这里调用技能结算逻辑 - - p_skill[i] = BattleActionI[i].(*info.SelectSkillAction) - temparg := p_skill[i].Skill.SideEffectArgS - for _, v := range p_skill[i].Skill.SideEffectS { - - t, ok := info.NodeM[v] - - if ok { //获取成功 - - args := t.GetArgSize() - t.SetArgs(temparg[:args]) //设置入参 - - //如果不是是房主方,说明施加的对象是反的,比如本来是false,实际上是给邀请方施加的 - //所以这里要对target取反 - if BattleActionI[i].GetPlayerID() != f.OwnerID { - t.SetTarget(!t.Target()) - } - temparg = temparg[args:] - f.EffectS.AddEffect(deepcopy.Copy(t).(info.Effect)) - - } - - } - spower := p_skill[i].Skill.CalculatePower(currpet[i].Type().ID) - - //开始计算技能效果battleLoop - _, ok := p_skill[i].Skill.CriticalRate() - //CalculatePower() - //记录伤害,到后手方出手时计算伤害 - currpetvale[i] = int(spower) - - fmt.Println("技能伤害", spower, "剩余血量", currpet[i].Info.Hp) - p_skill[i].Attack = info.AttackValue{ - p_skill[i].PlayerID, - uint32(p_skill[i].Skill.ID), - p_skill[i].Skill.CriticalisCritical(), - spower, - 0, - int32(currpet[i].Info.Hp), - currpet[i].Info.MaxHp, - 0, - 0, - []model.SkillInfo{}, - ok, - info.StatusDict{}, - info.PropDict{}, - } + //回合后操作 } - p_skill[0].Attack.RemainHp = int32(int(currpet[0].Info.Hp) - currpetvale[1]) - currpet[0].Info.Hp = uint32(p_skill[0].Attack.RemainHp) - p_skill[1].Attack.RemainHp = int32(int(currpet[1].Info.Hp) - currpetvale[0]) - currpet[1].Info.Hp = uint32(p_skill[1].Attack.RemainHp) - if p_skill[1].Attack.RemainHp <= 0 { //如果后手方被打死 - p_skill[1].Attack = info.AttackValue{ - p_skill[1].PlayerID, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - []model.SkillInfo{}, - 0, - info.StatusDict{}, - info.PropDict{}, - } - fmt.Println(currpet[1].Info.CatchTime, "被打死") - if f.CheakEnd(currpet[1].Info.CatchTime) { - break - } - } - - if p_skill[0].Attack.RemainHp <= 0 { - - if f.CheakEnd(currpet[0].Info.CatchTime) { - break - } - } - fmt.Println("P1", p_skill[0].Attack.RemainHp, "P2", p_skill[1].Attack.RemainHp) - f.BroadcastSkill(info.AttackValueS{ - p_skill[0].Attack, p_skill[1].Attack, - }) } - close(f.actionChan) //关闭战斗通道 - //取消战斗信息 - f.Our.End() - f.Opp.End() + +} + +type BPET struct { + *Input + + //*info.SelectSkillAction //技能实体 + *info.BattlePetEntity //精灵实体 + *info.AttackValue + *FightC + Damage uint32 //造成伤害 +} + +// 被击败的ID +func (b *BPET) IsWin(cache uint32) bool { + + fmt.Println("当前回合", b.FightC.Round, "开始检查战斗是否结束") + + var tt []info.ReadyFightPetInfo + bbb := b.FightC.Info.OurPetList + + if b.Input.Player.ID() == b.FightC.OwnerID { //如果是房主 + bbb = b.FightC.Info.OpponentPetList + } else { + bbb = b.FightC.Info.OurPetList + } + + for _, v := range bbb { + if v.CatchTime == cache { + v.NotAlive = true + + } + tt = append(tt, v) + } + + for _, v := range tt { + if !v.NotAlive { //如果存活 + return false + } + } + return true +} + +// 解析并 施加effect +func (f *FightC) parseskill(id *info.SelectSkillAction) { + temparg := id.Skill.SideEffectArgS + for _, v := range id.Skill.SideEffectS { + + t, ok := info.NodeM[v] + + if ok { //获取成功 + + args := t.GetArgSize() + t.SetArgs(temparg[:args]) //设置入参 + //如果不是是房主方,说明施加的对象是反的,比如本来是false,实际上是给邀请方施加的 + //所以这里要对target取反 + if id.GetPlayerID() != f.OwnerID { + t.SetTarget(!t.Target()) + } + temparg = temparg[args:] + f.EffectS.AddEffect(deepcopy.Copy(t).(info.Effect)) + + } + + } +} +func (f *FightC) enterturn(fattack, sattack info.BattleActionI) { + + // 伤害值 + + // 根据攻击方归属设置当前战斗的主/次攻击方属性 + var first, second *Input // 定义临时变量存储主/次攻击方 + if fattack.GetPlayerID() == f.OwnerID { + first = f.Our // 攻击方为我方时,主攻击方是我方 + second = f.Opp // 次攻击方是对方 + } else { + first = f.Opp // 攻击方为对方时,主攻击方是对方 + second = f.Our // 次攻击方是我方 + } + + // 统一赋值,减少重复代码 + f.First = &BPET{ + FightC: f, + Input: first, + BattlePetEntity: first.CurrentPet, + AttackValue: info.NewAttackValue(first.Player.ID()), + Damage: 0} + f.Second = &BPET{ + FightC: f, + Input: second, + BattlePetEntity: second.CurrentPet, + AttackValue: info.NewAttackValue(second.Player.ID()), + Damage: 0} + + fmt.Println("先手", f.First.CurrentPet.Info.CatchTime, "后手", f.Second.CurrentPet.Info.CatchTime) + + // TODO: 在这里调用技能结算逻辑 + + skill, _ := fattack.(*info.SelectSkillAction) + + f.parseskill(skill) + spower := skill.Skill.CalculatePower(f.Second.Type().ID) + + //开始计算技能效果battleLoop + _, ok := skill.Skill.IsCritical() + + //CalculatePower() + //记录伤害,到后手方出手时计算伤害 + f.First.Damage = (spower) + + fmt.Println("先手技能伤害", spower, "先手剩余血量", f.First.CurrentPet.Info.Hp) + + f.First.AttackValue.SkillID = uint32(skill.Skill.ID) + f.First.AttackValue.AttackTime = skill.Skill.AttackTime() + if ok { //判断暴击 + f.First.AttackValue.IsCritical = 1 + } + fmt.Println(f.First.CurrentPet.Info.CatchTime, "先手出招结束") + + if f.First.Damage > f.Second.CurrentPet.Info.Hp { + f.Second.CurrentPet.Info.Hp = 0 + } else { + f.Second.CurrentPet.Info.Hp = f.Second.CurrentPet.Info.Hp - f.First.Damage //扣减后手方血量 + } + if f.Second.CurrentPet.Info.Hp > 0 { //如果后手方没被打死 + skill, ok := sattack.(*info.SelectSkillAction) + if ok { + + f.parseskill(skill) + spower := skill.Skill.CalculatePower(f.First.Type().ID) + + //开始计算技能效果battleLoop + _, ok := skill.Skill.IsCritical() + + //CalculatePower() + //记录伤害,到后手方出手时计算伤害 + f.Second.Damage = (spower) + + fmt.Println("后手技能伤害", spower, "后手剩余血量", f.Second.CurrentPet.Info.Hp) + + f.Second.AttackValue.SkillID = uint32(skill.Skill.ID) + f.Second.AttackValue.AttackTime = skill.Skill.AttackTime() + if ok { //判断暴击 + f.Second.AttackValue.IsCritical = 1 + } + fmt.Println(f.Second.CurrentPet.Info.CatchTime, "后手出招结束") + if f.Second.Damage > f.First.CurrentPet.Info.Hp { + f.First.CurrentPet.Info.Hp = 0 + } else { + f.First.CurrentPet.Info.Hp = f.First.CurrentPet.Info.Hp - f.Second.Damage //扣减先手方血量 + } + + } //还有系统选择放弃出手的 + + if f.First.CurrentPet.Info.Hp == 0 { + f.First.CanChange = true //被打死就可以切精灵了 + if f.Second.IsWin(f.First.CurrentPet.Info.CatchTime) { //然后检查是否战斗结束 + defer f.Broadcast(func(ff *Input) { + ff.Player.SendFightEndInfo(info.FightOverInfo{ + WinnerId: f.Second.UserID, + }) //广播逃跑原因 + }) + defer close(f.actionChan) //关闭战斗通道 + + } + } + + } else { + f.Second.AttackValue = info.NewAttackValue(second.Player.ID()) //已经被打死了,直接将后手方输出归0 + f.Second.CanChange = true //被打死就可以切精灵了 + if f.First.IsWin(f.Second.CurrentPet.Info.CatchTime) { //然后检查是否战斗结束 + defer f.Broadcast(func(ff *Input) { + ff.Player.SendFightEndInfo(info.FightOverInfo{ + WinnerId: f.First.UserID, + }) //广播逃跑原因 + }) + defer close(f.actionChan) //关闭战斗通道 + + } + } + + f.Broadcast(func(ff *Input) { + ret := info.AttackValueS{ + FAttack: *f.First.AttackValue, + SAttack: *f.Second.AttackValue, + } + ret.FAttack.RemainHp = int32(f.First.CurrentPet.Info.Hp) + + ret.FAttack.LostHp = uint32(f.First.Damage) //先手方造成血量 + ret.SAttack.RemainHp = int32(f.Second.CurrentPet.Info.Hp) + ret.SAttack.LostHp = uint32(f.Second.Damage) //后手方造成血量 + ff.Player.SendAttackValue(ret) + }) + return } diff --git a/logic/service/player.go b/logic/service/player.go index 92a13526c..449d2078e 100644 --- a/logic/service/player.go +++ b/logic/service/player.go @@ -128,11 +128,7 @@ func (p *Player) GetAction() { return } -func (p *Player) End() { - p.FightC = nil - return -} func (p *Player) ID() uint32 { return p.Info.UserID @@ -182,16 +178,15 @@ func (p *Player) SendFightEndInfo(b info.FightOverInfo) { t1 := NewTomeeHeader(2506, p.Info.UserID) p.SendPack(t1.Pack(&b)) + p.FightC = nil } -func (p *Player) GetPetInfo() []*model.PetInfo { - var ret = make([]*model.PetInfo, 0) +func (p *Player) GetPetInfo() []model.PetInfo { - for _, v := range p.Info.PetList { - ret = append(ret, &v) + return p.Info.PetList +} - } - - return ret +func (f *Player) SetFightC(ff *FightC) { + f.FightC = ff } // Save 保存玩家数据