diff options
author | Treeston <treeston.mmoc@gmail.com> | 2018-08-23 14:33:28 +0200 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2021-10-22 23:47:51 +0200 |
commit | e4e8c1c59c8b37216814526b4d2551f23934f465 (patch) | |
tree | a135fb3fc2adff0bded65f29d0e165b668a63c5c /src | |
parent | 6a91fe3fbe28e3bf36ab6107b9c6cbb842f65262 (diff) |
Core/AI: Clean up charm AI handling, we now have two unique_ptr instead of a crapton of booleans
(cherry picked from commit 042f5515e4f3e52b0d2e23d9b9e147041849ce12)
Diffstat (limited to 'src')
67 files changed, 310 insertions, 395 deletions
diff --git a/src/server/game/AI/CoreAI/CombatAI.cpp b/src/server/game/AI/CoreAI/CombatAI.cpp index f0696db80f3..b4720802236 100644 --- a/src/server/game/AI/CoreAI/CombatAI.cpp +++ b/src/server/game/AI/CoreAI/CombatAI.cpp @@ -299,13 +299,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 58a6414b00e..cfec8f91e41 100644 --- a/src/server/game/AI/CoreAI/CombatAI.h +++ b/src/server/game/AI/CoreAI/CombatAI.h @@ -102,7 +102,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 02f54b13cd3..701d1a3dc42 100644 --- a/src/server/game/AI/CoreAI/PassiveAI.cpp +++ b/src/server/game/AI/CoreAI/PassiveAI.cpp @@ -68,12 +68,6 @@ void PossessedAI::KilledUnit(Unit* victim) me->RemoveDynamicFlag(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 9dc33ec02b9..d8621ae40f1 100644 --- a/src/server/game/AI/CoreAI/PassiveAI.h +++ b/src/server/game/AI/CoreAI/PassiveAI.h @@ -45,8 +45,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; } }; @@ -59,7 +57,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 de6c5c2308c..1c01ddf55d3 100644 --- a/src/server/game/AI/CoreAI/PetAI.cpp +++ b/src/server/game/AI/CoreAI/PetAI.cpp @@ -612,12 +612,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 57cbc9ca404..091b06378ee 100644 --- a/src/server/game/AI/CoreAI/PetAI.h +++ b/src/server/game/AI/CoreAI/PetAI.h @@ -51,8 +51,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 2665379e779..fe16a56497f 100644 --- a/src/server/game/AI/CoreAI/UnitAI.cpp +++ b/src/server/game/AI/CoreAI/UnitAI.cpp @@ -48,6 +48,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 bcfa93f33f3..5e5f657b08a 100644 --- a/src/server/game/AI/CoreAI/UnitAI.h +++ b/src/server/game/AI/CoreAI/UnitAI.h @@ -144,8 +144,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 a966829b07f..84c549553dd 100644 --- a/src/server/game/AI/CreatureAI.cpp +++ b/src/server/game/AI/CreatureAI.cpp @@ -27,6 +27,7 @@ #include "Map.h" #include "MapReference.h" #include "MotionMaster.h" +#include "ObjectAccessor.h" #include "Player.h" #include "SpellMgr.h" #include "TemporarySummon.h" @@ -34,13 +35,16 @@ #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.IsEmpty()) { - 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(); } + UnitAI::OnCharmed(isNew); } std::unordered_map<std::pair<uint32, Difficulty>, AISpellInfoType> UnitAI::AISpellInfo; diff --git a/src/server/game/AI/CreatureAI.h b/src/server/game/AI/CreatureAI.h index f68d76a5780..f2ff2ef4fb5 100644 --- a/src/server/game/AI/CreatureAI.h +++ b/src/server/game/AI/CreatureAI.h @@ -131,7 +131,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 when a spell cast gets interrupted virtual void OnSpellCastInterrupt(SpellInfo const* /*spell*/) { } diff --git a/src/server/game/AI/PlayerAI/PlayerAI.cpp b/src/server/game/AI/PlayerAI/PlayerAI.cpp index fb359ea6cb2..9dd296a7924 100644 --- a/src/server/game/AI/PlayerAI/PlayerAI.cpp +++ b/src/server/game/AI/PlayerAI/PlayerAI.cpp @@ -691,7 +691,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; } @@ -1325,9 +1329,9 @@ void SimpleCharmedPlayerAI::UpdateAI(const uint32 diff) } } -void SimpleCharmedPlayerAI::OnCharmed(bool apply) +void SimpleCharmedPlayerAI::OnCharmed(bool isNew) { - if (apply) + if (me->IsCharmed()) { me->CastStop(); me->AttackStop(); @@ -1343,4 +1347,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 195f7cb03b2..1e129879bd6 100644 --- a/src/server/game/AI/PlayerAI/PlayerAI.h +++ b/src/server/game/AI/PlayerAI/PlayerAI.h @@ -28,8 +28,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 @@ -97,7 +95,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 88fd051f2aa..69681e171aa 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp +++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp @@ -47,7 +47,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); @@ -111,7 +111,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 a3231bc79b3..adbfa359177 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp +++ b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp @@ -151,13 +151,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 9ab05c55271..76b3778b060 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.cpp +++ b/src/server/game/AI/SmartScripts/SmartAI.cpp @@ -663,17 +663,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); @@ -684,7 +685,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 6c40f429c13..801981a676a 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.h +++ b/src/server/game/AI/SmartScripts/SmartAI.h @@ -141,7 +141,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 d183409eb62..b019d6816e5 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -1064,7 +1064,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 %s", me->GetGUID().ToString().c_str()); diff --git a/src/server/game/Combat/CombatManager.cpp b/src/server/game/Combat/CombatManager.cpp index 18e4e011351..68233d45b64 100644 --- a/src/server/game/Combat/CombatManager.cpp +++ b/src/server/game/Combat/CombatManager.cpp @@ -70,10 +70,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; @@ -113,8 +115,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() @@ -270,8 +272,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() @@ -291,7 +293,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 c2ff5571012..8ac3828b8cb 100644 --- a/src/server/game/Combat/ThreatManager.cpp +++ b/src/server/game/Combat/ThreatManager.cpp @@ -94,7 +94,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())) @@ -278,7 +278,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()); } @@ -382,8 +382,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 b0b6ca9b270..303fefc1547 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -318,15 +318,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 @@ -430,8 +421,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(); @@ -691,7 +682,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(); @@ -810,21 +801,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.IsEmpty()) - 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) { @@ -863,14 +841,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) @@ -906,8 +881,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; } @@ -1035,13 +1010,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; } @@ -1054,29 +1023,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; } @@ -1987,7 +1951,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; @@ -2250,8 +2214,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; @@ -2616,7 +2580,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 @@ -3432,8 +3396,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 9c53daa0efb..d840f0378f1 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -70,7 +70,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; @@ -158,11 +157,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()); } SpellSchoolMask GetMeleeDamageSchoolMask(WeaponAttackType /*attackType*/ = BASE_ATTACK) const override { return m_meleeDamageSchoolMask; } void SetMeleeDamageSchool(SpellSchools school) { m_meleeDamageSchoolMask = SpellSchoolMask(1 << school); } diff --git a/src/server/game/Entities/Creature/TemporarySummon.cpp b/src/server/game/Entities/Creature/TemporarySummon.cpp index 2f2ff710143..1ccb481c8a7 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 c49cc3a4ddb..7b0861bf83b 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -974,14 +974,7 @@ void Player::Update(uint32 p_time) if (!aura->IsPermanent()) aura->SetDuration(aura->GetSpellInfo()->GetMaxDuration()); - 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 131ea5b775c..988e350e8ba 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1089,7 +1089,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 f1c7b99c186..d4b032ef359 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -299,9 +299,8 @@ SpellNonMeleeDamage::SpellNonMeleeDamage(Unit* _attacker, Unit* _target, SpellIn 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), + LastCharmerGUID(), m_ControlledByPlayer(false), + movespline(new Movement::MoveSpline()), m_AutoRepeatFirstCast(false), m_procDeep(0), m_removedAurasCount(0), m_interruptMask(SpellAuraInterruptFlags::None), m_interruptMask2(SpellAuraInterruptFlags2::None), i_motionMaster(new MotionMaster(this)), m_regenTimer(0), m_vehicle(nullptr), m_vehicleKit(nullptr), m_unitTypeMask(UNIT_MASK_NONE), m_Diminishing(), m_combatManager(this), @@ -477,6 +476,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 @@ -676,11 +678,11 @@ bool Unit::HasBreakableByDamageCrowdControlAura(Unit* excludeCasterChannel) cons /*static*/ uint32 Unit::DealDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellInfo const* spellProto, bool durabilityLoss) { - 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); @@ -692,8 +694,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)) @@ -2885,7 +2887,7 @@ void Unit::InterruptSpell(CurrentSpellTypes spellType, bool withDelayed, bool wi spell->SetReferencedFromCurrent(false); } - if (GetTypeId() == TYPEID_UNIT && IsAIEnabled) + if (GetTypeId() == TYPEID_UNIT && IsAIEnabled()) ToCreature()->AI()->OnSpellCastInterrupt(spell->GetSpellInfo()); } } @@ -4892,14 +4894,14 @@ void Unit::UpdateStatBuffModForClient(Stats stat) void Unit::_RegisterDynObject(DynamicObject* dynObj) { m_dynObj.push_back(dynObj); - if (GetTypeId() == TYPEID_UNIT && IsAIEnabled) + if (GetTypeId() == TYPEID_UNIT && IsAIEnabled()) ToCreature()->AI()->JustRegisteredDynObject(dynObj); } void Unit::_UnregisterDynObject(DynamicObject* dynObj) { m_dynObj.remove(dynObj); - if (GetTypeId() == TYPEID_UNIT && IsAIEnabled) + if (GetTypeId() == TYPEID_UNIT && IsAIEnabled()) ToCreature()->AI()->JustUnregisteredDynObject(dynObj); } @@ -4975,7 +4977,7 @@ void Unit::AddGameObject(GameObject* gameObj) GetSpellHistory()->StartCooldown(createBySpell, 0, nullptr, true); } - if (GetTypeId() == TYPEID_UNIT && ToCreature()->IsAIEnabled) + if (GetTypeId() == TYPEID_UNIT && ToCreature()->IsAIEnabled()) ToCreature()->AI()->JustSummonedGameobject(gameObj); } @@ -5009,7 +5011,7 @@ void Unit::RemoveGameObject(GameObject* gameObj, bool del) m_gameObj.remove(gameObj); - if (GetTypeId() == TYPEID_UNIT && ToCreature()->IsAIEnabled) + if (GetTypeId() == TYPEID_UNIT && ToCreature()->IsAIEnabled()) ToCreature()->AI()->SummonedGameobjectDespawn(gameObj); if (del) @@ -5059,14 +5061,14 @@ void Unit::RemoveAllGameObjects() void Unit::_RegisterAreaTrigger(AreaTrigger* areaTrigger) { m_areaTrigger.push_back(areaTrigger); - if (GetTypeId() == TYPEID_UNIT && IsAIEnabled) + if (GetTypeId() == TYPEID_UNIT && IsAIEnabled()) ToCreature()->AI()->JustRegisteredAreaTrigger(areaTrigger); } void Unit::_UnregisterAreaTrigger(AreaTrigger* areaTrigger) { m_areaTrigger.erase(std::remove(m_areaTrigger.begin(), m_areaTrigger.end(), areaTrigger)); - if (GetTypeId() == TYPEID_UNIT && IsAIEnabled) + if (GetTypeId() == TYPEID_UNIT && IsAIEnabled()) ToCreature()->AI()->JustUnregisteredAreaTrigger(areaTrigger); } @@ -5501,8 +5503,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; @@ -6062,14 +6064,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)); @@ -9072,6 +9071,44 @@ int32 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() +{ + 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() { WorldObject::AddToWorld(); @@ -9087,8 +9124,8 @@ void Unit::RemoveFromWorld() if (IsInWorld()) { m_duringRemoveFromWorld = true; - if (IsAIEnabled) - GetAI()->LeavingWorld(); + if (UnitAI* ai = GetAI()) + ai->LeavingWorld(); if (IsVehicle()) RemoveVehicleKit(true); @@ -9161,80 +9198,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 = ASSERT_NOTNULL(sCreatureAIRegistry->GetRegistryItem("PossessedAI"))->Create(ToCreature()); - else - i_AI = ASSERT_NOTNULL(sCreatureAIRegistry->GetRegistryItem("PetAI"))->Create(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 = ASSERT_NOTNULL(sCreatureAIRegistry->GetRegistryItem("PossessedAI"))->Create(ToCreature()); + else + newAI = ASSERT_NOTNULL(sCreatureAIRegistry->GetRegistryItem("PetAI"))->Create(ToCreature()); + } + + ASSERT(newAI); + i_AI.reset(newAI); + newAI->OnCharmed(true); + AIUpdateTick(0, true); + } + else + { + RestoreDisabledAI(); + if (i_AI) + i_AI->OnCharmed(true); } } @@ -10494,7 +10495,7 @@ void Unit::SetMeleeAnimKitId(uint16 animKitId) plrVictim->SendDurabilityLoss(plrVictim, loss); } // 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 @@ -10521,16 +10522,16 @@ void Unit::SetMeleeAnimKitId(uint16 animKitId) } // 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 @@ -10926,7 +10927,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()) { @@ -10936,12 +10941,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); } @@ -11043,16 +11046,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) @@ -11099,16 +11095,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()) @@ -11824,7 +11815,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 82b94f3b096..df0e080915b 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -764,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; @@ -1277,7 +1280,6 @@ class TC_GAME_API Unit : public WorldObject void DeleteCharmInfo(); void SetPetNumberForClient(uint32 petNumber) { SetUpdateFieldValue(m_values.ModifyValue(&Unit::m_unitData).ModifyValue(&UF::UnitData::PetNumber), petNumber); } void SetPetNameTimestamp(uint32 timestamp) { SetUpdateFieldValue(m_values.ModifyValue(&Unit::m_unitData).ModifyValue(&UF::UnitData::PetNameTimestamp), timestamp); } - void UpdateCharmAI(); // returns the unit that this player IS CONTROLLING Unit* GetUnitBeingMoved() const; // returns the player that this player IS CONTROLLING @@ -1751,7 +1753,6 @@ class TC_GAME_API Unit : public WorldObject uint32 GetModelForForm(ShapeshiftForm form, uint32 spellId) const; friend class VehicleJoinEvent; - bool IsAIEnabled, NeedChangeAI; ObjectGuid LastCharmerGUID; bool CreateVehicleKit(uint32 id, uint32 creatureEntry, bool loading = false); void RemoveVehicleKit(bool onRemoveFromWorld = false); @@ -1851,8 +1852,6 @@ class TC_GAME_API Unit : public WorldObject void DestroyForPlayer(Player* target) const override; void ClearUpdateMask(bool remove) override; - UnitAI* i_AI, *i_disabledAI; - void _UpdateSpells(uint32 time); void _DeleteRemovedAuras(); @@ -1964,6 +1963,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; bool m_cleanupDone; // lock made to not add stuff after cleanup before delete diff --git a/src/server/game/Entities/Vehicle/Vehicle.cpp b/src/server/game/Entities/Vehicle/Vehicle.cpp index 152751c91ad..ad8d4653ce2 100644 --- a/src/server/game/Entities/Vehicle/Vehicle.cpp +++ b/src/server/game/Entities/Vehicle/Vehicle.cpp @@ -506,7 +506,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) @@ -851,8 +851,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 2cfa51dd402..8aaf83018b9 100644 --- a/src/server/game/Events/GameEventMgr.cpp +++ b/src/server/game/Events/GameEventMgr.cpp @@ -1661,7 +1661,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 b68d366dbfb..a223e55f0ac 100644 --- a/src/server/game/Grids/Notifiers/GridNotifiers.cpp +++ b/src/server/game/Grids/Notifiers/GridNotifiers.cpp @@ -132,10 +132,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 944649d68ba..2ec61224cd1 100644 --- a/src/server/game/Grids/Notifiers/GridNotifiers.h +++ b/src/server/game/Grids/Notifiers/GridNotifiers.h @@ -1160,8 +1160,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 67d9c4f00b0..a92119e7685 100644 --- a/src/server/game/Handlers/PetHandler.cpp +++ b/src/server/game/Handlers/PetHandler.cpp @@ -202,7 +202,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); @@ -373,9 +373,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 91bb0e3540c..e52393a97ad 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 0691ffe0fef..6d2544f8f89 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 6f5c0506b96..543d40eb332 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 e8f9a532194..c6056806c8e 100644 --- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp @@ -116,8 +116,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) @@ -255,10 +255,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); @@ -285,8 +285,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 { @@ -313,8 +313,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; } } @@ -323,8 +323,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 b5e587eb149..b1022b43967 100644 --- a/src/server/game/Scripting/ScriptMgr.cpp +++ b/src/server/game/Scripting/ScriptMgr.cpp @@ -479,7 +479,9 @@ class CreatureGameObjectAreaTriggerScriptRegistrySwapHooks 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 90d342e1b3d..22a1b24329c 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -2634,18 +2634,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); @@ -2694,7 +2692,7 @@ void Spell::GOTargetInfo::DoTargetSpellHit(Spell* spell, SpellEffectInfo const& 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); @@ -3316,8 +3314,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); @@ -3563,7 +3561,7 @@ void Spell::_cast(bool skipCheck) // Call CreatureAI hook OnSuccessfulSpellCast if (Creature* caster = m_originalCaster->ToCreature()) - if (caster->IsAIEnabled) + if (caster->IsAIEnabled()) caster->AI()->OnSuccessfulSpellCast(GetSpellInfo()); } diff --git a/src/server/scripts/Argus/AntorusTheBurningThrone/boss_garothi_worldbreaker.cpp b/src/server/scripts/Argus/AntorusTheBurningThrone/boss_garothi_worldbreaker.cpp index 525879f6cc7..f4cdd4c4360 100644 --- a/src/server/scripts/Argus/AntorusTheBurningThrone/boss_garothi_worldbreaker.cpp +++ b/src/server/scripts/Argus/AntorusTheBurningThrone/boss_garothi_worldbreaker.cpp @@ -560,7 +560,7 @@ class spell_garothi_fel_bombardment_selector : public SpellScript void HandleWarningEffect(SpellEffIndex /*effIndex*/) { Creature* caster = GetCaster() ? GetCaster()->ToCreature() : nullptr; - if (!caster || !caster->IsAIEnabled) + if (!caster || !caster->IsAIEnabled()) return; Unit* target = GetHitUnit(); @@ -693,7 +693,7 @@ class spell_garothi_decimation_selector : public SpellScript { caster->CastSpell(GetHitUnit(), SPELL_DECIMATION_WARNING, true); if (Creature* decimator = caster->ToCreature()) - if (decimator->IsAIEnabled) + if (decimator->IsAIEnabled()) decimator->AI()->Talk(SAY_ANNOUNCE_DECIMATION, GetHitUnit()); } } @@ -843,7 +843,7 @@ class spell_garothi_cannon_chooser : public SpellScript void HandleDummyEffect(SpellEffIndex /*effIndex*/) { Creature* caster = GetHitCreature(); - if (!caster || !caster->IsAIEnabled) + if (!caster || !caster->IsAIEnabled()) return; InstanceScript* instance = caster->GetInstanceScript(); diff --git a/src/server/scripts/Commands/cs_debug.cpp b/src/server/scripts/Commands/cs_debug.cpp index 752fcc19386..f78442af163 100644 --- a/src/server/scripts/Commands/cs_debug.cpp +++ b/src/server/scripts/Commands/cs_debug.cpp @@ -1354,10 +1354,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 8d6ba06b49a..229f1ea9b64 100644 --- a/src/server/scripts/Commands/cs_npc.cpp +++ b/src/server/scripts/Commands/cs_npc.cpp @@ -1584,7 +1584,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 95543c71159..b9fc7583725 100644 --- a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp @@ -396,7 +396,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/ZulAman/instance_zulaman.cpp b/src/server/scripts/EasternKingdoms/ZulAman/instance_zulaman.cpp index 8db37e7275a..3e473f74ad3 100644 --- a/src/server/scripts/EasternKingdoms/ZulAman/instance_zulaman.cpp +++ b/src/server/scripts/EasternKingdoms/ZulAman/instance_zulaman.cpp @@ -226,7 +226,7 @@ class instance_zulaman : public InstanceMapScript case EVENT_START_ZULAMAN: if (Creature* voljin = instance->GetCreature(VoljinGUID)) { - if (voljin->IsAIEnabled) + if (voljin->IsAIEnabled()) voljin->AI()->DoAction(ACTION_START_ZULAMAN); } break; diff --git a/src/server/scripts/Kalimdor/Firelands/boss_baleroc.cpp b/src/server/scripts/Kalimdor/Firelands/boss_baleroc.cpp index 2307954145d..ceda6ec369b 100644 --- a/src/server/scripts/Kalimdor/Firelands/boss_baleroc.cpp +++ b/src/server/scripts/Kalimdor/Firelands/boss_baleroc.cpp @@ -326,7 +326,7 @@ class spell_baleroc_blades_of_baleroc : public SpellScript void ChooseBlade(SpellEffIndex /*effIndex*/) { Creature* caster = GetCaster()->ToCreature(); - if (!caster || !caster->IsAIEnabled) + if (!caster || !caster->IsAIEnabled()) return; switch (urand(1, 2)) @@ -364,13 +364,13 @@ class spell_baleroc_inferno_blade : public AuraScript void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { - if (GetTarget()->IsAIEnabled) + if (GetTarget()->IsAIEnabled()) GetTarget()->GetAI()->DoAction(ACTION_EQUIP_INFERNO_BLADE); } void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { - if (GetTarget()->IsAIEnabled) + if (GetTarget()->IsAIEnabled()) GetTarget()->GetAI()->DoAction(ACTION_EQUIP_DEFAULT); } @@ -393,13 +393,13 @@ class spell_baleroc_decimation_blade : public AuraScript void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { - if (GetTarget()->IsAIEnabled) + if (GetTarget()->IsAIEnabled()) GetTarget()->GetAI()->DoAction(ACTION_EQUIP_DECIMATION_BLADE); } void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { - if (GetTarget()->IsAIEnabled) + if (GetTarget()->IsAIEnabled()) GetTarget()->GetAI()->DoAction(ACTION_EQUIP_DEFAULT); } diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_cthun.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_cthun.cpp index 8862eeb7eb4..11415bff291 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 c15529ec5d4..1d24d0e25ac 100644 --- a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp +++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp @@ -1614,7 +1614,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 b2658110776..fef166d403e 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 73fe05ed0f3..0ab9547e3f2 100644 --- a/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_scourgelord_tyrannus.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_scourgelord_tyrannus.cpp @@ -449,10 +449,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*/) @@ -460,10 +457,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 @@ -471,9 +465,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 7609c5c6992..1efd753228c 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp @@ -1786,7 +1786,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 0ec4ace8d67..b0daf19085c 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp @@ -629,7 +629,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 3de744e67aa..f74c3d0395f 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp @@ -2350,8 +2350,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 35787628e51..e056c325bf9 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp @@ -1282,7 +1282,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 028bd2d4974..1cad6aa47f8 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 25416696d1f..43d96cea444 100644 --- a/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp +++ b/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp @@ -834,7 +834,7 @@ public: { Creature* casterDiskSummon = me->SummonCreature(NPC_HOVER_DISK_CASTER, RangeHoverDisksSpawnPositions[rangeDisks]); - if (casterDiskSummon->IsAIEnabled) + if (casterDiskSummon->IsAIEnabled()) casterDiskSummon->AI()->DoAction(rangeDisks); } @@ -855,7 +855,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 706bf99204a..2e4a561dc56 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 6f6a52b763a..cd76f07a932 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_auriaya.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_auriaya.cpp @@ -553,7 +553,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))) @@ -583,7 +583,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 fe76f6c875d..20074dba079 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp @@ -496,8 +496,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 b78f7289f1e..b810c15411a 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp @@ -1709,7 +1709,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 6b4b3a1aa1f..73afc6f7e81 100644 --- a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_keleseth.cpp +++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_keleseth.cpp @@ -372,7 +372,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 334436bb49f..638cc511472 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 126d24da50c..1e20cbb4562 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 c79f707e650..9b72f64d13b 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()->RemoveUnitFlag2(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 2a2737bd127..1f22d400708 100644 --- a/src/server/scripts/Northrend/VioletHold/boss_moragg.cpp +++ b/src/server/scripts/Northrend/VioletHold/boss_moragg.cpp @@ -103,7 +103,7 @@ class spell_moragg_ray : public SpellScriptLoader { PreventDefaultAction(); - if (!GetTarget()->IsAIEnabled) + if (!GetTarget()->GetAI()) return; if (Unit* target = GetTarget()->GetAI()->SelectTarget(SELECT_TARGET_RANDOM, 0, 45.0f, true)) diff --git a/src/server/scripts/Northrend/VioletHold/violet_hold.cpp b/src/server/scripts/Northrend/VioletHold/violet_hold.cpp index 8febf564b50..7e705934f96 100644 --- a/src/server/scripts/Northrend/VioletHold/violet_hold.cpp +++ b/src/server/scripts/Northrend/VioletHold/violet_hold.cpp @@ -1368,8 +1368,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 958d068eb79..d64644bab46 100644 --- a/src/server/scripts/Northrend/zone_storm_peaks.cpp +++ b/src/server/scripts/Northrend/zone_storm_peaks.cpp @@ -365,7 +365,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 21bf50ee269..8bf5a4cc888 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 @@ -57,16 +57,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_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp index c203bda137c..83436b4986e 100644 --- a/src/server/scripts/Spells/spell_generic.cpp +++ b/src/server/scripts/Spells/spell_generic.cpp @@ -1536,7 +1536,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 991b7d275ec..d429eafd36b 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); |