2009-02-19 18:46:19 -06:00
/*
2011-01-01 15:01:13 +01:00
* Copyright (C) 2008-2011 TrinityCore <http://www.trinitycore.org/>
2010-10-07 14:50:05 +02:00
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
2009-02-19 18:46:19 -06:00
*
2010-10-07 14:50:05 +02:00
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
2009-02-19 18:46:19 -06:00
*
2010-10-07 14:50:05 +02:00
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
2009-02-19 18:46:19 -06:00
*
2010-10-07 14:50:05 +02:00
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
2009-02-19 18:46:19 -06:00
*/
2009-10-17 15:51:44 -07:00
2010-06-25 03:50:19 -06:00
#include "PoolMgr.h"
2009-02-19 18:46:19 -06:00
#include "ObjectMgr.h"
#include "Log.h"
#include "MapManager.h"
2009-10-17 15:51:44 -07:00
2010-02-14 19:13:14 -07:00
////////////////////////////////////////////////////////////
2010-09-14 13:56:27 +02:00
// template class ActivePoolData
2010-02-14 19:13:14 -07:00
// Method that tell amount spawned objects/subpools
2010-09-14 13:56:27 +02:00
uint32 ActivePoolData :: GetActiveObjectCount ( uint32 pool_id ) const
2010-02-14 19:13:14 -07:00
{
2010-09-14 13:56:27 +02:00
ActivePoolPools :: const_iterator itr = mSpawnedPools . find ( pool_id );
2010-02-14 19:13:14 -07:00
return itr != mSpawnedPools . end () ? itr -> second : 0 ;
}
// Method that tell if a creature is spawned currently
template <>
2010-09-14 13:56:27 +02:00
bool ActivePoolData :: IsActiveObject < Creature > ( uint32 db_guid ) const
2010-02-14 19:13:14 -07:00
{
return mSpawnedCreatures . find ( db_guid ) != mSpawnedCreatures . end ();
}
// Method that tell if a gameobject is spawned currently
template <>
2010-09-14 13:56:27 +02:00
bool ActivePoolData :: IsActiveObject < GameObject > ( uint32 db_guid ) const
2010-02-14 19:13:14 -07:00
{
return mSpawnedGameobjects . find ( db_guid ) != mSpawnedGameobjects . end ();
}
2010-09-14 16:14:43 +02:00
// Method that tell if a pool is spawned currently
2010-09-14 13:56:27 +02:00
template <>
2010-09-14 16:14:43 +02:00
bool ActivePoolData :: IsActiveObject < Pool > ( uint32 sub_pool_id ) const
2010-09-14 13:56:27 +02:00
{
2010-09-14 16:14:43 +02:00
return mSpawnedPools . find ( sub_pool_id ) != mSpawnedPools . end ();
2010-09-14 13:56:27 +02:00
}
2010-09-14 16:14:43 +02:00
// Method that tell if a quest can be started
2010-02-14 19:13:14 -07:00
template <>
2010-09-14 16:14:43 +02:00
bool ActivePoolData :: IsActiveObject < Quest > ( uint32 quest_id ) const
2010-02-14 19:13:14 -07:00
{
2010-09-14 16:14:43 +02:00
return mActiveQuests . find ( quest_id ) != mActiveQuests . end ();
2010-02-14 19:13:14 -07:00
}
template <>
2010-09-14 13:56:27 +02:00
void ActivePoolData :: ActivateObject < Creature > ( uint32 db_guid , uint32 pool_id )
2010-02-14 19:13:14 -07:00
{
mSpawnedCreatures . insert ( db_guid );
++ mSpawnedPools [ pool_id ];
}
template <>
2010-09-14 13:56:27 +02:00
void ActivePoolData :: ActivateObject < GameObject > ( uint32 db_guid , uint32 pool_id )
2010-02-14 19:13:14 -07:00
{
mSpawnedGameobjects . insert ( db_guid );
++ mSpawnedPools [ pool_id ];
}
template <>
2010-09-14 16:14:43 +02:00
void ActivePoolData :: ActivateObject < Pool > ( uint32 sub_pool_id , uint32 pool_id )
2010-09-14 13:56:27 +02:00
{
2010-09-14 16:14:43 +02:00
mSpawnedPools [ sub_pool_id ] = 0 ;
2010-09-14 13:56:27 +02:00
++ mSpawnedPools [ pool_id ];
}
template <>
2010-09-14 16:14:43 +02:00
void ActivePoolData :: ActivateObject < Quest > ( uint32 quest_id , uint32 pool_id )
2010-02-14 19:13:14 -07:00
{
2010-09-14 16:14:43 +02:00
mActiveQuests . insert ( quest_id );
2010-02-14 19:13:14 -07:00
++ mSpawnedPools [ pool_id ];
}
template <>
2010-09-14 13:56:27 +02:00
void ActivePoolData :: RemoveObject < Creature > ( uint32 db_guid , uint32 pool_id )
2010-02-14 19:13:14 -07:00
{
mSpawnedCreatures . erase ( db_guid );
uint32 & val = mSpawnedPools [ pool_id ];
if ( val > 0 )
-- val ;
}
template <>
2010-09-14 13:56:27 +02:00
void ActivePoolData :: RemoveObject < GameObject > ( uint32 db_guid , uint32 pool_id )
2010-02-14 19:13:14 -07:00
{
mSpawnedGameobjects . erase ( db_guid );
uint32 & val = mSpawnedPools [ pool_id ];
if ( val > 0 )
-- val ;
}
template <>
2010-09-14 16:14:43 +02:00
void ActivePoolData :: RemoveObject < Pool > ( uint32 sub_pool_id , uint32 pool_id )
2010-09-14 13:56:27 +02:00
{
2010-09-14 16:14:43 +02:00
mSpawnedPools . erase ( sub_pool_id );
2010-09-14 13:56:27 +02:00
uint32 & val = mSpawnedPools [ pool_id ];
if ( val > 0 )
-- val ;
}
template <>
2010-09-14 16:14:43 +02:00
void ActivePoolData :: RemoveObject < Quest > ( uint32 quest_id , uint32 pool_id )
2010-02-14 19:13:14 -07:00
{
2010-09-14 16:14:43 +02:00
mActiveQuests . erase ( quest_id );
2010-02-14 19:13:14 -07:00
uint32 & val = mSpawnedPools [ pool_id ];
if ( val > 0 )
-- val ;
}
2009-02-19 18:50:12 -06:00
////////////////////////////////////////////////////////////
// Methods of template class PoolGroup
2009-10-17 15:51:44 -07:00
2009-02-19 18:50:12 -06:00
// Method to add a gameobject/creature guid to the proper list depending on pool type and chance value
template < class T >
2009-02-19 18:52:03 -06:00
void PoolGroup < T >:: AddEntry ( PoolObject & poolitem , uint32 maxentries )
2009-02-19 18:46:19 -06:00
{
2009-02-19 18:50:12 -06:00
if ( poolitem . chance != 0 && maxentries == 1 )
ExplicitlyChanced . push_back ( poolitem );
2009-02-19 18:46:19 -06:00
else
2009-02-19 18:50:12 -06:00
EqualChanced . push_back ( poolitem );
}
2009-10-17 15:51:44 -07:00
2009-02-19 18:50:12 -06:00
// Method to check the chances are proper in this object pool
template < class T >
2010-02-14 19:13:14 -07:00
bool PoolGroup < T >:: CheckPool () const
2009-02-19 18:50:12 -06:00
{
2011-07-01 14:58:44 +02:00
if ( EqualChanced . empty ())
2009-02-19 18:46:19 -06:00
{
2009-02-19 18:50:12 -06:00
float chance = 0 ;
2010-06-14 20:52:36 +02:00
for ( uint32 i = 0 ; i < ExplicitlyChanced . size (); ++ i )
2009-02-19 18:50:12 -06:00
chance += ExplicitlyChanced [ i ]. chance ;
if ( chance != 100 && chance != 0 )
return false ;
2009-02-19 18:46:19 -06:00
}
2009-02-19 18:50:12 -06:00
return true ;
}
2009-10-17 15:51:44 -07:00
2009-02-19 18:50:12 -06:00
template < class T >
2010-09-14 13:56:27 +02:00
PoolObject * PoolGroup < T >:: RollOne ( ActivePoolData & spawns , uint32 triggerFrom )
2009-02-19 18:50:12 -06:00
{
2009-12-18 06:54:49 +01:00
if ( ! ExplicitlyChanced . empty ())
2009-02-19 18:46:19 -06:00
{
2009-12-18 06:54:49 +01:00
float roll = ( float ) rand_chance ();
2009-10-17 15:51:44 -07:00
2010-09-14 13:56:27 +02:00
for ( uint32 i = 0 ; i < ExplicitlyChanced . size (); ++ i )
2009-02-19 18:50:12 -06:00
{
roll -= ExplicitlyChanced [ i ]. chance ;
2009-12-18 06:54:49 +01:00
// Triggering object is marked as spawned at this time and can be also rolled (respawn case)
// so this need explicit check for this case
2010-09-14 13:56:27 +02:00
if ( roll < 0 && ( ExplicitlyChanced [ i ]. guid == triggerFrom || ! spawns . IsActiveObject < T > ( ExplicitlyChanced [ i ]. guid )))
2010-02-14 19:13:14 -07:00
return & ExplicitlyChanced [ i ];
2009-02-19 18:50:12 -06:00
}
2009-02-19 18:46:19 -06:00
}
2009-02-19 18:50:12 -06:00
if ( ! EqualChanced . empty ())
2009-12-18 06:54:49 +01:00
{
2010-02-14 19:13:14 -07:00
int32 index = irand ( 0 , EqualChanced . size () - 1 );
2009-12-18 06:54:49 +01:00
// Triggering object is marked as spawned at this time and can be also rolled (respawn case)
// so this need explicit check for this case
2010-09-14 13:56:27 +02:00
if ( EqualChanced [ index ]. guid == triggerFrom || ! spawns . IsActiveObject < T > ( EqualChanced [ index ]. guid ))
2010-02-14 19:13:14 -07:00
return & EqualChanced [ index ];
2009-12-18 06:54:49 +01:00
}
2009-10-17 15:51:44 -07:00
2010-02-14 19:13:14 -07:00
return NULL ;
2009-02-19 18:50:12 -06:00
}
2009-10-17 15:51:44 -07:00
2009-02-19 18:50:12 -06:00
// Main method to despawn a creature or gameobject in a pool
// If no guid is passed, the pool is just removed (event end case)
// If guid is filled, cache will be used and no removal will occur, it just fill the cache
template < class T >
2010-09-14 13:56:27 +02:00
void PoolGroup < T >:: DespawnObject ( ActivePoolData & spawns , uint32 guid )
2009-02-19 18:50:12 -06:00
{
2010-09-14 13:56:27 +02:00
for ( size_t i = 0 ; i < EqualChanced . size (); ++ i )
2009-02-19 18:46:19 -06:00
{
2010-02-14 19:13:14 -07:00
// if spawned
2010-09-14 13:56:27 +02:00
if ( spawns . IsActiveObject < T > ( EqualChanced [ i ]. guid ))
2009-02-19 18:50:12 -06:00
{
if ( ! guid || EqualChanced [ i ]. guid == guid )
{
2009-12-18 06:54:49 +01:00
Despawn1Object ( EqualChanced [ i ]. guid );
2011-04-29 20:47:02 +02:00
spawns . RemoveObject < T > ( EqualChanced [ i ]. guid , poolId );
2009-02-19 18:50:12 -06:00
}
}
}
2009-12-18 06:54:49 +01:00
for ( size_t i = 0 ; i < ExplicitlyChanced . size (); ++ i )
{
2010-02-14 19:13:14 -07:00
// spawned
2010-09-14 13:56:27 +02:00
if ( spawns . IsActiveObject < T > ( ExplicitlyChanced [ i ]. guid ))
2009-12-18 06:54:49 +01:00
{
if ( ! guid || ExplicitlyChanced [ i ]. guid == guid )
{
Despawn1Object ( ExplicitlyChanced [ i ]. guid );
2011-04-29 20:47:02 +02:00
spawns . RemoveObject < T > ( ExplicitlyChanced [ i ]. guid , poolId );
2009-12-18 06:54:49 +01:00
}
}
}
2009-02-19 18:50:12 -06:00
}
2009-10-17 15:51:44 -07:00
2009-02-19 18:50:12 -06:00
// Method that is actualy doing the removal job on one creature
template <>
2009-02-19 18:52:03 -06:00
void PoolGroup < Creature >:: Despawn1Object ( uint32 guid )
2009-02-19 18:50:12 -06:00
{
2010-12-22 21:25:23 +01:00
if ( CreatureData const * data = sObjectMgr -> GetCreatureData ( guid ))
2009-02-19 18:50:12 -06:00
{
2010-12-22 21:25:23 +01:00
sObjectMgr -> RemoveCreatureFromGrid ( guid , data );
2009-10-17 15:51:44 -07:00
2011-10-07 11:08:09 -05:00
if ( Creature * creature = ObjectAccessor :: GetObjectInWorld ( MAKE_NEW_GUID ( guid , data -> id , HIGHGUID_UNIT ), ( Creature * ) NULL ))
creature -> AddObjectToRemoveList ();
2009-02-19 18:50:12 -06:00
}
}
2009-10-17 15:51:44 -07:00
2009-02-19 18:50:12 -06:00
// Same on one gameobject
template <>
2009-02-19 18:52:03 -06:00
void PoolGroup < GameObject >:: Despawn1Object ( uint32 guid )
2009-02-19 18:50:12 -06:00
{
2010-12-22 21:25:23 +01:00
if ( GameObjectData const * data = sObjectMgr -> GetGOData ( guid ))
2009-02-19 18:50:12 -06:00
{
2010-12-22 21:25:23 +01:00
sObjectMgr -> RemoveGameobjectFromGrid ( guid , data );
2009-10-17 15:51:44 -07:00
2010-12-23 23:25:44 +01:00
if ( GameObject * pGameobject = ObjectAccessor :: GetObjectInWorld ( MAKE_NEW_GUID ( guid , data -> id , HIGHGUID_GAMEOBJECT ), ( GameObject * ) NULL ))
2009-02-19 18:50:12 -06:00
pGameobject -> AddObjectToRemoveList ();
}
}
2009-10-17 15:51:44 -07:00
2010-09-14 16:14:43 +02:00
// Same on one pool
template <>
void PoolGroup < Pool >:: Despawn1Object ( uint32 child_pool_id )
{
2010-12-22 21:25:23 +01:00
sPoolMgr -> DespawnPool ( child_pool_id );
2010-09-14 16:14:43 +02:00
}
2010-09-14 13:56:27 +02:00
// Same on one quest
template <>
void PoolGroup < Quest >:: Despawn1Object ( uint32 quest_id )
{
// Creatures
2010-12-22 21:25:23 +01:00
QuestRelations * questMap = sObjectMgr -> GetCreatureQuestRelationMap ();
PooledQuestRelationBoundsNC qr = sPoolMgr -> mQuestCreatureRelation . equal_range ( quest_id );
2010-09-14 13:56:27 +02:00
for ( PooledQuestRelation :: iterator itr = qr . first ; itr != qr . second ; ++ itr )
{
QuestRelations :: iterator qitr = questMap -> find ( itr -> second );
if ( qitr == questMap -> end ())
continue ;
QuestRelations :: iterator lastElement = questMap -> upper_bound ( itr -> second );
for (; qitr != lastElement ; ++ qitr )
{
2011-10-23 12:11:38 +01:00
if ( qitr -> first == itr -> second && qitr -> second == itr -> first )
2010-09-14 13:56:27 +02:00
{
questMap -> erase ( qitr ); // iterator is now no more valid
break ; // but we can exit loop since the element is found
}
}
}
// Gameobjects
2010-12-22 21:25:23 +01:00
questMap = sObjectMgr -> GetGOQuestRelationMap ();
qr = sPoolMgr -> mQuestGORelation . equal_range ( quest_id );
2010-09-14 13:56:27 +02:00
for ( PooledQuestRelation :: iterator itr = qr . first ; itr != qr . second ; ++ itr )
{
QuestRelations :: iterator qitr = questMap -> find ( itr -> second );
if ( qitr == questMap -> end ())
continue ;
QuestRelations :: iterator lastElement = questMap -> upper_bound ( itr -> second );
for (; qitr != lastElement ; ++ qitr )
{
2011-10-23 12:11:38 +01:00
if ( qitr -> first == itr -> second && qitr -> second == itr -> first )
2010-09-14 13:56:27 +02:00
{
questMap -> erase ( qitr ); // iterator is now no more valid
break ; // but we can exit loop since the element is found
}
}
}
}
2009-02-19 18:50:12 -06:00
// Method for a pool only to remove any found record causing a circular dependency loop
template <>
2010-08-26 06:49:31 +03:00
void PoolGroup < Pool >:: RemoveOneRelation ( uint32 child_pool_id )
2009-02-19 18:50:12 -06:00
{
for ( PoolObjectList :: iterator itr = ExplicitlyChanced . begin (); itr != ExplicitlyChanced . end (); ++ itr )
2009-02-19 18:46:19 -06:00
{
2010-04-07 19:14:10 +02:00
if ( itr -> guid == child_pool_id )
2009-02-19 18:50:12 -06:00
{
ExplicitlyChanced . erase ( itr );
break ;
}
}
for ( PoolObjectList :: iterator itr = EqualChanced . begin (); itr != EqualChanced . end (); ++ itr )
{
2010-04-07 19:14:10 +02:00
if ( itr -> guid == child_pool_id )
2009-02-19 18:50:12 -06:00
{
EqualChanced . erase ( itr );
break ;
}
}
}
2009-10-17 15:51:44 -07:00
2009-02-19 18:50:12 -06:00
template < class T >
2010-09-14 13:56:27 +02:00
void PoolGroup < T >:: SpawnObject ( ActivePoolData & spawns , uint32 limit , uint32 triggerFrom )
2009-02-19 18:50:12 -06:00
{
2009-12-18 06:54:49 +01:00
uint32 lastDespawned = 0 ;
2010-09-14 13:56:27 +02:00
int count = limit - spawns . GetActiveObjectCount ( poolId );
2009-10-17 15:51:44 -07:00
2009-12-18 06:54:49 +01:00
// If triggered from some object respawn this object is still marked as spawned
2010-04-07 18:09:10 +02:00
// and also counted into m_SpawnedPoolAmount so we need increase count to be
2009-12-18 06:54:49 +01:00
// spawned by 1
if ( triggerFrom )
++ count ;
// This will try to spawn the rest of pool, not guaranteed
for ( int i = 0 ; i < count ; ++ i )
2009-02-19 18:46:19 -06:00
{
2010-09-14 13:56:27 +02:00
PoolObject * obj = RollOne ( spawns , triggerFrom );
2010-02-14 19:13:14 -07:00
if ( ! obj )
2009-12-18 06:54:49 +01:00
continue ;
2010-02-14 19:13:14 -07:00
if ( obj -> guid == lastDespawned )
2009-12-18 06:54:49 +01:00
continue ;
2009-10-17 15:51:44 -07:00
2010-02-14 19:13:14 -07:00
if ( obj -> guid == triggerFrom )
2009-12-18 06:54:49 +01:00
{
2010-02-14 19:13:14 -07:00
ReSpawn1Object ( obj );
2009-12-18 06:54:49 +01:00
triggerFrom = 0 ;
continue ;
}
2010-09-14 13:56:27 +02:00
spawns . ActivateObject < T > ( obj -> guid , poolId );
2010-02-14 19:13:14 -07:00
Spawn1Object ( obj );
2009-10-17 15:51:44 -07:00
2009-12-18 06:54:49 +01:00
if ( triggerFrom )
{
// One spawn one despawn no count increase
2010-02-14 19:13:14 -07:00
DespawnObject ( spawns , triggerFrom );
2009-12-18 06:54:49 +01:00
lastDespawned = triggerFrom ;
triggerFrom = 0 ;
2009-02-19 18:50:12 -06:00
}
}
}
2009-10-17 15:51:44 -07:00
2009-02-19 18:50:12 -06:00
// Method that is actualy doing the spawn job on 1 creature
template <>
2010-02-14 19:13:14 -07:00
void PoolGroup < Creature >:: Spawn1Object ( PoolObject * obj )
2009-02-19 18:50:12 -06:00
{
2010-12-22 21:25:23 +01:00
if ( CreatureData const * data = sObjectMgr -> GetCreatureData ( obj -> guid ))
2009-02-19 18:50:12 -06:00
{
2010-12-22 21:25:23 +01:00
sObjectMgr -> AddCreatureToGrid ( obj -> guid , data );
2009-10-17 15:51:44 -07:00
2009-02-19 18:50:12 -06:00
// Spawn if necessary (loaded grids only)
2011-11-23 12:51:20 -05:00
Map * map = sMapMgr -> CreateBaseMap ( data -> mapid );
2009-02-19 18:50:12 -06:00
// We use spawn coords to spawn
2011-10-18 11:51:30 -04:00
if ( ! map -> Instanceable () && map -> IsGridLoaded ( data -> posX , data -> posY ))
2009-02-19 18:50:12 -06:00
{
2011-10-07 11:08:09 -05:00
Creature * creature = new Creature ;
2011-04-29 20:47:02 +02:00
//sLog->outDebug(LOG_FILTER_POOLSYS, "Spawning creature %u", guid);
2011-10-07 11:08:09 -05:00
if ( ! creature -> LoadFromDB ( obj -> guid , map ))
2009-12-18 06:54:49 +01:00
{
2011-10-07 11:08:09 -05:00
delete creature ;
2010-02-14 19:13:14 -07:00
return ;
2009-12-18 06:54:49 +01:00
}
2009-02-19 18:50:12 -06:00
else
2011-10-10 17:39:34 -04:00
map -> AddToMap ( creature );
2009-02-19 18:50:12 -06:00
}
}
}
2009-10-17 15:51:44 -07:00
2009-02-19 18:50:12 -06:00
// Same for 1 gameobject
template <>
2010-02-14 19:13:14 -07:00
void PoolGroup < GameObject >:: Spawn1Object ( PoolObject * obj )
2009-02-19 18:50:12 -06:00
{
2010-12-22 21:25:23 +01:00
if ( GameObjectData const * data = sObjectMgr -> GetGOData ( obj -> guid ))
2009-02-19 18:50:12 -06:00
{
2010-12-22 21:25:23 +01:00
sObjectMgr -> AddGameobjectToGrid ( obj -> guid , data );
2009-02-19 18:50:12 -06:00
// Spawn if necessary (loaded grids only)
// this base map checked as non-instanced and then only existed
2011-11-23 12:51:20 -05:00
Map * map = sMapMgr -> CreateBaseMap ( data -> mapid );
2009-02-19 18:50:12 -06:00
// We use current coords to unspawn, not spawn coords since creature can have changed grid
2011-10-18 11:51:30 -04:00
if ( ! map -> Instanceable () && map -> IsGridLoaded ( data -> posX , data -> posY ))
2009-02-19 18:50:12 -06:00
{
GameObject * pGameobject = new GameObject ;
2011-02-20 20:16:34 +01:00
//sLog->outDebug(LOG_FILTER_POOLSYS, "Spawning gameobject %u", guid);
2010-02-14 19:13:14 -07:00
if ( ! pGameobject -> LoadFromDB ( obj -> guid , map ))
2009-12-18 06:54:49 +01:00
{
2009-02-19 18:50:12 -06:00
delete pGameobject ;
2010-02-14 19:13:14 -07:00
return ;
2009-12-18 06:54:49 +01:00
}
2009-02-19 18:50:12 -06:00
else
{
if ( pGameobject -> isSpawnedByDefault ())
2011-10-10 17:39:34 -04:00
map -> AddToMap ( pGameobject );
2009-02-19 18:50:12 -06:00
}
}
}
}
2009-10-17 15:51:44 -07:00
2010-09-14 16:14:43 +02:00
// Same for 1 pool
template <>
void PoolGroup < Pool >:: Spawn1Object ( PoolObject * obj )
{
2010-12-22 21:25:23 +01:00
sPoolMgr -> SpawnPool ( obj -> guid );
2010-09-14 16:14:43 +02:00
}
2010-09-14 13:56:27 +02:00
// Same for 1 quest
template <>
void PoolGroup < Quest >:: Spawn1Object ( PoolObject * obj )
{
// Creatures
2010-12-22 21:25:23 +01:00
QuestRelations * questMap = sObjectMgr -> GetCreatureQuestRelationMap ();
PooledQuestRelationBoundsNC qr = sPoolMgr -> mQuestCreatureRelation . equal_range ( obj -> guid );
2010-09-14 13:56:27 +02:00
for ( PooledQuestRelation :: iterator itr = qr . first ; itr != qr . second ; ++ itr )
{
2011-02-20 20:16:34 +01:00
sLog -> outDebug ( LOG_FILTER_POOLSYS , "PoolGroup<Quest>: Adding quest %u to creature %u" , itr -> first , itr -> second );
2010-09-14 13:56:27 +02:00
questMap -> insert ( QuestRelations :: value_type ( itr -> second , itr -> first ));
}
// Gameobjects
2010-12-22 21:25:23 +01:00
questMap = sObjectMgr -> GetGOQuestRelationMap ();
qr = sPoolMgr -> mQuestGORelation . equal_range ( obj -> guid );
2010-09-14 13:56:27 +02:00
for ( PooledQuestRelation :: iterator itr = qr . first ; itr != qr . second ; ++ itr )
{
2011-02-20 20:16:34 +01:00
sLog -> outDebug ( LOG_FILTER_POOLSYS , "PoolGroup<Quest>: Adding quest %u to GO %u" , itr -> first , itr -> second );
2010-09-14 13:56:27 +02:00
questMap -> insert ( QuestRelations :: value_type ( itr -> second , itr -> first ));
}
}
2009-02-19 18:50:12 -06:00
template <>
2010-09-14 16:14:43 +02:00
void PoolGroup < Quest >:: SpawnObject ( ActivePoolData & spawns , uint32 limit , uint32 triggerFrom )
2009-02-19 18:50:12 -06:00
{
2011-02-20 20:16:34 +01:00
sLog -> outDebug ( LOG_FILTER_POOLSYS , "PoolGroup<Quest>: Spawning pool %u" , poolId );
2010-09-14 16:14:43 +02:00
// load state from db
if ( ! triggerFrom )
{
QueryResult result = CharacterDatabase . PQuery ( "SELECT quest_id FROM pool_quest_save WHERE pool_id = %u" , poolId );
if ( result )
{
do
{
uint32 questId = result -> Fetch ()[ 0 ]. GetUInt32 ();
spawns . ActivateObject < Quest > ( questId , poolId );
PoolObject tempObj ( questId , 0.0f );
Spawn1Object ( & tempObj );
-- limit ;
} while ( result -> NextRow () && limit );
return ;
}
}
ActivePoolObjects currentQuests = spawns . GetActiveQuests ();
ActivePoolObjects newQuests ;
// always try to select different quests
for ( PoolObjectList :: iterator itr = EqualChanced . begin (); itr != EqualChanced . end (); ++ itr )
{
if ( spawns . IsActiveObject < Quest > ( itr -> guid ))
continue ;
newQuests . insert ( itr -> guid );
}
// clear the pool
DespawnObject ( spawns );
// recycle minimal amount of quests if possible count is lower than limit
if ( limit > newQuests . size () && ! currentQuests . empty ())
{
do
{
2011-09-15 21:28:40 +03:00
uint32 questId = SelectRandomContainerElement ( currentQuests );
newQuests . insert ( questId );
currentQuests . erase ( questId );
2010-09-15 10:35:54 +02:00
} while ( newQuests . size () < limit && ! currentQuests . empty ()); // failsafe
2010-09-14 16:14:43 +02:00
}
if ( newQuests . empty ())
return ;
// activate <limit> random quests
do
{
2011-09-15 21:28:40 +03:00
uint32 questId = SelectRandomContainerElement ( newQuests );
spawns . ActivateObject < Quest > ( questId , poolId );
PoolObject tempObj ( questId , 0.0f );
2010-09-14 16:14:43 +02:00
Spawn1Object ( & tempObj );
2011-09-15 21:28:40 +03:00
newQuests . erase ( questId );
2010-09-14 16:14:43 +02:00
-- limit ;
2011-07-01 14:58:44 +02:00
} while ( limit && ! newQuests . empty ());
2010-09-14 16:14:43 +02:00
// if we are here it means the pool is initialized at startup and did not have previous saved state
if ( ! triggerFrom )
2010-12-22 21:25:23 +01:00
sPoolMgr -> SaveQuestsToDB ();
2009-02-19 18:50:12 -06:00
}
2009-10-17 15:51:44 -07:00
2009-02-19 18:50:12 -06:00
// Method that does the respawn job on the specified creature
template <>
2010-02-14 19:13:14 -07:00
void PoolGroup < Creature >:: ReSpawn1Object ( PoolObject * obj )
2009-02-19 18:50:12 -06:00
{
2010-12-22 21:25:23 +01:00
if ( CreatureData const * data = sObjectMgr -> GetCreatureData ( obj -> guid ))
2011-10-07 11:08:09 -05:00
if ( Creature * creature = ObjectAccessor :: GetObjectInWorld ( MAKE_NEW_GUID ( obj -> guid , data -> id , HIGHGUID_UNIT ), ( Creature * ) NULL ))
2011-10-10 17:39:34 -04:00
creature -> GetMap () -> AddToMap ( creature );
2009-02-19 18:50:12 -06:00
}
2009-10-17 15:51:44 -07:00
2010-02-14 19:13:14 -07:00
// Method that does the respawn job on the specified gameobject
2009-02-19 18:50:12 -06:00
template <>
2010-02-14 19:13:14 -07:00
void PoolGroup < GameObject >:: ReSpawn1Object ( PoolObject * obj )
2009-02-19 18:50:12 -06:00
{
2010-12-22 21:25:23 +01:00
if ( GameObjectData const * data = sObjectMgr -> GetGOData ( obj -> guid ))
2010-12-23 23:25:44 +01:00
if ( GameObject * pGameobject = ObjectAccessor :: GetObjectInWorld ( MAKE_NEW_GUID ( obj -> guid , data -> id , HIGHGUID_GAMEOBJECT ), ( GameObject * ) NULL ))
2011-10-10 17:39:34 -04:00
pGameobject -> GetMap () -> AddToMap ( pGameobject );
2009-02-19 18:50:12 -06:00
}
2009-10-17 15:51:44 -07:00
2010-09-14 16:14:43 +02:00
// Nothing to do for a child Pool
2010-09-14 13:56:27 +02:00
template <>
2010-09-14 16:14:43 +02:00
void PoolGroup < Pool >:: ReSpawn1Object ( PoolObject * /*obj*/ )
2010-09-14 13:56:27 +02:00
{
}
2010-09-14 16:14:43 +02:00
// Nothing to do for a quest
2009-02-19 18:50:12 -06:00
template <>
2010-09-14 16:14:43 +02:00
void PoolGroup < Quest >:: ReSpawn1Object ( PoolObject * /*obj*/ )
2009-02-19 18:50:12 -06:00
{
}
////////////////////////////////////////////////////////////
2010-06-25 03:50:19 -06:00
// Methods of class PoolMgr
2009-10-17 15:51:44 -07:00
2011-03-10 22:21:50 +01:00
PoolMgr :: PoolMgr () : max_pool_id ( 0 )
2009-02-19 18:50:12 -06:00
{
}
2009-10-17 15:51:44 -07:00
2011-03-10 22:21:50 +01:00
void PoolMgr :: Initialize ()
2009-02-19 18:50:12 -06:00
{
2010-09-11 21:10:54 +02:00
QueryResult result = WorldDatabase . Query ( "SELECT MAX(entry) FROM pool_template" );
2011-03-10 22:21:50 +01:00
if ( result )
2009-02-19 18:50:12 -06:00
{
2011-09-15 14:08:17 +02:00
Field * fields = result -> Fetch ();
2010-08-26 06:49:31 +03:00
max_pool_id = fields [ 0 ]. GetUInt32 ();
2009-02-19 18:46:19 -06:00
}
2009-10-17 15:51:44 -07:00
2009-02-19 18:50:12 -06:00
mPoolTemplate . resize ( max_pool_id + 1 );
2011-03-10 22:21:50 +01:00
mPoolCreatureGroups . resize ( max_pool_id + 1 );
mPoolGameobjectGroups . resize ( max_pool_id + 1 );
mPoolPoolGroups . resize ( max_pool_id + 1 );
mPoolQuestGroups . resize ( max_pool_id + 1 );
2009-10-17 15:51:44 -07:00
2011-03-10 22:21:50 +01:00
mQuestSearchMap . clear ();
mGameobjectSearchMap . clear ();
mCreatureSearchMap . clear ();
}
2009-10-17 15:51:44 -07:00
2011-03-10 22:21:50 +01:00
void PoolMgr :: LoadFromDB ()
{
// Pool templates
2009-02-19 18:50:12 -06:00
{
2011-03-10 22:21:50 +01:00
uint32 oldMSTime = getMSTime ();
2009-10-17 15:51:44 -07:00
2011-04-29 20:47:02 +02:00
QueryResult result = WorldDatabase . Query ( "SELECT entry, max_limit FROM pool_template" );
2011-03-10 22:21:50 +01:00
if ( ! result )
{
mPoolTemplate . clear ();
sLog -> outString ( ">> Loaded 0 object pools. DB table `pool_template` is empty." );
sLog -> outString ();
return ;
}
2009-10-17 15:51:44 -07:00
2011-03-10 22:21:50 +01:00
uint32 count = 0 ;
do
{
2011-09-15 14:08:17 +02:00
Field * fields = result -> Fetch ();
2009-10-17 15:51:44 -07:00
2011-03-10 22:21:50 +01:00
uint32 pool_id = fields [ 0 ]. GetUInt32 ();
2009-10-17 15:51:44 -07:00
2011-03-10 22:21:50 +01:00
PoolTemplateData & pPoolTemplate = mPoolTemplate [ pool_id ];
pPoolTemplate . MaxLimit = fields [ 1 ]. GetUInt32 ();
2010-01-01 14:19:29 -06:00
2011-03-10 22:21:50 +01:00
++ count ;
}
while ( result -> NextRow ());
2009-10-17 15:51:44 -07:00
2011-03-10 22:21:50 +01:00
sLog -> outString ( ">> Loaded %u objects pools in %u ms" , count , GetMSTimeDiffToNow ( oldMSTime ));
2010-12-23 23:25:44 +01:00
sLog -> outString ();
2009-02-19 18:46:19 -06:00
}
2009-10-17 15:51:44 -07:00
2011-03-10 22:21:50 +01:00
// Creatures
2009-10-17 15:51:44 -07:00
2011-03-10 22:21:50 +01:00
sLog -> outString ( "Loading Creatures Pooling Data..." );
{
uint32 oldMSTime = getMSTime ();
2009-10-17 15:51:44 -07:00
2011-03-10 22:21:50 +01:00
// 1 2 3
QueryResult result = WorldDatabase . Query ( "SELECT guid, pool_entry, chance FROM pool_creature" );
2009-10-17 15:51:44 -07:00
2011-03-10 22:21:50 +01:00
if ( ! result )
{
sLog -> outString ( ">> Loaded 0 creatures in pools. DB table `pool_creature` is empty." );
sLog -> outString ();
}
else
{
uint32 count = 0 ;
do
2009-02-19 18:46:19 -06:00
{
2011-09-15 14:08:17 +02:00
Field * fields = result -> Fetch ();
2009-10-17 15:51:44 -07:00
2011-03-10 22:21:50 +01:00
uint32 guid = fields [ 0 ]. GetUInt32 ();
uint32 pool_id = fields [ 1 ]. GetUInt32 ();
float chance = fields [ 2 ]. GetFloat ();
2010-12-19 17:06:33 +01:00
2011-03-10 22:21:50 +01:00
CreatureData const * data = sObjectMgr -> GetCreatureData ( guid );
if ( ! data )
{
sLog -> outErrorDb ( "`pool_creature` has a non existing creature spawn (GUID: %u) defined for pool id (%u), skipped." , guid , pool_id );
continue ;
}
if ( pool_id > max_pool_id )
{
2011-04-29 20:47:02 +02:00
sLog -> outErrorDb ( "`pool_creature` pool id (%u) is out of range compared to max pool id in `pool_template`, skipped." , pool_id );
2011-03-10 22:21:50 +01:00
continue ;
}
if ( chance < 0 || chance > 100 )
{
sLog -> outErrorDb ( "`pool_creature` has an invalid chance (%f) for creature guid (%u) in pool id (%u), skipped." , chance , guid , pool_id );
continue ;
}
2011-09-15 14:08:17 +02:00
PoolTemplateData * pPoolTemplate = & mPoolTemplate [ pool_id ];
2011-03-10 22:21:50 +01:00
PoolObject plObject = PoolObject ( guid , chance );
PoolGroup < Creature >& cregroup = mPoolCreatureGroups [ pool_id ];
cregroup . SetPoolId ( pool_id );
cregroup . AddEntry ( plObject , pPoolTemplate -> MaxLimit );
SearchPair p ( guid , pool_id );
mCreatureSearchMap . insert ( p );
++ count ;
}
while ( result -> NextRow ());
2011-01-26 01:03:35 +01:00
2011-03-10 22:21:50 +01:00
sLog -> outString ( ">> Loaded %u creatures in pools in %u ms" , count , GetMSTimeDiffToNow ( oldMSTime ));
sLog -> outString ();
}
2009-02-19 18:46:19 -06:00
}
2009-10-17 15:51:44 -07:00
2009-02-19 18:50:12 -06:00
// Gameobjects
2009-10-17 15:51:44 -07:00
2010-12-23 23:25:44 +01:00
sLog -> outString ( "Loading Gameobject Pooling Data..." );
2009-02-19 18:46:19 -06:00
{
2011-03-10 22:21:50 +01:00
uint32 oldMSTime = getMSTime ();
2009-10-17 15:51:44 -07:00
2011-03-10 22:21:50 +01:00
// 1 2 3
QueryResult result = WorldDatabase . Query ( "SELECT guid, pool_entry, chance FROM pool_gameobject" );
if ( ! result )
2009-02-19 18:46:19 -06:00
{
2011-03-10 22:21:50 +01:00
sLog -> outString ( ">> Loaded 0 gameobjects in pools. DB table `pool_gameobject` is empty." );
sLog -> outString ();
}
else
{
uint32 count = 0 ;
do
{
2011-09-15 14:08:17 +02:00
Field * fields = result -> Fetch ();
2009-10-17 15:51:44 -07:00
2011-03-10 22:21:50 +01:00
uint32 guid = fields [ 0 ]. GetUInt32 ();
uint32 pool_id = fields [ 1 ]. GetUInt32 ();
float chance = fields [ 2 ]. GetFloat ();
2009-10-17 15:51:44 -07:00
2011-03-10 22:21:50 +01:00
GameObjectData const * data = sObjectMgr -> GetGOData ( guid );
if ( ! data )
{
sLog -> outErrorDb ( "`pool_gameobject` has a non existing gameobject spawn (GUID: %u) defined for pool id (%u), skipped." , guid , pool_id );
continue ;
}
2009-10-17 15:51:44 -07:00
2011-04-28 22:54:30 +02:00
GameObjectTemplate const * goinfo = sObjectMgr -> GetGameObjectTemplate ( data -> id );
2011-03-10 22:21:50 +01:00
if ( goinfo -> type != GAMEOBJECT_TYPE_CHEST &&
goinfo -> type != GAMEOBJECT_TYPE_GOOBER &&
goinfo -> type != GAMEOBJECT_TYPE_FISHINGHOLE )
{
sLog -> outErrorDb ( "`pool_gameobject` has a not lootable gameobject spawn (GUID: %u, type: %u) defined for pool id (%u), skipped." , guid , goinfo -> type , pool_id );
continue ;
}
2009-10-17 15:51:44 -07:00
2011-03-10 22:21:50 +01:00
if ( pool_id > max_pool_id )
{
2011-04-29 20:47:02 +02:00
sLog -> outErrorDb ( "`pool_gameobject` pool id (%u) is out of range compared to max pool id in `pool_template`, skipped." , pool_id );
2011-03-10 22:21:50 +01:00
continue ;
}
2009-10-17 15:51:44 -07:00
2011-03-10 22:21:50 +01:00
if ( chance < 0 || chance > 100 )
{
sLog -> outErrorDb ( "`pool_gameobject` has an invalid chance (%f) for gameobject guid (%u) in pool id (%u), skipped." , chance , guid , pool_id );
continue ;
}
2009-10-17 15:51:44 -07:00
2011-09-15 14:08:17 +02:00
PoolTemplateData * pPoolTemplate = & mPoolTemplate [ pool_id ];
2011-03-10 22:21:50 +01:00
PoolObject plObject = PoolObject ( guid , chance );
PoolGroup < GameObject >& gogroup = mPoolGameobjectGroups [ pool_id ];
gogroup . SetPoolId ( pool_id );
gogroup . AddEntry ( plObject , pPoolTemplate -> MaxLimit );
SearchPair p ( guid , pool_id );
mGameobjectSearchMap . insert ( p );
2010-12-19 17:06:33 +01:00
2011-03-10 22:21:50 +01:00
++ count ;
}
while ( result -> NextRow ());
sLog -> outString ( ">> Loaded %u gameobject in pools in %u ms" , count , GetMSTimeDiffToNow ( oldMSTime ));
sLog -> outString ();
}
2009-02-19 18:46:19 -06:00
}
2009-10-17 15:51:44 -07:00
2009-02-19 18:50:12 -06:00
// Pool of pools
2010-01-01 14:19:29 -06:00
2010-12-23 23:25:44 +01:00
sLog -> outString ( "Loading Mother Pooling Data..." );
2009-02-19 18:46:19 -06:00
{
2011-03-10 22:21:50 +01:00
uint32 oldMSTime = getMSTime ();
2009-10-17 15:51:44 -07:00
2011-03-10 22:21:50 +01:00
// 1 2 3
QueryResult result = WorldDatabase . Query ( "SELECT pool_id, mother_pool, chance FROM pool_pool" );
2009-10-17 15:51:44 -07:00
2011-03-10 22:21:50 +01:00
if ( ! result )
{
sLog -> outString ( ">> Loaded 0 pools in pools" );
sLog -> outString ();
}
else
{
uint32 count = 0 ;
do
{
2011-09-15 14:08:17 +02:00
Field * fields = result -> Fetch ();
2009-10-17 15:51:44 -07:00
2011-03-10 22:21:50 +01:00
uint32 child_pool_id = fields [ 0 ]. GetUInt32 ();
uint32 mother_pool_id = fields [ 1 ]. GetUInt32 ();
float chance = fields [ 2 ]. GetFloat ();
2009-10-17 15:51:44 -07:00
2011-03-10 22:21:50 +01:00
if ( mother_pool_id > max_pool_id )
{
2011-04-29 20:47:02 +02:00
sLog -> outErrorDb ( "`pool_pool` mother_pool id (%u) is out of range compared to max pool id in `pool_template`, skipped." , mother_pool_id );
2011-03-10 22:21:50 +01:00
continue ;
}
if ( child_pool_id > max_pool_id )
{
2011-04-29 20:47:02 +02:00
sLog -> outErrorDb ( "`pool_pool` included pool_id (%u) is out of range compared to max pool id in `pool_template`, skipped." , child_pool_id );
2011-03-10 22:21:50 +01:00
continue ;
}
if ( mother_pool_id == child_pool_id )
{
2011-04-29 20:47:02 +02:00
sLog -> outErrorDb ( "`pool_pool` pool_id (%u) includes itself, dead-lock detected, skipped." , child_pool_id );
2011-03-10 22:21:50 +01:00
continue ;
}
if ( chance < 0 || chance > 100 )
{
sLog -> outErrorDb ( "`pool_pool` has an invalid chance (%f) for pool id (%u) in mother pool id (%u), skipped." , chance , child_pool_id , mother_pool_id );
continue ;
}
2011-09-15 14:08:17 +02:00
PoolTemplateData * pPoolTemplateMother = & mPoolTemplate [ mother_pool_id ];
2011-03-10 22:21:50 +01:00
PoolObject plObject = PoolObject ( child_pool_id , chance );
PoolGroup < Pool >& plgroup = mPoolPoolGroups [ mother_pool_id ];
plgroup . SetPoolId ( mother_pool_id );
plgroup . AddEntry ( plObject , pPoolTemplateMother -> MaxLimit );
SearchPair p ( child_pool_id , mother_pool_id );
mPoolSearchMap . insert ( p );
++ count ;
2009-02-19 18:50:12 -06:00
}
2011-03-10 22:21:50 +01:00
while ( result -> NextRow ());
// Now check for circular reference
2011-07-01 14:58:44 +02:00
for ( uint32 i = 0 ; i < max_pool_id ; ++ i )
2009-02-19 18:50:12 -06:00
{
2011-03-10 22:21:50 +01:00
std :: set < uint32 > checkedPools ;
for ( SearchMap :: iterator poolItr = mPoolSearchMap . find ( i ); poolItr != mPoolSearchMap . end (); poolItr = mPoolSearchMap . find ( poolItr -> second ))
{
checkedPools . insert ( poolItr -> first );
if ( checkedPools . find ( poolItr -> second ) != checkedPools . end ())
{
std :: ostringstream ss ;
ss << "The pool(s) " ;
for ( std :: set < uint32 >:: const_iterator itr = checkedPools . begin (); itr != checkedPools . end (); ++ itr )
2011-07-29 14:18:28 +02:00
ss << * itr << ' ' ;
2011-03-10 22:21:50 +01:00
ss << "create(s) a circular reference, which can cause the server to freeze. \n Removing the last link between mother pool "
<< poolItr -> first << " and child pool " << poolItr -> second ;
sLog -> outErrorDb ( "%s" , ss . str (). c_str ());
mPoolPoolGroups [ poolItr -> second ]. RemoveOneRelation ( poolItr -> first );
mPoolSearchMap . erase ( poolItr );
-- count ;
break ;
}
}
2009-02-19 18:50:12 -06:00
}
2009-10-17 15:51:44 -07:00
2011-03-10 22:21:50 +01:00
sLog -> outString ( ">> Loaded %u pools in mother pools in %u ms" , count , GetMSTimeDiffToNow ( oldMSTime ));
sLog -> outString ();
}
}
2009-10-17 15:51:44 -07:00
2011-03-10 22:21:50 +01:00
sLog -> outString ( "Loading Quest Pooling Data..." );
{
uint32 oldMSTime = getMSTime ();
2009-10-17 15:51:44 -07:00
2011-03-10 22:21:50 +01:00
PreparedStatement * stmt = WorldDatabase . GetPreparedStatement ( WORLD_LOAD_QUEST_POOLS );
PreparedQueryResult result = WorldDatabase . Query ( stmt );
2009-10-17 15:51:44 -07:00
2011-03-10 22:21:50 +01:00
if ( ! result )
2009-02-19 18:46:19 -06:00
{
2011-03-10 22:21:50 +01:00
sLog -> outString ( ">> Loaded 0 quests in pools" );
sLog -> outString ();
2009-02-19 18:46:19 -06:00
}
2011-03-10 22:21:50 +01:00
else
{
PooledQuestRelationBounds creBounds ;
PooledQuestRelationBounds goBounds ;
2010-01-01 14:19:29 -06:00
2011-03-10 22:21:50 +01:00
enum eQuestTypes
{
QUEST_NONE = 0 ,
QUEST_DAILY = 1 ,
QUEST_WEEKLY = 2
};
2009-10-17 15:51:44 -07:00
2011-03-10 22:21:50 +01:00
std :: map < uint32 , int32 > poolTypeMap ;
uint32 count = 0 ;
do
{
Field * fields = result -> Fetch ();
2010-12-19 17:06:33 +01:00
2011-03-10 22:21:50 +01:00
uint32 entry = fields [ 0 ]. GetUInt32 ();
uint32 pool_id = fields [ 1 ]. GetUInt32 ();
2010-09-14 13:56:27 +02:00
2011-10-07 19:45:43 -05:00
Quest const * quest = sObjectMgr -> GetQuestTemplate ( entry );
if ( ! quest )
2011-03-10 22:21:50 +01:00
{
sLog -> outErrorDb ( "`pool_quest` has a non existing quest template (Entry: %u) defined for pool id (%u), skipped." , entry , pool_id );
continue ;
}
2010-09-14 13:56:27 +02:00
2011-03-10 22:21:50 +01:00
if ( pool_id > max_pool_id )
{
2011-04-29 20:47:02 +02:00
sLog -> outErrorDb ( "`pool_quest` pool id (%u) is out of range compared to max pool id in `pool_template`, skipped." , pool_id );
2011-03-10 22:21:50 +01:00
continue ;
}
2010-09-14 13:56:27 +02:00
2011-10-07 19:45:43 -05:00
if ( ! quest -> IsDailyOrWeekly ())
2011-03-10 22:21:50 +01:00
{
sLog -> outErrorDb ( "`pool_quest` has an quest (%u) which is not daily or weekly in pool id (%u), use ExclusiveGroup instead, skipped." , entry , pool_id );
continue ;
}
2010-09-14 13:56:27 +02:00
2011-03-10 22:21:50 +01:00
if ( poolTypeMap [ pool_id ] == QUEST_NONE )
2011-10-07 19:45:43 -05:00
poolTypeMap [ pool_id ] = quest -> IsDaily () ? QUEST_DAILY : QUEST_WEEKLY ;
2010-09-15 10:35:54 +02:00
2011-10-07 19:45:43 -05:00
int32 currType = quest -> IsDaily () ? QUEST_DAILY : QUEST_WEEKLY ;
2010-09-14 13:56:27 +02:00
2011-03-10 22:21:50 +01:00
if ( poolTypeMap [ pool_id ] != currType )
{
sLog -> outErrorDb ( "`pool_quest` quest %u is %s but pool (%u) is specified for %s, mixing not allowed, skipped." ,
entry , currType == QUEST_DAILY ? "QUEST_DAILY" : "QUEST_WEEKLY" , pool_id , poolTypeMap [ pool_id ] == QUEST_DAILY ? "QUEST_DAILY" : "QUEST_WEEKLY" );
continue ;
}
2010-09-14 13:56:27 +02:00
2011-03-10 22:21:50 +01:00
creBounds = mQuestCreatureRelation . equal_range ( entry );
goBounds = mQuestGORelation . equal_range ( entry );
2010-09-24 22:16:21 +02:00
2011-03-10 22:21:50 +01:00
if ( creBounds . first == creBounds . second && goBounds . first == goBounds . second )
{
sLog -> outErrorDb ( "`pool_quest` lists entry (%u) as member of pool (%u) but is not started anywhere, skipped." , entry , pool_id );
continue ;
}
2010-09-14 13:56:27 +02:00
2011-09-15 14:08:17 +02:00
PoolTemplateData * pPoolTemplate = & mPoolTemplate [ pool_id ];
2011-03-10 22:21:50 +01:00
PoolObject plObject = PoolObject ( entry , 0.0f );
PoolGroup < Quest >& questgroup = mPoolQuestGroups [ pool_id ];
questgroup . SetPoolId ( pool_id );
questgroup . AddEntry ( plObject , pPoolTemplate -> MaxLimit );
SearchPair p ( entry , pool_id );
mQuestSearchMap . insert ( p );
2010-09-14 13:56:27 +02:00
2011-03-10 22:21:50 +01:00
++ count ;
}
while ( result -> NextRow ());
2010-09-14 13:56:27 +02:00
2011-03-10 22:21:50 +01:00
sLog -> outString ( ">> Loaded %u quests in pools in %u ms" , count , GetMSTimeDiffToNow ( oldMSTime ));
sLog -> outString ();
2010-09-14 13:56:27 +02:00
}
2011-03-10 22:21:50 +01:00
}
2010-09-14 13:56:27 +02:00
2011-03-10 22:21:50 +01:00
// The initialize method will spawn all pools not in an event and not in another pool, this is why there is 2 left joins with 2 null checks
sLog -> outString ( "Starting objects pooling system..." );
{
uint32 oldMSTime = getMSTime ();
2010-09-14 13:56:27 +02:00
2011-03-10 22:21:50 +01:00
QueryResult result = WorldDatabase . Query ( "SELECT DISTINCT pool_template.entry, pool_pool.pool_id, pool_pool.mother_pool FROM pool_template"
" LEFT JOIN game_event_pool ON pool_template.entry=game_event_pool.pool_entry"
" LEFT JOIN pool_pool ON pool_template.entry=pool_pool.pool_id WHERE game_event_pool.pool_entry IS NULL" );
2010-09-14 13:56:27 +02:00
2011-03-10 22:21:50 +01:00
if ( ! result )
2010-09-14 13:56:27 +02:00
{
2011-03-10 22:21:50 +01:00
sLog -> outString ( ">> Pool handling system initialized, 0 pools spawned." );
sLog -> outString ();
2010-09-14 13:56:27 +02:00
}
2011-03-10 22:21:50 +01:00
else
2010-09-14 13:56:27 +02:00
{
2011-03-10 22:21:50 +01:00
uint32 count = 0 ;
do
{
2011-09-15 14:08:17 +02:00
Field * fields = result -> Fetch ();
2011-03-10 22:21:50 +01:00
uint32 pool_entry = fields [ 0 ]. GetUInt32 ();
uint32 pool_pool_id = fields [ 1 ]. GetUInt32 ();
2010-09-14 13:56:27 +02:00
2011-03-10 22:21:50 +01:00
if ( ! CheckPool ( pool_entry ))
{
if ( pool_pool_id )
// The pool is a child pool in pool_pool table. Ideally we should remove it from the pool handler to ensure it never gets spawned,
// however that could recursively invalidate entire chain of mother pools. It can be done in the future but for now we'll do nothing.
sLog -> outErrorDb ( "Pool Id %u has no equal chance pooled entites defined and explicit chance sum is not 100. This broken pool is a child pool of Id %u and cannot be safely removed." , pool_entry , fields [ 2 ]. GetUInt32 ());
else
sLog -> outErrorDb ( "Pool Id %u has no equal chance pooled entites defined and explicit chance sum is not 100. The pool will not be spawned." , pool_entry );
continue ;
}
2010-09-14 13:56:27 +02:00
2011-03-10 22:21:50 +01:00
// Don't spawn child pools, they are spawned recursively by their parent pools
if ( ! pool_pool_id )
{
SpawnPool ( pool_entry );
count ++ ;
}
}
while ( result -> NextRow ());
2010-09-14 13:56:27 +02:00
2011-03-10 22:21:50 +01:00
sLog -> outBasic ( "Pool handling system initialized, %u pools spawned in %u ms" , count , GetMSTimeDiffToNow ( oldMSTime ));
sLog -> outString ();
}
2010-09-24 22:16:21 +02:00
}
2010-09-14 13:56:27 +02:00
}
2011-03-10 22:21:50 +01:00
void PoolMgr :: LoadQuestPools ()
2009-02-19 18:46:19 -06:00
{
2009-10-17 15:51:44 -07:00
2009-02-19 18:46:19 -06:00
}
2009-10-17 15:51:44 -07:00
2010-09-14 13:56:27 +02:00
void PoolMgr :: SaveQuestsToDB ()
{
SQLTransaction trans = CharacterDatabase . BeginTransaction ();
2010-09-17 21:01:58 +02:00
2010-09-14 13:56:27 +02:00
for ( PoolGroupQuestMap :: iterator itr = mPoolQuestGroups . begin (); itr != mPoolQuestGroups . end (); ++ itr )
{
2010-11-12 17:12:38 +01:00
if ( itr -> isEmpty ())
continue ;
2010-09-17 21:01:58 +02:00
PreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_DEL_QUEST_POOL_SAVE );
stmt -> setUInt32 ( 0 , itr -> GetPoolId ());
trans -> Append ( stmt );
2010-09-14 13:56:27 +02:00
}
for ( SearchMap :: iterator itr = mQuestSearchMap . begin (); itr != mQuestSearchMap . end (); ++ itr )
{
if ( IsSpawnedObject < Quest > ( itr -> first ))
{
2010-09-17 21:01:58 +02:00
PreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_ADD_QUEST_POOL_SAVE );
stmt -> setUInt32 ( 0 , itr -> second );
stmt -> setUInt32 ( 1 , itr -> first );
trans -> Append ( stmt );
2010-09-14 13:56:27 +02:00
}
}
CharacterDatabase . CommitTransaction ( trans );
}
void PoolMgr :: ChangeDailyQuests ()
{
for ( PoolGroupQuestMap :: iterator itr = mPoolQuestGroups . begin (); itr != mPoolQuestGroups . end (); ++ itr )
{
2011-10-07 19:45:43 -05:00
if ( Quest const * quest = sObjectMgr -> GetQuestTemplate ( itr -> GetFirstEqualChancedObjectId ()))
2010-09-14 13:56:27 +02:00
{
2011-10-07 19:45:43 -05:00
if ( quest -> IsWeekly ())
2010-09-14 13:56:27 +02:00
continue ;
UpdatePool < Quest > ( itr -> GetPoolId (), 1 ); // anything non-zero means don't load from db
}
}
SaveQuestsToDB ();
}
void PoolMgr :: ChangeWeeklyQuests ()
{
for ( PoolGroupQuestMap :: iterator itr = mPoolQuestGroups . begin (); itr != mPoolQuestGroups . end (); ++ itr )
{
2011-10-07 19:45:43 -05:00
if ( Quest const * quest = sObjectMgr -> GetQuestTemplate ( itr -> GetFirstEqualChancedObjectId ()))
2010-09-14 13:56:27 +02:00
{
2011-10-07 19:45:43 -05:00
if ( quest -> IsDaily ())
2010-09-14 13:56:27 +02:00
continue ;
UpdatePool < Quest > ( itr -> GetPoolId (), 1 );
}
}
SaveQuestsToDB ();
}
2009-02-19 18:50:12 -06:00
// Call to spawn a pool, if cache if true the method will spawn only if cached entry is different
2010-02-14 19:13:14 -07:00
// If it's same, the creature is respawned only (added back to map)
template <>
2010-08-26 06:49:31 +03:00
void PoolMgr :: SpawnPool < Creature > ( uint32 pool_id , uint32 db_guid )
2009-02-19 18:46:19 -06:00
{
2010-02-14 19:13:14 -07:00
if ( ! mPoolCreatureGroups [ pool_id ]. isEmpty ())
mPoolCreatureGroups [ pool_id ]. SpawnObject ( mSpawnedData , mPoolTemplate [ pool_id ]. MaxLimit , db_guid );
2009-02-19 18:46:19 -06:00
}
2009-10-17 15:51:44 -07:00
2010-02-14 19:13:14 -07:00
// 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 <>
2010-08-26 06:49:31 +03:00
void PoolMgr :: SpawnPool < GameObject > ( uint32 pool_id , uint32 db_guid )
2009-02-19 18:46:19 -06:00
{
2009-12-18 06:54:49 +01:00
if ( ! mPoolGameobjectGroups [ pool_id ]. isEmpty ())
2010-02-14 19:13:14 -07:00
mPoolGameobjectGroups [ pool_id ]. SpawnObject ( mSpawnedData , mPoolTemplate [ pool_id ]. MaxLimit , db_guid );
}
2009-12-18 06:54:49 +01:00
2010-02-14 19:13:14 -07:00
// 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 <>
2010-08-26 06:49:31 +03:00
void PoolMgr :: SpawnPool < Pool > ( uint32 pool_id , uint32 sub_pool_id )
2010-02-14 19:13:14 -07:00
{
2009-12-18 06:54:49 +01:00
if ( ! mPoolPoolGroups [ pool_id ]. isEmpty ())
2010-02-14 19:13:14 -07:00
mPoolPoolGroups [ pool_id ]. SpawnObject ( mSpawnedData , mPoolTemplate [ pool_id ]. MaxLimit , sub_pool_id );
2009-02-19 18:46:19 -06:00
}
2009-10-17 15:51:44 -07:00
2010-09-14 16:14:43 +02:00
// Call to spawn a pool
template <>
void PoolMgr :: SpawnPool < Quest > ( uint32 pool_id , uint32 quest_id )
{
if ( ! mPoolQuestGroups [ pool_id ]. isEmpty ())
mPoolQuestGroups [ pool_id ]. SpawnObject ( mSpawnedData , mPoolTemplate [ pool_id ]. MaxLimit , quest_id );
}
2010-08-26 06:49:31 +03:00
void PoolMgr :: SpawnPool ( uint32 pool_id )
2009-02-19 18:46:19 -06:00
{
2010-02-14 19:13:14 -07:00
SpawnPool < Pool > ( pool_id , 0 );
SpawnPool < GameObject > ( pool_id , 0 );
SpawnPool < Creature > ( pool_id , 0 );
2010-09-14 13:56:27 +02:00
SpawnPool < Quest > ( pool_id , 0 );
2009-02-19 18:50:12 -06:00
}
2009-10-17 15:51:44 -07:00
2010-02-14 19:13:14 -07:00
// Call to despawn a pool, all gameobjects/creatures in this pool are removed
2010-08-26 06:49:31 +03:00
void PoolMgr :: DespawnPool ( uint32 pool_id )
2009-02-19 18:50:12 -06:00
{
2010-02-14 19:13:14 -07:00
if ( ! mPoolCreatureGroups [ pool_id ]. isEmpty ())
mPoolCreatureGroups [ pool_id ]. DespawnObject ( mSpawnedData );
if ( ! mPoolGameobjectGroups [ pool_id ]. isEmpty ())
mPoolGameobjectGroups [ pool_id ]. DespawnObject ( mSpawnedData );
if ( ! mPoolPoolGroups [ pool_id ]. isEmpty ())
mPoolPoolGroups [ pool_id ]. DespawnObject ( mSpawnedData );
2010-09-14 16:14:43 +02:00
if ( ! mPoolQuestGroups [ pool_id ]. isEmpty ())
mPoolQuestGroups [ pool_id ]. DespawnObject ( mSpawnedData );
2009-02-19 18:46:19 -06:00
}
2009-10-17 15:51:44 -07:00
2009-02-19 18:50:12 -06:00
// Method that check chance integrity of the creatures and gameobjects in this pool
2010-08-26 06:49:31 +03:00
bool PoolMgr :: CheckPool ( uint32 pool_id ) const
2009-02-19 18:46:19 -06:00
{
2009-03-28 16:14:56 -06:00
return pool_id <= max_pool_id &&
mPoolGameobjectGroups [ pool_id ]. CheckPool () &&
2009-02-19 18:50:12 -06:00
mPoolCreatureGroups [ pool_id ]. CheckPool () &&
2010-09-14 16:14:43 +02:00
mPoolPoolGroups [ pool_id ]. CheckPool () &&
mPoolQuestGroups [ pool_id ]. CheckPool ();
2009-02-19 18:50:12 -06:00
}
2009-10-17 15:51:44 -07:00
2010-02-14 19:13:14 -07:00
// Call to update the pool when a gameobject/creature part of pool [pool_id] is ready to respawn
// Here we cache only the creature/gameobject whose guid is passed as parameter
// Then the spawn pool call will use this cache to decide
template < typename T >
2010-08-26 06:49:31 +03:00
void PoolMgr :: UpdatePool ( uint32 pool_id , uint32 db_guid_or_pool_id )
2009-02-19 18:50:12 -06:00
{
2010-08-26 06:49:31 +03:00
if ( uint32 motherpoolid = IsPartOfAPool < Pool > ( pool_id ))
2010-02-14 19:13:14 -07:00
SpawnPool < Pool > ( motherpoolid , pool_id );
2009-02-19 18:50:12 -06:00
else
2010-02-14 19:13:14 -07:00
SpawnPool < T > ( pool_id , db_guid_or_pool_id );
2009-02-19 18:46:19 -06:00
}
2010-02-14 19:13:14 -07:00
2010-08-26 06:49:31 +03:00
template void PoolMgr :: UpdatePool < Pool > ( uint32 pool_id , uint32 db_guid_or_pool_id );
template void PoolMgr :: UpdatePool < GameObject > ( uint32 pool_id , uint32 db_guid_or_pool_id );
template void PoolMgr :: UpdatePool < Creature > ( uint32 pool_id , uint32 db_guid_or_pool_id );
2010-09-14 13:56:27 +02:00
template void PoolMgr :: UpdatePool < Quest > ( uint32 pool_id , uint32 db_guid_or_pool_id );