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:
hondacrx
2022-01-02 19:49:21 -05:00
parent 82d3e3d8f4
commit 92c90bf777
6 changed files with 76 additions and 91 deletions
+2 -2
View File
@@ -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
}
} }
+58 -75
View File
@@ -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; }
+1 -3
View File
@@ -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
+2 -2
View File
@@ -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)
+4 -4
View File
@@ -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));
} }
} }
} }