fix(Core/Creature): Make Respawn() respect conditions and linked respawns (#17597)

This commit is contained in:
KJack
2023-11-26 06:48:58 -05:00
committed by GitHub
parent 2a7b507dd1
commit b7f7a7c731
2 changed files with 106 additions and 101 deletions
+105 -100
View File
@@ -622,40 +622,7 @@ void Creature::Update(uint32 diff)
time_t now = GameTime::GetGameTime().count(); time_t now = GameTime::GetGameTime().count();
if (m_respawnTime <= now) if (m_respawnTime <= now)
{ {
Respawn();
ConditionList conditions = sConditionMgr->GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_CREATURE_RESPAWN, GetEntry());
if (!sConditionMgr->IsObjectMeetToConditions(this, conditions))
{
// Creature should not respawn, reset respawn timer. Conditions will be checked again the next time it tries to respawn.
m_respawnTime = GameTime::GetGameTime().count() + m_respawnDelay;
break;
}
bool allowed = !IsAIEnabled || AI()->CanRespawn(); // First check if there are any scripts that prevent us respawning
if (!allowed) // Will be rechecked on next Update call
break;
ObjectGuid dbtableHighGuid = ObjectGuid::Create<HighGuid::Unit>(m_creatureData ? m_creatureData->id1 : GetEntry(), m_spawnId);
time_t linkedRespawntime = GetMap()->GetLinkedRespawnTime(dbtableHighGuid);
CreatureTemplate const* cInfo = sObjectMgr->GetCreatureTemplate(GetEntry());
if (!linkedRespawntime || (cInfo && cInfo->HasFlagsExtra(CREATURE_FLAG_EXTRA_HARD_RESET))) // Can respawn
Respawn();
else // the master is dead
{
ObjectGuid targetGuid = sObjectMgr->GetLinkedRespawnGuid(dbtableHighGuid);
if (targetGuid == dbtableHighGuid) // if linking self, never respawn (check delayed to next day)
{
SetRespawnTime(DAY);
}
else
{
m_respawnTime = (now > linkedRespawntime ? now : linkedRespawntime) + urand(5, MINUTE); // else copy time from master and add a little
}
SaveRespawnTime(); // also save to DB immediately
}
} }
break; break;
} }
@@ -2006,83 +1973,121 @@ void Creature::setDeathState(DeathState s, bool despawn)
void Creature::Respawn(bool force) void Creature::Respawn(bool force)
{ {
//DestroyForNearbyPlayers(); // pussywizard: not needed
if (force) if (force)
{ {
if (IsAlive()) if (IsAlive())
{
setDeathState(DeathState::JustDied); setDeathState(DeathState::JustDied);
}
else if (getDeathState() != DeathState::Corpse) else if (getDeathState() != DeathState::Corpse)
{
setDeathState(DeathState::Corpse); setDeathState(DeathState::Corpse);
}
} }
RemoveCorpse(false, false); ConditionList conditions = sConditionMgr->GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_CREATURE_RESPAWN, GetEntry());
if (getDeathState() == DeathState::Dead) if (!sConditionMgr->IsObjectMeetToConditions(this, conditions) && !force)
{ {
if (m_spawnId) // Creature should not respawn, reset respawn timer. Conditions will be checked again the next time it tries to respawn.
{ m_respawnTime = GameTime::GetGameTime().count() + m_respawnDelay;
GetMap()->RemoveCreatureRespawnTime(m_spawnId); return;
CreatureData const* data = sObjectMgr->GetCreatureData(m_spawnId); }
// Respawn check if spawn has 2 entries
if (data->id2) bool allowed = !IsAIEnabled || AI()->CanRespawn(); // First check if there are any scripts that prevent us respawning
{ if (!allowed && !force) // Will be rechecked on next Update call
uint32 entry = GetRandomId(data->id1, data->id2, data->id3); return;
UpdateEntry(entry, data, true); // Select Random Entry
m_defaultMovementType = MovementGeneratorType(data->movementType); // Reload Movement Type ObjectGuid dbtableHighGuid = ObjectGuid::Create<HighGuid::Unit>(m_creatureData ? m_creatureData->id1 : GetEntry(), m_spawnId);
LoadEquipment(data->equipmentId); // Reload Equipment time_t linkedRespawntime = GetMap()->GetLinkedRespawnTime(dbtableHighGuid);
AIM_Initialize(); // Reload AI
} CreatureTemplate const* cInfo = sObjectMgr->GetCreatureTemplate(GetEntry());
else
{ if (!linkedRespawntime || (cInfo && cInfo->HasFlagsExtra(CREATURE_FLAG_EXTRA_HARD_RESET)) || force) // Should respawn
if (m_originalEntry != GetEntry()) {
UpdateEntry(m_originalEntry); RemoveCorpse(false, false);
}
} if (getDeathState() == DeathState::Dead)
{
LOG_DEBUG("entities.unit", "Respawning creature {} (SpawnId: {}, {})", GetName(), GetSpawnId(), GetGUID().ToString()); if (m_spawnId)
m_respawnTime = 0; {
ResetPickPocketLootTime(); GetMap()->RemoveCreatureRespawnTime(m_spawnId);
loot.clear(); CreatureData const* data = sObjectMgr->GetCreatureData(m_spawnId);
SelectLevel(); // Respawn check if spawn has 2 entries
if (data->id2)
setDeathState(DeathState::JustRespawned); {
uint32 entry = GetRandomId(data->id1, data->id2, data->id3);
// MDic - Acidmanifesto UpdateEntry(entry, data, true); // Select Random Entry
// Do not override transform auras m_defaultMovementType = MovementGeneratorType(data->movementType); // Reload Movement Type
if (GetAuraEffectsByType(SPELL_AURA_TRANSFORM).empty()) LoadEquipment(data->equipmentId); // Reload Equipment
{ AIM_Initialize(); // Reload AI
uint32 displayID = GetNativeDisplayId(); }
if (sObjectMgr->GetCreatureModelRandomGender(&displayID)) // Cancel load if no model defined else
{ {
SetDisplayId(displayID); if (m_originalEntry != GetEntry())
SetNativeDisplayId(displayID); UpdateEntry(m_originalEntry);
} }
} }
GetMotionMaster()->InitDefault(); LOG_DEBUG("entities.unit", "Respawning creature {} (SpawnId: {}, {})", GetName(), GetSpawnId(), GetGUID().ToString());
m_respawnTime = 0;
//Call AI respawn virtual function ResetPickPocketLootTime();
if (IsAIEnabled) loot.clear();
{ SelectLevel();
//reset the AI to be sure no dirty or uninitialized values will be used till next tick
AI()->Reset(); setDeathState(DeathState::JustRespawned);
TriggerJustRespawned = true;//delay event to next tick so all creatures are created on the map before processing
} // MDic - Acidmanifesto
// Do not override transform auras
uint32 poolid = m_spawnId ? sPoolMgr->IsPartOfAPool<Creature>(m_spawnId) : 0; if (GetAuraEffectsByType(SPELL_AURA_TRANSFORM).empty())
if (poolid) {
sPoolMgr->UpdatePool<Creature>(poolid, m_spawnId); uint32 displayID = GetNativeDisplayId();
if (sObjectMgr->GetCreatureModelRandomGender(&displayID)) // Cancel load if no model defined
//Re-initialize reactstate that could be altered by movementgenerators {
InitializeReactState(); SetDisplayId(displayID);
SetNativeDisplayId(displayID);
m_respawnedTime = GameTime::GetGameTime().count(); }
}
GetMotionMaster()->InitDefault();
//Call AI respawn virtual function
if (IsAIEnabled)
{
//reset the AI to be sure no dirty or uninitialized values will be used till next tick
AI()->Reset();
TriggerJustRespawned = true;//delay event to next tick so all creatures are created on the map before processing
}
uint32 poolid = m_spawnId ? sPoolMgr->IsPartOfAPool<Creature>(m_spawnId) : 0;
if (poolid)
sPoolMgr->UpdatePool<Creature>(poolid, m_spawnId);
//Re-initialize reactstate that could be altered by movementgenerators
InitializeReactState();
m_respawnedTime = GameTime::GetGameTime().count();
}
m_respawnedTime = GameTime::GetGameTime().count();
// xinef: relocate notifier, fixes npc appearing in corpse position after forced respawn (instead of spawn)
m_last_notify_position.Relocate(-5000.0f, -5000.0f, -5000.0f, 0.0f);
UpdateObjectVisibility(false);
}
else // the master is dead
{
ObjectGuid targetGuid = sObjectMgr->GetLinkedRespawnGuid(dbtableHighGuid);
if (targetGuid == dbtableHighGuid) // if linking self, never respawn (check delayed to next day)
{
SetRespawnTime(DAY);
}
else
{
time_t now = GameTime::GetGameTime().count();
m_respawnTime = (now > linkedRespawntime ? now : linkedRespawntime) + urand(5, MINUTE); // else copy time from master and add a little
}
SaveRespawnTime(); // also save to DB immediately
} }
m_respawnedTime = GameTime::GetGameTime().count();
// xinef: relocate notifier, fixes npc appearing in corpse position after forced respawn (instead of spawn)
m_last_notify_position.Relocate(-5000.0f, -5000.0f, -5000.0f, 0.0f);
UpdateObjectVisibility(false);
} }
void Creature::ForcedDespawn(uint32 timeMSToDespawn, Seconds forceRespawnTimer) void Creature::ForcedDespawn(uint32 timeMSToDespawn, Seconds forceRespawnTimer)
+1 -1
View File
@@ -2391,7 +2391,7 @@ public:
if (target->isDead()) if (target->isDead())
{ {
target->ToCreature()->Respawn(); target->ToCreature()->Respawn(true);
} }
return true; return true;
} }