diff options
| author | MitchesD <majklprofik@seznam.cz> | 2016-10-01 13:48:16 +0200 |
|---|---|---|
| committer | Shauren <shauren.trinity@gmail.com> | 2016-10-01 13:48:16 +0200 |
| commit | ad3da9c971640c4ecc00cf4794ccc08057da7d38 (patch) | |
| tree | dd17307ceb82d116f37e1aea5443e3c4e0914f19 /src/server/game/Entities | |
| parent | 20f0db0e470342f6d599818f207ce1a6d9dcbadc (diff) | |
Core/Player: Implemented account wide mounts
Closes #17369
Diffstat (limited to 'src/server/game/Entities')
| -rw-r--r-- | src/server/game/Entities/Player/CollectionMgr.cpp | 154 | ||||
| -rw-r--r-- | src/server/game/Entities/Player/CollectionMgr.h | 20 | ||||
| -rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 11 |
3 files changed, 179 insertions, 6 deletions
diff --git a/src/server/game/Entities/Player/CollectionMgr.cpp b/src/server/game/Entities/Player/CollectionMgr.cpp index 297c67e3acf..b8b438ab64f 100644 --- a/src/server/game/Entities/Player/CollectionMgr.cpp +++ b/src/server/game/Entities/Player/CollectionMgr.cpp @@ -16,10 +16,53 @@ */ #include "CollectionMgr.h" +#include "MiscPackets.h" #include "ObjectMgr.h" #include "Player.h" #include "TransmogrificationPackets.h" +namespace +{ + MountDefinitionMap FactionSpecificMounts; +} + +void CollectionMgr::LoadMountDefinitions() +{ + uint32 oldMSTime = getMSTime(); + + QueryResult result = WorldDatabase.Query("SELECT spellId, otherFactionSpellId FROM mount_definitions"); + + if (!result) + { + TC_LOG_INFO("server.loading", ">> Loaded 0 mount definitions. DB table `mount_definitions` is empty."); + return; + } + + do + { + Field* fields = result->Fetch(); + + uint32 spellId = fields[0].GetUInt32(); + uint32 otherFactionSpellId = fields[1].GetUInt32(); + + if (!sDB2Manager.GetMount(spellId)) + { + TC_LOG_ERROR("sql.sql", "Mount spell %u defined in `mount_definitions` does not exist in Mount.db2, skipped", spellId); + continue; + } + + if (otherFactionSpellId && !sDB2Manager.GetMount(otherFactionSpellId)) + { + TC_LOG_ERROR("sql.sql", "otherFactionSpellId %u defined in `mount_definitions` for spell %u does not exist in Mount.db2, skipped", otherFactionSpellId, spellId); + continue; + } + + FactionSpecificMounts[spellId] = otherFactionSpellId; + } while (result->NextRow()); + + TC_LOG_INFO("server.loading", ">> Loaded " SZFMTD " mount definitions in %u ms", FactionSpecificMounts.size(), GetMSTimeDiffToNow(oldMSTime)); +} + CollectionMgr::CollectionMgr(WorldSession* owner) : _owner(owner), _appearances() { } @@ -195,7 +238,7 @@ void CollectionMgr::UpgradeHeirloom(uint32 itemId, uint32 castItem) // Get heirloom offset to update only one part of dynamic field std::vector<uint32> const& fields = player->GetDynamicValues(PLAYER_DYNAMIC_FIELD_HEIRLOOMS); - uint8 offset = std::find(fields.begin(), fields.end(), itemId) - fields.begin(); + uint8 offset = uint8(std::find(fields.begin(), fields.end(), itemId) - fields.begin()); player->SetDynamicValue(PLAYER_DYNAMIC_FIELD_HEIRLOOM_FLAGS, offset, flags); itr->second.flags = flags; @@ -235,7 +278,7 @@ void CollectionMgr::CheckHeirloomUpgrades(Item* item) if (newItemId) { std::vector<uint32> const& fields = player->GetDynamicValues(PLAYER_DYNAMIC_FIELD_HEIRLOOMS); - uint8 offset = std::find(fields.begin(), fields.end(), itr->first) - fields.begin(); + uint8 offset = uint8(std::find(fields.begin(), fields.end(), itr->first) - fields.begin()); player->SetDynamicValue(PLAYER_DYNAMIC_FIELD_HEIRLOOMS, offset, newItemId); player->SetDynamicValue(PLAYER_DYNAMIC_FIELD_HEIRLOOM_FLAGS, offset, 0); @@ -274,6 +317,107 @@ bool CollectionMgr::CanApplyHeirloomXpBonus(uint32 itemId, uint32 level) return level <= 60; } +void CollectionMgr::LoadMounts() +{ + for (auto const& m : _mounts) + AddMount(m.first, m.second, false, false); +} + +void CollectionMgr::LoadAccountMounts(PreparedQueryResult result) +{ + if (!result) + return; + + do + { + Field* fields = result->Fetch(); + uint32 mountSpellId = fields[0].GetUInt32(); + MountStatusFlags flags = MountStatusFlags(fields[1].GetUInt8()); + + if (!sDB2Manager.GetMount(mountSpellId)) + continue; + + _mounts[mountSpellId] = flags; + } while (result->NextRow()); +} + +void CollectionMgr::SaveAccountMounts(SQLTransaction& trans) +{ + for (auto const& mount : _mounts) + { + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_REP_ACCOUNT_MOUNTS); + stmt->setUInt32(0, _owner->GetBattlenetAccountId()); + stmt->setUInt32(1, mount.first); + stmt->setUInt8(2, mount.second); + trans->Append(stmt); + } +} + +bool CollectionMgr::AddMount(uint32 spellId, MountStatusFlags flags, bool factionMount /*= false*/, bool learned /*= false*/) +{ + Player* player = _owner->GetPlayer(); + if (!player) + return false; + + MountEntry const* mount = sDB2Manager.GetMount(spellId); + if (!mount) + return false; + + MountDefinitionMap::const_iterator itr = FactionSpecificMounts.find(spellId); + if (itr != FactionSpecificMounts.end() && !factionMount) + AddMount(itr->second, flags, true, learned); + + _mounts.insert(MountContainer::value_type(spellId, flags)); + + // Mount condition only applies to using it, should still learn it. + if (mount->PlayerConditionId) + { + PlayerConditionEntry const* playerCondition = sPlayerConditionStore.LookupEntry(mount->PlayerConditionId); + if (!ConditionMgr::IsPlayerMeetingCondition(player, playerCondition)) + return false; + } + + if (!learned) + { + if (!factionMount) + SendSingleMountUpdate(std::make_pair(spellId, flags)); + if (!player->HasSpell(spellId)) + player->LearnSpell(spellId, true); + } + + return true; +} + +void CollectionMgr::MountSetFavorite(uint32 spellId, bool favorite) +{ + auto itr = _mounts.find(spellId); + if (itr == _mounts.end()) + return; + + if (favorite) + itr->second = MountStatusFlags(itr->second | MOUNT_IS_FAVORITE); + else + itr->second = MountStatusFlags(itr->second & ~MOUNT_IS_FAVORITE); + + SendSingleMountUpdate(*itr); +} + +void CollectionMgr::SendSingleMountUpdate(std::pair<uint32, MountStatusFlags> mount) +{ + Player* player = _owner->GetPlayer(); + if (!player) + return; + + // Temporary container, just need to store only selected mount + MountContainer tempMounts; + tempMounts.insert(mount); + + WorldPackets::Misc::AccountMountUpdate mountUpdate; + mountUpdate.IsFullUpdate = false; + mountUpdate.Mounts = &tempMounts; + player->SendDirectMessage(mountUpdate.Write()); +} + struct DynamicBitsetBlockOutputIterator : public std::iterator<std::output_iterator_tag, void, void, void, void> { explicit DynamicBitsetBlockOutputIterator(std::function<void(uint32)>&& action) : _action(std::forward<std::function<void(uint32)>>(action)) { } @@ -351,7 +495,7 @@ void CollectionMgr::SaveAccountItemAppearances(SQLTransaction& trans) if (blockValue) // this table is only appended/bits are set (never cleared) so don't save empty blocks { PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_BNET_ITEM_APPEARANCES); - stmt->setUInt32(0, GetOwner()->GetBattlenetAccountId()); + stmt->setUInt32(0, _owner->GetBattlenetAccountId()); stmt->setUInt16(1, blockIndex); stmt->setUInt32(2, blockValue); trans->Append(stmt); @@ -515,7 +659,7 @@ void CollectionMgr::AddItemAppearance(ItemModifiedAppearanceEntry const* itemMod { if (_appearances.size() <= itemModifiedAppearance->ID) { - uint32 numBlocks = _appearances.num_blocks(); + std::size_t numBlocks = _appearances.num_blocks(); _appearances.resize(itemModifiedAppearance->ID + 1); numBlocks = _appearances.num_blocks() - numBlocks; while (numBlocks--) @@ -619,7 +763,7 @@ void CollectionMgr::SendFavoriteAppearances() const transmogCollectionUpdate.FavoriteAppearances.reserve(_favoriteAppearances.size()); for (auto itr = _favoriteAppearances.begin(); itr != _favoriteAppearances.end(); ++itr) if (itr->second != FavoriteAppearanceState::Removed) - transmogCollectionUpdate.FavoriteAppearances.push_back(itr->first); + transmogCollectionUpdate.FavoriteAppearances.push_back(itr->first); _owner->SendPacket(transmogCollectionUpdate.Write()); } diff --git a/src/server/game/Entities/Player/CollectionMgr.h b/src/server/game/Entities/Player/CollectionMgr.h index 7090995689d..f78a88950ba 100644 --- a/src/server/game/Entities/Player/CollectionMgr.h +++ b/src/server/game/Entities/Player/CollectionMgr.h @@ -48,12 +48,22 @@ struct HeirloomData typedef std::map<uint32, bool> ToyBoxContainer; typedef std::map<uint32, HeirloomData> HeirloomContainer; +enum MountStatusFlags : uint8 +{ + MOUNT_STATUS_NONE = 0x00, + MOUNT_NEEDS_FANFARE = 0x01, + MOUNT_IS_FAVORITE = 0x02 +}; + +typedef std::map<uint32, MountStatusFlags> MountContainer; +typedef std::unordered_map<uint32, uint32> MountDefinitionMap; + class TC_GAME_API CollectionMgr { public: explicit CollectionMgr(WorldSession* owner); - WorldSession* GetOwner() const { return _owner; } + static void LoadMountDefinitions(); // Account-wide toys void LoadToys(); @@ -83,6 +93,13 @@ public: HeirloomContainer const& GetAccountHeirlooms() const { return _heirlooms; } // Account-wide mounts + void LoadMounts(); + void LoadAccountMounts(PreparedQueryResult result); + void SaveAccountMounts(SQLTransaction& trans); + bool AddMount(uint32 spellId, MountStatusFlags flags, bool factionMount = false, bool learned = false); + void MountSetFavorite(uint32 spellId, bool favorite); + void SendSingleMountUpdate(std::pair<uint32, MountStatusFlags> mount); + MountContainer const& GetAccountMounts() const { return _mounts; } // Appearances void LoadItemAppearances(); @@ -114,6 +131,7 @@ private: ToyBoxContainer _toys; HeirloomContainer _heirlooms; + MountContainer _mounts; boost::dynamic_bitset<uint32> _appearances; std::unordered_map<uint32, std::unordered_set<ObjectGuid>> _temporaryAppearances; std::unordered_map<uint32, FavoriteAppearanceState> _favoriteAppearances; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index f4c2188c18a..81566daa587 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -3149,6 +3149,10 @@ bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent UpdateCriteria(CRITERIA_TYPE_LEARN_SPELL, spellId); } + // needs to be when spell is already learned, to prevent infinite recursion crashes + if (sDB2Manager.GetMount(spellId)) + GetSession()->GetCollectionMgr()->AddMount(spellId, MOUNT_STATUS_NONE, false, IsInWorld() ? false : true); + // return true (for send learn packet) only if spell active (in case ranked spells) and not replace old spell return active && !disabled && !superceded_old; } @@ -17551,6 +17555,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) _LoadSpells(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_SPELLS)); GetSession()->GetCollectionMgr()->LoadToys(); GetSession()->GetCollectionMgr()->LoadHeirlooms(); + GetSession()->GetCollectionMgr()->LoadMounts(); GetSession()->GetCollectionMgr()->LoadItemAppearances(); LearnSpecializationSpells(); @@ -19604,6 +19609,7 @@ void Player::SaveToDB(bool create /*=false*/) GetSession()->GetCollectionMgr()->SaveAccountToys(trans); GetSession()->GetBattlePetMgr()->SaveToDB(trans); GetSession()->GetCollectionMgr()->SaveAccountHeirlooms(trans); + GetSession()->GetCollectionMgr()->SaveAccountMounts(trans); GetSession()->GetCollectionMgr()->SaveAccountItemAppearances(trans); stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_BNET_LAST_PLAYER_CHARACTERS); @@ -23041,6 +23047,11 @@ void Player::SendInitialPacketsBeforeAddToMap() SendDirectMessage(worldServerInfo.Write()); // SMSG_ACCOUNT_MOUNT_UPDATE + WorldPackets::Misc::AccountMountUpdate mountUpdate; + mountUpdate.IsFullUpdate = true; + mountUpdate.Mounts = &GetSession()->GetCollectionMgr()->GetAccountMounts(); + SendDirectMessage(mountUpdate.Write()); + // SMSG_ACCOUNT_TOYS_UPDATE WorldPackets::Toy::AccountToysUpdate toysUpdate; toysUpdate.IsFullUpdate = true; |
