Core/Pets: Updated pet summoning for latest client version (5 Call Pet spells and stable size 200)
This commit is contained in:
@@ -732,7 +732,6 @@ void CharacterDatabaseConnection::DoPrepareStatements()
|
||||
PrepareStatement(CHAR_UPD_CHAR_PET_NAME, "UPDATE character_pet SET name = ?, renamed = 1 WHERE owner = ? AND id = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_UPD_CHAR_PET_SLOT_BY_ID, "UPDATE character_pet SET slot = ? WHERE owner = ? AND id = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_DEL_CHAR_PET_BY_ID, "DELETE FROM character_pet WHERE id = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_DEL_CHAR_PET_BY_SLOT, "DELETE FROM character_pet WHERE owner = ? AND slot IN (?, ?)", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_DEL_ALL_PET_SPELLS_BY_OWNER, "DELETE FROM pet_spell WHERE guid in (SELECT id FROM character_pet WHERE owner=?)", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_UPD_PET_SPECS_BY_OWNER, "UPDATE character_pet SET specialization = 0 WHERE owner=?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_INS_PET, "INSERT INTO character_pet (id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, abdata, savetime, CreatedBySpell, PetType, specialization) "
|
||||
|
||||
@@ -599,7 +599,6 @@ enum CharacterDatabaseStatements : uint32
|
||||
CHAR_UPD_CHAR_PET_NAME,
|
||||
CHAR_UPD_CHAR_PET_SLOT_BY_ID,
|
||||
CHAR_DEL_CHAR_PET_BY_ID,
|
||||
CHAR_DEL_CHAR_PET_BY_SLOT,
|
||||
CHAR_DEL_ALL_PET_SPELLS_BY_OWNER,
|
||||
CHAR_UPD_PET_SPECS_BY_OWNER,
|
||||
CHAR_INS_PET,
|
||||
|
||||
@@ -101,13 +101,14 @@ void Pet::RemoveFromWorld()
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<PetStable::PetInfo const*, PetSaveMode> Pet::GetLoadPetInfo(PetStable const& stable, uint32 petEntry, uint32 petnumber, bool current)
|
||||
std::pair<PetStable::PetInfo const*, PetSaveMode> Pet::GetLoadPetInfo(PetStable const& stable, uint32 petEntry, uint32 petnumber, Optional<PetSaveMode> slot)
|
||||
{
|
||||
if (petnumber)
|
||||
{
|
||||
// Known petnumber entry
|
||||
if (stable.CurrentPet && stable.CurrentPet->PetNumber == petnumber)
|
||||
return { &stable.CurrentPet.value(), PET_SAVE_AS_CURRENT };
|
||||
for (std::size_t activeSlot = 0; activeSlot < stable.ActivePets.size(); ++activeSlot)
|
||||
if (stable.ActivePets[activeSlot] && stable.ActivePets[activeSlot]->PetNumber == petnumber)
|
||||
return { &stable.ActivePets[activeSlot].value(), PetSaveMode(PET_SAVE_FIRST_ACTIVE_SLOT + activeSlot) };
|
||||
|
||||
for (std::size_t stableSlot = 0; stableSlot < stable.StabledPets.size(); ++stableSlot)
|
||||
if (stable.StabledPets[stableSlot] && stable.StabledPets[stableSlot]->PetNumber == petnumber)
|
||||
@@ -117,18 +118,24 @@ std::pair<PetStable::PetInfo const*, PetSaveMode> Pet::GetLoadPetInfo(PetStable
|
||||
if (pet.PetNumber == petnumber)
|
||||
return { &pet, PET_SAVE_NOT_IN_SLOT };
|
||||
}
|
||||
else if (current)
|
||||
else if (slot)
|
||||
{
|
||||
// Current pet (slot 0)
|
||||
if (stable.CurrentPet)
|
||||
return { &stable.CurrentPet.value(), PET_SAVE_AS_CURRENT };
|
||||
// Current pet
|
||||
if (slot == PET_SAVE_AS_CURRENT)
|
||||
if (stable.GetCurrentActivePetIndex() && stable.ActivePets[*stable.GetCurrentActivePetIndex()])
|
||||
return { &stable.ActivePets[*stable.GetCurrentActivePetIndex()].value(), PetSaveMode(*stable.GetCurrentActivePetIndex()) };
|
||||
|
||||
if (slot >= PET_SAVE_FIRST_ACTIVE_SLOT && slot < PET_SAVE_LAST_ACTIVE_SLOT)
|
||||
if (stable.ActivePets[*slot])
|
||||
return { &stable.ActivePets[*slot].value(), *slot };
|
||||
|
||||
if (slot >= PET_SAVE_FIRST_STABLE_SLOT && slot < PET_SAVE_LAST_STABLE_SLOT)
|
||||
if (stable.StabledPets[*slot])
|
||||
return { &stable.StabledPets[*slot].value(), *slot };
|
||||
}
|
||||
else if (petEntry)
|
||||
{
|
||||
// known petEntry entry (unique for summoned pet, but non unique for hunter pet (only from current or not stabled pets)
|
||||
if (stable.CurrentPet && stable.CurrentPet->CreatureId == petEntry)
|
||||
return { &stable.CurrentPet.value(), PET_SAVE_AS_CURRENT };
|
||||
|
||||
for (PetStable::PetInfo const& pet : stable.UnslottedPets)
|
||||
if (pet.CreatureId == petEntry)
|
||||
return { &pet, PET_SAVE_NOT_IN_SLOT };
|
||||
@@ -136,8 +143,8 @@ std::pair<PetStable::PetInfo const*, PetSaveMode> Pet::GetLoadPetInfo(PetStable
|
||||
else
|
||||
{
|
||||
// Any current or other non-stabled pet (for hunter "call pet")
|
||||
if (stable.CurrentPet)
|
||||
return { &stable.CurrentPet.value(), PET_SAVE_AS_CURRENT };
|
||||
if (stable.ActivePets[0])
|
||||
return { &stable.ActivePets[0].value(), PET_SAVE_FIRST_ACTIVE_SLOT };
|
||||
|
||||
if (!stable.UnslottedPets.empty())
|
||||
return { &stable.UnslottedPets.front(), PET_SAVE_NOT_IN_SLOT };
|
||||
@@ -194,24 +201,24 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
bool Pet::LoadPetFromDB(Player* owner, uint32 petEntry, uint32 petnumber, bool current)
|
||||
bool Pet::LoadPetFromDB(Player* owner, uint32 petEntry, uint32 petnumber, bool current, Optional<PetSaveMode> forcedSlot /*= {}*/)
|
||||
{
|
||||
m_loading = true;
|
||||
|
||||
PetStable* petStable = ASSERT_NOTNULL(owner->GetPetStable());
|
||||
|
||||
ObjectGuid::LowType ownerid = owner->GetGUID().GetCounter();
|
||||
std::pair<PetStable::PetInfo const*, PetSaveMode> info = GetLoadPetInfo(*petStable, petEntry, petnumber, current);
|
||||
std::pair<PetStable::PetInfo const*, PetSaveMode> info = GetLoadPetInfo(*petStable, petEntry, petnumber, forcedSlot);
|
||||
PetStable::PetInfo const* petInfo = info.first;
|
||||
PetSaveMode slot = info.second;
|
||||
if (!petInfo)
|
||||
if (!petInfo || (slot >= PET_SAVE_FIRST_STABLE_SLOT && slot < PET_SAVE_LAST_STABLE_SLOT))
|
||||
{
|
||||
m_loading = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Don't try to reload the current pet
|
||||
if (petStable->CurrentPet && owner->GetPet() && petStable->CurrentPet.value().PetNumber == petInfo->PetNumber)
|
||||
if (petStable->GetCurrentPet() && owner->GetPet() && petStable->GetCurrentPet()->PetNumber == petInfo->PetNumber)
|
||||
return false;
|
||||
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(petInfo->CreatedBySpellId, owner->GetMap()->GetDifficultyID());
|
||||
@@ -329,40 +336,33 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petEntry, uint32 petnumber, bool c
|
||||
}
|
||||
|
||||
// set current pet as current
|
||||
// 0=current
|
||||
// 1..MAX_PET_STABLES in stable slot
|
||||
// PET_SAVE_NOT_IN_SLOT(100) = not stable slot (summoning))
|
||||
// 0-4=current
|
||||
// PET_SAVE_NOT_IN_SLOT(-1) = not stable slot (summoning))
|
||||
if (slot == PET_SAVE_NOT_IN_SLOT)
|
||||
{
|
||||
uint32 petInfoNumber = petInfo->PetNumber;
|
||||
if (petStable->CurrentPet)
|
||||
if (petStable->CurrentPetIndex)
|
||||
owner->RemovePet(nullptr, PET_SAVE_NOT_IN_SLOT);
|
||||
|
||||
auto unslottedPetItr = std::find_if(petStable->UnslottedPets.begin(), petStable->UnslottedPets.end(), [&](PetStable::PetInfo const& unslottedPet)
|
||||
{
|
||||
return unslottedPet.PetNumber == petInfoNumber;
|
||||
});
|
||||
ASSERT(!petStable->CurrentPet);
|
||||
ASSERT(!petStable->CurrentPetIndex);
|
||||
ASSERT(unslottedPetItr != petStable->UnslottedPets.end());
|
||||
|
||||
petStable->CurrentPet = std::move(*unslottedPetItr);
|
||||
petStable->UnslottedPets.erase(unslottedPetItr);
|
||||
|
||||
// old petInfo pointer is no longer valid, refresh it
|
||||
petInfo = &petStable->CurrentPet.value();
|
||||
petStable->SetCurrentUnslottedPetIndex(std::distance(petStable->UnslottedPets.begin(), unslottedPetItr));
|
||||
}
|
||||
else if (PET_SAVE_FIRST_STABLE_SLOT <= slot && slot <= PET_SAVE_LAST_STABLE_SLOT)
|
||||
else if (PET_SAVE_FIRST_ACTIVE_SLOT <= slot && slot <= PET_SAVE_LAST_ACTIVE_SLOT)
|
||||
{
|
||||
auto stabledPet = std::find_if(petStable->StabledPets.begin(), petStable->StabledPets.end(), [petnumber](Optional<PetStable::PetInfo> const& pet)
|
||||
auto activePetItr = std::find_if(petStable->ActivePets.begin(), petStable->ActivePets.end(), [&](Optional<PetStable::PetInfo> const& pet)
|
||||
{
|
||||
return pet && pet->PetNumber == petnumber;
|
||||
return pet && pet->PetNumber == petInfo->PetNumber;
|
||||
});
|
||||
ASSERT(stabledPet != petStable->StabledPets.end());
|
||||
ASSERT(!petStable->CurrentPetIndex);
|
||||
ASSERT(activePetItr != petStable->ActivePets.end());
|
||||
|
||||
std::swap(*stabledPet, petStable->CurrentPet);
|
||||
|
||||
// old petInfo pointer is no longer valid, refresh it
|
||||
petInfo = &petStable->CurrentPet.value();
|
||||
petStable->SetCurrentActivePetIndex(std::distance(petStable->ActivePets.begin(), activePetItr));
|
||||
}
|
||||
|
||||
// Send fake summon spell cast - this is needed for correct cooldown application for spells
|
||||
@@ -491,8 +491,12 @@ void Pet::SavePetToDB(PetSaveMode mode)
|
||||
// save auras before possibly removing them
|
||||
_SaveAuras(trans);
|
||||
|
||||
if (mode == PET_SAVE_AS_CURRENT)
|
||||
if (Optional<uint32> activeSlot = owner->GetPetStable()->GetCurrentActivePetIndex())
|
||||
mode = PetSaveMode(*activeSlot);
|
||||
|
||||
// stable and not in slot saves
|
||||
if (mode > PET_SAVE_AS_CURRENT)
|
||||
if (mode < PET_SAVE_FIRST_ACTIVE_SLOT || mode >= PET_SAVE_LAST_ACTIVE_SLOT)
|
||||
RemoveAllAuras();
|
||||
|
||||
_SaveSpells(trans);
|
||||
@@ -500,7 +504,7 @@ void Pet::SavePetToDB(PetSaveMode mode)
|
||||
CharacterDatabase.CommitTransaction(trans);
|
||||
|
||||
// current/stable/not_in_slot
|
||||
if (mode >= PET_SAVE_AS_CURRENT)
|
||||
if (mode != PET_SAVE_AS_DELETED)
|
||||
{
|
||||
ObjectGuid::LowType ownerLowGUID = GetOwnerGUID().GetCounter();
|
||||
trans = CharacterDatabase.BeginTransaction();
|
||||
@@ -510,21 +514,11 @@ void Pet::SavePetToDB(PetSaveMode mode)
|
||||
stmt->setUInt32(0, m_charmInfo->GetPetNumber());
|
||||
trans->Append(stmt);
|
||||
|
||||
// prevent existence another hunter pet in PET_SAVE_AS_CURRENT and PET_SAVE_NOT_IN_SLOT
|
||||
if (getPetType() == HUNTER_PET && (mode == PET_SAVE_AS_CURRENT || mode == PET_SAVE_NOT_IN_SLOT))
|
||||
{
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_PET_BY_SLOT);
|
||||
stmt->setUInt64(0, ownerLowGUID);
|
||||
stmt->setInt16(1, mode);
|
||||
stmt->setInt16(2, PET_SAVE_NOT_IN_SLOT);
|
||||
trans->Append(stmt);
|
||||
}
|
||||
|
||||
// save pet
|
||||
std::string actionBar = GenerateActionBarData();
|
||||
|
||||
ASSERT(owner->GetPetStable()->CurrentPet && owner->GetPetStable()->CurrentPet->PetNumber == m_charmInfo->GetPetNumber());
|
||||
FillPetInfo(&owner->GetPetStable()->CurrentPet.value());
|
||||
ASSERT(owner->GetPetStable()->GetCurrentPet() && owner->GetPetStable()->GetCurrentPet()->PetNumber == m_charmInfo->GetPetNumber());
|
||||
FillPetInfo(owner->GetPetStable()->GetCurrentPet());
|
||||
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PET);
|
||||
stmt->setUInt32(0, m_charmInfo->GetPetNumber());
|
||||
@@ -534,7 +528,7 @@ void Pet::SavePetToDB(PetSaveMode mode)
|
||||
stmt->setUInt8(4, GetLevel());
|
||||
stmt->setUInt32(5, m_unitData->PetExperience);
|
||||
stmt->setUInt8(6, GetReactState());
|
||||
stmt->setInt16(7, mode);
|
||||
stmt->setInt16(7, owner->GetPetStable()->GetCurrentActivePetIndex().value_or(PET_SAVE_NOT_IN_SLOT));
|
||||
stmt->setString(8, m_name);
|
||||
stmt->setUInt8(9, HasPetFlag(UNIT_PET_FLAG_CAN_BE_RENAMED) ? 0 : 1);
|
||||
stmt->setUInt32(10, curhealth);
|
||||
|
||||
@@ -65,8 +65,8 @@ class TC_GAME_API Pet : public Guardian
|
||||
bool CreateBaseAtCreature(Creature* creature);
|
||||
bool CreateBaseAtCreatureInfo(CreatureTemplate const* cinfo, Unit* owner);
|
||||
bool CreateBaseAtTamed(CreatureTemplate const* cinfo, Map* map);
|
||||
static std::pair<PetStable::PetInfo const*, PetSaveMode> GetLoadPetInfo(PetStable const& stable, uint32 petEntry, uint32 petnumber, bool current);
|
||||
bool LoadPetFromDB(Player* owner, uint32 petEntry, uint32 petnumber, bool current);
|
||||
static std::pair<PetStable::PetInfo const*, PetSaveMode> GetLoadPetInfo(PetStable const& stable, uint32 petEntry, uint32 petnumber, Optional<PetSaveMode> slot);
|
||||
bool LoadPetFromDB(Player* owner, uint32 petEntry, uint32 petnumber, bool current, Optional<PetSaveMode> forcedSlot = {});
|
||||
bool IsLoading() const override { return m_loading;}
|
||||
void SavePetToDB(PetSaveMode mode);
|
||||
void FillPetInfo(PetStable::PetInfo* petInfo) const;
|
||||
|
||||
@@ -33,18 +33,31 @@ enum PetType : uint8
|
||||
MAX_PET_TYPE = 4
|
||||
};
|
||||
|
||||
#define MAX_PET_STABLES 4
|
||||
#define MAX_ACTIVE_PETS 5
|
||||
#define MAX_PET_STABLES 200
|
||||
|
||||
// stored in character_pet.slot
|
||||
enum PetSaveMode : int16
|
||||
{
|
||||
PET_SAVE_AS_DELETED = -2, // not saved in fact
|
||||
PET_SAVE_AS_CURRENT = 0, // in current slot (with player)
|
||||
PET_SAVE_FIRST_STABLE_SLOT = 1,
|
||||
PET_SAVE_LAST_STABLE_SLOT = MAX_PET_STABLES, // last in DB stable slot index (including), all higher have same meaning as PET_SAVE_NOT_IN_SLOT
|
||||
PET_SAVE_AS_CURRENT = -3, // in current slot (with player)
|
||||
PET_SAVE_FIRST_ACTIVE_SLOT = 0,
|
||||
PET_SAVE_LAST_ACTIVE_SLOT = PET_SAVE_FIRST_ACTIVE_SLOT + MAX_ACTIVE_PETS,
|
||||
PET_SAVE_FIRST_STABLE_SLOT = 5,
|
||||
PET_SAVE_LAST_STABLE_SLOT = PET_SAVE_FIRST_STABLE_SLOT + MAX_PET_STABLES, // last in DB stable slot index
|
||||
PET_SAVE_NOT_IN_SLOT = -1 // for avoid conflict with stable size grow will use negative value
|
||||
};
|
||||
|
||||
constexpr bool IsActivePetSlot(PetSaveMode slot)
|
||||
{
|
||||
return slot >= PET_SAVE_FIRST_ACTIVE_SLOT && slot < PET_SAVE_LAST_ACTIVE_SLOT;
|
||||
}
|
||||
|
||||
constexpr bool IsStabledPetSlot(PetSaveMode slot)
|
||||
{
|
||||
return slot >= PET_SAVE_FIRST_STABLE_SLOT && slot < PET_SAVE_LAST_STABLE_SLOT;
|
||||
}
|
||||
|
||||
enum PetSpellState
|
||||
{
|
||||
PETSPELL_UNCHANGED = 0,
|
||||
@@ -97,6 +110,8 @@ enum class PetTameResult : uint8
|
||||
EliteTooHighLevel = 14
|
||||
};
|
||||
|
||||
constexpr uint32 CALL_PET_SPELL_ID = 883;
|
||||
|
||||
class PetStable
|
||||
{
|
||||
public:
|
||||
@@ -121,14 +136,33 @@ public:
|
||||
bool WasRenamed = false;
|
||||
};
|
||||
|
||||
Optional<PetInfo> CurrentPet; // PET_SAVE_AS_CURRENT
|
||||
Optional<uint32> CurrentPetIndex; // index into ActivePets or UnslottedPets if highest bit is set
|
||||
std::array<Optional<PetInfo>, MAX_ACTIVE_PETS> ActivePets; // PET_SAVE_FIRST_ACTIVE_SLOT - PET_SAVE_LAST_ACTIVE_SLOT
|
||||
std::array<Optional<PetInfo>, MAX_PET_STABLES> StabledPets; // PET_SAVE_FIRST_STABLE_SLOT - PET_SAVE_LAST_STABLE_SLOT
|
||||
std::vector<PetInfo> UnslottedPets; // PET_SAVE_NOT_IN_SLOT
|
||||
|
||||
PetInfo const* GetUnslottedHunterPet() const
|
||||
PetInfo* GetCurrentPet() { return const_cast<PetInfo*>(const_cast<PetStable const*>(this)->GetCurrentPet()); }
|
||||
PetInfo const* GetCurrentPet() const
|
||||
{
|
||||
return UnslottedPets.size() == 1 && UnslottedPets[0].Type == HUNTER_PET ? &UnslottedPets[0] : nullptr;
|
||||
if (!CurrentPetIndex)
|
||||
return nullptr;
|
||||
|
||||
if (Optional<uint32> activePetIndex = GetCurrentActivePetIndex())
|
||||
return ActivePets[*activePetIndex] ? &ActivePets[*activePetIndex].value() : nullptr;
|
||||
|
||||
if (Optional<uint32> unslottedPetIndex = GetCurrentUnslottedPetIndex())
|
||||
return *unslottedPetIndex < UnslottedPets.size() ? &UnslottedPets[*unslottedPetIndex] : nullptr;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Optional<uint32> GetCurrentActivePetIndex() const { return CurrentPetIndex && ((*CurrentPetIndex & UnslottedPetIndexMask) == 0) ? CurrentPetIndex : std::nullopt; }
|
||||
void SetCurrentActivePetIndex(uint32 index) { CurrentPetIndex = index; }
|
||||
Optional<uint32> GetCurrentUnslottedPetIndex() const { return CurrentPetIndex && ((*CurrentPetIndex & UnslottedPetIndexMask) != 0) ? Optional<uint32>(*CurrentPetIndex & ~UnslottedPetIndexMask) : std::nullopt; }
|
||||
void SetCurrentUnslottedPetIndex(uint32 index) { CurrentPetIndex = index | UnslottedPetIndexMask; }
|
||||
|
||||
private:
|
||||
static constexpr uint32 UnslottedPetIndexMask = 0x80000000;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -18413,8 +18413,7 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder* holder)
|
||||
|
||||
uint32 extraflags = fields.extra_flags;
|
||||
|
||||
_LoadPetStable(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_PET_SLOTS));
|
||||
m_temporaryUnsummonedPetNumber = fields.summonedPetNumber;
|
||||
_LoadPetStable(fields.summonedPetNumber, holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_PET_SLOTS));
|
||||
|
||||
if (HasAtLoginFlag(AT_LOGIN_RENAME))
|
||||
{
|
||||
@@ -20611,7 +20610,7 @@ void Player::SaveToDB(LoginDatabaseTransaction loginTransaction, CharacterDataba
|
||||
stmt->setUInt32(index++, GetPrimarySpecialization());
|
||||
stmt->setUInt16(index++, (uint16)m_ExtraFlags);
|
||||
if (PetStable const* petStable = GetPetStable())
|
||||
stmt->setUInt32(index++, petStable->CurrentPet && petStable->CurrentPet->Health > 0 ? petStable->CurrentPet->PetNumber : 0); // summonedPetNumber
|
||||
stmt->setUInt32(index++, petStable->GetCurrentPet() && petStable->GetCurrentPet()->Health > 0 ? petStable->GetCurrentPet()->PetNumber : 0); // summonedPetNumber
|
||||
else
|
||||
stmt->setUInt32(index++, 0); // summonedPetNumber
|
||||
stmt->setUInt16(index++, (uint16)m_atLoginFlags);
|
||||
@@ -21955,49 +21954,22 @@ void Player::RemovePet(Pet* pet, PetSaveMode mode, bool returnreagent)
|
||||
|
||||
if (!pet)
|
||||
{
|
||||
if (mode == PET_SAVE_NOT_IN_SLOT && m_petStable && m_petStable->CurrentPet)
|
||||
{
|
||||
// Handle removing pet while it is in "temporarily unsummoned" state, for example on mount
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_PET_SLOT_BY_ID);
|
||||
stmt->setInt16(0, PET_SAVE_NOT_IN_SLOT);
|
||||
stmt->setUInt64(1, GetGUID().GetCounter());
|
||||
stmt->setUInt32(2, m_petStable->CurrentPet->PetNumber);
|
||||
CharacterDatabase.Execute(stmt);
|
||||
|
||||
m_petStable->UnslottedPets.push_back(std::move(*m_petStable->CurrentPet));
|
||||
m_petStable->CurrentPet.reset();
|
||||
}
|
||||
// Handle removing pet while it is in "temporarily unsummoned" state, for example on mount
|
||||
if (mode == PET_SAVE_NOT_IN_SLOT && m_petStable && m_petStable->CurrentPetIndex)
|
||||
m_petStable->CurrentPetIndex.reset();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
pet->CombatStop();
|
||||
|
||||
if (returnreagent)
|
||||
{
|
||||
switch (pet->GetEntry())
|
||||
{
|
||||
//warlock pets except imp are removed(?) when logging out
|
||||
case 1860:
|
||||
case 1863:
|
||||
case 417:
|
||||
case 17252:
|
||||
mode = PET_SAVE_NOT_IN_SLOT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// only if current pet in slot
|
||||
pet->SavePetToDB(mode);
|
||||
|
||||
ASSERT(m_petStable->CurrentPet && m_petStable->CurrentPet->PetNumber == pet->GetCharmInfo()->GetPetNumber());
|
||||
if (mode == PET_SAVE_NOT_IN_SLOT)
|
||||
{
|
||||
m_petStable->UnslottedPets.push_back(std::move(*m_petStable->CurrentPet));
|
||||
m_petStable->CurrentPet.reset();
|
||||
}
|
||||
else if (mode == PET_SAVE_AS_DELETED)
|
||||
m_petStable->CurrentPet.reset();
|
||||
PetStable::PetInfo const* currentPet = m_petStable->GetCurrentPet();
|
||||
ASSERT(currentPet && currentPet->PetNumber == pet->GetCharmInfo()->GetPetNumber());
|
||||
if (mode == PET_SAVE_NOT_IN_SLOT || mode == PET_SAVE_AS_DELETED)
|
||||
m_petStable->CurrentPetIndex.reset();
|
||||
// else if (stable slots) handled in opcode handlers due to required swaps
|
||||
// else (current pet) doesnt need to do anything
|
||||
|
||||
@@ -28288,7 +28260,7 @@ void Player::_LoadInstanceTimeRestrictions(PreparedQueryResult result)
|
||||
} while (result->NextRow());
|
||||
}
|
||||
|
||||
void Player::_LoadPetStable(PreparedQueryResult result)
|
||||
void Player::_LoadPetStable(uint32 summonedPetNumber, PreparedQueryResult result)
|
||||
{
|
||||
if (!result)
|
||||
return;
|
||||
@@ -28319,15 +28291,18 @@ void Player::_LoadPetStable(PreparedQueryResult result)
|
||||
petInfo.CreatedBySpellId = fields[13].GetUInt32();
|
||||
petInfo.Type = PetType(fields[14].GetUInt8());
|
||||
petInfo.SpecializationId = fields[15].GetUInt16();
|
||||
if (slot == PET_SAVE_AS_CURRENT)
|
||||
m_petStable->CurrentPet = std::move(petInfo);
|
||||
else if (slot >= PET_SAVE_FIRST_STABLE_SLOT && slot <= PET_SAVE_LAST_STABLE_SLOT)
|
||||
m_petStable->StabledPets[slot - 1] = std::move(petInfo);
|
||||
if (slot >= PET_SAVE_FIRST_ACTIVE_SLOT && slot < PET_SAVE_LAST_ACTIVE_SLOT)
|
||||
m_petStable->ActivePets[slot] = std::move(petInfo);
|
||||
else if (slot >= PET_SAVE_FIRST_STABLE_SLOT && slot < PET_SAVE_LAST_STABLE_SLOT)
|
||||
m_petStable->StabledPets[slot - PET_SAVE_FIRST_STABLE_SLOT] = std::move(petInfo);
|
||||
else if (slot == PET_SAVE_NOT_IN_SLOT)
|
||||
m_petStable->UnslottedPets.push_back(std::move(petInfo));
|
||||
|
||||
} while (result->NextRow());
|
||||
}
|
||||
|
||||
if (Pet::GetLoadPetInfo(*m_petStable, 0, summonedPetNumber, {}).first)
|
||||
m_temporaryUnsummonedPetNumber = summonedPetNumber;
|
||||
}
|
||||
|
||||
void Player::_SaveInstanceTimeRestrictions(CharacterDatabaseTransaction& trans)
|
||||
@@ -28665,18 +28640,21 @@ Guild const* Player::GetGuild() const
|
||||
return guildId ? sGuildMgr->GetGuildById(guildId) : nullptr;
|
||||
}
|
||||
|
||||
Pet* Player::SummonPet(uint32 entry, float x, float y, float z, float ang, PetType petType, uint32 duration)
|
||||
Pet* Player::SummonPet(uint32 entry, Optional<PetSaveMode> slot, float x, float y, float z, float ang, uint32 duration, bool* isNew /*= nullptr*/)
|
||||
{
|
||||
PetStable& petStable = GetOrInitPetStable();
|
||||
|
||||
Pet* pet = new Pet(this, petType);
|
||||
Pet* pet = new Pet(this, SUMMON_PET);
|
||||
|
||||
if (petType == SUMMON_PET && pet->LoadPetFromDB(this, entry, 0, false))
|
||||
if (pet->LoadPetFromDB(this, entry, 0, false, slot))
|
||||
{
|
||||
if (duration > 0)
|
||||
pet->SetDuration(duration);
|
||||
|
||||
return nullptr;
|
||||
if (isNew)
|
||||
*isNew = false;
|
||||
|
||||
return pet;
|
||||
}
|
||||
|
||||
// petentry == 0 for hunter "call pet" (current pet summoned if any)
|
||||
@@ -28686,6 +28664,8 @@ Pet* Player::SummonPet(uint32 entry, float x, float y, float z, float ang, PetTy
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// only SUMMON_PET are handled here
|
||||
|
||||
pet->Relocate(x, y, z, ang);
|
||||
if (!pet->IsPositionValid())
|
||||
{
|
||||
@@ -28703,7 +28683,7 @@ Pet* Player::SummonPet(uint32 entry, float x, float y, float z, float ang, PetTy
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (petType == SUMMON_PET && petStable.CurrentPet)
|
||||
if (petStable.GetCurrentPet())
|
||||
RemovePet(nullptr, PET_SAVE_NOT_IN_SLOT);
|
||||
|
||||
PhasingHandler::InheritPhaseShift(pet, this);
|
||||
@@ -28717,43 +28697,33 @@ Pet* Player::SummonPet(uint32 entry, float x, float y, float z, float ang, PetTy
|
||||
|
||||
SetMinion(pet, true);
|
||||
|
||||
switch (petType)
|
||||
{
|
||||
case SUMMON_PET:
|
||||
// this enables pet details window (Shift+P)
|
||||
pet->GetCharmInfo()->SetPetNumber(pet_number, true);
|
||||
pet->SetClass(CLASS_MAGE);
|
||||
pet->SetPetExperience(0);
|
||||
pet->SetPetNextLevelExperience(1000);
|
||||
pet->SetFullHealth();
|
||||
pet->SetFullPower(POWER_MANA);
|
||||
pet->SetPetNameTimestamp(uint32(GameTime::GetGameTime()));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// this enables pet details window (Shift+P)
|
||||
pet->GetCharmInfo()->SetPetNumber(pet_number, true);
|
||||
pet->SetClass(CLASS_MAGE);
|
||||
pet->SetPetExperience(0);
|
||||
pet->SetPetNextLevelExperience(1000);
|
||||
pet->SetFullHealth();
|
||||
pet->SetFullPower(POWER_MANA);
|
||||
pet->SetPetNameTimestamp(uint32(GameTime::GetGameTime()));
|
||||
|
||||
map->AddToMap(pet->ToCreature());
|
||||
|
||||
ASSERT(!petStable.CurrentPet && (petType != HUNTER_PET || !petStable.GetUnslottedHunterPet()));
|
||||
pet->FillPetInfo(&petStable.CurrentPet.emplace());
|
||||
ASSERT(!petStable.CurrentPetIndex);
|
||||
petStable.SetCurrentUnslottedPetIndex(petStable.UnslottedPets.size());
|
||||
pet->FillPetInfo(&petStable.UnslottedPets.emplace_back());
|
||||
|
||||
switch (petType)
|
||||
{
|
||||
case SUMMON_PET:
|
||||
pet->InitPetCreateSpells();
|
||||
pet->SavePetToDB(PET_SAVE_AS_CURRENT);
|
||||
PetSpellInitialize();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
pet->InitPetCreateSpells();
|
||||
pet->SavePetToDB(PET_SAVE_AS_CURRENT);
|
||||
PetSpellInitialize();
|
||||
|
||||
if (duration > 0)
|
||||
pet->SetDuration(duration);
|
||||
|
||||
//ObjectAccessor::UpdateObjectVisibility(pet);
|
||||
|
||||
if (isNew)
|
||||
*isNew = true;
|
||||
|
||||
return pet;
|
||||
}
|
||||
|
||||
|
||||
@@ -1211,7 +1211,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
|
||||
PetStable const* GetPetStable() const { return m_petStable.get(); }
|
||||
|
||||
Pet* GetPet() const;
|
||||
Pet* SummonPet(uint32 entry, float x, float y, float z, float ang, PetType petType, uint32 despwtime);
|
||||
Pet* SummonPet(uint32 entry, Optional<PetSaveMode> slot, float x, float y, float z, float ang, uint32 despwtime, bool* isNew = nullptr);
|
||||
void RemovePet(Pet* pet, PetSaveMode mode, bool returnreagent = false);
|
||||
void SendTameFailure(PetTameResult result);
|
||||
|
||||
@@ -2835,7 +2835,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
|
||||
void _LoadTalents(PreparedQueryResult result);
|
||||
void _LoadPvpTalents(PreparedQueryResult result);
|
||||
void _LoadInstanceTimeRestrictions(PreparedQueryResult result);
|
||||
void _LoadPetStable(PreparedQueryResult result);
|
||||
void _LoadPetStable(uint32 summonedPetNumber, PreparedQueryResult result);
|
||||
void _LoadCurrency(PreparedQueryResult result);
|
||||
void _LoadCUFProfiles(PreparedQueryResult result);
|
||||
|
||||
|
||||
@@ -10316,7 +10316,12 @@ bool Unit::InitTamedPet(Pet* pet, uint8 level, uint32 spell_id)
|
||||
{
|
||||
Player* player = ToPlayer();
|
||||
PetStable& petStable = player->GetOrInitPetStable();
|
||||
if (petStable.CurrentPet || petStable.GetUnslottedHunterPet())
|
||||
auto freeActiveSlotItr = std::find_if(petStable.ActivePets.begin(), petStable.ActivePets.end(), [](Optional<PetStable::PetInfo> const& petInfo)
|
||||
{
|
||||
return !petInfo.has_value();
|
||||
});
|
||||
|
||||
if (freeActiveSlotItr == petStable.ActivePets.end())
|
||||
return false;
|
||||
|
||||
pet->SetCreatorGUID(GetGUID());
|
||||
@@ -10340,7 +10345,8 @@ bool Unit::InitTamedPet(Pet* pet, uint8 level, uint32 spell_id)
|
||||
//pet->InitLevelupSpellsForLevel();
|
||||
pet->SetFullHealth();
|
||||
|
||||
pet->FillPetInfo(&petStable.CurrentPet.emplace());
|
||||
petStable.SetCurrentActivePetIndex(std::distance(petStable.ActivePets.begin(), freeActiveSlotItr));
|
||||
pet->FillPetInfo(&freeActiveSlotItr->emplace());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1146,6 +1146,10 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder)
|
||||
pCurrChar->SetGuildLevel(0);
|
||||
}
|
||||
|
||||
// Send stable contents to display icons on Call Pet spells
|
||||
if (pCurrChar->HasSpell(CALL_PET_SPELL_ID))
|
||||
SendStablePet(ObjectGuid::Empty);
|
||||
|
||||
pCurrChar->GetSession()->GetBattlePetMgr()->SendJournalLockStatus();
|
||||
|
||||
pCurrChar->SendInitialPacketsBeforeAddToMap();
|
||||
|
||||
@@ -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)
|
||||
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;
|
||||
|
||||
if (!srcPet || srcPet->Type != HUNTER_PET)
|
||||
{
|
||||
if (!petStable->StabledPets[freeSlot])
|
||||
SendPetStableResult(StableResult::InternalError);
|
||||
return;
|
||||
}
|
||||
|
||||
if (dstPet && dstPet->Type != HUNTER_PET)
|
||||
{
|
||||
SendPetStableResult(StableResult::InternalError);
|
||||
return;
|
||||
}
|
||||
|
||||
Optional<PetStable::PetInfo>* src = nullptr;
|
||||
Optional<PetStable::PetInfo>* dst = nullptr;
|
||||
Optional<int16> newActivePetIndex;
|
||||
|
||||
if (IsActivePetSlot(srcPetSlot) && IsActivePetSlot(dstPetSlot))
|
||||
{
|
||||
// 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];
|
||||
|
||||
if (petStable->GetCurrentActivePetIndex() == srcPetSlot)
|
||||
newActivePetIndex = dstPetSlot;
|
||||
else if (petStable->GetCurrentActivePetIndex() == dstPetSlot)
|
||||
newActivePetIndex = srcPetSlot;
|
||||
}
|
||||
else if (IsStabledPetSlot(srcPetSlot) && IsStabledPetSlot(dstPetSlot))
|
||||
{
|
||||
// stabled<->stabled: only swap StabledPets
|
||||
src = &petStable->StabledPets[srcPetSlot - PET_SAVE_FIRST_STABLE_SLOT];
|
||||
dst = &petStable->StabledPets[dstPetSlot - PET_SAVE_FIRST_STABLE_SLOT];
|
||||
}
|
||||
else if (IsActivePetSlot(srcPetSlot) && IsStabledPetSlot(dstPetSlot))
|
||||
{
|
||||
// active<->stabled: swap petStable contents and despawn active pet if it is involved in swap
|
||||
if (petStable->CurrentPetIndex == srcPetSlot)
|
||||
{
|
||||
if (pet)
|
||||
Pet* oldPet = _player->GetPet();
|
||||
if (oldPet && !oldPet->IsAlive())
|
||||
{
|
||||
// stable summoned pet
|
||||
_player->RemovePet(pet, PetSaveMode(PET_SAVE_FIRST_STABLE_SLOT + freeSlot));
|
||||
std::swap(petStable->StabledPets[freeSlot], petStable->CurrentPet);
|
||||
SendPetStableResult(StableResult::StableSuccess);
|
||||
SendPetStableResult(StableResult::InternalError);
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
_player->RemovePet(oldPet, PET_SAVE_NOT_IN_SLOT);
|
||||
}
|
||||
|
||||
if (dstPet)
|
||||
{
|
||||
CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(dstPet->CreatureId);
|
||||
if (!creatureInfo || !creatureInfo->IsTameable(_player->CanTameExoticPets()))
|
||||
{
|
||||
SendPetStableResult(StableResult::CantControlExotic);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
src = &petStable->ActivePets[srcPetSlot - PET_SAVE_FIRST_ACTIVE_SLOT];
|
||||
dst = &petStable->StabledPets[dstPetSlot - PET_SAVE_FIRST_STABLE_SLOT];
|
||||
}
|
||||
|
||||
// not free stable slot
|
||||
SendPetStableResult(StableResult::InvalidSlot);
|
||||
}
|
||||
|
||||
void WorldSession::HandleUnstablePet(WorldPacket& recvData)
|
||||
{
|
||||
ObjectGuid npcGUID;
|
||||
uint32 petnumber;
|
||||
|
||||
recvData >> npcGUID >> petnumber;
|
||||
|
||||
if (!CheckStableMaster(npcGUID))
|
||||
else if (IsStabledPetSlot(srcPetSlot) && IsActivePetSlot(dstPetSlot))
|
||||
{
|
||||
SendPetStableResult(StableResult::InternalError);
|
||||
return;
|
||||
}
|
||||
// stabled<->active: swap petStable contents and despawn active pet if it is involved in swap
|
||||
if (petStable->CurrentPetIndex == dstPetSlot)
|
||||
{
|
||||
Pet* oldPet = _player->GetPet();
|
||||
if (oldPet && !oldPet->IsAlive())
|
||||
{
|
||||
SendPetStableResult(StableResult::InternalError);
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
|
||||
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
|
||||
_player->RemovePet(oldPet, PET_SAVE_NOT_IN_SLOT);
|
||||
}
|
||||
|
||||
PetStable* petStable = GetPlayer()->GetPetStable();
|
||||
if (!petStable)
|
||||
{
|
||||
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;
|
||||
});
|
||||
|
||||
if (stabledPet == petStable->StabledPets.end())
|
||||
{
|
||||
SendPetStableResult(StableResult::InternalError);
|
||||
return;
|
||||
}
|
||||
|
||||
CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate((*stabledPet)->CreatureId);
|
||||
if (!creatureInfo || !creatureInfo->IsTameable(_player->CanTameExoticPets()))
|
||||
{
|
||||
// if problem in exotic pet
|
||||
if (creatureInfo && creatureInfo->IsTameable(true))
|
||||
CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(srcPet->CreatureId);
|
||||
if (!creatureInfo || !creatureInfo->IsTameable(_player->CanTameExoticPets()))
|
||||
{
|
||||
SendPetStableResult(StableResult::CantControlExotic);
|
||||
else
|
||||
SendPetStableResult(StableResult::InternalError);
|
||||
return;
|
||||
}
|
||||
|
||||
Pet* oldPet = _player->GetPet();
|
||||
if (oldPet)
|
||||
{
|
||||
// try performing a swap, client sends this packet instead of swap when starting from stabled slot
|
||||
if (!oldPet->IsAlive() || !oldPet->IsHunterPet())
|
||||
{
|
||||
SendPetStableResult(StableResult::InternalError);
|
||||
return;
|
||||
}
|
||||
|
||||
_player->RemovePet(oldPet, PetSaveMode(PET_SAVE_FIRST_STABLE_SLOT + std::distance(petStable->StabledPets.begin(), stabledPet)));
|
||||
src = &petStable->StabledPets[srcPetSlot - PET_SAVE_FIRST_STABLE_SLOT];
|
||||
dst = &petStable->ActivePets[dstPetSlot - PET_SAVE_FIRST_ACTIVE_SLOT];
|
||||
}
|
||||
else if (petStable->UnslottedPets.size() == 1)
|
||||
|
||||
CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
|
||||
|
||||
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);
|
||||
|
||||
if (dstPet)
|
||||
{
|
||||
if (petStable->CurrentPet || !petStable->UnslottedPets[0].Health || petStable->UnslottedPets[0].Type != HUNTER_PET)
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_PET_SLOT_BY_ID);
|
||||
stmt->setInt16(0, srcPetSlot);
|
||||
stmt->setUInt64(1, _player->GetGUID().GetCounter());
|
||||
stmt->setUInt32(2, dstPet->PetNumber);
|
||||
trans->Append(stmt);
|
||||
}
|
||||
|
||||
AddTransactionCallback(CharacterDatabase.AsyncCommitTransaction(trans)).AfterComplete(
|
||||
[this, currentPlayerGuid = _player->GetGUID(), src, dst, newActivePetIndex](bool success)
|
||||
{
|
||||
if (_player && _player->GetGUID() == currentPlayerGuid)
|
||||
{
|
||||
SendPetStableResult(StableResult::InternalError);
|
||||
return;
|
||||
if (success)
|
||||
{
|
||||
std::swap(*src, *dst);
|
||||
if (newActivePetIndex)
|
||||
GetPlayer()->GetPetStable()->SetCurrentActivePetIndex(*newActivePetIndex);
|
||||
|
||||
SendPetStableResult(StableResult::StableSuccess);
|
||||
}
|
||||
else
|
||||
{
|
||||
SendPetStableResult(StableResult::InternalError);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandleStableSwapPet(WorldPacket& recvData)
|
||||
{
|
||||
ObjectGuid npcGUID;
|
||||
uint32 petId;
|
||||
|
||||
recvData >> npcGUID >> petId;
|
||||
|
||||
if (!CheckStableMaster(npcGUID))
|
||||
{
|
||||
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())
|
||||
{
|
||||
SendPetStableResult(StableResult::InternalError);
|
||||
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)
|
||||
{
|
||||
SendPetStableResult(StableResult::InternalError);
|
||||
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;
|
||||
}
|
||||
|
||||
// summon unstabled pet
|
||||
Pet* newPet = new Pet(_player, HUNTER_PET);
|
||||
if (!newPet->LoadPetFromDB(_player, 0, petId, false))
|
||||
{
|
||||
delete newPet;
|
||||
SendPetStableResult(StableResult::InternalError);
|
||||
|
||||
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, 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->setUInt64(1, _player->GetGUID().GetCounter());
|
||||
stmt->setUInt32(2, petId);
|
||||
CharacterDatabase.Execute(stmt);
|
||||
|
||||
SendPetStableResult(StableResult::UnstableSuccess);
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandleRepairItemOpcode(WorldPackets::Item::RepairItem& packet)
|
||||
|
||||
@@ -538,7 +538,7 @@ void WorldSession::HandlePetRename(WorldPackets::Pet::PetRename& packet)
|
||||
if (!pet || !pet->IsPet() || ((Pet*)pet)->getPetType() != HUNTER_PET ||
|
||||
!pet->HasPetFlag(UNIT_PET_FLAG_CAN_BE_RENAMED) ||
|
||||
pet->GetOwnerGUID() != _player->GetGUID() || !pet->GetCharmInfo() ||
|
||||
!petStable || !petStable->CurrentPet || petStable->CurrentPet->PetNumber != pet->GetCharmInfo()->GetPetNumber())
|
||||
!petStable || !petStable->GetCurrentPet() || petStable->GetCurrentPet()->PetNumber != pet->GetCharmInfo()->GetPetNumber())
|
||||
return;
|
||||
|
||||
PetNameInvalidReason res = ObjectMgr::CheckPetName(name);
|
||||
@@ -560,8 +560,8 @@ void WorldSession::HandlePetRename(WorldPackets::Pet::PetRename& packet)
|
||||
|
||||
pet->RemovePetFlag(UNIT_PET_FLAG_CAN_BE_RENAMED);
|
||||
|
||||
petStable->CurrentPet->Name = name;
|
||||
petStable->CurrentPet->WasRenamed = true;
|
||||
petStable->GetCurrentPet()->Name = name;
|
||||
petStable->GetCurrentPet()->WasRenamed = true;
|
||||
|
||||
if (declinedname)
|
||||
{
|
||||
|
||||
@@ -224,5 +224,12 @@ void RequestStabledPets::Read()
|
||||
{
|
||||
_worldPacket >> StableMaster;
|
||||
}
|
||||
|
||||
void SetPetSlot::Read()
|
||||
{
|
||||
_worldPacket >> PetNumber;
|
||||
_worldPacket >> DestSlot;
|
||||
_worldPacket >> StableMaster;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -264,6 +264,18 @@ namespace WorldPackets
|
||||
|
||||
ObjectGuid StableMaster;
|
||||
};
|
||||
|
||||
class SetPetSlot final : public ClientPacket
|
||||
{
|
||||
public:
|
||||
SetPetSlot(WorldPacket&& packet) : ClientPacket(CMSG_SET_PET_SLOT, std::move(packet)) { }
|
||||
|
||||
void Read() override;
|
||||
|
||||
ObjectGuid StableMaster;
|
||||
uint32 PetNumber = 0;
|
||||
uint8 DestSlot = 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -808,7 +808,7 @@ void OpcodeTable::Initialize()
|
||||
DEFINE_HANDLER(CMSG_SET_LOOT_SPECIALIZATION, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSetLootSpecialization);
|
||||
DEFINE_HANDLER(CMSG_SET_PARTY_ASSIGNMENT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSetPartyAssignment);
|
||||
DEFINE_HANDLER(CMSG_SET_PARTY_LEADER, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleSetPartyLeaderOpcode);
|
||||
DEFINE_HANDLER(CMSG_SET_PET_SLOT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL);
|
||||
DEFINE_HANDLER(CMSG_SET_PET_SLOT, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleSetPetSlot);
|
||||
DEFINE_HANDLER(CMSG_SET_PLAYER_DECLINED_NAMES, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleSetPlayerDeclinedNames);
|
||||
DEFINE_HANDLER(CMSG_SET_PREFERRED_CEMETERY, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL);
|
||||
DEFINE_HANDLER(CMSG_SET_PVP, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSetPvP);
|
||||
|
||||
@@ -547,6 +547,7 @@ namespace WorldPackets
|
||||
class SpiritHealerActivate;
|
||||
class TrainerBuySpell;
|
||||
class RequestStabledPets;
|
||||
class SetPetSlot;
|
||||
}
|
||||
|
||||
namespace Party
|
||||
@@ -1403,9 +1404,7 @@ class TC_GAME_API WorldSession
|
||||
void HandleNpcTextQueryOpcode(WorldPackets::Query::QueryNPCText& packet);
|
||||
void HandleBinderActivateOpcode(WorldPackets::NPC::Hello& packet);
|
||||
void HandleRequestStabledPets(WorldPackets::NPC::RequestStabledPets& packet);
|
||||
void HandleStablePet(WorldPacket& recvPacket);
|
||||
void HandleUnstablePet(WorldPacket& recvPacket);
|
||||
void HandleStableSwapPet(WorldPacket& recvPacket);
|
||||
void HandleSetPetSlot(WorldPackets::NPC::SetPetSlot& setPetSlot);
|
||||
|
||||
void HandleCanDuel(WorldPackets::Duel::CanDuel& packet);
|
||||
void HandleDuelResponseOpcode(WorldPackets::Duel::DuelResponse& duelResponse);
|
||||
|
||||
@@ -5928,13 +5928,23 @@ SpellCastResult Spell::CheckCast(bool strict, int32* param1 /*= nullptr*/, int32
|
||||
}
|
||||
case SPELL_EFFECT_RESURRECT_PET:
|
||||
{
|
||||
Unit* unitCaster = m_caster->ToUnit();
|
||||
if (!unitCaster)
|
||||
Player* playerCaster = m_caster->ToPlayer();
|
||||
if (!playerCaster || !playerCaster->GetPetStable())
|
||||
return SPELL_FAILED_BAD_TARGETS;
|
||||
|
||||
Creature* pet = unitCaster->GetGuardianPet();
|
||||
Pet* pet = playerCaster->GetPet();
|
||||
if (pet && pet->IsAlive())
|
||||
return SPELL_FAILED_ALREADY_HAVE_SUMMON;
|
||||
|
||||
PetStable const* petStable = playerCaster->GetPetStable();
|
||||
auto deadPetItr = std::find_if(petStable->ActivePets.begin(), petStable->ActivePets.end(), [](Optional<PetStable::PetInfo> const& petInfo)
|
||||
{
|
||||
return petInfo && !petInfo->Health;
|
||||
});
|
||||
|
||||
if (deadPetItr == petStable->ActivePets.end())
|
||||
return SPELL_FAILED_BAD_TARGETS;
|
||||
|
||||
break;
|
||||
}
|
||||
// This is generic summon effect
|
||||
@@ -5998,17 +6008,27 @@ SpellCastResult Spell::CheckCast(bool strict, int32* param1 /*= nullptr*/, int32
|
||||
Player* playerCaster = unitCaster->ToPlayer();
|
||||
if (playerCaster && playerCaster->GetPetStable())
|
||||
{
|
||||
std::pair<PetStable::PetInfo const*, PetSaveMode> info = Pet::GetLoadPetInfo(*playerCaster->GetPetStable(), spellEffectInfo.MiscValue, 0, false);
|
||||
if (info.first)
|
||||
Optional<PetSaveMode> petSlot;
|
||||
if (!spellEffectInfo.MiscValue)
|
||||
{
|
||||
if (info.first->Type == HUNTER_PET)
|
||||
petSlot = PetSaveMode(spellEffectInfo.CalcValue());
|
||||
|
||||
// No pet can be summoned if any pet is dead
|
||||
for (Optional<PetStable::PetInfo> const& activePet : playerCaster->GetPetStable()->ActivePets)
|
||||
{
|
||||
if (!info.first->Health)
|
||||
if (activePet && !activePet->Health)
|
||||
{
|
||||
playerCaster->SendTameFailure(PetTameResult::Dead);
|
||||
return SPELL_FAILED_DONT_REPORT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<PetStable::PetInfo const*, PetSaveMode> info = Pet::GetLoadPetInfo(*playerCaster->GetPetStable(), spellEffectInfo.MiscValue, 0, petSlot);
|
||||
if (info.first)
|
||||
{
|
||||
if (info.first->Type == HUNTER_PET)
|
||||
{
|
||||
CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(info.first->CreatureId);
|
||||
if (!creatureInfo || !creatureInfo->IsTameable(playerCaster->CanTameExoticPets()))
|
||||
{
|
||||
@@ -6031,6 +6051,21 @@ SpellCastResult Spell::CheckCast(bool strict, int32* param1 /*= nullptr*/, int32
|
||||
|
||||
break;
|
||||
}
|
||||
case SPELL_EFFECT_DISMISS_PET:
|
||||
{
|
||||
Player* playerCaster = m_caster->ToPlayer();
|
||||
if (!playerCaster)
|
||||
return SPELL_FAILED_BAD_TARGETS;
|
||||
|
||||
Pet* pet = playerCaster->GetPet();
|
||||
if (!pet)
|
||||
return SPELL_FAILED_NO_PET;
|
||||
|
||||
if (!pet->IsAlive())
|
||||
return SPELL_FAILED_TARGETS_DEAD;
|
||||
|
||||
break;
|
||||
}
|
||||
case SPELL_EFFECT_SUMMON_PLAYER:
|
||||
{
|
||||
if (m_caster->GetTypeId() != TYPEID_PLAYER)
|
||||
|
||||
@@ -2626,27 +2626,35 @@ void Spell::EffectSummonPet()
|
||||
return;
|
||||
}
|
||||
|
||||
Optional<PetSaveMode> petSlot;
|
||||
if (!petentry)
|
||||
petSlot = PetSaveMode(damage);
|
||||
|
||||
float x, y, z;
|
||||
owner->GetClosePoint(x, y, z, owner->GetCombatReach());
|
||||
Pet* pet = owner->SummonPet(petentry, x, y, z, owner->GetOrientation(), SUMMON_PET, 0);
|
||||
bool isNew = false;
|
||||
Pet* pet = owner->SummonPet(petentry, petSlot, x, y, z, owner->GetOrientation(), 0, &isNew);
|
||||
if (!pet)
|
||||
return;
|
||||
|
||||
if (m_caster->GetTypeId() == TYPEID_UNIT)
|
||||
if (isNew)
|
||||
{
|
||||
if (m_caster->ToCreature()->IsTotem())
|
||||
pet->SetReactState(REACT_AGGRESSIVE);
|
||||
else
|
||||
pet->SetReactState(REACT_DEFENSIVE);
|
||||
if (m_caster->GetTypeId() == TYPEID_UNIT)
|
||||
{
|
||||
if (m_caster->ToCreature()->IsTotem())
|
||||
pet->SetReactState(REACT_AGGRESSIVE);
|
||||
else
|
||||
pet->SetReactState(REACT_DEFENSIVE);
|
||||
}
|
||||
|
||||
pet->SetCreatedBySpell(m_spellInfo->Id);
|
||||
|
||||
// generate new name for summon pet
|
||||
std::string new_name = sObjectMgr->GeneratePetName(petentry);
|
||||
if (!new_name.empty())
|
||||
pet->SetName(new_name);
|
||||
}
|
||||
|
||||
pet->SetCreatedBySpell(m_spellInfo->Id);
|
||||
|
||||
// generate new name for summon pet
|
||||
std::string new_name = sObjectMgr->GeneratePetName(petentry);
|
||||
if (!new_name.empty())
|
||||
pet->SetName(new_name);
|
||||
|
||||
ExecuteLogEffectSummonObject(SpellEffectName(effectInfo->Effect), pet);
|
||||
}
|
||||
|
||||
@@ -4252,9 +4260,17 @@ void Spell::EffectResurrectPet()
|
||||
|
||||
if (!player->GetPet())
|
||||
{
|
||||
PetStable const* petStable = player->GetPetStable();
|
||||
auto deadPetItr = std::find_if(petStable->ActivePets.begin(), petStable->ActivePets.end(), [](Optional<PetStable::PetInfo> const& petInfo)
|
||||
{
|
||||
return petInfo && !petInfo->Health;
|
||||
});
|
||||
|
||||
PetSaveMode slot = PetSaveMode(std::distance(petStable->ActivePets.begin(), deadPetItr));
|
||||
|
||||
// Position passed to SummonPet is irrelevant with current implementation,
|
||||
// pet will be relocated without using these coords in Pet::LoadPetFromDB
|
||||
player->SummonPet(0, 0.0f, 0.0f, 0.0f, 0.0f, SUMMON_PET, 0);
|
||||
player->SummonPet(0, slot, 0.0f, 0.0f, 0.0f, 0.0f, 0);
|
||||
hadPet = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -615,6 +615,15 @@ class spell_hun_tame_beast : public SpellScriptLoader
|
||||
{
|
||||
PrepareSpellScript(spell_hun_tame_beast_SpellScript);
|
||||
|
||||
static constexpr uint32 CallPetSpellIds[MAX_ACTIVE_PETS] =
|
||||
{
|
||||
883,
|
||||
83242,
|
||||
83243,
|
||||
83244,
|
||||
83245,
|
||||
};
|
||||
|
||||
SpellCastResult CheckCast()
|
||||
{
|
||||
Player* caster = GetCaster()->ToPlayer();
|
||||
@@ -633,13 +642,25 @@ class spell_hun_tame_beast : public SpellScriptLoader
|
||||
if (!target->GetCreatureTemplate()->IsTameable(caster->CanTameExoticPets()))
|
||||
return SPELL_FAILED_BAD_TARGETS;
|
||||
|
||||
PetStable const* petStable = caster->GetPetStable();
|
||||
if (petStable)
|
||||
if (PetStable const* petStable = caster->GetPetStable())
|
||||
{
|
||||
if (petStable->CurrentPet)
|
||||
if (petStable->CurrentPetIndex)
|
||||
return SPELL_FAILED_ALREADY_HAVE_SUMMON;
|
||||
|
||||
if (petStable->GetUnslottedHunterPet())
|
||||
auto freeSlotItr = std::find_if(petStable->ActivePets.begin(), petStable->ActivePets.end(), [](Optional<PetStable::PetInfo> const& petInfo)
|
||||
{
|
||||
return !petInfo.has_value();
|
||||
});
|
||||
|
||||
if (freeSlotItr == petStable->ActivePets.end())
|
||||
{
|
||||
caster->SendTameFailure(PetTameResult::TooMany);
|
||||
return SPELL_FAILED_DONT_REPORT;
|
||||
}
|
||||
|
||||
// Check for known Call Pet X spells
|
||||
std::size_t freeSlotIndex = std::distance(petStable->ActivePets.begin(), freeSlotItr);
|
||||
if (!caster->HasSpell(CallPetSpellIds[freeSlotIndex]))
|
||||
{
|
||||
caster->SendTameFailure(PetTameResult::TooMany);
|
||||
return SPELL_FAILED_DONT_REPORT;
|
||||
|
||||
Reference in New Issue
Block a user