mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-29 16:43:47 +00:00
feat(Core/Pets): Management refactoring (#9712)
* feat(Core/Pets): rework managment * 1 * 2 * 3 * 4 * 5 * cs pet * check before ressurect * pet DECLINED_NAMES * display - https://github.com/azerothcore/azerothcore-wotlk/issues/9297 * ArenaSpectator * 1
This commit is contained in:
@@ -202,13 +202,17 @@ bool LoginQueryHolder::Initialize()
|
||||
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_INSTANCE_LOCK_TIMES, stmt);
|
||||
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CORPSE_LOCATION);
|
||||
stmt->setUInt64(0, lowGuid);
|
||||
stmt->setUInt32(0, lowGuid);
|
||||
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_CORPSE_LOCATION, stmt);
|
||||
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_SETTINGS);
|
||||
stmt->setUInt64(0, lowGuid);
|
||||
stmt->setUInt32(0, lowGuid);
|
||||
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_CHARACTER_SETTINGS, stmt);
|
||||
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_PETS);
|
||||
stmt->setUInt32(0, lowGuid);
|
||||
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_PET_SLOTS, stmt);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
@@ -488,74 +488,61 @@ void WorldSession::HandleListStabledPetsOpcode(WorldPacket& recvData)
|
||||
|
||||
void WorldSession::SendStablePet(ObjectGuid guid)
|
||||
{
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PET_SLOTS_DETAIL);
|
||||
|
||||
stmt->setUInt32(0, _player->GetGUID().GetCounter());
|
||||
stmt->setUInt8(1, PET_SAVE_FIRST_STABLE_SLOT);
|
||||
stmt->setUInt8(2, PET_SAVE_LAST_STABLE_SLOT);
|
||||
|
||||
_queryProcessor.AddCallback(CharacterDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSession::SendStablePetCallback, this, guid, std::placeholders::_1)));
|
||||
}
|
||||
|
||||
void WorldSession::SendStablePetCallback(ObjectGuid guid, PreparedQueryResult result)
|
||||
{
|
||||
if (!GetPlayer())
|
||||
return;
|
||||
|
||||
LOG_DEBUG("network", "WORLD: Recv MSG_LIST_STABLED_PETS Send.");
|
||||
|
||||
WorldPacket data(MSG_LIST_STABLED_PETS, 200); // guess size
|
||||
data << guid;
|
||||
size_t wpos = data.wpos();
|
||||
data << uint8(0); // place holder for slot show number
|
||||
data << uint8(GetPlayer()->m_stableSlots);
|
||||
|
||||
Pet* pet = _player->GetPet();
|
||||
PetStable* petStable = GetPlayer()->GetPetStable();
|
||||
if (!petStable)
|
||||
{
|
||||
data << uint8(0); // stable slots
|
||||
SendPacket(&data);
|
||||
return;
|
||||
}
|
||||
|
||||
data << uint8(petStable->MaxStabledPets);
|
||||
|
||||
uint8 num = 0; // counter for place holder
|
||||
|
||||
// not let move dead pet in slot
|
||||
if (pet && pet->IsAlive() && pet->getPetType() == HUNTER_PET)
|
||||
if (petStable->CurrentPet)
|
||||
{
|
||||
data << uint32(pet->GetCharmInfo()->GetPetNumber());
|
||||
data << uint32(pet->GetEntry());
|
||||
data << uint32(pet->getLevel());
|
||||
data << pet->GetName(); // petname
|
||||
data << uint8(1); // 1 = current, 2/3 = in stable (any from 4, 5, ... create problems with proper show)
|
||||
PetStable::PetInfo const& pet = *petStable->CurrentPet;
|
||||
data << uint32(pet.PetNumber);
|
||||
data << uint32(pet.CreatureId);
|
||||
data << uint32(pet.Level);
|
||||
data << pet.Name; // petname
|
||||
data << uint8(1); // flags: 1 active, 2 inactive
|
||||
++num;
|
||||
}
|
||||
else if (_player->IsPetDismissed() || _player->GetTemporaryUnsummonedPetNumber())
|
||||
else
|
||||
{
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_PET_BY_ENTRY_AND_SLOT_SYNS);
|
||||
stmt->setUInt32(0, _player->GetGUID().GetCounter());
|
||||
stmt->setUInt8(1, uint8(_player->GetTemporaryUnsummonedPetNumber() ? PET_SAVE_AS_CURRENT : PET_SAVE_NOT_IN_SLOT));
|
||||
|
||||
if (PreparedQueryResult _result = CharacterDatabase.Query(stmt))
|
||||
if (PetStable::PetInfo const* pet = petStable->GetUnslottedHunterPet())
|
||||
{
|
||||
Field* fields = _result->Fetch();
|
||||
|
||||
data << uint32(fields[0].GetUInt32()); // id
|
||||
data << uint32(fields[1].GetUInt32()); // entry
|
||||
data << uint32(fields[4].GetUInt16()); // level
|
||||
data << fields[8].GetString(); // petname
|
||||
data << uint8(1);
|
||||
data << uint32(pet->PetNumber);
|
||||
data << uint32(pet->CreatureId);
|
||||
data << uint32(pet->Level);
|
||||
data << pet->Name; // petname
|
||||
data << uint8(1); // flags: 1 active, 2 inactive
|
||||
++num;
|
||||
}
|
||||
}
|
||||
|
||||
if (result)
|
||||
for (Optional<PetStable::PetInfo> const& stabledSlot : petStable->StabledPets)
|
||||
{
|
||||
do
|
||||
if (stabledSlot)
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
data << uint32(fields[1].GetUInt32()); // petnumber
|
||||
data << uint32(fields[2].GetUInt32()); // creature entry
|
||||
data << uint32(fields[3].GetUInt16()); // level
|
||||
data << fields[4].GetString(); // name
|
||||
data << uint8(2); // 1 = current, 2/3 = in stable (any from 4, 5, ... create problems with proper show)
|
||||
|
||||
PetStable::PetInfo const& pet = *stabledSlot;
|
||||
data << uint32(pet.PetNumber);
|
||||
data << uint32(pet.CreatureId);
|
||||
data << uint32(pet.Level);
|
||||
data << pet.Name; // petname
|
||||
data << uint8(2); // flags: 1 active, 2 inactive
|
||||
++num;
|
||||
} while (result->NextRow());
|
||||
}
|
||||
}
|
||||
|
||||
data.put<uint8>(wpos, num); // set real data to placeholder
|
||||
@@ -592,81 +579,49 @@ void WorldSession::HandleStablePet(WorldPacket& recvData)
|
||||
if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
|
||||
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
|
||||
|
||||
PetStable* petStable = GetPlayer()->GetPetStable();
|
||||
if (!petStable)
|
||||
return;
|
||||
|
||||
Pet* pet = _player->GetPet();
|
||||
|
||||
// can't place in stable dead pet
|
||||
if (pet)
|
||||
if ((pet && (!pet->IsAlive() || pet->getPetType() != HUNTER_PET))
|
||||
|| (!pet && (petStable->UnslottedPets.size() != 1 || !petStable->UnslottedPets[0].Health || petStable->UnslottedPets[0].Type != HUNTER_PET)))
|
||||
{
|
||||
if (!pet->IsAlive() || pet->getPetType() != HUNTER_PET)
|
||||
{
|
||||
SendStableResult(STABLE_ERR_STABLE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SpellCastResult loadResult = Pet::TryLoadFromDB(_player, _player->GetTemporaryUnsummonedPetNumber() != 0, HUNTER_PET);
|
||||
if (loadResult != SPELL_CAST_OK)
|
||||
{
|
||||
SendStableResult(STABLE_ERR_STABLE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PET_SLOTS);
|
||||
|
||||
stmt->setUInt32(0, _player->GetGUID().GetCounter());
|
||||
stmt->setUInt8(1, PET_SAVE_FIRST_STABLE_SLOT);
|
||||
stmt->setUInt8(2, PET_SAVE_LAST_STABLE_SLOT);
|
||||
|
||||
_queryProcessor.AddCallback(CharacterDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSession::HandleStablePetCallback, this, std::placeholders::_1)));
|
||||
}
|
||||
|
||||
void WorldSession::HandleStablePetCallback(PreparedQueryResult result)
|
||||
{
|
||||
if (!GetPlayer())
|
||||
SendStableResult(STABLE_ERR_STABLE);
|
||||
return;
|
||||
|
||||
uint8 freeSlot = 1;
|
||||
if (result)
|
||||
{
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
uint8 slot = fields[1].GetUInt8();
|
||||
|
||||
// slots ordered in query, and if not equal then free
|
||||
if (slot != freeSlot)
|
||||
break;
|
||||
|
||||
// this slot not free, skip
|
||||
++freeSlot;
|
||||
} while (result->NextRow());
|
||||
}
|
||||
|
||||
WorldPacket data(SMSG_STABLE_RESULT, 1);
|
||||
if (freeSlot > 0 && freeSlot <= GetPlayer()->m_stableSlots)
|
||||
for (uint32 freeSlot = 0; freeSlot < petStable->MaxStabledPets; ++freeSlot)
|
||||
{
|
||||
if (_player->GetPetGUID())
|
||||
if (!petStable->StabledPets[freeSlot])
|
||||
{
|
||||
_player->RemovePet(_player->GetPet(), PetSaveMode(freeSlot));
|
||||
if (pet)
|
||||
{
|
||||
// stable summoned pet
|
||||
_player->RemovePet(pet, PetSaveMode(PET_SAVE_FIRST_STABLE_SLOT + freeSlot));
|
||||
std::swap(petStable->StabledPets[freeSlot], petStable->CurrentPet);
|
||||
SendStableResult(STABLE_SUCCESS_STABLE);
|
||||
return;
|
||||
}
|
||||
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_PET_SLOT_BY_ID);
|
||||
stmt->setUInt8(0, PetSaveMode(PET_SAVE_FIRST_STABLE_SLOT + freeSlot));
|
||||
stmt->setUInt32(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();
|
||||
SendStableResult(STABLE_SUCCESS_STABLE);
|
||||
return;
|
||||
}
|
||||
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UDP_CHAR_PET_SLOT_BY_SLOT);
|
||||
stmt->setUInt8(0, freeSlot);
|
||||
stmt->setUInt32(1, _player->GetGUID().GetCounter());
|
||||
stmt->setUInt8(2, uint8(_player->GetTemporaryUnsummonedPetNumber() ? PET_SAVE_AS_CURRENT : PET_SAVE_NOT_IN_SLOT));
|
||||
CharacterDatabase.Execute(stmt);
|
||||
|
||||
_player->SetTemporaryUnsummonedPetNumber(0);
|
||||
SendStableResult(STABLE_SUCCESS_STABLE);
|
||||
return;
|
||||
}
|
||||
else
|
||||
SendStableResult(STABLE_ERR_STABLE);
|
||||
|
||||
// not free stable slot
|
||||
SendStableResult(STABLE_ERR_STABLE);
|
||||
}
|
||||
|
||||
void WorldSession::HandleUnstablePet(WorldPacket& recvData)
|
||||
@@ -687,37 +642,25 @@ void WorldSession::HandleUnstablePet(WorldPacket& recvData)
|
||||
if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
|
||||
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
|
||||
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PET_ENTRY);
|
||||
|
||||
stmt->setUInt32(0, _player->GetGUID().GetCounter());
|
||||
stmt->setUInt32(1, petnumber);
|
||||
stmt->setUInt8(2, PET_SAVE_FIRST_STABLE_SLOT);
|
||||
stmt->setUInt8(3, PET_SAVE_LAST_STABLE_SLOT);
|
||||
|
||||
_queryProcessor.AddCallback(CharacterDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSession::HandleUnstablePetCallback, this, petnumber, std::placeholders::_1)));
|
||||
}
|
||||
|
||||
void WorldSession::HandleUnstablePetCallback(uint32 petId, PreparedQueryResult result)
|
||||
{
|
||||
if (!GetPlayer())
|
||||
return;
|
||||
|
||||
uint32 petEntry = 0;
|
||||
uint32 slot = 0;
|
||||
if (result)
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
petEntry = fields[0].GetUInt32();
|
||||
slot = fields[1].GetUInt32();
|
||||
}
|
||||
|
||||
if (!petEntry)
|
||||
PetStable* petStable = GetPlayer()->GetPetStable();
|
||||
if (!petStable)
|
||||
{
|
||||
SendStableResult(STABLE_ERR_STABLE);
|
||||
return;
|
||||
}
|
||||
|
||||
CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(petEntry);
|
||||
auto stabledPet = std::find_if(petStable->StabledPets.begin(), petStable->StabledPets.end(), [petnumber](Optional<PetStable::PetInfo> const& pet)
|
||||
{
|
||||
return pet && pet->PetNumber == petnumber;
|
||||
});
|
||||
|
||||
if (stabledPet == petStable->StabledPets.end())
|
||||
{
|
||||
SendStableResult(STABLE_ERR_STABLE);
|
||||
return;
|
||||
}
|
||||
|
||||
CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate((*stabledPet)->CreatureId);
|
||||
if (!creatureInfo || !creatureInfo->IsTameable(_player->CanTameExoticPets()))
|
||||
{
|
||||
// if problem in exotic pet
|
||||
@@ -725,45 +668,74 @@ void WorldSession::HandleUnstablePetCallback(uint32 petId, PreparedQueryResult r
|
||||
SendStableResult(STABLE_ERR_EXOTIC);
|
||||
else
|
||||
SendStableResult(STABLE_ERR_STABLE);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Pet* pet = _player->GetPet();
|
||||
if (pet && pet->IsAlive())
|
||||
Pet* oldPet = _player->GetPet();
|
||||
if (oldPet)
|
||||
{
|
||||
SendStableResult(STABLE_ERR_STABLE);
|
||||
return;
|
||||
}
|
||||
|
||||
// delete dead pet
|
||||
if (pet)
|
||||
{
|
||||
_player->RemovePet(pet, PET_SAVE_AS_DELETED);
|
||||
}
|
||||
else if (_player->IsPetDismissed() || _player->GetTemporaryUnsummonedPetNumber())
|
||||
{
|
||||
// try to find if pet is actually temporary unsummoned and alive
|
||||
SpellCastResult loadResult = Pet::TryLoadFromDB(_player, _player->GetTemporaryUnsummonedPetNumber() != 0, HUNTER_PET);
|
||||
if (loadResult != SPELL_CAST_OK)
|
||||
// try performing a swap, client sends this packet instead of swap when starting from stabled slot
|
||||
if (!oldPet->IsAlive() || !oldPet->IsHunterPet())
|
||||
{
|
||||
SendStableResult(STABLE_ERR_STABLE);
|
||||
return;
|
||||
}
|
||||
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UDP_CHAR_PET_SLOT_BY_SLOT);
|
||||
stmt->setUInt8(0, 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)
|
||||
{
|
||||
SendStableResult(STABLE_ERR_STABLE);
|
||||
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->setUInt32(1, _player->GetGUID().GetCounter());
|
||||
stmt->setUInt8(2, uint8(_player->GetTemporaryUnsummonedPetNumber() ? PET_SAVE_AS_CURRENT : PET_SAVE_NOT_IN_SLOT));
|
||||
stmt->setUInt32(2, petStable->UnslottedPets[0].PetNumber);
|
||||
CharacterDatabase.Execute(stmt);
|
||||
|
||||
_player->SetTemporaryUnsummonedPetNumber(0);
|
||||
// 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();
|
||||
}
|
||||
|
||||
if (!Pet::LoadPetFromDB(_player, PET_LOAD_HANDLE_UNSTABLE_CALLBACK, petEntry, petId))
|
||||
else if (petStable->CurrentPet || !petStable->UnslottedPets.empty())
|
||||
{
|
||||
SendStableResult(STABLE_ERR_STABLE);
|
||||
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->setUInt32(1, _player->GetGUID().GetCounter());
|
||||
stmt->setUInt32(2, petnumber);
|
||||
CharacterDatabase.Execute(stmt);
|
||||
|
||||
SendStableResult(STABLE_ERR_STABLE);
|
||||
}
|
||||
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->setUInt32(1, _player->GetGUID().GetCounter());
|
||||
stmt->setUInt32(2, petnumber);
|
||||
CharacterDatabase.Execute(stmt);
|
||||
|
||||
SendStableResult(STABLE_SUCCESS_UNSTABLE);
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandleBuyStableSlot(WorldPacket& recvData)
|
||||
@@ -783,12 +755,13 @@ void WorldSession::HandleBuyStableSlot(WorldPacket& recvData)
|
||||
if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
|
||||
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
|
||||
|
||||
if (GetPlayer()->m_stableSlots < MAX_PET_STABLES)
|
||||
PetStable& petStable = GetPlayer()->GetOrInitPetStable();
|
||||
if (petStable.MaxStabledPets < MAX_PET_STABLES)
|
||||
{
|
||||
StableSlotPricesEntry const* SlotPrice = sStableSlotPricesStore.LookupEntry(GetPlayer()->m_stableSlots + 1);
|
||||
StableSlotPricesEntry const* SlotPrice = sStableSlotPricesStore.LookupEntry(petStable.MaxStabledPets + 1);
|
||||
if (_player->HasEnoughMoney(SlotPrice->Price))
|
||||
{
|
||||
++GetPlayer()->m_stableSlots;
|
||||
++petStable.MaxStabledPets;
|
||||
_player->ModifyMoney(-int32(SlotPrice->Price));
|
||||
SendStableResult(STABLE_SUCCESS_BUY_SLOT);
|
||||
}
|
||||
@@ -822,58 +795,26 @@ void WorldSession::HandleStableSwapPet(WorldPacket& recvData)
|
||||
if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
|
||||
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
|
||||
|
||||
Pet* pet = _player->GetPet();
|
||||
|
||||
if (pet)
|
||||
PetStable* petStable = GetPlayer()->GetPetStable();
|
||||
if (!petStable)
|
||||
{
|
||||
if (pet->getPetType() != HUNTER_PET)
|
||||
{
|
||||
SendStableResult(STABLE_ERR_STABLE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (_player->IsPetDismissed() || _player->GetTemporaryUnsummonedPetNumber())
|
||||
{
|
||||
// try to find if pet is actually temporary unsummoned and alive
|
||||
SpellCastResult loadResult = Pet::TryLoadFromDB(_player, _player->GetTemporaryUnsummonedPetNumber() != 0, HUNTER_PET);
|
||||
if (loadResult != SPELL_CAST_OK)
|
||||
{
|
||||
SendStableResult(STABLE_ERR_STABLE);
|
||||
return;
|
||||
}
|
||||
SendStableResult(STABLE_ERR_STABLE);
|
||||
return;
|
||||
}
|
||||
|
||||
// Find swapped pet slot in stable
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PET_SLOT_BY_ID);
|
||||
auto stabledPet = std::find_if(petStable->StabledPets.begin(), petStable->StabledPets.end(), [petId](Optional<PetStable::PetInfo> const& pet)
|
||||
{
|
||||
return pet && pet->PetNumber == petId;
|
||||
});
|
||||
|
||||
stmt->setUInt32(0, _player->GetGUID().GetCounter());
|
||||
stmt->setUInt32(1, petId);
|
||||
|
||||
_queryProcessor.AddCallback(CharacterDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSession::HandleStableSwapPetCallback, this, petId, std::placeholders::_1)));
|
||||
}
|
||||
|
||||
void WorldSession::HandleStableSwapPetCallback(uint32 petId, PreparedQueryResult result)
|
||||
{
|
||||
if (!GetPlayer())
|
||||
return;
|
||||
|
||||
if (!result)
|
||||
if (stabledPet == petStable->StabledPets.end())
|
||||
{
|
||||
SendStableResult(STABLE_ERR_STABLE);
|
||||
return;
|
||||
}
|
||||
|
||||
Field* fields = result->Fetch();
|
||||
uint32 slot = fields[0].GetUInt8();
|
||||
uint32 petEntry = fields[1].GetUInt32();
|
||||
|
||||
if (!petEntry)
|
||||
{
|
||||
SendStableResult(STABLE_ERR_STABLE);
|
||||
return;
|
||||
}
|
||||
|
||||
CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(petEntry);
|
||||
CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate((*stabledPet)->CreatureId);
|
||||
if (!creatureInfo || !creatureInfo->IsTameable(_player->CanTameExoticPets()))
|
||||
{
|
||||
// if problem in exotic pet
|
||||
@@ -884,29 +825,69 @@ void WorldSession::HandleStableSwapPetCallback(uint32 petId, PreparedQueryResult
|
||||
return;
|
||||
}
|
||||
|
||||
Pet* pet = _player->GetPet();
|
||||
|
||||
// move alive pet to slot or delete dead pet
|
||||
if (pet)
|
||||
_player->RemovePet(pet, pet->IsAlive() ? PetSaveMode(slot) : PET_SAVE_AS_DELETED);
|
||||
else if (_player->IsPetDismissed() || _player->GetTemporaryUnsummonedPetNumber())
|
||||
Pet* oldPet = _player->GetPet();
|
||||
if (oldPet)
|
||||
{
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UDP_CHAR_PET_SLOT_BY_SLOT);
|
||||
stmt->setUInt8(0, slot);
|
||||
if (!oldPet->IsAlive() || !oldPet->IsHunterPet())
|
||||
{
|
||||
SendStableResult(STABLE_ERR_STABLE);
|
||||
return;
|
||||
}
|
||||
|
||||
_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)
|
||||
{
|
||||
SendStableResult(STABLE_ERR_STABLE);
|
||||
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->setUInt32(1, _player->GetGUID().GetCounter());
|
||||
stmt->setUInt8(2, uint8(_player->GetTemporaryUnsummonedPetNumber() ? PET_SAVE_AS_CURRENT : PET_SAVE_NOT_IN_SLOT));
|
||||
stmt->setUInt32(2, petStable->UnslottedPets[0].PetNumber);
|
||||
CharacterDatabase.Execute(stmt);
|
||||
|
||||
_player->SetTemporaryUnsummonedPetNumber(0);
|
||||
// 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())
|
||||
{
|
||||
SendStableResult(STABLE_ERR_STABLE);
|
||||
return;
|
||||
}
|
||||
|
||||
// summon unstabled pet
|
||||
if (!Pet::LoadPetFromDB(_player, PET_LOAD_HANDLE_UNSTABLE_CALLBACK, petEntry, petId))
|
||||
Pet* newPet = new Pet(_player, HUNTER_PET);
|
||||
if (!newPet->LoadPetFromDB(_player, 0, petId, false))
|
||||
{
|
||||
delete newPet;
|
||||
SendStableResult(STABLE_ERR_STABLE);
|
||||
|
||||
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->setUInt32(1, _player->GetGUID().GetCounter());
|
||||
stmt->setUInt32(2, petId);
|
||||
CharacterDatabase.Execute(stmt);
|
||||
}
|
||||
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->setUInt32(1, _player->GetGUID().GetCounter());
|
||||
stmt->setUInt32(2, petId);
|
||||
CharacterDatabase.Execute(stmt);
|
||||
|
||||
SendStableResult(STABLE_SUCCESS_UNSTABLE);
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandleRepairItemOpcode(WorldPacket& recvData)
|
||||
|
||||
@@ -35,355 +35,6 @@
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
|
||||
class LoadPetFromDBQueryHolder : public CharacterDatabaseQueryHolder
|
||||
{
|
||||
public:
|
||||
LoadPetFromDBQueryHolder(uint32 petNumber, bool current, uint32 diffTime, std::string&& actionBar, uint32 health, uint32 mana)
|
||||
: _petNumber(petNumber),
|
||||
_current(current),
|
||||
_diffTime(diffTime),
|
||||
_actionBar(std::move(actionBar)),
|
||||
_savedHealth(health),
|
||||
_savedMana(mana) { }
|
||||
|
||||
uint32 GetPetNumber() const { return _petNumber; }
|
||||
uint32 GetDiffTime() const { return _diffTime; }
|
||||
bool GetCurrent() const { return _current; }
|
||||
uint32 GetSavedHealth() const { return _savedHealth; }
|
||||
uint32 GetSavedMana() const { return _savedMana; }
|
||||
std::string GetActionBar() const { return _actionBar; }
|
||||
|
||||
bool Initialize();
|
||||
private:
|
||||
enum
|
||||
{
|
||||
AURAS,
|
||||
SPELLS,
|
||||
COOLDOWNS,
|
||||
|
||||
MAX
|
||||
};
|
||||
|
||||
const uint32 _petNumber;
|
||||
const bool _current;
|
||||
const uint32 _diffTime;
|
||||
const std::string _actionBar;
|
||||
const uint32 _savedHealth;
|
||||
const uint32 _savedMana;
|
||||
};
|
||||
|
||||
bool LoadPetFromDBQueryHolder::Initialize()
|
||||
{
|
||||
SetSize(MAX);
|
||||
|
||||
bool res = true;
|
||||
CharacterDatabasePreparedStatement* stmt = nullptr;
|
||||
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PET_AURA);
|
||||
stmt->setUInt32(0, _petNumber);
|
||||
res &= SetPreparedQuery(AURAS, stmt);
|
||||
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PET_SPELL);
|
||||
stmt->setUInt32(0, _petNumber);
|
||||
res &= SetPreparedQuery(SPELLS, stmt);
|
||||
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PET_SPELL_COOLDOWN);
|
||||
stmt->setUInt32(0, _petNumber);
|
||||
res &= SetPreparedQuery(COOLDOWNS, stmt);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
uint8 WorldSession::HandleLoadPetFromDBFirstCallback(PreparedQueryResult result, uint8 asynchLoadType, AsynchPetSummon* info)
|
||||
{
|
||||
if (!result)
|
||||
return PET_LOAD_NO_RESULT;
|
||||
|
||||
Player* owner = GetPlayer();
|
||||
if (!owner || owner->GetPet() || owner->GetVehicle() || owner->IsSpectator() || owner->IsBeingTeleportedFar())
|
||||
{
|
||||
return PET_LOAD_ERROR;
|
||||
}
|
||||
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
// Xinef: this can happen if fetch is called twice, impossibru.
|
||||
if (!fields)
|
||||
return PET_LOAD_ERROR;
|
||||
|
||||
// update for case of current pet "slot = 0"
|
||||
uint32 petentry = fields[1].GetUInt32();
|
||||
if (!petentry)
|
||||
return PET_LOAD_NO_RESULT;
|
||||
|
||||
uint8 petSlot = fields[7].GetUInt8();
|
||||
bool current = petSlot == PET_SAVE_AS_CURRENT;
|
||||
uint32 summon_spell_id = fields[15].GetUInt32();
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(summon_spell_id); // CANT BE nullptr
|
||||
bool is_temporary_summoned = spellInfo && spellInfo->GetDuration() > 0;
|
||||
uint32 pet_number = fields[0].GetUInt32();
|
||||
uint32 savedhealth = fields[10].GetUInt32();
|
||||
uint32 savedmana = fields[11].GetUInt32();
|
||||
PetType pet_type = PetType(fields[16].GetUInt8());
|
||||
|
||||
// xinef: BG resurrect, overwrite saved value
|
||||
if (asynchLoadType == PET_LOAD_BG_RESURRECT)
|
||||
savedhealth = 1;
|
||||
|
||||
if (pet_type == HUNTER_PET && savedhealth == 0 && asynchLoadType != PET_LOAD_SUMMON_DEAD_PET)
|
||||
{
|
||||
WorldPacket data(SMSG_CAST_FAILED, 1 + 4 + 1 + 4);
|
||||
data << uint8(0);
|
||||
data << uint32(883);
|
||||
data << uint8(SPELL_FAILED_TARGETS_DEAD);
|
||||
SendPacket(&data);
|
||||
owner->RemoveSpellCooldown(883, false);
|
||||
return PET_LOAD_ERROR;
|
||||
}
|
||||
|
||||
// check temporary summoned pets like mage water elemental
|
||||
if (current && is_temporary_summoned)
|
||||
return PET_LOAD_ERROR;
|
||||
|
||||
if (pet_type == HUNTER_PET)
|
||||
{
|
||||
CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(petentry);
|
||||
if (!creatureInfo || !creatureInfo->IsTameable(owner->CanTameExoticPets()))
|
||||
return PET_LOAD_ERROR;
|
||||
}
|
||||
|
||||
Map* map = owner->GetMap();
|
||||
ObjectGuid::LowType guid = map->GenerateLowGuid<HighGuid::Pet>();
|
||||
Pet* pet = new Pet(owner, pet_type);
|
||||
if (!pet->Create(guid, map, owner->GetPhaseMask(), petentry, pet_number))
|
||||
{
|
||||
delete pet;
|
||||
return PET_LOAD_ERROR;
|
||||
}
|
||||
|
||||
std::shared_ptr<LoadPetFromDBQueryHolder> holder = std::make_shared<LoadPetFromDBQueryHolder>(pet_number, current, uint32(time(nullptr) - fields[14].GetUInt32()), fields[13].GetString(), savedhealth, savedmana);
|
||||
if (!holder->Initialize())
|
||||
{
|
||||
delete pet;
|
||||
return PET_LOAD_ERROR;
|
||||
}
|
||||
|
||||
float px, py, pz;
|
||||
owner->GetClosePoint(px, py, pz, pet->GetObjectSize(), PET_FOLLOW_DIST, pet->GetFollowAngle());
|
||||
if (!pet->IsPositionValid())
|
||||
{
|
||||
LOG_ERROR("network.opcode", "Pet (%s, entry %d) not loaded. Suggested coordinates isn't valid (X: %f Y: %f)",
|
||||
pet->GetGUID().ToString().c_str(), pet->GetEntry(), pet->GetPositionX(), pet->GetPositionY());
|
||||
delete pet;
|
||||
return PET_LOAD_ERROR;
|
||||
}
|
||||
|
||||
pet->SetLoading(true);
|
||||
pet->Relocate(px, py, pz, owner->GetOrientation());
|
||||
pet->setPetType(pet_type);
|
||||
pet->SetFaction(owner->GetFaction());
|
||||
pet->SetUInt32Value(UNIT_CREATED_BY_SPELL, summon_spell_id);
|
||||
|
||||
if (pet->IsCritter())
|
||||
{
|
||||
pet->UpdatePositionData();
|
||||
map->AddToMap(pet->ToCreature(), true);
|
||||
pet->SetLoading(false); // xinef, mine
|
||||
return PET_LOAD_OK;
|
||||
}
|
||||
|
||||
if (pet->getPetType() == HUNTER_PET || pet->GetCreatureTemplate()->type == CREATURE_TYPE_DEMON || pet->GetCreatureTemplate()->type == CREATURE_TYPE_UNDEAD)
|
||||
pet->GetCharmInfo()->SetPetNumber(pet_number, pet->IsPermanentPetFor(owner)); // Show pet details tab (Shift+P) only for hunter pets, demons or undead
|
||||
else
|
||||
pet->GetCharmInfo()->SetPetNumber(pet_number, false);
|
||||
|
||||
pet->SetDisplayId(fields[3].GetUInt32());
|
||||
pet->UpdatePositionData();
|
||||
pet->SetNativeDisplayId(fields[3].GetUInt32());
|
||||
pet->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE);
|
||||
pet->SetName(fields[8].GetString());
|
||||
uint32 petlevel = fields[4].GetUInt16();
|
||||
|
||||
switch (pet->getPetType())
|
||||
{
|
||||
case SUMMON_PET:
|
||||
petlevel = owner->getLevel();
|
||||
|
||||
if (pet->IsPetGhoul())
|
||||
pet->SetUInt32Value(UNIT_FIELD_BYTES_0, 0x400); // class = rogue
|
||||
else
|
||||
pet->SetUInt32Value(UNIT_FIELD_BYTES_0, 0x800); // class = mage
|
||||
|
||||
pet->SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED);
|
||||
// this enables popup window (pet dismiss, cancel)
|
||||
break;
|
||||
case HUNTER_PET:
|
||||
pet->SetUInt32Value(UNIT_FIELD_BYTES_0, 0x02020100); // class = warrior, gender = none, power = focus
|
||||
pet->SetSheath(SHEATH_STATE_MELEE);
|
||||
pet->SetByteFlag(UNIT_FIELD_BYTES_2, 2, fields[9].GetBool() ? UNIT_CAN_BE_ABANDONED : UNIT_CAN_BE_RENAMED | UNIT_CAN_BE_ABANDONED);
|
||||
pet->SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED);
|
||||
// this enables popup window (pet abandon, cancel)
|
||||
pet->SetMaxPower(POWER_HAPPINESS, pet->GetCreatePowers(POWER_HAPPINESS));
|
||||
pet->SetPower(POWER_HAPPINESS, fields[12].GetUInt32());
|
||||
pet->setPowerType(POWER_FOCUS);
|
||||
break;
|
||||
default:
|
||||
if (!pet->IsPetGhoul())
|
||||
LOG_ERROR("network.opcode", "Pet have incorrect type (%u) for pet loading.", pet->getPetType());
|
||||
break;
|
||||
}
|
||||
|
||||
pet->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, uint32(time(nullptr))); // cast can't be helped here
|
||||
pet->SetCreatorGUID(owner->GetGUID());
|
||||
owner->SetMinion(pet, true);
|
||||
|
||||
pet->InitStatsForLevel(petlevel);
|
||||
pet->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, fields[5].GetUInt32());
|
||||
pet->SynchronizeLevelWithOwner();
|
||||
pet->SetReactState(ReactStates(fields[6].GetUInt8()));
|
||||
pet->SetCanModifyStats(true);
|
||||
|
||||
// set current pet as current
|
||||
// 0=current
|
||||
// 1..MAX_PET_STABLES in stable slot
|
||||
// PET_SAVE_NOT_IN_SLOT(100) = not stable slot (summoning))
|
||||
if (petSlot)
|
||||
{
|
||||
CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
|
||||
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UDP_CHAR_PET_SLOT_BY_SLOT_EXCLUDE_ID);
|
||||
stmt->setUInt8(0, uint8(PET_SAVE_NOT_IN_SLOT));
|
||||
stmt->setUInt32(1, owner->GetGUID().GetCounter());
|
||||
stmt->setUInt8(2, uint8(PET_SAVE_AS_CURRENT));
|
||||
stmt->setUInt32(3, pet_number);
|
||||
trans->Append(stmt);
|
||||
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_PET_SLOT_BY_ID);
|
||||
stmt->setUInt8(0, uint8(PET_SAVE_AS_CURRENT));
|
||||
stmt->setUInt32(1, owner->GetGUID().GetCounter());
|
||||
stmt->setUInt32(2, pet_number);
|
||||
trans->Append(stmt);
|
||||
|
||||
CharacterDatabase.CommitTransaction(trans);
|
||||
}
|
||||
|
||||
// Send fake summon spell cast - this is needed for correct cooldown application for spells
|
||||
// Example: 46584 - without this cooldown (which should be set always when pet is loaded) isn't set clientside
|
||||
// TODO: pets should be summoned from real cast instead of just faking it?
|
||||
if (summon_spell_id)
|
||||
{
|
||||
WorldPacket data(SMSG_SPELL_GO, (8 + 8 + 4 + 4 + 2));
|
||||
data << owner->GetPackGUID();
|
||||
data << owner->GetPackGUID();
|
||||
data << uint8(0);
|
||||
data << uint32(summon_spell_id);
|
||||
data << uint32(256); // CAST_FLAG_UNKNOWN3
|
||||
data << uint32(0);
|
||||
owner->SendMessageToSet(&data, true);
|
||||
}
|
||||
|
||||
// do it as early as possible!
|
||||
pet->InitTalentForLevel(); // set original talents points before spell loading
|
||||
|
||||
if (!is_temporary_summoned)
|
||||
pet->GetCharmInfo()->InitPetActionBar();
|
||||
|
||||
map->AddToMap(pet->ToCreature(), true);
|
||||
|
||||
if (pet->getPetType() == SUMMON_PET && !current) //all (?) summon pets come with full health when called, but not when they are current
|
||||
pet->SetPower(POWER_MANA, pet->GetMaxPower(POWER_MANA));
|
||||
else
|
||||
{
|
||||
pet->SetHealth(savedhealth > pet->GetMaxHealth() ? pet->GetMaxHealth() : savedhealth);
|
||||
pet->SetPower(POWER_MANA, savedmana > pet->GetMaxPower(POWER_MANA) ? pet->GetMaxPower(POWER_MANA) : savedmana);
|
||||
}
|
||||
|
||||
pet->SetAsynchLoadType(asynchLoadType);
|
||||
|
||||
AddQueryHolderCallback(CharacterDatabase.DelayQueryHolder(holder)).AfterComplete([this, info](SQLQueryHolderBase const& holder)
|
||||
{
|
||||
HandleLoadPetFromDBSecondCallback(static_cast<LoadPetFromDBQueryHolder const&>(holder), info);
|
||||
});
|
||||
|
||||
return PET_LOAD_OK;
|
||||
}
|
||||
|
||||
void WorldSession::HandleLoadPetFromDBSecondCallback(LoadPetFromDBQueryHolder const& holder, AsynchPetSummon* info)
|
||||
{
|
||||
if (!GetPlayer())
|
||||
return;
|
||||
|
||||
Player* owner = GetPlayer();
|
||||
Pet* pet = owner->GetPet();
|
||||
if (!pet)
|
||||
return;
|
||||
|
||||
pet->_LoadAuras(holder.GetPreparedResult(PET_LOAD_QUERY_LOADAURAS), holder.GetDiffTime());
|
||||
bool current = holder.GetCurrent();
|
||||
uint32 summon_spell_id = pet->GetUInt32Value(UNIT_CREATED_BY_SPELL);
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(summon_spell_id); // CANT BE nullptr
|
||||
bool is_temporary_summoned = spellInfo && spellInfo->GetDuration() > 0;
|
||||
|
||||
// load action bar, if data broken will fill later by default spells.
|
||||
if (!is_temporary_summoned)
|
||||
{
|
||||
pet->GetCharmInfo()->LoadPetActionBar(holder.GetActionBar()); // action bar stored in already read string
|
||||
pet->_LoadSpells(holder.GetPreparedResult(PET_LOAD_QUERY_LOADSPELLS));
|
||||
pet->InitTalentForLevel(); // re-init to check talent count
|
||||
pet->_LoadSpellCooldowns(holder.GetPreparedResult(PET_LOAD_QUERY_LOADSPELLCOOLDOWN));
|
||||
pet->LearnPetPassives();
|
||||
pet->InitLevelupSpellsForLevel();
|
||||
pet->CastPetAuras(current);
|
||||
}
|
||||
|
||||
pet->CleanupActionBar(); // remove unknown spells from action bar after load
|
||||
owner->PetSpellInitialize();
|
||||
owner->SendTalentsInfoData(true);
|
||||
|
||||
if (owner->GetGroup())
|
||||
owner->SetGroupUpdateFlag(GROUP_UPDATE_PET);
|
||||
|
||||
//set last used pet number (for use in BG's)
|
||||
if (owner->GetTypeId() == TYPEID_PLAYER && pet->isControlled() && !pet->isTemporarySummoned() && (pet->getPetType() == SUMMON_PET || pet->getPetType() == HUNTER_PET))
|
||||
{
|
||||
owner->ToPlayer()->SetLastPetNumber(holder.GetPetNumber());
|
||||
owner->SetLastPetSpell(pet->GetUInt32Value(UNIT_CREATED_BY_SPELL));
|
||||
}
|
||||
|
||||
if (pet->getPetType() == SUMMON_PET && !current) //all (?) summon pets come with full health when called, but not when they are current
|
||||
{
|
||||
pet->SetPower(POWER_MANA, pet->GetMaxPower(POWER_MANA));
|
||||
pet->SetHealth(pet->GetMaxHealth());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!holder.GetSavedHealth() && pet->getPetType() == HUNTER_PET && pet->GetAsynchLoadType() != PET_LOAD_SUMMON_DEAD_PET)
|
||||
pet->setDeathState(JUST_DIED);
|
||||
else
|
||||
{
|
||||
pet->SetHealth(holder.GetSavedHealth() > pet->GetMaxHealth() ? pet->GetMaxHealth() : holder.GetSavedHealth());
|
||||
pet->SetPower(POWER_MANA, holder.GetSavedMana() > pet->GetMaxPower(POWER_MANA) ? pet->GetMaxPower(POWER_MANA) : holder.GetSavedMana());
|
||||
}
|
||||
}
|
||||
|
||||
pet->SetLoading(false);
|
||||
owner->SetTemporaryUnsummonedPetNumber(0); // clear this only if pet is loaded successfuly
|
||||
|
||||
// current
|
||||
if (current && owner->IsPetNeedBeTemporaryUnsummoned())
|
||||
{
|
||||
owner->UnsummonPetTemporaryIfAny();
|
||||
return;
|
||||
}
|
||||
|
||||
pet->HandleAsynchLoadSucceed();
|
||||
|
||||
if (info && info->m_healthPct)
|
||||
{
|
||||
pet->SetHealth(pet->CountPctFromMaxHealth(info->m_healthPct));
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandleDismissCritter(WorldPacket& recvData)
|
||||
{
|
||||
ObjectGuid guid;
|
||||
@@ -1193,12 +844,18 @@ void WorldSession::HandlePetRename(WorldPacket& recvData)
|
||||
recvData >> name;
|
||||
recvData >> isdeclined;
|
||||
|
||||
PetStable* petStable = _player->GetPetStable();
|
||||
|
||||
Pet* pet = ObjectAccessor::GetPet(*_player, petguid);
|
||||
|
||||
// check it!
|
||||
if (!pet || !pet->IsPet() || ((Pet*)pet)->getPetType() != HUNTER_PET ||
|
||||
!pet->HasByteFlag(UNIT_FIELD_BYTES_2, 2, UNIT_CAN_BE_RENAMED) ||
|
||||
pet->GetOwnerGUID() != _player->GetGUID() || !pet->GetCharmInfo())
|
||||
!pet->HasByteFlag(UNIT_FIELD_BYTES_2, 2, UNIT_CAN_BE_RENAMED) ||
|
||||
pet->GetOwnerGUID() != _player->GetGUID() || !pet->GetCharmInfo() ||
|
||||
!petStable || !petStable->CurrentPet || petStable->CurrentPet->PetNumber != pet->GetCharmInfo()->GetPetNumber())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
PetNameInvalidReason res = ObjectMgr::CheckPetName(name);
|
||||
if (res != PET_NAME_SUCCESS)
|
||||
@@ -1221,6 +878,9 @@ void WorldSession::HandlePetRename(WorldPacket& recvData)
|
||||
|
||||
pet->RemoveByteFlag(UNIT_FIELD_BYTES_2, 2, UNIT_CAN_BE_RENAMED);
|
||||
|
||||
petStable->CurrentPet->Name = name;
|
||||
petStable->CurrentPet->WasRenamed = true;
|
||||
|
||||
if (isdeclined)
|
||||
{
|
||||
for (uint8 i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
|
||||
|
||||
Reference in New Issue
Block a user