Core/BattlePets: Misc fixes (#26964)

* Define BattlePetSpeciesFlags enum class.
* Define BattlePetDbFlags enum class.
* Added check to prevent the pet from being caged if its species has flag BattlePetSpeciesFlags::NotTradable.
* Added check to prevent the pet from being caged if it's in battle pet slots.
* Added check to prevent the pet from being caged if its health is below maximum health.
* Only add pet if the species has flag BattlePetSpeciesFlags::WellKnown.
* Added function to check flag BattlePetSpeciesFlags::LegacyAccountUnique to avoid learning copies of unique pets.
* Implemented CMSG_BATTLE_PET_CLEAR_FANFARE.
This commit is contained in:
Meji
2021-09-29 22:26:25 +02:00
committed by GitHub
parent f507737ecf
commit de4eaa0de9
10 changed files with 116 additions and 9 deletions

View File

@@ -196,9 +196,9 @@ void BattlePetMgr::LoadFromDB(PreparedQueryResult pets, PreparedQueryResult slot
if (BattlePetSpeciesEntry const* speciesEntry = sBattlePetSpeciesStore.LookupEntry(species))
{
if (GetPetCount(species) >= MAX_BATTLE_PETS_PER_SPECIES)
if (HasMaxPetCount(speciesEntry))
{
TC_LOG_ERROR("misc", "Battlenet account with id %u has more than 3 battle pets of species %u", _owner->GetBattlenetAccountId(), species);
TC_LOG_ERROR("misc", "Battlenet account with id %u has more than maximum battle pets of species %u", _owner->GetBattlenetAccountId(), species);
continue;
}
@@ -314,6 +314,9 @@ void BattlePetMgr::AddPet(uint32 species, uint32 creatureId, uint16 breed, uint8
if (!battlePetSpecies) // should never happen
return;
if (!battlePetSpecies->GetFlags().HasFlag(BattlePetSpeciesFlags::WellKnown)) // Not learnable
return;
BattlePet pet;
pet.PacketInfo.Guid = ObjectGuid::Create<HighGuid::BattlePet>(sObjectMgr->GetGenerator<HighGuid::BattlePet>().Generate());
pet.PacketInfo.Species = species;
@@ -351,6 +354,27 @@ void BattlePetMgr::RemovePet(ObjectGuid guid)
_owner->GetPlayer()->RemoveSpell(speciesEntry->SummonSpellID);*/
}
void BattlePetMgr::ClearFanfare(ObjectGuid guid)
{
BattlePet* pet = GetPet(guid);
if (!pet)
return;
pet->PacketInfo.Flags &= ~uint16(BattlePetDbFlags::FanfareNeeded);
if (pet->SaveInfo != BATTLE_PET_NEW)
pet->SaveInfo = BATTLE_PET_CHANGED;
}
bool BattlePetMgr::IsPetInSlot(ObjectGuid guid)
{
for (WorldPackets::BattlePet::BattlePetSlot const& slot : _slots)
if (slot.Pet.Guid == guid)
return true;
return false;
}
uint8 BattlePetMgr::GetPetCount(uint32 species) const
{
return uint8(std::count_if(_pets.begin(), _pets.end(), [species](std::pair<uint64 const, BattlePet> const& pet)
@@ -359,6 +383,13 @@ uint8 BattlePetMgr::GetPetCount(uint32 species) const
}));
}
bool BattlePetMgr::HasMaxPetCount(BattlePetSpeciesEntry const* speciesEntry) const
{
uint8 maxPetsPerSpecies = speciesEntry->GetFlags().HasFlag(BattlePetSpeciesFlags::LegacyAccountUnique) ? 1 : DEFAULT_MAX_BATTLE_PETS_PER_SPECIES;
return GetPetCount(speciesEntry->ID) >= maxPetsPerSpecies;
}
uint32 BattlePetMgr::GetPetUniqueSpeciesCount() const
{
std::set<uint32> speciesIds;
@@ -399,6 +430,16 @@ void BattlePetMgr::CageBattlePet(ObjectGuid guid)
if (!pet)
return;
if (BattlePetSpeciesEntry const* battlePetSpecies = sBattlePetSpeciesStore.LookupEntry(pet->PacketInfo.Species))
if (battlePetSpecies->GetFlags().HasFlag(BattlePetSpeciesFlags::NotTradable))
return;
if (IsPetInSlot(guid))
return;
if (pet->PacketInfo.Health < pet->PacketInfo.MaxHealth)
return;
ItemPosCountVec dest;
if (_owner->GetPlayer()->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, BATTLE_PET_CAGE_ITEM_ID, 1) != EQUIP_ERR_OK)
@@ -413,7 +454,6 @@ void BattlePetMgr::CageBattlePet(ObjectGuid guid)
item->SetModifier(ITEM_MODIFIER_BATTLE_PET_LEVEL, pet->PacketInfo.Level);
item->SetModifier(ITEM_MODIFIER_BATTLE_PET_DISPLAY_ID, pet->PacketInfo.CreatureID);
// FIXME: "You create: ." - item name missing in chat
_owner->GetPlayer()->SendNewItem(item, 1, true, false);
RemovePet(guid);

View File

@@ -22,14 +22,32 @@
#include "DatabaseEnvFwd.h"
#include <unordered_map>
struct BattlePetSpeciesEntry;
enum BattlePetMisc
{
MAX_PET_BATTLE_SLOTS = 3,
MAX_BATTLE_PETS_PER_SPECIES = 3,
BATTLE_PET_CAGE_ITEM_ID = 82800,
DEFAULT_SUMMON_BATTLE_PET_SPELL = 118301
MAX_PET_BATTLE_SLOTS = 3,
DEFAULT_MAX_BATTLE_PETS_PER_SPECIES = 3,
BATTLE_PET_CAGE_ITEM_ID = 82800,
DEFAULT_SUMMON_BATTLE_PET_SPELL = 118301
};
enum class BattlePetDbFlags : uint16
{
None = 0x000,
Favorite = 0x001,
Converted = 0x002,
Revoked = 0x004,
LockedForConvert = 0x008,
Ability0Selection = 0x010,
Ability1Selection = 0x020,
Ability2Selection = 0x040,
FanfareNeeded = 0x080,
DisplayOverridden = 0x100
};
DEFINE_ENUM_FLAG(BattlePetDbFlags);
// 6.2.4
enum FlagsControlType
{
@@ -112,8 +130,11 @@ public:
BattlePet* GetPet(ObjectGuid guid);
void AddPet(uint32 species, uint32 creatureId, uint16 breed, uint8 quality, uint16 level = 1);
void RemovePet(ObjectGuid guid);
void ClearFanfare(ObjectGuid guid);
bool IsPetInSlot(ObjectGuid guid);
uint8 GetPetCount(uint32 species) const;
bool HasMaxPetCount(BattlePetSpeciesEntry const* speciesEntry) const;
uint32 GetPetUniqueSpeciesCount() const;
WorldPackets::BattlePet::BattlePetSlot* GetSlot(uint8 slot) { return slot < _slots.size() ? &_slots[slot] : nullptr; }

View File

@@ -479,6 +479,8 @@ struct BattlePetSpeciesEntry
int32 CardUIModelSceneID;
int32 LoadoutUIModelSceneID;
int32 CovenantID;
EnumFlag<BattlePetSpeciesFlags> GetFlags() const { return static_cast<BattlePetSpeciesFlags>(Flags); }
};
struct BattlePetSpeciesStateEntry

View File

@@ -193,6 +193,28 @@ enum AzeriteTierUnlockSetFlags
#define BATTLE_PET_SPECIES_MAX_ID 3159
enum class BattlePetSpeciesFlags : uint16
{
NoRename = 0x0001,
WellKnown = 0x0002,
NotAccountWide = 0x0004,
Capturable = 0x0008,
NotTradable = 0x0010,
HideFromJournal = 0x0020,
LegacyAccountUnique = 0x0040,
CantBattle = 0x0080,
HordeOnly = 0x0100,
AllianceOnly = 0x0200,
Boss = 0x0400,
RandomDisplay = 0x0800,
NoLicenseRequired = 0x1000,
AddsAllowedWithBoss = 0x2000,
HideUntilLearned = 0x4000,
MatchPlayerHighPetLevel = 0x8000
};
DEFINE_ENUM_FLAG(BattlePetSpeciesFlags);
enum class BattlemasterListFlags : uint32
{
InternalOnly = 0x01,

View File

@@ -62,6 +62,11 @@ void WorldSession::HandleBattlePetSetFlags(WorldPackets::BattlePet::BattlePetSet
}
}
void WorldSession::HandleBattlePetClearFanfare(WorldPackets::BattlePet::BattlePetClearFanfare& battlePetClearFanfare)
{
GetBattlePetMgr()->ClearFanfare(battlePetClearFanfare.PetGuid);
}
void WorldSession::HandleCageBattlePet(WorldPackets::BattlePet::CageBattlePet& cageBattlePet)
{
GetBattlePetMgr()->CageBattlePet(cageBattlePet.PetGuid);

View File

@@ -140,6 +140,11 @@ void WorldPackets::BattlePet::BattlePetSetFlags::Read()
ControlType = _worldPacket.ReadBits(2);
}
void WorldPackets::BattlePet::BattlePetClearFanfare::Read()
{
_worldPacket >> PetGuid;
}
void WorldPackets::BattlePet::CageBattlePet::Read()
{
_worldPacket >> PetGuid;

View File

@@ -158,6 +158,16 @@ namespace WorldPackets
uint8 ControlType = 0;
};
class BattlePetClearFanfare final : public ClientPacket
{
public:
BattlePetClearFanfare(WorldPacket&& packet) : ClientPacket(CMSG_BATTLE_PET_CLEAR_FANFARE, std::move(packet)) { }
void Read() override;
ObjectGuid PetGuid;
};
class CageBattlePet final : public ClientPacket
{
public:

View File

@@ -206,7 +206,7 @@ void OpcodeTable::Initialize()
DEFINE_HANDLER(CMSG_BATTLE_PAY_REQUEST_PRICE_INFO, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL);
DEFINE_HANDLER(CMSG_BATTLE_PAY_START_PURCHASE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL);
DEFINE_HANDLER(CMSG_BATTLE_PAY_START_VAS_PURCHASE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL);
DEFINE_HANDLER(CMSG_BATTLE_PET_CLEAR_FANFARE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL);
DEFINE_HANDLER(CMSG_BATTLE_PET_CLEAR_FANFARE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleBattlePetClearFanfare);
DEFINE_HANDLER(CMSG_BATTLE_PET_DELETE_PET, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleBattlePetDeletePet);
DEFINE_HANDLER(CMSG_BATTLE_PET_DELETE_PET_CHEAT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL);
DEFINE_HANDLER(CMSG_BATTLE_PET_MODIFY_NAME, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleBattlePetModifyName);

View File

@@ -194,6 +194,7 @@ namespace WorldPackets
class BattlePetModifyName;
class BattlePetDeletePet;
class BattlePetSetFlags;
class BattlePetClearFanfare;
class BattlePetSummon;
class CageBattlePet;
}
@@ -1756,6 +1757,7 @@ class TC_GAME_API WorldSession
void HandleBattlePetModifyName(WorldPackets::BattlePet::BattlePetModifyName& battlePetModifyName);
void HandleBattlePetDeletePet(WorldPackets::BattlePet::BattlePetDeletePet& battlePetDeletePet);
void HandleBattlePetSetFlags(WorldPackets::BattlePet::BattlePetSetFlags& battlePetSetFlags);
void HandleBattlePetClearFanfare(WorldPackets::BattlePet::BattlePetClearFanfare& battlePetClearFanfare);
void HandleBattlePetSummon(WorldPackets::BattlePet::BattlePetSummon& battlePetSummon);
void HandleCageBattlePet(WorldPackets::BattlePet::CageBattlePet& cageBattlePet);

View File

@@ -5607,7 +5607,7 @@ void Spell::EffectUncageBattlePet()
return;
}
if (battlePetMgr->GetPetCount(speciesId) >= MAX_BATTLE_PETS_PER_SPECIES)
if (battlePetMgr->HasMaxPetCount(speciesEntry))
{
battlePetMgr->SendError(BATTLEPETRESULT_CANT_HAVE_MORE_PETS_OF_THAT_TYPE, creatureId); // or speciesEntry.CreatureID
SendCastResult(SPELL_FAILED_CANT_ADD_BATTLE_PET);