Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
HKevinH committed Sep 25, 2023
2 parents 0c57cde + 33847e2 commit b146797
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 13 deletions.
13 changes: 13 additions & 0 deletions src/server/game/AI/CreatureAI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ static bool ShouldFollowOnSpawn(SummonPropertiesEntry const* properties)
return false;
}
}

void CreatureAI::JustAppeared()
{
if (!IsEngaged())
Expand Down Expand Up @@ -298,6 +299,7 @@ bool CreatureAI::_EnterEvadeMode(EvadeReason /*why*/)
return false;
}


me->RemoveAurasOnEvade();

me->CombatStop(true);
Expand All @@ -311,6 +313,17 @@ bool CreatureAI::_EnterEvadeMode(EvadeReason /*why*/)
me->SetTarget(ObjectGuid::Empty);
EngagementOver();

if (TempSummon* summon = me->ToTempSummon())
{
if (SummonPropertiesEntry const* properties = summon->m_Properties)
{ // Allied summons, pet summons join a formation unless the following exceptions are being met.
if ((properties->Flags & SUMMON_PROP_FLAG_DESPAWN_ON_SUMMONER_DEATH) || ((me->IsGuardian() || me->IsPet()) && !me->GetOwner()->IsAlive()))
{
me->DespawnOrUnsummon();
return true;
}
}
}
return true;
}

Expand Down
2 changes: 1 addition & 1 deletion src/server/game/DataStores/DBCEnums.h
Original file line number Diff line number Diff line change
Expand Up @@ -666,7 +666,7 @@ enum SummonPropFlags
SUMMON_PROP_FLAG_UNK1 = 0x00000001, // 75 spells in 3.0.3, something unfriendly
SUMMON_PROP_FLAG_UNK2 = 0x00000002, // 616 spells in 3.0.3, something friendly
SUMMON_PROP_FLAG_UNK3 = 0x00000004, // 22 spells in 3.0.3, no idea...
SUMMON_PROP_FLAG_UNK4 = 0x00000008, // 49 spells in 3.0.3, some mounts
SUMMON_PROP_FLAG_DESPAWN_ON_SUMMONER_DEATH = 0x00000008, // 49 spells in 3.0.3, some mounts, Despawns on Summoner Death
SUMMON_PROP_FLAG_PERSONAL_SPAWN = 0x00000010, // Only Visible to Summoner
SUMMON_PROP_FLAG_UNK6 = 0x00000020, // 0 spells in 3.3.5, unused
SUMMON_PROP_FLAG_UNK7 = 0x00000040, // 12 spells in 3.0.3, no idea
Expand Down
51 changes: 40 additions & 11 deletions src/server/game/Entities/Unit/Unit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6386,31 +6386,51 @@ Unit* Unit::GetFirstControlled() const
return unit;
}

void Unit::RemoveAllControlled()
// RemoveAllControlled gets called twice - in Unit::setDeathState() & void Unit::RemoveFromWorld()
// It removes charming effects, controlled vehicles and unsummons minions.
void Unit::RemoveAllControlled(bool onDeath /*= false*/)
{
// possessed pet and vehicle
if (GetTypeId() == TYPEID_PLAYER)
ToPlayer()->StopCastingCharm();

while (!m_Controlled.empty())
{
bool controlledKeepsFighting = false;

Unit* target = *m_Controlled.begin();
m_Controlled.erase(m_Controlled.begin());
if (target->GetCharmerGUID() == GetGUID())
target->RemoveCharmAuras();
// A pet/guardian should continue combat. Since we despawned every other summon type in UnsummonAllTotems(), we can waive on a additional type check and continue with IsSummon().
else if (target->GetOwnerOrCreatorGUID() == GetGUID() && target->IsSummon())
target->ToTempSummon()->UnSummon();
{
if (!(onDeath && !IsPlayer() && target->IsGuardian()))
{
target->ToTempSummon()->UnSummon();
}
if (!target->IsInCombat())
target->ToTempSummon()->UnSummon();
else
// we set this for edge case checks
controlledKeepsFighting = true;
}
else
LOG_ERROR("entities.unit", "Unit %u is trying to release unit %u which is neither charmed nor owned by it", GetEntry(), target->GetEntry());

// checking for edge cases
if (!controlledKeepsFighting)
{
if (GetPetGUID())
LOG_FATAL("entities.unit", "Unit %u is not able to release its pet %s", GetEntry(), GetPetGUID().ToString().c_str());
if (GetMinionGUID())
LOG_FATAL("entities.unit", "Unit %u is not able to release its minion %s", GetEntry(), GetMinionGUID().ToString().c_str());
if (GetCharmedGUID())
LOG_FATAL("entities.unit", "Unit %u is not able to release its charm %s", GetEntry(), GetCharmedGUID().ToString().c_str());
if (!IsPet()) // pets don't use the flag for this
RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PET_IN_COMBAT); // m_controlled is now empty, so we know none of our minions are in combat
}
}
if (GetPetGUID())
LOG_FATAL("entities.unit", "Unit %u is not able to release its pet %s", GetEntry(), GetPetGUID().ToString().c_str());
if (GetMinionGUID())
LOG_FATAL("entities.unit", "Unit %u is not able to release its minion %s", GetEntry(), GetMinionGUID().ToString().c_str());
if (GetCharmedGUID())
LOG_FATAL("entities.unit", "Unit %u is not able to release its charm %s", GetEntry(), GetCharmedGUID().ToString().c_str());
if (!IsPet()) // pets don't use the flag for this
RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PET_IN_COMBAT); // m_controlled is now empty, so we know none of our minions are in combat
}

bool Unit::isPossessedByPlayer() const { return HasUnitState(UNIT_STATE_POSSESSED) && GetCharmerGUID().IsPlayer(); }
Expand Down Expand Up @@ -6515,6 +6535,8 @@ void Unit::RemoveCharmAuras()
RemoveAurasByType(SPELL_AURA_AOE_CHARM);
}

// UnsummonAllTotems gets called twice - in Unit::setDeathState() & void Unit::RemoveFromWorld()
// It iterates through all summon slots and despawns the summons
void Unit::UnsummonAllTotems()
{
for (uint8 i = 0; i < MAX_SUMMON_SLOT; ++i)
Expand All @@ -6523,8 +6545,15 @@ void Unit::UnsummonAllTotems()
continue;

if (Creature* OldTotem = GetMap()->GetCreature(m_SummonSlot[i]))
{
if (OldTotem->IsSummon())
OldTotem->ToTempSummon()->UnSummon();
// We want to keep guardians and pets alive for now. A InCombat check is not needed here, we do this
// in void Unit::RemoveAllControlled()
{
if (!OldTotem->IsGuardian() && !OldTotem->IsPet())
OldTotem->ToTempSummon()->UnSummon();
}
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/server/game/Entities/Unit/Unit.h
Original file line number Diff line number Diff line change
Expand Up @@ -1302,7 +1302,7 @@ class FC_GAME_API Unit : public WorldObject

ControlList m_Controlled;
Unit* GetFirstControlled() const;
void RemoveAllControlled();
void RemoveAllControlled(bool onDeath = false);

bool IsCharmed() const { return !GetCharmerGUID().IsEmpty(); }
bool IsCharming() const { return !GetCharmedGUID().IsEmpty(); }
Expand Down

0 comments on commit b146797

Please sign in to comment.