diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index b4c84138635..bd3a447b19e 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -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; diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index 2b4bfd402d9..96a5315f4c4 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -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; diff --git a/src/server/game/Instances/InstanceScript.cpp b/src/server/game/Instances/InstanceScript.cpp index 8266f9795d4..de41d1bd235 100644 --- a/src/server/game/Instances/InstanceScript.cpp +++ b/src/server/game/Instances/InstanceScript.cpp @@ -242,32 +242,49 @@ void InstanceScript::UpdateSpawnGroups() { if (!_instanceSpawnGroups) return; - enum states { BLOCK, SPAWN, FORCEBLOCK }; - std::unordered_map newStates; + enum states : uint8 + { + BLOCK = 0x0, + SPAWN = 0x1, + FORCEBLOCK = 0x2, + FORCEDESPAWN = 0x4 + }; + + std::unordered_map 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()) {