aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/Entities
diff options
context:
space:
mode:
authorMitchesD <majklprofik@seznam.cz>2016-10-01 13:48:16 +0200
committerShauren <shauren.trinity@gmail.com>2016-10-01 13:48:16 +0200
commitad3da9c971640c4ecc00cf4794ccc08057da7d38 (patch)
treedd17307ceb82d116f37e1aea5443e3c4e0914f19 /src/server/game/Entities
parent20f0db0e470342f6d599818f207ce1a6d9dcbadc (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.cpp154
-rw-r--r--src/server/game/Entities/Player/CollectionMgr.h20
-rw-r--r--src/server/game/Entities/Player/Player.cpp11
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;