aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/Handlers/NPCHandler.cpp
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2022-02-02 00:08:37 +0100
committerShauren <shauren.trinity@gmail.com>2022-02-02 00:08:37 +0100
commit950db60435e7e513633ff5b22ad7f0ed8b1147e4 (patch)
treecb5b9e47570528dea0374f804f829512c89a5410 /src/server/game/Handlers/NPCHandler.cpp
parentd6a2461fc77f156dfe9e62c1c2387815c27e43de (diff)
Core/Pets: Updated pet summoning for latest client version (5 Call Pet spells and stable size 200)
Diffstat (limited to 'src/server/game/Handlers/NPCHandler.cpp')
-rw-r--r--src/server/game/Handlers/NPCHandler.cpp377
1 files changed, 109 insertions, 268 deletions
diff --git a/src/server/game/Handlers/NPCHandler.cpp b/src/server/game/Handlers/NPCHandler.cpp
index 0607103ad6c..43ac2e581d8 100644
--- a/src/server/game/Handlers/NPCHandler.cpp
+++ b/src/server/game/Handlers/NPCHandler.cpp
@@ -32,14 +32,11 @@
#include "MailPackets.h"
#include "Map.h"
#include "NPCPackets.h"
-#include "ObjectAccessor.h"
#include "ObjectMgr.h"
-#include "Opcodes.h"
#include "Pet.h"
#include "PetPackets.h"
#include "Player.h"
#include "ReputationMgr.h"
-#include "ScriptMgr.h"
#include "SpellInfo.h"
#include "SpellMgr.h"
#include "Trainer.h"
@@ -373,51 +370,36 @@ void WorldSession::SendStablePet(ObjectGuid guid)
return;
}
- int32 petSlot = 0;
- if (petStable->CurrentPet)
+ for (uint32 petSlot = 0; petSlot < petStable->ActivePets.size(); ++petSlot)
{
- PetStable::PetInfo const& pet = *petStable->CurrentPet;
+ if (!petStable->ActivePets[petSlot])
+ continue;
+
+ PetStable::PetInfo const& pet = *petStable->ActivePets[petSlot];
WorldPackets::Pet::PetStableInfo& stableEntry = packet.Pets.emplace_back();
- stableEntry.PetSlot = petSlot;
+ stableEntry.PetSlot = petSlot + PET_SAVE_FIRST_ACTIVE_SLOT;
stableEntry.PetNumber = pet.PetNumber;
stableEntry.CreatureID = pet.CreatureId;
stableEntry.DisplayID = pet.DisplayId;
stableEntry.ExperienceLevel = pet.Level;
stableEntry.PetFlags = PET_STABLE_ACTIVE;
stableEntry.PetName = pet.Name;
- ++petSlot;
- }
- else
- {
- if (PetStable::PetInfo const* pet = petStable->GetUnslottedHunterPet())
- {
- WorldPackets::Pet::PetStableInfo& stableEntry = packet.Pets.emplace_back();
- stableEntry.PetSlot = petSlot;
- stableEntry.PetNumber = pet->PetNumber;
- stableEntry.CreatureID = pet->CreatureId;
- stableEntry.DisplayID = pet->DisplayId;
- stableEntry.ExperienceLevel = pet->Level;
- stableEntry.PetFlags = PET_STABLE_ACTIVE;
- stableEntry.PetName = pet->Name;
- ++petSlot;
- }
}
- for (Optional<PetStable::PetInfo> const& stabledSlot : petStable->StabledPets)
+ for (uint32 petSlot = 0; petSlot < petStable->StabledPets.size(); ++petSlot)
{
- if (stabledSlot)
- {
- PetStable::PetInfo const& pet = *stabledSlot;
- WorldPackets::Pet::PetStableInfo& stableEntry = packet.Pets.emplace_back();
- stableEntry.PetSlot = petSlot;
- stableEntry.PetNumber = pet.PetNumber;
- stableEntry.CreatureID = pet.CreatureId;
- stableEntry.DisplayID = pet.DisplayId;
- stableEntry.ExperienceLevel = pet.Level;
- stableEntry.PetFlags = PET_STABLE_INACTIVE;
- stableEntry.PetName = pet.Name;
- ++petSlot;
- }
+ if (!petStable->StabledPets[petSlot])
+ continue;
+
+ PetStable::PetInfo const& pet = *petStable->StabledPets[petSlot];
+ WorldPackets::Pet::PetStableInfo& stableEntry = packet.Pets.emplace_back();
+ stableEntry.PetSlot = petSlot + PET_SAVE_FIRST_STABLE_SLOT;
+ stableEntry.PetNumber = pet.PetNumber;
+ stableEntry.CreatureID = pet.CreatureId;
+ stableEntry.DisplayID = pet.DisplayId;
+ stableEntry.ExperienceLevel = pet.Level;
+ stableEntry.PetFlags = PET_STABLE_INACTIVE;
+ stableEntry.PetName = pet.Name;
}
SendPacket(packet.Write());
@@ -430,291 +412,150 @@ void WorldSession::SendPetStableResult(StableResult result)
SendPacket(petStableResult.Write());
}
-void WorldSession::HandleStablePet(WorldPacket& recvData)
+void WorldSession::HandleSetPetSlot(WorldPackets::NPC::SetPetSlot& setPetSlot)
{
- ObjectGuid npcGUID;
-
- recvData >> npcGUID;
-
- if (!GetPlayer()->IsAlive())
+ if (!CheckStableMaster(setPetSlot.StableMaster) || setPetSlot.DestSlot >= PET_SAVE_LAST_STABLE_SLOT)
{
SendPetStableResult(StableResult::InternalError);
return;
}
- if (!CheckStableMaster(npcGUID))
- {
- SendPetStableResult(StableResult::InternalError);
- return;
- }
-
- // remove fake death
- if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
- GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
+ GetPlayer()->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Interacting);
PetStable* petStable = GetPlayer()->GetPetStable();
if (!petStable)
- return;
-
- Pet* pet = _player->GetPet();
-
- // can't place in stable dead pet
- if ((pet && (!pet->IsAlive() || pet->getPetType() != HUNTER_PET))
- || (!pet && (petStable->UnslottedPets.size() != 1 || !petStable->UnslottedPets[0].Health || petStable->UnslottedPets[0].Type != HUNTER_PET)))
{
SendPetStableResult(StableResult::InternalError);
return;
}
- for (uint32 freeSlot = 0; freeSlot < petStable->StabledPets.size(); ++freeSlot)
- {
- if (!petStable->StabledPets[freeSlot])
- {
- if (pet)
- {
- // stable summoned pet
- _player->RemovePet(pet, PetSaveMode(PET_SAVE_FIRST_STABLE_SLOT + freeSlot));
- std::swap(petStable->StabledPets[freeSlot], petStable->CurrentPet);
- SendPetStableResult(StableResult::StableSuccess);
- return;
- }
+ auto [srcPet, srcPetSlot] = Pet::GetLoadPetInfo(*petStable, 0, setPetSlot.PetNumber, {});
+ PetSaveMode dstPetSlot = PetSaveMode(setPetSlot.DestSlot);
+ PetStable::PetInfo const* dstPet = Pet::GetLoadPetInfo(*petStable, 0, 0, dstPetSlot).first;
- CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_PET_SLOT_BY_ID);
- stmt->setUInt8(0, PetSaveMode(PET_SAVE_FIRST_STABLE_SLOT + freeSlot));
- stmt->setUInt64(1, _player->GetGUID().GetCounter());
- stmt->setUInt32(2, petStable->UnslottedPets[0].PetNumber);
- CharacterDatabase.Execute(stmt);
-
- // stable unsummoned pet
- petStable->StabledPets[freeSlot] = std::move(petStable->UnslottedPets.back());
- petStable->UnslottedPets.pop_back();
- SendPetStableResult(StableResult::StableSuccess);
- return;
- }
- }
-
- // not free stable slot
- SendPetStableResult(StableResult::InvalidSlot);
-}
-
-void WorldSession::HandleUnstablePet(WorldPacket& recvData)
-{
- ObjectGuid npcGUID;
- uint32 petnumber;
-
- recvData >> npcGUID >> petnumber;
-
- if (!CheckStableMaster(npcGUID))
+ if (!srcPet || srcPet->Type != HUNTER_PET)
{
SendPetStableResult(StableResult::InternalError);
return;
}
- // remove fake death
- if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
- GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
-
- PetStable* petStable = GetPlayer()->GetPetStable();
- if (!petStable)
+ if (dstPet && dstPet->Type != HUNTER_PET)
{
SendPetStableResult(StableResult::InternalError);
return;
}
- auto stabledPet = std::find_if(petStable->StabledPets.begin(), petStable->StabledPets.end(), [petnumber](Optional<PetStable::PetInfo> const& pet)
- {
- return pet && pet->PetNumber == petnumber;
- });
+ Optional<PetStable::PetInfo>* src = nullptr;
+ Optional<PetStable::PetInfo>* dst = nullptr;
+ Optional<int16> newActivePetIndex;
- if (stabledPet == petStable->StabledPets.end())
+ if (IsActivePetSlot(srcPetSlot) && IsActivePetSlot(dstPetSlot))
{
- SendPetStableResult(StableResult::InternalError);
- return;
- }
+ // active<->active: only swap ActivePets and CurrentPetIndex (do not despawn pets)
+ src = &petStable->ActivePets[srcPetSlot - PET_SAVE_FIRST_ACTIVE_SLOT];
+ dst = &petStable->ActivePets[dstPetSlot - PET_SAVE_FIRST_ACTIVE_SLOT];
- CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate((*stabledPet)->CreatureId);
- if (!creatureInfo || !creatureInfo->IsTameable(_player->CanTameExoticPets()))
+ if (petStable->GetCurrentActivePetIndex() == srcPetSlot)
+ newActivePetIndex = dstPetSlot;
+ else if (petStable->GetCurrentActivePetIndex() == dstPetSlot)
+ newActivePetIndex = srcPetSlot;
+ }
+ else if (IsStabledPetSlot(srcPetSlot) && IsStabledPetSlot(dstPetSlot))
{
- // if problem in exotic pet
- if (creatureInfo && creatureInfo->IsTameable(true))
- SendPetStableResult(StableResult::CantControlExotic);
- else
- SendPetStableResult(StableResult::InternalError);
- return;
+ // stabled<->stabled: only swap StabledPets
+ src = &petStable->StabledPets[srcPetSlot - PET_SAVE_FIRST_STABLE_SLOT];
+ dst = &petStable->StabledPets[dstPetSlot - PET_SAVE_FIRST_STABLE_SLOT];
}
-
- Pet* oldPet = _player->GetPet();
- if (oldPet)
+ else if (IsActivePetSlot(srcPetSlot) && IsStabledPetSlot(dstPetSlot))
{
- // try performing a swap, client sends this packet instead of swap when starting from stabled slot
- if (!oldPet->IsAlive() || !oldPet->IsHunterPet())
+ // active<->stabled: swap petStable contents and despawn active pet if it is involved in swap
+ if (petStable->CurrentPetIndex == srcPetSlot)
{
- SendPetStableResult(StableResult::InternalError);
- return;
+ Pet* oldPet = _player->GetPet();
+ if (oldPet && !oldPet->IsAlive())
+ {
+ SendPetStableResult(StableResult::InternalError);
+ return;
+ }
+
+ _player->RemovePet(oldPet, PET_SAVE_NOT_IN_SLOT);
}
- _player->RemovePet(oldPet, PetSaveMode(PET_SAVE_FIRST_STABLE_SLOT + std::distance(petStable->StabledPets.begin(), stabledPet)));
- }
- else if (petStable->UnslottedPets.size() == 1)
- {
- if (petStable->CurrentPet || !petStable->UnslottedPets[0].Health || petStable->UnslottedPets[0].Type != HUNTER_PET)
+ if (dstPet)
{
- SendPetStableResult(StableResult::InternalError);
- return;
+ CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(dstPet->CreatureId);
+ if (!creatureInfo || !creatureInfo->IsTameable(_player->CanTameExoticPets()))
+ {
+ SendPetStableResult(StableResult::CantControlExotic);
+ return;
+ }
}
- CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_PET_SLOT_BY_ID);
- stmt->setUInt8(0, PetSaveMode(PET_SAVE_FIRST_STABLE_SLOT + std::distance(petStable->StabledPets.begin(), stabledPet)));
- stmt->setUInt64(1, _player->GetGUID().GetCounter());
- stmt->setUInt32(2, petStable->UnslottedPets[0].PetNumber);
- CharacterDatabase.Execute(stmt);
-
- // move unsummoned pet into CurrentPet slot so that it gets moved into stable slot later
- petStable->CurrentPet = std::move(petStable->UnslottedPets.back());
- petStable->UnslottedPets.pop_back();
- }
- else if (petStable->CurrentPet || !petStable->UnslottedPets.empty())
- {
- SendPetStableResult(StableResult::InternalError);
- return;
- }
-
- Pet* newPet = new Pet(_player, HUNTER_PET);
- if (!newPet->LoadPetFromDB(_player, 0, petnumber, false))
- {
- delete newPet;
-
- petStable->UnslottedPets.push_back(std::move(*petStable->CurrentPet));
- petStable->CurrentPet.reset();
-
- // update current pet slot in db immediately to maintain slot consistency, dismissed pet was already saved
- CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_PET_SLOT_BY_ID);
- stmt->setUInt8(0, PET_SAVE_NOT_IN_SLOT);
- stmt->setUInt64(1, _player->GetGUID().GetCounter());
- stmt->setUInt32(2, petnumber);
- CharacterDatabase.Execute(stmt);
-
- SendPetStableResult(StableResult::InternalError);
- }
- else
- {
- // update current pet slot in db immediately to maintain slot consistency, dismissed pet was already saved
- CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_PET_SLOT_BY_ID);
- stmt->setUInt8(0, PET_SAVE_AS_CURRENT);
- stmt->setUInt64(1, _player->GetGUID().GetCounter());
- stmt->setUInt32(2, petnumber);
- CharacterDatabase.Execute(stmt);
-
- SendPetStableResult(StableResult::UnstableSuccess);
+ src = &petStable->ActivePets[srcPetSlot - PET_SAVE_FIRST_ACTIVE_SLOT];
+ dst = &petStable->StabledPets[dstPetSlot - PET_SAVE_FIRST_STABLE_SLOT];
}
-}
-
-void WorldSession::HandleStableSwapPet(WorldPacket& recvData)
-{
- ObjectGuid npcGUID;
- uint32 petId;
-
- recvData >> npcGUID >> petId;
-
- if (!CheckStableMaster(npcGUID))
+ else if (IsStabledPetSlot(srcPetSlot) && IsActivePetSlot(dstPetSlot))
{
- SendPetStableResult(StableResult::InternalError);
- return;
- }
-
- // remove fake death
- if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
- GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
-
- PetStable* petStable = GetPlayer()->GetPetStable();
- if (!petStable)
- {
- SendPetStableResult(StableResult::InternalError);
- return;
- }
-
- // Find swapped pet slot in stable
- auto stabledPet = std::find_if(petStable->StabledPets.begin(), petStable->StabledPets.end(), [petId](Optional<PetStable::PetInfo> const& pet)
- {
- return pet && pet->PetNumber == petId;
- });
-
- if (stabledPet == petStable->StabledPets.end())
- {
- SendPetStableResult(StableResult::InternalError);
- return;
- }
-
- CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate((*stabledPet)->CreatureId);
- if (!creatureInfo || !creatureInfo->IsTameable(true))
- {
- SendPetStableResult(StableResult::InternalError);
- return;
- }
-
- Pet* oldPet = _player->GetPet();
- if (oldPet)
- {
- if (!oldPet->IsAlive() || !oldPet->IsHunterPet())
+ // stabled<->active: swap petStable contents and despawn active pet if it is involved in swap
+ if (petStable->CurrentPetIndex == dstPetSlot)
{
- SendPetStableResult(StableResult::InternalError);
- return;
+ Pet* oldPet = _player->GetPet();
+ if (oldPet && !oldPet->IsAlive())
+ {
+ SendPetStableResult(StableResult::InternalError);
+ return;
+ }
+
+ _player->RemovePet(oldPet, PET_SAVE_NOT_IN_SLOT);
}
- _player->RemovePet(oldPet, PetSaveMode(PET_SAVE_FIRST_STABLE_SLOT + std::distance(petStable->StabledPets.begin(), stabledPet)));
- }
- else if (petStable->UnslottedPets.size() == 1)
- {
- if (petStable->CurrentPet || !petStable->UnslottedPets[0].Health || petStable->UnslottedPets[0].Type != HUNTER_PET)
+ CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(srcPet->CreatureId);
+ if (!creatureInfo || !creatureInfo->IsTameable(_player->CanTameExoticPets()))
{
- SendPetStableResult(StableResult::InternalError);
+ SendPetStableResult(StableResult::CantControlExotic);
return;
}
- CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_PET_SLOT_BY_ID);
- stmt->setUInt8(0, PetSaveMode(PET_SAVE_FIRST_STABLE_SLOT + std::distance(petStable->StabledPets.begin(), stabledPet)));
- stmt->setUInt64(1, _player->GetGUID().GetCounter());
- stmt->setUInt32(2, petStable->UnslottedPets[0].PetNumber);
- CharacterDatabase.Execute(stmt);
-
- // move unsummoned pet into CurrentPet slot so that it gets moved into stable slot later
- petStable->CurrentPet = std::move(petStable->UnslottedPets.back());
- petStable->UnslottedPets.pop_back();
- }
- else if (petStable->CurrentPet || !petStable->UnslottedPets.empty())
- {
- SendPetStableResult(StableResult::InternalError);
- return;
+ src = &petStable->StabledPets[srcPetSlot - PET_SAVE_FIRST_STABLE_SLOT];
+ dst = &petStable->ActivePets[dstPetSlot - PET_SAVE_FIRST_ACTIVE_SLOT];
}
- // summon unstabled pet
- Pet* newPet = new Pet(_player, HUNTER_PET);
- if (!newPet->LoadPetFromDB(_player, 0, petId, false))
- {
- delete newPet;
- SendPetStableResult(StableResult::InternalError);
+ CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
- petStable->UnslottedPets.push_back(std::move(*petStable->CurrentPet));
- petStable->CurrentPet.reset();
+ CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_PET_SLOT_BY_ID);
+ stmt->setInt16(0, dstPetSlot);
+ stmt->setUInt64(1, _player->GetGUID().GetCounter());
+ stmt->setUInt32(2, srcPet->PetNumber);
+ trans->Append(stmt);
- // update current pet slot in db immediately to maintain slot consistency, dismissed pet was already saved
- CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_PET_SLOT_BY_ID);
- stmt->setUInt8(0, PET_SAVE_NOT_IN_SLOT);
+ if (dstPet)
+ {
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_PET_SLOT_BY_ID);
+ stmt->setInt16(0, srcPetSlot);
stmt->setUInt64(1, _player->GetGUID().GetCounter());
- stmt->setUInt32(2, petId);
- CharacterDatabase.Execute(stmt);
+ stmt->setUInt32(2, dstPet->PetNumber);
+ trans->Append(stmt);
}
- else
+
+ AddTransactionCallback(CharacterDatabase.AsyncCommitTransaction(trans)).AfterComplete(
+ [this, currentPlayerGuid = _player->GetGUID(), src, dst, newActivePetIndex](bool success)
{
- // update current pet slot in db immediately to maintain slot consistency, dismissed pet was already saved
- CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_PET_SLOT_BY_ID);
- stmt->setUInt8(0, PET_SAVE_AS_CURRENT);
- stmt->setUInt64(1, _player->GetGUID().GetCounter());
- stmt->setUInt32(2, petId);
- CharacterDatabase.Execute(stmt);
+ if (_player && _player->GetGUID() == currentPlayerGuid)
+ {
+ if (success)
+ {
+ std::swap(*src, *dst);
+ if (newActivePetIndex)
+ GetPlayer()->GetPetStable()->SetCurrentActivePetIndex(*newActivePetIndex);
- SendPetStableResult(StableResult::UnstableSuccess);
- }
+ SendPetStableResult(StableResult::StableSuccess);
+ }
+ else
+ {
+ SendPetStableResult(StableResult::InternalError);
+ }
+ }
+ });
}
void WorldSession::HandleRepairItemOpcode(WorldPackets::Item::RepairItem& packet)