From 286294a108c48d7d17fee41aafbbc2b616201a8d Mon Sep 17 00:00:00 2001 From: hondacrx Date: Tue, 14 Jun 2022 23:07:23 -0400 Subject: [PATCH] Core/Transmog: Implemented Transmog Illusions + Spelleffect to unlock them Port From (https://github.com/TrinityCore/TrinityCore/commit/125ada42f6be220a52315d06d61e472a2ba83395) --- .../Database/Databases/LoginDatabase.cs | 7 +- .../Game/Entities/Player/CollectionManager.cs | 161 +++++++++++++----- Source/Game/Entities/Player/Player.DB.cs | 2 + Source/Game/Entities/Player/Player.cs | 4 + Source/Game/Server/WorldSession.cs | 8 +- Source/Game/Spells/SpellEffects.cs | 13 ++ 6 files changed, 152 insertions(+), 43 deletions(-) diff --git a/Source/Framework/Database/Databases/LoginDatabase.cs b/Source/Framework/Database/Databases/LoginDatabase.cs index 646e9977e..a38ed3ebd 100644 --- a/Source/Framework/Database/Databases/LoginDatabase.cs +++ b/Source/Framework/Database/Databases/LoginDatabase.cs @@ -170,11 +170,12 @@ namespace Framework.Database // Transmog collection PrepareStatement(LoginStatements.SEL_BNET_ITEM_APPEARANCES, "SELECT blobIndex, appearanceMask FROM battlenet_item_appearances WHERE battlenetAccountId = ? ORDER BY blobIndex DESC"); - PrepareStatement(LoginStatements.INS_BNET_ITEM_APPEARANCES, "INSERT INTO battlenet_item_appearances (battlenetAccountId, blobIndex, appearanceMask) VALUES (?, ?, ?) " + - "ON DUPLICATE KEY UPDATE appearanceMask = appearanceMask | VALUES(appearanceMask)"); + PrepareStatement(LoginStatements.INS_BNET_ITEM_APPEARANCES, "INSERT INTO battlenet_item_appearances (battlenetAccountId, blobIndex, appearanceMask) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE appearanceMask = appearanceMask | VALUES(appearanceMask)"); PrepareStatement(LoginStatements.SEL_BNET_ITEM_FAVORITE_APPEARANCES, "SELECT itemModifiedAppearanceId FROM battlenet_item_favorite_appearances WHERE battlenetAccountId = ?"); PrepareStatement(LoginStatements.INS_BNET_ITEM_FAVORITE_APPEARANCE, "INSERT INTO battlenet_item_favorite_appearances (battlenetAccountId, itemModifiedAppearanceId) VALUES (?, ?)"); PrepareStatement(LoginStatements.DEL_BNET_ITEM_FAVORITE_APPEARANCE, "DELETE FROM battlenet_item_favorite_appearances WHERE battlenetAccountId = ? AND itemModifiedAppearanceId = ?"); + PrepareStatement(LoginStatements.SEL_BNET_TRANSMOG_ILLUSIONS, "SELECT blobIndex, illusionMask FROM battlenet_account_transmog_illusions WHERE battlenetAccountId = ? ORDER BY blobIndex DESC"); + PrepareStatement(LoginStatements.INS_BNET_TRANSMOG_ILLUSIONS, "INSERT INTO battlenet_account_transmog_illusions (battlenetAccountId, blobIndex, illusionMask) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE illusionMask = illusionMask | VALUES(illusionMask)"); } } @@ -318,6 +319,8 @@ namespace Framework.Database SEL_BNET_ITEM_FAVORITE_APPEARANCES, INS_BNET_ITEM_FAVORITE_APPEARANCE, DEL_BNET_ITEM_FAVORITE_APPEARANCE, + SEL_BNET_TRANSMOG_ILLUSIONS, + INS_BNET_TRANSMOG_ILLUSIONS, MAX_LOGINDATABASE_STATEMENTS } diff --git a/Source/Game/Entities/Player/CollectionManager.cs b/Source/Game/Entities/Player/CollectionManager.cs index d5afcd0fd..9ae42d0a6 100644 --- a/Source/Game/Entities/Player/CollectionManager.cs +++ b/Source/Game/Entities/Player/CollectionManager.cs @@ -37,6 +37,7 @@ namespace Game.Entities BitSet _appearances; MultiMap _temporaryAppearances = new(); Dictionary _favoriteAppearances = new(); + BitSet _transmogIllusions; public static void LoadMountDefinitions() { @@ -76,6 +77,7 @@ namespace Game.Entities { _owner = owner; _appearances = new BitSet(0); + _transmogIllusions = new BitSet(0); } public void LoadToys() @@ -489,7 +491,7 @@ namespace Game.Entities foreach (uint hiddenItem in hiddenAppearanceItems) { - ItemModifiedAppearanceRecord hiddenAppearance = Global.DB2Mgr.GetItemModifiedAppearance(hiddenItem, 0); + ItemModifiedAppearanceRecord hiddenAppearance = Global.DB2Mgr.GetItemModifiedAppearance(hiddenItem, 0); //ASSERT(hiddenAppearance); if (_appearances.Length <= hiddenAppearance.Id) _appearances.Length = (int)hiddenAppearance.Id + 1; @@ -611,48 +613,48 @@ namespace Game.Entities switch (itemTemplate.GetClass()) { case ItemClass.Weapon: - { - if (!Convert.ToBoolean(_owner.GetPlayer().GetWeaponProficiency() & (1 << (int)itemTemplate.GetSubClass()))) - return false; - if (itemTemplate.GetSubClass() == (int)ItemSubClassWeapon.Exotic || - itemTemplate.GetSubClass() == (int)ItemSubClassWeapon.Exotic2 || - itemTemplate.GetSubClass() == (int)ItemSubClassWeapon.Miscellaneous || - itemTemplate.GetSubClass() == (int)ItemSubClassWeapon.Thrown || - itemTemplate.GetSubClass() == (int)ItemSubClassWeapon.Spear || - itemTemplate.GetSubClass() == (int)ItemSubClassWeapon.FishingPole) - return false; - break; - } + { + if (!Convert.ToBoolean(_owner.GetPlayer().GetWeaponProficiency() & (1 << (int)itemTemplate.GetSubClass()))) + return false; + if (itemTemplate.GetSubClass() == (int)ItemSubClassWeapon.Exotic || + itemTemplate.GetSubClass() == (int)ItemSubClassWeapon.Exotic2 || + itemTemplate.GetSubClass() == (int)ItemSubClassWeapon.Miscellaneous || + itemTemplate.GetSubClass() == (int)ItemSubClassWeapon.Thrown || + itemTemplate.GetSubClass() == (int)ItemSubClassWeapon.Spear || + itemTemplate.GetSubClass() == (int)ItemSubClassWeapon.FishingPole) + return false; + break; + } case ItemClass.Armor: + { + switch (itemTemplate.GetInventoryType()) { - switch (itemTemplate.GetInventoryType()) - { - case InventoryType.Body: - case InventoryType.Shield: - case InventoryType.Cloak: - case InventoryType.Tabard: - case InventoryType.Holdable: - break; - case InventoryType.Head: - case InventoryType.Shoulders: - case InventoryType.Chest: - case InventoryType.Waist: - case InventoryType.Legs: - case InventoryType.Feet: - case InventoryType.Wrists: - case InventoryType.Hands: - case InventoryType.Robe: - if ((ItemSubClassArmor)itemTemplate.GetSubClass() == ItemSubClassArmor.Miscellaneous) - return false; - break; - default: + case InventoryType.Body: + case InventoryType.Shield: + case InventoryType.Cloak: + case InventoryType.Tabard: + case InventoryType.Holdable: + break; + case InventoryType.Head: + case InventoryType.Shoulders: + case InventoryType.Chest: + case InventoryType.Waist: + case InventoryType.Legs: + case InventoryType.Feet: + case InventoryType.Wrists: + case InventoryType.Hands: + case InventoryType.Robe: + if ((ItemSubClassArmor)itemTemplate.GetSubClass() == ItemSubClassArmor.Miscellaneous) return false; - } - if (itemTemplate.GetInventoryType() != InventoryType.Cloak) - if (!Convert.ToBoolean(PlayerClassByArmorSubclass[itemTemplate.GetSubClass()] & _owner.GetPlayer().GetClassMask())) - return false; - break; + break; + default: + return false; } + if (itemTemplate.GetInventoryType() != InventoryType.Cloak) + if (!Convert.ToBoolean(PlayerClassByArmorSubclass[itemTemplate.GetSubClass()] & _owner.GetPlayer().GetClassMask())) + return false; + break; + } default: return false; } @@ -755,7 +757,7 @@ namespace Game.Entities return appearances; } - + public void SetAppearanceIsFavorite(uint itemModifiedAppearanceId, bool apply) { var apperanceState = _favoriteAppearances.LookupByKey(itemModifiedAppearanceId); @@ -847,6 +849,85 @@ namespace Game.Entities return !knownPieces.Contains(0); } + public void LoadTransmogIllusions() + { + Player owner = _owner.GetPlayer(); + foreach (var blockValue in _transmogIllusions.ToBlockRange()) + owner.AddIllusionBlock(blockValue); + } + + public void LoadAccountTransmogIllusions(SQLResult knownTransmogIllusions) + { + uint[] blocks = new uint[7]; + + if (!knownTransmogIllusions.IsEmpty()) + { + do + { + ushort blobIndex = knownTransmogIllusions.Read(0); + if (blobIndex >= blocks.Length) + Array.Resize(ref blocks, blobIndex + 1); + + blocks[blobIndex] = knownTransmogIllusions.Read(1); + + } while (knownTransmogIllusions.NextRow()); + } + + _transmogIllusions = new(blocks); + + // Static illusions known by every player + ushort[] defaultIllusions = + { + 3, // Lifestealing + 13, // Crusader + 22, // Striking + 23, // Agility + 34, // Hide Weapon Enchant + 43, // Beastslayer + 44, // Titanguard + }; + + foreach (ushort illusionId in defaultIllusions) + _transmogIllusions.Set(illusionId, true); + } + + public void SaveAccountTransmogIllusions(SQLTransaction trans) + { + ushort blockIndex = 0; + + foreach (var blockValue in _transmogIllusions.ToBlockRange()) + { + if (blockValue != 0) // this table is only appended/bits are set (never cleared) so don't save empty blocks + { + PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.INS_BNET_TRANSMOG_ILLUSIONS); + stmt.AddValue(0, _owner.GetBattlenetAccountId()); + stmt.AddValue(1, blockIndex); + stmt.AddValue(2, blockValue); + trans.Append(stmt); + } + ++blockIndex; + } + } + + public void AddTransmogIllusion(ushort illusionId) + { + Player owner = _owner.GetPlayer(); + if (_transmogIllusions.Count <= illusionId) + { + uint numBlocks = (uint)(_transmogIllusions.Count << 2); + _transmogIllusions.Length = illusionId + 1; + numBlocks = (uint)(_transmogIllusions.Count << 2) - numBlocks; + while (numBlocks-- != 0) + owner.AddIllusionBlock(0); + } + + _transmogIllusions.Set(illusionId, true); + int blockIndex = illusionId / 32; + int bitIndex = illusionId % 32; + + owner.AddIllusionFlag(blockIndex, (uint)(1 << bitIndex)); + } + public bool HasToy(uint itemId) { return _toys.ContainsKey(itemId); } public Dictionary GetAccountToys() { return _toys; } public Dictionary GetAccountHeirlooms() { return _heirlooms; } diff --git a/Source/Game/Entities/Player/Player.DB.cs b/Source/Game/Entities/Player/Player.DB.cs index 5ef583f3d..38934229b 100644 --- a/Source/Game/Entities/Player/Player.DB.cs +++ b/Source/Game/Entities/Player/Player.DB.cs @@ -3135,6 +3135,7 @@ namespace Game.Entities GetSession().GetCollectionMgr().LoadHeirlooms(); GetSession().GetCollectionMgr().LoadMounts(); GetSession().GetCollectionMgr().LoadItemAppearances(); + GetSession().GetCollectionMgr().LoadTransmogIllusions(); LearnSpecializationSpells(); @@ -3732,6 +3733,7 @@ namespace Game.Entities GetSession().GetCollectionMgr().SaveAccountHeirlooms(loginTransaction); GetSession().GetCollectionMgr().SaveAccountMounts(loginTransaction); GetSession().GetCollectionMgr().SaveAccountItemAppearances(loginTransaction); + GetSession().GetCollectionMgr().SaveAccountTransmogIllusions(loginTransaction); stmt = DB.Login.GetPreparedStatement(LoginStatements.DEL_BNET_LAST_PLAYER_CHARACTERS); stmt.AddValue(0, GetSession().GetAccountId()); diff --git a/Source/Game/Entities/Player/Player.cs b/Source/Game/Entities/Player/Player.cs index 02876b8f5..daafa0ae0 100644 --- a/Source/Game/Entities/Player/Player.cs +++ b/Source/Game/Entities/Player/Player.cs @@ -7721,6 +7721,10 @@ namespace Game.Entities if (index >= 0) RemoveDynamicUpdateFieldValue(m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.ConditionalTransmog), index); } + + public void AddIllusionBlock(uint blockValue) { AddDynamicUpdateFieldValue(m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.TransmogIllusions), blockValue); } + public void AddIllusionFlag(int slot, uint flag) { SetUpdateFieldFlagValue(m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.TransmogIllusions, slot), flag); } + public void AddSelfResSpell(uint spellId) { AddDynamicUpdateFieldValue(m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.SelfResSpells), spellId); } public void RemoveSelfResSpell(uint spellId) { diff --git a/Source/Game/Server/WorldSession.cs b/Source/Game/Server/WorldSession.cs index c559052f2..fbdab6934 100644 --- a/Source/Game/Server/WorldSession.cs +++ b/Source/Game/Server/WorldSession.cs @@ -798,6 +798,7 @@ namespace Game _collectionMgr.LoadAccountHeirlooms(holder.GetResult(AccountInfoQueryLoad.GlobalAccountHeirlooms)); _collectionMgr.LoadAccountMounts(holder.GetResult(AccountInfoQueryLoad.Mounts)); _collectionMgr.LoadAccountItemAppearances(holder.GetResult(AccountInfoQueryLoad.ItemAppearances), holder.GetResult(AccountInfoQueryLoad.ItemFavoriteAppearances)); + _collectionMgr.LoadAccountTransmogIllusions(holder.GetResult(AccountInfoQueryLoad.TransmogIllusions)); if (!m_inQueue) SendAuthResponse(BattlenetRpcErrorCode.Ok, false); @@ -1164,6 +1165,10 @@ namespace Game stmt = DB.Login.GetPreparedStatement(LoginStatements.SEL_BNET_ITEM_FAVORITE_APPEARANCES); stmt.AddValue(0, battlenetAccountId); SetQuery(AccountInfoQueryLoad.ItemFavoriteAppearances, stmt); + + stmt = DB.Login.GetPreparedStatement(LoginStatements.SEL_BNET_TRANSMOG_ILLUSIONS); + stmt.AddValue(0, battlenetAccountId); + SetQuery(AccountInfoQueryLoad.TransmogIllusions, stmt); } } @@ -1178,6 +1183,7 @@ namespace Game ItemAppearances, ItemFavoriteAppearances, GlobalAccountDataIndexPerRealm, - TutorialsIndexPerRealm + TutorialsIndexPerRealm, + TransmogIllusions, } } diff --git a/Source/Game/Spells/SpellEffects.cs b/Source/Game/Spells/SpellEffects.cs index 42f6ce47f..e74bafa9b 100644 --- a/Source/Game/Spells/SpellEffects.cs +++ b/Source/Game/Spells/SpellEffects.cs @@ -5655,6 +5655,19 @@ namespace Game.Spells playerCaster.GetSession().GetBattlePetMgr().GrantBattlePetExperience(unitTarget.GetBattlePetCompanionGUID(), (ushort)damage, BattlePetXpSource.SpellEffect); } + + [SpellEffectHandler(SpellEffectName.LearnTransmogIllusion)] + void EffectLearnTransmogIllusion() + { + if (effectHandleMode != SpellEffectHandleMode.HitTarget) + return; + + Player player = unitTarget?.ToPlayer(); + if (player == null) + return; + + player.GetSession().GetCollectionMgr().AddTransmogIllusion((ushort)effectInfo.MiscValue); + } } public class DispelableAura