diff options
Diffstat (limited to 'src/server/game/Maps/Map.cpp')
-rw-r--r-- | src/server/game/Maps/Map.cpp | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index 6c3794d16db..79136e3f663 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -3603,6 +3603,148 @@ void Map::ApplyDynamicModeRespawnScaling(WorldObject const* obj, ObjectGuid::Low respawnDelay = std::max<uint32>(ceil(respawnDelay * adjustFactor), timeMinimum); } +SpawnGroupTemplateData const* Map::GetSpawnGroupData(uint32 groupId) const +{ + SpawnGroupTemplateData const* data = sObjectMgr->GetSpawnGroupData(groupId); + if (data && data->mapId == GetId()) + return data; + return nullptr; +} + +bool Map::SpawnGroupSpawn(uint32 groupId, bool ignoreRespawn, bool force, std::vector<WorldObject*>* spawnedObjects) +{ + SpawnGroupTemplateData const* groupData = GetSpawnGroupData(groupId); + if (!groupData || groupData->flags & SPAWNGROUP_FLAG_SYSTEM) + { + TC_LOG_ERROR("maps", "Tried to spawn non-existing (or system) spawn group %u on map %u. Blocked.", groupId, GetId()); + return false; + } + + for (auto& pair : sObjectMgr->GetSpawnDataForGroup(groupId)) + { + SpawnData const* data = pair.second; + ASSERT(groupData->mapId == data->spawnPoint.GetMapId()); + // Check if there's already an instance spawned + if (!force) + if (WorldObject* obj = GetWorldObjectBySpawnId(data->type, data->spawnId)) + if ((data->type != SPAWN_TYPE_CREATURE) || obj->ToCreature()->IsAlive()) + continue; + + time_t respawnTime = GetRespawnTime(data->type, data->spawnId); + if (respawnTime && respawnTime > time(NULL)) + { + if (!force && !ignoreRespawn) + continue; + + // we need to remove the respawn time, otherwise we'd end up double spawning + RemoveRespawnTime(data->type, data->spawnId, false); + } + + // don't spawn if the grid isn't loaded (will be handled in grid loader) + if (!IsGridLoaded(data->spawnPoint)) + continue; + + // Everything OK, now do the actual (re)spawn + switch (data->type) + { + case SPAWN_TYPE_CREATURE: + { + Creature* creature = new Creature(); + if (!creature->LoadFromDB(data->spawnId, this, true, force)) + delete creature; + else if (spawnedObjects) + spawnedObjects->push_back(creature); + break; + } + case SPAWN_TYPE_GAMEOBJECT: + { + GameObject* gameobject = new GameObject(); + if (!gameobject->LoadFromDB(data->spawnId, this, true)) + delete gameobject; + else if (spawnedObjects) + spawnedObjects->push_back(gameobject); + break; + } + default: + ASSERT(false, "Invalid spawn type %u with spawnId " UI64FMTD, uint32(data->type), data->spawnId); + return false; + } + } + SetSpawnGroupActive(groupId, true); // start processing respawns for the group + return true; +} + +bool Map::SpawnGroupDespawn(uint32 groupId, bool deleteRespawnTimes) +{ + SpawnGroupTemplateData const* groupData = GetSpawnGroupData(groupId); + if (!groupData || groupData->flags & SPAWNGROUP_FLAG_SYSTEM) + { + TC_LOG_ERROR("maps", "Tried to despawn non-existing (or system) spawn group %u on map %u. Blocked.", groupId, GetId()); + return false; + } + + std::vector<WorldObject*> toUnload; // unload after iterating, otherwise iterator invalidation + for (auto const& pair : sObjectMgr->GetSpawnDataForGroup(groupId)) + { + SpawnData const* data = pair.second; + ASSERT(groupData->mapId == data->spawnPoint.GetMapId()); + if (deleteRespawnTimes) + RemoveRespawnTime(data->type, data->spawnId); + switch (data->type) + { + case SPAWN_TYPE_CREATURE: + { + auto bounds = GetCreatureBySpawnIdStore().equal_range(data->spawnId); + for (auto it = bounds.first; it != bounds.second; ++it) + toUnload.emplace_back(it->second); + break; + } + case SPAWN_TYPE_GAMEOBJECT: + { + auto bounds = GetGameObjectBySpawnIdStore().equal_range(data->spawnId); + for (auto it = bounds.first; it != bounds.second; ++it) + toUnload.emplace_back(it->second); + break; + } + default: + ASSERT(false, "Invalid spawn type %u in spawn data with spawnId " UI64FMTD ".", uint32(data->type), data->spawnId); + return false; + } + } + // now do the actual despawning + for (WorldObject* obj : toUnload) + obj->AddObjectToRemoveList(); + SetSpawnGroupActive(groupId, false); // stop processing respawns for the group, too + return true; +} + +void Map::SetSpawnGroupActive(uint32 groupId, bool state) +{ + SpawnGroupTemplateData const* const data = GetSpawnGroupData(groupId); + if (!data || data->flags & SPAWNGROUP_FLAG_SYSTEM) + { + TC_LOG_ERROR("maps", "Tried to set non-existing (or system) spawn group %u to %s on map %u. Blocked.", groupId, state ? "active" : "inactive", GetId()); + return; + } + if (state != !(data->flags & SPAWNGROUP_FLAG_MANUAL_SPAWN)) // toggled + _toggledSpawnGroupIds.insert(groupId); + else + _toggledSpawnGroupIds.erase(groupId); +} + +bool Map::IsSpawnGroupActive(uint32 groupId) const +{ + SpawnGroupTemplateData const* const data = GetSpawnGroupData(groupId); + if (!data) + { + TC_LOG_WARN("maps", "Tried to query state of non-existing spawn group %u on map %u.", groupId, GetId()); + return false; + } + if (data->flags & SPAWNGROUP_FLAG_SYSTEM) + return true; + return (_toggledSpawnGroupIds.find(groupId) != _toggledSpawnGroupIds.end()) != !(data->flags & SPAWNGROUP_FLAG_MANUAL_SPAWN); +} + void Map::DelayedUpdate(uint32 t_diff) { for (_transportsUpdateIter = _transports.begin(); _transportsUpdateIter != _transports.end();) |