From c69c715cc0310811fa14fa883de919e3756772fe Mon Sep 17 00:00:00 2001 From: hondacrx Date: Sun, 8 Apr 2018 18:50:05 -0400 Subject: [PATCH] Core/Spells: Implemented personal summons --- Source/Framework/Constants/CliDBConst.cs | 26 +++++++++++++++++++ .../Game/Collision/Models/GameObjectModel.cs | 3 +-- Source/Game/Combat/ThreatManager.cs | 19 +++++++++++++- Source/Game/DataStorage/Structs/S_Records.cs | 2 +- Source/Game/Entities/Object/WorldObject.cs | 19 +++++++++++--- Source/Game/Entities/Player/Player.Spells.cs | 3 ++- Source/Game/Entities/Player/Player.cs | 3 +++ Source/Game/Entities/TemporarySummon.cs | 4 +++ Source/Game/Maps/Map.cs | 8 +++--- Source/Game/Spells/SpellEffects.cs | 12 +++++---- 10 files changed, 81 insertions(+), 18 deletions(-) diff --git a/Source/Framework/Constants/CliDBConst.cs b/Source/Framework/Constants/CliDBConst.cs index 1cafe9fad..9ba1cb4a0 100644 --- a/Source/Framework/Constants/CliDBConst.cs +++ b/Source/Framework/Constants/CliDBConst.cs @@ -1438,6 +1438,32 @@ namespace Framework.Constants PreventEmoteSounds = 0x1000a } + public enum SummonPropFlags + { + None = 0x00000000, // 1342 Spells In 3.0.3 + Unk1 = 0x00000001, // 75 Spells In 3.0.3, Something Unfriendly + Unk2 = 0x00000002, // 616 Spells In 3.0.3, Something Friendly + Unk3 = 0x00000004, // 22 Spells In 3.0.3, No Idea... + Unk4 = 0x00000008, // 49 Spells In 3.0.3, Some Mounts + PersonalSpawn = 0x00000010, // Personal Spawn (Creature Visible Only By Summoner) + Unk6 = 0x00000020, // 0 Spells In 3.3.5, Unused + Unk7 = 0x00000040, // 12 Spells In 3.0.3, No Idea + Unk8 = 0x00000080, // 4 Spells In 3.0.3, No Idea + Unk9 = 0x00000100, // 51 Spells In 3.0.3, No Idea, Many Quest Related + Unk10 = 0x00000200, // 51 Spells In 3.0.3, Something Defensive + Unk11 = 0x00000400, // 3 Spells, Requires Something Near? + Unk12 = 0x00000800, // 30 Spells In 3.0.3, No Idea + Unk13 = 0x00001000, // Lightwell, Jeeves, Gnomish Alarm-O-Bot, Build Vehicles(Wintergrasp) + Unk14 = 0x00002000, // Guides, Player Follows + Unk15 = 0x00004000, // Force Of Nature, Shadowfiend, Feral Spirit, Summon Water Elemental + Unk16 = 0x00008000, // Light/Dark Bullet, Soul/Fiery Consumption, Twisted Visage, Twilight Whelp. Phase Related? + Unk17 = 0x00010000, + Unk18 = 0x00020000, + Unk19 = 0x00040000, + Unk20 = 0x00080000, + Unk21 = 0x00100000 // Totems + } + public enum TaxiNodeFlags : byte { Alliance = 0x1, diff --git a/Source/Game/Collision/Models/GameObjectModel.cs b/Source/Game/Collision/Models/GameObjectModel.cs index d08153c4e..d74b40706 100644 --- a/Source/Game/Collision/Models/GameObjectModel.cs +++ b/Source/Game/Collision/Models/GameObjectModel.cs @@ -37,7 +37,6 @@ namespace Game.Collision public abstract Vector3 GetPosition(); public abstract float GetOrientation(); public abstract float GetScale(); - public abstract void DebugVisualizeCorner(Vector3 corner); } public class GameObjectModel : IModel @@ -196,7 +195,7 @@ namespace Game.Collision string magic = reader.ReadStringFromChars(8); if (magic != MapConst.VMapMagic) { - Log.outError(LogFilter.Misc, $"File '{MapConst.GAMEOBJECT_MODELS}' has wrong header, expected {MapConst.VMapMagic}."); + Log.outError(LogFilter.Misc, $"File '{filename}' has wrong header, expected {MapConst.VMapMagic}."); return; } diff --git a/Source/Game/Combat/ThreatManager.cs b/Source/Game/Combat/ThreatManager.cs index c63119fc9..b71bda899 100644 --- a/Source/Game/Combat/ThreatManager.cs +++ b/Source/Game/Combat/ThreatManager.cs @@ -56,11 +56,28 @@ namespace Game.Combat public void doAddThreat(Unit victim, float threat) { uint redirectThreadPct = victim.GetRedirectThreatPercent(); + Unit redirectTarget = victim.GetRedirectThreatTarget(); + + // If victim is personnal spawn, redirect all aggro to summoner + TempSummon tempSummonVictim = victim.ToTempSummon(); + if (tempSummonVictim) + { + if (tempSummonVictim.IsVisibleBySummonerOnly()) + { + // Personnal Spawns from same summoner can aggro each other + if (!GetOwner().ToTempSummon() || + !GetOwner().ToTempSummon().IsVisibleBySummonerOnly() || + tempSummonVictim.GetSummonerGUID() != GetOwner().ToTempSummon().GetSummonerGUID()) + { + redirectThreadPct = 100; + redirectTarget = tempSummonVictim.GetSummoner(); + } + } + } // must check > 0.0f, otherwise dead loop if (threat > 0.0f && redirectThreadPct != 0) { - Unit redirectTarget = victim.GetRedirectThreatTarget(); if (redirectTarget != null) { float redirectThreat = MathFunctions.CalculatePct(threat, redirectThreadPct); diff --git a/Source/Game/DataStorage/Structs/S_Records.cs b/Source/Game/DataStorage/Structs/S_Records.cs index 7b35b78fd..933410a29 100644 --- a/Source/Game/DataStorage/Structs/S_Records.cs +++ b/Source/Game/DataStorage/Structs/S_Records.cs @@ -548,7 +548,7 @@ namespace Game.DataStorage public sealed class SummonPropertiesRecord { public uint Id; - public uint Flags; + public SummonPropFlags Flags; public SummonCategory Control; public ushort Faction; public SummonType Title; diff --git a/Source/Game/Entities/Object/WorldObject.cs b/Source/Game/Entities/Object/WorldObject.cs index 2b934e864..3932bc7cb 100644 --- a/Source/Game/Entities/Object/WorldObject.cs +++ b/Source/Game/Entities/Object/WorldObject.cs @@ -1719,8 +1719,19 @@ namespace Game.Entities WorldObject viewpoint = this; Player player = ToPlayer(); if (player != null) + { viewpoint = player.GetViewpoint(); + Creature creature = obj.ToCreature(); + if (creature) + { + TempSummon tempSummon = creature.ToTempSummon(); + if (tempSummon) + if (tempSummon.IsVisibleBySummonerOnly() && GetGUID() != tempSummon.GetSummonerGUID()) + return false; + } + } + if (viewpoint == null) viewpoint = this; @@ -1990,7 +2001,7 @@ namespace Game.Entities return null; } - public TempSummon SummonCreature(uint id, float x, float y, float z, float ang = 0, TempSummonType spwtype = TempSummonType.ManualDespawn, uint despwtime = 0) + public TempSummon SummonCreature(uint id, float x, float y, float z, float ang = 0, TempSummonType spwtype = TempSummonType.ManualDespawn, uint despwtime = 0, bool visibleBySummonerOnly = false) { if (x == 0.0f && y == 0.0f && z == 0.0f) { @@ -1999,15 +2010,15 @@ namespace Game.Entities } Position pos = new Position(); pos.Relocate(x, y, z, ang); - return SummonCreature(id, pos, spwtype, despwtime, 0); + return SummonCreature(id, pos, spwtype, despwtime, 0, visibleBySummonerOnly); } - public TempSummon SummonCreature(uint entry, Position pos, TempSummonType spwtype = TempSummonType.ManualDespawn, uint duration = 0, uint vehId = 0) + public TempSummon SummonCreature(uint entry, Position pos, TempSummonType spwtype = TempSummonType.ManualDespawn, uint duration = 0, uint vehId = 0, bool visibleBySummonerOnly = false) { Map map = GetMap(); if (map != null) { - TempSummon summon = map.SummonCreature(entry, pos, null, duration, isTypeMask(TypeMask.Unit) ? ToUnit() : null); + TempSummon summon = map.SummonCreature(entry, pos, null, duration, ToUnit(), 0, vehId, visibleBySummonerOnly); if (summon != null) { summon.SetTempSummonType(spwtype); diff --git a/Source/Game/Entities/Player/Player.Spells.cs b/Source/Game/Entities/Player/Player.Spells.cs index 5d4ddd097..b835bd2a3 100644 --- a/Source/Game/Entities/Player/Player.Spells.cs +++ b/Source/Game/Entities/Player/Player.Spells.cs @@ -1716,7 +1716,8 @@ namespace Game.Entities void CastAllObtainSpells() { - for (byte slot = InventorySlots.ItemStart; slot < InventorySlots.ItemEnd; ++slot) + int inventoryEnd = InventorySlots.ItemStart + GetInventorySlotCount(); + for (byte slot = InventorySlots.ItemStart; slot < inventoryEnd; ++slot) { Item item = GetItemByPos(InventorySlots.Bag0, slot); if (item) diff --git a/Source/Game/Entities/Player/Player.cs b/Source/Game/Entities/Player/Player.cs index 60f89e4fb..ef47f800f 100644 --- a/Source/Game/Entities/Player/Player.cs +++ b/Source/Game/Entities/Player/Player.cs @@ -4501,6 +4501,9 @@ namespace Game.Entities // update visibility UpdateObjectVisibility(); + // recast lost by death auras of any items held in the inventory + CastAllObtainSpells(); + if (!applySickness) return; diff --git a/Source/Game/Entities/TemporarySummon.cs b/Source/Game/Entities/TemporarySummon.cs index dde5e6f5d..9f91da292 100644 --- a/Source/Game/Entities/TemporarySummon.cs +++ b/Source/Game/Entities/TemporarySummon.cs @@ -296,11 +296,15 @@ namespace Game.Entities public uint GetTimer() { return m_timer; } + public void SetVisibleBySummonerOnly(bool visibleBySummonerOnly) { m_visibleBySummonerOnly = visibleBySummonerOnly; } + public bool IsVisibleBySummonerOnly() { return m_visibleBySummonerOnly; } + public SummonPropertiesRecord m_Properties; TempSummonType m_type; uint m_timer; uint m_lifetime; ObjectGuid m_summonerGUID; + bool m_visibleBySummonerOnly; } public class Minion : TempSummon diff --git a/Source/Game/Maps/Map.cs b/Source/Game/Maps/Map.cs index 350b4d1f1..c32181978 100644 --- a/Source/Game/Maps/Map.cs +++ b/Source/Game/Maps/Map.cs @@ -3294,7 +3294,7 @@ namespace Game.Maps } } - public TempSummon SummonCreature(uint entry, Position pos, SummonPropertiesRecord properties = null, uint duration = 0, Unit summoner = null, uint spellId = 0, uint vehId = 0) + public TempSummon SummonCreature(uint entry, Position pos, SummonPropertiesRecord properties = null, uint duration = 0, Unit summoner = null, uint spellId = 0, uint vehId = 0, bool visibleBySummonerOnly = false) { var mask = UnitTypeMask.Summon; if (properties != null) @@ -3333,7 +3333,7 @@ namespace Game.Maps mask = UnitTypeMask.Minion; break; default: - if (Convert.ToBoolean(properties.Flags & 512)) // Mirror Image, Summon Gargoyle + if (Convert.ToBoolean(properties.Flags & SummonPropFlags.Unk10)) // Mirror Image, Summon Gargoyle mask = UnitTypeMask.Guardian; break; } @@ -3374,10 +3374,10 @@ namespace Game.Maps PhasingHandler.InheritPhaseShift(summon, summoner); summon.SetUInt32Value(UnitFields.CreatedBySpell, spellId); - summon.SetHomePosition(pos); - summon.InitStats(duration); + summon.SetVisibleBySummonerOnly(visibleBySummonerOnly); + AddToMap(summon.ToCreature()); summon.InitSummon(); diff --git a/Source/Game/Spells/SpellEffects.cs b/Source/Game/Spells/SpellEffects.cs index f63dad263..8e0d6040b 100644 --- a/Source/Game/Spells/SpellEffects.cs +++ b/Source/Game/Spells/SpellEffects.cs @@ -1710,6 +1710,8 @@ namespace Game.Spells if (m_originalCaster == null) return; + bool personalSpawn = (properties.Flags & SummonPropFlags.PersonalSpawn) != 0; + int duration = m_spellInfo.CalcDuration(m_originalCaster); TempSummon summon = null; @@ -1750,7 +1752,7 @@ namespace Game.Spells case SummonCategory.Wild: case SummonCategory.Ally: case SummonCategory.Unk: - if (Convert.ToBoolean(properties.Flags & 512)) + if (Convert.ToBoolean(properties.Flags & SummonPropFlags.Unk10)) { SummonGuardian(effIndex, entry, properties, numSummons); break; @@ -1771,7 +1773,7 @@ namespace Game.Spells case SummonType.LightWell: case SummonType.Totem: { - summon = m_caster.GetMap().SummonCreature(entry, destTarget, properties, (uint)duration, m_originalCaster, m_spellInfo.Id); + summon = m_caster.GetMap().SummonCreature(entry, destTarget, properties, (uint)duration, m_originalCaster, m_spellInfo.Id, 0, personalSpawn); if (summon == null || !summon.IsTotem()) return; @@ -1784,7 +1786,7 @@ namespace Game.Spells } case SummonType.Minipet: { - summon = m_caster.GetMap().SummonCreature(entry, destTarget, properties, (uint)duration, m_originalCaster, m_spellInfo.Id); + summon = m_caster.GetMap().SummonCreature(entry, destTarget, properties, (uint)duration, m_originalCaster, m_spellInfo.Id, 0, personalSpawn); if (summon == null || !summon.HasUnitTypeMask(UnitTypeMask.Minion)) return; @@ -1811,7 +1813,7 @@ namespace Game.Spells // randomize position for multiple summons m_caster.GetRandomPoint(destTarget, radius, out pos); - summon = m_originalCaster.SummonCreature(entry, pos, summonType, (uint)duration); + summon = m_originalCaster.SummonCreature(entry, pos, summonType, (uint)duration, 0, personalSpawn); if (summon == null) continue; @@ -1832,7 +1834,7 @@ namespace Game.Spells SummonGuardian(effIndex, entry, properties, numSummons); break; case SummonCategory.Puppet: - summon = m_caster.GetMap().SummonCreature(entry, destTarget, properties, (uint)duration, m_originalCaster, m_spellInfo.Id); + summon = m_caster.GetMap().SummonCreature(entry, destTarget, properties, (uint)duration, m_originalCaster, m_spellInfo.Id, 0, personalSpawn); break; case SummonCategory.Vehicle: // Summoning spells (usually triggered by npc_spellclick) that spawn a vehicle and that cause the clicker