Core/Unit: Spell focusing now no longer nonsensical. HasSpellFocus always const. Error logs for various stuff.
Port From (https://github.com/TrinityCore/TrinityCore/commit/14c38a1c529e634b068a67b3e7475ddcf599086b)
This commit is contained in:
@@ -254,7 +254,7 @@ namespace Game.AI
|
|||||||
{
|
{
|
||||||
Unit victim = me.SelectVictim();
|
Unit victim = me.SelectVictim();
|
||||||
if (victim != null)
|
if (victim != null)
|
||||||
if (!me.HandleSpellFocus(null, true) && victim != me.GetVictim())
|
if (!me.HasSpellFocus() && victim != me.GetVictim())
|
||||||
AttackStart(victim);
|
AttackStart(victim);
|
||||||
|
|
||||||
return me.GetVictim() != null;
|
return me.GetVictim() != null;
|
||||||
@@ -313,7 +313,7 @@ namespace Game.AI
|
|||||||
me.ResetPlayerDamageReq();
|
me.ResetPlayerDamageReq();
|
||||||
me.SetLastDamagedTime(0);
|
me.SetLastDamagedTime(0);
|
||||||
me.SetCannotReachTarget(false);
|
me.SetCannotReachTarget(false);
|
||||||
me.DoNotReacquireTarget();
|
me.DoNotReacquireSpellFocusTarget();
|
||||||
EngagementOver();
|
EngagementOver();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -27,11 +27,7 @@ namespace Game.Entities
|
|||||||
CreatureTemplate m_creatureInfo;
|
CreatureTemplate m_creatureInfo;
|
||||||
CreatureData m_creatureData;
|
CreatureData m_creatureData;
|
||||||
|
|
||||||
Spell _focusSpell; // Locks the target during spell cast for proper facing
|
SpellFocusInfo _spellFocusInfo;
|
||||||
uint _spellFocusDelay;
|
|
||||||
bool _shouldReacquireSpellFocusTarget;
|
|
||||||
ObjectGuid _suppressedSpellFocusTarget; // Stores the creature's "real" target while casting
|
|
||||||
float _suppressedSpellFocusOrientation; // Stores the creature's "real" orientation while casting
|
|
||||||
|
|
||||||
long _lastDamagedTime; // Part of Evade mechanics
|
long _lastDamagedTime; // Part of Evade mechanics
|
||||||
MultiMap<byte, byte> m_textRepeat = new();
|
MultiMap<byte, byte> m_textRepeat = new();
|
||||||
@@ -104,4 +100,12 @@ namespace Game.Entities
|
|||||||
Active, // in move list
|
Active, // in move list
|
||||||
Inactive // in move list but should not move
|
Inactive // in move list but should not move
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct SpellFocusInfo
|
||||||
|
{
|
||||||
|
public Spell spell;
|
||||||
|
public uint delay; // ms until the creature's target should snap back (0 = no snapback scheduled)
|
||||||
|
public ObjectGuid target; // the creature's "real" target while casting
|
||||||
|
public float orientation; // the creature's "real" orientation while casting
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -532,23 +532,12 @@ namespace Game.Entities
|
|||||||
|
|
||||||
GetThreatManager().Update(diff);
|
GetThreatManager().Update(diff);
|
||||||
|
|
||||||
if (_shouldReacquireSpellFocusTarget && !HandleSpellFocus(null, true))
|
if (_spellFocusInfo.delay != 0)
|
||||||
{
|
{
|
||||||
SetTarget(_suppressedSpellFocusTarget);
|
if (_spellFocusInfo.delay <= diff)
|
||||||
|
ReacquireSpellFocusTarget();
|
||||||
if (!HasUnitFlag2(UnitFlags2.DisableTurn))
|
else
|
||||||
{
|
_spellFocusInfo.delay -= 0;
|
||||||
if (!_suppressedSpellFocusTarget.IsEmpty())
|
|
||||||
{
|
|
||||||
WorldObject objTarget = Global.ObjAccessor.GetWorldObject(this, _suppressedSpellFocusTarget);
|
|
||||||
if (objTarget)
|
|
||||||
SetFacingToObject(objTarget);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
SetFacingTo(_suppressedSpellFocusOrientation);
|
|
||||||
}
|
|
||||||
|
|
||||||
_shouldReacquireSpellFocusTarget = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// periodic check to see if the creature has passed an evade boundary
|
// periodic check to see if the creature has passed an evade boundary
|
||||||
@@ -932,7 +921,7 @@ namespace Game.Entities
|
|||||||
|
|
||||||
if (target && _IsTargetAcceptable(target) && CanCreatureAttack(target))
|
if (target && _IsTargetAcceptable(target) && CanCreatureAttack(target))
|
||||||
{
|
{
|
||||||
if (!HandleSpellFocus(null, true))
|
if (!HasSpellFocus())
|
||||||
SetInFront(target);
|
SetInFront(target);
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
@@ -1121,7 +1110,7 @@ namespace Game.Entities
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HasSpellFocusTarget())
|
if (HasSpellFocus())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (HasUnitState(UnitState.Casting))
|
if (HasUnitState(UnitState.Casting))
|
||||||
@@ -1820,8 +1809,8 @@ namespace Game.Entities
|
|||||||
SaveRespawnTime();
|
SaveRespawnTime();
|
||||||
|
|
||||||
ReleaseSpellFocus(null, false); // remove spellcast focus
|
ReleaseSpellFocus(null, false); // remove spellcast focus
|
||||||
DoNotReacquireTarget(); // cancel delayed re-target
|
DoNotReacquireSpellFocusTarget(); // cancel delayed re-target
|
||||||
SetTarget(ObjectGuid.Empty); // drop target - dead mobs shouldn't ever target things
|
SetTarget(ObjectGuid.Empty); // drop target - dead mobs shouldn't ever target things
|
||||||
|
|
||||||
SetNpcFlags(NPCFlags.None);
|
SetNpcFlags(NPCFlags.None);
|
||||||
SetNpcFlags2(NPCFlags2.None);
|
SetNpcFlags2(NPCFlags2.None);
|
||||||
@@ -2919,16 +2908,16 @@ namespace Game.Entities
|
|||||||
|
|
||||||
public override void SetTarget(ObjectGuid guid)
|
public override void SetTarget(ObjectGuid guid)
|
||||||
{
|
{
|
||||||
if (HandleSpellFocus(null, true))
|
if (HasSpellFocus())
|
||||||
_suppressedSpellFocusTarget = guid;
|
_spellFocusInfo.target = guid;
|
||||||
else
|
else
|
||||||
SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.Target), guid);
|
SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.Target), guid);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetSpellFocusTarget(Spell focusSpell, WorldObject target)
|
public void SetSpellFocus(Spell focusSpell, WorldObject target)
|
||||||
{
|
{
|
||||||
// already focused
|
// already focused
|
||||||
if (_focusSpell != null)
|
if (_spellFocusInfo.spell != null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Prevent dead/feigning death creatures from setting a focus target, so they won't turn
|
// Prevent dead/feigning death creatures from setting a focus target, so they won't turn
|
||||||
@@ -2953,14 +2942,17 @@ namespace Game.Entities
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// store pre-cast values for target and orientation (used to later restore)
|
// store pre-cast values for target and orientation (used to later restore)
|
||||||
if (!HandleSpellFocus(null, true))
|
if (_spellFocusInfo.delay == 0)
|
||||||
{ // only overwrite these fields if we aren't transitioning from one spell focus to another
|
{ // only overwrite these fields if we aren't transitioning from one spell focus to another
|
||||||
_suppressedSpellFocusTarget = GetTarget();
|
_spellFocusInfo.target = GetTarget();
|
||||||
_suppressedSpellFocusOrientation = GetOrientation();
|
_spellFocusInfo.orientation = GetOrientation();
|
||||||
}
|
}
|
||||||
|
else // don't automatically reacquire target for the previous spellcast
|
||||||
|
_spellFocusInfo.delay = 0;
|
||||||
|
|
||||||
_focusSpell = focusSpell;
|
_spellFocusInfo.spell = focusSpell;
|
||||||
|
|
||||||
|
bool noTurnDuringCast = spellInfo.HasAttribute(SpellAttr5.DontTurnDuringCast);
|
||||||
// set target, then force send update packet to players if it changed to provide appropriate facing
|
// set target, then force send update packet to players if it changed to provide appropriate facing
|
||||||
ObjectGuid newTarget = target ? target.GetGUID() : ObjectGuid.Empty;
|
ObjectGuid newTarget = target ? target.GetGUID() : ObjectGuid.Empty;
|
||||||
if (GetTarget() != newTarget)
|
if (GetTarget() != newTarget)
|
||||||
@@ -2970,7 +2962,7 @@ namespace Game.Entities
|
|||||||
// here we determine if the (relatively expensive) forced update is worth it, or whether we can afford to wait until the scheduled update tick
|
// here we determine if the (relatively expensive) forced update is worth it, or whether we can afford to wait until the scheduled update tick
|
||||||
// only require instant update for spells that actually have a visual
|
// only require instant update for spells that actually have a visual
|
||||||
if (spellInfo.GetSpellVisual() != 0 && (focusSpell.GetCastTime() == 0 || // if the spell is instant cast
|
if (spellInfo.GetSpellVisual() != 0 && (focusSpell.GetCastTime() == 0 || // if the spell is instant cast
|
||||||
spellInfo.HasAttribute(SpellAttr5.DontTurnDuringCast))) // client gets confused if we attempt to turn at the regularly scheduled update packet
|
noTurnDuringCast)) // client gets confused if we attempt to turn at the regularly scheduled update packet
|
||||||
{
|
{
|
||||||
List<Unit> playersNearby = GetPlayerListInGrid(GetVisibilityRange());
|
List<Unit> playersNearby = GetPlayerListInGrid(GetVisibilityRange());
|
||||||
foreach (Player player in playersNearby)
|
foreach (Player player in playersNearby)
|
||||||
@@ -2982,8 +2974,6 @@ namespace Game.Entities
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool noTurnDuringCast = spellInfo.HasAttribute(SpellAttr5.DontTurnDuringCast);
|
|
||||||
|
|
||||||
if (!HasUnitFlag2(UnitFlags2.DisableTurn))
|
if (!HasUnitFlag2(UnitFlags2.DisableTurn))
|
||||||
{
|
{
|
||||||
// Face the target - we need to do this before the unit state is modified for no-turn spells
|
// Face the target - we need to do this before the unit state is modified for no-turn spells
|
||||||
@@ -3001,75 +2991,68 @@ namespace Game.Entities
|
|||||||
AddUnitState(UnitState.Focusing);
|
AddUnitState(UnitState.Focusing);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool HandleSpellFocus(Spell focusSpell = null, bool withDelay = false)
|
public override bool HasSpellFocus(Spell focusSpell = null)
|
||||||
{
|
{
|
||||||
if (!IsAlive()) // dead creatures cannot focus
|
if (!IsAlive()) // dead creatures cannot focus
|
||||||
{
|
{
|
||||||
ReleaseSpellFocus(null, false);
|
if (_spellFocusInfo.spell != null || _spellFocusInfo.delay != 0)
|
||||||
|
Log.outWarn(LogFilter.Unit, $"Creature '{GetName()}' (entry {GetEntry()}) has spell focus (spell id {(_spellFocusInfo.spell != null ? _spellFocusInfo.spell.GetSpellInfo().Id : 0)}, delay {_spellFocusInfo.delay}ms) despite being dead.");
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (focusSpell && (focusSpell != _focusSpell))
|
if (focusSpell)
|
||||||
return false;
|
return focusSpell == _spellFocusInfo.spell;
|
||||||
|
else
|
||||||
if (!_focusSpell)
|
return _spellFocusInfo.spell != null || _spellFocusInfo.delay != 0;
|
||||||
{
|
|
||||||
if (!withDelay || _spellFocusDelay == 0)
|
|
||||||
return false;
|
|
||||||
if (Time.GetMSTimeDiffToNow(_spellFocusDelay) > 1000) // @todo figure out if we can get rid of this magic number somehow
|
|
||||||
{
|
|
||||||
_spellFocusDelay = 0; // save checks in the future
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ReleaseSpellFocus(Spell focusSpell = null, bool withDelay = true)
|
public void ReleaseSpellFocus(Spell focusSpell = null, bool withDelay = true)
|
||||||
{
|
{
|
||||||
if (_focusSpell == null)
|
if (!_spellFocusInfo.spell)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// focused to something else
|
// focused to something else
|
||||||
if (focusSpell && focusSpell != _focusSpell)
|
if (focusSpell && focusSpell != _spellFocusInfo.spell)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (IsPet() && !HasUnitFlag2(UnitFlags2.DisableTurn))// player pets do not use delay system
|
if (_spellFocusInfo.spell.GetSpellInfo().HasAttribute(SpellAttr5.DontTurnDuringCast))
|
||||||
|
ClearUnitState(UnitState.Focusing);
|
||||||
|
|
||||||
|
if (IsPet()) // player pets do not use delay system
|
||||||
{
|
{
|
||||||
SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.Target), _suppressedSpellFocusTarget);
|
if (!HasUnitFlag2(UnitFlags2.DisableTurn))
|
||||||
if (!_suppressedSpellFocusTarget.IsEmpty())
|
ReacquireSpellFocusTarget();
|
||||||
|
}
|
||||||
|
else // don't allow re-target right away to prevent visual bugs
|
||||||
|
_spellFocusInfo.delay = withDelay ? 1000 : 1u;
|
||||||
|
|
||||||
|
_spellFocusInfo.spell = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReacquireSpellFocusTarget()
|
||||||
|
{
|
||||||
|
if (!HasSpellFocus())
|
||||||
|
return;
|
||||||
|
|
||||||
|
SetTarget(_spellFocusInfo.target);
|
||||||
|
|
||||||
|
if (!HasUnitFlag2(UnitFlags2.DisableTurn))
|
||||||
|
{
|
||||||
|
if (!_spellFocusInfo.target.IsEmpty())
|
||||||
{
|
{
|
||||||
WorldObject objTarget = Global.ObjAccessor.GetWorldObject(this, _suppressedSpellFocusTarget);
|
WorldObject objTarget = Global.ObjAccessor.GetWorldObject(this, _spellFocusInfo.target);
|
||||||
if (objTarget)
|
if (objTarget)
|
||||||
SetFacingToObject(objTarget, false);
|
SetFacingToObject(objTarget, false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
SetFacingTo(_suppressedSpellFocusOrientation, false);
|
SetFacingTo(_spellFocusInfo.orientation, false);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
// tell the creature that it should reacquire its actual target after the delay expires (this is handled in ::Update)
|
|
||||||
// player pets don't need to do this, as they automatically reacquire their target on focus release
|
|
||||||
MustReacquireTarget();
|
|
||||||
|
|
||||||
if (_focusSpell.GetSpellInfo().HasAttribute(SpellAttr5.DontTurnDuringCast))
|
_spellFocusInfo.delay = 0;
|
||||||
ClearUnitState(UnitState.Focusing);
|
|
||||||
|
|
||||||
_focusSpell = null;
|
|
||||||
_spellFocusDelay = (!IsPet() && withDelay) ? GameTime.GetGameTimeMS() : 0; // don't allow re-target right away to prevent visual bugs
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool HasSpellFocusTarget() { return IsAlive() && (_focusSpell != null || _spellFocusDelay != 0); }
|
public void DoNotReacquireSpellFocusTarget() { _spellFocusInfo.delay = 0; }
|
||||||
|
|
||||||
public void MustReacquireTarget() { _shouldReacquireSpellFocusTarget = true; } // flags the Creature for forced (client displayed) target reacquisition in the next Update call
|
|
||||||
|
|
||||||
public void DoNotReacquireTarget()
|
|
||||||
{
|
|
||||||
_shouldReacquireSpellFocusTarget = false;
|
|
||||||
_suppressedSpellFocusTarget = ObjectGuid.Empty;
|
|
||||||
SetTarget(ObjectGuid.Empty);
|
|
||||||
_suppressedSpellFocusOrientation = 0.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ulong GetSpawnId() { return m_spawnId; }
|
public ulong GetSpawnId() { return m_spawnId; }
|
||||||
|
|
||||||
|
|||||||
@@ -1041,9 +1041,7 @@ namespace Game.Entities
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual bool HandleSpellFocus(Spell focusSpell = null, bool withDelay = false) { return false; }
|
public virtual bool HasSpellFocus(Spell focusSpell = null) { return false; }
|
||||||
|
|
||||||
public virtual bool HasSpellFocusTarget() { return false; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Check if our current channel spell has attribute SPELL_ATTR5_CAN_CHANNEL_WHEN_MOVING
|
/// Check if our current channel spell has attribute SPELL_ATTR5_CAN_CHANNEL_WHEN_MOVING
|
||||||
|
|||||||
@@ -327,7 +327,7 @@ namespace Game
|
|||||||
Unit unit_target2 = spell.m_targets.GetUnitTarget();
|
Unit unit_target2 = spell.m_targets.GetUnitTarget();
|
||||||
if (unit_target)
|
if (unit_target)
|
||||||
{
|
{
|
||||||
if (!pet.HandleSpellFocus())
|
if (!pet.HasSpellFocus())
|
||||||
pet.SetInFront(unit_target);
|
pet.SetInFront(unit_target);
|
||||||
Player player = unit_target.ToPlayer();
|
Player player = unit_target.ToPlayer();
|
||||||
if (player)
|
if (player)
|
||||||
@@ -335,7 +335,7 @@ namespace Game
|
|||||||
}
|
}
|
||||||
else if (unit_target2)
|
else if (unit_target2)
|
||||||
{
|
{
|
||||||
if (!pet.HandleSpellFocus())
|
if (!pet.HasSpellFocus())
|
||||||
pet.SetInFront(unit_target2);
|
pet.SetInFront(unit_target2);
|
||||||
Player player = unit_target2.ToPlayer();
|
Player player = unit_target2.ToPlayer();
|
||||||
if (player)
|
if (player)
|
||||||
|
|||||||
@@ -2343,9 +2343,9 @@ namespace Game.Spells
|
|||||||
if (!(m_spellInfo.IsNextMeleeSwingSpell() || IsAutoRepeat()))
|
if (!(m_spellInfo.IsNextMeleeSwingSpell() || IsAutoRepeat()))
|
||||||
{
|
{
|
||||||
if (m_targets.GetObjectTarget() && m_caster != m_targets.GetObjectTarget())
|
if (m_targets.GetObjectTarget() && m_caster != m_targets.GetObjectTarget())
|
||||||
m_caster.ToCreature().SetSpellFocusTarget(this, m_targets.GetObjectTarget());
|
m_caster.ToCreature().SetSpellFocus(this, m_targets.GetObjectTarget());
|
||||||
else if (m_spellInfo.HasAttribute(SpellAttr5.DontTurnDuringCast))
|
else if (m_spellInfo.HasAttribute(SpellAttr5.DontTurnDuringCast))
|
||||||
m_caster.ToCreature().SetSpellFocusTarget(this, null);
|
m_caster.ToCreature().SetSpellFocus(this, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3998,8 +3998,8 @@ namespace Game.Spells
|
|||||||
{
|
{
|
||||||
Creature creatureCaster = unitCaster.ToCreature();
|
Creature creatureCaster = unitCaster.ToCreature();
|
||||||
if (creatureCaster != null)
|
if (creatureCaster != null)
|
||||||
if (!creatureCaster.HandleSpellFocus(this))
|
if (!creatureCaster.HasSpellFocus())
|
||||||
creatureCaster.SetSpellFocusTarget(this, Global.ObjAccessor.GetWorldObject(creatureCaster, target.TargetGUID));
|
creatureCaster.SetSpellFocus(this, Global.ObjAccessor.GetWorldObject(creatureCaster, target.TargetGUID));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user