diff options
| author | Treeston <treeston.mmoc@gmail.com> | 2018-08-23 14:33:28 +0200 |
|---|---|---|
| committer | Treeston <treeston.mmoc@gmail.com> | 2018-08-23 16:34:42 +0200 |
| commit | 042f5515e4f3e52b0d2e23d9b9e147041849ce12 (patch) | |
| tree | e9bd421089edfd6098a96300393d086875f9a054 /src/server/game | |
| parent | 0e4a49b0a4c86eb4a2d0d128e24bc8aaabb47e31 (diff) | |
Core/AI: Clean up charm AI handling, we now have two unique_ptr instead of a crapton of booleans
Diffstat (limited to 'src/server/game')
37 files changed, 249 insertions, 308 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); |
