diff options
66 files changed, 305 insertions, 400 deletions
diff --git a/src/server/game/AI/CoreAI/CombatAI.cpp b/src/server/game/AI/CoreAI/CombatAI.cpp index 680b5ebb7c3..60ed90b8507 100644 --- a/src/server/game/AI/CoreAI/CombatAI.cpp +++ b/src/server/game/AI/CoreAI/CombatAI.cpp @@ -288,13 +288,14 @@ void VehicleAI::UpdateAI(uint32 diff)      }  } -void VehicleAI::OnCharmed(bool apply) +void VehicleAI::OnCharmed(bool /*isNew*/)  { -    if (!me->GetVehicleKit()->IsVehicleInUse() && !apply && m_HasConditions) // was used and has conditions +    bool const charmed = me->IsCharmed(); +    if (!me->GetVehicleKit()->IsVehicleInUse() && !charmed && m_HasConditions) // was used and has conditions      {          m_DoDismiss = true; // needs reset      } -    else if (apply) +    else if (charmed)          m_DoDismiss = false; // in use again      m_DismissTimer = VEHICLE_DISMISS_TIME; // reset timer diff --git a/src/server/game/AI/CoreAI/CombatAI.h b/src/server/game/AI/CoreAI/CombatAI.h index a27c8fc64ef..7c4525d1b0d 100644 --- a/src/server/game/AI/CoreAI/CombatAI.h +++ b/src/server/game/AI/CoreAI/CombatAI.h @@ -103,7 +103,7 @@ struct TC_GAME_API VehicleAI : public CreatureAI          void UpdateAI(uint32 diff) override;          void MoveInLineOfSight(Unit*) override { }          void AttackStart(Unit*) override { } -        void OnCharmed(bool apply) override; +        void OnCharmed(bool isNew) override;          static int32 Permissible(Creature const* creature); diff --git a/src/server/game/AI/CoreAI/PassiveAI.cpp b/src/server/game/AI/CoreAI/PassiveAI.cpp index f0c8958a14c..52b04cc90a0 100644 --- a/src/server/game/AI/CoreAI/PassiveAI.cpp +++ b/src/server/game/AI/CoreAI/PassiveAI.cpp @@ -69,12 +69,6 @@ void PossessedAI::KilledUnit(Unit* victim)          victim->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);  } -void PossessedAI::OnCharmed(bool /*apply*/) -{ -    me->NeedChangeAI = true; -    me->IsAIEnabled = false; -} -  void CritterAI::DamageTaken(Unit* /*done_by*/, uint32&)  {      if (!me->HasUnitState(UNIT_STATE_FLEEING)) diff --git a/src/server/game/AI/CoreAI/PassiveAI.h b/src/server/game/AI/CoreAI/PassiveAI.h index 93b2577e9f3..ce4efe52372 100644 --- a/src/server/game/AI/CoreAI/PassiveAI.h +++ b/src/server/game/AI/CoreAI/PassiveAI.h @@ -46,8 +46,6 @@ class TC_GAME_API PossessedAI : public CreatureAI          void JustDied(Unit*) override;          void KilledUnit(Unit* victim) override; -        void OnCharmed(bool /*apply*/) override; -          static int32 Permissible(Creature const* /*creature*/) { return PERMIT_BASE_NO; }  }; @@ -60,7 +58,7 @@ class TC_GAME_API NullCreatureAI : public CreatureAI          void AttackStart(Unit*) override { }          void UpdateAI(uint32) override { }          void EnterEvadeMode(EvadeReason /*why*/) override { } -        void OnCharmed(bool /*apply*/) override { } +        void OnCharmed(bool /*isNew*/) override { }          static int32 Permissible(Creature const* creature);  }; diff --git a/src/server/game/AI/CoreAI/PetAI.cpp b/src/server/game/AI/CoreAI/PetAI.cpp index a16ffc6721d..20a93451c93 100644 --- a/src/server/game/AI/CoreAI/PetAI.cpp +++ b/src/server/game/AI/CoreAI/PetAI.cpp @@ -610,12 +610,6 @@ void PetAI::ReceiveEmote(Player* player, uint32 emote)          }  } -void PetAI::OnCharmed(bool /*apply*/) -{ -    me->NeedChangeAI = true; -    me->IsAIEnabled = false; -} -  void PetAI::ClearCharmInfoFlags()  {      // Quick access to set all flags to FALSE diff --git a/src/server/game/AI/CoreAI/PetAI.h b/src/server/game/AI/CoreAI/PetAI.h index d8b4002293a..d41a1080f6d 100644 --- a/src/server/game/AI/CoreAI/PetAI.h +++ b/src/server/game/AI/CoreAI/PetAI.h @@ -52,8 +52,6 @@ class TC_GAME_API PetAI : public CreatureAI          void MoveInLineOfSight_Safe(Unit* /*who*/) { } // CreatureAI interferes with returning pets          void EnterEvadeMode(EvadeReason /*why*/) override { } // For fleeing, pets don't use this type of Evade mechanic -        void OnCharmed(bool /*apply*/) override; -      private:          bool _needToStop(void);          void _stopAttack(void); diff --git a/src/server/game/AI/CoreAI/UnitAI.cpp b/src/server/game/AI/CoreAI/UnitAI.cpp index 0d8700fb091..01c7dd6997f 100644 --- a/src/server/game/AI/CoreAI/UnitAI.cpp +++ b/src/server/game/AI/CoreAI/UnitAI.cpp @@ -47,6 +47,12 @@ void UnitAI::InitializeAI()          Reset();  } +void UnitAI::OnCharmed(bool isNew) +{ +    if (!isNew) +        me->ScheduleAIChange(); +} +  void UnitAI::AttackStartCaster(Unit* victim, float dist)  {      if (victim && me->Attack(victim, false)) diff --git a/src/server/game/AI/CoreAI/UnitAI.h b/src/server/game/AI/CoreAI/UnitAI.h index 5b2071b9d8d..a15a15fe199 100644 --- a/src/server/game/AI/CoreAI/UnitAI.h +++ b/src/server/game/AI/CoreAI/UnitAI.h @@ -143,8 +143,11 @@ class TC_GAME_API UnitAI          virtual void Reset() { } -        // Called when unit is charmed -        virtual void OnCharmed(bool apply) = 0; +        // Called when unit's charm state changes with isNew = false +        // Implementation should call me->ScheduleAIChange() if AI replacement is desired +        // If this call is made, AI will be replaced on the next tick +        // When replacement is made, OnCharmed is called with isNew = true +        virtual void OnCharmed(bool isNew);          // Pass parameters between AI          virtual void DoAction(int32 /*param*/) { } diff --git a/src/server/game/AI/CreatureAI.cpp b/src/server/game/AI/CreatureAI.cpp index 7b6615f36f1..d322a7d9597 100644 --- a/src/server/game/AI/CreatureAI.cpp +++ b/src/server/game/AI/CreatureAI.cpp @@ -33,12 +33,14 @@  #include "World.h"  //Disable CreatureAI when charmed -void CreatureAI::OnCharmed(bool apply) +void CreatureAI::OnCharmed(bool isNew)  { -    if (apply) +    if (isNew && !me->IsCharmed() && me->LastCharmerGUID)      { -        me->NeedChangeAI = true; -        me->IsAIEnabled = false; +        if (!me->HasReactState(REACT_PASSIVE)) +            if (Unit* lastCharmer = ObjectAccessor::GetUnit(*me, me->LastCharmerGUID)) +                me->EngageWithTarget(lastCharmer); +            me->LastCharmerGUID.Clear();      }  } diff --git a/src/server/game/AI/CreatureAI.h b/src/server/game/AI/CreatureAI.h index f189462bd8b..c4b67765a63 100644 --- a/src/server/game/AI/CreatureAI.h +++ b/src/server/game/AI/CreatureAI.h @@ -139,7 +139,7 @@ class TC_GAME_API CreatureAI : public UnitAI          // Called at waypoint reached or point movement finished          virtual void MovementInform(uint32 /*type*/, uint32 /*id*/) { } -        void OnCharmed(bool apply) override; +        void OnCharmed(bool isNew) override;          // Called at reaching home after evade          virtual void JustReachedHome() { } diff --git a/src/server/game/AI/PlayerAI/PlayerAI.cpp b/src/server/game/AI/PlayerAI/PlayerAI.cpp index 98cfbd287f7..a17e465c131 100644 --- a/src/server/game/AI/PlayerAI/PlayerAI.cpp +++ b/src/server/game/AI/PlayerAI/PlayerAI.cpp @@ -806,7 +806,11 @@ bool SimpleCharmedPlayerAI::CanAIAttack(Unit const* who) const  Unit* SimpleCharmedPlayerAI::SelectAttackTarget() const  {      if (Unit* charmer = me->GetCharmer()) -        return charmer->IsAIEnabled ? charmer->GetAI()->SelectTarget(SELECT_TARGET_RANDOM, 0, ValidTargetSelectPredicate(this)) : charmer->GetVictim(); +    { +        if (UnitAI* charmerAI = charmer->GetAI()) +            return charmerAI->SelectTarget(SELECT_TARGET_RANDOM, 0, ValidTargetSelectPredicate(this)); +        return charmer->GetVictim(); +    }      return nullptr;  } @@ -1321,6 +1325,7 @@ PlayerAI::TargetedSpell SimpleCharmedPlayerAI::SelectAppropriateCastForSpec()  static const float CASTER_CHASE_DISTANCE = 28.0f;  void SimpleCharmedPlayerAI::UpdateAI(const uint32 diff)  { +    printf("SCPAI updateai %u\n", diff);      Creature* charmer = GetCharmer();      if (!charmer)          return; @@ -1422,9 +1427,10 @@ void SimpleCharmedPlayerAI::UpdateAI(const uint32 diff)      }  } -void SimpleCharmedPlayerAI::OnCharmed(bool apply) +void SimpleCharmedPlayerAI::OnCharmed(bool isNew)  { -    if (apply) +    printf("SCPAI oncharm %u\n", isNew); +    if (me->IsCharmed())      {          me->CastStop();          me->AttackStop(); @@ -1440,4 +1446,5 @@ void SimpleCharmedPlayerAI::OnCharmed(bool apply)          me->GetMotionMaster()->Clear();          me->StopMoving();      } +    PlayerAI::OnCharmed(isNew);  } diff --git a/src/server/game/AI/PlayerAI/PlayerAI.h b/src/server/game/AI/PlayerAI/PlayerAI.h index 348e89ba52c..ed77e46c1eb 100644 --- a/src/server/game/AI/PlayerAI/PlayerAI.h +++ b/src/server/game/AI/PlayerAI/PlayerAI.h @@ -29,8 +29,6 @@ class TC_GAME_API PlayerAI : public UnitAI      public:          explicit PlayerAI(Player* player); -        void OnCharmed(bool /*apply*/) override { } // charm AI application for players is handled by Unit::SetCharmedBy / Unit::RemoveCharmedBy -          Creature* GetCharmer() const;          // helper functions to determine player info @@ -101,7 +99,7 @@ class TC_GAME_API SimpleCharmedPlayerAI : public PlayerAI      public:          SimpleCharmedPlayerAI(Player* player) : PlayerAI(player), _castCheckTimer(2500), _chaseCloser(false), _forceFacing(true), _isFollowing(false) { }          void UpdateAI(uint32 diff) override; -        void OnCharmed(bool apply) override; +        void OnCharmed(bool isNew) override;      protected:          bool CanAIAttack(Unit const* who) const override; diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp index f58cd12829f..d57dc6c4c24 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp +++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp @@ -54,7 +54,7 @@ void SummonList::DoZoneInCombat(uint32 entry)      {          Creature* summon = ObjectAccessor::GetCreature(*me, *i);          ++i; -        if (summon && summon->IsAIEnabled +        if (summon && summon->IsAIEnabled()                  && (!entry || summon->GetEntry() == entry))          {              summon->AI()->DoZoneInCombat(nullptr); @@ -118,7 +118,7 @@ void SummonList::DoActionImpl(int32 action, StorageType const& summons)      for (auto const& guid : summons)      {          Creature* summon = ObjectAccessor::GetCreature(*me, guid); -        if (summon && summon->IsAIEnabled) +        if (summon && summon->IsAIEnabled())              summon->AI()->DoAction(action);      }  } diff --git a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp index c82ad99911a..56675f48218 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp +++ b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp @@ -154,13 +154,6 @@ void EscortAI::MovementInform(uint32 type, uint32 id)      }  } -///@todo investigate whether if its necessary to handle anything on charm -/* -void EscortAI::OnCharmed(bool apply) -{ -} -*/ -  void EscortAI::UpdateAI(uint32 diff)  {      // Waypoint Updating diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp index 56bad41e3a4..058652563c3 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.cpp +++ b/src/server/game/AI/SmartScripts/SmartAI.cpp @@ -661,17 +661,18 @@ void SmartAI::PassengerBoarded(Unit* who, int8 seatId, bool apply)      GetScript()->ProcessEventsFor(apply ? SMART_EVENT_PASSENGER_BOARDED : SMART_EVENT_PASSENGER_REMOVED, who, uint32(seatId), 0, apply);  } -void SmartAI::OnCharmed(bool apply) +void SmartAI::OnCharmed(bool /*isNew*/)  { -    if (apply) // do this before we change charmed state, as charmed state might prevent these things from processing +    bool const charmed = me->IsCharmed(); +    if (charmed) // do this before we change charmed state, as charmed state might prevent these things from processing      {          if (HasEscortState(SMART_ESCORT_ESCORTING | SMART_ESCORT_PAUSED | SMART_ESCORT_RETURNING))              EndPath(true);      } -    mIsCharmed = apply; +    mIsCharmed = charmed; -    if (!apply && !me->IsInEvadeMode()) +    if (!charmed && !me->IsInEvadeMode())      {          if (_repeatWaypointPath)              StartPath(mRun, GetScript()->GetPathId(), true); @@ -682,7 +683,7 @@ void SmartAI::OnCharmed(bool apply)              AttackStart(charmer);      } -    GetScript()->ProcessEventsFor(SMART_EVENT_CHARMED, nullptr, 0, 0, apply); +    GetScript()->ProcessEventsFor(SMART_EVENT_CHARMED, nullptr, 0, 0, charmed);  }  void SmartAI::DoAction(int32 param) diff --git a/src/server/game/AI/SmartScripts/SmartAI.h b/src/server/game/AI/SmartScripts/SmartAI.h index 2164509ac52..b96682564fe 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.h +++ b/src/server/game/AI/SmartScripts/SmartAI.h @@ -140,7 +140,7 @@ class TC_GAME_API SmartAI : public CreatureAI          void InitializeAI() override;          // Called when creature gets charmed by another unit -        void OnCharmed(bool apply) override; +        void OnCharmed(bool isNew) override;          // Used in scripts to share variables          void DoAction(int32 param = 0) override; diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index cc5aeb2dcd5..7d5bbac162c 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -1037,7 +1037,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u          }          case SMART_ACTION_SET_IN_COMBAT_WITH_ZONE:          { -            if (me && me->IsAIEnabled) +            if (me && me->IsAIEnabled())              {                  me->AI()->DoZoneInCombat();                  TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_SET_IN_COMBAT_WITH_ZONE: Creature %u", me->GetGUID().GetCounter()); diff --git a/src/server/game/Combat/CombatManager.cpp b/src/server/game/Combat/CombatManager.cpp index 2e90d37bcb7..0024195bbed 100644 --- a/src/server/game/Combat/CombatManager.cpp +++ b/src/server/game/Combat/CombatManager.cpp @@ -71,10 +71,12 @@ void CombatReference::EndCombat()      bool const needSecondAI = second->GetCombatManager().UpdateOwnerCombatState();      // ...and if that happened, also notify the AI of it... -    if (needFirstAI && first->IsAIEnabled) -        first->GetAI()->JustExitedCombat(); -    if (needSecondAI && second->IsAIEnabled) -        second->GetAI()->JustExitedCombat(); +    if (needFirstAI) +        if (UnitAI* firstAI = first->GetAI()) +            firstAI->JustExitedCombat(); +    if (needSecondAI) +        if (UnitAI* secondAI = second->GetAI()) +            secondAI->JustExitedCombat();      // ...and finally clean up the reference object      delete this; @@ -114,8 +116,8 @@ void PvPCombatReference::SuppressFor(Unit* who)  {      Suppress(who);      if (who->GetCombatManager().UpdateOwnerCombatState()) -        if (who->IsAIEnabled) -            who->GetAI()->JustExitedCombat(); +        if (UnitAI* ai = who->GetAI()) +            ai->JustExitedCombat();  }  CombatManager::~CombatManager() @@ -271,8 +273,8 @@ void CombatManager::SuppressPvPCombat()      for (auto const& pair : _pvpRefs)          pair.second->Suppress(_owner);      if (UpdateOwnerCombatState()) -        if (_owner->IsAIEnabled) -            _owner->GetAI()->JustExitedCombat(); +        if (UnitAI* ownerAI = _owner->GetAI()) +            ownerAI->JustExitedCombat();  }  void CombatManager::EndAllPvECombat() @@ -292,7 +294,7 @@ void CombatManager::EndAllPvPCombat()  /*static*/ void CombatManager::NotifyAICombat(Unit* me, Unit* other)  { -    if (!me->IsAIEnabled) +    if (!me->IsAIEnabled())          return;      me->GetAI()->JustEnteredCombat(other); diff --git a/src/server/game/Combat/ThreatManager.cpp b/src/server/game/Combat/ThreatManager.cpp index 0a28183b3fd..50e195088c1 100644 --- a/src/server/game/Combat/ThreatManager.cpp +++ b/src/server/game/Combat/ThreatManager.cpp @@ -96,7 +96,7 @@ ThreatReference::OnlineState ThreatReference::SelectOnlineState()          return ONLINE_STATE_OFFLINE;      if (!FlagsAllowFighting(_owner, _victim) || !FlagsAllowFighting(_victim, _owner))          return ONLINE_STATE_OFFLINE; -    if (_owner->IsAIEnabled && !_owner->GetAI()->CanAIAttack(_victim)) +    if (_owner->IsAIEnabled() && !_owner->GetAI()->CanAIAttack(_victim))          return ONLINE_STATE_OFFLINE;      // next, check suppression (immunity to chosen melee attack school)      if (_victim->IsImmunedToDamage(_owner->GetMeleeDamageSchoolMask())) @@ -280,7 +280,7 @@ void ThreatManager::UpdateOnlineStates(bool meThreateningOthers, bool othersThre  static void SaveCreatureHomePositionIfNeed(Creature* c)  {      MovementGeneratorType const movetype = c->GetMotionMaster()->GetCurrentMovementGeneratorType(); -    if (movetype == WAYPOINT_MOTION_TYPE || movetype == POINT_MOTION_TYPE || (c->IsAIEnabled && c->AI()->IsEscorted())) +    if (movetype == WAYPOINT_MOTION_TYPE || movetype == POINT_MOTION_TYPE || (c->IsAIEnabled() && c->AI()->IsEscorted()))          c->SetHomePosition(c->GetPosition());  } @@ -374,8 +374,8 @@ void ThreatManager::AddThreat(Unit* target, float amount, SpellInfo const* spell          Creature* cOwner = _owner->ToCreature();          ASSERT(cOwner); // if we got here the owner can have a threat list, and must be a creature!          SaveCreatureHomePositionIfNeed(cOwner); -        if (cOwner->IsAIEnabled) -            cOwner->AI()->JustEngagedWith(target); +        if (CreatureAI* ownerAI = cOwner->AI()) +            ownerAI->JustEngagedWith(target);      }  } diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 0951a75ead1..6df264d909f 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -272,15 +272,6 @@ Creature::Creature(bool isWorldObject): Unit(isWorldObject), MapObject(), m_grou      m_isTempWorldObject = false;  } -Creature::~Creature() -{ -    delete i_AI; -    i_AI = nullptr; - -    //if (m_uint32Values) -    //    TC_LOG_ERROR("entities.unit", "Deconstruct Creature Entry = %u", GetEntry()); -} -  void Creature::AddToWorld()  {      ///- Register the creature for guid lookup @@ -388,8 +379,8 @@ void Creature::RemoveCorpse(bool setSpawnTime, bool destroyForNearbyPlayers)          RemoveAllAuras();          loot.clear();          uint32 respawnDelay = m_respawnDelay; -        if (IsAIEnabled) -            AI()->CorpseRemoved(respawnDelay); +        if (CreatureAI* ai = AI()) +            ai->CorpseRemoved(respawnDelay);          if (destroyForNearbyPlayers)              DestroyForNearbyPlayers(); @@ -637,7 +628,7 @@ bool Creature::UpdateEntry(uint32 entry, CreatureData const* data /*= nullptr*/,  void Creature::Update(uint32 diff)  { -    if (IsAIEnabled && m_triggerJustAppeared && m_deathState != DEAD) +    if (IsAIEnabled() && m_triggerJustAppeared && m_deathState != DEAD)      {          if (m_respawnCompatibilityMode && m_vehicleKit)              m_vehicleKit->Reset(); @@ -755,21 +746,8 @@ void Creature::Update(uint32 diff)                  m_shouldReacquireTarget = false;              } -            // if creature is charmed, switch to charmed AI (and back) -            if (NeedChangeAI) -            { -                UpdateCharmAI(); -                NeedChangeAI = false; -                IsAIEnabled = true; -                if (!IsInEvadeMode() && LastCharmerGUID) -                    if (Unit* charmer = ObjectAccessor::GetUnit(*this, LastCharmerGUID)) -                        EngageWithTarget(charmer); - -                LastCharmerGUID.Clear(); -            } -              // periodic check to see if the creature has passed an evade boundary -            if (IsAIEnabled && !IsInEvadeMode() && IsEngaged()) +            if (IsAIEnabled() && !IsInEvadeMode() && IsEngaged())              {                  if (diff >= m_boundaryCheckTime)                  { @@ -808,14 +786,11 @@ void Creature::Update(uint32 diff)                  }              } -            if (!IsInEvadeMode() && IsAIEnabled) -            { -                // do not allow the AI to be changed during update -                m_AI_locked = true; -                i_AI->UpdateAI(diff); -                m_AI_locked = false; -            } +            // do not allow the AI to be changed during update +            m_AI_locked = true; +            Unit::AIUpdateTick(diff); +            m_AI_locked = false;              // creature can be dead after UpdateAI call              // CORPSE/DEAD state will processed at next tick (in other case death timer will be updated unexpectedly) @@ -851,8 +826,8 @@ void Creature::Update(uint32 diff)              {                  m_cannotReachTimer += diff;                  if (m_cannotReachTimer >= CREATURE_NOPATH_EVADE_TIME) -                    if (IsAIEnabled) -                        AI()->EnterEvadeMode(CreatureAI::EVADE_REASON_NO_PATH); +                    if (CreatureAI* ai = AI()) +                        ai->EnterEvadeMode(CreatureAI::EVADE_REASON_NO_PATH);              }              break;          } @@ -988,13 +963,7 @@ bool Creature::AIM_Destroy()          return false;      } -    ASSERT(!i_disabledAI, -           "The disabled AI wasn't cleared!"); - -    delete i_AI; -    i_AI = nullptr; - -    IsAIEnabled = false; +    SetAI(nullptr);      return true;  } @@ -1007,29 +976,24 @@ bool Creature::AIM_Create(CreatureAI* ai /*= nullptr*/)          return false;      } -    AIM_Destroy(); +    if (!ai) +        ai = FactorySelector::SelectAI(this); + +    SetAI(ai);      Motion_Initialize(); -    i_AI = ai ? ai : FactorySelector::SelectAI(this);      return true;  } -void Creature::AI_InitializeAndEnable() -{ -    IsAIEnabled = true; -    i_AI->InitializeAI(); -    // Initialize vehicle -    if (GetVehicleKit()) -        GetVehicleKit()->Reset(); -} -  bool Creature::AIM_Initialize(CreatureAI* ai)  {      if (!AIM_Create(ai))          return false; -    AI_InitializeAndEnable(); +    AI()->InitializeAI(); +    if (GetVehicleKit()) +        GetVehicleKit()->Reset();      return true;  } @@ -1831,7 +1795,7 @@ bool Creature::IsInvisibleDueToDespawn() const  bool Creature::CanAlwaysSee(WorldObject const* obj) const  { -    if (IsAIEnabled && AI()->CanSeeAlways(obj)) +    if (IsAIEnabled() && AI()->CanSeeAlways(obj))          return true;      return false; @@ -2079,8 +2043,8 @@ void Creature::Respawn(bool force)              // Re-initialize reactstate that could be altered by movementgenerators              InitializeReactState(); -            if (IsAIEnabled) // reset the AI to be sure no dirty or uninitialized values will be used till next tick -                AI()->Reset(); +            if (UnitAI* ai = AI()) // reset the AI to be sure no dirty or uninitialized values will be used till next tick +                ai->Reset();              m_triggerJustAppeared = true; @@ -2445,7 +2409,7 @@ bool Creature::CanCreatureAttack(Unit const* victim, bool /*force*/) const      if (!victim->isInAccessiblePlaceFor(this))          return false; -    if (IsAIEnabled && !AI()->CanAIAttack(victim)) +    if (IsAIEnabled() && !AI()->CanAIAttack(victim))          return false;      // we cannot attack in evade mode @@ -3275,8 +3239,7 @@ void Creature::AtExitCombat()  bool Creature::IsEscortNPC(bool onlyIfActive)  { -    if (!IsAIEnabled) -        return false; - -    return AI()->IsEscortNPC(onlyIfActive); +    if (CreatureAI* ai = AI()) +        return ai->IsEscortNPC(onlyIfActive); +    return false;  } diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index 23e567f7332..f6424e2ec11 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -62,7 +62,6 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma  {      public:          explicit Creature(bool isWorldObject = false); -        virtual ~Creature();          void AddToWorld() override;          void RemoveFromWorld() override; @@ -134,11 +133,10 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma          bool AIM_Destroy();          bool AIM_Create(CreatureAI* ai = nullptr); -        void AI_InitializeAndEnable();          bool AIM_Initialize(CreatureAI* ai = nullptr);          void Motion_Initialize(); -        CreatureAI* AI() const { return reinterpret_cast<CreatureAI*>(i_AI); } +        CreatureAI* AI() const { return reinterpret_cast<CreatureAI*>(GetAI()); }          bool SetWalk(bool enable) override;          bool SetDisableGravity(bool disable, bool packetOnly = false) override; diff --git a/src/server/game/Entities/Creature/TemporarySummon.cpp b/src/server/game/Entities/Creature/TemporarySummon.cpp index 6bb6d864006..0f92d0e29aa 100644 --- a/src/server/game/Entities/Creature/TemporarySummon.cpp +++ b/src/server/game/Entities/Creature/TemporarySummon.cpp @@ -206,9 +206,9 @@ void TempSummon::InitSummon()      Unit* owner = GetSummoner();      if (owner)      { -        if (owner->GetTypeId() == TYPEID_UNIT && owner->ToCreature()->IsAIEnabled) +        if (owner->GetTypeId() == TYPEID_UNIT && owner->ToCreature()->IsAIEnabled())              owner->ToCreature()->AI()->JustSummoned(this); -        if (IsAIEnabled) +        if (IsAIEnabled())              AI()->IsSummonedBy(owner);      }  } @@ -242,7 +242,7 @@ void TempSummon::UnSummon(uint32 msTime)      }      Unit* owner = GetSummoner(); -    if (owner && owner->GetTypeId() == TYPEID_UNIT && owner->ToCreature()->IsAIEnabled) +    if (owner && owner->GetTypeId() == TYPEID_UNIT && owner->ToCreature()->IsAIEnabled())          owner->ToCreature()->AI()->SummonedCreatureDespawn(this);      AddObjectToRemoveList(); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 8902b8575ea..14492cb203b 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -1058,14 +1058,7 @@ void Player::Update(uint32 p_time)      UpdateAfkReport(now); -    if (IsAIEnabled && GetAI()) -        GetAI()->UpdateAI(p_time); -    else if (NeedChangeAI) -    { -        UpdateCharmAI(); -        NeedChangeAI = false; -        IsAIEnabled = (GetAI() != nullptr); -    } +    AIUpdateTick(p_time);      // Update items that have just a limited lifetime      if (now > m_Last_tick) diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 0bb4b515ac0..c6b8511c7ee 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -886,7 +886,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>          explicit Player(WorldSession* session);          ~Player(); -        PlayerAI* AI() const { return reinterpret_cast<PlayerAI*>(i_AI); } +        PlayerAI* AI() const { return reinterpret_cast<PlayerAI*>(GetAI()); }          void CleanupsBeforeDelete(bool finalCleanup = true) override; diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 09f5ef01a5e..dc948fa498d 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -289,12 +289,11 @@ bool DispelableAura::RollDispel() const  Unit::Unit(bool isWorldObject) :      WorldObject(isWorldObject), m_playerMovingMe(nullptr), m_lastSanctuaryTime(0), -    IsAIEnabled(false), NeedChangeAI(false), LastCharmerGUID(), m_ControlledByPlayer(false), -    movespline(new Movement::MoveSpline()), i_AI(nullptr), i_disabledAI(nullptr), -    m_AutoRepeatFirstCast(false), m_procDeep(0), m_removedAurasCount(0), -    i_motionMaster(new MotionMaster(this)), m_regenTimer(0), m_vehicle(nullptr), -    m_vehicleKit(nullptr), m_unitTypeMask(UNIT_MASK_NONE), m_Diminishing(), m_combatManager(this), -    m_threatManager(this), m_comboTarget(nullptr), m_comboPoints(0), m_spellHistory(new SpellHistory(this)) +    LastCharmerGUID(), m_ControlledByPlayer(false), +    movespline(new Movement::MoveSpline()), m_AutoRepeatFirstCast(false), m_procDeep(0), m_removedAurasCount(0), +    i_motionMaster(new MotionMaster(this)), m_regenTimer(0), m_vehicle(nullptr), m_vehicleKit(nullptr), +    m_unitTypeMask(UNIT_MASK_NONE), m_Diminishing(), m_combatManager(this), m_threatManager(this), +    m_comboTarget(nullptr), m_comboPoints(0), m_spellHistory(new SpellHistory(this))  {      m_objectType |= TYPEMASK_UNIT;      m_objectTypeId = TYPEID_UNIT; @@ -453,6 +452,9 @@ void Unit::Update(uint32 p_time)      UpdateSplineMovement(p_time);      i_motionMaster->Update(p_time); + +    if (!i_AI && (GetTypeId() != TYPEID_PLAYER || IsCharmed())) +        UpdateCharmAI();  }  bool Unit::haveOffhandWeapon() const @@ -640,11 +642,11 @@ bool Unit::HasBreakableByDamageCrowdControlAura(Unit* excludeCasterChannel) cons  {      uint32 rage_damage = damage + (cleanDamage ? cleanDamage->absorbed_damage : 0); -    if (victim->IsAIEnabled) -        victim->GetAI()->DamageTaken(attacker, damage); +    if (UnitAI* victimAI = victim->GetAI()) +        victimAI->DamageTaken(attacker, damage); -    if (attacker && attacker->IsAIEnabled) -        attacker->GetAI()->DamageDealt(victim, damage, damagetype); +    if (UnitAI* attackerAI = attacker ? attacker->GetAI() : nullptr) +        attackerAI->DamageDealt(victim, damage, damagetype);      // Hook for OnDamage Event      sScriptMgr->OnDamage(attacker, victim, damage); @@ -656,8 +658,8 @@ bool Unit::HasBreakableByDamageCrowdControlAura(Unit* excludeCasterChannel) cons          {              for (Unit* controlled : victim->m_Controlled)                  if (Creature* cControlled = controlled->ToCreature()) -                    if (cControlled->IsAIEnabled) -                        cControlled->AI()->OwnerAttackedBy(attacker); +                    if (CreatureAI* controlledAI = cControlled->AI()) +                        controlledAI->OwnerAttackedBy(attacker);          }          if (victim->ToPlayer()->GetCommandStatus(CHEAT_GOD)) @@ -5544,8 +5546,8 @@ bool Unit::Attack(Unit* victim, bool meleeAttack)      {          for (Unit* controlled : m_Controlled)              if (Creature* cControlled = controlled->ToCreature()) -                if (cControlled->IsAIEnabled) -                    cControlled->AI()->OwnerAttacked(victim); +                if (CreatureAI* controlledAI = cControlled->AI()) +                    controlledAI->OwnerAttacked(victim);      }      return true; @@ -6093,14 +6095,11 @@ void Unit::SetCharm(Unit* charm, bool apply)      Unit* victim = healInfo.GetTarget();      uint32 addhealth = healInfo.GetHeal(); -    if (healer) -    { -        if (victim->IsAIEnabled) -            victim->GetAI()->HealReceived(healer, addhealth); +    if (UnitAI* victimAI = victim->GetAI()) +        victimAI->HealReceived(healer, addhealth); -        if (healer->IsAIEnabled) -            healer->GetAI()->HealDone(victim, addhealth); -    } +    if (UnitAI* healerAI = healer ? healer->GetAI() : nullptr) +        healerAI->HealDone(victim, addhealth);      if (addhealth)          gain = victim->ModifyHealth(int32(addhealth)); @@ -9408,12 +9407,49 @@ uint32 Unit::GetCreatePowers(Powers power) const      return 0;  } +void Unit::AIUpdateTick(uint32 diff, bool /*force*/) +{ +    if (!diff) // some places call with diff = 0, which does nothing (for now), see PR #22296 +        return; +    if (UnitAI* ai = GetAI()) +        ai->UpdateAI(diff); +} + +void Unit::SetAI(UnitAI* newAI) +{ +    if (i_AI) +        AIUpdateTick(0, true); // old AI gets a final tick if enabled +    i_AI.reset(newAI); +    AIUpdateTick(0, true); // new AI gets its initial tick +} + +void Unit::ScheduleAIChange() +{ +    printf("ScheduleAIChange %s\n", GetName().c_str()); +    bool const charmed = IsCharmed(); +    // if charm is applied, we can't have disabled AI already, and vice versa +    if (charmed) +        ASSERT(!i_disabledAI, "Attempt to schedule charm AI change on unit that already has disabled AI"); +    else if (GetTypeId() != TYPEID_PLAYER) +        ASSERT(i_disabledAI, "Attempt to schedule charm ID change on unit that doesn't have disabled AI"); + +    if (charmed) +        i_disabledAI = std::move(i_AI); +    else +        i_AI.reset(); +} + +void Unit::RestoreDisabledAI() +{ +    ASSERT((GetTypeId() == TYPEID_PLAYER) || i_disabledAI, "Attempt to restore disabled AI on creature without disabled AI"); +    i_AI = std::move(i_disabledAI); +    AIUpdateTick(0, true); +} +  void Unit::AddToWorld()  {      if (!IsInWorld()) -    {          WorldObject::AddToWorld(); -    }  }  void Unit::RemoveFromWorld() @@ -9424,8 +9460,8 @@ void Unit::RemoveFromWorld()      if (IsInWorld())      {          m_duringRemoveFromWorld = true; -        if (IsAIEnabled) -            GetAI()->LeavingWorld(); +        if (UnitAI* ai = GetAI()) +            ai->LeavingWorld();          if (IsVehicle())              RemoveVehicleKit(); @@ -9501,80 +9537,44 @@ void Unit::CleanupsBeforeDelete(bool finalCleanup)  void Unit::UpdateCharmAI()  { -    switch (GetTypeId()) +    if (IsCharmed())      { -        case TYPEID_UNIT: -            if (i_disabledAI) // disabled AI must be primary AI -            { -                if (!IsCharmed()) -                { -                    delete i_AI; -                    i_AI = i_disabledAI; -                    i_disabledAI = nullptr; - -                    if (GetTypeId() == TYPEID_UNIT) -                        ToCreature()->AI()->OnCharmed(false); -                } -            } -            else -            { -                if (IsCharmed()) -                { -                    i_disabledAI = i_AI; -                    if (isPossessed() || IsVehicle()) -                        i_AI = new PossessedAI(ToCreature()); -                    else -                        i_AI = new PetAI(ToCreature()); -                } -            } -            break; -        case TYPEID_PLAYER: +        UnitAI* newAI = nullptr; +        if (GetTypeId() == TYPEID_PLAYER)          { -            if (IsCharmed()) // if we are currently being charmed, then we should apply charm AI +            if (Unit* charmer = GetCharmer())              { -                i_disabledAI = i_AI; - -                UnitAI* newAI = nullptr;                  // first, we check if the creature's own AI specifies an override playerai for its owned players -                if (Unit* charmer = GetCharmer()) -                { -                    if (Creature* creatureCharmer = charmer->ToCreature()) -                    { -                        if (PlayerAI* charmAI = creatureCharmer->IsAIEnabled ? creatureCharmer->AI()->GetAIForCharmedPlayer(ToPlayer()) : nullptr) -                            newAI = charmAI; -                    } -                    else -                    { -                        TC_LOG_ERROR("misc", "Attempt to assign charm AI to player %s who is charmed by non-creature %s.", GetGUID().ToString().c_str(), GetCharmerGUID().ToString().c_str()); -                    } -                } -                if (!newAI) // otherwise, we default to the generic one -                    newAI = new SimpleCharmedPlayerAI(ToPlayer()); -                i_AI = newAI; -                newAI->OnCharmed(true); -            } -            else -            { -                if (i_AI) +                if (Creature* creatureCharmer = charmer->ToCreature())                  { -                    // we allow the charmed PlayerAI to clean up -                    i_AI->OnCharmed(false); -                    // then delete it -                    delete i_AI; +                    if (CreatureAI* charmerAI = creatureCharmer->AI()) +                        newAI = charmerAI->GetAIForCharmedPlayer(ToPlayer());                  }                  else -                { -                    TC_LOG_ERROR("misc", "Attempt to remove charm AI from player %s who doesn't currently have charm AI.", GetGUID().ToString().c_str()); -                } -                // and restore our previous PlayerAI (if we had one) -                i_AI = i_disabledAI; -                i_disabledAI = nullptr; -                // IsAIEnabled gets handled in the caller +                    TC_LOG_ERROR("misc", "Attempt to assign charm AI to player %s who is charmed by non-creature %s.", GetGUID().ToString().c_str(), GetCharmerGUID().ToString().c_str());              } -            break; +            if (!newAI) // otherwise, we default to the generic one +                newAI = new SimpleCharmedPlayerAI(ToPlayer());          } -        default: -            TC_LOG_ERROR("misc", "Attempt to update charm AI for unit %s, which is neither player nor creature.", GetGUID().ToString().c_str()); +        else +        { +            ASSERT(GetTypeId() == TYPEID_UNIT); +            if (isPossessed() || IsVehicle()) +                newAI = new PossessedAI(ToCreature()); +            else +                newAI = new PetAI(ToCreature()); +        } + +        ASSERT(newAI); +        i_AI.reset(newAI); +        newAI->OnCharmed(true); +        AIUpdateTick(0, true); +    } +    else +    { +        RestoreDisabledAI(); +        if (i_AI) +            i_AI->OnCharmed(true);      }  } @@ -10946,7 +10946,7 @@ bool Unit::InitTamedPet(Pet* pet, uint8 level, uint32 spell_id)              plrVictim->SendDirectMessage(&data);          }          // Call KilledUnit for creatures -        if (attacker && attacker->GetTypeId() == TYPEID_UNIT && attacker->IsAIEnabled) +        if (attacker && attacker->GetTypeId() == TYPEID_UNIT && attacker->IsAIEnabled())              attacker->ToCreature()->AI()->KilledUnit(victim);          // last damage from non duel opponent or opponent controlled creature @@ -10973,16 +10973,16 @@ bool Unit::InitTamedPet(Pet* pet, uint8 level, uint32 spell_id)          }          // Call KilledUnit for creatures, this needs to be called after the lootable flag is set -        if (attacker && attacker->GetTypeId() == TYPEID_UNIT && attacker->IsAIEnabled) +        if (attacker && attacker->GetTypeId() == TYPEID_UNIT && attacker->IsAIEnabled())              attacker->ToCreature()->AI()->KilledUnit(victim);          // Call creature just died function -        if (creature->IsAIEnabled) -            creature->AI()->JustDied(attacker); +        if (CreatureAI* ai = creature->AI()) +            ai->JustDied(attacker);          if (TempSummon* summon = creature->ToTempSummon())              if (Unit* summoner = summon->GetSummoner()) -                if (summoner->ToCreature() && summoner->IsAIEnabled) +                if (summoner->ToCreature() && summoner->IsAIEnabled())                      summoner->ToCreature()->AI()->SummonedCreatureDies(creature, attacker);          // Dungeon specific stuff, only applies to players killing creatures @@ -11400,7 +11400,11 @@ bool Unit::SetCharmedBy(Unit* charmer, CharmType type, AuraApplication const* au          StopMoving(); -        ToCreature()->AI()->OnCharmed(true); +        // AI will schedule its own change if appropriate +        if (UnitAI* ai = GetAI()) +            ai->OnCharmed(false); +        else +            ScheduleAIChange();      }      else if (Player* player = ToPlayer())      { @@ -11410,12 +11414,10 @@ bool Unit::SetCharmedBy(Unit* charmer, CharmType type, AuraApplication const* au          if (charmer->GetTypeId() == TYPEID_UNIT) // we are charmed by a creature          {              // change AI to charmed AI on next Update tick -            NeedChangeAI = true; -            if (IsAIEnabled) -            { -                IsAIEnabled = false; -                player->AI()->OnCharmed(true); -            } +            if (UnitAI* ai = GetAI()) +                ai->OnCharmed(false); +            else +                player->ScheduleAIChange();          }          player->SetClientControl(this, false);      } @@ -11517,16 +11519,9 @@ void Unit::RemoveCharmedBy(Unit* charmer)      ///@todo Handle SLOT_IDLE motion resume      GetMotionMaster()->InitializeDefault(); -    if (Creature* creature = ToCreature()) -    { -        // Creature will restore its old AI on next update -        if (creature->AI()) -            creature->AI()->OnCharmed(false); - -        // Vehicle should not attack its passenger after he exists the seat -        if (type != CHARM_TYPE_VEHICLE) -            LastCharmerGUID = ASSERT_NOTNULL(charmer)->GetGUID(); -    } +    // Vehicle should not attack its passenger after he exists the seat +    if (type != CHARM_TYPE_VEHICLE) +        LastCharmerGUID = ASSERT_NOTNULL(charmer)->GetGUID();      // If charmer still exists      if (!charmer) @@ -11573,16 +11568,11 @@ void Unit::RemoveCharmedBy(Unit* charmer)          }      } -    if (Player* player = ToPlayer()) -    { -        if (charmer->GetTypeId() == TYPEID_UNIT) // charmed by a creature, this means we had PlayerAI -        { -            NeedChangeAI = true; -            IsAIEnabled = false; -        } +    if (GetTypeId() != TYPEID_PLAYER || charmer->GetTypeId() == TYPEID_UNIT) +        GetAI()->OnCharmed(false); // AI will potentially schedule a charm ai update +    if (Player* player = ToPlayer())          player->SetClientControl(this, true); -    }      // a guardian should always have charminfo      if (playerCharmer && this != charmer->GetFirstControlled()) @@ -12466,7 +12456,7 @@ void Unit::HandleSpellClick(Unit* clicker, int8 seatId /*= -1*/)      }      Creature* creature = ToCreature(); -    if (creature && creature->IsAIEnabled) +    if (creature && creature->IsAIEnabled())          creature->AI()->OnSpellClick(clicker, spellClickHandled);  } diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index dfd1c1e020c..774ba7d5c46 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -28,6 +28,7 @@  #include "UnitDefines.h"  #include "Util.h"  #include <map> +#include <memory>  #define VISUAL_WAYPOINT 1 // Creature Entry ID used for waypoints show, visible only for GMs  #define WORLD_TRIGGER 12999 @@ -763,8 +764,11 @@ class TC_GAME_API Unit : public WorldObject          virtual ~Unit(); -        UnitAI* GetAI() { return i_AI; } -        void SetAI(UnitAI* newAI) { i_AI = newAI; } +        bool IsAIEnabled() const { return (i_AI != nullptr); } +        void AIUpdateTick(uint32 diff, bool force = false); +        UnitAI* GetAI() const { return i_AI.get(); } +        void SetAI(UnitAI* newAI); +        void ScheduleAIChange();          void AddToWorld() override;          void RemoveFromWorld() override; @@ -1180,7 +1184,6 @@ class TC_GAME_API Unit : public WorldObject          CharmInfo* GetCharmInfo() { return m_charmInfo; }          CharmInfo* InitCharmInfo();          void DeleteCharmInfo(); -        void UpdateCharmAI();          // returns the unit that this player IS CONTROLLING          Unit* GetUnitBeingMoved() const;          // returns the player that this player IS CONTROLLING @@ -1595,7 +1598,6 @@ class TC_GAME_API Unit : public WorldObject          uint32 GetModelForTotem(PlayerTotemType totemType);          friend class VehicleJoinEvent; -        bool IsAIEnabled, NeedChangeAI;          ObjectGuid LastCharmerGUID;          bool CreateVehicleKit(uint32 id, uint32 creatureEntry);          void RemoveVehicleKit(); @@ -1681,8 +1683,6 @@ class TC_GAME_API Unit : public WorldObject          void BuildValuesUpdate(uint8 updatetype, ByteBuffer* data, Player* target) const override; -        UnitAI* i_AI, *i_disabledAI; -          void _UpdateSpells(uint32 time);          void _DeleteRemovedAuras(); @@ -1785,6 +1785,10 @@ class TC_GAME_API Unit : public WorldObject          friend class ThreatManager;          ThreatManager m_threatManager; +        void UpdateCharmAI(); +        void RestoreDisabledAI(); +        std::unique_ptr<UnitAI> i_AI, i_disabledAI; +          std::unordered_set<AbstractFollower*> m_followingMe;          Unit* m_comboTarget; diff --git a/src/server/game/Entities/Vehicle/Vehicle.cpp b/src/server/game/Entities/Vehicle/Vehicle.cpp index 528b521f59d..b6a1e2f437c 100755 --- a/src/server/game/Entities/Vehicle/Vehicle.cpp +++ b/src/server/game/Entities/Vehicle/Vehicle.cpp @@ -514,7 +514,7 @@ Vehicle* Vehicle::RemovePassenger(Unit* unit)      if (unit->IsFlying())          _me->CastSpell(unit, VEHICLE_SPELL_PARACHUTE, true); -    if (_me->GetTypeId() == TYPEID_UNIT && _me->ToCreature()->IsAIEnabled) +    if (_me->GetTypeId() == TYPEID_UNIT && _me->ToCreature()->IsAIEnabled())          _me->ToCreature()->AI()->PassengerBoarded(unit, seat->first, false);      if (GetBase()->GetTypeId() == TYPEID_UNIT) @@ -854,8 +854,8 @@ bool VehicleJoinEvent::Execute(uint64, uint32)      if (Creature* creature = Target->GetBase()->ToCreature())      { -        if (creature->IsAIEnabled) -            creature->AI()->PassengerBoarded(Passenger, Seat->first, true); +        if (CreatureAI* ai = creature->AI()) +            ai->PassengerBoarded(Passenger, Seat->first, true);          sScriptMgr->OnAddPassenger(Target, Passenger, Seat->first); diff --git a/src/server/game/Events/GameEventMgr.cpp b/src/server/game/Events/GameEventMgr.cpp index e2930f42552..89c9d27efe7 100644 --- a/src/server/game/Events/GameEventMgr.cpp +++ b/src/server/game/Events/GameEventMgr.cpp @@ -1687,7 +1687,7 @@ public:      void Visit(std::unordered_map<ObjectGuid, Creature*>& creatureMap)      {          for (auto const& p : creatureMap) -            if (p.second->IsInWorld() && p.second->IsAIEnabled) +            if (p.second->IsInWorld() && p.second->IsAIEnabled())                  p.second->AI()->OnGameEvent(_activate, _eventId);      } diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.cpp b/src/server/game/Grids/Notifiers/GridNotifiers.cpp index 7fb56b3e686..b60f2ef0af4 100644 --- a/src/server/game/Grids/Notifiers/GridNotifiers.cpp +++ b/src/server/game/Grids/Notifiers/GridNotifiers.cpp @@ -133,10 +133,10 @@ inline void CreatureUnitRelocationWorker(Creature* c, Unit* u)      if (!c->HasUnitState(UNIT_STATE_SIGHTLESS))      { -        if (c->IsAIEnabled && c->CanSeeOrDetect(u, false, true)) +        if (c->IsAIEnabled() && c->CanSeeOrDetect(u, false, true))              c->AI()->MoveInLineOfSight_Safe(u);          else -            if (u->GetTypeId() == TYPEID_PLAYER && u->HasStealthAura() && c->IsAIEnabled && c->CanSeeOrDetect(u, false, true, true)) +            if (u->GetTypeId() == TYPEID_PLAYER && u->HasStealthAura() && c->IsAIEnabled() && c->CanSeeOrDetect(u, false, true, true))                  c->AI()->TriggerAlert(u);      }  } diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.h b/src/server/game/Grids/Notifiers/GridNotifiers.h index d4687d1b1ee..f55acdca8d7 100644 --- a/src/server/game/Grids/Notifiers/GridNotifiers.h +++ b/src/server/game/Grids/Notifiers/GridNotifiers.h @@ -1102,8 +1102,7 @@ namespace Trinity                  if (!u->IsWithinLOSInMap(i_enemy))                      return; -                if (u->GetAI() && u->IsAIEnabled) -                    u->GetAI()->AttackStart(i_enemy); +                u->EngageWithTarget(i_enemy);              }          private:              Unit* const i_funit; diff --git a/src/server/game/Handlers/PetHandler.cpp b/src/server/game/Handlers/PetHandler.cpp index d266fef5a42..3ef03ffc80b 100644 --- a/src/server/game/Handlers/PetHandler.cpp +++ b/src/server/game/Handlers/PetHandler.cpp @@ -209,7 +209,7 @@ void WorldSession::HandlePetActionHelper(Unit* pet, ObjectGuid guid1, uint32 spe                          if (pet->GetVictim())                              pet->AttackStop(); -                        if (pet->GetTypeId() != TYPEID_PLAYER && pet->ToCreature()->IsAIEnabled) +                        if (pet->GetTypeId() != TYPEID_PLAYER && pet->ToCreature()->IsAIEnabled())                          {                              charmInfo->SetIsCommandAttack(true);                              charmInfo->SetIsAtStay(false); @@ -368,9 +368,8 @@ void WorldSession::HandlePetActionHelper(Unit* pet, ObjectGuid guid1, uint32 spe                      if (pet->GetVictim() != unit_target)                      {                          pet->GetMotionMaster()->Clear(); -                        if (pet->ToCreature()->IsAIEnabled) +                        if (CreatureAI* AI = pet->ToCreature()->AI())                          { -                            CreatureAI* AI = pet->ToCreature()->AI();                              if (PetAI* petAI = dynamic_cast<PetAI*>(AI))                                  petAI->_AttackStart(unit_target); // force victim switch                              else diff --git a/src/server/game/Movement/MovementGenerators/ChaseMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/ChaseMovementGenerator.cpp index 973921aafe1..2bf8c3f48f9 100644 --- a/src/server/game/Movement/MovementGenerators/ChaseMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/ChaseMovementGenerator.cpp @@ -52,9 +52,8 @@ static void DoMovementInform(Unit* owner, Unit* target)      if (owner->GetTypeId() != TYPEID_UNIT)          return; -    Creature* creatureOwner = owner->ToCreature(); -    if (creatureOwner->IsAIEnabled && creatureOwner->AI()) -        creatureOwner->AI()->MovementInform(CHASE_MOTION_TYPE, target->GetGUID().GetCounter()); +    if (CreatureAI* AI = owner->ToCreature()->AI()) +        AI->MovementInform(CHASE_MOTION_TYPE, target->GetGUID().GetCounter());  }  ChaseMovementGenerator::ChaseMovementGenerator(Unit* target, Optional<ChaseRange> range, Optional<ChaseAngle> angle) : AbstractFollower(ASSERT_NOTNULL(target)), _range(range), _angle(angle) diff --git a/src/server/game/Movement/MovementGenerators/FollowMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/FollowMovementGenerator.cpp index e4b7fc78832..adcc35b1c86 100644 --- a/src/server/game/Movement/MovementGenerators/FollowMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/FollowMovementGenerator.cpp @@ -31,9 +31,8 @@ static void DoMovementInform(Unit* owner, Unit* target)      if (owner->GetTypeId() != TYPEID_UNIT)          return; -    Creature* creatureOwner = owner->ToCreature(); -    if (creatureOwner->IsAIEnabled && creatureOwner->AI()) -        creatureOwner->AI()->MovementInform(FOLLOW_MOTION_TYPE, target->GetGUID().GetCounter()); +    if (CreatureAI* AI = owner->ToCreature()->AI()) +        AI->MovementInform(FOLLOW_MOTION_TYPE, target->GetGUID().GetCounter());  }  FollowMovementGenerator::FollowMovementGenerator(Unit* target, float range, ChaseAngle angle) : AbstractFollower(ASSERT_NOTNULL(target)), _range(range), _angle(angle) diff --git a/src/server/game/Movement/MovementGenerators/SplineChainMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/SplineChainMovementGenerator.cpp index a90a8b7af36..5df2ea43fef 100644 --- a/src/server/game/Movement/MovementGenerators/SplineChainMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/SplineChainMovementGenerator.cpp @@ -185,8 +185,8 @@ void SplineChainMovementGenerator::Finalize(Unit* owner, bool active, bool movem      if (movementInform && HasFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED))      {          Creature* ownerCreature = owner->ToCreature(); -        if (ownerCreature && ownerCreature->IsAIEnabled) -            ownerCreature->AI()->MovementInform(SPLINE_CHAIN_MOTION_TYPE, _id); +        if (CreatureAI* AI = ownerCreature ? ownerCreature->AI() : nullptr) +            AI->MovementInform(SPLINE_CHAIN_MOTION_TYPE, _id);      }  } diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp index 7c0336e6523..aa81d6d0d92 100755 --- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp @@ -117,8 +117,8 @@ void WaypointMovementGenerator<Creature>::DoInitialize(Creature* owner)      _nextMoveTime.Reset(1000);      // inform AI -    if (owner->IsAIEnabled) -        owner->AI()->WaypointPathStarted(_path->id); +    if (CreatureAI* AI = owner->AI()) +        AI->WaypointPathStarted(_path->id);  }  void WaypointMovementGenerator<Creature>::DoReset(Creature* owner) @@ -256,10 +256,10 @@ void WaypointMovementGenerator<Creature>::OnArrived(Creature* owner)      }      // inform AI -    if (owner->IsAIEnabled) +    if (CreatureAI* AI = owner->AI())      { -        owner->AI()->MovementInform(WAYPOINT_MOTION_TYPE, _currentNode); -        owner->AI()->WaypointReached(waypoint.id, _path->id); +        AI->MovementInform(WAYPOINT_MOTION_TYPE, _currentNode); +        AI->WaypointReached(waypoint.id, _path->id);      }      owner->UpdateCurrentWaypointInfo(waypoint.id, _path->id); @@ -286,8 +286,8 @@ void WaypointMovementGenerator<Creature>::StartMove(Creature* owner, bool relaun              ASSERT(_currentNode < _path->nodes.size(), "WaypointMovementGenerator::StartMove: tried to reference a node id (%u) which is not included in path (%u)", _currentNode, _path->id);              // inform AI -            if (owner->IsAIEnabled) -                owner->AI()->WaypointStarted(_path->nodes[_currentNode].id, _path->id); +            if (CreatureAI* AI = owner->AI()) +                AI->WaypointStarted(_path->nodes[_currentNode].id, _path->id);          }          else          { @@ -314,8 +314,8 @@ void WaypointMovementGenerator<Creature>::StartMove(Creature* owner, bool relaun              owner->UpdateCurrentWaypointInfo(0, 0);              // inform AI -            if (owner->IsAIEnabled) -                owner->AI()->WaypointPathEnded(waypoint.id, _path->id); +            if (CreatureAI* AI = owner->AI()) +                AI->WaypointPathEnded(waypoint.id, _path->id);              return;          }      } @@ -324,8 +324,8 @@ void WaypointMovementGenerator<Creature>::StartMove(Creature* owner, bool relaun          AddFlag(MOVEMENTGENERATOR_FLAG_INITIALIZED);          // inform AI -        if (owner->IsAIEnabled) -            owner->AI()->WaypointStarted(_path->nodes[_currentNode].id, _path->id); +        if (CreatureAI* AI = owner->AI()) +            AI->WaypointStarted(_path->nodes[_currentNode].id, _path->id);      }      ASSERT(_currentNode < _path->nodes.size(), "WaypointMovementGenerator::StartMove: tried to reference a node id (%u) which is not included in path (%u)", _currentNode, _path->id); diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp index 16c6bc1a281..d63eca92429 100644 --- a/src/server/game/Scripting/ScriptMgr.cpp +++ b/src/server/game/Scripting/ScriptMgr.cpp @@ -432,7 +432,9 @@ class CreatureGameObjectScriptRegistrySwapHooks          if (!creature->IsAlive())              return; -        creature->AI_InitializeAndEnable(); +        creature->AI()->InitializeAI(); +        if (creature->GetVehicleKit()) +            creature->GetVehicleKit()->Reset();          creature->AI()->EnterEvadeMode();          // Cast a dummy visual spell asynchronously here to signal diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 58c2fa7755a..ec8b1202208 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -2541,18 +2541,16 @@ void Spell::TargetInfo::DoDamageAndTriggers(Spell* spell)      if (_spellHitTarget)      {          //AI functions -        if (_spellHitTarget->GetTypeId() == TYPEID_UNIT) -        { -            if (_spellHitTarget->ToCreature()->IsAIEnabled) +        if (Creature* cHitTarget = _spellHitTarget->ToCreature()) +            if (CreatureAI* hitTargetAI = cHitTarget->AI())              {                  if (spell->m_caster->GetTypeId() == TYPEID_GAMEOBJECT) -                    _spellHitTarget->ToCreature()->AI()->SpellHit(spell->m_caster->ToGameObject(), spell->m_spellInfo); +                    hitTargetAI->SpellHit(spell->m_caster->ToGameObject(), spell->m_spellInfo);                  else -                    _spellHitTarget->ToCreature()->AI()->SpellHit(spell->m_caster->ToUnit(), spell->m_spellInfo); +                    hitTargetAI->SpellHit(spell->m_caster->ToUnit(), spell->m_spellInfo);              } -        } -        if (spell->m_caster->GetTypeId() == TYPEID_UNIT && spell->m_caster->ToCreature()->IsAIEnabled) +        if (spell->m_caster->GetTypeId() == TYPEID_UNIT && spell->m_caster->ToCreature()->IsAIEnabled())              spell->m_caster->ToCreature()->AI()->SpellHitTarget(_spellHitTarget, spell->m_spellInfo);          else if (spell->m_caster->GetTypeId() == TYPEID_GAMEOBJECT && spell->m_caster->ToGameObject()->AI())              spell->m_caster->ToGameObject()->AI()->SpellHitTarget(_spellHitTarget, spell->m_spellInfo); @@ -2601,7 +2599,7 @@ void Spell::GOTargetInfo::DoTargetSpellHit(Spell* spell, uint8 effIndex)              go->AI()->SpellHit(spell->m_caster->ToUnit(), spell->m_spellInfo);      } -    if (spell->m_caster->GetTypeId() == TYPEID_UNIT && spell->m_caster->ToCreature()->IsAIEnabled) +    if (spell->m_caster->GetTypeId() == TYPEID_UNIT && spell->m_caster->ToCreature()->IsAIEnabled())          spell->m_caster->ToCreature()->AI()->SpellHitTarget(go, spell->m_spellInfo);      else if (spell->m_caster->GetTypeId() == TYPEID_GAMEOBJECT && spell->m_caster->ToGameObject()->AI())          spell->m_caster->ToGameObject()->AI()->SpellHitTarget(go, spell->m_spellInfo); @@ -3222,8 +3220,8 @@ void Spell::_cast(bool skipCheck)              if (Unit* target = m_targets.GetUnitTarget())                  for (Unit* controlled : playerCaster->m_Controlled)                      if (Creature* cControlled = controlled->ToCreature()) -                        if (cControlled->IsAIEnabled) -                            cControlled->AI()->OwnerAttacked(target); +                        if (CreatureAI* controlledAI = cControlled->AI()) +                                controlledAI->OwnerAttacked(target);      }      SetExecutedCurrently(true); diff --git a/src/server/scripts/Commands/cs_debug.cpp b/src/server/scripts/Commands/cs_debug.cpp index 90785c53017..59ea2cde03c 100644 --- a/src/server/scripts/Commands/cs_debug.cpp +++ b/src/server/scripts/Commands/cs_debug.cpp @@ -1615,10 +1615,8 @@ public:          if (!player)              return false;          Creature* target = handler->getSelectedCreature(); -        if (!target || !target->IsAIEnabled || !target->AI()) -        { +        if (!target || !target->IsAIEnabled())              return false; -        }          char* fill_str = args ? strtok((char*)args, " ") : nullptr;          char* duration_str = args ? strtok(nullptr, " ") : nullptr; diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp index edfa6d15d89..db606da8c86 100644 --- a/src/server/scripts/Commands/cs_npc.cpp +++ b/src/server/scripts/Commands/cs_npc.cpp @@ -1502,7 +1502,7 @@ public:              return false;          } -        if (!creatureTarget->IsAIEnabled) +        if (!creatureTarget->IsAIEnabled())          {              handler->PSendSysMessage(LANG_CREATURE_NOT_AI_ENABLED);              handler->SetSentErrorMessage(true); diff --git a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp index 95e6a925ddd..33b490065fb 100644 --- a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp @@ -390,7 +390,7 @@ class npc_eye_of_acherus : public CreatureScript                  _events.ScheduleEvent(EVENT_MOVE_START, 7s);              } -            void OnCharmed(bool /*apply*/) override { } +            void OnCharmed(bool /*isNew*/) override { }              void UpdateAI(uint32 diff) override              { diff --git a/src/server/scripts/EasternKingdoms/zone_stormwind_city.cpp b/src/server/scripts/EasternKingdoms/zone_stormwind_city.cpp index c6939561f3b..82151ecbf1e 100644 --- a/src/server/scripts/EasternKingdoms/zone_stormwind_city.cpp +++ b/src/server/scripts/EasternKingdoms/zone_stormwind_city.cpp @@ -336,7 +336,7 @@ public:              if (me->IsSummon())              {                  Unit* summoner = me->ToTempSummon()->GetSummoner(); -                if (summoner && summoner->GetTypeId() == TYPEID_UNIT && summoner->IsAIEnabled) +                if (summoner && summoner->GetTypeId() == TYPEID_UNIT && summoner->IsAIEnabled())                  {                      npc_lord_gregor_lescovar::npc_lord_gregor_lescovarAI* ai =                          CAST_AI(npc_lord_gregor_lescovar::npc_lord_gregor_lescovarAI, summoner->GetAI()); diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_cthun.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_cthun.cpp index 3066efeb80f..e11a398bc6a 100644 --- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_cthun.cpp +++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_cthun.cpp @@ -1291,7 +1291,7 @@ public:          {              if (TempSummon* summon = me->ToTempSummon())                  if (Unit* summoner = summon->GetSummoner()) -                    if (summoner->IsAIEnabled) +                    if (summoner->IsAIEnabled())                          summoner->GetAI()->DoAction(ACTION_FLESH_TENTACLE_KILLED);          }      }; diff --git a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp index 4c902435ba8..ebc0c04935d 100644 --- a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp +++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp @@ -1608,7 +1608,7 @@ class spell_halion_damage_aoe_summon : public SpellScriptLoader                  Position pos = caster->GetPosition();                  if (Creature* summon = caster->GetMap()->SummonCreature(entry, pos, properties, duration, caster, GetSpellInfo()->Id)) -                    if (summon->IsAIEnabled) +                    if (summon->IsAIEnabled())                          summon->AI()->SetData(DATA_STACKS_DISPELLED, GetSpellValue()->EffectBasePoints[EFFECT_1]);              } diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp index b8269474ab3..d0718b0745c 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp @@ -1079,7 +1079,7 @@ class spell_gormok_ride_player : public AuraScript              return;          if (Unit *caster = GetCaster()) -            if (caster->IsAIEnabled) +            if (caster->IsAIEnabled())                  caster->GetAI()->SetGUID(target->GetGUID(), DATA_NEW_TARGET);      } @@ -1300,7 +1300,7 @@ class spell_icehowl_trample : public SpellScript      void CheckTargets(std::list<WorldObject*>& targets)      {          Creature* caster = GetCaster()->ToCreature(); -        if (!caster || !caster->IsAIEnabled) +        if (!caster || !caster->IsAIEnabled())              return;          if (targets.empty()) diff --git a/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_scourgelord_tyrannus.cpp b/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_scourgelord_tyrannus.cpp index cc21eeec7b5..2f351308e9f 100644 --- a/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_scourgelord_tyrannus.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_scourgelord_tyrannus.cpp @@ -447,10 +447,7 @@ class spell_tyrannus_overlord_brand : public SpellScriptLoader                      return;                  Player* pTarget = GetTarget()->ToPlayer(); -                oldAI = pTarget->AI(); -                oldAIState = pTarget->IsAIEnabled;                  GetTarget()->SetAI(new player_overlord_brandAI(pTarget, GetCasterGUID())); -                GetTarget()->IsAIEnabled = true;              }              void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) @@ -458,10 +455,7 @@ class spell_tyrannus_overlord_brand : public SpellScriptLoader                  if (GetTarget()->GetTypeId() != TYPEID_PLAYER)                      return; -                GetTarget()->IsAIEnabled = oldAIState; -                PlayerAI* thisAI = GetTarget()->ToPlayer()->AI(); -                GetTarget()->SetAI(oldAI); -                delete thisAI; +                GetTarget()->SetAI(nullptr);              }              void Register() override @@ -469,9 +463,6 @@ class spell_tyrannus_overlord_brand : public SpellScriptLoader                  AfterEffectApply += AuraEffectApplyFn(spell_tyrannus_overlord_brand_AuraScript::OnApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);                  AfterEffectRemove += AuraEffectRemoveFn(spell_tyrannus_overlord_brand_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);              } - -            PlayerAI* oldAI = nullptr; -            bool oldAIState = false;          };          AuraScript* GetAuraScript() const override diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp index e80d238d7c9..b9fb998dd9f 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp @@ -1792,7 +1792,7 @@ class npc_gunship_cannon : public CreatureScript              {              } -            void OnCharmed(bool /*apply*/) override { } +            void OnCharmed(bool /*isNew*/) override { }              void PassengerBoarded(Unit* /*passenger*/, int8 /*seat*/, bool apply) override              { diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp index 1d107a720fc..bb1e60e6d96 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp @@ -630,7 +630,7 @@ class spell_marrowgar_bone_spike_graveyard : public SpellScriptLoader              bool Load() override              { -                return GetCaster()->GetTypeId() == TYPEID_UNIT && GetCaster()->IsAIEnabled; +                return GetCaster()->GetTypeId() == TYPEID_UNIT && GetCaster()->IsAIEnabled();              }              SpellCastResult CheckCast() diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp index 0878b5645f5..8d56c9cfb18 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp @@ -2367,8 +2367,8 @@ class spell_the_lich_king_quake : public SpellScriptLoader              void HandleSendEvent(SpellEffIndex /*effIndex*/)              { -                if (GetCaster()->IsAIEnabled) -                    GetCaster()->GetAI()->DoAction(ACTION_START_ATTACK); +                if (UnitAI* AI = GetCaster()->GetAI()) +                    AI->DoAction(ACTION_START_ATTACK);              }              void Register() override diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp index 95360a368ed..924a400da2a 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp @@ -1279,7 +1279,7 @@ class spell_dreamwalker_summon_suppresser : public SpellScriptLoader              void HandleSummon(Unit* caster)              { -                if (!caster || !caster->IsAIEnabled) +                if (!caster || !caster->IsAIEnabled())                      return;                  std::list<Creature*> summoners; diff --git a/src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp b/src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp index e6bd23bde49..2b6968d26ea 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp @@ -216,24 +216,11 @@ class npc_dk_understudy : public CreatureScript                  DoMeleeAttackIfReady();              } -            void OnCharmed(bool apply) override +            void OnCharmed(bool isNew) override              { -                ScriptedAI::OnCharmed(apply); -                if (apply) -                { -                    if (!me->IsInCombat()) -                        JustEngagedWith(nullptr); -                    me->StopMoving(); -                    me->SetReactState(REACT_PASSIVE); -                    _charmer = me->GetCharmerGUID(); -                } -                else -                { -                    me->SetReactState(REACT_AGGRESSIVE); -                    if (Unit* charmer = ObjectAccessor::GetUnit(*me, _charmer)) -                        AddThreat(charmer, 100000.0f); -                    DoZoneInCombat(); -                } +                if (me->IsCharmed() && !me->IsEngaged()) +                    JustEngagedWith(nullptr); +                ScriptedAI::OnCharmed(isNew);              }          private:              InstanceScript* const _instance; diff --git a/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp b/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp index b718655ceb3..675ca6fcd9c 100644 --- a/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp +++ b/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp @@ -836,7 +836,7 @@ public:                              {                                  Creature* casterDiskSummon = me->SummonCreature(NPC_HOVER_DISK_CASTER, RangeHoverDisksSpawnPositions[rangeDisks]); -                                if (casterDiskSummon->IsAIEnabled) +                                if (casterDiskSummon->IsAIEnabled())                                      casterDiskSummon->AI()->DoAction(rangeDisks);                              } @@ -857,7 +857,7 @@ public:                          {                              Creature* casterDiskSummon = me->SummonCreature(NPC_HOVER_DISK_CASTER, RangeHoverDisksSpawnPositions[rangeDisks]); -                            if (casterDiskSummon->IsAIEnabled) +                            if (casterDiskSummon->IsAIEnabled())                                  casterDiskSummon->AI()->DoAction(rangeDisks);                          } diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp index 0da39233faa..3e95824e546 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp @@ -1232,7 +1232,7 @@ class spell_algalon_big_bang : public SpellScriptLoader          private:              bool Load() override              { -                return GetCaster()->GetTypeId() == TYPEID_UNIT && GetCaster()->IsAIEnabled; +                return GetCaster()->GetTypeId() == TYPEID_UNIT;              }              void CountTargets(std::list<WorldObject*>& targets) diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_auriaya.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_auriaya.cpp index 3292edc24e2..413af0ef1f1 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_auriaya.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_auriaya.cpp @@ -550,7 +550,7 @@ class spell_auriaya_agro_creator : public SpellScript      void HandleDummyEffect(SpellEffIndex /*effIndex*/)      {          Creature* caster = GetCaster()->ToCreature(); -        if (!caster || !caster->IsAIEnabled || caster->HasReactState(REACT_PASSIVE)) +        if (!caster || !caster->IsAIEnabled() || caster->HasReactState(REACT_PASSIVE))              return;          if (Unit* target = caster->AI()->SelectTarget(SELECT_TARGET_RANDOM, 0, CatsTargetSelector(caster, 5.0f, 10.0f))) @@ -580,7 +580,7 @@ class spell_auriaya_random_agro_periodic : public AuraScript      void HandleEffectPeriodic(AuraEffect const* /*aurEff*/)      {          Creature* owner = GetUnitOwner()->ToCreature(); -        if (!owner || !owner->IsAIEnabled || owner->HasReactState(REACT_PASSIVE)) +        if (!owner || !owner->IsAIEnabled() || owner->HasReactState(REACT_PASSIVE))              return;          bool farTarget = true; diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp index 86e6eca283f..042a5adce34 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp @@ -495,8 +495,8 @@ class achievement_ignis_shattered : public AchievementCriteriaScript          bool OnCheck(Player* /*source*/, Unit* target) override          { -            if (target && target->IsAIEnabled) -                return target->GetAI()->GetData(DATA_SHATTERED) != 0; +            if (UnitAI* ai = target ? target->GetAI() : nullptr) +                return ai->GetData(DATA_SHATTERED) != 0;              return false;          } diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp index fd96955add0..6cf9fa22145 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp @@ -1711,7 +1711,7 @@ class achievement_iron_dwarf_medium_rare : public AchievementCriteriaScript          bool OnCheck(Player* /*player*/, Unit* target) override          { -            return target && target->IsAIEnabled && target->GetAI()->GetData(DATA_IRON_DWARF_MEDIUM_RARE); +            return target && target->GetAI() && target->GetAI()->GetData(DATA_IRON_DWARF_MEDIUM_RARE);          }  }; diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_keleseth.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_keleseth.cpp index 2a392030b0f..be1b482aa60 100644 --- a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_keleseth.cpp +++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_keleseth.cpp @@ -373,7 +373,7 @@ class achievement_on_the_rocks : public AchievementCriteriaScript          bool OnCheck(Player* /*source*/, Unit* target) override          { -            return target && target->IsAIEnabled && target->GetAI()->GetData(DATA_ON_THE_ROCKS); +            return target && target->GetAI() && target->GetAI()->GetData(DATA_ON_THE_ROCKS);          }  }; diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_svala.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_svala.cpp index 07780da659b..96ea8405b0a 100644 --- a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_svala.cpp +++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_svala.cpp @@ -606,7 +606,7 @@ class achievement_incredible_hulk : public AchievementCriteriaScript          bool OnCheck(Player* /*player*/, Unit* target) override          { -            return target && target->IsAIEnabled && target->GetAI()->GetData(DATA_INCREDIBLE_HULK); +            return target && target->GetAI() && target->GetAI()->GetData(DATA_INCREDIBLE_HULK);          }  }; diff --git a/src/server/scripts/Northrend/VaultOfArchavon/boss_toravon.cpp b/src/server/scripts/Northrend/VaultOfArchavon/boss_toravon.cpp index d9800fab916..9752d775fba 100644 --- a/src/server/scripts/Northrend/VaultOfArchavon/boss_toravon.cpp +++ b/src/server/scripts/Northrend/VaultOfArchavon/boss_toravon.cpp @@ -181,13 +181,12 @@ class spell_toravon_random_aggro : public SpellScript      void HandleScript(SpellEffIndex /*effIndex*/)      {          Creature* caster = GetCaster()->ToCreature(); -        if (!caster->IsAIEnabled) -            return;          caster->GetThreatManager().ResetAllThreat(); -        if (Unit* target = caster->AI()->SelectTarget(SELECT_TARGET_RANDOM, 1)) -            caster->GetThreatManager().AddThreat(target, 1000000); +        if (CreatureAI* ai = caster->AI()) +            if (Unit* target = ai->SelectTarget(SELECT_TARGET_RANDOM, 1)) +                caster->GetThreatManager().AddThreat(target, 1000000);      }      void Register() override diff --git a/src/server/scripts/Northrend/VioletHold/boss_ichoron.cpp b/src/server/scripts/Northrend/VioletHold/boss_ichoron.cpp index cc92cf2bd85..40169d95b2a 100644 --- a/src/server/scripts/Northrend/VioletHold/boss_ichoron.cpp +++ b/src/server/scripts/Northrend/VioletHold/boss_ichoron.cpp @@ -324,8 +324,8 @@ class spell_ichoron_drained : public SpellScriptLoader                  GetTarget()->RemoveFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_FEIGN_DEATH);                  if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE) -                    if (GetTarget()->IsAIEnabled) -                        GetTarget()->GetAI()->DoAction(ACTION_DRAINED); +                    if (UnitAI* ai = GetTarget()->GetAI()) +                        ai->DoAction(ACTION_DRAINED);              }              void Register() override @@ -398,8 +398,8 @@ class spell_ichoron_protective_bubble : public SpellScriptLoader              {                  //if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_ENEMY_SPELL)                  if (GetAura()->GetCharges() <= 1) -                    if (GetTarget()->IsAIEnabled) -                        GetTarget()->GetAI()->DoAction(ACTION_PROTECTIVE_BUBBLE_SHATTERED); +                    if (UnitAI* targetAI = GetTarget()->GetAI()) +                        targetAI->DoAction(ACTION_PROTECTIVE_BUBBLE_SHATTERED);              }              void Register() override diff --git a/src/server/scripts/Northrend/VioletHold/boss_moragg.cpp b/src/server/scripts/Northrend/VioletHold/boss_moragg.cpp index fbff39951d7..b9b73d0bcc5 100644 --- a/src/server/scripts/Northrend/VioletHold/boss_moragg.cpp +++ b/src/server/scripts/Northrend/VioletHold/boss_moragg.cpp @@ -111,14 +111,12 @@ class spell_moragg_ray : public SpellScriptLoader              {                  PreventDefaultAction(); -                if (!GetTarget()->IsAIEnabled) -                    return; - -                if (Unit* target = GetTarget()->GetAI()->SelectTarget(SELECT_TARGET_RANDOM, 0, 45.0f, true)) -                { -                    uint32 triggerSpell = GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell; -                    GetTarget()->CastSpell(target, triggerSpell, aurEff); -                } +                if (UnitAI* AI = GetTarget()->GetAI()) +                    if (Unit* target = AI->SelectTarget(SELECT_TARGET_RANDOM, 0, 45.0f, true)) +                    { +                        uint32 triggerSpell = GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell; +                        GetTarget()->CastSpell(target, triggerSpell, aurEff); +                    }              }              void Register() override diff --git a/src/server/scripts/Northrend/VioletHold/violet_hold.cpp b/src/server/scripts/Northrend/VioletHold/violet_hold.cpp index 3487fcdd92a..a59f999fadf 100644 --- a/src/server/scripts/Northrend/VioletHold/violet_hold.cpp +++ b/src/server/scripts/Northrend/VioletHold/violet_hold.cpp @@ -1367,8 +1367,8 @@ class spell_violet_hold_portal_periodic : public SpellScriptLoader              void PeriodicTick(AuraEffect const* aurEff)              {                  PreventDefaultAction(); -                if (GetTarget()->IsAIEnabled) -                    GetTarget()->GetAI()->SetData(DATA_PORTAL_PERIODIC_TICK, aurEff->GetTickNumber()); +                if (UnitAI* targetAI = GetTarget()->GetAI()) +                    targetAI->SetData(DATA_PORTAL_PERIODIC_TICK, aurEff->GetTickNumber());              }              void Register() override diff --git a/src/server/scripts/Northrend/zone_storm_peaks.cpp b/src/server/scripts/Northrend/zone_storm_peaks.cpp index 302cdd7704a..9fc29686972 100644 --- a/src/server/scripts/Northrend/zone_storm_peaks.cpp +++ b/src/server/scripts/Northrend/zone_storm_peaks.cpp @@ -364,7 +364,7 @@ public:          }          void JustDied(Unit* /*killer*/) override { } -        void OnCharmed(bool /*apply*/) override { } +        void OnCharmed(bool /*isNew*/) override { }          void UpdateAI(uint32 diff) override          { diff --git a/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/boss_blackheart_the_inciter.cpp b/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/boss_blackheart_the_inciter.cpp index 850e3379213..81dcb72821b 100644 --- a/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/boss_blackheart_the_inciter.cpp +++ b/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/boss_blackheart_the_inciter.cpp @@ -58,16 +58,15 @@ enum Events  class BlackheartCharmedPlayerAI : public SimpleCharmedPlayerAI  {      using SimpleCharmedPlayerAI::SimpleCharmedPlayerAI; -    void OnCharmed(bool apply) override +    void OnCharmed(bool isNew) override      { -        SimpleCharmedPlayerAI::OnCharmed(apply); -        if (!me->GetMap()->IsDungeon()) -            return; -        if (Creature* blackheart = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(DATA_BLACKHEART_THE_INCITER))) -        { -            blackheart->AI()->SetData(0, apply); -            blackheart->GetThreatManager().AddThreat(me, 0.0f); -        } +        if (me->GetMap()->IsDungeon()) +            if (Creature* blackheart = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(DATA_BLACKHEART_THE_INCITER))) +            { +                blackheart->AI()->SetData(0, me->IsCharmed()); +                blackheart->GetThreatManager().AddThreat(me, 0.0f); +            } +        SimpleCharmedPlayerAI::OnCharmed(isNew);      }  }; diff --git a/src/server/scripts/Spells/spell_dk.cpp b/src/server/scripts/Spells/spell_dk.cpp index 9d79f6d2398..5dbad258d65 100644 --- a/src/server/scripts/Spells/spell_dk.cpp +++ b/src/server/scripts/Spells/spell_dk.cpp @@ -2914,20 +2914,14 @@ public:              if (ghoulGuid.IsEmpty())                  return; -            oldAI = player->AI(); -            oldAIState = player->IsAIEnabled;              player->SetAI(new player_ghoulAI(player, ghoulGuid)); -            player->IsAIEnabled = true;          }          void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)          {              Player* player = GetTarget()->ToPlayer(); -            player->IsAIEnabled = oldAIState; -            PlayerAI* thisAI = player->AI(); -            player->SetAI(oldAI); -            delete thisAI; +            player->SetAI(nullptr);              // Dismiss ghoul if necessary              if (Creature* ghoul = ObjectAccessor::GetCreature(*player, ghoulGuid)) @@ -2946,8 +2940,6 @@ public:          }          ObjectGuid ghoulGuid; -        PlayerAI* oldAI = nullptr; -        bool oldAIState = false;      };      AuraScript* GetAuraScript() const override diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp index 2ff9d51dc8b..543a566df62 100644 --- a/src/server/scripts/Spells/spell_generic.cpp +++ b/src/server/scripts/Spells/spell_generic.cpp @@ -1647,7 +1647,7 @@ class spell_ethereal_pet_aura : public AuraScript          GetUnitOwner()->GetAllMinionsByEntry(minionList, NPC_ETHEREAL_SOUL_TRADER);          for (Creature* minion : minionList)          { -            if (minion->IsAIEnabled)  +            if (minion->IsAIEnabled())              {                  minion->AI()->Talk(SAY_STEAL_ESSENCE);                  minion->CastSpell(eventInfo.GetProcTarget(), SPELL_STEAL_ESSENCE_VISUAL); diff --git a/src/server/scripts/Spells/spell_quest.cpp b/src/server/scripts/Spells/spell_quest.cpp index 63d084e589b..09c5238bc51 100644 --- a/src/server/scripts/Spells/spell_quest.cpp +++ b/src/server/scripts/Spells/spell_quest.cpp @@ -54,8 +54,8 @@ class spell_generic_quest_update_entry_SpellScript : public SpellScript                  if (!creatureTarget->IsPet() && creatureTarget->GetEntry() == _originalEntry)                  {                      creatureTarget->UpdateEntry(_newEntry); -                    if (_shouldAttack && creatureTarget->IsAIEnabled) -                        creatureTarget->AI()->AttackStart(GetCaster()); +                    if (_shouldAttack) +                        creatureTarget->EngageWithTarget(GetCaster());                      if (_despawnTime)                          creatureTarget->DespawnOrUnsummon(_despawnTime);  | 
