diff --git a/src/server/game/BattlePets/PetBattleMgr.cpp b/src/server/game/BattlePets/PetBattleMgr.cpp index f7220c8e1..6e78cf3f2 100644 --- a/src/server/game/BattlePets/PetBattleMgr.cpp +++ b/src/server/game/BattlePets/PetBattleMgr.cpp @@ -549,7 +549,11 @@ namespace PetBattles battle->Start(); WorldPackets::BattlePet::PetBattleFinalizeLocation finalizeLocation; - finalizeLocation.Location = p1->GetPosition(); + finalizeLocation.Location.LocationResult = 0; + finalizeLocation.Location.BattleOrigin = p1->GetPosition(); + finalizeLocation.Location.BattleFacing = p1->GetAbsoluteAngle(p2); + finalizeLocation.Location.PlayerPositions[0] = p1->GetPosition(); + finalizeLocation.Location.PlayerPositions[1] = p2->GetPosition(); p1->SendDirectMessage(finalizeLocation.Write()); p2->SendDirectMessage(finalizeLocation.Write()); } diff --git a/src/server/game/Handlers/BattlePetHandler.cpp b/src/server/game/Handlers/BattlePetHandler.cpp index 2a426e164..287aebea3 100644 --- a/src/server/game/Handlers/BattlePetHandler.cpp +++ b/src/server/game/Handlers/BattlePetHandler.cpp @@ -211,22 +211,43 @@ static void BuildPetBattleRoundPlayerData(WorldPackets::BattlePet::PetBattleRoun roundData.NextInputFlags = team.InputFlags; roundData.NextTrapStatus = battle ? static_cast(battle->GetTrapStatus(teamIdx)) : static_cast(team.TrapStatus); roundData.RoundTimeSecs = PetBattles::PET_BATTLE_MAX_ROUND_TIME; +} - for (uint8 i = 0; i < team.PetCount; ++i) +static void BuildRoundCooldowns(std::vector& cooldowns, + PetBattles::PetBattle const* battle) +{ + for (uint8 t = 0; t < PetBattles::MAX_PET_BATTLE_PLAYERS; ++t) { - std::vector petCds; - for (uint8 j = 0; j < PetBattles::MAX_PET_BATTLE_ABILITIES; ++j) + PetBattles::PetBattleTeamData const& team = battle->GetTeam(t); + for (uint8 i = 0; i < team.PetCount; ++i) { - if (team.Pets[i].AbilityIDs[j] == 0) - continue; + for (uint8 j = 0; j < PetBattles::MAX_PET_BATTLE_ABILITIES; ++j) + { + if (team.Pets[i].AbilityIDs[j] == 0) + continue; - WorldPackets::BattlePet::PetBattleCooldownInfo cd; - cd.AbilityID = team.Pets[i].AbilityIDs[j]; - cd.CooldownRemaining = team.Pets[i].AbilityCooldowns[j]; - cd.LockdownRemaining = team.Pets[i].AbilityLockdowns[j]; - petCds.push_back(cd); + WorldPackets::BattlePet::PetBattleCooldownInfo cd; + cd.AbilityID = team.Pets[i].AbilityIDs[j]; + cd.CooldownRemaining = team.Pets[i].AbilityCooldowns[j]; + cd.LockdownRemaining = team.Pets[i].AbilityLockdowns[j]; + cd.AbilityIndex = static_cast(j); + cd.Pboid = t * PetBattles::MAX_PET_BATTLE_TEAM_SIZE + i; + cooldowns.push_back(cd); + } + } + } +} + +static void BuildPetXDied(std::vector& petXDied, PetBattles::PetBattle const* battle) +{ + for (uint8 t = 0; t < PetBattles::MAX_PET_BATTLE_PLAYERS; ++t) + { + PetBattles::PetBattleTeamData const& team = battle->GetTeam(t); + for (uint8 i = 0; i < team.PetCount; ++i) + { + if (battle->WasPetKilledThisRound(t, i)) + petXDied.push_back(static_cast(t * PetBattles::MAX_PET_BATTLE_TEAM_SIZE + i)); } - roundData.PetCooldowns.push_back(std::move(petCds)); } } @@ -238,16 +259,65 @@ static void BuildRoundEffects(std::vector(roundEffect.SourceTeam * PetBattles::MAX_PET_BATTLE_TEAM_SIZE + roundEffect.SourcePet); + effect.SourceAuraInstanceID = 0; + effect.TurnInstanceID = 0; + effect.PetBattleEffectType = static_cast(roundEffect.EffectType); + effect.CasterPBOID = static_cast(roundEffect.SourceTeam * PetBattles::MAX_PET_BATTLE_TEAM_SIZE + roundEffect.SourcePet); + effect.StackDepth = 0; WorldPackets::BattlePet::PetBattleEffectTargetInfo target; - target.Type = roundEffect.EffectType; target.Petx = static_cast(roundEffect.TargetTeam * PetBattles::MAX_PET_BATTLE_TEAM_SIZE + roundEffect.TargetPet); - target.Param1 = roundEffect.Param1; - target.Param2 = roundEffect.Param2; - effect.Targets.push_back(target); + // Map effect type to target type and variable-length params + // Target types: 0=none, 1=aura(4 i32), 2=state(2 i32), 3=health(1 i32), + // 4=stat(1 i32), 5=trigger(1 i32), 6=cooldown(3 i32), 7=broadcast(1 i32) + switch (roundEffect.EffectType) + { + case PetBattles::PET_BATTLE_EFFECT_SET_HEALTH: + case PetBattles::PET_BATTLE_EFFECT_SET_MAX_HEALTH: + target.Type = 3; // Health + target.Params.push_back(roundEffect.Param1); + break; + case PetBattles::PET_BATTLE_EFFECT_AURA_APPLY: + case PetBattles::PET_BATTLE_EFFECT_AURA_CANCEL: + case PetBattles::PET_BATTLE_EFFECT_AURA_CHANGE: + target.Type = 1; // Aura + target.Params.push_back(roundEffect.Param1); // AuraInstanceID + target.Params.push_back(roundEffect.Param2); // AuraAbilityID + target.Params.push_back(0); // RoundsRemaining + target.Params.push_back(0); // CurrentRound + break; + case PetBattles::PET_BATTLE_EFFECT_SET_STATE: + target.Type = 2; // State + target.Params.push_back(roundEffect.Param1); // StateID + target.Params.push_back(roundEffect.Param2); // StateValue + break; + case PetBattles::PET_BATTLE_EFFECT_STATUS_CHANGE: + case PetBattles::PET_BATTLE_EFFECT_SET_SPEED: + case PetBattles::PET_BATTLE_EFFECT_SET_POWER: + target.Type = 4; // NewStatValue + target.Params.push_back(roundEffect.Param1); + break; + case PetBattles::PET_BATTLE_EFFECT_TRIGGER_ABILITY: + target.Type = 5; // TriggerAbilityID + target.Params.push_back(roundEffect.Param1); + break; + case PetBattles::PET_BATTLE_EFFECT_ABILITY_CHANGE: + target.Type = 6; // Cooldown + target.Params.push_back(roundEffect.Param1); // ChangedAbilityID + target.Params.push_back(roundEffect.Param2); // CooldownRemaining + target.Params.push_back(0); // LockdownRemaining + break; + case PetBattles::PET_BATTLE_EFFECT_NPC_EMOTE: + target.Type = 7; // BroadcastTextID + target.Params.push_back(roundEffect.Param1); + break; + default: + target.Type = 0; // No data + break; + } + + effect.Targets.push_back(target); effectList.push_back(std::move(effect)); } } @@ -330,7 +400,11 @@ void WorldSession::HandlePetBattleRequestWild(WorldPackets::BattlePet::PetBattle // Send finalize location WorldPackets::BattlePet::PetBattleFinalizeLocation finalizeLocation; - finalizeLocation.Location = player->GetPosition(); + finalizeLocation.Location.LocationResult = 0; + finalizeLocation.Location.BattleOrigin = player->GetPosition(); + finalizeLocation.Location.BattleFacing = player->GetAbsoluteAngle(creature); + finalizeLocation.Location.PlayerPositions[0] = player->GetPosition(); + finalizeLocation.Location.PlayerPositions[1] = creature->GetPosition(); SendPacket(finalizeLocation.Write()); // Build and send initial update @@ -391,18 +465,37 @@ void WorldSession::HandlePetBattleInput(WorldPackets::BattlePet::PetBattleInput& { // Send final round WorldPackets::BattlePet::PetBattleFinalRound finalRound; - finalRound.CurRound = battle->GetCurrentRound(); - finalRound.NextPetBattleState = static_cast(battle->GetBattleState()); - for (uint8 i = 0; i < PetBattles::MAX_PET_BATTLE_PLAYERS; ++i) - BuildPetBattleRoundPlayerData(finalRound.Players[i], battle->GetTeam(i), battle, i); - BuildRoundEffects(finalRound.Effects, battle); - + finalRound.Abandoned = false; + finalRound.PvpBattle = (battle->GetBattleType() == PetBattles::PET_BATTLE_TYPE_PVP || battle->GetBattleType() == PetBattles::PET_BATTLE_TYPE_LFPB); finalRound.Winners[battle->GetWinnerTeam()] = true; - // Send to player team 1 + for (uint8 t = 0; t < PetBattles::MAX_PET_BATTLE_PLAYERS; ++t) + { + PetBattles::PetBattleTeamData const& team = battle->GetTeam(t); + + if (battle->GetBattleType() == PetBattles::PET_BATTLE_TYPE_NPC && t == PetBattles::PET_BATTLE_TEAM_2) + finalRound.NpcCreatureID[t] = team.Pets[0].CreatureID; + + for (uint8 i = 0; i < team.PetCount; ++i) + { + WorldPackets::BattlePet::PetBattleFinalPet pet; + pet.Guid = team.Pets[i].BattlePetGUID; + pet.Level = team.Pets[i].Level; + pet.Xp = team.Pets[i].Xp; + pet.Health = team.Pets[i].Health; + pet.MaxHealth = team.Pets[i].MaxHealth; + pet.InitialLevel = team.Pets[i].Level; // TODO: track initial level before XP awards + pet.Pboid = t * PetBattles::MAX_PET_BATTLE_TEAM_SIZE + i; + pet.Captured = team.Pets[i].IsCaptured; + pet.Caged = false; + pet.SeenAction = true; + pet.AwardedXP = battle->CanAwardXP() && (battle->GetWinnerTeam() == t); + finalRound.Pets.push_back(pet); + } + } + if (Player* p1 = battle->GetPlayerForTeam(PetBattles::PET_BATTLE_TEAM_1)) p1->SendDirectMessage(finalRound.Write()); - // Send to player team 2 (PvP) if (Player* p2 = battle->GetPlayerForTeam(PetBattles::PET_BATTLE_TEAM_2)) p2->SendDirectMessage(finalRound.Write()); @@ -438,10 +531,12 @@ void WorldSession::HandlePetBattleInput(WorldPackets::BattlePet::PetBattleInput& { WorldPackets::BattlePet::PetBattleFirstRound firstRound; firstRound.CurRound = battle->GetCurrentRound(); - firstRound.NextPetBattleState = static_cast(battle->GetBattleState()); + firstRound.NextPetBattleState = static_cast(battle->GetBattleState()); for (uint8 i = 0; i < PetBattles::MAX_PET_BATTLE_PLAYERS; ++i) BuildPetBattleRoundPlayerData(firstRound.Players[i], battle->GetTeam(i), battle, i); BuildRoundEffects(firstRound.Effects, battle); + BuildRoundCooldowns(firstRound.Cooldowns, battle); + BuildPetXDied(firstRound.PetXDied, battle); if (Player* p1 = battle->GetPlayerForTeam(PetBattles::PET_BATTLE_TEAM_1)) p1->SendDirectMessage(firstRound.Write()); @@ -452,10 +547,12 @@ void WorldSession::HandlePetBattleInput(WorldPackets::BattlePet::PetBattleInput& { WorldPackets::BattlePet::PetBattleRoundResult roundResult; roundResult.CurRound = battle->GetCurrentRound(); - roundResult.NextPetBattleState = static_cast(battle->GetBattleState()); + roundResult.NextPetBattleState = static_cast(battle->GetBattleState()); for (uint8 i = 0; i < PetBattles::MAX_PET_BATTLE_PLAYERS; ++i) BuildPetBattleRoundPlayerData(roundResult.Players[i], battle->GetTeam(i), battle, i); BuildRoundEffects(roundResult.Effects, battle); + BuildRoundCooldowns(roundResult.Cooldowns, battle); + BuildPetXDied(roundResult.PetXDied, battle); if (Player* p1 = battle->GetPlayerForTeam(PetBattles::PET_BATTLE_TEAM_1)) p1->SendDirectMessage(roundResult.Write()); @@ -495,9 +592,12 @@ void WorldSession::HandlePetBattleReplaceFrontPet(WorldPackets::BattlePet::PetBa WorldPackets::BattlePet::PetBattleReplacementsMade replacements; replacements.CurRound = battle->GetCurrentRound(); - replacements.NextPetBattleState = static_cast(battle->GetBattleState()); + replacements.NextPetBattleState = static_cast(battle->GetBattleState()); for (uint8 i = 0; i < PetBattles::MAX_PET_BATTLE_PLAYERS; ++i) BuildPetBattleRoundPlayerData(replacements.Players[i], battle->GetTeam(i), battle, i); + BuildRoundEffects(replacements.Effects, battle); + BuildRoundCooldowns(replacements.Cooldowns, battle); + BuildPetXDied(replacements.PetXDied, battle); if (Player* p1 = battle->GetPlayerForTeam(PetBattles::PET_BATTLE_TEAM_1)) p1->SendDirectMessage(replacements.Write()); @@ -530,12 +630,31 @@ void WorldSession::HandlePetBattleQuitNotify(WorldPackets::BattlePet::PetBattleQ // Send final round to both players WorldPackets::BattlePet::PetBattleFinalRound finalRound; - finalRound.CurRound = battle->GetCurrentRound(); - finalRound.NextPetBattleState = static_cast(battle->GetBattleState()); - for (uint8 i = 0; i < PetBattles::MAX_PET_BATTLE_PLAYERS; ++i) - BuildPetBattleRoundPlayerData(finalRound.Players[i], battle->GetTeam(i), battle, i); + finalRound.Abandoned = true; + finalRound.PvpBattle = (battle->GetBattleType() == PetBattles::PET_BATTLE_TYPE_PVP || battle->GetBattleType() == PetBattles::PET_BATTLE_TYPE_LFPB); finalRound.Winners[battle->GetWinnerTeam()] = true; + for (uint8 t = 0; t < PetBattles::MAX_PET_BATTLE_PLAYERS; ++t) + { + PetBattles::PetBattleTeamData const& team = battle->GetTeam(t); + for (uint8 i = 0; i < team.PetCount; ++i) + { + WorldPackets::BattlePet::PetBattleFinalPet pet; + pet.Guid = team.Pets[i].BattlePetGUID; + pet.Level = team.Pets[i].Level; + pet.Xp = team.Pets[i].Xp; + pet.Health = team.Pets[i].Health; + pet.MaxHealth = team.Pets[i].MaxHealth; + pet.InitialLevel = team.Pets[i].Level; + pet.Pboid = t * PetBattles::MAX_PET_BATTLE_TEAM_SIZE + i; + pet.Captured = team.Pets[i].IsCaptured; + pet.Caged = false; + pet.SeenAction = true; + pet.AwardedXP = false; + finalRound.Pets.push_back(pet); + } + } + if (Player* p1 = battle->GetPlayerForTeam(PetBattles::PET_BATTLE_TEAM_1)) p1->SendDirectMessage(finalRound.Write()); if (Player* p2 = battle->GetPlayerForTeam(PetBattles::PET_BATTLE_TEAM_2)) @@ -655,7 +774,11 @@ void WorldSession::HandlePetBattleRequestPVP(WorldPackets::BattlePet::PetBattleR // Send PVP challenge to target WorldPackets::BattlePet::PetBattlePVPChallenge challenge; challenge.ChallengerGUID = player->GetGUID(); - challenge.BattleOrigin = player->GetPosition(); + challenge.Location.LocationResult = 0; + challenge.Location.BattleOrigin = player->GetPosition(); + challenge.Location.BattleFacing = player->GetAbsoluteAngle(target); + challenge.Location.PlayerPositions[0] = player->GetPosition(); + challenge.Location.PlayerPositions[1] = target->GetPosition(); target->SendDirectMessage(challenge.Write()); } diff --git a/src/server/game/Server/Packets/BattlePetPackets.cpp b/src/server/game/Server/Packets/BattlePetPackets.cpp index 790f93bc5..5e9996f2a 100644 --- a/src/server/game/Server/Packets/BattlePetPackets.cpp +++ b/src/server/game/Server/Packets/BattlePetPackets.cpp @@ -16,7 +16,6 @@ */ #include "BattlePetPackets.h" -#include "MovementPackets.h" #include "PacketOperators.h" namespace WorldPackets::BattlePet @@ -327,10 +326,13 @@ namespace WorldPackets::BattlePet ByteBuffer& operator<<(ByteBuffer& data, PetBattleEffectTargetInfo const& target) { - data << uint8(target.Type); + data << Bits<3>(target.Type); + data.FlushBits(); + data << uint8(target.Petx); - data << int32(target.Param1); - data << int32(target.Param2); + + for (int32 param : target.Params) + data << int32(param); return data; } @@ -339,10 +341,11 @@ namespace WorldPackets::BattlePet { data << uint32(effect.AbilityEffectID); data << uint16(effect.Flags); - data << uint8(effect.SourceAuraPetInstance); + data << uint16(effect.SourceAuraInstanceID); + data << uint16(effect.TurnInstanceID); + data << int8(effect.PetBattleEffectType); + data << uint8(effect.CasterPBOID); data << uint8(effect.StackDepth); - data << uint8(effect.PetBattleEffectType); - data << int8(effect.CasterPBOID); data << uint32(effect.Targets.size()); for (PetBattleEffectTargetInfo const& target : effect.Targets) @@ -356,46 +359,76 @@ namespace WorldPackets::BattlePet data << int32(cd.AbilityID); data << int16(cd.CooldownRemaining); data << int16(cd.LockdownRemaining); + data << int8(cd.AbilityIndex); + data << uint8(cd.Pboid); return data; } - static void WriteRoundPlayerData(ByteBuffer& data, PetBattleRoundPlayerData const& player) + // Writes the common round result wire format shared by FirstRound, RoundResult, and ReplacementsMade + static void WriteRoundResult(ByteBuffer& data, uint32 curRound, int8 nextPetBattleState, + std::array const& players, + std::vector const& effects, + std::vector const& cooldowns, + std::vector const& petXDied) { - data << uint8(player.NextInputFlags); - data << int8(player.NextTrapStatus); - data << uint16(player.RoundTimeSecs); + data << uint32(curRound); + data << int8(nextPetBattleState); - data << uint32(player.PetCooldowns.size()); - for (std::vector const& petCds : player.PetCooldowns) - { - data << uint32(petCds.size()); - for (PetBattleCooldownInfo const& cd : petCds) - data << cd; - } - } - - static void WriteRoundEffects(ByteBuffer& data, std::vector const& effects) - { data << uint32(effects.size()); + + for (std::size_t i = 0; i < 2; ++i) + { + data << uint8(players[i].NextInputFlags); + data << int8(players[i].NextTrapStatus); + data << uint16(players[i].RoundTimeSecs); + } + + data << uint32(cooldowns.size()); + for (PetBattleEffectInfo const& effect : effects) data << effect; + + for (PetBattleCooldownInfo const& cd : cooldowns) + data << cd; + + data << Bits<3>(petXDied.size()); + data.FlushBits(); + + for (int8 pboid : petXDied) + data << int8(pboid); } // ---- CMSG Read() implementations ---- + static void ReadPetBattleLocation(ByteBuffer& data, PetBattleLocation& loc) + { + data >> loc.LocationResult; + data >> loc.BattleOrigin.m_positionX; + data >> loc.BattleOrigin.m_positionY; + data >> loc.BattleOrigin.m_positionZ; + data >> loc.BattleFacing; + for (std::size_t i = 0; i < 2; ++i) + { + data >> loc.PlayerPositions[i].m_positionX; + data >> loc.PlayerPositions[i].m_positionY; + data >> loc.PlayerPositions[i].m_positionZ; + } + } + void PetBattleRequestWild::Read() { _worldPacket >> TargetGUID; - _worldPacket >> LocationInfo; - BattleOrigin = LocationInfo.pos; + ReadPetBattleLocation(_worldPacket, Location); } void PetBattleInput::Read() { _worldPacket >> MoveType; - _worldPacket >> AbilityID; _worldPacket >> NewFrontPetIndex; + _worldPacket >> DebugFlags; + _worldPacket >> BattleInterrupted; + _worldPacket >> AbilityID; _worldPacket >> Round; _worldPacket >> Bits<1>(IgnoreAbandonPenalty); } @@ -408,8 +441,7 @@ namespace WorldPackets::BattlePet void PetBattleRequestPVP::Read() { _worldPacket >> TargetGUID; - _worldPacket >> LocationInfo; - BattleOrigin = LocationInfo.pos; + ReadPetBattleLocation(_worldPacket, Location); } void PetBattleQueueProposeMatchResult::Read() @@ -425,12 +457,24 @@ namespace WorldPackets::BattlePet // ---- SMSG Write() implementations ---- + static void WritePetBattleLocation(ByteBuffer& data, PetBattleLocation const& loc) + { + data << int32(loc.LocationResult); + data << loc.BattleOrigin.m_positionX; + data << loc.BattleOrigin.m_positionY; + data << loc.BattleOrigin.m_positionZ; + data << loc.BattleFacing; + for (std::size_t i = 0; i < 2; ++i) + { + data << loc.PlayerPositions[i].m_positionX; + data << loc.PlayerPositions[i].m_positionY; + data << loc.PlayerPositions[i].m_positionZ; + } + } + WorldPacket const* PetBattleFinalizeLocation::Write() { - _worldPacket << Location.m_positionX; - _worldPacket << Location.m_positionY; - _worldPacket << Location.m_positionZ; - _worldPacket << Location.GetOrientation(); + WritePetBattleLocation(_worldPacket, Location); return &_worldPacket; } @@ -474,59 +518,59 @@ namespace WorldPackets::BattlePet WorldPacket const* PetBattleFirstRound::Write() { - _worldPacket << uint32(CurRound); - _worldPacket << uint8(NextPetBattleState); - - for (std::size_t i = 0; i < 2; ++i) - WriteRoundPlayerData(_worldPacket, Players[i]); - - WriteRoundEffects(_worldPacket, Effects); + WriteRoundResult(_worldPacket, CurRound, NextPetBattleState, Players, Effects, Cooldowns, PetXDied); return &_worldPacket; } WorldPacket const* PetBattleRoundResult::Write() { - _worldPacket << uint32(CurRound); - _worldPacket << uint8(NextPetBattleState); - - for (std::size_t i = 0; i < 2; ++i) - WriteRoundPlayerData(_worldPacket, Players[i]); - - WriteRoundEffects(_worldPacket, Effects); + WriteRoundResult(_worldPacket, CurRound, NextPetBattleState, Players, Effects, Cooldowns, PetXDied); return &_worldPacket; } WorldPacket const* PetBattleReplacementsMade::Write() { - _worldPacket << uint32(CurRound); - _worldPacket << uint8(NextPetBattleState); - - for (std::size_t i = 0; i < 2; ++i) - WriteRoundPlayerData(_worldPacket, Players[i]); + WriteRoundResult(_worldPacket, CurRound, NextPetBattleState, Players, Effects, Cooldowns, PetXDied); return &_worldPacket; } + ByteBuffer& operator<<(ByteBuffer& data, PetBattleFinalPet const& pet) + { + data << pet.Guid; + data << uint16(pet.Level); + data << uint16(pet.Xp); + data << int32(pet.Health); + data << int32(pet.MaxHealth); + data << uint16(pet.InitialLevel); + data << uint8(pet.Pboid); + + data << Bits<1>(pet.Captured); + data << Bits<1>(pet.Caged); + data << Bits<1>(pet.SeenAction); + data << Bits<1>(pet.AwardedXP); + data.FlushBits(); + + return data; + } + WorldPacket const* PetBattleFinalRound::Write() { - _worldPacket << uint32(CurRound); - _worldPacket << uint8(NextPetBattleState); - - for (std::size_t i = 0; i < 2; ++i) - WriteRoundPlayerData(_worldPacket, Players[i]); - - WriteRoundEffects(_worldPacket, Effects); - - _worldPacket << Bits<1>(AbandonedPVP); - _worldPacket << Bits<1>(PVPWinner); + _worldPacket << Bits<1>(Abandoned); + _worldPacket << Bits<1>(PvpBattle); for (std::size_t i = 0; i < 2; ++i) _worldPacket << Bits<1>(Winners[i]); _worldPacket.FlushBits(); for (std::size_t i = 0; i < 2; ++i) - _worldPacket << uint32(NpcCreatureID[i]); + _worldPacket << int32(NpcCreatureID[i]); + + _worldPacket << uint32(Pets.size()); + + for (PetBattleFinalPet const& pet : Pets) + _worldPacket << pet; return &_worldPacket; } @@ -541,10 +585,7 @@ namespace WorldPackets::BattlePet WorldPacket const* PetBattlePVPChallenge::Write() { _worldPacket << ChallengerGUID; - _worldPacket << BattleOrigin.m_positionX; - _worldPacket << BattleOrigin.m_positionY; - _worldPacket << BattleOrigin.m_positionZ; - _worldPacket << BattleOrigin.GetOrientation(); + WritePetBattleLocation(_worldPacket, Location); return &_worldPacket; } diff --git a/src/server/game/Server/Packets/BattlePetPackets.h b/src/server/game/Server/Packets/BattlePetPackets.h index 342c32686..e19011a3c 100644 --- a/src/server/game/Server/Packets/BattlePetPackets.h +++ b/src/server/game/Server/Packets/BattlePetPackets.h @@ -20,7 +20,6 @@ #include "Packet.h" #include "PacketUtilities.h" -#include "MovementInfo.h" #include "ObjectGuid.h" #include "Optional.h" #include "Position.h" @@ -349,20 +348,23 @@ namespace WorldPackets struct PetBattleEffectTargetInfo { - uint8 Type = 0; + uint8 Type = 0; // Written as 3 bits + ResetBitReader uint8 Petx = 0; - int32 Param1 = 0; - int32 Param2 = 0; + // Variable-length params based on Type: + // 0: nothing, 1: 4 int32s (aura), 2: 2 int32s (state), 3: 1 int32 (health), + // 4: 1 int32 (stat), 5: 1 int32 (trigger), 6: 3 int32s (cooldown), 7: 1 int32 (broadcast) + std::vector Params; }; struct PetBattleEffectInfo { uint32 AbilityEffectID = 0; uint16 Flags = 0; - uint8 SourceAuraPetInstance = 0; + uint16 SourceAuraInstanceID = 0; + uint16 TurnInstanceID = 0; + int8 PetBattleEffectType = 0; + uint8 CasterPBOID = 0; uint8 StackDepth = 0; - uint8 PetBattleEffectType = 0; - int8 CasterPBOID = 0; std::vector Targets; }; @@ -371,6 +373,8 @@ namespace WorldPackets int32 AbilityID = 0; int16 CooldownRemaining = 0; int16 LockdownRemaining = 0; + int8 AbilityIndex = 0; + uint8 Pboid = 0; }; struct PetBattleRoundPlayerData @@ -378,7 +382,15 @@ namespace WorldPackets uint8 NextInputFlags = 0; int8 NextTrapStatus = 0; uint16 RoundTimeSecs = 0; - std::vector> PetCooldowns; // per pet + }; + + // Shared location structure used by multiple pet battle packets + struct PetBattleLocation + { + int32 LocationResult = 0; + Position BattleOrigin; // Only XYZ written + float BattleFacing = 0.0f; + std::array PlayerPositions; // Only XYZ written }; // ---- CMSG packets ---- @@ -391,8 +403,7 @@ namespace WorldPackets void Read() override; ObjectGuid TargetGUID; - MovementInfo LocationInfo; - Position BattleOrigin; + PetBattleLocation Location; }; class PetBattleInput final : public ClientPacket @@ -402,10 +413,12 @@ namespace WorldPackets void Read() override; - uint8 MoveType = 0; - int32 AbilityID = 0; + int32 MoveType = 0; int8 NewFrontPetIndex = -1; - uint8 Round = 0; + int32 DebugFlags = 0; + uint8 BattleInterrupted = 0; + int32 AbilityID = 0; + int32 Round = 0; bool IgnoreAbandonPenalty = false; }; @@ -443,8 +456,7 @@ namespace WorldPackets void Read() override; ObjectGuid TargetGUID; - MovementInfo LocationInfo; - Position BattleOrigin; + PetBattleLocation Location; }; class JoinPetBattleQueue final : public ClientPacket @@ -509,7 +521,7 @@ namespace WorldPackets WorldPacket const* Write() override; - Position Location; + PetBattleLocation Location; }; class PetBattleInitialUpdate final : public ServerPacket @@ -541,9 +553,11 @@ namespace WorldPackets WorldPacket const* Write() override; uint32 CurRound = 0; - uint8 NextPetBattleState = 0; + int8 NextPetBattleState = 0; std::array Players; std::vector Effects; + std::vector Cooldowns; + std::vector PetXDied; }; class PetBattleRoundResult final : public ServerPacket @@ -554,9 +568,11 @@ namespace WorldPackets WorldPacket const* Write() override; uint32 CurRound = 0; - uint8 NextPetBattleState = 0; + int8 NextPetBattleState = 0; std::array Players; std::vector Effects; + std::vector Cooldowns; + std::vector PetXDied; }; class PetBattleReplacementsMade final : public ServerPacket @@ -567,8 +583,26 @@ namespace WorldPackets WorldPacket const* Write() override; uint32 CurRound = 0; - uint8 NextPetBattleState = 0; + int8 NextPetBattleState = 0; std::array Players; + std::vector Effects; + std::vector Cooldowns; + std::vector PetXDied; + }; + + struct PetBattleFinalPet + { + ObjectGuid Guid; + uint16 Level = 0; + uint16 Xp = 0; + int32 Health = 0; + int32 MaxHealth = 0; + uint16 InitialLevel = 0; + uint8 Pboid = 0; + bool Captured = false; + bool Caged = false; + bool SeenAction = false; + bool AwardedXP = false; }; class PetBattleFinalRound final : public ServerPacket @@ -578,15 +612,11 @@ namespace WorldPackets WorldPacket const* Write() override; - uint32 CurRound = 0; - uint8 NextPetBattleState = 0; - std::array Players; - std::vector Effects; - // Final state includes flags - bool AbandonedPVP = false; - bool PVPWinner = false; + bool Abandoned = false; + bool PvpBattle = false; std::array Winners = {}; - std::array NpcCreatureID = {}; + std::array NpcCreatureID = {}; + std::vector Pets; }; class PetBattleFinished final : public ServerPacket @@ -615,7 +645,7 @@ namespace WorldPackets WorldPacket const* Write() override; ObjectGuid ChallengerGUID; - Position BattleOrigin; + PetBattleLocation Location; }; class PetBattleQueueStatus final : public ServerPacket