diff --git a/Source/Game/Entities/Creature/Creature.cs b/Source/Game/Entities/Creature/Creature.cs index 323bbf57f..4c64fb2fc 100644 --- a/Source/Game/Entities/Creature/Creature.cs +++ b/Source/Game/Entities/Creature/Creature.cs @@ -2975,39 +2975,15 @@ namespace Game.Entities _spellFocusInfo.Spell = focusSpell; bool noTurnDuringCast = spellInfo.HasAttribute(SpellAttr5.DontTurnDuringCast); + bool turnDisabled = HasUnitFlag2(UnitFlags2.CannotTurn); // 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 != null && !noTurnDuringCast && !turnDisabled) ? target.GetGUID() : ObjectGuid.Empty; if (GetTarget() != newTarget) - { SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.Target), newTarget); - // 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 - if (spellInfo.GetSpellVisual() != 0 && (focusSpell.GetCastTime() == 0 || // if the spell is instant cast - noTurnDuringCast)) // client gets confused if we attempt to turn at the regularly scheduled update packet - { - List playersNearby = GetPlayerListInGrid(GetVisibilityRange()); - foreach (Player player in playersNearby) - { - // only update players that are known to the client (have already been created) - if (player.HaveAtClient(this)) - SendUpdateToPlayer(player); - } - } - } - - if (!HasUnitFlag2(UnitFlags2.CannotTurn)) - { - // 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) - { - Unit victim = GetVictim(); - if (victim) - SetFacingToObject(victim, false); // ensure server-side 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(UnitState.Focusing); diff --git a/Source/Game/Spells/Auras/AuraEffect.cs b/Source/Game/Spells/Auras/AuraEffect.cs index fad4a108a..09743e325 100644 --- a/Source/Game/Spells/Auras/AuraEffect.cs +++ b/Source/Game/Spells/Auras/AuraEffect.cs @@ -513,6 +513,18 @@ namespace Game.Spells Unit target = aurApp.GetTarget(); + // Update serverside orientation of tracking channeled auras on periodic update ticks + if (caster != null && m_spellInfo.IsChanneled() && m_spellInfo.HasAttribute(SpellAttr1.ChannelTrackTarget) && !caster.m_unitData.ChannelObjects.Empty()) + { + ObjectGuid channelGuid = caster.m_unitData.ChannelObjects[0]; + if (channelGuid != caster.GetGUID()) + { + WorldObject objectTarget = Global.ObjAccessor.GetWorldObject(caster, channelGuid); + if (objectTarget != null) + caster.SetInFront(objectTarget); + } + } + switch (GetAuraType()) { case AuraType.PeriodicDummy: diff --git a/Source/Game/Spells/Spell.cs b/Source/Game/Spells/Spell.cs index 38bca9a5b..3a43ca621 100644 --- a/Source/Game/Spells/Spell.cs +++ b/Source/Game/Spells/Spell.cs @@ -2462,16 +2462,15 @@ namespace Game.Spells } } - // focus if not controlled creature - if (m_caster.GetTypeId() == TypeId.Unit && !m_caster.ToUnit().HasUnitFlag(UnitFlags.Possessed)) + // Creatures focus their target when possible + if (m_casttime != 0 && m_caster.IsCreature() && !m_spellInfo.IsNextMeleeSwingSpell() && !IsAutoRepeat() && !m_caster.ToUnit().HasUnitFlag(UnitFlags.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(SpellAttr5.DontTurnDuringCast)) - m_caster.ToCreature().SetSpellFocus(this, null); - } + // 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 focusTarget = !m_spellInfo.IsChanneled() && !_triggeredCastFlags.HasFlag(TriggerCastFlags.IgnoreSetFacing); + if (focusTarget && m_targets.GetObjectTarget() && m_caster != m_targets.GetObjectTarget()) + m_caster.ToCreature().SetSpellFocus(this, m_targets.GetObjectTarget()); + else + m_caster.ToCreature().SetSpellFocus(this, null); } // set timer base at cast time @@ -2641,10 +2640,6 @@ namespace Game.Spells SetExecutedCurrently(true); - if (!Convert.ToBoolean(_triggeredCastFlags & TriggerCastFlags.IgnoreSetFacing)) - if (m_caster.IsTypeId(TypeId.Unit) && m_targets.GetObjectTarget() != null && 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 != null) @@ -2730,17 +2725,11 @@ namespace Game.Spells } } - // 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::FocusTarget - if (m_caster.IsTypeId(TypeId.Unit) && !m_caster.ToUnit().HasUnitFlag(UnitFlags.Possessed)) - { - if (!m_spellInfo.HasAttribute(SpellAttr5.DontTurnDuringCast)) - { - WorldObject objTarget = m_targets.GetObjectTarget(); - if (objTarget != null) - 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. + Creature creatureCaster = m_caster.ToCreature(); + if (creatureCaster != null) + if (!creatureCaster.GetTarget().IsEmpty() && !creatureCaster.HasUnitFlag(UnitFlags.Possessed)) + creatureCaster.SetInFront(Global.ObjAccessor.GetUnit(creatureCaster, creatureCaster.GetTarget())); SelectSpellTargets(); @@ -2816,11 +2805,8 @@ namespace Game.Spells SendSpellGo(); if (!m_spellInfo.IsChanneled()) - { - Creature creatureCaster = m_caster.ToCreature(); if (creatureCaster != null) creatureCaster.ReleaseSpellFocus(this); - } // Okay, everything is prepared. Now we need to distinguish between immediate and evented delayed spells if ((m_spellInfo.HasHitDelay() && !m_spellInfo.IsChanneled()) || m_spellInfo.HasAttribute(SpellAttr4.Unk4))