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)
This commit is contained in:
hondacrx
2023-09-14 03:27:06 -04:00
parent 0449c88951
commit 45c95d22ed
4 changed files with 80 additions and 17 deletions
+3 -2
View File
@@ -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)
+69 -11
View File
@@ -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()}";
+6 -2
View File
@@ -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);
+2 -2
View File
@@ -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)]