aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/server/game/Entities/Creature/Creature.cpp13
-rw-r--r--src/server/game/Entities/Creature/CreatureGroups.cpp29
-rw-r--r--src/server/game/Entities/Creature/CreatureGroups.h8
-rw-r--r--src/server/game/Maps/ZoneScript.cpp7
-rw-r--r--src/server/game/Maps/ZoneScript.h12
5 files changed, 63 insertions, 6 deletions
diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp
index d466920c81f..9b3a159e2f7 100644
--- a/src/server/game/Entities/Creature/Creature.cpp
+++ b/src/server/game/Entities/Creature/Creature.cpp
@@ -362,7 +362,7 @@ void Creature::RemoveFromWorld()
GetZoneScript()->OnCreatureRemove(this);
if (m_formation)
- sFormationMgr->RemoveCreatureFromGroup(m_formation, this);
+ FormationMgr::RemoveCreatureFromGroup(m_formation, this);
Unit::RemoveFromWorld();
@@ -2216,8 +2216,15 @@ void Creature::setDeathState(DeathState s)
SetNoSearchAssistance(false);
//Dismiss group if is leader
- if (m_formation && m_formation->GetLeader() == this)
- m_formation->FormationReset(true);
+ if (m_formation)
+ {
+ if (m_formation->GetLeader() == this)
+ m_formation->FormationReset(true);
+
+ if (ZoneScript* script = GetZoneScript())
+ if (!m_formation->HasAliveMembers())
+ script->OnCreatureGroupDepleted(m_formation);
+ }
bool needsFalling = (IsFlying() || IsHovering()) && !IsUnderWater() && !HasUnitState(UNIT_STATE_ROOT);
SetHover(false, false);
diff --git a/src/server/game/Entities/Creature/CreatureGroups.cpp b/src/server/game/Entities/Creature/CreatureGroups.cpp
index 4f04f26ea90..179e3c5179f 100644
--- a/src/server/game/Entities/Creature/CreatureGroups.cpp
+++ b/src/server/game/Entities/Creature/CreatureGroups.cpp
@@ -25,6 +25,7 @@
#include "MotionMaster.h"
#include "MovementGenerator.h"
#include "ObjectMgr.h"
+#include "ZoneScript.h"
FormationMgr::FormationMgr() = default;
FormationMgr::~FormationMgr() = default;
@@ -74,6 +75,12 @@ void FormationMgr::RemoveCreatureFromGroup(CreatureGroup* group, Creature* membe
TC_LOG_DEBUG("entities.unit", "Deleting member pointer to GUID: {} from group {}", leaderSpawnId, member->GetSpawnId());
group->RemoveMember(member);
+ // If removed member was alive we need to check if we have any other alive members
+ // if not - fire OnCreatureGroupDepleted
+ if (ZoneScript* script = member->GetZoneScript())
+ if (member->IsAlive() && !group->HasAliveMembers())
+ script->OnCreatureGroupDepleted(group);
+
if (group->IsEmpty())
{
if (leaderSpawnId)
@@ -302,3 +309,25 @@ bool CreatureGroup::CanLeaderStartMoving() const
return true;
}
+
+bool CreatureGroup::HasAliveMembers() const
+{
+ return std::ranges::any_of(_members, [](Creature const* member) { return member->IsAlive(); }, &MembersMap::value_type::first);
+}
+
+bool CreatureGroup::LeaderHasStringId(std::string_view id) const
+{
+ if (_leader)
+ return _leader->HasStringId(id);
+
+ if (CreatureData const* leaderCreatureData = sObjectMgr->GetCreatureData(_leaderSpawnId))
+ {
+ if (leaderCreatureData->StringId == id)
+ return true;
+
+ if (ASSERT_NOTNULL(sObjectMgr->GetCreatureTemplate(leaderCreatureData->id))->StringId == id)
+ return true;
+ }
+
+ return false;
+}
diff --git a/src/server/game/Entities/Creature/CreatureGroups.h b/src/server/game/Entities/Creature/CreatureGroups.h
index be8a9967bf5..c7afaa1cedd 100644
--- a/src/server/game/Entities/Creature/CreatureGroups.h
+++ b/src/server/game/Entities/Creature/CreatureGroups.h
@@ -74,7 +74,9 @@ class TC_GAME_API CreatureGroup
{
private:
Creature* _leader;
- std::unordered_map<Creature*, FormationInfo*> _members;
+
+ using MembersMap = std::unordered_map<Creature*, FormationInfo*>;
+ MembersMap _members;
ObjectGuid::LowType _leaderSpawnId;
bool _formed;
@@ -103,6 +105,10 @@ class TC_GAME_API CreatureGroup
void LeaderStartedMoving();
void MemberEngagingTarget(Creature* member, Unit* target);
bool CanLeaderStartMoving() const;
+
+ bool HasAliveMembers() const;
+
+ bool LeaderHasStringId(std::string_view id) const;
};
#define sFormationMgr FormationMgr::instance()
diff --git a/src/server/game/Maps/ZoneScript.cpp b/src/server/game/Maps/ZoneScript.cpp
index 03ddf65e6cb..599847d911a 100644
--- a/src/server/game/Maps/ZoneScript.cpp
+++ b/src/server/game/Maps/ZoneScript.cpp
@@ -19,6 +19,13 @@
#include "Creature.h"
#include "GameEventSender.h"
+ControlZoneHandler::ControlZoneHandler() = default;
+ControlZoneHandler::ControlZoneHandler(ControlZoneHandler const& right) = default;
+ControlZoneHandler::ControlZoneHandler(ControlZoneHandler&& right) noexcept = default;
+ControlZoneHandler& ControlZoneHandler::operator=(ControlZoneHandler const& right) = default;
+ControlZoneHandler& ControlZoneHandler::operator=(ControlZoneHandler&& right) noexcept = default;
+ControlZoneHandler::~ControlZoneHandler() = default;
+
ZoneScript::ZoneScript() = default;
ZoneScript::ZoneScript(ZoneScript const& right) = default;
ZoneScript::ZoneScript(ZoneScript&& right) noexcept = default;
diff --git a/src/server/game/Maps/ZoneScript.h b/src/server/game/Maps/ZoneScript.h
index 3fd9e85aa19..8f37b2a3cf5 100644
--- a/src/server/game/Maps/ZoneScript.h
+++ b/src/server/game/Maps/ZoneScript.h
@@ -23,6 +23,7 @@
class AreaTrigger;
class Creature;
+class CreatureGroup;
class GameObject;
class Player;
class Unit;
@@ -41,8 +42,12 @@ enum class EncounterType : uint8
class TC_GAME_API ControlZoneHandler
{
public:
- explicit ControlZoneHandler() = default;
- virtual ~ControlZoneHandler() = default;
+ explicit ControlZoneHandler();
+ ControlZoneHandler(ControlZoneHandler const& right);
+ ControlZoneHandler(ControlZoneHandler&& right) noexcept;
+ ControlZoneHandler& operator=(ControlZoneHandler const& right);
+ ControlZoneHandler& operator=(ControlZoneHandler&& right) noexcept;
+ virtual ~ControlZoneHandler();
virtual void HandleCaptureEventHorde([[maybe_unused]] GameObject* controlZone) { }
virtual void HandleCaptureEventAlliance([[maybe_unused]] GameObject* controlZone) { }
@@ -79,6 +84,9 @@ class TC_GAME_API ZoneScript
virtual void OnUnitDeath([[maybe_unused]] Unit* unit) { }
+ // Triggers when the CreatureGroup no longer has any alive members (either last alive member dies or is removed from the group)
+ virtual void OnCreatureGroupDepleted([[maybe_unused]] CreatureGroup const* creatureGroup) { }
+
//All-purpose data storage ObjectGuid
virtual ObjectGuid GetGuidData(uint32 /*DataId*/) const { return ObjectGuid::Empty; }
virtual void SetGuidData(uint32 /*DataId*/, ObjectGuid /*Value*/) { }