Core/Spawns: define and implement FLAG_FORCE_DESPAWN for instance spawn groups

* made instance spawn group handling bitmask based to offer more flexibility
* validate flag combinations on loading so we can no longer combine FLAG_ACTIVATE_SPAWN and FLAG_BLOCK_SPAWN in a single entry
This commit is contained in:
Ovahlord
2019-08-12 18:24:33 +02:00
parent 57e8752b6f
commit 64ecd14f55
3 changed files with 48 additions and 23 deletions

View File

@@ -2708,6 +2708,13 @@ void ObjectMgr::LoadInstanceSpawnGroups()
info.BossStates = states;
uint8 const flags = fields[4].GetUInt8();
if ((flags & (InstanceSpawnGroupInfo::FLAG_BLOCK_SPAWN | InstanceSpawnGroupInfo::FLAG_ACTIVATE_SPAWN)))
{
info.Flags = flags & InstanceSpawnGroupInfo::FLAG_BLOCK_SPAWN;
TC_LOG_ERROR("sql.sql", "Instance spawn group (%u,%u) FLAG_ACTIVATE_SPAWN and FLAG_BLOCK_SPAWN may not be used together in a single entry - truncated to %u.", instanceMapId, spawnGroupId, info.Flags);
}
if (flags & ~InstanceSpawnGroupInfo::FLAG_ALL)
{
info.Flags = flags & InstanceSpawnGroupInfo::FLAG_ALL;

View File

@@ -433,9 +433,10 @@ struct TC_GAME_API InstanceSpawnGroupInfo
enum
{
FLAG_ACTIVATE_SPAWN = 0x01,
FLAG_BLOCK_SPAWN = 0x02,
FLAG_BLOCK_SPAWN = 0x02,
FLAG_FORCE_DESPAWN = 0x04,
FLAG_ALL = (FLAG_ACTIVATE_SPAWN | FLAG_BLOCK_SPAWN)
FLAG_ALL = (FLAG_ACTIVATE_SPAWN | FLAG_BLOCK_SPAWN | FLAG_FORCE_DESPAWN)
};
uint8 BossStateId;
uint8 BossStates;

View File

@@ -242,32 +242,49 @@ void InstanceScript::UpdateSpawnGroups()
{
if (!_instanceSpawnGroups)
return;
enum states { BLOCK, SPAWN, FORCEBLOCK };
std::unordered_map<uint32, states> newStates;
enum states : uint8
{
BLOCK = 0x0,
SPAWN = 0x1,
FORCEBLOCK = 0x2,
FORCEDESPAWN = 0x4
};
std::unordered_map<uint32, uint8> newStates;
for (auto it = _instanceSpawnGroups->begin(), end = _instanceSpawnGroups->end(); it != end; ++it)
{
InstanceSpawnGroupInfo const& info = *it;
states& curValue = newStates[info.SpawnGroupId]; // makes sure there's a BLOCK value in the map
uint8& curValue = newStates[info.SpawnGroupId]; // makes sure there's a BLOCK value in the map
if (curValue == FORCEBLOCK) // nothing will change this
continue;
if (!((1 << GetBossState(info.BossStateId)) & info.BossStates))
continue;
if (info.Flags & InstanceSpawnGroupInfo::FLAG_BLOCK_SPAWN)
curValue = FORCEBLOCK;
else if (info.Flags & InstanceSpawnGroupInfo::FLAG_ACTIVATE_SPAWN)
curValue = SPAWN;
curValue |= FORCEBLOCK;
if (info.Flags & InstanceSpawnGroupInfo::FLAG_ACTIVATE_SPAWN)
curValue |= SPAWN;
if (info.Flags & InstanceSpawnGroupInfo::FLAG_FORCE_DESPAWN)
curValue |= FORCEDESPAWN;
}
for (auto const& pair : newStates)
{
uint32 const groupId = pair.first;
bool const doSpawn = (pair.second == SPAWN);
if (instance->IsSpawnGroupActive(groupId) == doSpawn)
continue; // nothing to do here
// if we should spawn group, then spawn it...
if (doSpawn)
uint8 state = pair.second;
// Spawn group is already active, skip
if (instance->IsSpawnGroupActive(groupId) == (state & SPAWN))
continue;
// Spawn group shall be spawned, spawn it
if (state & SPAWN)
instance->SpawnGroupSpawn(groupId);
else // otherwise, set it as inactive so it no longer respawns (but don't despawn it)
// Spawn group shall be disabled, disable it
if (state & FORCEBLOCK)
instance->SetSpawnGroupInactive(groupId);
// Spawn group shall be despawned, despawn it
if (state & FORCEDESPAWN)
instance->SpawnGroupDespawn(groupId);
}
}
@@ -349,10 +366,10 @@ bool InstanceScript::SetBossState(uint32 id, EncounterState state)
return false;
}
else
{
if (bossInfo->state == state)
return false;
else
{
if (bossInfo->state == state)
return false;
if (bossInfo->state == DONE)
{
@@ -360,11 +377,11 @@ bool InstanceScript::SetBossState(uint32 id, EncounterState state)
return false;
}
if (state == DONE)
for (GuidSet::iterator i = bossInfo->minion.begin(); i != bossInfo->minion.end(); ++i)
if (Creature* minion = instance->GetCreature(*i))
if (minion->isWorldBoss() && minion->IsAlive())
return false;
if (state == DONE)
for (GuidSet::iterator i = bossInfo->minion.begin(); i != bossInfo->minion.end(); ++i)
if (Creature * minion = instance->GetCreature(*i))
if (minion->isWorldBoss() && minion->IsAlive())
return false;
if (instance->IsRaid())
{