mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-16 18:40:28 +00:00
fix(Core/Pets): fix crash at pet resurrect (#10120)
This commit is contained in:
@@ -8667,6 +8667,136 @@ Pet* Player::GetPet() const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Pet* Player::SummonPet(uint32 entry, float x, float y, float z, float ang, PetType petType, Milliseconds duration /*= 0s*/)
|
||||
{
|
||||
PetStable& petStable = GetOrInitPetStable();
|
||||
|
||||
Pet* pet = new Pet(this, petType);
|
||||
|
||||
if (petType == SUMMON_PET && pet->LoadPetFromDB(this, entry, 0, false))
|
||||
{
|
||||
// Remove Demonic Sacrifice auras (known pet)
|
||||
Unit::AuraEffectList const& auraClassScripts = GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
|
||||
for (Unit::AuraEffectList::const_iterator itr = auraClassScripts.begin(); itr != auraClassScripts.end();)
|
||||
{
|
||||
if ((*itr)->GetMiscValue() == 2228)
|
||||
{
|
||||
RemoveAurasDueToSpell((*itr)->GetId());
|
||||
itr = auraClassScripts.begin();
|
||||
}
|
||||
else
|
||||
++itr;
|
||||
}
|
||||
|
||||
if (duration > 0s)
|
||||
pet->SetDuration(duration);
|
||||
|
||||
// Generate a new name for the newly summoned ghoul
|
||||
if (pet->IsPetGhoul())
|
||||
{
|
||||
std::string new_name = sObjectMgr->GeneratePetName(entry);
|
||||
if (!new_name.empty())
|
||||
pet->SetName(new_name);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// petentry == 0 for hunter "call pet" (current pet summoned if any)
|
||||
if (!entry)
|
||||
{
|
||||
delete pet;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
pet->Relocate(x, y, z, ang);
|
||||
if (!pet->IsPositionValid())
|
||||
{
|
||||
LOG_ERROR("misc", "Player::SummonPet: Pet (%s, Entry: %d) not summoned. Suggested coordinates aren't valid (X: %f Y: %f)", pet->GetGUID().ToString().c_str(), pet->GetEntry(), pet->GetPositionX(), pet->GetPositionY());
|
||||
delete pet;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Map* map = GetMap();
|
||||
uint32 pet_number = sObjectMgr->GeneratePetNumber();
|
||||
if (!pet->Create(map->GenerateLowGuid<HighGuid::Pet>(), map, GetPhaseMask(), entry, pet_number))
|
||||
{
|
||||
LOG_ERROR("misc", "Player::SummonPet: No such creature entry %u", entry);
|
||||
delete pet;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (petType == SUMMON_PET && petStable.CurrentPet)
|
||||
RemovePet(nullptr, PET_SAVE_NOT_IN_SLOT);
|
||||
|
||||
pet->SetCreatorGUID(GetGUID());
|
||||
pet->SetFaction(GetFaction());
|
||||
pet->setPowerType(POWER_MANA);
|
||||
pet->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE);
|
||||
pet->SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
|
||||
pet->InitStatsForLevel(getLevel());
|
||||
|
||||
SetMinion(pet, true);
|
||||
|
||||
switch (petType)
|
||||
{
|
||||
case SUMMON_PET:
|
||||
{
|
||||
if (pet->GetCreatureTemplate()->type == CREATURE_TYPE_DEMON || pet->GetCreatureTemplate()->type == CREATURE_TYPE_UNDEAD)
|
||||
pet->GetCharmInfo()->SetPetNumber(pet_number, true); // Show pet details tab (Shift+P) only for demons & undead
|
||||
else
|
||||
pet->GetCharmInfo()->SetPetNumber(pet_number, false);
|
||||
|
||||
pet->SetUInt32Value(UNIT_FIELD_BYTES_0, 2048);
|
||||
pet->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0);
|
||||
pet->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, 1000);
|
||||
pet->SetFullHealth();
|
||||
pet->SetPower(POWER_MANA, pet->GetMaxPower(POWER_MANA));
|
||||
pet->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, uint32(time(nullptr))); // cast can't be helped in this case
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
map->AddToMap(pet->ToCreature(), true);
|
||||
|
||||
ASSERT(!petStable.CurrentPet && (petType != HUNTER_PET || !petStable.GetUnslottedHunterPet()));
|
||||
pet->FillPetInfo(&petStable.CurrentPet.emplace());
|
||||
|
||||
if (petType == SUMMON_PET)
|
||||
{
|
||||
pet->InitPetCreateSpells();
|
||||
pet->InitTalentForLevel();
|
||||
pet->SavePetToDB(PET_SAVE_AS_CURRENT);
|
||||
PetSpellInitialize();
|
||||
|
||||
// Remove Demonic Sacrifice auras (known pet)
|
||||
Unit::AuraEffectList const& auraClassScripts = GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
|
||||
for (Unit::AuraEffectList::const_iterator itr = auraClassScripts.begin(); itr != auraClassScripts.end();)
|
||||
{
|
||||
if ((*itr)->GetMiscValue() == 2228)
|
||||
{
|
||||
RemoveAurasDueToSpell((*itr)->GetId());
|
||||
itr = auraClassScripts.begin();
|
||||
}
|
||||
else
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
|
||||
if (duration > 0s)
|
||||
pet->SetDuration(duration);
|
||||
|
||||
if (NeedSendSpectatorData() && pet->GetCreatureTemplate()->family)
|
||||
{
|
||||
ArenaSpectator::SendCommand_UInt32Value(FindMap(), GetGUID(), "PHP", (uint32)pet->GetHealthPct());
|
||||
ArenaSpectator::SendCommand_UInt32Value(FindMap(), GetGUID(), "PET", pet->GetCreatureTemplate()->family);
|
||||
}
|
||||
|
||||
return pet;
|
||||
}
|
||||
|
||||
void Player::RemovePet(Pet* pet, PetSaveMode mode, bool returnreagent)
|
||||
{
|
||||
if (!pet)
|
||||
@@ -8782,6 +8912,138 @@ void Player::RemovePet(Pet* pet, PetSaveMode mode, bool returnreagent)
|
||||
}
|
||||
}
|
||||
|
||||
bool Player::CanPetResurrect()
|
||||
{
|
||||
PetStable* const petStable = GetPetStable();
|
||||
if (!petStable)
|
||||
{
|
||||
// No pets
|
||||
return false;
|
||||
}
|
||||
|
||||
auto const& currectPet = petStable->CurrentPet;
|
||||
auto const& unslottedHunterPet = petStable->GetUnslottedHunterPet();
|
||||
|
||||
if (!currectPet && !unslottedHunterPet)
|
||||
{
|
||||
// No pets
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check current pet
|
||||
if (currectPet && !currectPet->Health)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check dismiss/unslotted hunter pet
|
||||
if (unslottedHunterPet && !unslottedHunterPet->Health)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Player::IsExistPet()
|
||||
{
|
||||
PetStable* const petStable = GetPetStable();
|
||||
return petStable && (petStable->CurrentPet || petStable->GetUnslottedHunterPet());
|
||||
}
|
||||
|
||||
Pet* Player::CreatePet(Creature* creatureTarget, uint32 spellID /*= 0*/)
|
||||
{
|
||||
if (IsExistPet())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!creatureTarget || creatureTarget->IsPet() || creatureTarget->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CreatureTemplate const* creatrueTemplate = sObjectMgr->GetCreatureTemplate(creatureTarget->GetEntry());
|
||||
if (!creatrueTemplate->family)
|
||||
{
|
||||
// Creatures with family 0 crashes the server
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Everything looks OK, create new pet
|
||||
Pet* pet = CreateTamedPetFrom(creatureTarget, spellID);
|
||||
if (!pet)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// "kill" original creature
|
||||
creatureTarget->DespawnOrUnsummon();
|
||||
|
||||
// calculate proper level
|
||||
uint8 level = (creatureTarget->getLevel() < (getLevel() - 5)) ? (getLevel() - 5) : getLevel();
|
||||
|
||||
// prepare visual effect for levelup
|
||||
pet->SetUInt32Value(UNIT_FIELD_LEVEL, level - 1);
|
||||
|
||||
// add to world
|
||||
pet->GetMap()->AddToMap(pet->ToCreature());
|
||||
|
||||
// visual effect for levelup
|
||||
pet->SetUInt32Value(UNIT_FIELD_LEVEL, level);
|
||||
|
||||
// caster have pet now
|
||||
SetMinion(pet, true);
|
||||
|
||||
pet->InitTalentForLevel();
|
||||
|
||||
pet->SavePetToDB(PET_SAVE_AS_CURRENT);
|
||||
PetSpellInitialize();
|
||||
|
||||
return pet;
|
||||
}
|
||||
|
||||
Pet* Player::CreatePet(uint32 creatureEntry, uint32 spellID /*= 0*/)
|
||||
{
|
||||
if (IsExistPet())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CreatureTemplate const* creatrueTemplate = sObjectMgr->GetCreatureTemplate(creatureEntry);
|
||||
if (!creatrueTemplate->family)
|
||||
{
|
||||
// Creatures with family 0 crashes the server
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Everything looks OK, create new pet
|
||||
Pet* pet = CreateTamedPetFrom(creatureEntry, spellID);
|
||||
if (!pet)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// prepare visual effect for levelup
|
||||
pet->SetUInt32Value(UNIT_FIELD_LEVEL, getLevel() - 1);
|
||||
|
||||
// add to world
|
||||
pet->GetMap()->AddToMap(pet->ToCreature());
|
||||
|
||||
// visual effect for levelup
|
||||
pet->SetUInt32Value(UNIT_FIELD_LEVEL, getLevel());
|
||||
|
||||
// caster have pet now
|
||||
SetMinion(pet, true);
|
||||
|
||||
pet->InitTalentForLevel();
|
||||
|
||||
pet->SavePetToDB(PET_SAVE_AS_CURRENT);
|
||||
PetSpellInitialize();
|
||||
|
||||
return pet;
|
||||
}
|
||||
|
||||
void Player::StopCastingCharm()
|
||||
{
|
||||
Unit* charm = GetCharm();
|
||||
@@ -15180,136 +15442,6 @@ Guild* Player::GetGuild() const
|
||||
return guildId ? sGuildMgr->GetGuildById(guildId) : nullptr;
|
||||
}
|
||||
|
||||
Pet* Player::SummonPet(uint32 entry, float x, float y, float z, float ang, PetType petType, Milliseconds duration /*= 0s*/)
|
||||
{
|
||||
PetStable& petStable = GetOrInitPetStable();
|
||||
|
||||
Pet* pet = new Pet(this, petType);
|
||||
|
||||
if (petType == SUMMON_PET && pet->LoadPetFromDB(this, entry, 0, false))
|
||||
{
|
||||
// Remove Demonic Sacrifice auras (known pet)
|
||||
Unit::AuraEffectList const& auraClassScripts = GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
|
||||
for (Unit::AuraEffectList::const_iterator itr = auraClassScripts.begin(); itr != auraClassScripts.end();)
|
||||
{
|
||||
if ((*itr)->GetMiscValue() == 2228)
|
||||
{
|
||||
RemoveAurasDueToSpell((*itr)->GetId());
|
||||
itr = auraClassScripts.begin();
|
||||
}
|
||||
else
|
||||
++itr;
|
||||
}
|
||||
|
||||
if (duration > 0s)
|
||||
pet->SetDuration(duration);
|
||||
|
||||
// Generate a new name for the newly summoned ghoul
|
||||
if (pet->IsPetGhoul())
|
||||
{
|
||||
std::string new_name = sObjectMgr->GeneratePetName(entry);
|
||||
if (!new_name.empty())
|
||||
pet->SetName(new_name);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// petentry == 0 for hunter "call pet" (current pet summoned if any)
|
||||
if (!entry)
|
||||
{
|
||||
delete pet;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
pet->Relocate(x, y, z, ang);
|
||||
if (!pet->IsPositionValid())
|
||||
{
|
||||
LOG_ERROR("misc", "Player::SummonPet: Pet (%s, Entry: %d) not summoned. Suggested coordinates aren't valid (X: %f Y: %f)", pet->GetGUID().ToString().c_str(), pet->GetEntry(), pet->GetPositionX(), pet->GetPositionY());
|
||||
delete pet;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Map* map = GetMap();
|
||||
uint32 pet_number = sObjectMgr->GeneratePetNumber();
|
||||
if (!pet->Create(map->GenerateLowGuid<HighGuid::Pet>(), map, GetPhaseMask(), entry, pet_number))
|
||||
{
|
||||
LOG_ERROR("misc", "Player::SummonPet: No such creature entry %u", entry);
|
||||
delete pet;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (petType == SUMMON_PET && petStable.CurrentPet)
|
||||
RemovePet(nullptr, PET_SAVE_NOT_IN_SLOT);
|
||||
|
||||
pet->SetCreatorGUID(GetGUID());
|
||||
pet->SetFaction(GetFaction());
|
||||
pet->setPowerType(POWER_MANA);
|
||||
pet->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE);
|
||||
pet->SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
|
||||
pet->InitStatsForLevel(getLevel());
|
||||
|
||||
SetMinion(pet, true);
|
||||
|
||||
switch (petType)
|
||||
{
|
||||
case SUMMON_PET:
|
||||
{
|
||||
if (pet->GetCreatureTemplate()->type == CREATURE_TYPE_DEMON || pet->GetCreatureTemplate()->type == CREATURE_TYPE_UNDEAD)
|
||||
pet->GetCharmInfo()->SetPetNumber(pet_number, true); // Show pet details tab (Shift+P) only for demons & undead
|
||||
else
|
||||
pet->GetCharmInfo()->SetPetNumber(pet_number, false);
|
||||
|
||||
pet->SetUInt32Value(UNIT_FIELD_BYTES_0, 2048);
|
||||
pet->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0);
|
||||
pet->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, 1000);
|
||||
pet->SetFullHealth();
|
||||
pet->SetPower(POWER_MANA, pet->GetMaxPower(POWER_MANA));
|
||||
pet->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, uint32(time(nullptr))); // cast can't be helped in this case
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
map->AddToMap(pet->ToCreature(), true);
|
||||
|
||||
ASSERT(!petStable.CurrentPet && (petType != HUNTER_PET || !petStable.GetUnslottedHunterPet()));
|
||||
pet->FillPetInfo(&petStable.CurrentPet.emplace());
|
||||
|
||||
if (petType == SUMMON_PET)
|
||||
{
|
||||
pet->InitPetCreateSpells();
|
||||
pet->InitTalentForLevel();
|
||||
pet->SavePetToDB(PET_SAVE_AS_CURRENT);
|
||||
PetSpellInitialize();
|
||||
|
||||
// Remove Demonic Sacrifice auras (known pet)
|
||||
Unit::AuraEffectList const& auraClassScripts = GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
|
||||
for (Unit::AuraEffectList::const_iterator itr = auraClassScripts.begin(); itr != auraClassScripts.end();)
|
||||
{
|
||||
if ((*itr)->GetMiscValue() == 2228)
|
||||
{
|
||||
RemoveAurasDueToSpell((*itr)->GetId());
|
||||
itr = auraClassScripts.begin();
|
||||
}
|
||||
else
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
|
||||
if (duration > 0s)
|
||||
pet->SetDuration(duration);
|
||||
|
||||
if (NeedSendSpectatorData() && pet->GetCreatureTemplate()->family)
|
||||
{
|
||||
ArenaSpectator::SendCommand_UInt32Value(FindMap(), GetGUID(), "PHP", (uint32)pet->GetHealthPct());
|
||||
ArenaSpectator::SendCommand_UInt32Value(FindMap(), GetGUID(), "PET", pet->GetCreatureTemplate()->family);
|
||||
}
|
||||
|
||||
return pet;
|
||||
}
|
||||
|
||||
uint32 Player::GetSpec(int8 spec)
|
||||
{
|
||||
uint32 mostTalentTabId = 0;
|
||||
|
||||
Reference in New Issue
Block a user