fix(Core/Pets): fix crash at pet resurrect (#10120)
This commit is contained in:
@@ -342,24 +342,6 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petEntry, uint32 petnumber, bool c
|
|||||||
SetReactState(petInfo->ReactState);
|
SetReactState(petInfo->ReactState);
|
||||||
SetCanModifyStats(true);
|
SetCanModifyStats(true);
|
||||||
|
|
||||||
if (getPetType() == SUMMON_PET && !current) //all (?) summon pets come with full health when called, but not when they are current
|
|
||||||
{
|
|
||||||
SetPower(POWER_MANA, GetMaxPower(POWER_MANA));
|
|
||||||
//SetHealth(GetMaxHealth());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
uint32 savedhealth = petInfo->Health;
|
|
||||||
uint32 savedmana = petInfo->Mana;
|
|
||||||
if (!savedhealth && getPetType() == HUNTER_PET)
|
|
||||||
setDeathState(JUST_DIED);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SetHealth(savedhealth > GetMaxHealth() ? GetMaxHealth() : savedhealth);
|
|
||||||
SetPower(POWER_MANA, savedmana > GetMaxPower(POWER_MANA) ? GetMaxPower(POWER_MANA) : savedmana);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// set current pet as current
|
// set current pet as current
|
||||||
// 0=current
|
// 0=current
|
||||||
// 1..MAX_PET_STABLES in stable slot
|
// 1..MAX_PET_STABLES in stable slot
|
||||||
@@ -426,7 +408,8 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petEntry, uint32 petnumber, bool c
|
|||||||
owner->ToPlayer()->SetLastPetNumber(petInfo->PetNumber);
|
owner->ToPlayer()->SetLastPetNumber(petInfo->PetNumber);
|
||||||
|
|
||||||
owner->GetSession()->AddQueryHolderCallback(CharacterDatabase.DelayQueryHolder(std::make_shared<PetLoadQueryHolder>(ownerid, petInfo->PetNumber)))
|
owner->GetSession()->AddQueryHolderCallback(CharacterDatabase.DelayQueryHolder(std::make_shared<PetLoadQueryHolder>(ownerid, petInfo->PetNumber)))
|
||||||
.AfterComplete([this, owner, session = owner->GetSession(), isTemporarySummon, current, lastSaveTime = petInfo->LastSaveTime](SQLQueryHolderBase const& holder)
|
.AfterComplete([this, owner, session = owner->GetSession(), isTemporarySummon, current, lastSaveTime = petInfo->LastSaveTime, savedhealth = petInfo->Health, savedmana = petInfo->Mana]
|
||||||
|
(SQLQueryHolderBase const& holder)
|
||||||
{
|
{
|
||||||
if (session->GetPlayer() != owner || owner->GetPet() != this)
|
if (session->GetPlayer() != owner || owner->GetPet() != this)
|
||||||
return;
|
return;
|
||||||
@@ -475,6 +458,22 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petEntry, uint32 petnumber, bool c
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (getPetType() == SUMMON_PET && !current) //all (?) summon pets come with full health when called, but not when they are current
|
||||||
|
{
|
||||||
|
SetPower(POWER_MANA, GetMaxPower(POWER_MANA));
|
||||||
|
SetFullHealth();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!savedhealth && getPetType() == HUNTER_PET)
|
||||||
|
setDeathState(JUST_DIED);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetHealth(savedhealth > GetMaxHealth() ? GetMaxHealth() : savedhealth);
|
||||||
|
SetPower(POWER_MANA, savedmana > GetMaxPower(POWER_MANA) ? GetMaxPower(POWER_MANA) : savedmana);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// must be after SetMinion (owner guid check)
|
// must be after SetMinion (owner guid check)
|
||||||
//LoadTemplateImmunities();
|
//LoadTemplateImmunities();
|
||||||
//LoadMechanicTemplateImmunity();
|
//LoadMechanicTemplateImmunity();
|
||||||
|
|||||||
@@ -8667,6 +8667,136 @@ Pet* Player::GetPet() const
|
|||||||
return nullptr;
|
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)
|
void Player::RemovePet(Pet* pet, PetSaveMode mode, bool returnreagent)
|
||||||
{
|
{
|
||||||
if (!pet)
|
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()
|
void Player::StopCastingCharm()
|
||||||
{
|
{
|
||||||
Unit* charm = GetCharm();
|
Unit* charm = GetCharm();
|
||||||
@@ -15180,136 +15442,6 @@ Guild* Player::GetGuild() const
|
|||||||
return guildId ? sGuildMgr->GetGuildById(guildId) : nullptr;
|
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 Player::GetSpec(int8 spec)
|
||||||
{
|
{
|
||||||
uint32 mostTalentTabId = 0;
|
uint32 mostTalentTabId = 0;
|
||||||
|
|||||||
@@ -1173,6 +1173,11 @@ public:
|
|||||||
[[nodiscard]] Pet* GetPet() const;
|
[[nodiscard]] Pet* GetPet() const;
|
||||||
Pet* SummonPet(uint32 entry, float x, float y, float z, float ang, PetType petType, Milliseconds duration = 0s);
|
Pet* SummonPet(uint32 entry, float x, float y, float z, float ang, PetType petType, Milliseconds duration = 0s);
|
||||||
void RemovePet(Pet* pet, PetSaveMode mode, bool returnreagent = false);
|
void RemovePet(Pet* pet, PetSaveMode mode, bool returnreagent = false);
|
||||||
|
bool CanPetResurrect();
|
||||||
|
bool IsExistPet();
|
||||||
|
Pet* CreatePet(Creature* creatureTarget, uint32 spellID = 0);
|
||||||
|
Pet* CreatePet(uint32 creatureEntry, uint32 spellID = 0);
|
||||||
|
|
||||||
[[nodiscard]] uint32 GetPhaseMaskForSpawn() const; // used for proper set phase for DB at GM-mode creature/GO spawn
|
[[nodiscard]] uint32 GetPhaseMaskForSpawn() const; // used for proper set phase for DB at GM-mode creature/GO spawn
|
||||||
|
|
||||||
/// Handles said message in regular chat based on declared language and in config pre-defined Range.
|
/// Handles said message in regular chat based on declared language and in config pre-defined Range.
|
||||||
|
|||||||
@@ -5932,17 +5932,6 @@ SpellCastResult Spell::CheckCast(bool strict)
|
|||||||
if (pet && pet->IsAlive())
|
if (pet && pet->IsAlive())
|
||||||
return SPELL_FAILED_ALREADY_HAVE_SUMMON;
|
return SPELL_FAILED_ALREADY_HAVE_SUMMON;
|
||||||
|
|
||||||
Player* player = unitCaster->ToPlayer();
|
|
||||||
if (player)
|
|
||||||
{
|
|
||||||
// Check pet before resurrect
|
|
||||||
auto [petStable, petSlot] = Pet::GetLoadPetInfo(*player->GetPetStable(), 0, 0, false);
|
|
||||||
if (!petStable)
|
|
||||||
{
|
|
||||||
return SPELL_FAILED_NO_PET;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// This is generic summon effect
|
// This is generic summon effect
|
||||||
|
|||||||
@@ -1157,7 +1157,7 @@ public:
|
|||||||
|
|
||||||
Player* player = handler->GetSession()->GetPlayer();
|
Player* player = handler->GetSession()->GetPlayer();
|
||||||
|
|
||||||
if (player->GetPetGUID())
|
if (player->IsExistPet())
|
||||||
{
|
{
|
||||||
handler->SendSysMessage(LANG_YOU_ALREADY_HAVE_PET);
|
handler->SendSysMessage(LANG_YOU_ALREADY_HAVE_PET);
|
||||||
handler->SetSentErrorMessage(true);
|
handler->SetSentErrorMessage(true);
|
||||||
@@ -1173,41 +1173,13 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Everything looks OK, create new pet
|
if (!player->CreatePet(creatureTarget))
|
||||||
Pet* pet = player->CreateTamedPetFrom(creatureTarget);
|
|
||||||
if (!pet)
|
|
||||||
{
|
{
|
||||||
handler->PSendSysMessage(LANG_CREATURE_NON_TAMEABLE, cInfo->Entry);
|
handler->PSendSysMessage(LANG_CREATURE_NON_TAMEABLE, cInfo->Entry);
|
||||||
handler->SetSentErrorMessage(true);
|
handler->SetSentErrorMessage(true);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// place pet before player
|
|
||||||
float x, y, z;
|
|
||||||
player->GetClosePoint (x, y, z, creatureTarget->GetObjectSize(), CONTACT_DISTANCE);
|
|
||||||
pet->Relocate(x, y, z, M_PI - player->GetOrientation());
|
|
||||||
|
|
||||||
// set pet to defensive mode by default (some classes can't control controlled pets in fact).
|
|
||||||
pet->SetReactState(REACT_DEFENSIVE);
|
|
||||||
|
|
||||||
// calculate proper level
|
|
||||||
uint8 level = (creatureTarget->getLevel() < (player->getLevel() - 5)) ? (player->getLevel() - 5) : creatureTarget->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
|
|
||||||
player->SetMinion(pet, true);
|
|
||||||
|
|
||||||
pet->SavePetToDB(PET_SAVE_AS_CURRENT);
|
|
||||||
player->PetSpellInitialize();
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -66,44 +66,24 @@ public:
|
|||||||
// Creatures with family 0 crashes the server
|
// Creatures with family 0 crashes the server
|
||||||
if (!creatrueTemplate->family)
|
if (!creatrueTemplate->family)
|
||||||
{
|
{
|
||||||
handler->PSendSysMessage("This creature cannot be tamed. (family id: 0).");
|
handler->PSendSysMessage(LANG_CREATURE_NON_TAMEABLE, creatrueTemplate->Entry);
|
||||||
handler->SetSentErrorMessage(true);
|
handler->SetSentErrorMessage(true);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
PetStable const* petStable = player->GetPetStable();
|
if (player->IsExistPet())
|
||||||
|
|
||||||
if (petStable && (petStable->CurrentPet || petStable->GetUnslottedHunterPet()))
|
|
||||||
{
|
{
|
||||||
handler->PSendSysMessage("You already have a pet");
|
handler->SendSysMessage(LANG_YOU_ALREADY_HAVE_PET);
|
||||||
handler->SetSentErrorMessage(true);
|
handler->SetSentErrorMessage(true);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Everything looks OK, create new pet
|
if (!player->CreatePet(creatureTarget))
|
||||||
Pet* pet = player->CreateTamedPetFrom(creatureTarget);
|
{
|
||||||
|
handler->PSendSysMessage(LANG_CREATURE_NON_TAMEABLE, creatrueTemplate->Entry);
|
||||||
// "kill" original creature
|
handler->SetSentErrorMessage(true);
|
||||||
creatureTarget->DespawnOrUnsummon();
|
return false;
|
||||||
|
}
|
||||||
uint8 level = (creatureTarget->getLevel() < (player->getLevel() - 5)) ? (player->getLevel() - 5) : player->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
|
|
||||||
player->SetMinion(pet, true);
|
|
||||||
|
|
||||||
pet->InitTalentForLevel();
|
|
||||||
|
|
||||||
pet->SavePetToDB(PET_SAVE_AS_CURRENT);
|
|
||||||
player->PetSpellInitialize();
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -517,4 +517,3 @@ void AddSC_elwynn_forest()
|
|||||||
RegisterCreatureAI(npc_supervisor_raelen);
|
RegisterCreatureAI(npc_supervisor_raelen);
|
||||||
RegisterCreatureAI(npc_eastvale_peasent);
|
RegisterCreatureAI(npc_eastvale_peasent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1998,4 +1998,3 @@ void AddSC_go_scripts()
|
|||||||
new go_veil_skith_cage();
|
new go_veil_skith_cage();
|
||||||
new go_bells();
|
new go_bells();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user