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:
@@ -1892,7 +1892,7 @@ namespace Game.DataStorage
|
|||||||
return _talentsByPosition[(int)class_][tier][column];
|
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)
|
if (requiredTotemCategoryId == 0)
|
||||||
return true;
|
return true;
|
||||||
@@ -1909,7 +1909,8 @@ namespace Game.DataStorage
|
|||||||
if (itemEntry.TotemCategoryType != reqEntry.TotemCategoryType)
|
if (itemEntry.TotemCategoryType != reqEntry.TotemCategoryType)
|
||||||
return false;
|
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)
|
public bool IsToyItem(uint toy)
|
||||||
|
|||||||
@@ -4,9 +4,11 @@
|
|||||||
using Framework.Constants;
|
using Framework.Constants;
|
||||||
using Framework.Dynamic;
|
using Framework.Dynamic;
|
||||||
using Game.DataStorage;
|
using Game.DataStorage;
|
||||||
|
using Game.Maps;
|
||||||
|
using Game.Spells;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Game.Maps;
|
using System.Linq;
|
||||||
|
|
||||||
namespace Game.Entities
|
namespace Game.Entities
|
||||||
{
|
{
|
||||||
@@ -199,7 +201,10 @@ namespace Game.Entities
|
|||||||
if (unitSummoner != null)
|
if (unitSummoner != null)
|
||||||
{
|
{
|
||||||
int slot = m_Properties.Slot;
|
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())
|
if (!unitSummoner.m_SummonSlot[slot].IsEmpty() && unitSummoner.m_SummonSlot[slot] != GetGUID())
|
||||||
{
|
{
|
||||||
@@ -335,16 +340,13 @@ namespace Game.Entities
|
|||||||
if (!IsInWorld)
|
if (!IsInWorld)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (m_Properties != null)
|
if (m_Properties != null && m_Properties.Slot != 0)
|
||||||
{
|
{
|
||||||
int slot = m_Properties.Slot;
|
Unit owner = GetSummonerUnit();
|
||||||
if (slot > 0)
|
if (owner != null)
|
||||||
{
|
foreach (ObjectGuid summonSlot in owner.m_SummonSlot)
|
||||||
Unit owner = GetSummonerUnit();
|
if (summonSlot == GetGUID())
|
||||||
if (owner != null)
|
summonSlot.Clear();
|
||||||
if (owner.m_SummonSlot[slot] == GetGUID())
|
|
||||||
owner.m_SummonSlot[slot].Clear();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!GetOwnerGUID().IsEmpty())
|
if (!GetOwnerGUID().IsEmpty())
|
||||||
@@ -353,6 +355,62 @@ namespace Game.Entities
|
|||||||
base.RemoveFromWorld();
|
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()
|
public override string GetDebugInfo()
|
||||||
{
|
{
|
||||||
return $"{base.GetDebugInfo()}\nTempSummonType : {GetSummonType()} Summoner: {GetSummonerGUID()} Timer: {GetTimer()}";
|
return $"{base.GetDebugInfo()}\nTempSummonType : {GetSummonType()} Summoner: {GetSummonerGUID()} Timer: {GetTimer()}";
|
||||||
|
|||||||
@@ -44,11 +44,15 @@ namespace Game.Entities
|
|||||||
Player owner = GetOwner().ToPlayer();
|
Player owner = GetOwner().ToPlayer();
|
||||||
if (owner)
|
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();
|
TotemCreated packet = new();
|
||||||
packet.Totem = GetGUID();
|
packet.Totem = GetGUID();
|
||||||
packet.Slot = (byte)(m_Properties.Slot - (int)SummonSlot.Totem);
|
packet.Slot = (byte)(slot - (int)SummonSlot.Totem);
|
||||||
packet.Duration = duration;
|
packet.Duration = duration;
|
||||||
packet.SpellID = m_unitData.CreatedBySpell;
|
packet.SpellID = m_unitData.CreatedBySpell;
|
||||||
owner.ToPlayer().SendPacket(packet);
|
owner.ToPlayer().SendPacket(packet);
|
||||||
|
|||||||
@@ -527,8 +527,8 @@ namespace Game
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
Creature totem = ObjectAccessor.GetCreature(GetPlayer(), _player.m_SummonSlot[slotId]);
|
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.
|
if (totem != null && totem.IsTotem() && (totemDestroyed.TotemGUID.IsEmpty() || totem.GetGUID() == totemDestroyed.TotemGUID))
|
||||||
totem.ToTotem().UnSummon();
|
totem.DespawnOrUnsummon();
|
||||||
}
|
}
|
||||||
|
|
||||||
[WorldPacketHandler(ClientOpcodes.SelfRes)]
|
[WorldPacketHandler(ClientOpcodes.SelfRes)]
|
||||||
|
|||||||
Reference in New Issue
Block a user