From 45c95d22edb5c0a589db25442fa804c2dc2fc316 Mon Sep 17 00:00:00 2001 From: hondacrx Date: Thu, 14 Sep 2023 03:27:06 -0400 Subject: [PATCH] Core/Creatures: Updated totem slot assignment logic * Implemented SUMMON_SLOT_ANY_TOTEM * Fixed showing totems on player frames * Fixed removing totems from player frames * Fixed being able to summon unlimited windfury totems Port From (https://github.com/TrinityCore/TrinityCore/commit/fefc7192631764245396cd2622aa11f649411946) --- Source/Game/DataStorage/DB2Manager.cs | 5 +- Source/Game/Entities/TemporarySummon.cs | 80 +++++++++++++++++++++---- Source/Game/Entities/Totem.cs | 8 ++- Source/Game/Handlers/SpellHandler.cs | 4 +- 4 files changed, 80 insertions(+), 17 deletions(-) diff --git a/Source/Game/DataStorage/DB2Manager.cs b/Source/Game/DataStorage/DB2Manager.cs index fef4de9b1..e00e7a727 100644 --- a/Source/Game/DataStorage/DB2Manager.cs +++ b/Source/Game/DataStorage/DB2Manager.cs @@ -1892,7 +1892,7 @@ namespace Game.DataStorage return _talentsByPosition[(int)class_][tier][column]; } - public bool IsTotemCategoryCompatibleWith(uint itemTotemCategoryId, uint requiredTotemCategoryId) + public bool IsTotemCategoryCompatibleWith(uint itemTotemCategoryId, uint requiredTotemCategoryId, bool requireAllTotems = true) { if (requiredTotemCategoryId == 0) return true; @@ -1909,7 +1909,8 @@ namespace Game.DataStorage if (itemEntry.TotemCategoryType != reqEntry.TotemCategoryType) return false; - return (itemEntry.TotemCategoryMask & reqEntry.TotemCategoryMask) == reqEntry.TotemCategoryMask; + int sharedMask = itemEntry.TotemCategoryMask & reqEntry.TotemCategoryMask; + return requireAllTotems ? sharedMask == reqEntry.TotemCategoryMask : sharedMask != 0; } public bool IsToyItem(uint toy) diff --git a/Source/Game/Entities/TemporarySummon.cs b/Source/Game/Entities/TemporarySummon.cs index cb5b47345..a3c90b31c 100644 --- a/Source/Game/Entities/TemporarySummon.cs +++ b/Source/Game/Entities/TemporarySummon.cs @@ -4,9 +4,11 @@ using Framework.Constants; using Framework.Dynamic; using Game.DataStorage; +using Game.Maps; +using Game.Spells; using System; using System.Collections.Generic; -using Game.Maps; +using System.Linq; namespace Game.Entities { @@ -199,7 +201,10 @@ namespace Game.Entities if (unitSummoner != null) { int slot = m_Properties.Slot; - if (slot > 0) + if (slot == (int)SummonSlot.Any) + slot = FindUsableTotemSlot(unitSummoner); + + if (slot != 0) { if (!unitSummoner.m_SummonSlot[slot].IsEmpty() && unitSummoner.m_SummonSlot[slot] != GetGUID()) { @@ -335,16 +340,13 @@ namespace Game.Entities if (!IsInWorld) return; - if (m_Properties != null) + if (m_Properties != null && m_Properties.Slot != 0) { - int slot = m_Properties.Slot; - if (slot > 0) - { - Unit owner = GetSummonerUnit(); - if (owner != null) - if (owner.m_SummonSlot[slot] == GetGUID()) - owner.m_SummonSlot[slot].Clear(); - } + Unit owner = GetSummonerUnit(); + if (owner != null) + foreach (ObjectGuid summonSlot in owner.m_SummonSlot) + if (summonSlot == GetGUID()) + summonSlot.Clear(); } if (!GetOwnerGUID().IsEmpty()) @@ -353,6 +355,62 @@ namespace Game.Entities base.RemoveFromWorld(); } + public int FindUsableTotemSlot(Unit summoner) + { + var list = summoner.m_SummonSlot[new Range((int)SummonSlot.Totem, SharedConst.MaxTotemSlot)].ToList(); + + // first try exact guid match + var totemSlot = list.FindIndex(otherTotemGuid => otherTotemGuid == GetGUID()); + + // then a slot that shares totem category with this new summon + if (totemSlot == -1) + totemSlot = list.FindIndex(IsSharingTotemSlotWith); + + // any empty slot...? + if (totemSlot == -1) + totemSlot = list.FindIndex(otherTotemGuid => otherTotemGuid.IsEmpty()); + + // if no usable slot was found, try used slot by a summon with the same creature id + // we must not despawn unrelated summons + if (totemSlot == -1) + totemSlot = list.FindIndex(otherTotemGuid => GetEntry() == otherTotemGuid.GetEntry()); + + // if no slot was found, this summon gets no slot and will not be stored in m_SummonSlot + if (totemSlot == -1) + return 0; + + return totemSlot; + } + + bool IsSharingTotemSlotWith(ObjectGuid objectGuid) + { + Creature otherSummon = GetMap().GetCreature(objectGuid); + if (!otherSummon) + return false; + + SpellInfo mySummonSpell = Global.SpellMgr.GetSpellInfo(m_unitData.CreatedBySpell, Difficulty.None); + if (mySummonSpell == null) + return false; + + SpellInfo otherSummonSpell = Global.SpellMgr.GetSpellInfo(otherSummon.m_unitData.CreatedBySpell, Difficulty.None); + if (otherSummonSpell == null) + return false; + + foreach (var myTotemCategory in mySummonSpell.TotemCategory) + if (myTotemCategory != 0) + foreach (var otherTotemCategory in otherSummonSpell.TotemCategory) + if (otherTotemCategory != 0 && Global.DB2Mgr.IsTotemCategoryCompatibleWith(myTotemCategory, otherTotemCategory, false)) + return true; + + foreach (int myTotemId in mySummonSpell.Totem) + if (myTotemId != 0) + foreach (int otherTotemId in otherSummonSpell.Totem) + if (otherTotemId != 0 && myTotemId == otherTotemId) + return true; + + return false; + } + public override string GetDebugInfo() { return $"{base.GetDebugInfo()}\nTempSummonType : {GetSummonType()} Summoner: {GetSummonerGUID()} Timer: {GetTimer()}"; diff --git a/Source/Game/Entities/Totem.cs b/Source/Game/Entities/Totem.cs index 26203645c..1bc7abd3c 100644 --- a/Source/Game/Entities/Totem.cs +++ b/Source/Game/Entities/Totem.cs @@ -44,11 +44,15 @@ namespace Game.Entities Player owner = GetOwner().ToPlayer(); if (owner) { - if (m_Properties.Slot >= (int)SummonSlot.Totem && m_Properties.Slot < SharedConst.MaxTotemSlot) + int slot = m_Properties.Slot; + if (slot == (int)SummonSlot.Any) + slot = FindUsableTotemSlot(owner); + + if (slot >= (int)SummonSlot.Totem && slot < SharedConst.MaxTotemSlot) { TotemCreated packet = new(); packet.Totem = GetGUID(); - packet.Slot = (byte)(m_Properties.Slot - (int)SummonSlot.Totem); + packet.Slot = (byte)(slot - (int)SummonSlot.Totem); packet.Duration = duration; packet.SpellID = m_unitData.CreatedBySpell; owner.ToPlayer().SendPacket(packet); diff --git a/Source/Game/Handlers/SpellHandler.cs b/Source/Game/Handlers/SpellHandler.cs index 280c4fd6c..69d020f9d 100644 --- a/Source/Game/Handlers/SpellHandler.cs +++ b/Source/Game/Handlers/SpellHandler.cs @@ -527,8 +527,8 @@ namespace Game return; Creature totem = ObjectAccessor.GetCreature(GetPlayer(), _player.m_SummonSlot[slotId]); - if (totem != null && totem.IsTotem())// && totem.GetGUID() == packet.TotemGUID) Unknown why blizz doesnt send the guid when you right click it. - totem.ToTotem().UnSummon(); + if (totem != null && totem.IsTotem() && (totemDestroyed.TotemGUID.IsEmpty() || totem.GetGUID() == totemDestroyed.TotemGUID)) + totem.DespawnOrUnsummon(); } [WorldPacketHandler(ClientOpcodes.SelfRes)]