Core/Creatures: moved despawning summons upon summoner death to SummonInfo API and implemented more specific despawn rules

This commit is contained in:
Ovahlord committed 2025-08-24 13:23:45 +02:00
1 parent c77ed42bf2
commit 0e5489a9da
5 files changed
+65 -5

No files matched your search

@@ -32,7 +32,8 @@
SummonInfo::SummonInfo(Creature* summonedCreature, SummonInfoArgs const& args) :
_summonedCreature(ASSERT_NOTNULL(summonedCreature)), _summonerGUID(args.Summoner ? args.Summoner->GetGUID() : ObjectGuid::Empty),
_remainingDuration(args.Duration), _maxHealth(args.MaxHealth), _creatureLevel(args.CreatureLevel),
_flags(SummonPropertiesFlags::None), _control(SummonPropertiesControl::None), _summonSlot(SummonPropertiesSlot::None)
_flags(SummonPropertiesFlags::None), _control(SummonPropertiesControl::None), _summonSlot(SummonPropertiesSlot::None),
_hasBeenSummonedByCreature(args.Summoner ? args.Summoner->IsCreature() : false)
{
if (args.SummonPropertiesId.has_value())
InitializeSummonProperties(*args.SummonPropertiesId, Object::ToUnit(args.Summoner));
@@ -59,7 +60,7 @@ void SummonInfo::InitializeSummonProperties(uint32 summonPropertiesId, Unit cons
if (_flags.HasFlag(SummonPropertiesFlags::UseSummonerFaction))
_factionId = summoner->GetFaction();
if (_control != SummonPropertiesControl::None)
if (IsControlledBySummoner())
{
// Controlled summons inherit the level of their summoner unless explicitly stated otherwise.
// Level can be overridden either by SummonPropertiesFlags::UseCreatureLevel or by a spell effect value
@@ -234,7 +235,20 @@ void SummonInfo::UpdateRemainingDuration(Milliseconds deltaTime)
bool SummonInfo::DespawnsOnSummonerLogout() const
{
return _flags.HasFlag(SummonPropertiesFlags::DespawnOnSummonerLogout);
if (_flags.HasFlag(SummonPropertiesFlags::DespawnOnSummonerLogout))
return true;
if (IsControlledBySummoner())
{
// Controlled creatures summoned by a creature will only despawn when not engaged
if (_hasBeenSummonedByCreature)
return !_summonedCreature->IsEngaged();
// Player controlled summons, however, always despawn
return true;
}
return false;
}
void SummonInfo::SetDespawnOnSummonerLogout(bool set)
@@ -247,7 +261,20 @@ void SummonInfo::SetDespawnOnSummonerLogout(bool set)
bool SummonInfo::DespawnsOnSummonerDeath() const
{
return _flags.HasFlag(SummonPropertiesFlags::DespawnOnSummonerDeath);
if (_flags.HasFlag(SummonPropertiesFlags::DespawnOnSummonerDeath))
return true;
if (IsControlledBySummoner())
{
// Controlled creatures summoned by a creature will only despawn when not engaged (they will despawn when reaching home)
if (_hasBeenSummonedByCreature)
return !_summonedCreature->IsEngaged();
// Player controlled summons, however, always despawn
return true;
}
return false;
}
void SummonInfo::SetDespawnOnSummonerDeath(bool set)
@@ -114,6 +114,7 @@ private:
EnumFlag<SummonPropertiesFlags> _flags;
SummonPropertiesControl _control;
SummonPropertiesSlot _summonSlot;
bool _hasBeenSummonedByCreature;
};
#endif // _SummonInfo_h__
+15 -1
View File
@@ -8606,7 +8606,8 @@ void Unit::setDeathState(DeathState s)
ExitVehicle(); // Exit vehicle before calling RemoveAllControlled
// vehicles use special type of charm that is not removed by the next function
// triggering an assert
UnsummonAllTotems();
DespawnSummonsOnSummonerDeath();
RemoveAllControlled();
RemoveAllAurasOnDeath();
}
@@ -8889,6 +8890,19 @@ void Unit::DespawnSummonsOnSummonerLogout()
summon->GetSummonedCreature()->DespawnOrUnsummon();
}
void Unit::DespawnSummonsOnSummonerDeath()
{
std::vector<SummonInfo*> slottedSummons = _slottedSummons;
for (SummonInfo* summon : slottedSummons)
if (summon && summon->DespawnsOnSummonerDeath())
summon->GetSummonedCreature()->DespawnOrUnsummon();
std::vector<SummonInfo*> wildSummons = _wildSummons;
for (SummonInfo* summon : wildSummons)
if (summon->DespawnsOnSummonerDeath())
summon->GetSummonedCreature()->DespawnOrUnsummon();
}
SummonInfo* Unit::GetSummonInSlot(SummonPropertiesSlot slot) const
{
if (slot == SummonPropertiesSlot::None ||
+2
View File
@@ -1339,6 +1339,8 @@ class TC_GAME_API Unit : public WorldObject
void UnregisterSummon(SummonInfo* summon);
// Despawns all summons that should despawn when the summoner logs out or despawns
void DespawnSummonsOnSummonerLogout();
// Despawns all summons that should despawn when the summoner dies
void DespawnSummonsOnSummonerDeath();
// Returns the currently active summon that is the summoner's specified summon slot
SummonInfo* GetSummonInSlot(SummonPropertiesSlot slot) const;
@@ -21,6 +21,7 @@
#include "MoveSpline.h"
#include "MoveSplineInit.h"
#include "PathGenerator.h"
#include "SummonInfo.h"
#include "Vehicle.h"
template<class T>
@@ -81,6 +82,21 @@ void HomeMovementGenerator<Creature>::DoFinalize(Creature* owner)
{
if (_arrived)
{
// Creature controlled summons may persist for the remainder of a combat interaction.
// However, they do despawn upon reaching home when the summoner is either dead or gone
if (SummonInfo* summonInfo = owner->GetSummonInfo())
{
if (summonInfo->IsControlledBySummoner())
{
Unit* summoner = summonInfo->GetUnitSummoner();
if (!summoner || !summoner->IsAlive())
{
owner->DespawnOrUnsummon();
return;
}
}
}
if (owner->IsStateRestoredOnEvade())
{
owner->ClearUnitState(UNIT_STATE_EVADE);