aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/game/Entities/Creature/Creature.cpp3
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp63
-rw-r--r--src/server/game/Entities/Unit/Unit.h15
-rw-r--r--src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_scourgelord_tyrannus.cpp4
-rw-r--r--src/server/scripts/Spells/spell_dk.cpp4
5 files changed, 60 insertions, 29 deletions
diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp
index 7da8902842c..371b588e5e8 100644
--- a/src/server/game/Entities/Creature/Creature.cpp
+++ b/src/server/game/Entities/Creature/Creature.cpp
@@ -949,7 +949,8 @@ void Creature::DoFleeToGetAssistance()
bool Creature::AIM_Destroy()
{
- SetAI(nullptr);
+ PopAI();
+ RefreshAI();
return true;
}
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index d424210000f..366b330d507 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -63,6 +63,7 @@
#include "TemporarySummon.h"
#include "Transport.h"
#include "Totem.h"
+#include "UnitAI.h"
#include "UpdateFieldFlags.h"
#include "Util.h"
#include "Vehicle.h"
@@ -451,8 +452,9 @@ void Unit::Update(uint32 p_time)
UpdateSplineMovement(p_time);
i_motionMaster->Update(p_time);
- if (!i_AI && (GetTypeId() != TYPEID_PLAYER || IsCharmed()))
+ if (!GetAI() && (GetTypeId() != TYPEID_PLAYER || IsCharmed()))
UpdateCharmAI();
+ RefreshAI();
}
bool Unit::haveOffhandWeapon() const
@@ -9409,37 +9411,56 @@ void Unit::AIUpdateTick(uint32 diff)
}
}
+void Unit::PushAI(UnitAI* newAI)
+{
+ i_AIs.emplace(newAI);
+}
+
void Unit::SetAI(UnitAI* newAI)
{
- ASSERT(!m_aiLocked, "Attempt to replace AI during AI update tick");
- i_AI.reset(newAI);
+ PushAI(newAI);
+ RefreshAI();
+}
+
+bool Unit::PopAI()
+{
+ if (!i_AIs.empty())
+ {
+ i_AIs.pop();
+ return true;
+ }
+ else
+ return false;
+}
+
+void Unit::RefreshAI()
+{
+ ASSERT(!m_aiLocked, "Tried to change current AI during UpdateAI()");
+ if (i_AIs.empty())
+ i_AI = nullptr;
+ else
+ i_AI = i_AIs.top();
}
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 if (m_aiLocked)
+ PushAI(nullptr);
+ else
{
- ASSERT(!i_lockedAILifetimeExtension, "Attempt to schedule multiple charm AI changes during one update");
- i_lockedAILifetimeExtension = std::move(i_AI); // AI needs to live just a bit longer to finish its UpdateAI
+ RestoreDisabledAI();
+ PushAI(nullptr); //This could actually be PopAI() to get the previous AI but it's required atm to trigger UpdateCharmAI()
}
- 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);
- i_lockedAILifetimeExtension.reset();
+ // Keep popping the stack until we either reach the bottom or find a valid AI
+ while (PopAI())
+ if (GetTopAI())
+ return;
}
void Unit::AddToWorld()
@@ -9559,14 +9580,16 @@ void Unit::UpdateCharmAI()
}
ASSERT(newAI);
- i_AI.reset(newAI);
+ SetAI(newAI);
newAI->OnCharmed(true);
}
else
{
RestoreDisabledAI();
- if (i_AI)
- i_AI->OnCharmed(true);
+ // Hack: this is required because we want to call OnCharmed(true) on the restored AI
+ RefreshAI();
+ if (UnitAI* ai = GetAI())
+ ai->OnCharmed(true);
}
}
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index f8832dff52a..0a787f04de5 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -29,6 +29,7 @@
#include "Util.h"
#include <map>
#include <memory>
+#include <stack>
#define VISUAL_WAYPOINT 1 // Creature Entry ID used for waypoints show, visible only for GMs
#define WORLD_TRIGGER 12999
@@ -767,8 +768,14 @@ class TC_GAME_API Unit : public WorldObject
bool IsAIEnabled() const { return (i_AI != nullptr); }
void AIUpdateTick(uint32 diff);
UnitAI* GetAI() const { return i_AI.get(); }
- void SetAI(UnitAI* newAI);
void ScheduleAIChange();
+ void PushAI(UnitAI* newAI);
+ bool PopAI();
+ protected:
+ void SetAI(UnitAI* newAI);
+ UnitAI* GetTopAI() const { return i_AIs.empty() ? nullptr : i_AIs.top().get(); }
+ void RefreshAI();
+ public:
void AddToWorld() override;
void RemoveFromWorld() override;
@@ -1791,9 +1798,9 @@ class TC_GAME_API Unit : public WorldObject
void UpdateCharmAI();
void RestoreDisabledAI();
- std::unique_ptr<UnitAI> i_AI;
- std::unique_ptr<UnitAI> i_disabledAI;
- std::unique_ptr<UnitAI> i_lockedAILifetimeExtension; // yes, this lifetime extension is terrible
+ typedef std::stack<std::shared_ptr<UnitAI>> UnitAIStack;
+ UnitAIStack i_AIs;
+ std::shared_ptr<UnitAI> i_AI;
bool m_aiLocked;
std::unordered_set<AbstractFollower*> m_followingMe;
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 a813c84994c..f76da2e1c95 100644
--- a/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_scourgelord_tyrannus.cpp
+++ b/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_scourgelord_tyrannus.cpp
@@ -447,7 +447,7 @@ class spell_tyrannus_overlord_brand : public SpellScriptLoader
return;
Player* pTarget = GetTarget()->ToPlayer();
- GetTarget()->SetAI(new player_overlord_brandAI(pTarget, GetCasterGUID()));
+ GetTarget()->PushAI(new player_overlord_brandAI(pTarget, GetCasterGUID()));
}
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
@@ -455,7 +455,7 @@ class spell_tyrannus_overlord_brand : public SpellScriptLoader
if (GetTarget()->GetTypeId() != TYPEID_PLAYER)
return;
- GetTarget()->SetAI(nullptr);
+ GetTarget()->PopAI();
}
void Register() override
diff --git a/src/server/scripts/Spells/spell_dk.cpp b/src/server/scripts/Spells/spell_dk.cpp
index 43020beaa9b..5739c27ee33 100644
--- a/src/server/scripts/Spells/spell_dk.cpp
+++ b/src/server/scripts/Spells/spell_dk.cpp
@@ -2914,14 +2914,14 @@ public:
if (ghoulGuid.IsEmpty())
return;
- player->SetAI(new player_ghoulAI(player, ghoulGuid));
+ player->PushAI(new player_ghoulAI(player, ghoulGuid));
}
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
Player* player = GetTarget()->ToPlayer();
- player->SetAI(nullptr);
+ player->PopAI();
// Dismiss ghoul if necessary
if (Creature* ghoul = ObjectAccessor::GetCreature(*player, ghoulGuid))