Core/Spells: cleaned up and improved spell focusing behavior (PR #25440)

This commit is contained in:
Ovah
2020-09-14 19:47:51 +02:00
committed by GitHub
parent d52acf1b72
commit 39a436bd65
3 changed files with 27 additions and 53 deletions

View File

@@ -3133,42 +3133,15 @@ void Creature::SetSpellFocus(Spell const* focusSpell, WorldObject const* target)
_spellFocusInfo.Spell = focusSpell;
bool const noTurnDuringCast = spellInfo->HasAttribute(SPELL_ATTR5_DONT_TURN_DURING_CAST);
bool const turnDisabled = HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_DISABLE_TURN);
// 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 && !noTurnDuringCast && !turnDisabled) ? target->GetGUID() : ObjectGuid::Empty;
if (GetGuidValue(UNIT_FIELD_TARGET) != newTarget)
{
SetGuidValue(UNIT_FIELD_TARGET, newTarget);
if ( // 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
spellInfo->SpellVisual[0] ||
spellInfo->SpellVisual[1]
) && (
!focusSpell->GetCastTime() || // if the spell is instant cast
noTurnDuringCast // client gets confused if we attempt to turn at the regularly scheduled update packet
)
)
{
std::vector<Player*> playersNearby;
GetPlayerListInGrid(playersNearby, GetVisibilityRange());
for (Player* player : playersNearby)
{
// only update players that are known to the client (have already been created)
if (player->HaveAtClient(this))
SendUpdateToPlayer(player);
}
}
}
if (!HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_DISABLE_TURN))
{
// Face the target - we need to do this before the unit state is modified for no-turn spells
if (target)
SetFacingToObject(target, false);
else if (noTurnDuringCast)
if (Unit* victim = GetVictim())
SetFacingToObject(victim, false); // ensure orientation is correct at beginning of cast
}
// If we are not allowed to turn during cast but have a focus target, face the target
if (!turnDisabled && noTurnDuringCast && target)
SetFacingToObject(target, false);
if (noTurnDuringCast)
AddUnitState(UNIT_STATE_FOCUSING);

View File

@@ -868,6 +868,15 @@ void AuraEffect::PeriodicTick(AuraApplication* aurApp, Unit* caster) const
Unit* target = aurApp->GetTarget();
// Update serverside orientation of tracking channeled auras on periodic update ticks
if (caster && m_spellInfo->IsChanneled() && m_spellInfo->HasAttribute(SPELL_ATTR1_CHANNEL_TRACK_TARGET))
{
ObjectGuid const channelGuid = caster->GetChannelObjectGuid();
if (!channelGuid.IsEmpty() && channelGuid != caster->GetGUID())
if (WorldObject const* objectTarget = ObjectAccessor::GetWorldObject(*caster, channelGuid))
caster->SetInFront(objectTarget);
}
switch (GetAuraType())
{
case SPELL_AURA_PERIODIC_DUMMY:

View File

@@ -3116,16 +3116,15 @@ SpellCastResult Spell::prepare(SpellCastTargets const& targets, AuraEffect const
}
}
// focus if not controlled creature
if (m_caster->GetTypeId() == TYPEID_UNIT && !m_caster->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_POSSESSED))
// Creatures focus their target when possible
if (m_casttime && m_caster->IsCreature() && !m_spellInfo->IsNextMeleeSwingSpell() && !IsAutoRepeat() && !m_caster->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_POSSESSED))
{
if (!(m_spellInfo->IsNextMeleeSwingSpell() || IsAutoRepeat()))
{
if (m_targets.GetObjectTarget() && m_caster != m_targets.GetObjectTarget())
m_caster->ToCreature()->SetSpellFocus(this, m_targets.GetObjectTarget());
else if (m_spellInfo->HasAttribute(SPELL_ATTR5_DONT_TURN_DURING_CAST))
m_caster->ToCreature()->SetSpellFocus(this, nullptr);
}
// Channeled spells and some triggered spells do not focus a cast target. They face their target later on via channel object guid and via spell attribute or not at all
bool const focusTarget = !m_spellInfo->IsChanneled() && !(_triggeredCastFlags & TRIGGERED_IGNORE_SET_FACING);
if (focusTarget && m_targets.GetObjectTarget() && m_caster != m_targets.GetObjectTarget())
m_caster->ToCreature()->SetSpellFocus(this, m_targets.GetObjectTarget());
else
m_caster->ToCreature()->SetSpellFocus(this, nullptr);
}
// set timer base at cast time
@@ -3282,10 +3281,6 @@ void Spell::_cast(bool skipCheck)
SetExecutedCurrently(true);
if (!(_triggeredCastFlags & TRIGGERED_IGNORE_SET_FACING))
if (m_caster->GetTypeId() == TYPEID_UNIT && m_targets.GetObjectTarget() && m_caster != m_targets.GetObjectTarget())
m_caster->ToCreature()->SetInFront(m_targets.GetObjectTarget());
// Should this be done for original caster?
Player* modOwner = m_caster->GetSpellModOwner();
if (modOwner)
@@ -3368,13 +3363,10 @@ void Spell::_cast(bool skipCheck)
}
}
}
// if the spell allows the creature to turn while casting, then adjust server-side orientation to face the target now
// client-side orientation is handled by the client itself, as the cast target is targeted due to Creature::SetSpellFocusTarget
if (m_caster->GetTypeId() == TYPEID_UNIT && !m_caster->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_POSSESSED))
if (!m_spellInfo->HasAttribute(SPELL_ATTR5_DONT_TURN_DURING_CAST))
if (WorldObject* objTarget = m_targets.GetObjectTarget())
m_caster->ToCreature()->SetInFront(objTarget);
// The spell focusing is making sure that we have a valid cast target guid when we need it so only check for a guid value here.
if (Creature* creatureCaster = m_caster->ToCreature())
if (!creatureCaster->GetTarget().IsEmpty() && !creatureCaster->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_POSSESSED))
creatureCaster->SetInFront(ObjectAccessor::GetUnit(*creatureCaster, creatureCaster->GetTarget()));
SelectSpellTargets();
@@ -4615,7 +4607,7 @@ void Spell::SendChannelStart(uint32 duration)
if (!unitCaster)
return;
ObjectGuid channelTarget = m_targets.GetObjectTargetGUID();
ObjectGuid channelTarget = m_targets.HasDst() ? unitCaster->GetGUID() : m_targets.GetObjectTargetGUID();
if (!channelTarget && !m_spellInfo->NeedsExplicitUnitTarget())
if (m_UniqueTargetInfo.size() + m_UniqueGOTargetInfo.size() == 1) // this is for TARGET_SELECT_CATEGORY_NEARBY
channelTarget = !m_UniqueTargetInfo.empty() ? m_UniqueTargetInfo.front().TargetGUID : m_UniqueGOTargetInfo.front().TargetGUID;