diff options
| -rw-r--r-- | src/server/game/Entities/Creature/Creature.cpp | 65 | ||||
| -rw-r--r-- | src/server/game/Entities/Creature/Creature.h | 9 | ||||
| -rw-r--r-- | src/server/game/Entities/Unit/Unit.cpp | 7 | ||||
| -rw-r--r-- | src/server/game/Entities/Unit/Unit.h | 2 | ||||
| -rw-r--r-- | src/server/game/Spells/Spell.cpp | 32 | ||||
| -rw-r--r-- | src/server/game/Spells/Spell.h | 1 | ||||
| -rw-r--r-- | src/server/scripts/Northrend/zone_dalaran.cpp | 1 |
7 files changed, 55 insertions, 62 deletions
diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index b556fde1705..c4a2e193be9 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -183,7 +183,7 @@ m_lootRecipient(), m_lootRecipientGroup(0), _skinner(), _pickpocketLootRestore(0 m_respawnDelay(300), m_corpseDelay(60), m_respawnradius(0.0f), m_boundaryCheckTime(2500), m_combatPulseTime(0), m_combatPulseDelay(0), m_reactState(REACT_AGGRESSIVE), m_defaultMovementType(IDLE_MOTION_TYPE), m_spawnId(0), m_equipmentId(0), m_originalEquipmentId(0), m_AlreadyCallAssistance(false), m_AlreadySearchedAssistance(false), m_regenHealth(true), m_cannotReachTarget(false), m_cannotReachTimer(0), m_AI_locked(false), m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL), -m_originalEntry(0), m_homePosition(), m_transportHomePosition(), m_creatureInfo(nullptr), m_creatureData(nullptr), m_waypointID(0), m_path_id(0), m_formation(nullptr), m_focusSpell(nullptr), m_focusDelay(0) +m_originalEntry(0), m_homePosition(), m_transportHomePosition(), m_creatureInfo(nullptr), m_creatureData(nullptr), m_waypointID(0), m_path_id(0), m_formation(nullptr), m_focusSpell(nullptr), m_focusDelay(0), m_shouldReacquireTarget(false), m_suppressedOrientation(0.0f) { m_regenTimer = CREATURE_REGEN_INTERVAL; m_valuesCount = UNIT_END; @@ -571,6 +571,19 @@ void Creature::Update(uint32 diff) if (!IsAlive()) break; + if (m_shouldReacquireTarget && !IsFocusing(nullptr, true)) + { + SetTarget(m_suppressedTarget); + if (m_suppressedTarget) + { + if (WorldObject const* objTarget = ObjectAccessor::GetWorldObject(*this, m_suppressedTarget)) + SetFacingToObject(objTarget); + } + else + SetFacingTo(m_suppressedOrientation); + m_shouldReacquireTarget = false; + } + // if creature is charmed, switch to charmed AI (and back) if (NeedChangeAI) { @@ -2781,31 +2794,39 @@ void Creature::SetDisplayId(uint32 modelId) void Creature::SetTarget(ObjectGuid guid) { - if (!IsFocusing()) + if (IsFocusing(nullptr, true)) + m_suppressedTarget = guid; + else SetGuidValue(UNIT_FIELD_TARGET, guid); } -bool Creature::FocusTarget(Spell const* focusSpell, WorldObject const* target) +void Creature::FocusTarget(Spell const* focusSpell, WorldObject const* target) { // already focused if (m_focusSpell) - return false; + return; + + // don't use spell focus for vehicle spells + if (focusSpell->GetSpellInfo()->HasAura(SPELL_AURA_CONTROL_VEHICLE)) + return; if ((!target || target == this) && !focusSpell->GetCastTime()) // instant cast, untargeted (or self-targeted) spell doesn't need any facing updates - return false; + return; - m_focusSpell = focusSpell; + // store pre-cast values for target and orientation (used to later restore) + if (!IsFocusing(nullptr, true)) + { // only overwrite these fields if we aren't transitioning from one spell focus to another + m_suppressedTarget = GetGuidValue(UNIT_FIELD_TARGET); + m_suppressedOrientation = GetOrientation(); + } - // "instant" creature casts that require re-targeting will be delayed by a short moment to prevent facing bugs - bool shouldDelay = false; + m_focusSpell = focusSpell; // set target, then force send update packet to players if it changed to provide appropriate facing ObjectGuid newTarget = target ? target->GetGUID() : ObjectGuid::Empty; if (GetGuidValue(UNIT_FIELD_TARGET) != newTarget) { SetGuidValue(UNIT_FIELD_TARGET, newTarget); - if (target) - SetFacingToObject(target); 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 @@ -2823,28 +2844,21 @@ bool Creature::FocusTarget(Spell const* focusSpell, WorldObject const* target) { // only update players that are known to the client (have already been created) if (player->HaveAtClient(this)) - { SendUpdateToPlayer(player); - shouldDelay = true; - } } - if (shouldDelay) - shouldDelay = !(focusSpell->IsTriggered() || focusSpell->GetCastTime() || focusSpell->GetSpellInfo()->IsChanneled()); } } bool canTurnDuringCast = !focusSpell->GetSpellInfo()->HasAttribute(SPELL_ATTR5_DONT_TURN_DURING_CAST); // Face the target - we need to do this before the unit state is modified for no-turn spells if (target) - SetInFront(target); + SetFacingTo(GetAngle(target)); else if (!canTurnDuringCast) if (Unit* victim = GetVictim()) - SetInFront(victim); // ensure server-side orientation is correct at beginning of cast + SetFacingTo(GetAngle(victim)); // ensure orientation is correct at beginning of cast if (!canTurnDuringCast) AddUnitState(UNIT_STATE_CANNOT_TURN); - - return shouldDelay; } bool Creature::IsFocusing(Spell const* focusSpell, bool withDelay) @@ -2882,9 +2896,18 @@ void Creature::ReleaseFocus(Spell const* focusSpell, bool withDelay) return; if (IsPet()) // player pets do not use delay system - SetGuidValue(UNIT_FIELD_TARGET, GetVictim() ? EnsureVictim()->GetGUID() : ObjectGuid::Empty); + { + SetGuidValue(UNIT_FIELD_TARGET, m_suppressedTarget); + if (m_suppressedTarget) + { + if (WorldObject const* objTarget = ObjectAccessor::GetWorldObject(*this, m_suppressedTarget)) + SetFacingTo(GetAngle(objTarget)); + } + else + SetFacingTo(m_suppressedOrientation); + } else - // tell the creature that it should reacquire its actual target after the delay expires (this is handled in ::Attack) + // 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(); diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index 57a025fdd88..029dd1eb77b 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -689,7 +689,8 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma // Handling caster facing during spellcast void SetTarget(ObjectGuid guid) override; - bool FocusTarget(Spell const* focusSpell, WorldObject const* target); + void MustReacquireTarget() { m_shouldReacquireTarget = true; } // flags the Creature for forced (client displayed) target reacquisition in the next ::Update call + void FocusTarget(Spell const* focusSpell, WorldObject const* target); bool IsFocusing(Spell const* focusSpell = nullptr, bool withDelay = false); void ReleaseFocus(Spell const* focusSpell = nullptr, bool withDelay = true); @@ -765,8 +766,12 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma CreatureGroup* m_formation; bool m_TriggerJustRespawned; - Spell const* m_focusSpell; ///> Locks the target during spell cast for proper facing + /* Spell focus system */ + Spell const* m_focusSpell; // Locks the target during spell cast for proper facing uint32 m_focusDelay; + bool m_shouldReacquireTarget; + ObjectGuid m_suppressedTarget; // Stores the creature's "real" target while casting + float m_suppressedOrientation; // Stores the creature's "real" orientation while casting CreatureTextRepeatGroup m_textRepeat; }; diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 339b2e9b71f..7b066f57def 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -247,7 +247,6 @@ Unit::Unit(bool isWorldObject) : m_createStats[i] = 0.0f; m_attacking = nullptr; - m_shouldReacquireTarget = false; m_modMeleeHitChance = 0.0f; m_modRangedHitChance = 0.0f; m_modSpellHitChance = 0.0f; @@ -8558,12 +8557,6 @@ bool Unit::Attack(Unit* victim, bool meleeAttack) if (HasAuraType(SPELL_AURA_MOD_UNATTACKABLE)) RemoveAurasByType(SPELL_AURA_MOD_UNATTACKABLE); - if (m_shouldReacquireTarget) - { - SetTarget(victim->GetGUID()); - m_shouldReacquireTarget = false; - } - if (m_attacking) { if (m_attacking == victim) diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 8441252bef6..61b7665254b 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1300,7 +1300,6 @@ class TC_GAME_API Unit : public WorldObject void _removeAttacker(Unit* pAttacker); // must be called only from Unit::AttackStop() Unit* getAttackerForHelper() const; // If someone wants to help, who to give them bool Attack(Unit* victim, bool meleeAttack); - void MustReacquireTarget() { m_shouldReacquireTarget = true; } // flags the Unit for forced (client displayed) target reacquisition in the next ::Attack call void CastStop(uint32 except_spellid = 0); bool AttackStop(); void RemoveAllAttackers(); @@ -2203,7 +2202,6 @@ class TC_GAME_API Unit : public WorldObject AttackerSet m_attackers; Unit* m_attacking; - bool m_shouldReacquireTarget; DeathState m_deathState; diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 9545b957c57..45dcb6d9d17 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -603,8 +603,6 @@ m_caster((info->HasAttribute(SPELL_ATTR6_CAST_BY_CHARMER) && caster->GetCharmerO //Auto Shot & Shoot (wand) m_autoRepeat = m_spellInfo->IsAutoRepeatRangedSpell(); - m_isDelayedInstantCast = false; - m_runesState = 0; m_powerCost = 0; // setup to correct value in Spell::prepare, must not be used before. m_casttime = 0; // setup to correct value in Spell::prepare, must not be used before. @@ -2977,21 +2975,9 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect const* triggered if (!(IsNextMeleeSwingSpell() || IsAutoRepeat() || _triggeredCastFlags & TRIGGERED_IGNORE_SET_FACING)) { if (m_targets.GetObjectTarget() && m_caster != m_targets.GetObjectTarget()) - { - if (m_caster->ToCreature()->FocusTarget(this, m_targets.GetObjectTarget())) - { - m_isDelayedInstantCast = true; - m_timer = 100; // 100ms delay ensures client has updated creature orientation when cast goes off - } - } + m_caster->ToCreature()->FocusTarget(this, m_targets.GetObjectTarget()); else if (m_spellInfo->HasAttribute(SPELL_ATTR5_DONT_TURN_DURING_CAST)) - { - if (m_caster->ToCreature()->FocusTarget(this, nullptr)) - { - m_isDelayedInstantCast = true; - m_timer = 100; - } - } + m_caster->ToCreature()->FocusTarget(this, nullptr); } // don't allow channeled spells / spells with cast time to be cast while moving @@ -3034,14 +3020,13 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect const* triggered } m_caster->SetCurrentCastSpell(this); - if (!m_isDelayedInstantCast) - SendSpellStart(); + SendSpellStart(); if (!(_triggeredCastFlags & TRIGGERED_IGNORE_GCD)) TriggerGlobalCooldown(); //item: first cast may destroy item and second cast causes crash - if (!m_casttime && !m_isDelayedInstantCast && !m_spellInfo->StartRecoveryTime && !m_castItemGUID && GetCurrentContainer() == CURRENT_GENERIC_SPELL) + if (!m_casttime && !m_spellInfo->StartRecoveryTime && !m_castItemGUID && GetCurrentContainer() == CURRENT_GENERIC_SPELL) cast(true); } } @@ -3050,9 +3035,6 @@ void Spell::cancel() { if (m_spellState == SPELL_STATE_FINISHED) return; - // delayed instant casts are used for client-side visual orientation; they are treated as instant for all intents and purposes server-side, and thus cannot be interrupted by another cast - if (m_isDelayedInstantCast) - return; uint32 oldState = m_spellState; m_spellState = SPELL_STATE_FINISHED; @@ -3122,9 +3104,6 @@ void Spell::cast(bool skipCheck) return; } - if (m_isDelayedInstantCast) - SendSpellStart(); - if (Player* playerCaster = m_caster->ToPlayer()) { // now that we've done the basic check, now run the scripts @@ -3209,10 +3188,7 @@ void Spell::cast(bool skipCheck) if (m_caster->GetTypeId() == TYPEID_UNIT && !m_caster->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED)) if (!m_spellInfo->HasAttribute(SPELL_ATTR5_DONT_TURN_DURING_CAST)) if (WorldObject* objTarget = m_targets.GetObjectTarget()) - { m_caster->SetInFront(objTarget); - m_caster->SetFacingToObject(objTarget); - } SelectSpellTargets(); diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index c834d187720..016af275141 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -527,7 +527,6 @@ class TC_GAME_API Spell int32 m_channeledDuration; // Calculated channeled spell duration in order to calculate correct pushback. bool m_canReflect; // can reflect this spell? bool m_autoRepeat; - bool m_isDelayedInstantCast; // whether this is a creature's delayed instant cast uint8 m_runesState; uint8 m_delayAtDamageCount; diff --git a/src/server/scripts/Northrend/zone_dalaran.cpp b/src/server/scripts/Northrend/zone_dalaran.cpp index 03af1a6417f..ac05c421efb 100644 --- a/src/server/scripts/Northrend/zone_dalaran.cpp +++ b/src/server/scripts/Northrend/zone_dalaran.cpp @@ -115,7 +115,6 @@ public: } break; } - me->SetOrientation(me->GetHomePosition().GetOrientation()); return; } |
