package fight import ( "blazing/logic/service/common" "blazing/logic/service/fight/action" "blazing/logic/service/fight/info" "blazing/logic/service/fight/input" "blazing/modules/player/model" "bytes" "encoding/binary" ) const ( groupCmdReadyToFight uint32 = 7555 groupCmdReadyFightFinish uint32 = 7556 groupCmdStartFight uint32 = 7557 groupCmdUseSkill uint32 = 7558 groupCmdSkillHurt uint32 = 7559 groupCmdFightOver uint32 = 7560 groupCmdSpriteDie uint32 = 7561 groupCmdUseItem uint32 = 7562 groupCmdChangePet uint32 = 7563 groupCmdEscape uint32 = 7565 groupCmdBoutDone uint32 = 7566 groupCmdChangePetSuc uint32 = 7567 groupCmdEscapeSuc uint32 = 7568 groupCmdChat uint32 = 7569 groupCmdLoadPercent uint32 = 7571 groupCmdLoadPercentNotice uint32 = 7572 groupCmdSpriteNotice uint32 = 7573 groupCmdFightWinClose uint32 = 7574 groupCmdFightOvertime uint32 = 7585 groupCmdSkillPlayOver uint32 = 7586 groupCmdFightTimeoutExit uint32 = 7587 groupCmdFightRelation uint32 = 7588 groupModelNPC uint32 = 3 groupModelBoss uint32 = 4 groupModelPlayerSingle uint32 = 5 groupModelPlayerMulti uint32 = 6 ) func groupModelByFight(f *FightC) uint32 { if f == nil { return groupModelBoss } switch { case f.Info.Status == 0: return groupModelNPC case f.Info.Status == 1 && f.Info.Mode == 1: return groupModelPlayerSingle case f.Info.Status == 1: return groupModelPlayerMulti default: return groupModelBoss } } func writeUint8(buf *bytes.Buffer, v uint8) { _ = buf.WriteByte(v) } func writeUint32(buf *bytes.Buffer, v uint32) { _ = binary.Write(buf, binary.BigEndian, v) } func writeInt32(buf *bytes.Buffer, v int32) { _ = binary.Write(buf, binary.BigEndian, v) } func writeFixedString16(buf *bytes.Buffer, s string) { raw := make([]byte, 16) copy(raw, []byte(s)) _, _ = buf.Write(raw) } func buildPacket(cmd uint32, userID uint32, payload []byte) []byte { header := common.NewTomeeHeader(cmd, userID) totalLen := uint32(17 + len(payload)) header.Len = totalLen buf := make([]byte, totalLen) binary.BigEndian.PutUint32(buf[0:4], totalLen) buf[4] = header.Version binary.BigEndian.PutUint32(buf[5:9], cmd) binary.BigEndian.PutUint32(buf[9:13], userID) binary.BigEndian.PutUint32(buf[13:17], 0) copy(buf[17:], payload) return buf } func (f *FightC) sendLegacyGroupReady() { f.Broadcast(func(ff *input.Input) { if ff == nil || ff.Player == nil { return } sendLegacyPacket(ff.Player, groupCmdReadyToFight, f.buildLegacyGroupReadyPayload()) }) } func (f *FightC) sendLegacyGroupStart(player common.PlayerI) { if player == nil { return } sendLegacyPacket(player, groupCmdStartFight, f.buildLegacyGroupStartPayload()) } func (f *FightC) sendLegacyGroupOver(player common.PlayerI, over *model.FightOverInfo) { if player == nil { return } sendLegacyPacket(player, groupCmdFightOver, f.buildLegacyGroupOverPayload(over)) } func sendLegacyPacket(player common.PlayerI, cmd uint32, payload []byte) { if player == nil { return } if sender, ok := player.(interface{ SendPack([]byte) error }); ok { _ = sender.SendPack(buildPacket(cmd, player.GetInfo().UserID, payload)) } } func (f *FightC) buildLegacyGroupReadyPayload() []byte { var ( buf bytes.Buffer users [][]*input.Input ) writeUint32(&buf, groupModelByFight(f)) users = [][]*input.Input{f.Our, f.Opp} for sideIndex, sideInputs := range users { writeUint8(&buf, 1) var leaderID uint32 if len(sideInputs) > 0 && sideInputs[0] != nil && sideInputs[0].Player != nil { leaderID = sideInputs[0].Player.GetInfo().UserID } writeUint32(&buf, leaderID) writeUint8(&buf, 1) if leaderID == 0 { writeUint32(&buf, 0) writeFixedString16(&buf, "boss") } else { writeUint32(&buf, leaderID) writeFixedString16(&buf, sideInputs[0].Player.GetInfo().Nick) } writeUint32(&buf, uint32(len(sideInputs))) for _, slot := range sideInputs { if slot == nil || slot.CurrentPet() == nil { continue } currentPet := slot.CurrentPet() writeUint32(&buf, currentPet.Info.ID) writeUint32(&buf, uint32(len(currentPet.Info.SkillList))) for _, skill := range currentPet.Info.SkillList { writeUint32(&buf, skill.ID) } } if sideIndex == 0 && len(sideInputs) == 0 { writeUint32(&buf, 0) writeFixedString16(&buf, "") writeUint32(&buf, 0) } } return buf.Bytes() } func (f *FightC) buildLegacyGroupStartPayload() []byte { var ( buf bytes.Buffer sides [][]*input.Input ) writeUint8(&buf, 0) sides = [][]*input.Input{f.Our, f.Opp} for sideIndex, sideInputs := range sides { writeUint8(&buf, uint8(len(sideInputs))) for pos, slot := range sideInputs { if slot == nil || slot.CurrentPet() == nil { continue } currentPet := slot.CurrentPet() writeUint8(&buf, uint8(sideIndex+1)) writeUint8(&buf, uint8(pos)) if slot.Player != nil { writeUint32(&buf, slot.Player.GetInfo().UserID) } else { writeUint32(&buf, 0) } writeUint8(&buf, 0) writeUint32(&buf, currentPet.Info.ID) writeUint32(&buf, currentPet.Info.CatchTime) writeUint32(&buf, currentPet.Info.Hp) writeUint32(&buf, currentPet.Info.MaxHp) writeUint32(&buf, currentPet.Info.Level) writeUint32(&buf, 0) writeUint32(&buf, 1) } } return buf.Bytes() } func (f *FightC) buildLegacyGroupOverPayload(over *model.FightOverInfo) []byte { var ( buf bytes.Buffer winnerID uint32 endReason uint32 playerInfo *model.PlayerInfo ) if over != nil { winnerID = over.WinnerId endReason = uint32(over.Reason) } if our := f.primaryOurPlayer(); our != nil { playerInfo = our.GetInfo() } writeUint8(&buf, 0) writeUint32(&buf, endReason) writeUint32(&buf, winnerID) writeUint32(&buf, 0) if playerInfo != nil { writeUint32(&buf, uint32(playerInfo.TwoTimes)) writeUint32(&buf, uint32(playerInfo.ThreeTimes)) writeUint32(&buf, playerInfo.AutoFightTime) writeUint32(&buf, 0) writeUint32(&buf, uint32(playerInfo.EnergyTime)) writeUint32(&buf, playerInfo.LearnTimes) } else { for i := 0; i < 6; i++ { writeUint32(&buf, 0) } } return buf.Bytes() } func (f *FightC) SendLegacyEscapeSuccess(player common.PlayerI, actorIndex int) { if f == nil || !f.LegacyGroupProtocol || player == nil { return } payload := f.buildLegacyEscapePayload(player, actorIndex) f.Broadcast(func(ff *input.Input) { if ff == nil || ff.Player == nil { return } sendLegacyPacket(ff.Player, groupCmdEscapeSuc, payload) }) } func (f *FightC) buildLegacyEscapePayload(player common.PlayerI, actorIndex int) []byte { var buf bytes.Buffer side := uint8(1) if !f.isOurPlayerID(player.GetInfo().UserID) { side = 2 } writeUint32(&buf, player.GetInfo().UserID) writeFixedString16(&buf, player.GetInfo().Nick) writeUint8(&buf, side) writeUint8(&buf, uint8(actorIndex)) return buf.Bytes() } func (f *FightC) sendLegacyRoundBroadcast(firstAttack, secondAttack *action.SelectSkillAction) { if f == nil || !f.LegacyGroupProtocol { return } if firstAttack != nil { f.sendLegacyGroupSkillHurt(firstAttack) } if secondAttack != nil { f.sendLegacyGroupSkillHurt(secondAttack) } f.sendLegacyGroupBoutDone() } func (f *FightC) sendLegacyGroupSkillHurt(skillAction *action.SelectSkillAction) { var payload []byte if skillAction == nil { return } payload = f.buildLegacyGroupSkillHurtPayload(skillAction) if len(payload) == 0 { return } f.Broadcast(func(ff *input.Input) { if ff == nil || ff.Player == nil { return } sendLegacyPacket(ff.Player, groupCmdSkillHurt, payload) }) } func (f *FightC) buildLegacyGroupSkillHurtPayload(skillAction *action.SelectSkillAction) []byte { var buf bytes.Buffer attacker := f.GetInputByAction(skillAction, false) defender := f.GetInputByAction(skillAction, true) if attacker == nil || defender == nil || attacker.AttackValue == nil || defender.AttackValue == nil { return nil } writeUint8(&buf, 0) f.writeLegacySkillHurtInfo(&buf, skillAction, attacker, defender, true) f.writeLegacySkillHurtInfo(&buf, skillAction, defender, attacker, false) return buf.Bytes() } func (f *FightC) writeLegacySkillHurtInfo(buf *bytes.Buffer, skillAction *action.SelectSkillAction, self *input.Input, opponent *input.Input, isAttacker bool) { var ( moveID uint32 attackVal *model.AttackValue currentPet *info.BattlePetEntity side uint8 pos uint8 ) if self == nil || buf == nil { return } if self.AttackValue == nil { attackVal = info.NewAttackValue(self.UserID) } else { attackVal = self.AttackValue } currentPet = self.CurrentPet() side = 1 if !f.isOurPlayerID(self.UserID) { side = 2 } pos = uint8(self.TeamSlotIndex()) moveID = attackVal.SkillID if isAttacker { if skillAction != nil && skillAction.SkillEntity != nil { moveID = uint32(skillAction.SkillEntity.XML.ID) } writeUint8(buf, 0) } else { writeUint8(buf, 1) moveID = 0 } writeUint8(buf, side) writeUint8(buf, pos) writeUint32(buf, self.UserID) for i := 0; i < 20; i++ { writeUint8(buf, uint8(attackVal.Status[i])) } writeUint8(buf, 0) writeUint8(buf, 0) for i := 0; i < 6; i++ { writeUint8(buf, uint8(attackVal.Prop[i])) } if currentPet != nil { writeUint32(buf, currentPet.Info.ID) } else { writeUint32(buf, 0) } writeUint32(buf, moveID) if currentPet != nil { writeUint32(buf, currentPet.Info.Hp) writeUint32(buf, currentPet.Info.MaxHp) writeUint32(buf, uint32(len(currentPet.Info.SkillList))) for _, skill := range currentPet.Info.SkillList { writeUint32(buf, skill.ID) writeUint32(buf, skill.PP) } } else { writeUint32(buf, uint32(maxInt32(attackVal.RemainHp))) writeUint32(buf, attackVal.MaxHp) writeUint32(buf, uint32(len(attackVal.SkillList))) for _, skill := range attackVal.SkillList { writeUint32(buf, skill.ID) writeUint32(buf, skill.PP) } } writeUint32(buf, attackVal.State) if isAttacker { writeUint32(buf, attackVal.IsCritical) writeUint32(buf, attackVal.State) writeUint32(buf, 1) writeInt32(buf, int32(attackVal.LostHp)) writeInt32(buf, attackVal.GainHp) } writeUint32(buf, 0) } func (f *FightC) sendLegacyGroupBoutDone() { var buf bytes.Buffer if f == nil || !f.LegacyGroupProtocol { return } writeUint32(&buf, f.Round) f.Broadcast(func(ff *input.Input) { if ff == nil || ff.Player == nil { return } sendLegacyPacket(ff.Player, groupCmdBoutDone, buf.Bytes()) }) } func (f *FightC) sendLegacySpriteDie(in *input.Input, hasBackup bool) { var ( buf bytes.Buffer side uint8 data uint32 ) if f == nil || !f.LegacyGroupProtocol || in == nil { return } side = 1 if !f.isOurPlayerID(in.UserID) { side = 2 } if hasBackup { data = 1 } writeUint8(&buf, 1) writeUint8(&buf, side) writeUint8(&buf, uint8(in.TeamSlotIndex())) writeUint8(&buf, 1) writeUint32(&buf, data) f.Broadcast(func(ff *input.Input) { if ff == nil || ff.Player == nil { return } sendLegacyPacket(ff.Player, groupCmdSpriteDie, buf.Bytes()) }) } func maxInt32(v int32) int32 { if v < 0 { return 0 } return v }