diff --git a/src/game/Creature.cpp b/src/game/Creature.cpp index 00358f540..82eeea81f 100644 --- a/src/game/Creature.cpp +++ b/src/game/Creature.cpp @@ -374,11 +374,7 @@ void Creature::Update(uint32 diff) //Call AI respawn virtual function i_AI->JustRespawned(); - uint16 poolid = GetDBTableGUIDLow() ? sPoolMgr.IsPartOfAPool(GetDBTableGUIDLow()) : 0; - if (poolid) - sPoolMgr.UpdatePool(poolid, GetDBTableGUIDLow()); - else - GetMap()->Add(this); + GetMap()->Add(this); } break; } @@ -389,8 +385,16 @@ void Creature::Update(uint32 diff) if( m_deathTimer <= diff ) { - RemoveCorpse(); - DEBUG_LOG("Removing corpse... %u ", GetEntry()); + // since pool system can fail to roll unspawned object, this one can remain spawned, so must set respawn nevertheless + uint16 poolid = GetDBTableGUIDLow() ? sPoolMgr.IsPartOfAPool(GetDBTableGUIDLow()) : 0; + if (poolid) + sPoolMgr.UpdatePool(poolid, GetDBTableGUIDLow()); + + if (IsInWorld()) // can be despawned by update pool + { + RemoveCorpse(); + DEBUG_LOG("Removing corpse... %u ", GetEntry()); + } } else { @@ -419,8 +423,19 @@ void Creature::Update(uint32 diff) { if( m_deathTimer <= diff ) { - RemoveCorpse(); - DEBUG_LOG("Removing alive corpse... %u ", GetEntry()); + // since pool system can fail to roll unspawned object, this one can remain spawned, so must set respawn nevertheless + uint16 poolid = GetDBTableGUIDLow() ? sPoolMgr.IsPartOfAPool(GetDBTableGUIDLow()) : 0; + + if (poolid) + sPoolMgr.UpdatePool(poolid, GetDBTableGUIDLow()); + + if (IsInWorld()) // can be despawned by update pool + { + RemoveCorpse(); + DEBUG_LOG("Removing alive corpse... %u ", GetEntry()); + } + else + return; } else { diff --git a/src/game/GameEventMgr.cpp b/src/game/GameEventMgr.cpp index 6d3c55b4a..77d1d417a 100644 --- a/src/game/GameEventMgr.cpp +++ b/src/game/GameEventMgr.cpp @@ -574,7 +574,7 @@ void GameEventMgr::GameEventSpawn(int16 event_id) } for (IdList::iterator itr = mGameEventPoolIds[internal_event_id].begin();itr != mGameEventPoolIds[internal_event_id].end();++itr) - sPoolMgr.SpawnPool(*itr); + sPoolMgr.SpawnPool(*itr, true); } void GameEventMgr::GameEventUnspawn(int16 event_id) diff --git a/src/game/GameObject.cpp b/src/game/GameObject.cpp index b2df96073..0bfb0b918 100644 --- a/src/game/GameObject.cpp +++ b/src/game/GameObject.cpp @@ -256,11 +256,7 @@ void GameObject::Update(uint32 /*p_time*/) return; } // respawn timer - uint16 poolid = GetDBTableGUIDLow() ? sPoolMgr.IsPartOfAPool(GetDBTableGUIDLow()) : 0; - if (poolid) - sPoolMgr.UpdatePool(poolid, GetDBTableGUIDLow()); - else - GetMap()->Add(this); + GetMap()->Add(this); break; } } @@ -445,13 +441,20 @@ void GameObject::Update(uint32 /*p_time*/) return; } + // since pool system can fail to roll unspawned object, this one can remain spawned, so must set respawn nevertheless m_respawnTime = time(NULL) + m_respawnDelayTime; // if option not set then object will be saved at grid unload if(sWorld.getConfig(CONFIG_BOOL_SAVE_RESPAWN_TIME_IMMEDIATLY)) SaveRespawnTime(); - UpdateObjectVisibility(); + // if part of pool, let pool system schedule new spawn instead of just scheduling respawn + if(uint16 poolid = GetDBTableGUIDLow() ? sPoolMgr.IsPartOfAPool(GetDBTableGUIDLow()) : 0) + sPoolMgr.UpdatePool(poolid, GetDBTableGUIDLow()); + + // can be not in world at pool despawn + if (IsInWorld()) + UpdateObjectVisibility(); break; } diff --git a/src/game/PoolManager.cpp b/src/game/PoolManager.cpp index 3c56be9c9..15682b8d8 100644 --- a/src/game/PoolManager.cpp +++ b/src/game/PoolManager.cpp @@ -22,6 +22,7 @@ #include "ProgressBar.h" #include "Log.h" #include "MapManager.h" +#include "World.h" #include "Policies/SingletonImp.h" INSTANTIATE_SINGLETON_1(PoolManager); @@ -253,7 +254,7 @@ void PoolGroup::RemoveOneRelation(uint16 child_pool_id) } template -void PoolGroup::SpawnObject(SpawnedPoolData& spawns, uint32 limit, uint32 triggerFrom) +void PoolGroup::SpawnObject(SpawnedPoolData& spawns, uint32 limit, uint32 triggerFrom, bool instantly) { uint32 lastDespawned = 0; int count = limit - spawns.GetSpawnedObjects(poolId); @@ -283,7 +284,7 @@ void PoolGroup::SpawnObject(SpawnedPoolData& spawns, uint32 limit, uint32 tri } spawns.AddSpawn(obj->guid,poolId); - Spawn1Object(obj); + Spawn1Object(obj, instantly); if (triggerFrom) { @@ -297,7 +298,7 @@ void PoolGroup::SpawnObject(SpawnedPoolData& spawns, uint32 limit, uint32 tri // Method that is actualy doing the spawn job on 1 creature template <> -void PoolGroup::Spawn1Object(PoolObject* obj) +void PoolGroup::Spawn1Object(PoolObject* obj, bool instantly) { if (CreatureData const* data = sObjectMgr.GetCreatureData(obj->guid)) { @@ -305,7 +306,7 @@ void PoolGroup::Spawn1Object(PoolObject* obj) // Spawn if necessary (loaded grids only) Map* map = const_cast(sMapMgr.CreateBaseMap(data->mapid)); - // We use spawn coords to spawn + // We use spawn coords to spawn (avoid work for instances until implemented support) if (!map->Instanceable() && map->IsLoaded(data->posX, data->posY)) { Creature* pCreature = new Creature; @@ -316,14 +317,28 @@ void PoolGroup::Spawn1Object(PoolObject* obj) return; } else + { + // if new spawn replaces a just despawned creature, not instantly spawn but set respawn timer + if(!instantly) + { + pCreature->SetRespawnTime( pCreature->GetRespawnDelay() ); + if (sWorld.getConfig(CONFIG_SAVE_RESPAWN_TIME_IMMEDIATLY) || pCreature->isWorldBoss()) + pCreature->SaveRespawnTime(); + } map->Add(pCreature); + } + } + // for not loaded grid just update respawn time (avoid work for instances until implemented support) + else if(!map->Instanceable() && !instantly) + { + sObjectMgr.SaveCreatureRespawnTime(obj->guid,map->GetInstanceId(),time(NULL) + data->spawntimesecs); } } } // Same for 1 gameobject template <> -void PoolGroup::Spawn1Object(PoolObject* obj) +void PoolGroup::Spawn1Object(PoolObject* obj, bool instantly) { if (GameObjectData const* data = sObjectMgr.GetGOData(obj->guid)) { @@ -332,6 +347,7 @@ void PoolGroup::Spawn1Object(PoolObject* obj) // this base map checked as non-instanced and then only existed Map* map = const_cast(sMapMgr.CreateBaseMap(data->mapid)); // We use current coords to unspawn, not spawn coords since creature can have changed grid + // (avoid work for instances until implemented support) if (!map->Instanceable() && map->IsLoaded(data->posX, data->posY)) { GameObject* pGameobject = new GameObject; @@ -344,17 +360,33 @@ void PoolGroup::Spawn1Object(PoolObject* obj) else { if (pGameobject->isSpawnedByDefault()) + { + // if new spawn replaces a just despawned object, not instantly spawn but set respawn timer + if(!instantly) + { + pGameobject->SetRespawnTime( pGameobject->GetRespawnDelay() ); + if (sWorld.getConfig(CONFIG_SAVE_RESPAWN_TIME_IMMEDIATLY)) + pGameobject->SaveRespawnTime(); + } map->Add(pGameobject); + } } } + // for not loaded grid just update respawn time (avoid work for instances until implemented support) + else if(!map->Instanceable() && !instantly) + { + // for spawned by default object only + if (data->spawntimesecs >= 0) + sObjectMgr.SaveGORespawnTime(obj->guid,map->GetInstanceId(),time(NULL) + data->spawntimesecs); + } } } // Same for 1 pool template <> -void PoolGroup::Spawn1Object(PoolObject* obj) +void PoolGroup::Spawn1Object(PoolObject* obj, bool instantly) { - sPoolMgr.SpawnPool(obj->guid); + sPoolMgr.SpawnPool(obj->guid, instantly); } // Method that does the respawn job on the specified creature @@ -676,7 +708,7 @@ void PoolManager::Initialize() sLog.outErrorDb("Pool Id (%u) has all creatures or gameobjects with explicit chance sum <>100 and no equal chance defined. The pool system cannot pick one to spawn.", pool_entry); continue; } - SpawnPool(pool_entry); + SpawnPool(pool_entry, true); count++; } while (result->NextRow()); delete result; @@ -688,35 +720,37 @@ void PoolManager::Initialize() // Call to spawn a pool, if cache if true the method will spawn only if cached entry is different // If it's same, the creature is respawned only (added back to map) template<> -void PoolManager::SpawnPool(uint16 pool_id, uint32 db_guid) +void PoolManager::SpawnPoolGroup(uint16 pool_id, uint32 db_guid, bool instantly) { if (!mPoolCreatureGroups[pool_id].isEmpty()) - mPoolCreatureGroups[pool_id].SpawnObject(mSpawnedData, mPoolTemplate[pool_id].MaxLimit, db_guid); + mPoolCreatureGroups[pool_id].SpawnObject(mSpawnedData, mPoolTemplate[pool_id].MaxLimit, db_guid, instantly); } // Call to spawn a pool, if cache if true the method will spawn only if cached entry is different // If it's same, the gameobject is respawned only (added back to map) template<> -void PoolManager::SpawnPool(uint16 pool_id, uint32 db_guid) +void PoolManager::SpawnPoolGroup(uint16 pool_id, uint32 db_guid, bool instantly) { if (!mPoolGameobjectGroups[pool_id].isEmpty()) - mPoolGameobjectGroups[pool_id].SpawnObject(mSpawnedData, mPoolTemplate[pool_id].MaxLimit, db_guid); + mPoolGameobjectGroups[pool_id].SpawnObject(mSpawnedData, mPoolTemplate[pool_id].MaxLimit, db_guid, instantly); } // Call to spawn a pool, if cache if true the method will spawn only if cached entry is different // If it's same, the pool is respawned only template<> -void PoolManager::SpawnPool(uint16 pool_id, uint32 sub_pool_id) +void PoolManager::SpawnPoolGroup(uint16 pool_id, uint32 sub_pool_id, bool instantly) { if (!mPoolPoolGroups[pool_id].isEmpty()) - mPoolPoolGroups[pool_id].SpawnObject(mSpawnedData, mPoolTemplate[pool_id].MaxLimit, sub_pool_id); + mPoolPoolGroups[pool_id].SpawnObject(mSpawnedData, mPoolTemplate[pool_id].MaxLimit, sub_pool_id, instantly); } -void PoolManager::SpawnPool( uint16 pool_id ) +/*! + \param instantly defines if (leaf-)objects are spawned instantly or with fresh respawn timer */ +void PoolManager::SpawnPool(uint16 pool_id, bool instantly) { - SpawnPool(pool_id, 0); - SpawnPool(pool_id, 0); - SpawnPool(pool_id, 0); + SpawnPoolGroup(pool_id, 0, instantly); + SpawnPoolGroup(pool_id, 0, instantly); + SpawnPoolGroup(pool_id, 0, instantly); } // Call to despawn a pool, all gameobjects/creatures in this pool are removed @@ -748,9 +782,9 @@ template void PoolManager::UpdatePool(uint16 pool_id, uint32 db_guid_or_pool_id) { if (uint16 motherpoolid = IsPartOfAPool(pool_id)) - SpawnPool(motherpoolid, pool_id); + SpawnPoolGroup(motherpoolid, pool_id, false); else - SpawnPool(pool_id, db_guid_or_pool_id); + SpawnPoolGroup(pool_id, db_guid_or_pool_id, false); } template void PoolManager::UpdatePool(uint16 pool_id, uint32 db_guid_or_pool_id); diff --git a/src/game/PoolManager.h b/src/game/PoolManager.h index fa1f28543..5cdeeda7d 100644 --- a/src/game/PoolManager.h +++ b/src/game/PoolManager.h @@ -76,9 +76,9 @@ class PoolGroup PoolObject* RollOne(SpawnedPoolData& spawns, uint32 triggerFrom); void DespawnObject(SpawnedPoolData& spawns, uint32 guid=0); void Despawn1Object(uint32 guid); - void SpawnObject(SpawnedPoolData& spawns, uint32 limit, uint32 triggerFrom); + void SpawnObject(SpawnedPoolData& spawns, uint32 limit, uint32 triggerFrom, bool instantly); - void Spawn1Object(PoolObject* obj); + void Spawn1Object(PoolObject* obj, bool instantly); void ReSpawn1Object(PoolObject* obj); void RemoveOneRelation(uint16 child_pool_id); private: @@ -104,7 +104,7 @@ class PoolManager bool CheckPool(uint16 pool_id) const; - void SpawnPool(uint16 pool_id); + void SpawnPool(uint16 pool_id, bool instantly); void DespawnPool(uint16 pool_id); template @@ -112,7 +112,7 @@ class PoolManager protected: template - void SpawnPool(uint16 pool_id, uint32 db_guid_or_pool_id); + void SpawnPoolGroup(uint16 pool_id, uint32 db_guid_or_pool_id, bool instantly); uint16 max_pool_id; typedef std::vector PoolTemplateDataMap; diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index da85b5628..e8033669b 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "9391" + #define REVISION_NR "9392" #endif // __REVISION_NR_H__