2009-02-19 18:46:19 -06:00
/*
2009-02-19 18:47:52 -06:00
* Copyright (C) 2005-2009 MaNGOS <http://www.mangosproject.org/>
2009-02-19 18:46:19 -06: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.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
2009-10-17 15:51:44 -07:00
2009-02-19 18:46:19 -06:00
#include "PoolHandler.h"
#include "ObjectMgr.h"
#include "ProgressBar.h"
#include "Log.h"
#include "MapManager.h"
2009-10-17 15:51:44 -07:00
2010-02-14 19:13:14 -07:00
////////////////////////////////////////////////////////////
// template class SpawnedPoolData
// Method that tell amount spawned objects/subpools
uint32 SpawnedPoolData :: GetSpawnedObjects ( uint32 pool_id ) const
{
SpawnedPoolPools :: const_iterator itr = mSpawnedPools . find ( pool_id );
return itr != mSpawnedPools . end () ? itr -> second : 0 ;
}
// Method that tell if a creature is spawned currently
template <>
bool SpawnedPoolData :: IsSpawnedObject < Creature > ( uint32 db_guid ) const
{
return mSpawnedCreatures . find ( db_guid ) != mSpawnedCreatures . end ();
}
// Method that tell if a gameobject is spawned currently
template <>
bool SpawnedPoolData :: IsSpawnedObject < GameObject > ( uint32 db_guid ) const
{
return mSpawnedGameobjects . find ( db_guid ) != mSpawnedGameobjects . end ();
}
// Method that tell if a pool is spawned currently
template <>
bool SpawnedPoolData :: IsSpawnedObject < Pool > ( uint32 sub_pool_id ) const
{
return mSpawnedPools . find ( sub_pool_id ) != mSpawnedPools . end ();
}
template <>
void SpawnedPoolData :: AddSpawn < Creature > ( uint32 db_guid , uint32 pool_id )
{
mSpawnedCreatures . insert ( db_guid );
++ mSpawnedPools [ pool_id ];
}
template <>
void SpawnedPoolData :: AddSpawn < GameObject > ( uint32 db_guid , uint32 pool_id )
{
mSpawnedGameobjects . insert ( db_guid );
++ mSpawnedPools [ pool_id ];
}
template <>
void SpawnedPoolData :: AddSpawn < Pool > ( uint32 sub_pool_id , uint32 pool_id )
{
mSpawnedPools [ sub_pool_id ] = 0 ;
++ mSpawnedPools [ pool_id ];
}
template <>
void SpawnedPoolData :: RemoveSpawn < Creature > ( uint32 db_guid , uint32 pool_id )
{
mSpawnedCreatures . erase ( db_guid );
uint32 & val = mSpawnedPools [ pool_id ];
if ( val > 0 )
-- val ;
}
template <>
void SpawnedPoolData :: RemoveSpawn < GameObject > ( uint32 db_guid , uint32 pool_id )
{
mSpawnedGameobjects . erase ( db_guid );
uint32 & val = mSpawnedPools [ pool_id ];
if ( val > 0 )
-- val ;
}
template <>
void SpawnedPoolData :: RemoveSpawn < Pool > ( uint32 sub_pool_id , uint32 pool_id )
{
mSpawnedPools . erase ( sub_pool_id );
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
{
2010-06-17 05:37:37 +02:00
if ( ! EqualChanced . size ())
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-02-14 19:13:14 -07:00
PoolObject * PoolGroup < T >:: RollOne ( SpawnedPoolData & 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
2009-02-19 18:50:12 -06:00
for ( uint32 i = 0 ; i < ExplicitlyChanced . size (); ++ i )
{
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-02-14 19:13:14 -07:00
if ( roll < 0 && ( ExplicitlyChanced [ i ]. guid == triggerFrom || ! spawns . IsSpawnedObject < T > ( ExplicitlyChanced [ i ]. guid )))
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-02-14 19:13:14 -07:00
if ( EqualChanced [ index ]. guid == triggerFrom || ! spawns . IsSpawnedObject < T > ( EqualChanced [ index ]. guid ))
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-02-14 19:13:14 -07:00
void PoolGroup < T >:: DespawnObject ( SpawnedPoolData & spawns , uint32 guid )
2009-02-19 18:50:12 -06:00
{
2009-09-18 14:10:37 -07: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
if ( spawns . IsSpawnedObject < 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 );
2010-02-14 19:13:14 -07:00
spawns . RemoveSpawn < 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
if ( spawns . IsSpawnedObject < T > ( ExplicitlyChanced [ i ]. guid ))
2009-12-18 06:54:49 +01:00
{
if ( ! guid || ExplicitlyChanced [ i ]. guid == guid )
{
Despawn1Object ( ExplicitlyChanced [ i ]. guid );
2010-02-14 19:13:14 -07:00
spawns . RemoveSpawn < 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
{
if ( CreatureData const * data = objmgr . GetCreatureData ( guid ))
{
objmgr . RemoveCreatureFromGrid ( guid , data );
2009-10-17 15:51:44 -07:00
2010-06-25 00:18:01 +02:00
if ( Creature * pCreature = sObjectAccessor . GetObjectInWorld ( MAKE_NEW_GUID ( guid , data -> id , HIGHGUID_UNIT ), ( Creature * ) NULL ))
2009-02-19 18:50:12 -06:00
pCreature -> AddObjectToRemoveList ();
}
}
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
{
if ( GameObjectData const * data = objmgr . GetGOData ( guid ))
{
objmgr . RemoveGameobjectFromGrid ( guid , data );
2009-10-17 15:51:44 -07:00
2010-06-25 00:18:01 +02:00
if ( GameObject * pGameobject = sObjectAccessor . 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
2009-02-19 18:50:12 -06:00
// Same on one pool
template <>
2009-02-19 18:52:03 -06:00
void PoolGroup < Pool >:: Despawn1Object ( uint32 child_pool_id )
2009-02-19 18:50:12 -06:00
{
poolhandler . DespawnPool ( child_pool_id );
}
2009-10-17 15:51:44 -07:00
2009-02-19 18:50:12 -06:00
// Method for a pool only to remove any found record causing a circular dependency loop
template <>
2009-02-19 18:52:03 -06:00
void PoolGroup < Pool >:: RemoveOneRelation ( uint16 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-02-14 19:13:14 -07:00
void PoolGroup < T >:: SpawnObject ( SpawnedPoolData & 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-02-14 19:13:14 -07:00
int count = limit - spawns . GetSpawnedObjects ( 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-02-14 19:13:14 -07:00
PoolObject * obj = RollOne ( spawns , triggerFrom );
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-02-14 19:13:14 -07:00
spawns . AddSpawn < T > ( obj -> guid , poolId );
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-02-14 19:13:14 -07:00
if ( CreatureData const * data = objmgr . GetCreatureData ( obj -> guid ))
2009-02-19 18:50:12 -06:00
{
2010-02-14 19:13:14 -07:00
objmgr . 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)
2010-06-25 00:18:01 +02:00
Map * map = const_cast < Map *> ( sMapMgr . CreateBaseMap ( data -> mapid ));
2009-02-19 18:50:12 -06:00
// We use spawn coords to spawn
2009-10-31 17:34:35 -07:00
if ( ! map -> Instanceable () && map -> IsLoaded ( data -> posX , data -> posY ))
2009-02-19 18:50:12 -06:00
{
Creature * pCreature = new Creature ;
//sLog.outDebug("Spawning creature %u",guid);
2010-02-14 19:13:14 -07:00
if ( ! pCreature -> LoadFromDB ( obj -> guid , map ))
2009-12-18 06:54:49 +01:00
{
2009-02-19 18:50:12 -06:00
delete pCreature ;
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
map -> Add ( pCreature );
}
}
}
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-02-14 19:13:14 -07:00
if ( GameObjectData const * data = objmgr . GetGOData ( obj -> guid ))
2009-02-19 18:50:12 -06:00
{
2010-02-14 19:13:14 -07:00
objmgr . 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
2010-06-25 00:18:01 +02:00
Map * map = const_cast < 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
2009-10-31 17:34:35 -07:00
if ( ! map -> Instanceable () && map -> IsLoaded ( data -> posX , data -> posY ))
2009-02-19 18:50:12 -06:00
{
GameObject * pGameobject = new GameObject ;
//sLog.outDebug("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 ())
map -> Add ( pGameobject );
}
}
}
}
2009-10-17 15:51:44 -07:00
2009-02-19 18:50:12 -06:00
// Same for 1 pool
template <>
2010-02-14 19:13:14 -07:00
void PoolGroup < Pool >:: Spawn1Object ( PoolObject * obj )
2009-02-19 18:50:12 -06:00
{
2010-02-14 19:13:14 -07:00
poolhandler . SpawnPool ( obj -> guid );
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-02-14 19:13:14 -07:00
if ( CreatureData const * data = objmgr . GetCreatureData ( obj -> guid ))
2010-06-25 00:18:01 +02:00
if ( Creature * pCreature = sObjectAccessor . GetObjectInWorld ( MAKE_NEW_GUID ( obj -> guid , data -> id , HIGHGUID_UNIT ), ( Creature * ) NULL ))
2009-02-19 18:50:12 -06:00
pCreature -> GetMap () -> Add ( pCreature );
}
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-02-14 19:13:14 -07:00
if ( GameObjectData const * data = objmgr . GetGOData ( obj -> guid ))
2010-06-25 00:18:01 +02:00
if ( GameObject * pGameobject = sObjectAccessor . GetObjectInWorld ( MAKE_NEW_GUID ( obj -> guid , data -> id , HIGHGUID_GAMEOBJECT ), ( GameObject * ) NULL ))
2009-02-19 18:50:12 -06:00
pGameobject -> GetMap () -> Add ( pGameobject );
}
2009-10-17 15:51:44 -07:00
2009-02-19 18:50:12 -06:00
// Nothing to do for a child Pool
template <>
2010-02-14 19:13:14 -07:00
void PoolGroup < Pool >:: ReSpawn1Object ( PoolObject * /*obj*/ )
2009-02-19 18:50:12 -06:00
{
}
////////////////////////////////////////////////////////////
// Methods of class PoolHandler
2009-10-17 15:51:44 -07:00
2009-02-19 18:50:12 -06:00
PoolHandler :: PoolHandler ()
{
}
2009-10-17 15:51:44 -07:00
2009-02-19 18:50:12 -06:00
void PoolHandler :: LoadFromDB ()
{
2010-01-23 14:45:58 +01:00
QueryResult_AutoPtr result = WorldDatabase . Query ( "SELECT MAX(entry) FROM pool_template" );
2009-02-19 18:50:12 -06:00
if ( ! result )
{
sLog . outString ( ">> Table pool_template is empty." );
2009-04-03 16:36:20 -06:00
sLog . outString ();
2009-02-19 18:50:12 -06:00
return ;
}
else
{
Field * fields = result -> Fetch ();
max_pool_id = fields [ 0 ]. GetUInt16 ();
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 );
2009-10-17 15:51:44 -07:00
2009-02-19 18:50:12 -06:00
result = WorldDatabase . Query ( "SELECT entry,max_limit FROM pool_template" );
if ( ! result )
{
mPoolTemplate . clear ();
sLog . outString ( ">> Table pool_template is empty:" );
2009-04-03 16:36:20 -06:00
sLog . outString ();
2009-02-19 18:50:12 -06:00
return ;
}
2009-10-17 15:51:44 -07:00
2009-02-19 18:50:12 -06:00
uint32 count = 0 ;
2009-10-17 15:51:44 -07:00
2009-02-19 18:50:12 -06:00
barGoLink bar ( result -> GetRowCount ());
do
{
++ count ;
Field * fields = result -> Fetch ();
2009-10-17 15:51:44 -07:00
2009-02-19 18:50:12 -06:00
bar . step ();
2009-10-17 15:51:44 -07:00
2009-02-19 18:50:12 -06:00
uint16 pool_id = fields [ 0 ]. GetUInt16 ();
2009-10-17 15:51:44 -07:00
2009-02-19 18:50:12 -06:00
PoolTemplateData & pPoolTemplate = mPoolTemplate [ pool_id ];
pPoolTemplate . MaxLimit = fields [ 1 ]. GetUInt32 ();
2009-10-17 15:51:44 -07:00
2009-02-19 18:50:12 -06:00
} while ( result -> NextRow ());
2009-10-17 15:51:44 -07:00
2009-04-03 16:36:20 -06:00
sLog . outString ();
2010-04-07 22:59:46 +02:00
sLog . outString ( ">> Loaded %u objects pools" , count );
2009-10-17 15:51:44 -07:00
2009-02-19 18:50:12 -06:00
// Creatures
2009-10-17 15:51:44 -07:00
2010-01-01 14:19:29 -06:00
sLog . outString ();
2010-04-07 22:59:46 +02:00
sLog . outString ( "Loading Creatures Pooling Data..." );
2010-01-01 14:19:29 -06:00
2009-02-19 18:50:12 -06:00
mPoolCreatureGroups . resize ( max_pool_id + 1 );
mCreatureSearchMap . clear ();
2009-02-19 18:46:19 -06:00
// 1 2 3
2009-02-19 18:50:12 -06:00
result = WorldDatabase . Query ( "SELECT guid, pool_entry, chance FROM pool_creature" );
2009-10-17 15:51:44 -07:00
2009-02-19 18:46:19 -06:00
count = 0 ;
if ( ! result )
{
barGoLink bar2 ( 1 );
bar2 . step ();
2009-10-17 15:51:44 -07:00
2009-04-03 16:36:20 -06:00
sLog . outString ();
2010-04-07 22:59:46 +02:00
sLog . outString ( ">> Loaded %u creatures in pools" , count );
2009-02-19 18:46:19 -06:00
}
else
{
2009-10-17 15:51:44 -07:00
2009-02-19 18:46:19 -06:00
barGoLink bar2 ( result -> GetRowCount ());
do
{
Field * fields = result -> Fetch ();
2009-10-17 15:51:44 -07:00
2009-02-19 18:46:19 -06:00
bar2 . step ();
2009-10-17 15:51:44 -07:00
2009-02-19 18:46:19 -06:00
uint32 guid = fields [ 0 ]. GetUInt32 ();
uint16 pool_id = fields [ 1 ]. GetUInt16 ();
float chance = fields [ 2 ]. GetFloat ();
2009-10-17 15:51:44 -07:00
2009-02-19 18:50:12 -06:00
CreatureData const * data = objmgr . GetCreatureData ( guid );
2009-02-19 18:46:19 -06:00
if ( ! data )
{
2010-04-07 22:59:46 +02:00
sLog . outErrorDb ( "`pool_creature` has a non existing creature spawn (GUID: %u) defined for pool id (%u), skipped." , guid , pool_id );
2009-02-19 18:46:19 -06:00
continue ;
}
if ( pool_id > max_pool_id )
{
2009-02-19 18:50:12 -06:00
sLog . outErrorDb ( "`pool_creature` pool id (%i) is out of range compared to max pool id in `pool_template`, skipped." , pool_id );
2009-02-19 18:46:19 -06:00
continue ;
}
if ( chance < 0 || chance > 100 )
{
2009-02-19 18:50:12 -06:00
sLog . outErrorDb ( "`pool_creature` has an invalid chance (%f) for creature guid (%u) in pool id (%i), skipped." , chance , guid , pool_id );
2009-02-19 18:46:19 -06:00
continue ;
}
PoolTemplateData * pPoolTemplate = & mPoolTemplate [ pool_id ];
++ count ;
2009-10-17 15:51:44 -07:00
2009-02-19 18:46:19 -06:00
PoolObject plObject = PoolObject ( guid , chance );
2009-02-19 18:50:12 -06:00
PoolGroup < Creature >& cregroup = mPoolCreatureGroups [ pool_id ];
2010-02-14 19:13:14 -07:00
cregroup . SetPoolId ( pool_id );
2009-02-19 18:50:12 -06:00
cregroup . AddEntry ( plObject , pPoolTemplate -> MaxLimit );
2009-02-19 18:46:19 -06:00
SearchPair p ( guid , pool_id );
2009-02-19 18:50:12 -06:00
mCreatureSearchMap . insert ( p );
2009-10-17 15:51:44 -07:00
2009-02-19 18:50:12 -06:00
} while ( result -> NextRow ());
2009-04-03 16:36:20 -06:00
sLog . outString ();
2010-04-07 22:59:46 +02:00
sLog . outString ( ">> Loaded %u creatures in pools" , count );
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-04-07 22:59:46 +02:00
sLog . outString ( "Loading Gameobject Pooling Data..." );
2010-01-01 14:19:29 -06:00
2009-02-19 18:50:12 -06:00
mPoolGameobjectGroups . resize ( max_pool_id + 1 );
mGameobjectSearchMap . clear ();
// 1 2 3
result = WorldDatabase . Query ( "SELECT guid, pool_entry, chance FROM pool_gameobject" );
2009-10-17 15:51:44 -07:00
2009-02-19 18:46:19 -06:00
count = 0 ;
2009-02-19 18:50:12 -06:00
if ( ! result )
2009-02-19 18:46:19 -06:00
{
barGoLink bar2 ( 1 );
bar2 . step ();
2009-10-17 15:51:44 -07:00
2009-04-03 16:36:20 -06:00
sLog . outString ();
2010-04-07 22:59:46 +02:00
sLog . outString ( ">> Loaded %u gameobject in pools" , count );
2009-02-19 18:46:19 -06:00
}
else
{
2009-10-17 15:51:44 -07:00
2009-02-19 18:50:12 -06:00
barGoLink bar2 ( result -> GetRowCount ());
2009-02-19 18:46:19 -06:00
do
{
Field * fields = result -> Fetch ();
2009-10-17 15:51:44 -07:00
2009-02-19 18:46:19 -06:00
bar2 . step ();
2009-10-17 15:51:44 -07:00
2009-02-19 18:50:12 -06:00
uint32 guid = fields [ 0 ]. GetUInt32 ();
uint16 pool_id = fields [ 1 ]. GetUInt16 ();
float chance = fields [ 2 ]. GetFloat ();
2009-10-17 15:51:44 -07:00
2009-02-19 18:50:12 -06:00
GameObjectData const * data = objmgr . GetGOData ( guid );
if ( ! data )
2009-02-19 18:46:19 -06:00
{
2010-04-07 22:59:46 +02:00
sLog . outErrorDb ( "`pool_gameobject` has a non existing gameobject spawn (GUID: %u) defined for pool id (%u), skipped." , guid , pool_id );
2009-02-19 18:46:19 -06:00
continue ;
}
2009-02-19 18:50:12 -06:00
GameObjectInfo const * goinfo = objmgr . GetGameObjectInfo ( data -> id );
if ( goinfo -> type != GAMEOBJECT_TYPE_CHEST &&
goinfo -> type != GAMEOBJECT_TYPE_GOOBER &&
goinfo -> type != GAMEOBJECT_TYPE_FISHINGHOLE )
2009-02-19 18:46:19 -06:00
{
2010-04-07 22:59:46 +02:00
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 );
2009-02-19 18:46:19 -06:00
continue ;
}
2009-02-19 18:50:12 -06:00
if ( pool_id > max_pool_id )
2009-02-19 18:46:19 -06:00
{
2009-02-19 18:50:12 -06:00
sLog . outErrorDb ( "`pool_gameobject` pool id (%i) is out of range compared to max pool id in `pool_template`, skipped." , pool_id );
2009-02-19 18:46:19 -06:00
continue ;
}
if ( chance < 0 || chance > 100 )
{
2009-02-19 18:50:12 -06:00
sLog . outErrorDb ( "`pool_gameobject` has an invalid chance (%f) for gameobject guid (%u) in pool id (%i), skipped." , chance , guid , pool_id );
2009-02-19 18:46:19 -06:00
continue ;
}
2009-02-19 18:50:12 -06:00
PoolTemplateData * pPoolTemplate = & mPoolTemplate [ pool_id ];
2009-10-17 15:51:44 -07:00
2009-02-19 18:46:19 -06:00
++ count ;
2009-10-17 15:51:44 -07:00
2009-02-19 18:50:12 -06:00
PoolObject plObject = PoolObject ( guid , chance );
PoolGroup < GameObject >& gogroup = mPoolGameobjectGroups [ pool_id ];
2010-02-14 19:13:14 -07:00
gogroup . SetPoolId ( pool_id );
2009-02-19 18:50:12 -06:00
gogroup . AddEntry ( plObject , pPoolTemplate -> MaxLimit );
SearchPair p ( guid , pool_id );
mGameobjectSearchMap . insert ( p );
2009-10-17 15:51:44 -07:00
2010-04-07 22:59:46 +02:00
} while ( result -> NextRow ());
2009-04-03 16:36:20 -06:00
sLog . outString ();
2010-04-07 22:59:46 +02:00
sLog . outString ( ">> Loaded %u gameobject in pools" , count );
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-04-07 22:59:46 +02:00
sLog . outString ( "Loading Mother Pooling Data..." );
2010-01-01 14:19:29 -06:00
2009-02-19 18:50:12 -06:00
mPoolPoolGroups . resize ( max_pool_id + 1 );
2010-01-01 14:19:29 -06:00
// 1 2 3
2009-02-19 18:50:12 -06:00
result = WorldDatabase . Query ( "SELECT pool_id, mother_pool, chance FROM pool_pool" );
2009-10-17 15:51:44 -07:00
2009-02-19 18:50:12 -06:00
count = 0 ;
2010-01-01 14:19:29 -06:00
if ( ! result )
2009-02-19 18:46:19 -06:00
{
2009-02-19 18:50:12 -06:00
barGoLink bar2 ( 1 );
bar2 . step ();
2009-10-17 15:51:44 -07:00
2009-04-03 16:36:20 -06:00
sLog . outString ();
2010-04-07 22:59:46 +02:00
sLog . outString ( ">> Loaded %u pools in pools" , count );
2009-02-19 18:46:19 -06:00
}
2009-02-19 18:50:12 -06:00
else
2009-02-19 18:46:19 -06:00
{
2009-10-17 15:51:44 -07:00
2010-04-07 22:59:46 +02:00
barGoLink bar2 ( result -> GetRowCount ());
2009-02-19 18:50:12 -06:00
do
2009-02-19 18:46:19 -06:00
{
2009-02-19 18:50:12 -06:00
Field * fields = result -> Fetch ();
2009-10-17 15:51:44 -07:00
2009-02-19 18:50:12 -06:00
bar2 . step ();
2009-10-17 15:51:44 -07:00
2009-02-19 18:50:12 -06:00
uint16 child_pool_id = fields [ 0 ]. GetUInt16 ();
uint16 mother_pool_id = fields [ 1 ]. GetUInt16 ();
float chance = fields [ 2 ]. GetFloat ();
2009-10-17 15:51:44 -07:00
2009-02-19 18:50:12 -06:00
if ( mother_pool_id > max_pool_id )
2009-02-19 18:46:19 -06:00
{
2009-02-19 18:50:12 -06:00
sLog . outErrorDb ( "`pool_pool` mother_pool id (%i) is out of range compared to max pool id in `pool_template`, skipped." , mother_pool_id );
continue ;
2009-02-19 18:46:19 -06:00
}
2009-02-19 18:50:12 -06:00
if ( child_pool_id > max_pool_id )
{
sLog . outErrorDb ( "`pool_pool` included pool_id (%i) is out of range compared to max pool id in `pool_template`, skipped." , child_pool_id );
continue ;
}
if ( mother_pool_id == child_pool_id )
{
sLog . outErrorDb ( "`pool_pool` pool_id (%i) includes itself, dead-lock detected, skipped." , child_pool_id );
continue ;
}
if ( chance < 0 || chance > 100 )
{
sLog . outErrorDb ( "`pool_pool` has an invalid chance (%f) for pool id (%u) in mother pool id (%i), skipped." , chance , child_pool_id , mother_pool_id );
continue ;
}
PoolTemplateData * pPoolTemplateMother = & mPoolTemplate [ mother_pool_id ];
2009-10-17 15:51:44 -07:00
2009-02-19 18:50:12 -06:00
++ count ;
2009-10-17 15:51:44 -07:00
2009-02-19 18:50:12 -06:00
PoolObject plObject = PoolObject ( child_pool_id , chance );
PoolGroup < Pool >& plgroup = mPoolPoolGroups [ mother_pool_id ];
2010-02-14 19:13:14 -07:00
plgroup . SetPoolId ( mother_pool_id );
2009-02-19 18:50:12 -06:00
plgroup . AddEntry ( plObject , pPoolTemplateMother -> MaxLimit );
SearchPair p ( child_pool_id , mother_pool_id );
mPoolSearchMap . insert ( p );
2009-10-17 15:51:44 -07:00
2010-04-07 22:59:46 +02:00
} while ( result -> NextRow ());
2009-10-17 15:51:44 -07:00
2009-02-19 18:50:12 -06:00
// Now check for circular reference
2009-10-17 16:20:24 -07:00
for ( uint16 i = 0 ; i < max_pool_id ; ++ i )
2009-02-19 18:46:19 -06:00
{
2009-02-19 18:50:12 -06:00
std :: set < uint16 > checkedPools ;
2009-10-17 16:20:24 -07:00
for ( SearchMap :: iterator poolItr = mPoolSearchMap . find ( i ); poolItr != mPoolSearchMap . end (); poolItr = mPoolSearchMap . find ( poolItr -> second ))
2009-02-19 18:46:19 -06:00
{
2009-02-19 18:50:12 -06:00
checkedPools . insert ( poolItr -> first );
2010-04-07 19:14:10 +02:00
if ( checkedPools . find ( poolItr -> second ) != checkedPools . end ())
2009-02-19 18:50:12 -06:00
{
std :: ostringstream ss ;
ss << "The pool(s) " ;
2010-04-08 08:20:08 +02:00
for ( std :: set < uint16 >:: const_iterator itr = checkedPools . begin (); itr != checkedPools . end (); ++ itr )
2009-02-19 18:50:12 -06:00
ss << * itr << " " ;
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 ( ss . str (). c_str ());
mPoolPoolGroups [ poolItr -> second ]. RemoveOneRelation ( poolItr -> first );
mPoolSearchMap . erase ( poolItr );
-- count ;
break ;
}
2009-02-19 18:46:19 -06:00
}
}
2010-01-01 14:19:29 -06:00
2009-04-03 16:36:20 -06:00
sLog . outString ();
2010-04-07 22:59:46 +02:00
sLog . outString ( ">> Loaded %u pools in mother pools" , count );
2009-02-19 18:46:19 -06:00
}
}
2009-10-17 15:51:44 -07:00
2009-02-19 18:50:12 -06: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
void PoolHandler :: Initialize ()
2009-02-19 18:46:19 -06:00
{
2010-06-17 05:37:37 +02:00
QueryResult_AutoPtr 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" );
2009-02-19 18:50:12 -06:00
uint32 count = 0 ;
if ( result )
2009-02-19 18:46:19 -06:00
{
2009-02-19 18:50:12 -06:00
do
2009-02-19 18:46:19 -06:00
{
2009-02-19 18:50:12 -06:00
Field * fields = result -> Fetch ();
uint16 pool_entry = fields [ 0 ]. GetUInt16 ();
2010-06-17 05:37:37 +02:00
uint16 pool_pool_id = fields [ 1 ]. GetUInt16 ();
2009-02-19 18:50:12 -06:00
if ( ! CheckPool ( pool_entry ))
2009-02-19 18:46:19 -06:00
{
2010-06-17 05:37:37 +02:00
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 ]. GetUInt16 ());
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 );
2009-02-19 18:50:12 -06:00
continue ;
2009-02-19 18:46:19 -06:00
}
2010-06-17 05:37:37 +02:00
// Don't spawn child pools, they are spawned recursively by their parent pools
if ( ! pool_pool_id )
{
SpawnPool ( pool_entry );;
count ++ ;
}
2009-02-19 18:50:12 -06:00
} while ( result -> NextRow ());
2009-02-19 18:46:19 -06:00
}
2009-10-17 15:51:44 -07:00
2009-02-19 18:50:12 -06:00
sLog . outBasic ( "Pool handling system initialized, %u pools spawned." , count );
2009-02-19 18:46:19 -06:00
}
2009-10-17 15:51:44 -07:00
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 <>
void PoolHandler :: SpawnPool < Creature > ( uint16 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 <>
void PoolHandler :: SpawnPool < GameObject > ( uint16 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 <>
void PoolHandler :: SpawnPool < Pool > ( uint16 pool_id , uint32 sub_pool_id )
{
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-04-07 22:59:46 +02:00
void PoolHandler :: SpawnPool ( uint16 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 );
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
void PoolHandler :: DespawnPool ( uint16 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 );
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-02-14 19:13:14 -07:00
bool PoolHandler :: CheckPool ( uint16 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 () &&
mPoolPoolGroups [ pool_id ]. CheckPool ();
}
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 >
void PoolHandler :: UpdatePool ( uint16 pool_id , uint32 db_guid_or_pool_id )
2009-02-19 18:50:12 -06:00
{
2010-02-14 19:13:14 -07:00
if ( uint16 motherpoolid = IsPartOfAPool < Pool > ( pool_id ))
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
template void PoolHandler :: UpdatePool < Pool > ( uint16 pool_id , uint32 db_guid_or_pool_id );
template void PoolHandler :: UpdatePool < GameObject > ( uint16 pool_id , uint32 db_guid_or_pool_id );
2010-06-08 17:01:03 -06:00
template void PoolHandler :: UpdatePool < Creature > ( uint16 pool_id , uint32 db_guid_or_pool_id );