Core/Spells: rework part 5: GameObject casting
Port From (https://github.com/TrinityCore/TrinityCore/commit/962f6d7988b9003e550f6745be7cff812e9d8efa)
This commit is contained in:
@@ -399,10 +399,12 @@ namespace Game.AI
|
||||
public virtual void JustUnregisteredAreaTrigger(AreaTrigger areaTrigger) { }
|
||||
|
||||
// Called when hit by a spell
|
||||
public virtual void SpellHit(Unit caster, SpellInfo spell) { }
|
||||
public virtual void SpellHit(Unit caster, SpellInfo spellInfo) { }
|
||||
public virtual void SpellHit(GameObject caster, SpellInfo spellInfo) { }
|
||||
|
||||
// Called when spell hits a target
|
||||
public virtual void SpellHitTarget(Unit target, SpellInfo spell) { }
|
||||
public virtual void SpellHitTarget(Unit target, SpellInfo spellInfo) { }
|
||||
public virtual void SpellHitTarget(GameObject target, SpellInfo spellInfo) { }
|
||||
|
||||
public virtual bool IsEscorted() { return false; }
|
||||
|
||||
@@ -459,7 +461,7 @@ namespace Game.AI
|
||||
public virtual void QuestReward(Player player, Quest quest, LootItemType type, uint opt) { }
|
||||
|
||||
/// == Waypoints system =============================
|
||||
|
||||
///
|
||||
public virtual void WaypointPathStarted(uint pathId) { }
|
||||
|
||||
public virtual void WaypointStarted(uint nodeId, uint pathId) { }
|
||||
@@ -479,7 +481,6 @@ namespace Game.AI
|
||||
// Object destruction is handled by Unit::RemoveCharmedBy
|
||||
public virtual PlayerAI GetAIForCharmedPlayer(Player who) { return null; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Should return true if the NPC is target of an escort quest
|
||||
/// If onlyIfActive is set, should return true only if the escort quest is currently active
|
||||
|
||||
@@ -81,8 +81,8 @@ namespace Game.AI
|
||||
// prevents achievement tracking if returning true
|
||||
public virtual bool OnReportUse(Player player) { return false; }
|
||||
|
||||
public virtual void Destroyed(Player player, uint eventId) { }
|
||||
public virtual void Damaged(Player player, uint eventId) { }
|
||||
public virtual void Destroyed(WorldObject attacker, uint eventId) { }
|
||||
public virtual void Damaged(WorldObject attacker, uint eventId) { }
|
||||
|
||||
public virtual void SetData64(uint id, ulong value) { }
|
||||
public virtual ulong GetData64(uint id) { return 0; }
|
||||
@@ -93,6 +93,13 @@ namespace Game.AI
|
||||
public virtual void OnLootStateChanged(uint state, Unit unit) { }
|
||||
public virtual void OnStateChanged(GameObjectState state) { }
|
||||
public virtual void EventInform(uint eventId) { }
|
||||
public virtual void SpellHit(Unit unit, SpellInfo spellInfo) { }
|
||||
|
||||
// Called when hit by a spell
|
||||
public virtual void SpellHit(Unit caster, SpellInfo spellInfo) { }
|
||||
public virtual void SpellHit(GameObject caster, SpellInfo spellInfo) { }
|
||||
|
||||
// Called when spell hits a target
|
||||
public virtual void SpellHitTarget(Unit target, SpellInfo spellInfo) { }
|
||||
public virtual void SpellHitTarget(GameObject target, SpellInfo spellInfo) { }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -373,30 +373,6 @@ namespace Game.AI
|
||||
_isCombatMovementAllowed = allowMovement;
|
||||
}
|
||||
|
||||
// Called at any Damage from any attacker (before damage apply)
|
||||
public override void DamageTaken(Unit attacker, ref uint damage) { }
|
||||
|
||||
//Called at creature death
|
||||
public override void JustDied(Unit killer) { }
|
||||
|
||||
//Called at creature killing another unit
|
||||
public override void KilledUnit(Unit victim) { }
|
||||
|
||||
// Called when the creature summon successfully other creature
|
||||
public override void JustSummoned(Creature summon) { }
|
||||
|
||||
// Called when a summoned creature is despawned
|
||||
public override void SummonedCreatureDespawn(Creature summon) { }
|
||||
|
||||
// Called when hit by a spell
|
||||
public override void SpellHit(Unit caster, SpellInfo spell) { }
|
||||
|
||||
// Called when spell hits a target
|
||||
public override void SpellHitTarget(Unit target, SpellInfo spell) { }
|
||||
|
||||
// Called when AI is temporarily replaced or put back when possess is applied or removed
|
||||
public virtual void OnPossess(bool apply) { }
|
||||
|
||||
public static Creature GetClosestCreatureWithEntry(WorldObject source, uint entry, float maxSearchRange, bool alive = true)
|
||||
{
|
||||
return source.FindNearestCreature(entry, maxSearchRange, alive);
|
||||
@@ -407,12 +383,6 @@ namespace Game.AI
|
||||
return source.FindNearestGameObject(entry, maxSearchRange);
|
||||
}
|
||||
|
||||
//Called at creature reset either by death or evade
|
||||
public override void Reset() { }
|
||||
|
||||
//Called at creature aggro either by MoveInLOS or Attack Start
|
||||
public override void JustEngagedWith(Unit victim) { }
|
||||
|
||||
public bool HealthBelowPct(int pct) { return me.HealthBelowPct(pct); }
|
||||
public bool HealthAbovePct(int pct) { return me.HealthAbovePct(pct); }
|
||||
|
||||
|
||||
@@ -1118,9 +1118,9 @@ namespace Game.AI
|
||||
GetScript().ProcessEventsFor(SmartEvents.RewardQuest, player, quest.Id, opt, false, null, me);
|
||||
}
|
||||
|
||||
public override void Destroyed(Player player, uint eventId)
|
||||
public override void Destroyed(WorldObject attacker, uint eventId)
|
||||
{
|
||||
GetScript().ProcessEventsFor(SmartEvents.Death, player, eventId, 0, false, null, me);
|
||||
GetScript().ProcessEventsFor(SmartEvents.Death, attacker != null ? attacker.ToUnit() : null, eventId, 0, false, null, me);
|
||||
}
|
||||
|
||||
public override void SetData(uint id, uint value) { SetData(id, value, null); }
|
||||
|
||||
@@ -490,7 +490,7 @@ namespace Game.AI
|
||||
_me.CastSpell(target.ToUnit(), e.Action.cast.spell, new CastSpellExtraArgs(triggerFlag));
|
||||
}
|
||||
else if (_go)
|
||||
_go.CastSpell(target.ToUnit(), e.Action.cast.spell, triggerFlag);
|
||||
_go.CastSpell(target.ToUnit(), e.Action.cast.spell, new CastSpellExtraArgs(triggerFlag));
|
||||
}
|
||||
else
|
||||
Log.outDebug(LogFilter.ScriptsAi, "Spell {0} not casted because it has flag SMARTCAST_AURA_NOT_PRESENT and the target (Guid: {1} Entry: {2} Type: {3}) already has the aura",
|
||||
|
||||
+1712
-1688
File diff suppressed because it is too large
Load Diff
@@ -143,7 +143,7 @@ namespace Game.Collision
|
||||
|
||||
public bool IsInLineOfSight(uint mapId, float x1, float y1, float z1, float x2, float y2, float z2, ModelIgnoreFlags ignoreFlags)
|
||||
{
|
||||
if (!IsLineOfSightCalcEnabled() || Global.DisableMgr.IsDisabledFor(DisableType.VMAP, mapId, null, DisableFlags.VmapLOS))
|
||||
if (!IsLineOfSightCalcEnabled() || Global.DisableMgr.IsDisabledFor(DisableType.VMAP, mapId, null, (byte)DisableFlags.VmapLOS))
|
||||
return true;
|
||||
|
||||
var instanceTree = iInstanceMapTrees.LookupByKey(mapId);
|
||||
@@ -160,7 +160,7 @@ namespace Game.Collision
|
||||
|
||||
public bool GetObjectHitPos(uint mapId, float x1, float y1, float z1, float x2, float y2, float z2, out float rx, out float ry, out float rz, float modifyDist)
|
||||
{
|
||||
if (IsLineOfSightCalcEnabled() && !Global.DisableMgr.IsDisabledFor(DisableType.VMAP, mapId, null, DisableFlags.VmapLOS))
|
||||
if (IsLineOfSightCalcEnabled() && !Global.DisableMgr.IsDisabledFor(DisableType.VMAP, mapId, null, (byte)DisableFlags.VmapLOS))
|
||||
{
|
||||
var instanceTree = iInstanceMapTrees.LookupByKey(mapId);
|
||||
if (instanceTree != null)
|
||||
@@ -186,7 +186,7 @@ namespace Game.Collision
|
||||
|
||||
public float GetHeight(uint mapId, float x, float y, float z, float maxSearchDist)
|
||||
{
|
||||
if (IsHeightCalcEnabled() && !Global.DisableMgr.IsDisabledFor(DisableType.VMAP, mapId, null, DisableFlags.VmapHeight))
|
||||
if (IsHeightCalcEnabled() && !Global.DisableMgr.IsDisabledFor(DisableType.VMAP, mapId, null, (byte)DisableFlags.VmapHeight))
|
||||
{
|
||||
var instanceTree = iInstanceMapTrees.LookupByKey(mapId);
|
||||
if (instanceTree != null)
|
||||
@@ -209,7 +209,7 @@ namespace Game.Collision
|
||||
adtId = 0;
|
||||
rootId = 0;
|
||||
groupId = 0;
|
||||
if (!Global.DisableMgr.IsDisabledFor(DisableType.VMAP, mapId, null, DisableFlags.VmapAreaFlag))
|
||||
if (!Global.DisableMgr.IsDisabledFor(DisableType.VMAP, mapId, null, (byte)DisableFlags.VmapAreaFlag))
|
||||
{
|
||||
var instanceTree = iInstanceMapTrees.LookupByKey(mapId);
|
||||
if (instanceTree != null)
|
||||
@@ -227,7 +227,7 @@ namespace Game.Collision
|
||||
|
||||
public bool GetLiquidLevel(uint mapId, float x, float y, float z, uint reqLiquidType, ref float level, ref float floor, ref uint type)
|
||||
{
|
||||
if (!Global.DisableMgr.IsDisabledFor(DisableType.VMAP, mapId, null, DisableFlags.VmapLiquidStatus))
|
||||
if (!Global.DisableMgr.IsDisabledFor(DisableType.VMAP, mapId, null, (byte)DisableFlags.VmapLiquidStatus))
|
||||
{
|
||||
var instanceTree = iInstanceMapTrees.LookupByKey(mapId);
|
||||
if (instanceTree != null)
|
||||
@@ -253,7 +253,7 @@ namespace Game.Collision
|
||||
{
|
||||
var data = new AreaAndLiquidData();
|
||||
|
||||
if (!Global.DisableMgr.IsDisabledFor(DisableType.VMAP, mapId, null, DisableFlags.VmapLiquidStatus))
|
||||
if (!Global.DisableMgr.IsDisabledFor(DisableType.VMAP, mapId, null, (byte)DisableFlags.VmapLiquidStatus))
|
||||
{
|
||||
data.floorZ = z;
|
||||
int adtId, rootId, groupId;
|
||||
@@ -276,7 +276,7 @@ namespace Game.Collision
|
||||
if (info.hitInstance.GetLiquidLevel(pos, info, ref liquidLevel))
|
||||
data.liquidInfo.Set(new AreaAndLiquidData.LiquidInfo(liquidType, liquidLevel));
|
||||
|
||||
if (!Global.DisableMgr.IsDisabledFor(DisableType.VMAP, mapId, null, DisableFlags.VmapLiquidStatus))
|
||||
if (!Global.DisableMgr.IsDisabledFor(DisableType.VMAP, mapId, null, (byte)DisableFlags.VmapLiquidStatus))
|
||||
data.areaInfo.Set(new AreaAndLiquidData.AreaInfo(info.hitInstance.adtId, info.rootId, (int)info.hitModel.GetWmoID(), info.hitModel.GetMogpFlags()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,17 +63,17 @@ namespace Game
|
||||
}
|
||||
|
||||
uint entry = result.Read<uint>(1);
|
||||
byte flags = result.Read<byte>(2);
|
||||
DisableFlags flags = (DisableFlags)result.Read<byte>(2);
|
||||
string params_0 = result.Read<string>(3);
|
||||
string params_1 = result.Read<string>(4);
|
||||
|
||||
DisableData data = new();
|
||||
data.flags = flags;
|
||||
data.flags = (byte)flags;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case DisableType.Spell:
|
||||
if (!(Global.SpellMgr.HasSpellInfo(entry, Difficulty.None) || flags.HasAnyFlag<byte>(DisableFlags.SpellDeprecatedSpell)))
|
||||
if (!(Global.SpellMgr.HasSpellInfo(entry, Difficulty.None) || flags.HasFlag(DisableFlags.SpellDeprecatedSpell)))
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "Spell entry {0} from `disables` doesn't exist in dbc, skipped.", entry);
|
||||
continue;
|
||||
@@ -85,7 +85,7 @@ namespace Game
|
||||
continue;
|
||||
}
|
||||
|
||||
if (flags.HasAnyFlag(DisableFlags.SpellMap))
|
||||
if (flags.HasFlag(DisableFlags.SpellMap))
|
||||
{
|
||||
var array = new StringArray(params_0, ',');
|
||||
for (byte i = 0; i < array.Length;)
|
||||
@@ -95,7 +95,7 @@ namespace Game
|
||||
}
|
||||
}
|
||||
|
||||
if (flags.HasAnyFlag(DisableFlags.SpellArea))
|
||||
if (flags.HasFlag(DisableFlags.SpellArea))
|
||||
{
|
||||
var array = new StringArray(params_1, ',');
|
||||
for (byte i = 0; i < array.Length;)
|
||||
@@ -111,43 +111,43 @@ namespace Game
|
||||
break;
|
||||
case DisableType.Map:
|
||||
case DisableType.LFGMap:
|
||||
{
|
||||
MapRecord mapEntry = CliDB.MapStorage.LookupByKey(entry);
|
||||
if (mapEntry == null)
|
||||
{
|
||||
MapRecord mapEntry = CliDB.MapStorage.LookupByKey(entry);
|
||||
if (mapEntry == null)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "Map entry {0} from `disables` doesn't exist in dbc, skipped.", entry);
|
||||
continue;
|
||||
}
|
||||
bool isFlagInvalid = false;
|
||||
switch (mapEntry.InstanceType)
|
||||
{
|
||||
case MapTypes.Common:
|
||||
if (flags != 0)
|
||||
isFlagInvalid = true;
|
||||
break;
|
||||
case MapTypes.Instance:
|
||||
case MapTypes.Raid:
|
||||
if (flags.HasAnyFlag(DisableFlags.DungeonStatusHeroic) && Global.DB2Mgr.GetMapDifficultyData(entry, Difficulty.Heroic) == null)
|
||||
flags -= DisableFlags.DungeonStatusHeroic;
|
||||
if (flags.HasAnyFlag(DisableFlags.DungeonStatusHeroic10Man) && Global.DB2Mgr.GetMapDifficultyData(entry, Difficulty.Raid10HC) == null)
|
||||
flags -= DisableFlags.DungeonStatusHeroic10Man;
|
||||
if (flags.HasAnyFlag(DisableFlags.DungeonStatusHeroic25Man) && Global.DB2Mgr.GetMapDifficultyData(entry, Difficulty.Raid25HC) == null)
|
||||
flags -= DisableFlags.DungeonStatusHeroic25Man;
|
||||
if (flags == 0)
|
||||
isFlagInvalid = true;
|
||||
break;
|
||||
case MapTypes.Battleground:
|
||||
case MapTypes.Arena:
|
||||
Log.outError(LogFilter.Sql, "Battlegroundmap {0} specified to be disabled in map case, skipped.", entry);
|
||||
continue;
|
||||
}
|
||||
if (isFlagInvalid)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "Disable flags for map {0} are invalid, skipped.", entry);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
Log.outError(LogFilter.Sql, "Map entry {0} from `disables` doesn't exist in dbc, skipped.", entry);
|
||||
continue;
|
||||
}
|
||||
bool isFlagInvalid = false;
|
||||
switch (mapEntry.InstanceType)
|
||||
{
|
||||
case MapTypes.Common:
|
||||
if (flags != 0)
|
||||
isFlagInvalid = true;
|
||||
break;
|
||||
case MapTypes.Instance:
|
||||
case MapTypes.Raid:
|
||||
if (flags.HasFlag(DisableFlags.DungeonStatusHeroic) && Global.DB2Mgr.GetMapDifficultyData(entry, Difficulty.Heroic) == null)
|
||||
flags &= ~DisableFlags.DungeonStatusHeroic;
|
||||
if (flags.HasFlag(DisableFlags.DungeonStatusHeroic10Man) && Global.DB2Mgr.GetMapDifficultyData(entry, Difficulty.Raid10HC) == null)
|
||||
flags &= ~DisableFlags.DungeonStatusHeroic10Man;
|
||||
if (flags.HasFlag(DisableFlags.DungeonStatusHeroic25Man) && Global.DB2Mgr.GetMapDifficultyData(entry, Difficulty.Raid25HC) == null)
|
||||
flags &= ~DisableFlags.DungeonStatusHeroic25Man;
|
||||
if (flags == 0)
|
||||
isFlagInvalid = true;
|
||||
break;
|
||||
case MapTypes.Battleground:
|
||||
case MapTypes.Arena:
|
||||
Log.outError(LogFilter.Sql, "Battlegroundmap {0} specified to be disabled in map case, skipped.", entry);
|
||||
continue;
|
||||
}
|
||||
if (isFlagInvalid)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "Disable flags for map {0} are invalid, skipped.", entry);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DisableType.Battleground:
|
||||
if (!CliDB.BattlemasterListStorage.ContainsKey(entry))
|
||||
{
|
||||
@@ -176,73 +176,73 @@ namespace Game
|
||||
Log.outError(LogFilter.Sql, "Disable flags specified for Criteria {0}, useless data.", entry);
|
||||
break;
|
||||
case DisableType.VMAP:
|
||||
{
|
||||
MapRecord mapEntry = CliDB.MapStorage.LookupByKey(entry);
|
||||
if (mapEntry == null)
|
||||
{
|
||||
MapRecord mapEntry = CliDB.MapStorage.LookupByKey(entry);
|
||||
if (mapEntry == null)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "Map entry {0} from `disables` doesn't exist in dbc, skipped.", entry);
|
||||
continue;
|
||||
}
|
||||
switch (mapEntry.InstanceType)
|
||||
{
|
||||
case MapTypes.Common:
|
||||
if (flags.HasAnyFlag(DisableFlags.VmapAreaFlag))
|
||||
Log.outInfo(LogFilter.Server, "Areaflag disabled for world map {0}.", entry);
|
||||
if (flags.HasAnyFlag(DisableFlags.VmapLiquidStatus))
|
||||
Log.outInfo(LogFilter.Server, "Liquid status disabled for world map {0}.", entry);
|
||||
break;
|
||||
case MapTypes.Instance:
|
||||
case MapTypes.Raid:
|
||||
if (flags.HasAnyFlag(DisableFlags.VmapHeight))
|
||||
Log.outInfo(LogFilter.Server, "Height disabled for instance map {0}.", entry);
|
||||
if (flags.HasAnyFlag(DisableFlags.VmapLOS))
|
||||
Log.outInfo(LogFilter.Server, "LoS disabled for instance map {0}.", entry);
|
||||
break;
|
||||
case MapTypes.Battleground:
|
||||
if (flags.HasAnyFlag(DisableFlags.VmapHeight))
|
||||
Log.outInfo(LogFilter.Server, "Height disabled for Battlegroundmap {0}.", entry);
|
||||
if (flags.HasAnyFlag(DisableFlags.VmapLOS))
|
||||
Log.outInfo(LogFilter.Server, "LoS disabled for Battlegroundmap {0}.", entry);
|
||||
break;
|
||||
case MapTypes.Arena:
|
||||
if (flags.HasAnyFlag(DisableFlags.VmapHeight))
|
||||
Log.outInfo(LogFilter.Server, "Height disabled for arena map {0}.", entry);
|
||||
if (flags.HasAnyFlag(DisableFlags.VmapLOS))
|
||||
Log.outInfo(LogFilter.Server, "LoS disabled for arena map {0}.", entry);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
Log.outError(LogFilter.Sql, "Map entry {0} from `disables` doesn't exist in dbc, skipped.", entry);
|
||||
continue;
|
||||
}
|
||||
switch (mapEntry.InstanceType)
|
||||
{
|
||||
case MapTypes.Common:
|
||||
if (flags.HasFlag(DisableFlags.VmapAreaFlag))
|
||||
Log.outInfo(LogFilter.Server, "Areaflag disabled for world map {0}.", entry);
|
||||
if (flags.HasFlag(DisableFlags.VmapLiquidStatus))
|
||||
Log.outInfo(LogFilter.Server, "Liquid status disabled for world map {0}.", entry);
|
||||
break;
|
||||
case MapTypes.Instance:
|
||||
case MapTypes.Raid:
|
||||
if (flags.HasFlag(DisableFlags.VmapHeight))
|
||||
Log.outInfo(LogFilter.Server, "Height disabled for instance map {0}.", entry);
|
||||
if (flags.HasFlag(DisableFlags.VmapLOS))
|
||||
Log.outInfo(LogFilter.Server, "LoS disabled for instance map {0}.", entry);
|
||||
break;
|
||||
case MapTypes.Battleground:
|
||||
if (flags.HasFlag(DisableFlags.VmapHeight))
|
||||
Log.outInfo(LogFilter.Server, "Height disabled for Battlegroundmap {0}.", entry);
|
||||
if (flags.HasFlag(DisableFlags.VmapLOS))
|
||||
Log.outInfo(LogFilter.Server, "LoS disabled for Battlegroundmap {0}.", entry);
|
||||
break;
|
||||
case MapTypes.Arena:
|
||||
if (flags.HasFlag(DisableFlags.VmapHeight))
|
||||
Log.outInfo(LogFilter.Server, "Height disabled for arena map {0}.", entry);
|
||||
if (flags.HasFlag(DisableFlags.VmapLOS))
|
||||
Log.outInfo(LogFilter.Server, "LoS disabled for arena map {0}.", entry);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DisableType.MMAP:
|
||||
{
|
||||
MapRecord mapEntry = CliDB.MapStorage.LookupByKey(entry);
|
||||
if (mapEntry == null)
|
||||
{
|
||||
MapRecord mapEntry = CliDB.MapStorage.LookupByKey(entry);
|
||||
if (mapEntry == null)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "Map entry {0} from `disables` doesn't exist in dbc, skipped.", entry);
|
||||
continue;
|
||||
}
|
||||
switch (mapEntry.InstanceType)
|
||||
{
|
||||
case MapTypes.Common:
|
||||
Log.outInfo(LogFilter.Server, "Pathfinding disabled for world map {0}.", entry);
|
||||
break;
|
||||
case MapTypes.Instance:
|
||||
case MapTypes.Raid:
|
||||
Log.outInfo(LogFilter.Server, "Pathfinding disabled for instance map {0}.", entry);
|
||||
break;
|
||||
case MapTypes.Battleground:
|
||||
Log.outInfo(LogFilter.Server, "Pathfinding disabled for Battlegroundmap {0}.", entry);
|
||||
break;
|
||||
case MapTypes.Arena:
|
||||
Log.outInfo(LogFilter.Server, "Pathfinding disabled for arena map {0}.", entry);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
Log.outError(LogFilter.Sql, "Map entry {0} from `disables` doesn't exist in dbc, skipped.", entry);
|
||||
continue;
|
||||
}
|
||||
switch (mapEntry.InstanceType)
|
||||
{
|
||||
case MapTypes.Common:
|
||||
Log.outInfo(LogFilter.Server, "Pathfinding disabled for world map {0}.", entry);
|
||||
break;
|
||||
case MapTypes.Instance:
|
||||
case MapTypes.Raid:
|
||||
Log.outInfo(LogFilter.Server, "Pathfinding disabled for instance map {0}.", entry);
|
||||
break;
|
||||
case MapTypes.Battleground:
|
||||
Log.outInfo(LogFilter.Server, "Pathfinding disabled for Battlegroundmap {0}.", entry);
|
||||
break;
|
||||
case MapTypes.Arena:
|
||||
Log.outInfo(LogFilter.Server, "Pathfinding disabled for arena map {0}.", entry);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -284,7 +284,7 @@ namespace Game
|
||||
Log.outInfo(LogFilter.ServerLoading, "Checked {0} quest disables in {1} ms", m_DisableMap[DisableType.Quest].Count, Time.GetMSTimeDiffToNow(oldMSTime));
|
||||
}
|
||||
|
||||
public bool IsDisabledFor(DisableType type, uint entry, Unit unit, byte flags = 0)
|
||||
public bool IsDisabledFor(DisableType type, uint entry, WorldObject refe, byte flags = 0)
|
||||
{
|
||||
Cypher.Assert(type < DisableType.Max);
|
||||
if (!m_DisableMap.ContainsKey(type) || m_DisableMap[type].Empty())
|
||||
@@ -297,66 +297,67 @@ namespace Game
|
||||
switch (type)
|
||||
{
|
||||
case DisableType.Spell:
|
||||
{
|
||||
DisableFlags spellFlags = (DisableFlags)data.flags;
|
||||
if (refe != null)
|
||||
{
|
||||
byte spellFlags = data.flags;
|
||||
if (unit != null)
|
||||
if ((refe.IsPlayer() && spellFlags.HasFlag(DisableFlags.SpellPlayer)) ||
|
||||
(refe.IsCreature() && (spellFlags.HasFlag(DisableFlags.SpellCreature) || (refe.ToUnit().IsPet() && spellFlags.HasFlag(DisableFlags.SpellPet)))) ||
|
||||
(refe.IsGameObject() && spellFlags.HasFlag(DisableFlags.SpellGameobject)))
|
||||
{
|
||||
if ((spellFlags.HasAnyFlag(DisableFlags.SpellPlayer) && unit.IsTypeId(TypeId.Player)) ||
|
||||
(unit.IsTypeId(TypeId.Unit) && ((unit.IsPet() && spellFlags.HasAnyFlag(DisableFlags.SpellPet)) || spellFlags.HasAnyFlag(DisableFlags.SpellCreature))))
|
||||
if (spellFlags.HasFlag(DisableFlags.SpellMap))
|
||||
{
|
||||
if (spellFlags.HasAnyFlag(DisableFlags.SpellMap))
|
||||
{
|
||||
List<uint> mapIds = data.param0;
|
||||
if (mapIds.Contains(unit.GetMapId()))
|
||||
return true; // Spell is disabled on current map
|
||||
List<uint> mapIds = data.param0;
|
||||
if (mapIds.Contains(refe.GetMapId()))
|
||||
return true; // Spell is disabled on current map
|
||||
|
||||
if (!spellFlags.HasAnyFlag(DisableFlags.SpellArea))
|
||||
return false; // Spell is disabled on another map, but not this one, return false
|
||||
if (!spellFlags.HasFlag(DisableFlags.SpellArea))
|
||||
return false; // Spell is disabled on another map, but not this one, return false
|
||||
|
||||
// Spell is disabled in an area, but not explicitly our current mapId. Continue processing.
|
||||
}
|
||||
|
||||
if (spellFlags.HasAnyFlag(DisableFlags.SpellArea))
|
||||
{
|
||||
var areaIds = data.param1;
|
||||
if (areaIds.Contains(unit.GetAreaId()))
|
||||
return true; // Spell is disabled in this area
|
||||
return false; // Spell is disabled in another area, but not this one, return false
|
||||
}
|
||||
else
|
||||
return true; // Spell disabled for all maps
|
||||
// Spell is disabled in an area, but not explicitly our current mapId. Continue processing.
|
||||
}
|
||||
|
||||
return false;
|
||||
if (spellFlags.HasFlag(DisableFlags.SpellArea))
|
||||
{
|
||||
var areaIds = data.param1;
|
||||
if (areaIds.Contains(refe.GetAreaId()))
|
||||
return true; // Spell is disabled in this area
|
||||
return false; // Spell is disabled in another area, but not this one, return false
|
||||
}
|
||||
else
|
||||
return true; // Spell disabled for all maps
|
||||
}
|
||||
else if (spellFlags.HasAnyFlag(DisableFlags.SpellDeprecatedSpell)) // call not from spellcast
|
||||
return true;
|
||||
else if (flags.HasAnyFlag(DisableFlags.SpellLOS))
|
||||
return spellFlags.HasAnyFlag(DisableFlags.SpellLOS);
|
||||
|
||||
break;
|
||||
return false;
|
||||
}
|
||||
else if (spellFlags.HasFlag(DisableFlags.SpellDeprecatedSpell)) // call not from spellcast
|
||||
return true;
|
||||
else if (flags.HasAnyFlag((byte)DisableFlags.SpellLOS))
|
||||
return spellFlags.HasFlag(DisableFlags.SpellLOS);
|
||||
|
||||
break;
|
||||
}
|
||||
case DisableType.Map:
|
||||
case DisableType.LFGMap:
|
||||
Player player = unit.ToPlayer();
|
||||
Player player = refe.ToPlayer();
|
||||
if (player != null)
|
||||
{
|
||||
MapRecord mapEntry = CliDB.MapStorage.LookupByKey(entry);
|
||||
if (mapEntry.IsDungeon())
|
||||
{
|
||||
byte disabledModes = data.flags;
|
||||
DisableFlags disabledModes = (DisableFlags)data.flags;
|
||||
Difficulty targetDifficulty = player.GetDifficultyID(mapEntry);
|
||||
Global.DB2Mgr.GetDownscaledMapDifficultyData(entry, ref targetDifficulty);
|
||||
switch (targetDifficulty)
|
||||
{
|
||||
case Difficulty.Normal:
|
||||
return disabledModes.HasAnyFlag(DisableFlags.DungeonStatusNormal);
|
||||
return disabledModes.HasFlag(DisableFlags.DungeonStatusNormal);
|
||||
case Difficulty.Heroic:
|
||||
return disabledModes.HasAnyFlag(DisableFlags.DungeonStatusHeroic);
|
||||
return disabledModes.HasFlag(DisableFlags.DungeonStatusHeroic);
|
||||
case Difficulty.Raid10HC:
|
||||
return disabledModes.HasAnyFlag(DisableFlags.DungeonStatusHeroic10Man);
|
||||
return disabledModes.HasFlag(DisableFlags.DungeonStatusHeroic10Man);
|
||||
case Difficulty.Raid25HC:
|
||||
return disabledModes.HasAnyFlag(DisableFlags.DungeonStatusHeroic25Man);
|
||||
return disabledModes.HasFlag(DisableFlags.DungeonStatusHeroic25Man);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -366,9 +367,9 @@ namespace Game
|
||||
}
|
||||
return false;
|
||||
case DisableType.Quest:
|
||||
if (unit == null)
|
||||
if (refe == null)
|
||||
return true;
|
||||
Player player1 = unit.ToPlayer();
|
||||
Player player1 = refe.ToPlayer();
|
||||
if (player1 != null)
|
||||
if (player1.IsGameMaster())
|
||||
return false;
|
||||
@@ -401,7 +402,7 @@ namespace Game
|
||||
Spell = 0,
|
||||
Quest = 1,
|
||||
Map = 2,
|
||||
Battleground= 3,
|
||||
Battleground = 3,
|
||||
Criteria = 4,
|
||||
OutdoorPVP = 5,
|
||||
VMAP = 6,
|
||||
@@ -410,31 +411,32 @@ namespace Game
|
||||
Max = 9
|
||||
}
|
||||
|
||||
public struct DisableFlags
|
||||
[Flags]
|
||||
public enum DisableFlags
|
||||
{
|
||||
public const byte SpellPlayer = 0x1;
|
||||
public const byte SpellCreature = 0x2;
|
||||
public const byte SpellPet = 0x4;
|
||||
public const byte SpellDeprecatedSpell = 0x8;
|
||||
public const byte SpellMap = 0x10;
|
||||
public const byte SpellArea = 0x20;
|
||||
public const byte SpellLOS = 0x40;
|
||||
public const byte MaxSpell = (SpellPlayer | SpellCreature | SpellPet | SpellDeprecatedSpell | SpellMap | SpellArea | SpellLOS);
|
||||
SpellPlayer = 0x01,
|
||||
SpellCreature = 0x02,
|
||||
SpellPet = 0x04,
|
||||
SpellDeprecatedSpell = 0x08,
|
||||
SpellMap = 0x10,
|
||||
SpellArea = 0x20,
|
||||
SpellLOS = 0x40,
|
||||
SpellGameobject = 0x80,
|
||||
MaxSpell = SpellPlayer | SpellCreature | SpellPet | SpellDeprecatedSpell | SpellMap | SpellArea | SpellLOS | SpellGameobject,
|
||||
|
||||
public const byte VmapAreaFlag = 0x1;
|
||||
public const byte VmapHeight = 0x2;
|
||||
public const byte VmapLOS = 0x4;
|
||||
public const byte VmapLiquidStatus = 0x8;
|
||||
VmapAreaFlag = 0x01,
|
||||
VmapHeight = 0x02,
|
||||
VmapLOS = 0x04,
|
||||
VmapLiquidStatus = 0x08,
|
||||
|
||||
public const byte MMapPathFinding = 0x0;
|
||||
MMapPathFinding = 0x00,
|
||||
|
||||
public const byte DungeonStatusNormal = 0x01;
|
||||
public const byte DungeonStatusHeroic = 0x02;
|
||||
|
||||
public const byte DungeonStatusNormal10Man = 0x01;
|
||||
public const byte DungeonStatusNormal25Man = 0x02;
|
||||
public const byte DungeonStatusHeroic10Man = 0x04;
|
||||
public const byte DungeonStatusHeroic25Man = 0x08;
|
||||
DungeonStatusNormal = 0x01,
|
||||
DungeonStatusHeroic = 0x02,
|
||||
|
||||
DungeonStatusNormal10Man = 0x01,
|
||||
DungeonStatusNormal25Man = 0x02,
|
||||
DungeonStatusHeroic10Man = 0x04,
|
||||
DungeonStatusHeroic25Man = 0x08
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -491,6 +491,15 @@ namespace Game.Entities
|
||||
return Global.ObjAccessor.GetUnit(this, _targetGuid);
|
||||
}
|
||||
|
||||
public override uint GetFaction()
|
||||
{
|
||||
Unit caster = GetCaster();
|
||||
if (caster)
|
||||
return caster.GetFaction();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void UpdatePolygonOrientation()
|
||||
{
|
||||
float newOrientation = GetOrientation();
|
||||
@@ -1002,6 +1011,7 @@ namespace Game.Entities
|
||||
|
||||
public AreaTriggerMiscTemplate GetMiscTemplate() { return _areaTriggerMiscTemplate; }
|
||||
|
||||
public override ObjectGuid GetOwnerGUID() { return GetCasterGuid(); }
|
||||
public ObjectGuid GetCasterGuid() { return m_areaTriggerData.Caster; }
|
||||
|
||||
public Vector3 GetRollPitchYaw() { return _rollPitchYaw; }
|
||||
|
||||
@@ -288,7 +288,9 @@ namespace Game.Entities
|
||||
public uint GetTextureKitId() { return _textureKitId; }
|
||||
|
||||
public ObjectGuid GetCreatorGuid() { return _creatorGuid; }
|
||||
|
||||
public override ObjectGuid GetOwnerGUID() { return GetCreatorGuid(); }
|
||||
public override uint GetFaction() { return 0; }
|
||||
|
||||
public override float GetStationaryX() { return _stationaryPosition.GetPositionX(); }
|
||||
public override float GetStationaryY() { return _stationaryPosition.GetPositionY(); }
|
||||
public override float GetStationaryZ() { return _stationaryPosition.GetPositionZ(); }
|
||||
|
||||
@@ -287,7 +287,7 @@ namespace Game.Entities
|
||||
public void AddCorpseDynamicFlag(CorpseDynFlags dynamicFlags) { SetUpdateFieldFlagValue(m_values.ModifyValue(m_corpseData).ModifyValue(m_corpseData.DynamicFlags), (uint)dynamicFlags); }
|
||||
public void RemoveCorpseDynamicFlag(CorpseDynFlags dynamicFlags) { RemoveUpdateFieldFlagValue(m_values.ModifyValue(m_corpseData).ModifyValue(m_corpseData.DynamicFlags), (uint)dynamicFlags); }
|
||||
public void SetCorpseDynamicFlags(CorpseDynFlags dynamicFlags) { SetUpdateFieldValue(m_values.ModifyValue(m_corpseData).ModifyValue(m_corpseData.DynamicFlags), (uint)dynamicFlags); }
|
||||
public ObjectGuid GetOwnerGUID() { return m_corpseData.Owner; }
|
||||
public override ObjectGuid GetOwnerGUID() { return m_corpseData.Owner; }
|
||||
public void SetOwnerGUID(ObjectGuid owner) { SetUpdateFieldValue(m_values.ModifyValue(m_corpseData).ModifyValue(m_corpseData.Owner), owner); }
|
||||
public void SetPartyGUID(ObjectGuid partyGuid) { SetUpdateFieldValue(m_values.ModifyValue(m_corpseData).ModifyValue(m_corpseData.PartyGUID), partyGuid); }
|
||||
public void SetGuildGUID(ObjectGuid guildGuid) { SetUpdateFieldValue(m_values.ModifyValue(m_corpseData).ModifyValue(m_corpseData.GuildGUID), guildGuid); }
|
||||
@@ -297,6 +297,8 @@ namespace Game.Entities
|
||||
public void SetSex(byte sex) { SetUpdateFieldValue(m_values.ModifyValue(m_corpseData).ModifyValue(m_corpseData.Sex), sex); }
|
||||
public void SetFlags(CorpseFlags flags) { SetUpdateFieldValue(m_values.ModifyValue(m_corpseData).ModifyValue(m_corpseData.Flags), (uint)flags); }
|
||||
public void SetFactionTemplate(int factionTemplate) { SetUpdateFieldValue(m_values.ModifyValue(m_corpseData).ModifyValue(m_corpseData.FactionTemplate), factionTemplate); }
|
||||
public override uint GetFaction() { return (uint)(int)m_corpseData.FactionTemplate; }
|
||||
public override void SetFaction(uint faction) { SetFactionTemplate((int)faction); }
|
||||
public void SetItem(uint slot, uint item) { SetUpdateFieldValue(ref m_values.ModifyValue(m_corpseData).ModifyValue(m_corpseData.Items, (int)slot), item); }
|
||||
|
||||
public void SetCustomizations(List<ChrCustomizationChoice> customizations)
|
||||
|
||||
@@ -2039,7 +2039,7 @@ namespace Game.Entities
|
||||
ApplySpellImmune(placeholderSpellId, SpellImmunity.School, 1u << i, true);
|
||||
}
|
||||
|
||||
public override bool IsImmunedToSpell(SpellInfo spellInfo, Unit caster)
|
||||
public override bool IsImmunedToSpell(SpellInfo spellInfo, WorldObject caster)
|
||||
{
|
||||
if (spellInfo == null)
|
||||
return false;
|
||||
@@ -2063,7 +2063,7 @@ namespace Game.Entities
|
||||
return base.IsImmunedToSpell(spellInfo, caster);
|
||||
}
|
||||
|
||||
public override bool IsImmunedToSpellEffect(SpellInfo spellInfo, uint index, Unit caster)
|
||||
public override bool IsImmunedToSpellEffect(SpellInfo spellInfo, uint index, WorldObject caster)
|
||||
{
|
||||
SpellEffectInfo effect = spellInfo.GetEffect(index);
|
||||
if (effect == null)
|
||||
|
||||
@@ -226,6 +226,12 @@ namespace Game.Entities
|
||||
}
|
||||
}
|
||||
|
||||
public override uint GetFaction()
|
||||
{
|
||||
Cypher.Assert(_caster != null);
|
||||
return _caster.GetFaction();
|
||||
}
|
||||
|
||||
void BindToCaster()
|
||||
{
|
||||
Cypher.Assert(_caster == null);
|
||||
@@ -312,6 +318,7 @@ namespace Game.Entities
|
||||
public Unit GetCaster() { return _caster; }
|
||||
public uint GetSpellId() { return m_dynamicObjectData.SpellID; }
|
||||
public ObjectGuid GetCasterGUID() { return m_dynamicObjectData.Caster; }
|
||||
public override ObjectGuid GetOwnerGUID() { return GetCasterGUID(); }
|
||||
public float GetRadius() { return m_dynamicObjectData.Radius; }
|
||||
|
||||
DynamicObjectData m_dynamicObjectData;
|
||||
|
||||
@@ -423,6 +423,8 @@ namespace Game.Entities
|
||||
|
||||
public override void Update(uint diff)
|
||||
{
|
||||
m_Events.Update(diff);
|
||||
|
||||
if (GetAI() != null)
|
||||
GetAI().UpdateAI(diff);
|
||||
else if (!AIM_Initialize())
|
||||
@@ -730,8 +732,9 @@ namespace Game.Entities
|
||||
else if (target)
|
||||
{
|
||||
// Some traps do not have a spell but should be triggered
|
||||
CastSpellExtraArgs args = new(GetOwnerGUID());
|
||||
if (goInfo.Trap.spell != 0)
|
||||
CastSpell(target, goInfo.Trap.spell);
|
||||
CastSpell(target, goInfo.Trap.spell, args);
|
||||
|
||||
// Template value or 4 seconds
|
||||
m_cooldownTime = (GameTime.GetGameTimeMS() + (goInfo.Trap.cooldown != 0 ? goInfo.Trap.cooldown : 4u)) * Time.InMilliseconds;
|
||||
@@ -1202,11 +1205,6 @@ namespace Game.Entities
|
||||
|
||||
public Transport ToTransport() { return GetGoInfo().type == GameObjectTypes.MapObjTransport ? (this as Transport) : null; }
|
||||
|
||||
public Unit GetOwner()
|
||||
{
|
||||
return Global.ObjAccessor.GetUnit(this, GetOwnerGUID());
|
||||
}
|
||||
|
||||
public override void SaveRespawnTime(uint forceDelay = 0, bool savetodb = true)
|
||||
{
|
||||
if (m_goData != null && (forceDelay != 0 || m_respawnTime > GameTime.GetGameTime()) && m_spawnedByDefault)
|
||||
@@ -2089,69 +2087,6 @@ namespace Game.Entities
|
||||
CastSpell(user, spellId);
|
||||
}
|
||||
|
||||
public void CastSpell(Unit target, uint spellId, bool triggered = true)
|
||||
{
|
||||
CastSpell(target, spellId, triggered ? TriggerCastFlags.FullMask : TriggerCastFlags.None);
|
||||
}
|
||||
|
||||
public void CastSpell(Unit target, uint spellId, TriggerCastFlags triggered)
|
||||
{
|
||||
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId, GetMap().GetDifficultyID());
|
||||
if (spellInfo == null)
|
||||
return;
|
||||
|
||||
bool self = false;
|
||||
foreach (SpellEffectInfo effect in spellInfo.GetEffects())
|
||||
{
|
||||
if (effect != null && effect.TargetA.GetTarget() == Targets.UnitCaster)
|
||||
{
|
||||
self = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (self)
|
||||
{
|
||||
if (target != null)
|
||||
target.CastSpell(target, spellInfo.Id, new CastSpellExtraArgs(triggered));
|
||||
return;
|
||||
}
|
||||
|
||||
//summon world trigger
|
||||
Creature trigger = SummonTrigger(GetPositionX(), GetPositionY(), GetPositionZ(), 0, (uint)(spellInfo.CalcCastTime() + 100));
|
||||
if (!trigger)
|
||||
return;
|
||||
|
||||
// remove immunity flags, to allow spell to target anything
|
||||
trigger.SetImmuneToAll(false);
|
||||
|
||||
PhasingHandler.InheritPhaseShift(trigger, this);
|
||||
|
||||
CastSpellExtraArgs args = new(triggered);
|
||||
Unit owner = GetOwner();
|
||||
if (owner)
|
||||
{
|
||||
trigger.SetFaction(owner.GetFaction());
|
||||
if (owner.HasUnitFlag(UnitFlags.PvpAttackable))
|
||||
trigger.AddUnitFlag(UnitFlags.PvpAttackable);
|
||||
// copy pvp state flags from owner
|
||||
trigger.SetPvpFlags(owner.GetPvpFlags());
|
||||
// needed for GO casts for proper target validation checks
|
||||
trigger.SetOwnerGUID(owner.GetGUID());
|
||||
|
||||
args.OriginalCaster = owner.GetGUID();
|
||||
trigger.CastSpell(target ?? trigger, spellInfo.Id, args);
|
||||
}
|
||||
else
|
||||
{
|
||||
trigger.SetFaction(spellInfo.IsPositive() ? 35 : 14u);
|
||||
// Set owner guid for target if no owner available - needed by trigger auras
|
||||
// - trigger gets despawned and there's no caster avalible (see AuraEffect.TriggerSpell())
|
||||
args.OriginalCaster = target ? target.GetGUID() : ObjectGuid.Empty;
|
||||
trigger.CastSpell(target ?? trigger, spellInfo.Id, args);
|
||||
}
|
||||
}
|
||||
|
||||
public void SendCustomAnim(uint anim)
|
||||
{
|
||||
GameObjectCustomAnim customAnim = new();
|
||||
@@ -2266,7 +2201,7 @@ namespace Game.Entities
|
||||
SetWorldRotation(quat.X, quat.Y, quat.Z, quat.W);
|
||||
}
|
||||
|
||||
public void ModifyHealth(int change, Unit attackerOrHealer = null, uint spellId = 0)
|
||||
public void ModifyHealth(int change, WorldObject attackerOrHealer = null, uint spellId = 0)
|
||||
{
|
||||
if (m_goValue.Building.MaxHealth == 0 || change == 0)
|
||||
return;
|
||||
@@ -2285,9 +2220,8 @@ namespace Game.Entities
|
||||
// Set the health bar, value = 255 * healthPct;
|
||||
SetGoAnimProgress(m_goValue.Building.Health * 255 / m_goValue.Building.MaxHealth);
|
||||
|
||||
Player player = attackerOrHealer.GetCharmerOrOwnerPlayerOrPlayerItself();
|
||||
|
||||
// dealing damage, send packet
|
||||
Player player = attackerOrHealer != null ? attackerOrHealer.GetCharmerOrOwnerPlayerOrPlayerItself() : null;
|
||||
if (player != null)
|
||||
{
|
||||
DestructibleBuildingDamage packet = new();
|
||||
@@ -2311,10 +2245,10 @@ namespace Game.Entities
|
||||
if (newState == GetDestructibleState())
|
||||
return;
|
||||
|
||||
SetDestructibleState(newState, player, false);
|
||||
SetDestructibleState(newState, attackerOrHealer, false);
|
||||
}
|
||||
|
||||
public void SetDestructibleState(GameObjectDestructibleState state, Player eventInvoker = null, bool setHealth = false)
|
||||
public void SetDestructibleState(GameObjectDestructibleState state, WorldObject attackerOrHealer = null, bool setHealth = false)
|
||||
{
|
||||
// the user calling this must know he is already operating on destructible gameobject
|
||||
Cypher.Assert(GetGoType() == GameObjectTypes.DestructibleBuilding);
|
||||
@@ -2333,8 +2267,8 @@ namespace Game.Entities
|
||||
break;
|
||||
case GameObjectDestructibleState.Damaged:
|
||||
{
|
||||
EventInform(m_goInfo.DestructibleBuilding.DamagedEvent, eventInvoker);
|
||||
GetAI().Damaged(eventInvoker, m_goInfo.DestructibleBuilding.DamagedEvent);
|
||||
EventInform(m_goInfo.DestructibleBuilding.DamagedEvent, attackerOrHealer);
|
||||
GetAI().Damaged(attackerOrHealer, m_goInfo.DestructibleBuilding.DamagedEvent);
|
||||
|
||||
RemoveFlag(GameObjectFlags.Destroyed);
|
||||
AddFlag(GameObjectFlags.Damaged);
|
||||
@@ -2359,13 +2293,14 @@ namespace Game.Entities
|
||||
}
|
||||
case GameObjectDestructibleState.Destroyed:
|
||||
{
|
||||
EventInform(m_goInfo.DestructibleBuilding.DestroyedEvent, eventInvoker);
|
||||
GetAI().Destroyed(eventInvoker, m_goInfo.DestructibleBuilding.DestroyedEvent);
|
||||
if (eventInvoker != null)
|
||||
EventInform(m_goInfo.DestructibleBuilding.DestroyedEvent, attackerOrHealer);
|
||||
GetAI().Destroyed(attackerOrHealer, m_goInfo.DestructibleBuilding.DestroyedEvent);
|
||||
|
||||
if (attackerOrHealer != null && attackerOrHealer.IsPlayer())
|
||||
{
|
||||
Battleground bg = eventInvoker.GetBattleground();
|
||||
if (bg)
|
||||
bg.DestroyGate(eventInvoker, this);
|
||||
var bg = attackerOrHealer.ToPlayer().GetBattleground();
|
||||
if (bg != null)
|
||||
bg.DestroyGate(attackerOrHealer.ToPlayer(), this);
|
||||
}
|
||||
|
||||
RemoveFlag(GameObjectFlags.Damaged);
|
||||
@@ -2388,7 +2323,7 @@ namespace Game.Entities
|
||||
}
|
||||
case GameObjectDestructibleState.Rebuilding:
|
||||
{
|
||||
EventInform(m_goInfo.DestructibleBuilding.RebuildingEvent, eventInvoker);
|
||||
EventInform(m_goInfo.DestructibleBuilding.RebuildingEvent, attackerOrHealer);
|
||||
RemoveFlag(GameObjectFlags.Damaged | GameObjectFlags.Destroyed);
|
||||
|
||||
uint modelId = m_goInfo.displayId;
|
||||
@@ -2769,7 +2704,7 @@ namespace Game.Entities
|
||||
m_spawnedByDefault = false; // all object with owner is despawned after delay
|
||||
SetUpdateFieldValue(m_values.ModifyValue(m_gameObjectData).ModifyValue(m_gameObjectData.CreatedBy), owner);
|
||||
}
|
||||
public ObjectGuid GetOwnerGUID() { return m_gameObjectData.CreatedBy; }
|
||||
public override ObjectGuid GetOwnerGUID() { return m_gameObjectData.CreatedBy; }
|
||||
|
||||
public void SetSpellId(uint id)
|
||||
{
|
||||
@@ -2871,8 +2806,8 @@ namespace Game.Entities
|
||||
|
||||
public uint GetDisplayId() { return m_gameObjectData.DisplayID; }
|
||||
|
||||
public uint GetFaction() { return m_gameObjectData.FactionTemplate; }
|
||||
public void SetFaction(uint faction) { SetUpdateFieldValue(m_values.ModifyValue(m_gameObjectData).ModifyValue(m_gameObjectData.FactionTemplate), faction); }
|
||||
public override uint GetFaction() { return m_gameObjectData.FactionTemplate; }
|
||||
public override void SetFaction(uint faction) { SetUpdateFieldValue(m_values.ModifyValue(m_gameObjectData).ModifyValue(m_gameObjectData.FactionTemplate), faction); }
|
||||
|
||||
public override float GetStationaryX() { return StationaryPosition.GetPositionX(); }
|
||||
public override float GetStationaryY() { return StationaryPosition.GetPositionY(); }
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -66,10 +66,10 @@ namespace Game.Entities
|
||||
m_questObjectiveCriteriaMgr.ResetCriteria(failEvent, failAsset, evenIfCriteriaComplete);
|
||||
}
|
||||
|
||||
public void UpdateCriteria(CriteriaTypes type, ulong miscValue1 = 0, ulong miscValue2 = 0, ulong miscValue3 = 0, Unit unit = null)
|
||||
public void UpdateCriteria(CriteriaTypes type, ulong miscValue1 = 0, ulong miscValue2 = 0, ulong miscValue3 = 0, WorldObject refe = null)
|
||||
{
|
||||
m_achievementSys.UpdateCriteria(type, miscValue1, miscValue2, miscValue3, unit, this);
|
||||
m_questObjectiveCriteriaMgr.UpdateCriteria(type, miscValue1, miscValue2, miscValue3, unit, this);
|
||||
m_achievementSys.UpdateCriteria(type, miscValue1, miscValue2, miscValue3, refe, this);
|
||||
m_questObjectiveCriteriaMgr.UpdateCriteria(type, miscValue1, miscValue2, miscValue3, refe, this);
|
||||
|
||||
// Update only individual achievement criteria here, otherwise we may get multiple updates
|
||||
// from a single boss kill
|
||||
@@ -78,11 +78,11 @@ namespace Game.Entities
|
||||
|
||||
Scenario scenario = GetScenario();
|
||||
if (scenario != null)
|
||||
scenario.UpdateCriteria(type, miscValue1, miscValue2, miscValue3, unit, this);
|
||||
scenario.UpdateCriteria(type, miscValue1, miscValue2, miscValue3, refe, this);
|
||||
|
||||
Guild guild = Global.GuildMgr.GetGuildById(GetGuildId());
|
||||
if (guild)
|
||||
guild.UpdateCriteria(type, miscValue1, miscValue2, miscValue3, unit, this);
|
||||
guild.UpdateCriteria(type, miscValue1, miscValue2, miscValue3, refe, this);
|
||||
}
|
||||
|
||||
public void CompletedAchievement(AchievementRecord entry)
|
||||
|
||||
@@ -3482,7 +3482,7 @@ namespace Game.Entities
|
||||
SetFaction(rEntry != null ? (uint)rEntry.FactionID : 0);
|
||||
}
|
||||
|
||||
public void SetResurrectRequestData(Unit caster, uint health, uint mana, uint appliedAura)
|
||||
public void SetResurrectRequestData(WorldObject caster, uint health, uint mana, uint appliedAura)
|
||||
{
|
||||
Cypher.Assert(!IsResurrectRequested());
|
||||
_resurrectionData = new ResurrectionData();
|
||||
@@ -3633,7 +3633,7 @@ namespace Game.Entities
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool IsImmunedToSpellEffect(SpellInfo spellInfo, uint index, Unit caster)
|
||||
public override bool IsImmunedToSpellEffect(SpellInfo spellInfo, uint index, WorldObject caster)
|
||||
{
|
||||
SpellEffectInfo effect = spellInfo.GetEffect(index);
|
||||
if (effect == null || !effect.IsEffect())
|
||||
@@ -6637,46 +6637,6 @@ namespace Game.Entities
|
||||
return m_auraBaseFlatMod[(int)modGroup] * m_auraBasePctMod[(int)modGroup];
|
||||
}
|
||||
|
||||
public void AddComboPoints(sbyte count, Spell spell = null)
|
||||
{
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
sbyte comboPoints = spell != null ? spell.m_comboPointGain : (sbyte)GetPower(PowerType.ComboPoints);
|
||||
|
||||
comboPoints += count;
|
||||
|
||||
if (comboPoints > 5)
|
||||
comboPoints = 5;
|
||||
else if (comboPoints < 0)
|
||||
comboPoints = 0;
|
||||
|
||||
if (spell == null)
|
||||
SetPower(PowerType.ComboPoints, comboPoints);
|
||||
else
|
||||
spell.m_comboPointGain = comboPoints;
|
||||
}
|
||||
public void GainSpellComboPoints(sbyte count)
|
||||
{
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
sbyte cp = (sbyte)GetPower(PowerType.ComboPoints);
|
||||
cp += count;
|
||||
|
||||
if (cp > 5)
|
||||
cp = 5;
|
||||
else if (cp < 0)
|
||||
cp = 0;
|
||||
|
||||
SetPower(PowerType.ComboPoints, cp);
|
||||
}
|
||||
public void ClearComboPoints()
|
||||
{
|
||||
SetPower(PowerType.ComboPoints, 0);
|
||||
}
|
||||
public byte GetComboPoints() { return (byte)GetPower(PowerType.ComboPoints); }
|
||||
|
||||
public byte GetDrunkValue() { return m_playerData.Inebriation; }
|
||||
public void SetDrunkValue(byte newDrunkValue, uint itemId = 0)
|
||||
{
|
||||
|
||||
@@ -788,7 +788,7 @@ namespace Game.Entities
|
||||
public void SetRangedWeaponAttackPower(int attackPower) { SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.RangedWeaponAttackPower), attackPower); }
|
||||
|
||||
//Chances
|
||||
float MeleeSpellMissChance(Unit victim, WeaponAttackType attType, SpellInfo spellInfo)
|
||||
public override float MeleeSpellMissChance(Unit victim, WeaponAttackType attType, SpellInfo spellInfo)
|
||||
{
|
||||
//calculate miss chance
|
||||
float missChance = victim.GetUnitMissChance();
|
||||
|
||||
@@ -143,7 +143,7 @@ namespace Game.Entities
|
||||
AddObjectToRemoveList();
|
||||
}
|
||||
|
||||
public override bool IsImmunedToSpellEffect(SpellInfo spellInfo, uint index, Unit caster)
|
||||
public override bool IsImmunedToSpellEffect(SpellInfo spellInfo, uint index, WorldObject caster)
|
||||
{
|
||||
// @todo possibly all negative auras immune?
|
||||
if (GetEntry() == 5925)
|
||||
|
||||
@@ -631,43 +631,6 @@ namespace Game.Entities
|
||||
|
||||
public void SetBaseWeaponDamage(WeaponAttackType attType, WeaponDamageRange damageRange, float value) { m_weaponDamage[(int)attType][(int)damageRange] = value; }
|
||||
|
||||
public Unit GetMagicHitRedirectTarget(Unit victim, SpellInfo spellInfo)
|
||||
{
|
||||
// Patch 1.2 notes: Spell Reflection no longer reflects abilities
|
||||
if (spellInfo.HasAttribute(SpellAttr0.Ability) || spellInfo.HasAttribute(SpellAttr1.CantBeRedirected) || spellInfo.HasAttribute(SpellAttr0.UnaffectedByInvulnerability))
|
||||
return victim;
|
||||
|
||||
var magnetAuras = victim.GetAuraEffectsByType(AuraType.SpellMagnet);
|
||||
foreach (var eff in magnetAuras)
|
||||
{
|
||||
Unit magnet = eff.GetBase().GetCaster();
|
||||
if (magnet != null)
|
||||
{
|
||||
if (spellInfo.CheckExplicitTarget(this, magnet) == SpellCastResult.SpellCastOk && IsValidAttackTarget(magnet, spellInfo))
|
||||
{
|
||||
// @todo handle this charge drop by proc in cast phase on explicit target
|
||||
if (spellInfo.HasHitDelay())
|
||||
{
|
||||
// Set up missile speed based delay
|
||||
float hitDelay = spellInfo.LaunchDelay;
|
||||
if (spellInfo.HasAttribute(SpellAttr9.SpecialDelayCalculation))
|
||||
hitDelay += spellInfo.Speed;
|
||||
else if (spellInfo.Speed > 0.0f)
|
||||
hitDelay += Math.Max(victim.GetDistance(this), 5.0f) / spellInfo.Speed;
|
||||
|
||||
uint delay = (uint)Math.Floor(hitDelay * 1000.0f);
|
||||
// Schedule charge drop
|
||||
eff.GetBase().DropChargeDelayed(delay, AuraRemoveMode.Expire);
|
||||
}
|
||||
else
|
||||
eff.GetBase().DropCharge(AuraRemoveMode.Expire);
|
||||
return magnet;
|
||||
}
|
||||
}
|
||||
}
|
||||
return victim;
|
||||
}
|
||||
|
||||
public Unit GetMeleeHitRedirectTarget(Unit victim, SpellInfo spellInfo = null)
|
||||
{
|
||||
var interceptAuras = victim.GetAuraEffectsByType(AuraType.InterceptMeleeRangedAttacks);
|
||||
@@ -753,17 +716,6 @@ namespace Game.Entities
|
||||
}
|
||||
}
|
||||
|
||||
internal void SendCombatLogMessage(CombatLogServerPacket combatLog)
|
||||
{
|
||||
CombatLogSender combatLogSender = new(combatLog);
|
||||
|
||||
if (IsPlayer())
|
||||
combatLogSender.Invoke(ToPlayer());
|
||||
|
||||
var notifier = new MessageDistDeliverer<CombatLogSender>(this, combatLogSender, GetVisibilityRange());
|
||||
Cell.VisitWorldObjects(this, notifier, GetVisibilityRange());
|
||||
}
|
||||
|
||||
bool IsThreatened()
|
||||
{
|
||||
return !m_threatManager.IsThreatListEmpty();
|
||||
@@ -1562,286 +1514,6 @@ namespace Game.Entities
|
||||
}
|
||||
}
|
||||
|
||||
// function based on function Unit::CanAttack from 13850 client
|
||||
public bool IsValidAttackTarget(WorldObject target, SpellInfo bySpell = null, bool spellCheck = true)
|
||||
{
|
||||
Cypher.Assert(target != null);
|
||||
|
||||
// can't attack self
|
||||
if (this == target)
|
||||
return false;
|
||||
|
||||
// can't attack GMs
|
||||
if (target.IsPlayer() && target.ToPlayer().IsGameMaster())
|
||||
return false;
|
||||
|
||||
Unit unit = ToUnit();
|
||||
Unit targetUnit = target.ToUnit();
|
||||
|
||||
// CvC case - can attack each other only when one of them is hostile
|
||||
if (unit && !unit.HasUnitFlag(UnitFlags.PvpAttackable) && targetUnit && !targetUnit.HasUnitFlag(UnitFlags.PvpAttackable))
|
||||
return IsHostileTo(target) || target.IsHostileTo(this);
|
||||
|
||||
// PvP, PvC, CvP case
|
||||
// can't attack friendly targets
|
||||
if (IsFriendlyTo(target) || target.IsFriendlyTo(this))
|
||||
return false;
|
||||
|
||||
Player playerAffectingAttacker = unit && unit.HasUnitFlag(UnitFlags.PvpAttackable) ? GetAffectingPlayer() : null;
|
||||
Player playerAffectingTarget = targetUnit && targetUnit.HasUnitFlag(UnitFlags.PvpAttackable) ? target.GetAffectingPlayer() : null;
|
||||
|
||||
// Not all neutral creatures can be attacked (even some unfriendly faction does not react aggresive to you, like Sporaggar)
|
||||
if ((playerAffectingAttacker && !playerAffectingTarget) || (!playerAffectingAttacker && playerAffectingTarget))
|
||||
{
|
||||
Player player = playerAffectingAttacker ? playerAffectingAttacker : playerAffectingTarget;
|
||||
Unit creature = playerAffectingAttacker ? targetUnit : unit;
|
||||
if (creature != null)
|
||||
{
|
||||
if (creature.IsContestedGuard() && player.HasPlayerFlag(PlayerFlags.ContestedPVP))
|
||||
return true;
|
||||
|
||||
var factionTemplate = creature.GetFactionTemplateEntry();
|
||||
if (factionTemplate != null)
|
||||
{
|
||||
if (player.GetReputationMgr().GetForcedRankIfAny(factionTemplate) == 0)
|
||||
{
|
||||
var factionEntry = CliDB.FactionStorage.LookupByKey(factionTemplate.Faction);
|
||||
if (factionEntry != null)
|
||||
{
|
||||
var repState = player.GetReputationMgr().GetState(factionEntry);
|
||||
if (repState != null)
|
||||
if (!repState.Flags.HasFlag(ReputationFlags.AtWar))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Creature creatureAttacker = ToCreature();
|
||||
if (creatureAttacker && creatureAttacker.GetCreatureTemplate().TypeFlags.HasFlag(CreatureTypeFlags.TreatAsRaidUnit))
|
||||
return false;
|
||||
|
||||
if (bySpell == null)
|
||||
spellCheck = false;
|
||||
|
||||
if (spellCheck && !IsValidSpellAttackTarget(target, bySpell))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool IsValidSpellAttackTarget(WorldObject target, SpellInfo bySpell)
|
||||
{
|
||||
Cypher.Assert(target != null);
|
||||
Cypher.Assert(bySpell != null);
|
||||
|
||||
// can't attack unattackable units
|
||||
Unit unitTarget = target.ToUnit();
|
||||
if (unitTarget && unitTarget.HasUnitState(UnitState.Unattackable))
|
||||
return false;
|
||||
|
||||
Unit unit = ToUnit();
|
||||
// visibility checks (only units)
|
||||
if (unit)
|
||||
{
|
||||
// can't attack invisible
|
||||
if (!bySpell.HasAttribute(SpellAttr6.CanTargetInvisible))
|
||||
{
|
||||
if (!unit.CanSeeOrDetect(target, bySpell.IsAffectingArea()))
|
||||
return false;
|
||||
|
||||
/*
|
||||
else if (!obj)
|
||||
{
|
||||
// ignore stealth for aoe spells. Ignore stealth if target is player and unit in combat with same player
|
||||
bool const ignoreStealthCheck = (bySpell && bySpell.IsAffectingArea()) ||
|
||||
(target.GetTypeId() == TYPEID_PLAYER && target.HasStealthAura() && IsInCombatWith(target));
|
||||
|
||||
if (!CanSeeOrDetect(target, ignoreStealthCheck))
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
// can't attack dead
|
||||
if (!bySpell.IsAllowingDeadTarget() && unitTarget && !unitTarget.IsAlive())
|
||||
return false;
|
||||
|
||||
// can't attack untargetable
|
||||
if (!bySpell.HasAttribute(SpellAttr6.CanTargetUntargetable) && unitTarget && unitTarget.HasUnitFlag(UnitFlags.NotSelectable))
|
||||
return false;
|
||||
|
||||
Player playerAttacker = ToPlayer();
|
||||
if (playerAttacker != null)
|
||||
{
|
||||
if (playerAttacker.HasPlayerFlag(PlayerFlags.Uber))
|
||||
return false;
|
||||
}
|
||||
|
||||
// check flags
|
||||
if (unitTarget != null && unitTarget.HasUnitFlag(UnitFlags.NonAttackable | UnitFlags.TaxiFlight | UnitFlags.NotAttackable1 | UnitFlags.Unk16))
|
||||
return false;
|
||||
|
||||
if (unit != null && !unit.HasUnitFlag(UnitFlags.PvpAttackable) && unitTarget && unitTarget.IsImmuneToNPC())
|
||||
return false;
|
||||
|
||||
if (unitTarget != null && !unitTarget.HasUnitFlag(UnitFlags.PvpAttackable) && unit && unit.IsImmuneToNPC())
|
||||
return false;
|
||||
|
||||
if (!bySpell.HasAttribute(SpellAttr8.AttackIgnoreImmuneToPCFlag))
|
||||
{
|
||||
if (unit && unit.HasUnitFlag(UnitFlags.PvpAttackable) && unitTarget && unitTarget.IsImmuneToPC())
|
||||
return false;
|
||||
|
||||
if (unitTarget && unitTarget.HasUnitFlag(UnitFlags.PvpAttackable) && unit && unit.IsImmuneToPC())
|
||||
return false;
|
||||
}
|
||||
|
||||
// check duel - before sanctuary checks
|
||||
Player playerAffectingAttacker = unit && unit.HasUnitFlag(UnitFlags.PvpAttackable) ? GetAffectingPlayer() : null;
|
||||
Player playerAffectingTarget = unitTarget && unitTarget.HasUnitFlag(UnitFlags.PvpAttackable) ? target.GetAffectingPlayer() : null;
|
||||
if (playerAffectingAttacker && playerAffectingTarget)
|
||||
if (playerAffectingAttacker.duel != null && playerAffectingAttacker.duel.opponent == playerAffectingTarget && playerAffectingAttacker.duel.startTime != 0)
|
||||
return true;
|
||||
|
||||
// PvP case - can't attack when attacker or target are in sanctuary
|
||||
// however, 13850 client doesn't allow to attack when one of the unit's has sanctuary flag and is pvp
|
||||
if (unitTarget && unitTarget.HasUnitFlag(UnitFlags.PvpAttackable) && unit && unit.HasUnitFlag(UnitFlags.PvpAttackable) && (unitTarget.IsInSanctuary() || unit.IsInSanctuary()))
|
||||
return false;
|
||||
|
||||
// additional checks - only PvP case
|
||||
if (playerAffectingAttacker && playerAffectingTarget)
|
||||
{
|
||||
if (unitTarget.IsPvP())
|
||||
return true;
|
||||
|
||||
if (unit.IsFFAPvP() && unitTarget.IsFFAPvP())
|
||||
return true;
|
||||
|
||||
return unit.HasPvpFlag(UnitPVPStateFlags.Unk1) ||
|
||||
unitTarget.HasPvpFlag(UnitPVPStateFlags.Unk1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// function based on function Unit::CanAssist from 13850 client
|
||||
public bool IsValidAssistTarget(WorldObject target, SpellInfo bySpell = null, bool spellCheck = true)
|
||||
{
|
||||
Cypher.Assert(target != null);
|
||||
|
||||
// can assist to self
|
||||
if (this == target)
|
||||
return true;
|
||||
|
||||
// can't assist GMs
|
||||
if (target.IsPlayer() && target.ToPlayer().IsGameMaster())
|
||||
return false;
|
||||
|
||||
// can't assist non-friendly targets
|
||||
if (GetReactionTo(target) < ReputationRank.Neutral && target.GetReactionTo(this) < ReputationRank.Neutral && (!ToCreature() || !ToCreature().GetCreatureTemplate().TypeFlags.HasFlag(CreatureTypeFlags.TreatAsRaidUnit)))
|
||||
return false;
|
||||
|
||||
if (bySpell == null)
|
||||
spellCheck = false;
|
||||
|
||||
if (spellCheck && !IsValidSpellAssistTarget(target, bySpell))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool IsValidSpellAssistTarget(WorldObject target, SpellInfo bySpell)
|
||||
{
|
||||
Cypher.Assert(target != null);
|
||||
Cypher.Assert(bySpell != null);
|
||||
|
||||
// can't assist unattackable units
|
||||
Unit unitTarget = target.ToUnit();
|
||||
if (unitTarget && unitTarget.HasUnitState(UnitState.Unattackable))
|
||||
return false;
|
||||
|
||||
// can't assist own vehicle or passenger
|
||||
Unit unit = ToUnit();
|
||||
if (unit && unitTarget && unit.GetVehicle())
|
||||
{
|
||||
if (unit.IsOnVehicle(unitTarget))
|
||||
return false;
|
||||
|
||||
if (unit.GetVehicleBase().IsOnVehicle(unitTarget))
|
||||
return false;
|
||||
}
|
||||
|
||||
// can't assist invisible
|
||||
if (!bySpell.HasAttribute(SpellAttr6.CanTargetInvisible) && !CanSeeOrDetect(target, bySpell.IsAffectingArea()))
|
||||
return false;
|
||||
|
||||
// can't assist dead
|
||||
if (!bySpell.IsAllowingDeadTarget() && unitTarget && !unitTarget.IsAlive())
|
||||
return false;
|
||||
|
||||
// can't assist untargetable
|
||||
if (!bySpell.HasAttribute(SpellAttr6.CanTargetUntargetable) && unitTarget && unitTarget.HasUnitFlag(UnitFlags.NotSelectable))
|
||||
return false;
|
||||
|
||||
if (!bySpell.HasAttribute(SpellAttr6.AssistIgnoreImmuneFlag))
|
||||
{
|
||||
if (unit && unit.HasUnitFlag(UnitFlags.PvpAttackable))
|
||||
{
|
||||
if (unitTarget && unitTarget.IsImmuneToPC())
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (unitTarget && unitTarget.IsImmuneToNPC())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// PvP case
|
||||
if (unitTarget && unitTarget.HasUnitFlag(UnitFlags.PvpAttackable))
|
||||
{
|
||||
Player targetPlayerOwner = target.GetAffectingPlayer();
|
||||
if (unit && unit.HasUnitFlag(UnitFlags.PvpAttackable))
|
||||
{
|
||||
Player selfPlayerOwner = GetAffectingPlayer();
|
||||
if (selfPlayerOwner && targetPlayerOwner)
|
||||
{
|
||||
// can't assist player which is dueling someone
|
||||
if (selfPlayerOwner != targetPlayerOwner && targetPlayerOwner.duel != null)
|
||||
return false;
|
||||
}
|
||||
// can't assist player in ffa_pvp zone from outside
|
||||
if (unitTarget.IsFFAPvP() && unit && !unit.IsFFAPvP())
|
||||
return false;
|
||||
|
||||
// can't assist player out of sanctuary from sanctuary if has pvp enabled
|
||||
if (unitTarget.IsPvP())
|
||||
if (unit && unit.IsInSanctuary() && !unitTarget.IsInSanctuary())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// PvC case - player can assist creature only if has specific type flags
|
||||
// !target.HasFlag(UNIT_FIELD_FLAGS, UnitFlags.PvpAttackable) &&
|
||||
else if (unit && unit.HasUnitFlag(UnitFlags.PvpAttackable))
|
||||
{
|
||||
if (!bySpell.HasAttribute(SpellAttr6.AssistIgnoreImmuneFlag))
|
||||
{
|
||||
if (unitTarget && !unitTarget.IsPvP())
|
||||
{
|
||||
Creature creatureTarget = target.ToCreature();
|
||||
if (creatureTarget != null)
|
||||
return creatureTarget.GetCreatureTemplate().TypeFlags.HasFlag(CreatureTypeFlags.TreatAsRaidUnit) || creatureTarget.GetCreatureTemplate().TypeFlags.HasFlag(CreatureTypeFlags.CanAssist);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual bool CheckAttackFitToAuraRequirement(WeaponAttackType attackType, AuraEffect aurEff) { return true; }
|
||||
|
||||
public void ApplyAttackTimePercentMod(WeaponAttackType att, float val, bool apply)
|
||||
|
||||
@@ -55,7 +55,7 @@ namespace Game.Entities
|
||||
protected float[][] m_weaponDamage = new float[(int)WeaponAttackType.Max][];
|
||||
|
||||
uint[] m_baseAttackSpeed = new uint[(int)WeaponAttackType.Max];
|
||||
float[] m_modAttackSpeedPct = new float[(int)WeaponAttackType.Max];
|
||||
internal float[] m_modAttackSpeedPct = new float[(int)WeaponAttackType.Max];
|
||||
protected uint[] m_attackTimer = new uint[(int)WeaponAttackType.Max];
|
||||
|
||||
CombatManager m_combatManager;
|
||||
@@ -117,7 +117,6 @@ namespace Game.Entities
|
||||
float[] m_floatStatNegBuff = new float[(int)Stats.Max];
|
||||
public ObjectGuid[] m_SummonSlot = new ObjectGuid[7];
|
||||
public ObjectGuid[] m_ObjectSlot = new ObjectGuid[4];
|
||||
public EventSystem m_Events = new();
|
||||
public UnitTypeMask UnitTypeMask { get; set; }
|
||||
UnitState m_state;
|
||||
protected LiquidTypeRecord _lastLiquid;
|
||||
@@ -498,14 +497,14 @@ namespace Game.Entities
|
||||
|
||||
public class DispelInfo
|
||||
{
|
||||
public DispelInfo(Unit dispeller, uint dispellerSpellId, byte chargesRemoved)
|
||||
public DispelInfo(WorldObject dispeller, uint dispellerSpellId, byte chargesRemoved)
|
||||
{
|
||||
_dispellerUnit = dispeller;
|
||||
_dispeller = dispeller;
|
||||
_dispellerSpell = dispellerSpellId;
|
||||
_chargesRemoved = chargesRemoved;
|
||||
}
|
||||
|
||||
public Unit GetDispeller() { return _dispellerUnit; }
|
||||
public WorldObject GetDispeller() { return _dispeller; }
|
||||
uint GetDispellerSpellId() { return _dispellerSpell; }
|
||||
public byte GetRemovedCharges() { return _chargesRemoved; }
|
||||
public void SetRemovedCharges(byte amount)
|
||||
@@ -513,7 +512,7 @@ namespace Game.Entities
|
||||
_chargesRemoved = amount;
|
||||
}
|
||||
|
||||
Unit _dispellerUnit;
|
||||
WorldObject _dispeller;
|
||||
uint _dispellerSpell;
|
||||
byte _chargesRemoved;
|
||||
}
|
||||
@@ -554,22 +553,4 @@ namespace Game.Entities
|
||||
{
|
||||
public StringArray name = new(SharedConst.MaxDeclinedNameCases);
|
||||
}
|
||||
|
||||
class CombatLogSender : IDoWork<Player>
|
||||
{
|
||||
CombatLogServerPacket i_message;
|
||||
|
||||
public CombatLogSender(CombatLogServerPacket msg)
|
||||
{
|
||||
i_message = msg;
|
||||
}
|
||||
|
||||
public void Invoke(Player player)
|
||||
{
|
||||
i_message.Clear();
|
||||
i_message.SetAdvancedCombatLogging(player.IsAdvancedCombatLoggingEnabled());
|
||||
|
||||
player.SendPacket(i_message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,19 +32,6 @@ namespace Game.Entities
|
||||
|
||||
public void SetInstantCast(bool set) { _instantCast = set; }
|
||||
public bool CanInstantCast() { return _instantCast; }
|
||||
|
||||
// function uses real base points (typically value - 1)
|
||||
public int CalculateSpellDamage(Unit target, SpellInfo spellProto, uint effect_index, int? basePoints = null, uint castItemId = 0, int itemLevel = -1)
|
||||
{
|
||||
SpellEffectInfo effect = spellProto.GetEffect(effect_index);
|
||||
return effect != null ? effect.CalcValue(this, basePoints, target, castItemId, itemLevel) : 0;
|
||||
}
|
||||
public int CalculateSpellDamage(Unit target, SpellInfo spellProto, uint effect_index, out float variance, int? basePoints = null, uint castItemId = 0, int itemLevel = -1)
|
||||
{
|
||||
SpellEffectInfo effect = spellProto.GetEffect(effect_index);
|
||||
variance = 0.0f;
|
||||
return effect != null ? effect.CalcValue(out variance, this, basePoints, target, castItemId, itemLevel) : 0;
|
||||
}
|
||||
|
||||
public int SpellBaseDamageBonusDone(SpellSchoolMask schoolMask)
|
||||
{
|
||||
@@ -754,66 +741,8 @@ namespace Game.Entities
|
||||
return Math.Max(crit_chance, 0.0f);
|
||||
}
|
||||
|
||||
// Calculate spell hit result can be:
|
||||
// Every spell can: Evade/Immune/Reflect/Sucesful hit
|
||||
// For melee based spells:
|
||||
// Miss
|
||||
// Dodge
|
||||
// Parry
|
||||
// For spells
|
||||
// Resist
|
||||
public SpellMissInfo SpellHitResult(Unit victim, SpellInfo spellInfo, bool canReflect = false)
|
||||
{
|
||||
// All positive spells can`t miss
|
||||
// @todo client not show miss log for this spells - so need find info for this in dbc and use it!
|
||||
if (spellInfo.IsPositive()
|
||||
&& (!IsHostileTo(victim))) // prevent from affecting enemy by "positive" spell
|
||||
return SpellMissInfo.None;
|
||||
|
||||
if (this == victim)
|
||||
return SpellMissInfo.None;
|
||||
|
||||
// Return evade for units in evade mode
|
||||
if (victim.IsTypeId(TypeId.Unit) && victim.ToCreature().IsEvadingAttacks())
|
||||
return SpellMissInfo.Evade;
|
||||
|
||||
// Try victim reflect spell
|
||||
if (canReflect)
|
||||
{
|
||||
int reflectchance = victim.GetTotalAuraModifier(AuraType.ReflectSpells);
|
||||
reflectchance += victim.GetTotalAuraModifierByMiscMask(AuraType.ReflectSpellsSchool, (int)spellInfo.GetSchoolMask());
|
||||
|
||||
if (reflectchance > 0 && RandomHelper.randChance(reflectchance))
|
||||
return SpellMissInfo.Reflect;
|
||||
}
|
||||
|
||||
if (spellInfo.HasAttribute(SpellAttr3.IgnoreHitResult))
|
||||
return SpellMissInfo.None;
|
||||
|
||||
// Check for immune
|
||||
if (victim.IsImmunedToSpell(spellInfo, this))
|
||||
return SpellMissInfo.Immune;
|
||||
|
||||
// Damage immunity is only checked if the spell has damage effects, this immunity must not prevent aura apply
|
||||
// returns SPELL_MISS_IMMUNE in that case, for other spells, the SMSG_SPELL_GO must show hit
|
||||
if (spellInfo.HasOnlyDamageEffects() && victim.IsImmunedToDamage(spellInfo))
|
||||
return SpellMissInfo.Immune;
|
||||
|
||||
switch (spellInfo.DmgClass)
|
||||
{
|
||||
case SpellDmgClass.Ranged:
|
||||
case SpellDmgClass.Melee:
|
||||
return MeleeSpellHitResult(victim, spellInfo);
|
||||
case SpellDmgClass.None:
|
||||
return SpellMissInfo.None;
|
||||
case SpellDmgClass.Magic:
|
||||
return MagicSpellHitResult(victim, spellInfo);
|
||||
}
|
||||
return SpellMissInfo.None;
|
||||
}
|
||||
|
||||
// Melee based spells hit result calculations
|
||||
SpellMissInfo MeleeSpellHitResult(Unit victim, SpellInfo spellInfo)
|
||||
public override SpellMissInfo MeleeSpellHitResult(Unit victim, SpellInfo spellInfo)
|
||||
{
|
||||
WeaponAttackType attType = WeaponAttackType.BaseAttack;
|
||||
|
||||
@@ -949,142 +878,6 @@ namespace Game.Entities
|
||||
return SpellMissInfo.None;
|
||||
}
|
||||
|
||||
SpellMissInfo MagicSpellHitResult(Unit victim, SpellInfo spell)
|
||||
{
|
||||
// Can`t miss on dead target (on skinning for example)
|
||||
if (!victim.IsAlive() && !victim.IsTypeId(TypeId.Player))
|
||||
return SpellMissInfo.None;
|
||||
|
||||
SpellSchoolMask schoolMask = spell.GetSchoolMask();
|
||||
// PvP - PvE spell misschances per leveldif > 2
|
||||
int lchance = victim.IsTypeId(TypeId.Player) ? 7 : 11;
|
||||
int thisLevel = (int)GetLevelForTarget(victim);
|
||||
if (IsTypeId(TypeId.Unit) && ToCreature().IsTrigger())
|
||||
thisLevel = (int)Math.Max(thisLevel, spell.SpellLevel);
|
||||
int leveldif = (int)(victim.GetLevelForTarget(this)) - thisLevel;
|
||||
int levelBasedHitDiff = leveldif;
|
||||
|
||||
// Base hit chance from attacker and victim levels
|
||||
int modHitChance;
|
||||
if (levelBasedHitDiff >= 0)
|
||||
{
|
||||
if (!victim.IsTypeId(TypeId.Player))
|
||||
{
|
||||
modHitChance = 94 - 3 * Math.Min(levelBasedHitDiff, 3);
|
||||
levelBasedHitDiff -= 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
modHitChance = 96 - Math.Min(levelBasedHitDiff, 2);
|
||||
levelBasedHitDiff -= 2;
|
||||
}
|
||||
if (levelBasedHitDiff > 0)
|
||||
modHitChance -= lchance * Math.Min(levelBasedHitDiff, 7);
|
||||
}
|
||||
else
|
||||
modHitChance = 97 - levelBasedHitDiff;
|
||||
|
||||
// Spellmod from SpellModOp.HitChance
|
||||
Player modOwner = GetSpellModOwner();
|
||||
if (modOwner != null)
|
||||
modOwner.ApplySpellMod(spell, SpellModOp.HitChance, ref modHitChance);
|
||||
|
||||
// Spells with SPELL_ATTR3_IGNORE_HIT_RESULT will ignore target's avoidance effects
|
||||
if (!spell.HasAttribute(SpellAttr3.IgnoreHitResult))
|
||||
{
|
||||
// Chance hit from victim SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE auras
|
||||
modHitChance += victim.GetTotalAuraModifierByMiscMask(AuraType.ModAttackerSpellHitChance, (int)schoolMask);
|
||||
}
|
||||
|
||||
int HitChance = modHitChance * 100;
|
||||
// Increase hit chance from attacker SPELL_AURA_MOD_SPELL_HIT_CHANCE and attacker ratings
|
||||
HitChance += (int)(modHitChance * 100.0f);
|
||||
|
||||
MathFunctions.RoundToInterval(ref HitChance, 0, 10000);
|
||||
|
||||
int tmp = 10000 - HitChance;
|
||||
|
||||
int rand = RandomHelper.IRand(0, 9999);
|
||||
if (tmp > 0 && rand < tmp)
|
||||
return SpellMissInfo.Miss;
|
||||
|
||||
// Spells with SPELL_ATTR3_IGNORE_HIT_RESULT will additionally fully ignore
|
||||
// resist and deflect chances
|
||||
if (spell.HasAttribute(SpellAttr3.IgnoreHitResult))
|
||||
return SpellMissInfo.None;
|
||||
|
||||
// Chance resist mechanic (select max value from every mechanic spell effect)
|
||||
int resist_chance = victim.GetMechanicResistChance(spell) * 100;
|
||||
|
||||
// Roll chance
|
||||
if (resist_chance > 0 && rand < (tmp += resist_chance))
|
||||
return SpellMissInfo.Resist;
|
||||
|
||||
// cast by caster in front of victim
|
||||
if (!victim.HasUnitState(UnitState.Controlled) && (victim.HasInArc(MathFunctions.PI, this) || victim.HasAuraType(AuraType.IgnoreHitDirection)))
|
||||
{
|
||||
int deflect_chance = victim.GetTotalAuraModifier(AuraType.DeflectSpells) * 100;
|
||||
if (deflect_chance > 0 && rand < (tmp += deflect_chance))
|
||||
return SpellMissInfo.Deflect;
|
||||
}
|
||||
|
||||
return SpellMissInfo.None;
|
||||
}
|
||||
|
||||
public void CastSpell(SpellCastTargets targets, uint spellId, CastSpellExtraArgs args)
|
||||
{
|
||||
if (args == null)
|
||||
args = new CastSpellExtraArgs();
|
||||
|
||||
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId, args.CastDifficulty != Difficulty.None ? args.CastDifficulty : GetMap().GetDifficultyID());
|
||||
if (spellInfo == null)
|
||||
{
|
||||
Log.outError(LogFilter.Unit, $"CastSpell: unknown spell {spellId} by caster: {GetGUID()}");
|
||||
return;
|
||||
}
|
||||
|
||||
Spell spell = new(this, spellInfo, args.TriggerFlags, args.OriginalCaster);
|
||||
foreach (var pair in args.SpellValueOverrides)
|
||||
spell.SetSpellValue(pair.Key, pair.Value);
|
||||
|
||||
spell.m_CastItem = args.CastItem;
|
||||
spell.Prepare(targets, args.TriggeringAura);
|
||||
}
|
||||
|
||||
public void CastSpell(WorldObject target, uint spellId, bool triggered)
|
||||
{
|
||||
CastSpell(target, spellId, new CastSpellExtraArgs(triggered));
|
||||
}
|
||||
|
||||
public void CastSpell(WorldObject target, uint spellId, CastSpellExtraArgs args = null)
|
||||
{
|
||||
SpellCastTargets targets = new();
|
||||
if (target)
|
||||
{
|
||||
Unit unitTarget = target.ToUnit();
|
||||
GameObject goTarget = target.ToGameObject();
|
||||
if (unitTarget != null)
|
||||
targets.SetUnitTarget(unitTarget);
|
||||
else if (goTarget != null)
|
||||
targets.SetGOTarget(goTarget);
|
||||
else
|
||||
{
|
||||
Log.outError(LogFilter.Unit, $"CastSpell: Invalid target {target.GetGUID()} passed to spell cast by {GetGUID()}");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
CastSpell(targets, spellId, args);
|
||||
}
|
||||
|
||||
public void CastSpell(Position dest, uint spellId, CastSpellExtraArgs args = null)
|
||||
{
|
||||
SpellCastTargets targets = new();
|
||||
targets.SetDst(dest);
|
||||
|
||||
CastSpell(targets, spellId, args);
|
||||
}
|
||||
|
||||
public void FinishSpell(CurrentSpellTypes spellType, bool ok = true)
|
||||
{
|
||||
Spell spell = GetCurrentSpell(spellType);
|
||||
@@ -1223,7 +1016,7 @@ namespace Game.Entities
|
||||
return spellInfo;
|
||||
}
|
||||
|
||||
public uint GetCastSpellXSpellVisualId(SpellInfo spellInfo)
|
||||
public override uint GetCastSpellXSpellVisualId(SpellInfo spellInfo)
|
||||
{
|
||||
var visualOverrides = GetAuraEffectsByType(AuraType.OverrideSpellVisual);
|
||||
foreach (AuraEffect effect in visualOverrides)
|
||||
@@ -1239,7 +1032,7 @@ namespace Game.Entities
|
||||
}
|
||||
}
|
||||
|
||||
return spellInfo.GetSpellXSpellVisualId(this);
|
||||
return base.GetCastSpellXSpellVisualId(spellInfo);
|
||||
}
|
||||
|
||||
public SpellHistory GetSpellHistory() { return _spellHistory; }
|
||||
@@ -1520,7 +1313,7 @@ namespace Game.Entities
|
||||
}
|
||||
}
|
||||
}
|
||||
public virtual bool IsImmunedToSpell(SpellInfo spellInfo, Unit caster)
|
||||
public virtual bool IsImmunedToSpell(SpellInfo spellInfo, WorldObject caster)
|
||||
{
|
||||
if (spellInfo == null)
|
||||
return false;
|
||||
@@ -1617,7 +1410,7 @@ namespace Game.Entities
|
||||
|
||||
return mask;
|
||||
}
|
||||
public virtual bool IsImmunedToSpellEffect(SpellInfo spellInfo, uint index, Unit caster)
|
||||
public virtual bool IsImmunedToSpellEffect(SpellInfo spellInfo, uint index, WorldObject caster)
|
||||
{
|
||||
if (spellInfo == null)
|
||||
return false;
|
||||
@@ -1887,88 +1680,11 @@ namespace Game.Entities
|
||||
if (GetCurrentSpell(i) != null && GetCurrentSpell(i).m_spellInfo.Id != except_spellid)
|
||||
InterruptSpell(i, false);
|
||||
}
|
||||
public void ModSpellCastTime(SpellInfo spellInfo, ref int castTime, Spell spell = null)
|
||||
{
|
||||
if (spellInfo == null || castTime < 0)
|
||||
return;
|
||||
|
||||
// called from caster
|
||||
Player modOwner = GetSpellModOwner();
|
||||
if (modOwner != null)
|
||||
modOwner.ApplySpellMod(spellInfo, SpellModOp.ChangeCastTime, ref castTime, spell);
|
||||
|
||||
if (!(spellInfo.HasAttribute(SpellAttr0.Ability | SpellAttr0.Tradespell) || spellInfo.HasAttribute(SpellAttr3.NoDoneBonus))
|
||||
&& (IsTypeId(TypeId.Player) && spellInfo.SpellFamilyName != 0) || IsTypeId(TypeId.Unit))
|
||||
castTime = CanInstantCast() ? 0 : (int)(castTime * m_unitData.ModCastingSpeed);
|
||||
else if (spellInfo.HasAttribute(SpellAttr0.ReqAmmo) && !spellInfo.HasAttribute(SpellAttr2.AutorepeatFlag))
|
||||
castTime = (int)(castTime * m_modAttackSpeedPct[(int)WeaponAttackType.RangedAttack]);
|
||||
else if (Global.SpellMgr.IsPartOfSkillLine(SkillType.Cooking, spellInfo.Id) && HasAura(67556)) // cooking with Chef Hat.
|
||||
castTime = 500;
|
||||
}
|
||||
public void ModSpellDurationTime(SpellInfo spellInfo, ref int duration, Spell spell = null)
|
||||
{
|
||||
if (spellInfo == null || duration < 0)
|
||||
return;
|
||||
|
||||
if (spellInfo.IsChanneled() && !spellInfo.HasAttribute(SpellAttr5.HasteAffectDuration))
|
||||
return;
|
||||
|
||||
// called from caster
|
||||
Player modOwner = GetSpellModOwner();
|
||||
if (modOwner)
|
||||
modOwner.ApplySpellMod(spellInfo, SpellModOp.ChangeCastTime, ref duration, spell);
|
||||
|
||||
if (!(spellInfo.HasAttribute(SpellAttr0.Ability) || spellInfo.HasAttribute(SpellAttr0.Tradespell) || spellInfo.HasAttribute(SpellAttr3.NoDoneBonus)) &&
|
||||
(IsTypeId(TypeId.Player) && spellInfo.SpellFamilyName != 0) || IsTypeId(TypeId.Unit))
|
||||
duration = (int)(duration * m_unitData.ModCastingSpeed);
|
||||
else if (spellInfo.HasAttribute(SpellAttr0.ReqAmmo) && !spellInfo.HasAttribute(SpellAttr2.AutorepeatFlag))
|
||||
duration = (int)(duration * m_modAttackSpeedPct[(int)WeaponAttackType.RangedAttack]);
|
||||
}
|
||||
public float ApplyEffectModifiers(SpellInfo spellProto, uint effect_index, float value)
|
||||
{
|
||||
Player modOwner = GetSpellModOwner();
|
||||
if (modOwner != null)
|
||||
{
|
||||
modOwner.ApplySpellMod(spellProto, SpellModOp.Points, ref value);
|
||||
switch (effect_index)
|
||||
{
|
||||
case 0:
|
||||
modOwner.ApplySpellMod(spellProto, SpellModOp.PointsIndex0, ref value);
|
||||
break;
|
||||
case 1:
|
||||
modOwner.ApplySpellMod(spellProto, SpellModOp.PointsIndex1, ref value);
|
||||
break;
|
||||
case 2:
|
||||
modOwner.ApplySpellMod(spellProto, SpellModOp.PointsIndex2, ref value);
|
||||
break;
|
||||
case 3:
|
||||
modOwner.ApplySpellMod(spellProto, SpellModOp.PointsIndex3, ref value);
|
||||
break;
|
||||
case 4:
|
||||
modOwner.ApplySpellMod(spellProto, SpellModOp.PointsIndex4, ref value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public ushort GetMaxSkillValueForLevel(Unit target = null)
|
||||
{
|
||||
return (ushort)(target != null ? GetLevelForTarget(target) : GetLevel() * 5);
|
||||
}
|
||||
public Player GetSpellModOwner()
|
||||
{
|
||||
if (IsTypeId(TypeId.Player))
|
||||
return ToPlayer();
|
||||
|
||||
if (HasUnitTypeMask(UnitTypeMask.Pet | UnitTypeMask.Totem | UnitTypeMask.Guardian))
|
||||
{
|
||||
Unit owner = GetOwner();
|
||||
if (owner != null && owner.IsTypeId(TypeId.Player))
|
||||
return owner.ToPlayer();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Spell GetCurrentSpell(CurrentSpellTypes spellType)
|
||||
{
|
||||
@@ -2283,7 +1999,6 @@ namespace Game.Entities
|
||||
|
||||
// update for out of range group members (on 1 slot use)
|
||||
aura.SetNeedClientUpdateForTargets();
|
||||
Log.outDebug(LogFilter.Spells, "Aura {0} partially interrupted on {1}, new duration: {2} ms", aura.GetId(), GetGUID().ToString(), aura.GetDuration());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2641,7 +2356,7 @@ namespace Game.Entities
|
||||
diminish.HitCount = currentLevel + 1;
|
||||
}
|
||||
|
||||
public bool ApplyDiminishingToDuration(SpellInfo auraSpellInfo, ref int duration, Unit caster, DiminishingLevels previousLevel)
|
||||
public bool ApplyDiminishingToDuration(SpellInfo auraSpellInfo, ref int duration, WorldObject caster, DiminishingLevels previousLevel)
|
||||
{
|
||||
DiminishingGroup group = auraSpellInfo.GetDiminishingReturnsGroupForSpell();
|
||||
if (duration == -1 || group == DiminishingGroup.None)
|
||||
@@ -2656,7 +2371,7 @@ namespace Game.Entities
|
||||
if (limitDuration > 0 && duration > limitDuration)
|
||||
{
|
||||
Unit target = targetOwner ?? this;
|
||||
Unit source = casterOwner ?? caster;
|
||||
WorldObject source = casterOwner ?? caster;
|
||||
|
||||
if (target.IsAffectedByDiminishingReturns() && source.IsPlayer())
|
||||
duration = limitDuration;
|
||||
@@ -2863,9 +2578,6 @@ namespace Game.Entities
|
||||
if (spellInfo == null)
|
||||
return null;
|
||||
|
||||
if (!target.IsAlive() && !spellInfo.IsPassive() && !spellInfo.HasAttribute(SpellAttr2.CanTargetDead))
|
||||
return null;
|
||||
|
||||
return AddAura(spellInfo, SpellConst.MaxEffectMask, target);
|
||||
}
|
||||
|
||||
@@ -2874,6 +2586,9 @@ namespace Game.Entities
|
||||
if (spellInfo == null)
|
||||
return null;
|
||||
|
||||
if (!target.IsAlive() && !spellInfo.IsPassive() && !spellInfo.HasAttribute(SpellAttr2.CanTargetDead))
|
||||
return null;
|
||||
|
||||
if (target.IsImmunedToSpell(spellInfo, this))
|
||||
return null;
|
||||
|
||||
@@ -3037,29 +2752,6 @@ namespace Game.Entities
|
||||
return false;
|
||||
}
|
||||
|
||||
// target dependent range checks
|
||||
public float GetSpellMaxRangeForTarget(Unit target, SpellInfo spellInfo)
|
||||
{
|
||||
if (spellInfo.RangeEntry == null)
|
||||
return 0;
|
||||
if (spellInfo.RangeEntry.RangeMax[0] == spellInfo.RangeEntry.RangeMax[1])
|
||||
return spellInfo.GetMaxRange();
|
||||
if (!target)
|
||||
return spellInfo.GetMaxRange(true);
|
||||
return spellInfo.GetMaxRange(!IsHostileTo(target));
|
||||
}
|
||||
|
||||
public float GetSpellMinRangeForTarget(Unit target, SpellInfo spellInfo)
|
||||
{
|
||||
if (spellInfo.RangeEntry == null)
|
||||
return 0;
|
||||
if (spellInfo.RangeEntry.RangeMin[0] == spellInfo.RangeEntry.RangeMin[1])
|
||||
return spellInfo.GetMinRange();
|
||||
if (!target)
|
||||
return spellInfo.GetMinRange(true);
|
||||
return spellInfo.GetMinRange(!IsHostileTo(target));
|
||||
}
|
||||
|
||||
public bool HasAuraType(AuraType auraType)
|
||||
{
|
||||
return !m_modAuras.LookupByKey(auraType).Empty();
|
||||
@@ -3177,7 +2869,7 @@ namespace Game.Entities
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<DispelableAura> GetDispellableAuraList(Unit caster, uint dispelMask, bool isReflect = false)
|
||||
public List<DispelableAura> GetDispellableAuraList(WorldObject caster, uint dispelMask, bool isReflect = false)
|
||||
{
|
||||
List<DispelableAura> dispelList = new();
|
||||
|
||||
@@ -3311,7 +3003,7 @@ namespace Game.Entities
|
||||
}
|
||||
}
|
||||
}
|
||||
public void RemoveAurasDueToSpellBySteal(uint spellId, ObjectGuid casterGUID, Unit stealer)
|
||||
public void RemoveAurasDueToSpellBySteal(uint spellId, ObjectGuid casterGUID, WorldObject stealer)
|
||||
{
|
||||
var range = m_ownedAuras.LookupByKey(spellId);
|
||||
foreach (var aura in range)
|
||||
@@ -3344,39 +3036,43 @@ namespace Game.Entities
|
||||
// Cast duration to unsigned to prevent permanent aura's such as Righteous Fury being permanently added to caster
|
||||
uint dur = (uint)Math.Min(2u * Time.Minute * Time.InMilliseconds, aura.GetDuration());
|
||||
|
||||
Aura oldAura = stealer.GetAura(aura.GetId(), aura.GetCasterGUID());
|
||||
if (oldAura != null)
|
||||
Unit unitStealer = stealer.ToUnit();
|
||||
if (unitStealer != null)
|
||||
{
|
||||
if (stealCharge)
|
||||
oldAura.ModCharges(1);
|
||||
else
|
||||
oldAura.ModStackAmount(1);
|
||||
oldAura.SetDuration((int)dur);
|
||||
}
|
||||
else
|
||||
{
|
||||
// single target state must be removed before aura creation to preserve existing single target aura
|
||||
if (aura.IsSingleTarget())
|
||||
aura.UnregisterSingleTarget();
|
||||
|
||||
AuraCreateInfo createInfo = new(aura.GetCastGUID(), aura.GetSpellInfo(), aura.GetCastDifficulty(), effMask, stealer);
|
||||
createInfo.SetCasterGUID(aura.GetCasterGUID());
|
||||
createInfo.SetBaseAmount(baseDamage);
|
||||
|
||||
Aura newAura = Aura.TryRefreshStackOrCreate(createInfo);
|
||||
if (newAura != null)
|
||||
Aura oldAura = unitStealer.GetAura(aura.GetId(), aura.GetCasterGUID());
|
||||
if (oldAura != null)
|
||||
{
|
||||
// created aura must not be single target aura, so stealer won't loose it on recast
|
||||
if (newAura.IsSingleTarget())
|
||||
if (stealCharge)
|
||||
oldAura.ModCharges(1);
|
||||
else
|
||||
oldAura.ModStackAmount(1);
|
||||
oldAura.SetDuration((int)dur);
|
||||
}
|
||||
else
|
||||
{
|
||||
// single target state must be removed before aura creation to preserve existing single target aura
|
||||
if (aura.IsSingleTarget())
|
||||
aura.UnregisterSingleTarget();
|
||||
|
||||
AuraCreateInfo createInfo = new(aura.GetCastGUID(), aura.GetSpellInfo(), aura.GetCastDifficulty(), effMask, stealer);
|
||||
createInfo.SetCasterGUID(aura.GetCasterGUID());
|
||||
createInfo.SetBaseAmount(baseDamage);
|
||||
|
||||
Aura newAura = Aura.TryRefreshStackOrCreate(createInfo);
|
||||
if (newAura != null)
|
||||
{
|
||||
newAura.UnregisterSingleTarget();
|
||||
// bring back single target aura status to the old aura
|
||||
aura.SetIsSingleTarget(true);
|
||||
caster.GetSingleCastAuras().Add(aura);
|
||||
// created aura must not be single target aura, so stealer won't loose it on recast
|
||||
if (newAura.IsSingleTarget())
|
||||
{
|
||||
newAura.UnregisterSingleTarget();
|
||||
// bring back single target aura status to the old aura
|
||||
aura.SetIsSingleTarget(true);
|
||||
caster.GetSingleCastAuras().Add(aura);
|
||||
}
|
||||
// FIXME: using aura.GetMaxDuration() maybe not blizzlike but it fixes stealing of spells like Innervate
|
||||
newAura.SetLoadedState(aura.GetMaxDuration(), (int)dur, stealCharge ? 1 : aura.GetCharges(), 1, recalculateMask, damage);
|
||||
newAura.ApplyForTargets();
|
||||
}
|
||||
// FIXME: using aura.GetMaxDuration() maybe not blizzlike but it fixes stealing of spells like Innervate
|
||||
newAura.SetLoadedState(aura.GetMaxDuration(), (int)dur, stealCharge ? 1 : aura.GetCharges(), 1, recalculateMask, damage);
|
||||
newAura.ApplyForTargets();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3524,7 +3220,7 @@ namespace Game.Entities
|
||||
}
|
||||
}
|
||||
}
|
||||
public void RemoveAurasDueToSpellByDispel(uint spellId, uint dispellerSpellId, ObjectGuid casterGUID, Unit dispeller, byte chargesRemoved = 1)
|
||||
public void RemoveAurasDueToSpellByDispel(uint spellId, uint dispellerSpellId, ObjectGuid casterGUID, WorldObject dispeller, byte chargesRemoved = 1)
|
||||
{
|
||||
foreach (var pair in GetOwnedAuras())
|
||||
{
|
||||
@@ -4270,6 +3966,14 @@ namespace Game.Entities
|
||||
if (createInfo.CasterGUID.IsEmpty() && !createInfo.GetSpellInfo().IsStackableOnOneSlotWithDifferentCasters())
|
||||
createInfo.CasterGUID = createInfo.Caster.GetGUID();
|
||||
|
||||
// world gameobjects can't own auras and they send empty casterguid
|
||||
// checked on sniffs with spell 22247
|
||||
if (createInfo.CasterGUID.IsGameObject())
|
||||
{
|
||||
createInfo.Caster = null;
|
||||
createInfo.CasterGUID.Clear();
|
||||
}
|
||||
|
||||
// passive and Incanter's Absorption and auras with different type can stack with themselves any number of times
|
||||
if (!createInfo.GetSpellInfo().IsMultiSlotAura())
|
||||
{
|
||||
@@ -4612,7 +4316,7 @@ namespace Game.Entities
|
||||
});
|
||||
}
|
||||
|
||||
int GetMaxNegativeAuraModifierByMiscValue(AuraType auratype, int miscValue)
|
||||
public int GetMaxNegativeAuraModifierByMiscValue(AuraType auratype, int miscValue)
|
||||
{
|
||||
return GetMaxNegativeAuraModifier(auratype, aurEff =>
|
||||
{
|
||||
|
||||
@@ -1394,101 +1394,6 @@ namespace Game.Entities
|
||||
SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.ShapeshiftForm), (byte)form);
|
||||
}
|
||||
|
||||
public int CalcSpellDuration(SpellInfo spellProto)
|
||||
{
|
||||
sbyte comboPoints = (sbyte)(m_playerMovingMe != null ? m_playerMovingMe.GetComboPoints() : 0);
|
||||
|
||||
int minduration = spellProto.GetDuration();
|
||||
int maxduration = spellProto.GetMaxDuration();
|
||||
|
||||
int duration;
|
||||
|
||||
if (comboPoints != 0 && minduration != -1 && minduration != maxduration)
|
||||
duration = minduration + (maxduration - minduration) * comboPoints / 5;
|
||||
else
|
||||
duration = minduration;
|
||||
|
||||
return duration;
|
||||
}
|
||||
|
||||
public int ModSpellDuration(SpellInfo spellProto, Unit target, int duration, bool positive, uint effectMask)
|
||||
{
|
||||
// don't mod permanent auras duration
|
||||
if (duration < 0)
|
||||
return duration;
|
||||
|
||||
// some auras are not affected by duration modifiers
|
||||
if (spellProto.HasAttribute(SpellAttr7.IgnoreDurationMods))
|
||||
return duration;
|
||||
|
||||
// cut duration only of negative effects
|
||||
if (!positive)
|
||||
{
|
||||
uint mechanic = spellProto.GetSpellMechanicMaskByEffectMask(effectMask);
|
||||
|
||||
int durationMod;
|
||||
int durationMod_always = 0;
|
||||
int durationMod_not_stack = 0;
|
||||
|
||||
for (byte i = 1; i <= (int)Mechanics.Enraged; ++i)
|
||||
{
|
||||
if (!Convert.ToBoolean(mechanic & 1 << i))
|
||||
continue;
|
||||
// Find total mod value (negative bonus)
|
||||
int new_durationMod_always = target.GetTotalAuraModifierByMiscValue(AuraType.MechanicDurationMod, i);
|
||||
// Find max mod (negative bonus)
|
||||
int new_durationMod_not_stack = target.GetMaxNegativeAuraModifierByMiscValue(AuraType.MechanicDurationModNotStack, i);
|
||||
// Check if mods applied before were weaker
|
||||
if (new_durationMod_always < durationMod_always)
|
||||
durationMod_always = new_durationMod_always;
|
||||
if (new_durationMod_not_stack < durationMod_not_stack)
|
||||
durationMod_not_stack = new_durationMod_not_stack;
|
||||
}
|
||||
|
||||
// Select strongest negative mod
|
||||
if (durationMod_always > durationMod_not_stack)
|
||||
durationMod = durationMod_not_stack;
|
||||
else
|
||||
durationMod = durationMod_always;
|
||||
|
||||
if (durationMod != 0)
|
||||
MathFunctions.AddPct(ref duration, durationMod);
|
||||
|
||||
// there are only negative mods currently
|
||||
durationMod_always = target.GetTotalAuraModifierByMiscValue(AuraType.ModAuraDurationByDispel, (int)spellProto.Dispel);
|
||||
durationMod_not_stack = target.GetMaxNegativeAuraModifierByMiscValue(AuraType.ModAuraDurationByDispelNotStack, (int)spellProto.Dispel);
|
||||
|
||||
durationMod = 0;
|
||||
if (durationMod_always > durationMod_not_stack)
|
||||
durationMod += durationMod_not_stack;
|
||||
else
|
||||
durationMod += durationMod_always;
|
||||
|
||||
if (durationMod != 0)
|
||||
MathFunctions.AddPct(ref duration, durationMod);
|
||||
}
|
||||
else
|
||||
{
|
||||
// else positive mods here, there are no currently
|
||||
// when there will be, change GetTotalAuraModifierByMiscValue to GetTotalPositiveAuraModifierByMiscValue
|
||||
|
||||
// Mixology - duration boost
|
||||
if (target.IsTypeId(TypeId.Player))
|
||||
{
|
||||
if (spellProto.SpellFamilyName == SpellFamilyNames.Potion && (
|
||||
Global.SpellMgr.IsSpellMemberOfSpellGroup(spellProto.Id, SpellGroup.ElixirBattle) ||
|
||||
Global.SpellMgr.IsSpellMemberOfSpellGroup(spellProto.Id, SpellGroup.ElixirGuardian)))
|
||||
{
|
||||
SpellEffectInfo effect = spellProto.GetEffect(0);
|
||||
if (target.HasAura(53042) && effect != null && target.HasSpell(effect.TriggerSpell))
|
||||
duration *= 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Math.Max(duration, 0);
|
||||
}
|
||||
|
||||
// creates aura application instance and registers it in lists
|
||||
// aura application effects are handled separately to prevent aura list corruption
|
||||
public AuraApplication _CreateAuraApplication(Aura aura, uint effMask)
|
||||
@@ -1528,8 +1433,8 @@ namespace Game.Entities
|
||||
return aurApp;
|
||||
}
|
||||
|
||||
bool HasInterruptFlag(SpellAuraInterruptFlags flags) { return m_interruptMask.HasFlag(flags); }
|
||||
bool HasInterruptFlag(SpellAuraInterruptFlags2 flags) { return m_interruptMask2.HasFlag(flags); }
|
||||
bool HasInterruptFlag(SpellAuraInterruptFlags flags) { return m_interruptMask.HasAnyFlag(flags); }
|
||||
bool HasInterruptFlag(SpellAuraInterruptFlags2 flags) { return m_interruptMask2.HasAnyFlag(flags); }
|
||||
|
||||
public void AddInterruptMask(SpellAuraInterruptFlags flags, SpellAuraInterruptFlags2 flags2)
|
||||
{
|
||||
@@ -1649,26 +1554,6 @@ namespace Game.Entities
|
||||
RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Sheathing);
|
||||
}
|
||||
|
||||
public FactionTemplateRecord GetFactionTemplateEntry()
|
||||
{
|
||||
FactionTemplateRecord entry = CliDB.FactionTemplateStorage.LookupByKey(GetFaction());
|
||||
if (entry == null)
|
||||
{
|
||||
Player player = ToPlayer();
|
||||
if (player != null)
|
||||
Log.outError(LogFilter.Unit, "Player {0} has invalid faction (faction template id) #{1}", player.GetName(), GetFaction());
|
||||
else
|
||||
{
|
||||
Creature creature = ToCreature();
|
||||
if (creature != null)
|
||||
Log.outError(LogFilter.Unit, "Creature (template id: {0}) has invalid faction (faction template id) #{1}", creature.GetCreatureTemplate().Entry, GetFaction());
|
||||
else
|
||||
Log.outError(LogFilter.Unit, "Unit (name={0}, type={1}) has invalid faction (faction template id) #{2}", GetName(), GetTypeId(), GetFaction());
|
||||
}
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
public bool IsInFeralForm()
|
||||
{
|
||||
ShapeShiftForm form = GetShapeshiftForm();
|
||||
@@ -1902,17 +1787,9 @@ namespace Game.Entities
|
||||
public uint GetMountDisplayId() { return m_unitData.MountDisplayID; }
|
||||
public void SetMountDisplayId(uint mountDisplayId) { SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.MountDisplayID), mountDisplayId); }
|
||||
|
||||
public virtual Unit GetOwner()
|
||||
{
|
||||
ObjectGuid ownerid = GetOwnerGUID();
|
||||
if (!ownerid.IsEmpty())
|
||||
return Global.ObjAccessor.GetUnit(this, ownerid);
|
||||
|
||||
return null;
|
||||
}
|
||||
public virtual float GetFollowAngle() { return MathFunctions.PiOver2; }
|
||||
|
||||
public ObjectGuid GetOwnerGUID() { return m_unitData.SummonedBy; }
|
||||
public override ObjectGuid GetOwnerGUID() { return m_unitData.SummonedBy; }
|
||||
public void SetOwnerGUID(ObjectGuid owner)
|
||||
{
|
||||
if (GetOwnerGUID() == owner)
|
||||
@@ -1947,18 +1824,10 @@ namespace Game.Entities
|
||||
public void SetCritterGUID(ObjectGuid guid) { SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.Critter), guid); }
|
||||
public ObjectGuid GetBattlePetCompanionGUID() { return m_unitData.BattlePetCompanionGUID; }
|
||||
public void SetBattlePetCompanionGUID(ObjectGuid guid) { SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.BattlePetCompanionGUID), guid); }
|
||||
public ObjectGuid GetCharmerOrOwnerGUID()
|
||||
public override ObjectGuid GetCharmerOrOwnerGUID()
|
||||
{
|
||||
return !GetCharmerGUID().IsEmpty() ? GetCharmerGUID() : GetOwnerGUID();
|
||||
}
|
||||
public ObjectGuid GetCharmerOrOwnerOrOwnGUID()
|
||||
{
|
||||
ObjectGuid guid = GetCharmerOrOwnerGUID();
|
||||
if (!guid.IsEmpty())
|
||||
return guid;
|
||||
|
||||
return GetGUID();
|
||||
}
|
||||
public Unit GetCharmer()
|
||||
{
|
||||
ObjectGuid charmerid = GetCharmerGUID();
|
||||
@@ -1966,22 +1835,6 @@ namespace Game.Entities
|
||||
return Global.ObjAccessor.GetUnit(this, charmerid);
|
||||
return null;
|
||||
}
|
||||
public Unit GetCharmerOrOwnerOrSelf()
|
||||
{
|
||||
Unit u = GetCharmerOrOwner();
|
||||
if (u != null)
|
||||
return u;
|
||||
|
||||
return this;
|
||||
}
|
||||
public Player GetCharmerOrOwnerPlayerOrPlayerItself()
|
||||
{
|
||||
ObjectGuid guid = GetCharmerOrOwnerGUID();
|
||||
if (guid.IsPlayer())
|
||||
return Global.ObjAccessor.FindPlayer(guid);
|
||||
|
||||
return IsTypeId(TypeId.Player) ? ToPlayer() : null;
|
||||
}
|
||||
public Unit GetCharmerOrOwner()
|
||||
{
|
||||
return !GetCharmerGUID().IsEmpty() ? GetCharmer() : GetOwner();
|
||||
@@ -2044,16 +1897,6 @@ namespace Game.Entities
|
||||
else
|
||||
return ToCreature().GetCreatureTemplate().CreatureType;
|
||||
}
|
||||
public Player GetAffectingPlayer()
|
||||
{
|
||||
if (GetCharmerOrOwnerGUID().IsEmpty())
|
||||
return IsTypeId(TypeId.Player) ? ToPlayer() : null;
|
||||
|
||||
Unit owner = GetCharmerOrOwner();
|
||||
if (owner != null)
|
||||
return owner.GetCharmerOrOwnerPlayerOrPlayerItself();
|
||||
return null;
|
||||
}
|
||||
|
||||
public void DeMorph()
|
||||
{
|
||||
@@ -2079,7 +1922,7 @@ namespace Game.Entities
|
||||
}
|
||||
public bool HasUnitState(UnitState f)
|
||||
{
|
||||
return m_state.HasFlag(f);
|
||||
return m_state.HasAnyFlag(f);
|
||||
}
|
||||
public void ClearUnitState(UnitState f)
|
||||
{
|
||||
@@ -2113,146 +1956,8 @@ namespace Game.Entities
|
||||
return false;
|
||||
}
|
||||
|
||||
//Faction
|
||||
public bool IsNeutralToAll()
|
||||
{
|
||||
var my_faction = GetFactionTemplateEntry();
|
||||
if (my_faction == null || my_faction.Faction == 0)
|
||||
return true;
|
||||
|
||||
var raw_faction = CliDB.FactionStorage.LookupByKey(my_faction.Faction);
|
||||
if (raw_faction != null && raw_faction.ReputationIndex >= 0)
|
||||
return false;
|
||||
|
||||
return my_faction.IsNeutralToAll();
|
||||
}
|
||||
public bool IsHostileTo(Unit unit)
|
||||
{
|
||||
return GetReactionTo(unit) <= ReputationRank.Hostile;
|
||||
}
|
||||
public bool IsFriendlyTo(Unit unit)
|
||||
{
|
||||
return GetReactionTo(unit) >= ReputationRank.Friendly;
|
||||
}
|
||||
public ReputationRank GetReactionTo(Unit target)
|
||||
{
|
||||
// always friendly to self
|
||||
if (this == target)
|
||||
return ReputationRank.Friendly;
|
||||
|
||||
// always friendly to charmer or owner
|
||||
if (GetCharmerOrOwnerOrSelf() == target.GetCharmerOrOwnerOrSelf())
|
||||
return ReputationRank.Friendly;
|
||||
|
||||
if (HasUnitFlag(UnitFlags.PvpAttackable))
|
||||
{
|
||||
if (target.HasUnitFlag(UnitFlags.PvpAttackable))
|
||||
{
|
||||
Player selfPlayerOwner = GetAffectingPlayer();
|
||||
Player targetPlayerOwner = target.GetAffectingPlayer();
|
||||
|
||||
if (selfPlayerOwner != null && targetPlayerOwner != null)
|
||||
{
|
||||
// always friendly to other unit controlled by player, or to the player himself
|
||||
if (selfPlayerOwner == targetPlayerOwner)
|
||||
return ReputationRank.Friendly;
|
||||
|
||||
// duel - always hostile to opponent
|
||||
if (selfPlayerOwner.duel != null && selfPlayerOwner.duel.opponent == targetPlayerOwner && selfPlayerOwner.duel.startTime != 0)
|
||||
return ReputationRank.Hostile;
|
||||
|
||||
// same group - checks dependant only on our faction - skip FFA_PVP for example
|
||||
if (selfPlayerOwner.IsInRaidWith(targetPlayerOwner))
|
||||
return ReputationRank.Friendly; // return true to allow config option AllowTwoSide.Interaction.Group to work
|
||||
}
|
||||
|
||||
// check FFA_PVP
|
||||
if (IsFFAPvP() && target.IsFFAPvP())
|
||||
return ReputationRank.Hostile;
|
||||
|
||||
if (selfPlayerOwner != null)
|
||||
{
|
||||
var targetFactionTemplateEntry = target.GetFactionTemplateEntry();
|
||||
if (targetFactionTemplateEntry != null)
|
||||
{
|
||||
if (!selfPlayerOwner.HasUnitFlag2(UnitFlags2.IgnoreReputation))
|
||||
{
|
||||
var targetFactionEntry = CliDB.FactionStorage.LookupByKey(targetFactionTemplateEntry.Faction);
|
||||
if (targetFactionEntry != null)
|
||||
{
|
||||
if (targetFactionEntry.CanHaveReputation())
|
||||
{
|
||||
// check contested flags
|
||||
if (Convert.ToBoolean(targetFactionTemplateEntry.Flags & (uint)FactionTemplateFlags.ContestedGuard)
|
||||
&& selfPlayerOwner.HasPlayerFlag(PlayerFlags.ContestedPVP))
|
||||
return ReputationRank.Hostile;
|
||||
|
||||
// if faction has reputation, hostile state depends only from AtWar state
|
||||
if (selfPlayerOwner.GetReputationMgr().IsAtWar(targetFactionEntry))
|
||||
return ReputationRank.Hostile;
|
||||
return ReputationRank.Friendly;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// do checks dependant only on our faction
|
||||
return GetFactionReactionTo(GetFactionTemplateEntry(), target);
|
||||
}
|
||||
ReputationRank GetFactionReactionTo(FactionTemplateRecord factionTemplateEntry, Unit target)
|
||||
{
|
||||
// always neutral when no template entry found
|
||||
if (factionTemplateEntry == null)
|
||||
return ReputationRank.Neutral;
|
||||
|
||||
var targetFactionTemplateEntry = target.GetFactionTemplateEntry();
|
||||
if (targetFactionTemplateEntry == null)
|
||||
return ReputationRank.Neutral;
|
||||
|
||||
Player targetPlayerOwner = target.GetAffectingPlayer();
|
||||
if (targetPlayerOwner != null)
|
||||
{
|
||||
// check contested flags
|
||||
if (Convert.ToBoolean(factionTemplateEntry.Flags & (uint)FactionTemplateFlags.ContestedGuard)
|
||||
&& targetPlayerOwner.HasPlayerFlag(PlayerFlags.ContestedPVP))
|
||||
return ReputationRank.Hostile;
|
||||
ReputationRank repRank = targetPlayerOwner.GetReputationMgr().GetForcedRankIfAny(factionTemplateEntry);
|
||||
if (repRank != ReputationRank.None)
|
||||
return repRank;
|
||||
if (!target.HasUnitFlag2(UnitFlags2.IgnoreReputation))
|
||||
{
|
||||
var factionEntry = CliDB.FactionStorage.LookupByKey(factionTemplateEntry.Faction);
|
||||
if (factionEntry != null)
|
||||
{
|
||||
if (factionEntry.CanHaveReputation())
|
||||
{
|
||||
// CvP case - check reputation, don't allow state higher than neutral when at war
|
||||
repRank = targetPlayerOwner.GetReputationMgr().GetRank(factionEntry);
|
||||
if (targetPlayerOwner.GetReputationMgr().IsAtWar(factionEntry))
|
||||
repRank = (ReputationRank)Math.Min((int)ReputationRank.Neutral, (int)repRank);
|
||||
return repRank;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// common faction based check
|
||||
if (factionTemplateEntry.IsHostileTo(targetFactionTemplateEntry))
|
||||
return ReputationRank.Hostile;
|
||||
if (factionTemplateEntry.IsFriendlyTo(targetFactionTemplateEntry))
|
||||
return ReputationRank.Friendly;
|
||||
if (targetFactionTemplateEntry.IsFriendlyTo(factionTemplateEntry))
|
||||
return ReputationRank.Friendly;
|
||||
if (Convert.ToBoolean(factionTemplateEntry.Flags & (uint)FactionTemplateFlags.HostileByDefault))
|
||||
return ReputationRank.Hostile;
|
||||
// neutral by default
|
||||
return ReputationRank.Neutral;
|
||||
}
|
||||
|
||||
public uint GetFaction() { return m_unitData.FactionTemplate; }
|
||||
public void SetFaction(uint faction) { SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.FactionTemplate), faction); }
|
||||
public override uint GetFaction() { return m_unitData.FactionTemplate; }
|
||||
public override void SetFaction(uint faction) { SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.FactionTemplate), faction); }
|
||||
|
||||
public void RestoreFaction()
|
||||
{
|
||||
@@ -2834,60 +2539,58 @@ namespace Game.Entities
|
||||
}
|
||||
}
|
||||
|
||||
if (damagetype != DamageEffectType.NoDamage)
|
||||
if (damagetype != DamageEffectType.NoDamage && damagetype != DamageEffectType.DOT)
|
||||
{
|
||||
if (victim != attacker && (spellProto == null || !(spellProto.HasAttribute(SpellAttr7.NoPushbackOnDamage) || spellProto.HasAttribute(SpellAttr3.TreatAsPeriodic))))
|
||||
{
|
||||
if (damagetype != DamageEffectType.DOT)
|
||||
Spell spell = victim.GetCurrentSpell(CurrentSpellTypes.Generic);
|
||||
if (spell != null)
|
||||
{
|
||||
Spell spell = victim.GetCurrentSpell(CurrentSpellTypes.Generic);
|
||||
if (spell != null)
|
||||
if (spell.GetState() == SpellState.Preparing)
|
||||
{
|
||||
if (spell.GetState() == SpellState.Preparing)
|
||||
bool isCastInterrupted()
|
||||
{
|
||||
bool isCastInterrupted()
|
||||
{
|
||||
if (damage == 0)
|
||||
return spell.m_spellInfo.InterruptFlags.HasAnyFlag(SpellInterruptFlags.ZeroDamageCancels);
|
||||
if (damage == 0)
|
||||
return spell.m_spellInfo.InterruptFlags.HasAnyFlag(SpellInterruptFlags.ZeroDamageCancels);
|
||||
|
||||
if (victim.IsPlayer() && spell.m_spellInfo.InterruptFlags.HasAnyFlag(SpellInterruptFlags.DamageCancelsPlayerOnly))
|
||||
return true;
|
||||
if (victim.IsPlayer() && spell.m_spellInfo.InterruptFlags.HasAnyFlag(SpellInterruptFlags.DamageCancelsPlayerOnly))
|
||||
return true;
|
||||
|
||||
if (spell.m_spellInfo.InterruptFlags.HasAnyFlag(SpellInterruptFlags.DamageCancels))
|
||||
return true;
|
||||
if (spell.m_spellInfo.InterruptFlags.HasAnyFlag(SpellInterruptFlags.DamageCancels))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
bool isCastDelayed()
|
||||
{
|
||||
if (damage == 0)
|
||||
return false;
|
||||
};
|
||||
|
||||
bool isCastDelayed()
|
||||
{
|
||||
if (damage == 0)
|
||||
return false;
|
||||
if (victim.IsPlayer() && spell.m_spellInfo.InterruptFlags.HasAnyFlag(SpellInterruptFlags.DamagePushbackPlayerOnly))
|
||||
return true;
|
||||
|
||||
if (victim.IsPlayer() && spell.m_spellInfo.InterruptFlags.HasAnyFlag(SpellInterruptFlags.DamagePushbackPlayerOnly))
|
||||
return true;
|
||||
if (spell.m_spellInfo.InterruptFlags.HasAnyFlag(SpellInterruptFlags.DamagePushback))
|
||||
return true;
|
||||
|
||||
if (spell.m_spellInfo.InterruptFlags.HasAnyFlag(SpellInterruptFlags.DamagePushback))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isCastInterrupted())
|
||||
victim.InterruptNonMeleeSpells(false);
|
||||
else if (isCastDelayed())
|
||||
spell.Delayed();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (damage != 0 && victim.IsPlayer())
|
||||
{
|
||||
Spell spell1 = victim.GetCurrentSpell(CurrentSpellTypes.Channeled);
|
||||
if (spell1 != null)
|
||||
if (spell1.GetState() == SpellState.Casting && spell1.m_spellInfo.HasChannelInterruptFlag(SpellAuraInterruptFlags.DamageChannelDuration))
|
||||
spell1.DelayedChannel();
|
||||
if (isCastInterrupted())
|
||||
victim.InterruptNonMeleeSpells(false);
|
||||
else if (isCastDelayed())
|
||||
spell.Delayed();
|
||||
}
|
||||
}
|
||||
|
||||
if (damage != 0 && victim.IsPlayer())
|
||||
{
|
||||
Spell spell1 = victim.GetCurrentSpell(CurrentSpellTypes.Channeled);
|
||||
if (spell1 != null)
|
||||
if (spell1.GetState() == SpellState.Casting && spell1.m_spellInfo.HasChannelInterruptFlag(SpellAuraInterruptFlags.DamageChannelDuration))
|
||||
spell1.DelayedChannel();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3322,6 +3025,47 @@ namespace Game.Entities
|
||||
return nearMembers[randTarget];
|
||||
}
|
||||
|
||||
public uint GetComboPoints() { return (uint)GetPower(PowerType.ComboPoints); }
|
||||
|
||||
public void AddComboPoints(sbyte count, Spell spell = null)
|
||||
{
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
sbyte comboPoints = (sbyte)(spell != null ? spell.m_comboPointGain : GetPower(PowerType.ComboPoints));
|
||||
|
||||
comboPoints += count;
|
||||
|
||||
if (comboPoints > 5)
|
||||
comboPoints = 5;
|
||||
else if (comboPoints < 0)
|
||||
comboPoints = 0;
|
||||
|
||||
if (!spell)
|
||||
SetPower(PowerType.ComboPoints, comboPoints);
|
||||
else
|
||||
spell.m_comboPointGain = comboPoints;
|
||||
}
|
||||
|
||||
void GainSpellComboPoints(sbyte count)
|
||||
{
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
sbyte cp = (sbyte)GetPower(PowerType.ComboPoints);
|
||||
|
||||
cp += count;
|
||||
if (cp > 5) cp = 5;
|
||||
else if (cp < 0) cp = 0;
|
||||
|
||||
SetPower(PowerType.ComboPoints, cp);
|
||||
}
|
||||
|
||||
public void ClearComboPoints()
|
||||
{
|
||||
SetPower(PowerType.ComboPoints, 0);
|
||||
}
|
||||
|
||||
public void ClearAllReactives()
|
||||
{
|
||||
for (ReactiveType i = 0; i < ReactiveType.Max; ++i)
|
||||
@@ -3411,22 +3155,25 @@ namespace Game.Entities
|
||||
return (uint)damageResisted;
|
||||
}
|
||||
|
||||
static float CalculateAverageResistReduction(Unit attacker, SpellSchoolMask schoolMask, Unit victim, SpellInfo spellInfo = null)
|
||||
static float CalculateAverageResistReduction(WorldObject caster, SpellSchoolMask schoolMask, Unit victim, SpellInfo spellInfo = null)
|
||||
{
|
||||
float victimResistance = victim.GetResistance(schoolMask);
|
||||
|
||||
if (attacker != null)
|
||||
if (caster != null)
|
||||
{
|
||||
// pets inherit 100% of masters penetration
|
||||
// excluding traps
|
||||
Player player = attacker.GetSpellModOwner();
|
||||
if (player != null && attacker.GetEntry() != SharedConst.WorldTrigger)
|
||||
Player player = caster.GetSpellModOwner();
|
||||
if (player != null)
|
||||
{
|
||||
victimResistance += player.GetTotalAuraModifierByMiscMask(AuraType.ModTargetResistance, (int)schoolMask);
|
||||
victimResistance -= player.GetSpellPenetrationItemMod();
|
||||
}
|
||||
else
|
||||
victimResistance += attacker.GetTotalAuraModifierByMiscMask(AuraType.ModTargetResistance, (int)schoolMask);
|
||||
{
|
||||
Unit unitCaster = caster.ToUnit();
|
||||
if (unitCaster != null)
|
||||
victimResistance += unitCaster.GetTotalAuraModifierByMiscMask(AuraType.ModTargetResistance, (int)schoolMask);
|
||||
}
|
||||
}
|
||||
|
||||
// holy resistance exists in pve and comes from level difference, ignore template values
|
||||
@@ -3440,12 +3187,13 @@ namespace Game.Entities
|
||||
victimResistance = Math.Max(victimResistance, 0.0f);
|
||||
|
||||
// level-based resistance does not apply to binary spells, and cannot be overcome by spell penetration
|
||||
if (attacker != null && (spellInfo == null || !spellInfo.HasAttribute(SpellCustomAttributes.BinarySpell)))
|
||||
victimResistance += Math.Max(((float)victim.GetLevelForTarget(attacker) - (float)attacker.GetLevelForTarget(victim)) * 5.0f, 0.0f);
|
||||
// gameobject caster -- should it have level based resistance?
|
||||
if (caster != null && !caster.IsGameObject() && (spellInfo == null || !spellInfo.HasAttribute(SpellCustomAttributes.BinarySpell)))
|
||||
victimResistance += Math.Max(((float)victim.GetLevelForTarget(caster) - (float)caster.GetLevelForTarget(victim)) * 5.0f, 0.0f);
|
||||
|
||||
uint bossLevel = 83;
|
||||
float bossResistanceConstant = 510.0f;
|
||||
uint level = attacker != null ? victim.GetLevelForTarget(attacker) : attacker.GetLevel();
|
||||
uint level = caster ? victim.GetLevelForTarget(caster) : victim.GetLevel();
|
||||
float resistanceConstant;
|
||||
|
||||
if (level == bossLevel)
|
||||
|
||||
@@ -2331,9 +2331,9 @@ namespace Game.Guilds
|
||||
return m_achievementSys.HasAchieved(achievementId);
|
||||
}
|
||||
|
||||
public void UpdateCriteria(CriteriaTypes type, ulong miscValue1, ulong miscValue2, ulong miscValue3, Unit unit, Player player)
|
||||
public void UpdateCriteria(CriteriaTypes type, ulong miscValue1, ulong miscValue2, ulong miscValue3, WorldObject refe, Player player)
|
||||
{
|
||||
m_achievementSys.UpdateCriteria(type, miscValue1, miscValue2, miscValue3, unit, player);
|
||||
m_achievementSys.UpdateCriteria(type, miscValue1, miscValue2, miscValue3, refe, player);
|
||||
}
|
||||
|
||||
public void HandleNewsSetSticky(WorldSession session, uint newsId, bool sticky)
|
||||
|
||||
@@ -2577,27 +2577,26 @@ namespace Game.Maps
|
||||
|
||||
class GameObjectFocusCheck : ICheck<GameObject>
|
||||
{
|
||||
public GameObjectFocusCheck(Unit unit, uint focusId)
|
||||
public GameObjectFocusCheck(WorldObject caster, uint focusId)
|
||||
{
|
||||
i_unit = unit;
|
||||
i_focusId = focusId;
|
||||
_caster = caster;
|
||||
_focusId = focusId;
|
||||
}
|
||||
|
||||
public bool Invoke(GameObject go)
|
||||
{
|
||||
if (go.GetGoInfo().GetSpellFocusType() != i_focusId)
|
||||
if (go.GetGoInfo().GetSpellFocusType() != _focusId)
|
||||
return false;
|
||||
|
||||
if (!go.IsSpawned())
|
||||
return false;
|
||||
|
||||
float dist = go.GetGoInfo().GetSpellFocusRadius() / 2.0f;
|
||||
|
||||
return go.IsWithinDistInMap(i_unit, dist);
|
||||
return go.IsWithinDistInMap(_caster, dist);
|
||||
}
|
||||
|
||||
Unit i_unit;
|
||||
uint i_focusId;
|
||||
WorldObject _caster;
|
||||
uint _focusId;
|
||||
}
|
||||
|
||||
// Find the nearest Fishing hole and return true only if source object is in range of hole
|
||||
@@ -2697,7 +2696,7 @@ namespace Game.Maps
|
||||
|
||||
public class AnyDeadUnitObjectInRangeCheck<T> : ICheck<T> where T : WorldObject
|
||||
{
|
||||
public AnyDeadUnitObjectInRangeCheck(Unit searchObj, float range)
|
||||
public AnyDeadUnitObjectInRangeCheck(WorldObject searchObj, float range)
|
||||
{
|
||||
i_searchObj = searchObj;
|
||||
i_range = range;
|
||||
@@ -2720,16 +2719,14 @@ namespace Game.Maps
|
||||
return false;
|
||||
}
|
||||
|
||||
Unit i_searchObj;
|
||||
WorldObject i_searchObj;
|
||||
float i_range;
|
||||
}
|
||||
|
||||
public class AnyDeadUnitSpellTargetInRangeCheck<T> : AnyDeadUnitObjectInRangeCheck<T> where T : WorldObject
|
||||
{
|
||||
public AnyDeadUnitSpellTargetInRangeCheck(Unit searchObj, float range, SpellInfo spellInfo, SpellTargetCheckTypes check, SpellTargetObjectTypes objectType)
|
||||
: base(searchObj, range)
|
||||
public AnyDeadUnitSpellTargetInRangeCheck(WorldObject searchObj, float range, SpellInfo spellInfo, SpellTargetCheckTypes check, SpellTargetObjectTypes objectType) : base(searchObj, range)
|
||||
{
|
||||
i_spellInfo = spellInfo;
|
||||
i_check = new WorldObjectSpellTargetCheck(searchObj, searchObj, spellInfo, check, null, objectType);
|
||||
}
|
||||
|
||||
@@ -2738,7 +2735,6 @@ namespace Game.Maps
|
||||
return base.Invoke(obj) && i_check.Invoke(obj);
|
||||
}
|
||||
|
||||
SpellInfo i_spellInfo;
|
||||
WorldObjectSpellTargetCheck i_check;
|
||||
}
|
||||
|
||||
|
||||
@@ -4994,7 +4994,7 @@ namespace Game.Maps
|
||||
|
||||
List<WorldObject> _updateObjects = new();
|
||||
|
||||
delegate void FarSpellCallback(Map map);
|
||||
public delegate void FarSpellCallback(Map map);
|
||||
Queue<FarSpellCallback> _farSpellCallbacks = new();
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ using System.Collections.Generic;
|
||||
|
||||
namespace Game.Networking.Packets
|
||||
{
|
||||
class CombatLogServerPacket : ServerPacket
|
||||
public class CombatLogServerPacket : ServerPacket
|
||||
{
|
||||
public CombatLogServerPacket(ServerOpcodes opcode, ConnectionType connection = ConnectionType.Realm) : base(opcode, connection)
|
||||
{
|
||||
|
||||
@@ -1181,21 +1181,25 @@ namespace Game.Networking.Packets
|
||||
|
||||
public void Initialize(Spell spell)
|
||||
{
|
||||
Health = (long)spell.GetCaster().GetHealth();
|
||||
AttackPower = (int)spell.GetCaster().GetTotalAttackPowerValue(spell.GetCaster().GetClass() == Class.Hunter ? WeaponAttackType.RangedAttack : WeaponAttackType.BaseAttack);
|
||||
SpellPower = spell.GetCaster().SpellBaseDamageBonusDone(SpellSchoolMask.Spell);
|
||||
Armor = spell.GetCaster().GetArmor();
|
||||
PowerType primaryPowerType = spell.GetCaster().GetPowerType();
|
||||
bool primaryPowerAdded = false;
|
||||
foreach (SpellPowerCost cost in spell.GetPowerCost())
|
||||
Unit unitCaster = spell.GetCaster().ToUnit();
|
||||
if (unitCaster != null)
|
||||
{
|
||||
PowerData.Add(new SpellLogPowerData((int)cost.Power, spell.GetCaster().GetPower(cost.Power), cost.Amount));
|
||||
if (cost.Power == primaryPowerType)
|
||||
primaryPowerAdded = true;
|
||||
}
|
||||
Health = (long)unitCaster.GetHealth();
|
||||
AttackPower = (int)unitCaster.GetTotalAttackPowerValue(unitCaster.GetClass() == Class.Hunter ? WeaponAttackType.RangedAttack : WeaponAttackType.BaseAttack);
|
||||
SpellPower = unitCaster.SpellBaseDamageBonusDone(SpellSchoolMask.Spell);
|
||||
Armor = unitCaster.GetArmor();
|
||||
PowerType primaryPowerType = unitCaster.GetPowerType();
|
||||
bool primaryPowerAdded = false;
|
||||
foreach (SpellPowerCost cost in spell.GetPowerCost())
|
||||
{
|
||||
PowerData.Add(new SpellLogPowerData((int)cost.Power, unitCaster.GetPower(cost.Power), (int)cost.Amount));
|
||||
if (cost.Power == primaryPowerType)
|
||||
primaryPowerAdded = true;
|
||||
}
|
||||
|
||||
if (!primaryPowerAdded)
|
||||
PowerData.Insert(0, new SpellLogPowerData((int)primaryPowerType, spell.GetCaster().GetPower(primaryPowerType), 0));
|
||||
if (!primaryPowerAdded)
|
||||
PowerData.Insert(0, new SpellLogPowerData((int)primaryPowerType, unitCaster.GetPower(primaryPowerType), 0));
|
||||
}
|
||||
}
|
||||
|
||||
public void Write(WorldPacket data)
|
||||
|
||||
@@ -540,7 +540,7 @@ namespace Game
|
||||
return;
|
||||
|
||||
// always invisible or hidden faction can't change war state
|
||||
if (factionState.Flags.HasFlag(ReputationFlags.Hidden | ReputationFlags.Header))
|
||||
if (factionState.Flags.HasAnyFlag(ReputationFlags.Hidden | ReputationFlags.Header))
|
||||
return;
|
||||
|
||||
SetAtWar(factionState, on);
|
||||
@@ -577,7 +577,7 @@ namespace Game
|
||||
void SetInactive(FactionState faction, bool inactive)
|
||||
{
|
||||
// always invisible or hidden faction can't be inactive
|
||||
if (faction.Flags.HasFlag(ReputationFlags.Hidden | ReputationFlags.Header) || !faction.Flags.HasFlag(ReputationFlags.Visible))
|
||||
if (faction.Flags.HasAnyFlag(ReputationFlags.Hidden | ReputationFlags.Header) || !faction.Flags.HasFlag(ReputationFlags.Visible))
|
||||
return;
|
||||
|
||||
// already set
|
||||
|
||||
@@ -536,7 +536,8 @@ namespace Game.Scripting
|
||||
// methods allowing interaction with Spell object
|
||||
//
|
||||
// methods useable during all spell handling phases
|
||||
public Unit GetCaster() { return m_spell.GetCaster(); }
|
||||
public Unit GetCaster() { return m_spell.GetCaster().ToUnit(); }
|
||||
public GameObject GetGObjCaster() { return m_spell.GetCaster().ToGameObject(); }
|
||||
public Unit GetOriginalCaster() { return m_spell.GetOriginalCaster(); }
|
||||
public SpellInfo GetSpellInfo() { return m_spell.GetSpellInfo(); }
|
||||
public Difficulty GetCastDifficulty() { return m_spell.GetCastDifficulty(); }
|
||||
@@ -1453,7 +1454,23 @@ namespace Game.Scripting
|
||||
// returns guid of object which casted the aura (m_originalCaster of the Spell class)
|
||||
public ObjectGuid GetCasterGUID() { return m_aura.GetCasterGUID(); }
|
||||
// returns unit which casted the aura or null if not avalible (caster logged out for example)
|
||||
public Unit GetCaster() { return m_aura.GetCaster(); }
|
||||
public Unit GetCaster()
|
||||
{
|
||||
WorldObject caster = m_aura.GetCaster();
|
||||
if (caster != null)
|
||||
return caster.ToUnit();
|
||||
|
||||
return null;
|
||||
}
|
||||
// returns gameobject which cast the aura or NULL if not available
|
||||
public GameObject GetGObjCaster()
|
||||
{
|
||||
WorldObject caster = m_aura.GetCaster();
|
||||
if (caster != null)
|
||||
return caster.ToGameObject();
|
||||
|
||||
return null;
|
||||
}
|
||||
// returns object on which aura was casted, target for non-area auras, area aura source for area auras
|
||||
public WorldObject GetOwner() { return m_aura.GetOwner(); }
|
||||
// returns owner if it's unit or unit derived object, null otherwise (only for persistent area auras null is returned)
|
||||
|
||||
@@ -330,7 +330,7 @@ namespace Game.Spells
|
||||
m_spellInfo = createInfo._spellInfo;
|
||||
m_castDifficulty = createInfo._castDifficulty;
|
||||
m_castGuid = createInfo._castId;
|
||||
m_casterGuid = createInfo.CasterGUID.IsEmpty() ? createInfo.Caster.GetGUID() : createInfo.CasterGUID;
|
||||
m_casterGuid = createInfo.CasterGUID;
|
||||
m_castItemGuid = createInfo.CastItemGUID;
|
||||
m_castItemId = createInfo.CastItemId;
|
||||
m_castItemLevel = createInfo.CastItemLevel;
|
||||
@@ -2457,8 +2457,6 @@ namespace Game.Spells
|
||||
|
||||
public static Aura TryCreate(AuraCreateInfo createInfo)
|
||||
{
|
||||
Cypher.Assert(createInfo.Caster != null || !createInfo.CasterGUID.IsEmpty());
|
||||
|
||||
uint effMask = createInfo._auraEffectMask;
|
||||
if (createInfo._targetEffectMask != 0)
|
||||
effMask = createInfo._targetEffectMask;
|
||||
@@ -2472,17 +2470,25 @@ namespace Game.Spells
|
||||
|
||||
public static Aura Create(AuraCreateInfo createInfo)
|
||||
{
|
||||
Cypher.Assert(createInfo.Caster != null || !createInfo.CasterGUID.IsEmpty());
|
||||
|
||||
// try to get caster of aura
|
||||
if (!createInfo.CasterGUID.IsEmpty())
|
||||
{
|
||||
if (createInfo.GetOwner().GetGUID() == createInfo.CasterGUID)
|
||||
createInfo.Caster = createInfo.GetOwner().ToUnit();
|
||||
// world gameobjects can't own auras and they send empty casterguid
|
||||
// checked on sniffs with spell 22247
|
||||
if (createInfo.CasterGUID.IsGameObject())
|
||||
{
|
||||
createInfo.Caster = null;
|
||||
createInfo.CasterGUID.Clear();
|
||||
}
|
||||
else
|
||||
createInfo.Caster = Global.ObjAccessor.GetUnit(createInfo.GetOwner(), createInfo.CasterGUID);
|
||||
{
|
||||
if (createInfo._owner.GetGUID() == createInfo.CasterGUID)
|
||||
createInfo.Caster = createInfo._owner.ToUnit();
|
||||
else
|
||||
createInfo.Caster = Global.ObjAccessor.GetUnit(createInfo._owner, createInfo.CasterGUID);
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (createInfo.Caster != null)
|
||||
createInfo.CasterGUID = createInfo.Caster.GetGUID();
|
||||
|
||||
// check if aura can be owned by owner
|
||||
|
||||
+767
-533
File diff suppressed because it is too large
Load Diff
@@ -345,9 +345,9 @@ namespace Game.Spells
|
||||
m_targetMask &= ~SpellCastTargetFlags.DestLocation;
|
||||
}
|
||||
|
||||
public void Update(Unit caster)
|
||||
public void Update(WorldObject caster)
|
||||
{
|
||||
m_objectTarget = !m_objectTargetGUID.IsEmpty() ? ((m_objectTargetGUID == caster.GetGUID()) ? caster : Global.ObjAccessor.GetWorldObject(caster, m_objectTargetGUID)) : null;
|
||||
m_objectTarget = (m_objectTargetGUID == caster.GetGUID()) ? caster : Global.ObjAccessor.GetWorldObject(caster, m_objectTargetGUID);
|
||||
|
||||
m_itemTarget = null;
|
||||
if (caster is Player)
|
||||
@@ -403,7 +403,6 @@ namespace Game.Spells
|
||||
public bool HasDst() { return Convert.ToBoolean(m_targetMask & SpellCastTargetFlags.DestLocation); }
|
||||
public bool HasTraj() { return m_speed != 0; }
|
||||
|
||||
|
||||
public float GetPitch() { return m_pitch; }
|
||||
public void SetPitch(float pitch) { m_pitch = pitch; }
|
||||
float GetSpeed() { return m_speed; }
|
||||
|
||||
+1117
-1008
File diff suppressed because it is too large
Load Diff
+111
-86
@@ -1010,7 +1010,7 @@ namespace Game.Spells
|
||||
return SpellCastResult.SpellCastOk;
|
||||
}
|
||||
|
||||
public SpellCastResult CheckTarget(Unit caster, WorldObject target, bool Implicit = true)
|
||||
public SpellCastResult CheckTarget(WorldObject caster, WorldObject target, bool Implicit = true)
|
||||
{
|
||||
if (HasAttribute(SpellAttr1.CantTargetSelf) && caster == target)
|
||||
return SpellCastResult.BadTargets;
|
||||
@@ -1112,7 +1112,7 @@ namespace Game.Spells
|
||||
}
|
||||
|
||||
// check GM mode and GM invisibility - only for player casts (npc casts are controlled by AI) and negative spells
|
||||
if (unitTarget != caster && (caster.IsControlledByPlayer() || !IsPositive()) && unitTarget.IsTypeId(TypeId.Player))
|
||||
if (unitTarget != caster && (caster.GetAffectingPlayer() != null || !IsPositive()) && unitTarget.IsTypeId(TypeId.Player))
|
||||
{
|
||||
if (!unitTarget.ToPlayer().IsVisible())
|
||||
return SpellCastResult.BmOrInvisgod;
|
||||
@@ -1132,13 +1132,17 @@ namespace Game.Spells
|
||||
him, because it would be it's passenger, there's no such case where this gets to fail legitimacy, this problem
|
||||
cannot be solved from within the check in other way since target type cannot be called for the spell currently
|
||||
Spell examples: [ID - 52864 Devour Water, ID - 52862 Devour Wind, ID - 49370 Wyrmrest Defender: Destabilize Azure Dragonshrine Effect] */
|
||||
if (!caster.IsVehicle() && caster.GetCharmerOrOwner() != target)
|
||||
Unit unitCaster = caster.ToUnit();
|
||||
if (unitCaster != null)
|
||||
{
|
||||
if (TargetAuraState != 0 && !unitTarget.HasAuraState(TargetAuraState, this, caster))
|
||||
return SpellCastResult.TargetAurastate;
|
||||
if (!unitCaster.IsVehicle() && unitCaster.GetCharmerOrOwner() != target)
|
||||
{
|
||||
if (TargetAuraState != 0 && !unitTarget.HasAuraState(TargetAuraState, this, unitCaster))
|
||||
return SpellCastResult.TargetAurastate;
|
||||
|
||||
if (ExcludeTargetAuraState != 0 && unitTarget.HasAuraState(ExcludeTargetAuraState, this, caster))
|
||||
return SpellCastResult.TargetAurastate;
|
||||
if (ExcludeTargetAuraState != 0 && unitTarget.HasAuraState(ExcludeTargetAuraState, this, unitCaster))
|
||||
return SpellCastResult.TargetAurastate;
|
||||
}
|
||||
}
|
||||
|
||||
if (TargetAuraSpell != 0 && !unitTarget.HasAura(TargetAuraSpell))
|
||||
@@ -1170,7 +1174,7 @@ namespace Game.Spells
|
||||
return SpellCastResult.SpellCastOk;
|
||||
}
|
||||
|
||||
public SpellCastResult CheckExplicitTarget(Unit caster, WorldObject target, Item itemTarget = null)
|
||||
public SpellCastResult CheckExplicitTarget(WorldObject caster, WorldObject target, Item itemTarget = null)
|
||||
{
|
||||
SpellCastTargetFlags neededTargets = GetExplicitTargetMask();
|
||||
if (target == null)
|
||||
@@ -1183,22 +1187,27 @@ namespace Game.Spells
|
||||
Unit unitTarget = target.ToUnit();
|
||||
if (unitTarget != null)
|
||||
{
|
||||
if (Convert.ToBoolean(neededTargets & (SpellCastTargetFlags.UnitEnemy | SpellCastTargetFlags.UnitAlly | SpellCastTargetFlags.UnitRaid | SpellCastTargetFlags.UnitParty | SpellCastTargetFlags.UnitMinipet | SpellCastTargetFlags.UnitPassenger)))
|
||||
if (neededTargets.HasAnyFlag(SpellCastTargetFlags.UnitEnemy | SpellCastTargetFlags.UnitAlly | SpellCastTargetFlags.UnitRaid | SpellCastTargetFlags.UnitParty | SpellCastTargetFlags.UnitMinipet | SpellCastTargetFlags.UnitPassenger))
|
||||
{
|
||||
if (Convert.ToBoolean(neededTargets & SpellCastTargetFlags.UnitEnemy))
|
||||
Unit unitCaster = caster.ToUnit();
|
||||
if (neededTargets.HasFlag(SpellCastTargetFlags.UnitEnemy))
|
||||
if (caster.IsValidAttackTarget(unitTarget, this))
|
||||
return SpellCastResult.SpellCastOk;
|
||||
if (neededTargets.HasAnyFlag(SpellCastTargetFlags.UnitAlly)
|
||||
|| (neededTargets.HasAnyFlag(SpellCastTargetFlags.UnitParty) && caster.IsInPartyWith(unitTarget))
|
||||
|| (neededTargets.HasAnyFlag(SpellCastTargetFlags.UnitRaid) && caster.IsInRaidWith(unitTarget)))
|
||||
|
||||
if (neededTargets.HasFlag(SpellCastTargetFlags.UnitAlly)
|
||||
|| (neededTargets.HasFlag(SpellCastTargetFlags.UnitParty) && unitCaster != null && unitCaster.IsInPartyWith(unitTarget))
|
||||
|| (neededTargets.HasFlag(SpellCastTargetFlags.UnitRaid) && unitCaster != null && unitCaster.IsInRaidWith(unitTarget)))
|
||||
if (caster.IsValidAssistTarget(unitTarget, this))
|
||||
return SpellCastResult.SpellCastOk;
|
||||
if (Convert.ToBoolean(neededTargets & SpellCastTargetFlags.UnitMinipet))
|
||||
if (unitTarget.GetGUID() == caster.GetCritterGUID())
|
||||
|
||||
if (neededTargets.HasFlag(SpellCastTargetFlags.UnitMinipet) && unitCaster != null)
|
||||
if (unitTarget.GetGUID() == unitCaster.GetCritterGUID())
|
||||
return SpellCastResult.SpellCastOk;
|
||||
if (Convert.ToBoolean(neededTargets & SpellCastTargetFlags.UnitPassenger))
|
||||
if (unitTarget.IsOnVehicle(caster))
|
||||
|
||||
if (neededTargets.HasFlag(SpellCastTargetFlags.UnitPassenger) && unitCaster != null)
|
||||
if (unitTarget.IsOnVehicle(unitCaster))
|
||||
return SpellCastResult.SpellCastOk;
|
||||
|
||||
return SpellCastResult.BadTargets;
|
||||
}
|
||||
}
|
||||
@@ -2625,7 +2634,7 @@ namespace Game.Spells
|
||||
return RangeEntry.RangeMin[positive ? 1 : 0];
|
||||
}
|
||||
|
||||
public float GetMaxRange(bool positive = false, Unit caster = null, Spell spell = null)
|
||||
public float GetMaxRange(bool positive = false, WorldObject caster = null, Spell spell = null)
|
||||
{
|
||||
if (RangeEntry == null)
|
||||
return 0.0f;
|
||||
@@ -2640,7 +2649,7 @@ namespace Game.Spells
|
||||
return range;
|
||||
}
|
||||
|
||||
public int CalcDuration(Unit caster = null)
|
||||
public int CalcDuration(WorldObject caster = null)
|
||||
{
|
||||
int duration = GetDuration();
|
||||
|
||||
@@ -2733,8 +2742,13 @@ namespace Game.Spells
|
||||
return RecoveryTime > CategoryRecoveryTime ? RecoveryTime : CategoryRecoveryTime;
|
||||
}
|
||||
|
||||
public SpellPowerCost CalcPowerCost(PowerType powerType, bool optionalCost, Unit caster, SpellSchoolMask schoolMask, Spell spell = null)
|
||||
public SpellPowerCost CalcPowerCost(PowerType powerType, bool optionalCost, WorldObject caster, SpellSchoolMask schoolMask, Spell spell = null)
|
||||
{
|
||||
// gameobject casts don't use power
|
||||
Unit unitCaster = caster.ToUnit();
|
||||
if (unitCaster == null)
|
||||
return null;
|
||||
|
||||
var spellPowerRecord = PowerCosts.FirstOrDefault(spellPowerEntry => spellPowerEntry?.PowerType == powerType);
|
||||
if (spellPowerRecord == null)
|
||||
return null;
|
||||
@@ -2742,9 +2756,14 @@ namespace Game.Spells
|
||||
return CalcPowerCost(spellPowerRecord, optionalCost, caster, schoolMask, spell);
|
||||
}
|
||||
|
||||
public SpellPowerCost CalcPowerCost(SpellPowerRecord power, bool optionalCost, Unit caster, SpellSchoolMask schoolMask, Spell spell = null)
|
||||
public SpellPowerCost CalcPowerCost(SpellPowerRecord power, bool optionalCost, WorldObject caster, SpellSchoolMask schoolMask, Spell spell = null)
|
||||
{
|
||||
if (power.RequiredAuraSpellID != 0 && !caster.HasAura(power.RequiredAuraSpellID))
|
||||
// gameobject casts don't use power
|
||||
Unit unitCaster = caster.ToUnit();
|
||||
if (!unitCaster)
|
||||
return null;
|
||||
|
||||
if (power.RequiredAuraSpellID != 0 && !unitCaster.HasAura(power.RequiredAuraSpellID))
|
||||
return null;
|
||||
|
||||
SpellPowerCost cost = new();
|
||||
@@ -2756,14 +2775,14 @@ namespace Game.Spells
|
||||
if (power.PowerType == PowerType.Health)
|
||||
{
|
||||
cost.Power = PowerType.Health;
|
||||
cost.Amount = (int)caster.GetHealth();
|
||||
cost.Amount = (int)unitCaster.GetHealth();
|
||||
return cost;
|
||||
}
|
||||
// Else drain all power
|
||||
if (power.PowerType < PowerType.Max)
|
||||
{
|
||||
cost.Power = power.PowerType;
|
||||
cost.Amount = caster.GetPower(cost.Power);
|
||||
cost.Amount = unitCaster.GetPower(cost.Power);
|
||||
return cost;
|
||||
}
|
||||
|
||||
@@ -2784,12 +2803,12 @@ namespace Game.Spells
|
||||
// health as power used
|
||||
case PowerType.Health:
|
||||
if (MathFunctions.fuzzyEq(power.PowerCostPct, 0.0f))
|
||||
powerCost += (int)MathFunctions.CalculatePct(caster.GetMaxHealth(), power.PowerCostMaxPct);
|
||||
powerCost += (int)MathFunctions.CalculatePct(unitCaster.GetMaxHealth(), power.PowerCostMaxPct);
|
||||
else
|
||||
powerCost += (int)MathFunctions.CalculatePct(caster.GetMaxHealth(), power.PowerCostPct);
|
||||
powerCost += (int)MathFunctions.CalculatePct(unitCaster.GetMaxHealth(), power.PowerCostPct);
|
||||
break;
|
||||
case PowerType.Mana:
|
||||
powerCost += (int)MathFunctions.CalculatePct(caster.GetCreateMana(), power.PowerCostPct);
|
||||
powerCost += (int)MathFunctions.CalculatePct(unitCaster.GetCreateMana(), power.PowerCostPct);
|
||||
break;
|
||||
case PowerType.AlternatePower:
|
||||
Log.outError(LogFilter.Spells, $"SpellInfo.CalcPowerCost: Unknown power type '{power.PowerType}' in spell {Id}");
|
||||
@@ -2812,7 +2831,7 @@ namespace Game.Spells
|
||||
else
|
||||
{
|
||||
powerCost = (int)power.OptionalCost;
|
||||
powerCost += caster.GetTotalAuraModifier(AuraType.ModAdditionalPowerCost, aurEff =>
|
||||
powerCost += unitCaster.GetTotalAuraModifier(AuraType.ModAdditionalPowerCost, aurEff =>
|
||||
{
|
||||
return aurEff.GetMiscValue() == (int)power.PowerType && aurEff.IsAffectingSpell(this);
|
||||
});
|
||||
@@ -2824,7 +2843,7 @@ namespace Game.Spells
|
||||
if (HasAttribute(SpellAttr4.SpellVsExtendCost))
|
||||
{
|
||||
uint speed = 0;
|
||||
SpellShapeshiftFormRecord ss = CliDB.SpellShapeshiftFormStorage.LookupByKey(caster.GetShapeshiftForm());
|
||||
SpellShapeshiftFormRecord ss = CliDB.SpellShapeshiftFormStorage.LookupByKey(unitCaster.GetShapeshiftForm());
|
||||
if (ss != null)
|
||||
speed = ss.CombatRoundTime;
|
||||
else
|
||||
@@ -2833,7 +2852,7 @@ namespace Game.Spells
|
||||
if (!HasAttribute(SpellAttr3.MainHand) && HasAttribute(SpellAttr3.ReqOffhand))
|
||||
slot = WeaponAttackType.OffAttack;
|
||||
|
||||
speed = caster.GetBaseAttackTime(slot);
|
||||
speed = unitCaster.GetBaseAttackTime(slot);
|
||||
}
|
||||
|
||||
powerCost += (int)speed / 100;
|
||||
@@ -2844,7 +2863,7 @@ namespace Game.Spells
|
||||
if (!optionalCost)
|
||||
{
|
||||
// Flat mod from caster auras by spell school and power type
|
||||
foreach (AuraEffect aura in caster.GetAuraEffectsByType(AuraType.ModPowerCostSchool))
|
||||
foreach (AuraEffect aura in unitCaster.GetAuraEffectsByType(AuraType.ModPowerCostSchool))
|
||||
{
|
||||
if ((aura.GetMiscValue() & (int)schoolMask) == 0)
|
||||
continue;
|
||||
@@ -2857,7 +2876,7 @@ namespace Game.Spells
|
||||
}
|
||||
|
||||
// PCT mod from user auras by spell school and power type
|
||||
foreach (var schoolCostPct in caster.GetAuraEffectsByType(AuraType.ModPowerCostSchoolPct))
|
||||
foreach (var schoolCostPct in unitCaster.GetAuraEffectsByType(AuraType.ModPowerCostSchoolPct))
|
||||
{
|
||||
if ((schoolCostPct.GetMiscValue() & (int)schoolMask) == 0)
|
||||
continue;
|
||||
@@ -2870,7 +2889,7 @@ namespace Game.Spells
|
||||
}
|
||||
|
||||
// Apply cost mod by spell
|
||||
Player modOwner = caster.GetSpellModOwner();
|
||||
Player modOwner = unitCaster.GetSpellModOwner();
|
||||
if (modOwner != null)
|
||||
{
|
||||
SpellModOp mod = SpellModOp.Max;
|
||||
@@ -2904,19 +2923,19 @@ namespace Game.Spells
|
||||
}
|
||||
}
|
||||
|
||||
if (!caster.IsControlledByPlayer() && MathFunctions.fuzzyEq(power.PowerCostPct, 0.0f) && SpellLevel != 0 && power.PowerType == PowerType.Mana)
|
||||
if (!unitCaster.IsControlledByPlayer() && MathFunctions.fuzzyEq(power.PowerCostPct, 0.0f) && SpellLevel != 0 && power.PowerType == PowerType.Mana)
|
||||
{
|
||||
if (HasAttribute(SpellAttr0.LevelDamageCalculation))
|
||||
{
|
||||
GtNpcManaCostScalerRecord spellScaler = CliDB.NpcManaCostScalerGameTable.GetRow(SpellLevel);
|
||||
GtNpcManaCostScalerRecord casterScaler = CliDB.NpcManaCostScalerGameTable.GetRow(caster.GetLevel());
|
||||
GtNpcManaCostScalerRecord casterScaler = CliDB.NpcManaCostScalerGameTable.GetRow(unitCaster.GetLevel());
|
||||
if (spellScaler != null && casterScaler != null)
|
||||
powerCost *= (int)(casterScaler.Scaler / spellScaler.Scaler);
|
||||
}
|
||||
}
|
||||
|
||||
if (power.PowerType == PowerType.Mana)
|
||||
powerCost = (int)((float)powerCost * (1.0f + caster.m_unitData.ManaCostMultiplier));
|
||||
powerCost = (int)((float)powerCost * (1.0f + unitCaster.m_unitData.ManaCostMultiplier));
|
||||
|
||||
// power cost cannot become negative if initially positive
|
||||
if (initiallyNegative != (powerCost < 0))
|
||||
@@ -2927,42 +2946,41 @@ namespace Game.Spells
|
||||
return cost;
|
||||
}
|
||||
|
||||
public List<SpellPowerCost> CalcPowerCost(Unit caster, SpellSchoolMask schoolMask, Spell spell = null)
|
||||
public List<SpellPowerCost> CalcPowerCost(WorldObject caster, SpellSchoolMask schoolMask, Spell spell = null)
|
||||
{
|
||||
List<SpellPowerCost> costs = new();
|
||||
|
||||
SpellPowerCost getOrCreatePowerCost(PowerType powerType)
|
||||
if (caster.IsUnit())
|
||||
{
|
||||
var itr = costs.Find(cost =>
|
||||
SpellPowerCost getOrCreatePowerCost(PowerType powerType)
|
||||
{
|
||||
return cost.Power == powerType;
|
||||
});
|
||||
if (itr != null)
|
||||
return itr;
|
||||
var itr = costs.Find(cost => cost.Power == powerType);
|
||||
if (itr != null)
|
||||
return itr;
|
||||
|
||||
SpellPowerCost cost = new();
|
||||
cost.Power = powerType;
|
||||
cost.Amount = 0;
|
||||
costs.Add(cost);
|
||||
return costs.Last();
|
||||
}
|
||||
SpellPowerCost cost = new();
|
||||
cost.Power = powerType;
|
||||
cost.Amount = 0;
|
||||
costs.Add(cost);
|
||||
return costs.Last();
|
||||
}
|
||||
|
||||
foreach (SpellPowerRecord power in PowerCosts)
|
||||
{
|
||||
if (power == null)
|
||||
continue;
|
||||
|
||||
SpellPowerCost cost = CalcPowerCost(power, false, caster, schoolMask, spell);
|
||||
if (cost != null)
|
||||
getOrCreatePowerCost(cost.Power).Amount += cost.Amount;
|
||||
|
||||
SpellPowerCost optionalCost = CalcPowerCost(power, true, caster, schoolMask, spell);
|
||||
if (optionalCost != null)
|
||||
foreach (SpellPowerRecord power in PowerCosts)
|
||||
{
|
||||
SpellPowerCost cost1 = getOrCreatePowerCost(optionalCost.Power);
|
||||
int remainingPower = caster.GetPower(optionalCost.Power) - cost1.Amount;
|
||||
if (remainingPower > 0)
|
||||
cost1.Amount += Math.Min(optionalCost.Amount, remainingPower);
|
||||
if (power == null)
|
||||
continue;
|
||||
|
||||
SpellPowerCost cost = CalcPowerCost(power, false, caster, schoolMask, spell);
|
||||
if (cost != null)
|
||||
getOrCreatePowerCost(cost.Power).Amount += cost.Amount;
|
||||
|
||||
SpellPowerCost optionalCost = CalcPowerCost(power, true, caster, schoolMask, spell);
|
||||
if (optionalCost != null)
|
||||
{
|
||||
SpellPowerCost cost1 = getOrCreatePowerCost(optionalCost.Power);
|
||||
int remainingPower = caster.ToUnit().GetPower(optionalCost.Power) - cost1.Amount;
|
||||
if (remainingPower > 0)
|
||||
cost1.Amount += Math.Min(optionalCost.Amount, remainingPower);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3195,11 +3213,10 @@ namespace Game.Spells
|
||||
return false;
|
||||
}
|
||||
|
||||
public uint GetSpellXSpellVisualId(Unit caster = null)
|
||||
public uint GetSpellXSpellVisualId(WorldObject caster = null)
|
||||
{
|
||||
foreach (SpellXSpellVisualRecord visual in _visuals)
|
||||
{
|
||||
|
||||
PlayerConditionRecord playerCondition = CliDB.PlayerConditionStorage.LookupByKey(visual.CasterPlayerConditionID);
|
||||
if (playerCondition == null || (caster && caster.GetTypeId() == TypeId.Player && ConditionManager.IsPlayerMeetingCondition(caster.ToPlayer(), playerCondition)))
|
||||
return visual.Id;
|
||||
@@ -3208,7 +3225,7 @@ namespace Game.Spells
|
||||
return 0;
|
||||
}
|
||||
|
||||
public uint GetSpellVisual(Unit caster = null)
|
||||
public uint GetSpellVisual(WorldObject caster = null)
|
||||
{
|
||||
var visual = CliDB.SpellXSpellVisualStorage.LookupByKey(GetSpellXSpellVisualId(caster));
|
||||
if (visual != null)
|
||||
@@ -3817,13 +3834,13 @@ namespace Game.Spells
|
||||
public bool HasAttribute(SpellAttr14 attribute) { return Convert.ToBoolean(AttributesEx14 & attribute); }
|
||||
public bool HasAttribute(SpellCustomAttributes attribute) { return Convert.ToBoolean(AttributesCu & attribute); }
|
||||
|
||||
public bool CanBeInterrupted(Unit interruptCaster, Unit interruptTarget)
|
||||
public bool CanBeInterrupted(WorldObject interruptCaster, Unit interruptTarget)
|
||||
{
|
||||
return HasAttribute(SpellAttr7.CanAlwaysBeInterrupted)
|
||||
|| HasChannelInterruptFlag(SpellAuraInterruptFlags.Damage | SpellAuraInterruptFlags.EnteringCombat)
|
||||
|| (interruptTarget.IsPlayer() && InterruptFlags.HasFlag(SpellInterruptFlags.DamageCancelsPlayerOnly))
|
||||
|| InterruptFlags.HasFlag(SpellInterruptFlags.DamageCancels)
|
||||
|| interruptCaster.HasAuraTypeWithMiscvalue(AuraType.AllowInterruptSpell, (int)Id)
|
||||
|| interruptCaster.IsUnit() && interruptCaster.ToUnit().HasAuraTypeWithMiscvalue(AuraType.AllowInterruptSpell, (int)Id)
|
||||
|| ((interruptTarget.GetMechanicImmunityMask() & (1 << (int)Mechanics.Interrupt)) == 0
|
||||
&& !interruptTarget.HasAuraTypeWithAffectMask(AuraType.PreventInterrupt, this)
|
||||
&& PreventionType.HasAnyFlag(SpellPreventionType.Silence));
|
||||
@@ -4028,12 +4045,12 @@ namespace Game.Spells
|
||||
return IsAreaAuraEffect() || Effect == SpellEffectName.ApplyAura || Effect == SpellEffectName.ApplyAuraOnPet;
|
||||
}
|
||||
|
||||
public int CalcValue(Unit caster = null, int? bp = null, Unit target = null, uint castItemId = 0, int itemLevel = -1)
|
||||
public int CalcValue(WorldObject caster = null, int? bp = null, Unit target = null, uint castItemId = 0, int itemLevel = -1)
|
||||
{
|
||||
return CalcValue(out _, caster, bp, target, castItemId, itemLevel);
|
||||
}
|
||||
|
||||
public int CalcValue(out float variance, Unit caster = null, int? bp = null, Unit target = null, uint castItemId = 0, int itemLevel = -1)
|
||||
public int CalcValue(out float variance, WorldObject caster = null, int? bp = null, Unit target = null, uint castItemId = 0, int itemLevel = -1)
|
||||
{
|
||||
variance = 0.0f;
|
||||
float basePointsPerLevel = RealPointsPerLevel;
|
||||
@@ -4042,6 +4059,10 @@ namespace Game.Spells
|
||||
float value = bp.HasValue ? bp.Value : basePoints;
|
||||
float comboDamage = PointsPerResource;
|
||||
|
||||
Unit casterUnit = null;
|
||||
if (caster != null)
|
||||
casterUnit = caster.ToUnit();
|
||||
|
||||
if (Scaling.Variance != 0)
|
||||
{
|
||||
float delta = Math.Abs(Scaling.Variance * 0.5f);
|
||||
@@ -4058,9 +4079,9 @@ namespace Game.Spells
|
||||
}
|
||||
else if (GetScalingExpectedStat() == ExpectedStatType.None)
|
||||
{
|
||||
if (caster != null && basePointsPerLevel != 0.0f)
|
||||
if (casterUnit != null && basePointsPerLevel != 0.0f)
|
||||
{
|
||||
int level = (int)caster.GetLevel();
|
||||
int level = (int)casterUnit.GetLevel();
|
||||
if (level > (int)_spellInfo.MaxLevel && _spellInfo.MaxLevel > 0)
|
||||
level = (int)_spellInfo.MaxLevel;
|
||||
|
||||
@@ -4072,31 +4093,32 @@ namespace Game.Spells
|
||||
}
|
||||
}
|
||||
// random damage
|
||||
if (caster)
|
||||
if (casterUnit != null)
|
||||
{
|
||||
// bonus amount from combo points
|
||||
if (caster.m_playerMovingMe && comboDamage != 0)
|
||||
if (comboDamage != 0)
|
||||
{
|
||||
uint comboPoints = caster.m_playerMovingMe.GetComboPoints();
|
||||
uint comboPoints = casterUnit.GetComboPoints();
|
||||
if (comboPoints != 0)
|
||||
value += comboDamage * comboPoints;
|
||||
}
|
||||
|
||||
value = caster.ApplyEffectModifiers(_spellInfo, EffectIndex, value);
|
||||
if (caster != null)
|
||||
value = caster.ApplyEffectModifiers(_spellInfo, EffectIndex, value);
|
||||
}
|
||||
|
||||
return (int)Math.Round(value);
|
||||
}
|
||||
|
||||
public int CalcBaseValue(Unit caster, Unit target, uint itemId, int itemLevel)
|
||||
public int CalcBaseValue(WorldObject caster, Unit target, uint itemId, int itemLevel)
|
||||
{
|
||||
if (Scaling.Coefficient != 0.0f)
|
||||
{
|
||||
uint level = _spellInfo.SpellLevel;
|
||||
if (target && _spellInfo.IsPositiveEffect(EffectIndex) && (Effect == SpellEffectName.ApplyAura))
|
||||
level = target.GetLevel();
|
||||
else if (caster)
|
||||
level = caster.GetLevel();
|
||||
else if (caster != null && caster.IsUnit())
|
||||
level = caster.ToUnit().GetLevel();
|
||||
|
||||
if (_spellInfo.BaseLevel != 0 && !_spellInfo.HasAttribute(SpellAttr11.ScalesWithItemLevel) && _spellInfo.HasAttribute(SpellAttr10.UseSpellBaseLevelForScaling))
|
||||
level = _spellInfo.BaseLevel;
|
||||
@@ -4188,7 +4210,7 @@ namespace Game.Spells
|
||||
if (contentTuning != null)
|
||||
expansion = contentTuning.ExpansionID;
|
||||
|
||||
uint level = caster ? caster.GetLevel() : 1;
|
||||
uint level = caster != null && caster.IsUnit() ? caster.ToUnit().GetLevel() : 1;
|
||||
tempValue = Global.DB2Mgr.EvaluateExpectedStat(stat, level, expansion, 0, Class.None) * BasePoints / 100.0f;
|
||||
}
|
||||
|
||||
@@ -4196,7 +4218,7 @@ namespace Game.Spells
|
||||
}
|
||||
}
|
||||
|
||||
public float CalcValueMultiplier(Unit caster, Spell spell = null)
|
||||
public float CalcValueMultiplier(WorldObject caster, Spell spell = null)
|
||||
{
|
||||
float multiplier = Amplitude;
|
||||
Player modOwner = (caster != null ? caster.GetSpellModOwner() : null);
|
||||
@@ -4205,7 +4227,7 @@ namespace Game.Spells
|
||||
return multiplier;
|
||||
}
|
||||
|
||||
public float CalcDamageMultiplier(Unit caster, Spell spell = null)
|
||||
public float CalcDamageMultiplier(WorldObject caster, Spell spell = null)
|
||||
{
|
||||
float multiplierPercent = ChainAmplitude * 100.0f;
|
||||
Player modOwner = (caster != null ? caster.GetSpellModOwner() : null);
|
||||
@@ -4224,7 +4246,7 @@ namespace Game.Spells
|
||||
return MaxRadiusEntry != null;
|
||||
}
|
||||
|
||||
public float CalcRadius(Unit caster = null, Spell spell = null)
|
||||
public float CalcRadius(WorldObject caster = null, Spell spell = null)
|
||||
{
|
||||
SpellRadiusRecord entry = RadiusEntry;
|
||||
if (!HasRadius() && HasMaxRadius())
|
||||
@@ -4241,7 +4263,10 @@ namespace Game.Spells
|
||||
|
||||
if (caster != null)
|
||||
{
|
||||
radius += entry.RadiusPerLevel * caster.GetLevel();
|
||||
Unit casterUnit = caster.ToUnit();
|
||||
if (casterUnit != null)
|
||||
radius += entry.RadiusPerLevel * casterUnit.GetLevel();
|
||||
|
||||
radius = Math.Min(radius, entry.RadiusMax);
|
||||
Player modOwner = caster.GetSpellModOwner();
|
||||
if (modOwner != null)
|
||||
|
||||
@@ -494,7 +494,7 @@ namespace Game.Entities
|
||||
}
|
||||
|
||||
// always trigger for these types
|
||||
if (eventInfo.GetTypeMask().HasFlag(ProcFlags.Killed | ProcFlags.Kill | ProcFlags.Death))
|
||||
if (eventInfo.GetTypeMask().HasAnyFlag(ProcFlags.Killed | ProcFlags.Kill | ProcFlags.Death))
|
||||
return true;
|
||||
|
||||
// Do not consider autoattacks as triggered spells
|
||||
|
||||
@@ -906,7 +906,7 @@ namespace Scripts.Spells.Druid
|
||||
if (caster != null)
|
||||
{
|
||||
// 0.01 * $AP * cp
|
||||
byte cp = caster.ToPlayer().GetComboPoints();
|
||||
byte cp = (byte)caster.ToPlayer().GetComboPoints();
|
||||
|
||||
// Idol of Feral Shadows. Can't be handled as SpellMod due its dependency from CPs
|
||||
AuraEffect idol = caster.GetAuraEffect(SpellIds.IdolOfFeralShadows, 0);
|
||||
|
||||
@@ -1380,7 +1380,7 @@ namespace Scripts.Spells.Items
|
||||
|
||||
void HandleProc(AuraEffect aurEff, ProcEventInfo eventInfo)
|
||||
{
|
||||
if (eventInfo.GetTypeMask().HasFlag(ProcFlags.DoneRangedAutoAttack | ProcFlags.DoneSpellRangedDmgClass))
|
||||
if (eventInfo.GetTypeMask().HasAnyFlag(ProcFlags.DoneRangedAutoAttack | ProcFlags.DoneSpellRangedDmgClass))
|
||||
{
|
||||
// in that case, do not cast heal spell
|
||||
PreventDefaultAction();
|
||||
|
||||
@@ -1463,7 +1463,7 @@ namespace Scripts.World.NpcSpecial
|
||||
public override void Reset() { }
|
||||
public override void JustEngagedWith(Unit who) { }
|
||||
|
||||
public override void OnPossess(bool apply)
|
||||
public void OnPossess(bool apply)
|
||||
{
|
||||
if (apply)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user