Core/Spells: Implemented personal summons

This commit is contained in:
hondacrx
2018-04-08 18:50:05 -04:00
parent 7c8f9d5d15
commit c69c715cc0
10 changed files with 81 additions and 18 deletions
+26
View File
@@ -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,
@@ -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;
}
+18 -1
View File
@@ -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);
+1 -1
View File
@@ -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;
+15 -4
View File
@@ -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);
+2 -1
View File
@@ -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)
+3
View File
@@ -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;
+4
View File
@@ -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
+4 -4
View File
@@ -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();
+7 -5
View File
@@ -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