aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/Entities
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2022-02-02 00:08:37 +0100
committerShauren <shauren.trinity@gmail.com>2022-02-02 00:08:37 +0100
commit950db60435e7e513633ff5b22ad7f0ed8b1147e4 (patch)
treecb5b9e47570528dea0374f804f829512c89a5410 /src/server/game/Entities
parentd6a2461fc77f156dfe9e62c1c2387815c27e43de (diff)
Core/Pets: Updated pet summoning for latest client version (5 Call Pet spells and stable size 200)
Diffstat (limited to 'src/server/game/Entities')
-rw-r--r--src/server/game/Entities/Pet/Pet.cpp92
-rw-r--r--src/server/game/Entities/Pet/Pet.h4
-rw-r--r--src/server/game/Entities/Pet/PetDefines.h48
-rw-r--r--src/server/game/Entities/Player/Player.cpp118
-rw-r--r--src/server/game/Entities/Player/Player.h4
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp10
6 files changed, 140 insertions, 136 deletions
diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp
index 8a2ffc81a07..88de7a45c84 100644
--- a/src/server/game/Entities/Pet/Pet.cpp
+++ b/src/server/game/Entities/Pet/Pet.cpp
@@ -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());
-
- std::swap(*stabledPet, petStable->CurrentPet);
+ ASSERT(!petStable->CurrentPetIndex);
+ ASSERT(activePetItr != petStable->ActivePets.end());
- // 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);
diff --git a/src/server/game/Entities/Pet/Pet.h b/src/server/game/Entities/Pet/Pet.h
index 9456dab4448..8dc3da1d1ea 100644
--- a/src/server/game/Entities/Pet/Pet.h
+++ b/src/server/game/Entities/Pet/Pet.h
@@ -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;
diff --git a/src/server/game/Entities/Pet/PetDefines.h b/src/server/game/Entities/Pet/PetDefines.h
index 5bdcc1ee67c..0b1048e79d0 100644
--- a/src/server/game/Entities/Pet/PetDefines.h
+++ b/src/server/game/Entities/Pet/PetDefines.h
@@ -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
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index e26ecd7528d..ed97075d7e1 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -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;
}
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 471720327f7..666db7ca213 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -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);
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index c62211a1a1d..b339b55e7d1 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -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;
}