diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index e1f54969b67..eff1aba3252 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -2789,6 +2789,10 @@ void Creature::FocusTarget(Spell const* focusSpell, WorldObject const* target) if (m_focusSpell) return; + // some spells shouldn't track targets + if (focusSpell->IsFocusDisabled()) + return; + SpellInfo const* spellInfo = focusSpell->GetSpellInfo(); // don't use spell focus for vehicle spells @@ -2847,7 +2851,7 @@ void Creature::FocusTarget(Spell const* focusSpell, WorldObject const* target) } if (noTurnDuringCast) - AddUnitState(UNIT_STATE_CANNOT_TURN); + AddUnitState(UNIT_STATE_FOCUSING); } bool Creature::IsFocusing(Spell const* focusSpell, bool withDelay) @@ -2901,7 +2905,7 @@ void Creature::ReleaseFocus(Spell const* focusSpell, bool withDelay) MustReacquireTarget(); if (m_focusSpell->GetSpellInfo()->HasAttribute(SPELL_ATTR5_DONT_TURN_DURING_CAST)) - ClearUnitState(UNIT_STATE_CANNOT_TURN); + ClearUnitState(UNIT_STATE_FOCUSING); m_focusSpell = nullptr; m_focusDelay = (!IsPet() && withDelay) ? GameTime::GetGameTimeMS() : 0; // don't allow re-target right away to prevent visual bugs diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 3ae1d2f96de..40fce35fde6 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -24934,6 +24934,10 @@ void Player::ResurrectUsingRequestData() void Player::SetClientControl(Unit* target, bool allowMove) { + // still affected by some aura that shouldn't allow control, only allow on last such aura to be removed + if (allowMove && target->HasUnitState(UNIT_STATE_CANT_CLIENT_CONTROL)) + return; + WorldPacket data(SMSG_CLIENT_CONTROL_UPDATE, target->GetPackGUID().size()+1); data << target->GetPackGUID(); data << uint8(allowMove ? 1 : 0); diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 24e66323290..754db24f082 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -11847,24 +11847,26 @@ void Unit::SetControlled(bool apply, UnitState state) return; } - ClearUnitState(state); - - // Unit States might have been already cleared but auras still present. I need to check with HasAuraType - if (HasAuraType(SPELL_AURA_MOD_STUN)) - SetStunned(true); - else - { - if (HasAuraType(SPELL_AURA_MOD_ROOT)) - SetRooted(true); - - if (HasAuraType(SPELL_AURA_MOD_CONFUSE)) - SetConfused(true); - else if (HasAuraType(SPELL_AURA_MOD_FEAR)) - SetFeared(true); - } + ApplyControlStatesIfNeeded(); } } +void Unit::ApplyControlStatesIfNeeded() +{ + // Unit States might have been already cleared but auras still present. I need to check with HasAuraType + if (HasUnitState(UNIT_STATE_STUNNED) || HasAuraType(SPELL_AURA_MOD_STUN)) + SetStunned(true); + + if (HasUnitState(UNIT_STATE_ROOT) || HasAuraType(SPELL_AURA_MOD_ROOT)) + SetRooted(true); + + if (HasUnitState(UNIT_STATE_CONFUSED) || HasAuraType(SPELL_AURA_MOD_CONFUSE)) + SetConfused(true); + + if (HasUnitState(UNIT_STATE_FLEEING) || HasAuraType(SPELL_AURA_MOD_FEAR)) + SetFeared(true); +} + void Unit::SetStunned(bool apply) { if (apply) @@ -11971,9 +11973,12 @@ void Unit::SetConfused(bool apply) } } - if (Player* player = ToPlayer()) - if (!player->HasUnitState(UNIT_STATE_POSSESSED)) - player->SetClientControl(this, !apply); + // block / allow control to real player in control (eg charmer) + if (GetTypeId() == TYPEID_PLAYER) + { + if (m_playerMovingMe) + m_playerMovingMe->SetClientControl(this, !apply); + } } bool Unit::SetCharmedBy(Unit* charmer, CharmType type, AuraApplication const* aurApp) @@ -12131,6 +12136,8 @@ bool Unit::SetCharmedBy(Unit* charmer, CharmType type, AuraApplication const* au break; } } + + AddUnitState(UNIT_STATE_CHARMED); return true; } @@ -12236,6 +12243,7 @@ void Unit::RemoveCharmedBy(Unit* charmer) NeedChangeAI = true; IsAIEnabled = false; } + player->SetClientControl(this, true); } @@ -12244,6 +12252,10 @@ void Unit::RemoveCharmedBy(Unit* charmer) playerCharmer->SendRemoveControlBar(); else if (GetTypeId() == TYPEID_PLAYER || (GetTypeId() == TYPEID_UNIT && !IsGuardian())) DeleteCharmInfo(); + + // reset confused movement for example + ApplyControlStatesIfNeeded(); + ClearUnitState(UNIT_STATE_CHARMED); } void Unit::RestoreFaction() diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 63db28fd316..08bad260381 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -412,11 +412,11 @@ enum UnitState : uint32 { UNIT_STATE_DIED = 0x00000001, // player has fake death aura UNIT_STATE_MELEE_ATTACKING = 0x00000002, // player is melee attacking someone - //UNIT_STATE_MELEE_ATTACK_BY = 0x00000004, // player is melee attack by someone + UNIT_STATE_CHARMED = 0x00000004, // having any kind of charm aura on self UNIT_STATE_STUNNED = 0x00000008, UNIT_STATE_ROAMING = 0x00000010, UNIT_STATE_CHASE = 0x00000020, - //UNIT_STATE_SEARCHING = 0x00000040, + UNIT_STATE_FOCUSING = 0x00000040, UNIT_STATE_FLEEING = 0x00000080, UNIT_STATE_IN_FLIGHT = 0x00000100, // player is in flight mode UNIT_STATE_FOLLOW = 0x00000200, @@ -426,7 +426,7 @@ enum UnitState : uint32 UNIT_STATE_ISOLATED = 0x00002000, // area auras do not affect other players UNIT_STATE_ATTACK_PLAYER = 0x00004000, UNIT_STATE_CASTING = 0x00008000, - UNIT_STATE_POSSESSED = 0x00010000, + UNIT_STATE_POSSESSED = 0x00010000, // being possessed by another unit UNIT_STATE_CHARGING = 0x00020000, UNIT_STATE_JUMPING = 0x00040000, UNIT_STATE_MOVE = 0x00100000, @@ -439,8 +439,8 @@ enum UnitState : uint32 UNIT_STATE_FOLLOW_MOVE = 0x08000000, UNIT_STATE_IGNORE_PATHFINDING = 0x10000000, // do not use pathfinding in any MovementGenerator - UNIT_STATE_ALL_STATE_SUPPORTED = UNIT_STATE_DIED | UNIT_STATE_MELEE_ATTACKING | UNIT_STATE_STUNNED | UNIT_STATE_ROAMING | UNIT_STATE_CHASE - | UNIT_STATE_FLEEING | UNIT_STATE_IN_FLIGHT | UNIT_STATE_FOLLOW | UNIT_STATE_ROOT | UNIT_STATE_CONFUSED + UNIT_STATE_ALL_STATE_SUPPORTED = UNIT_STATE_DIED | UNIT_STATE_MELEE_ATTACKING | UNIT_STATE_CHARMED | UNIT_STATE_STUNNED | UNIT_STATE_ROAMING | UNIT_STATE_CHASE + | UNIT_STATE_FOCUSING | UNIT_STATE_FLEEING | UNIT_STATE_IN_FLIGHT | UNIT_STATE_FOLLOW | UNIT_STATE_ROOT | UNIT_STATE_CONFUSED | UNIT_STATE_DISTRACTED | UNIT_STATE_ISOLATED | UNIT_STATE_ATTACK_PLAYER | UNIT_STATE_CASTING | UNIT_STATE_POSSESSED | UNIT_STATE_CHARGING | UNIT_STATE_JUMPING | UNIT_STATE_MOVE | UNIT_STATE_ROTATING | UNIT_STATE_EVADE | UNIT_STATE_ROAMING_MOVE | UNIT_STATE_CONFUSED_MOVE | UNIT_STATE_FLEEING_MOVE @@ -449,10 +449,11 @@ enum UnitState : uint32 UNIT_STATE_UNATTACKABLE = UNIT_STATE_IN_FLIGHT, UNIT_STATE_MOVING = UNIT_STATE_ROAMING_MOVE | UNIT_STATE_CONFUSED_MOVE | UNIT_STATE_FLEEING_MOVE | UNIT_STATE_CHASE_MOVE | UNIT_STATE_FOLLOW_MOVE, UNIT_STATE_CONTROLLED = UNIT_STATE_CONFUSED | UNIT_STATE_STUNNED | UNIT_STATE_FLEEING, + UNIT_STATE_CANT_CLIENT_CONTROL = UNIT_STATE_CONFUSED | UNIT_STATE_CHARMED | UNIT_STATE_POSSESSED | UNIT_STATE_FLEEING | UNIT_STATE_POSSESSED, UNIT_STATE_LOST_CONTROL = UNIT_STATE_CONTROLLED | UNIT_STATE_JUMPING | UNIT_STATE_CHARGING, + UNIT_STATE_CANNOT_AUTOATTACK = UNIT_STATE_CONTROLLED | UNIT_STATE_CHARGING | UNIT_STATE_CASTING, UNIT_STATE_SIGHTLESS = UNIT_STATE_LOST_CONTROL | UNIT_STATE_EVADE, - UNIT_STATE_CANNOT_AUTOATTACK = UNIT_STATE_LOST_CONTROL | UNIT_STATE_CASTING, - UNIT_STATE_CANNOT_TURN = UNIT_STATE_LOST_CONTROL | UNIT_STATE_ROTATING, + UNIT_STATE_CANNOT_TURN = UNIT_STATE_LOST_CONTROL | UNIT_STATE_ROTATING | UNIT_STATE_FOCUSING, UNIT_STATE_NOT_MOVE = UNIT_STATE_ROOT | UNIT_STATE_STUNNED | UNIT_STATE_DIED | UNIT_STATE_DISTRACTED, UNIT_STATE_ALL_ERASABLE = UNIT_STATE_ALL_STATE_SUPPORTED & ~(UNIT_STATE_IGNORE_PATHFINDING), @@ -1785,6 +1786,7 @@ class TC_GAME_API Unit : public WorldObject float GetPositionZMinusOffset() const; void SetControlled(bool apply, UnitState state); + void ApplyControlStatesIfNeeded(); void AddComboPointHolder(ObjectGuid lowguid) { m_ComboPointHolders.insert(lowguid); } void RemoveComboPointHolder(ObjectGuid lowguid) { m_ComboPointHolders.erase(lowguid); } diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index ab51ba00c98..499229175b0 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -3107,7 +3107,7 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect const* triggered // focus if not controlled creature if (m_caster->GetTypeId() == TYPEID_UNIT && !m_caster->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED)) { - if (!(m_spellInfo->IsNextMeleeSwingSpell() || IsAutoRepeat() || (_triggeredCastFlags & TRIGGERED_IGNORE_SET_FACING))) + if (!(m_spellInfo->IsNextMeleeSwingSpell() || IsAutoRepeat())) { if (m_targets.GetObjectTarget() && m_caster != m_targets.GetObjectTarget()) m_caster->ToCreature()->FocusTarget(this, m_targets.GetObjectTarget()); @@ -7079,6 +7079,11 @@ bool Spell::IsIgnoringCooldowns() const return (_triggeredCastFlags & TRIGGERED_IGNORE_SPELL_AND_CATEGORY_CD) != 0; } +bool Spell::IsFocusDisabled() const +{ + return ((_triggeredCastFlags & TRIGGERED_IGNORE_SET_FACING) || (m_spellInfo->IsChanneled() && !m_spellInfo->HasAttribute(SPELL_ATTR1_CHANNEL_TRACK_TARGET))); +} + bool Spell::IsProcDisabled() const { return (_triggeredCastFlags & TRIGGERED_DISALLOW_PROC_EVENTS) != 0; diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index f59eee71fb3..971b0be0bc8 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -514,6 +514,7 @@ class TC_GAME_API Spell void ReSetTimer() { m_timer = m_casttime > 0 ? m_casttime : 0; } bool IsTriggered() const; bool IsIgnoringCooldowns() const; + bool IsFocusDisabled() const; bool IsProcDisabled() const; bool IsChannelActive() const; bool IsAutoActionResetSpell() const; diff --git a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp index ede7e912b44..acc2e216d96 100644 --- a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp +++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp @@ -927,13 +927,6 @@ class npc_orb_carrier : public CreatureScript me->CastSpell((Unit*)nullptr, SPELL_TRACK_ROTATION, false); scheduler.Update(diff); - - /// Workaround: This is here because even though the above spell has SPELL_ATTR1_CHANNEL_TRACK_TARGET, - /// we are having two creatures involded here. This attribute is handled clientside, meaning the client - /// sends orientation update itself. Here, no packet is sent, and the creature does not rotate. By - /// forcing the carrier to always be facing the rotation focus, we ensure everything works as it should. - if (Creature* rotationFocus = _instance->GetCreature(DATA_ORB_ROTATION_FOCUS)) - me->SetFacingToObject(rotationFocus); // setInFront } void DoAction(int32 action) override