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
*/
#include "PoolHandler.h"
#include "ObjectMgr.h"
#include "ProgressBar.h"
#include "Log.h"
#include "MapManager.h"
#include "Policies/SingletonImp.h"
INSTANTIATE_SINGLETON_1 ( PoolHandler );
2009-02-19 18:50:12 -06:00
////////////////////////////////////////////////////////////
// Methods of template class PoolGroup
template < class T >
2009-02-19 18:52:03 -06:00
PoolGroup < T >:: PoolGroup ()
2009-02-19 18:46:19 -06:00
{
2009-02-19 18:50:12 -06:00
Spawned = 0 ;
2009-02-19 18:46:19 -06: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 );
}
// Method to check the chances are proper in this object pool
template < class T >
2009-02-19 18:52:03 -06:00
bool PoolGroup < T >:: CheckPool ( void )
2009-02-19 18:50:12 -06:00
{
if ( EqualChanced . size () == 0 )
2009-02-19 18:46:19 -06:00
{
2009-02-19 18:50:12 -06:00
float chance = 0 ;
for ( uint32 i = 0 ; i < ExplicitlyChanced . size (); ++ i )
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-02-19 18:46:19 -06:00
2009-02-19 18:50:12 -06:00
// Method that tell if the gameobject, creature or pool is spawned currently
template < class T >
2009-02-19 18:52:03 -06:00
bool PoolGroup < T >:: IsSpawnedObject ( uint32 guid )
2009-02-19 18:50:12 -06:00
{
for ( uint32 i = 0 ; i < ExplicitlyChanced . size (); ++ i )
if ( ExplicitlyChanced [ i ]. guid == guid )
return ExplicitlyChanced [ i ]. spawned ;
for ( uint32 i = 0 ; i < EqualChanced . size (); ++ i )
if ( EqualChanced [ i ]. guid == guid )
return EqualChanced [ i ]. spawned ;
return false ;
}
2009-02-19 18:46:19 -06:00
2009-02-19 18:50:12 -06:00
// Method that return a guid of a rolled creature or gameobject
// Note: Copy from loot system because it's very similar and only few things change
template < class T >
2009-02-19 18:52:03 -06:00
uint32 PoolGroup < T >:: RollOne ( void )
2009-02-19 18:50:12 -06:00
{
if ( ! ExplicitlyChanced . empty ()) // First explicitly chanced entries are checked
2009-02-19 18:46:19 -06:00
{
2009-02-19 18:50:12 -06:00
float roll = rand_chance ();
for ( uint32 i = 0 ; i < ExplicitlyChanced . size (); ++ i )
{
roll -= ExplicitlyChanced [ i ]. chance ;
if ( roll < 0 )
return ExplicitlyChanced [ i ]. guid ;
}
2009-02-19 18:46:19 -06:00
}
2009-02-19 18:50:12 -06:00
if ( ! EqualChanced . empty ())
return EqualChanced [ irand ( 0 , EqualChanced . size () - 1 )]. guid ;
2009-02-19 18:46:19 -06:00
2009-02-19 18:50:12 -06:00
return 0 ; // None found
}
2009-02-19 18:46:19 -06: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 >
2009-02-19 18:52:03 -06:00
void PoolGroup < T >:: DespawnObject ( uint32 guid )
2009-02-19 18:50:12 -06:00
{
for ( int i = 0 ; i < EqualChanced . size (); ++ i )
2009-02-19 18:46:19 -06:00
{
2009-02-19 18:50:12 -06:00
if ( EqualChanced [ i ]. spawned )
{
if ( ! guid || EqualChanced [ i ]. guid == guid )
{
if ( guid )
CacheValue = EqualChanced [ i ]. guid ;
else
Despawn1Object ( EqualChanced [ i ]. guid );
2009-02-19 18:46:19 -06:00
2009-02-19 18:50:12 -06:00
EqualChanced [ i ]. spawned = false ;
Spawned -- ;
}
}
}
}
2009-02-19 18:46:19 -06: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-02-19 18:46:19 -06:00
2009-02-19 18:50:12 -06:00
if ( Creature * pCreature = ObjectAccessor :: Instance (). GetObjectInWorld ( MAKE_NEW_GUID ( guid , data -> id , HIGHGUID_UNIT ), ( Creature * ) NULL ))
pCreature -> AddObjectToRemoveList ();
}
}
2009-02-19 18:46:19 -06: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-02-19 18:46:19 -06:00
2009-02-19 18:50:12 -06:00
if ( GameObject * pGameobject = ObjectAccessor :: Instance (). GetObjectInWorld ( MAKE_NEW_GUID ( guid , data -> id , HIGHGUID_GAMEOBJECT ), ( GameObject * ) NULL ))
pGameobject -> AddObjectToRemoveList ();
}
}
2009-02-19 18:46:19 -06: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-02-19 18:46:19 -06: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
{
2009-02-19 18:50:12 -06:00
if ( itr -> guid == child_pool_id )
{
ExplicitlyChanced . erase ( itr );
break ;
}
}
for ( PoolObjectList :: iterator itr = EqualChanced . begin (); itr != EqualChanced . end (); ++ itr )
{
if ( itr -> guid == child_pool_id )
{
EqualChanced . erase ( itr );
break ;
}
}
}
2009-02-19 18:46:19 -06:00
2009-02-19 18:50:12 -06:00
// Method that Spawn 1+ creatures or gameobject
// if cache is false (initialization or event start), X creatures are spawned with X <= limit (< if limit higher that the number of creatures in pool)
// if cache is true, this means only one has to be spawned (or respawned if the rolled one is same as cached one)
template < class T >
2009-02-19 18:52:03 -06:00
void PoolGroup < T >:: SpawnObject ( uint32 limit , bool cache )
2009-02-19 18:50:12 -06:00
{
if ( limit == 1 ) // This is the only case where explicit chance is used
{
uint32 roll = RollOne ();
if ( cache && CacheValue != roll )
Despawn1Object ( CacheValue );
CacheValue = Spawn1Object ( roll );
2009-02-19 18:46:19 -06:00
}
2009-02-19 18:50:12 -06:00
else if ( limit < EqualChanced . size () && Spawned < limit )
2009-02-19 18:46:19 -06:00
{
2009-02-19 18:50:12 -06:00
std :: vector < uint32 > IndexList ;
for ( int i = 0 ; i < EqualChanced . size (); ++ i )
if ( ! EqualChanced [ i ]. spawned )
IndexList . push_back ( i );
2009-02-19 18:46:19 -06:00
2009-02-19 18:50:12 -06:00
while ( Spawned < limit && IndexList . size () > 0 )
2009-02-19 18:46:19 -06:00
{
2009-02-19 18:50:12 -06:00
uint32 roll = urand ( 1 , IndexList . size ()) - 1 ;
uint32 index = IndexList [ roll ];
if ( ! cache || ( cache && EqualChanced [ index ]. guid != CacheValue ))
{
if ( cache )
Despawn1Object ( CacheValue );
EqualChanced [ index ]. spawned = Spawn1Object ( EqualChanced [ index ]. guid );
}
else
EqualChanced [ index ]. spawned = ReSpawn1Object ( EqualChanced [ index ]. guid );
2009-02-19 18:46:19 -06:00
2009-02-19 18:50:12 -06:00
if ( EqualChanced [ index ]. spawned )
++ Spawned ; // limited group use the Spawned variable to store the number of actualy spawned creatures
std :: vector < uint32 >:: iterator itr = IndexList . begin () + roll ;
IndexList . erase ( itr );
}
CacheValue = 0 ;
}
else // Not enough objects in pool, so spawn all
{
for ( int i = 0 ; i < EqualChanced . size (); ++ i )
EqualChanced [ i ]. spawned = Spawn1Object ( EqualChanced [ i ]. guid );
}
}
2009-02-19 18:46:19 -06:00
2009-02-19 18:50:12 -06:00
// Method that is actualy doing the spawn job on 1 creature
template <>
2009-02-19 18:52:03 -06:00
bool PoolGroup < Creature >:: Spawn1Object ( uint32 guid )
2009-02-19 18:50:12 -06:00
{
CreatureData const * data = objmgr . GetCreatureData ( guid );
if ( data )
{
objmgr . AddCreatureToGrid ( guid , data );
2009-02-19 18:46:19 -06:00
2009-02-19 18:50:12 -06:00
// Spawn if necessary (loaded grids only)
2009-06-16 11:19:59 -05:00
Map * map = const_cast < Map *> ( MapManager :: Instance (). CreateBaseMap ( data -> mapid ));
2009-02-19 18:50:12 -06:00
// We use spawn coords to spawn
if ( ! map -> Instanceable () && ! map -> IsRemovalGrid ( data -> posX , data -> posY ))
{
Creature * pCreature = new Creature ;
//sLog.outDebug("Spawning creature %u",guid);
if ( ! pCreature -> LoadFromDB ( guid , map ))
2009-02-19 18:46:19 -06:00
{
2009-02-19 18:50:12 -06:00
delete pCreature ;
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-02-19 18:50:12 -06:00
map -> Add ( pCreature );
2009-02-19 18:46:19 -06:00
}
2009-02-19 18:50:12 -06:00
}
return true ;
}
return false ;
}
2009-02-19 18:46:19 -06:00
2009-02-19 18:50:12 -06:00
// Same for 1 gameobject
template <>
2009-02-19 18:52:03 -06:00
bool PoolGroup < GameObject >:: Spawn1Object ( uint32 guid )
2009-02-19 18:50:12 -06:00
{
GameObjectData const * data = objmgr . GetGOData ( guid );
if ( data )
{
objmgr . AddGameobjectToGrid ( guid , data );
// Spawn if necessary (loaded grids only)
// this base map checked as non-instanced and then only existed
2009-06-16 11:19:59 -05:00
Map * map = const_cast < Map *> ( MapManager :: Instance (). 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
if ( ! map -> Instanceable () && ! map -> IsRemovalGrid ( data -> posX , data -> posY ))
{
GameObject * pGameobject = new GameObject ;
//sLog.outDebug("Spawning gameobject %u", guid);
if ( ! pGameobject -> LoadFromDB ( guid , map ))
{
delete pGameobject ;
}
else
{
if ( pGameobject -> isSpawnedByDefault ())
map -> Add ( pGameobject );
}
}
return true ;
}
return false ;
}
// Same for 1 pool
template <>
2009-02-19 18:52:03 -06:00
bool PoolGroup < Pool >:: Spawn1Object ( uint32 child_pool_id )
2009-02-19 18:50:12 -06:00
{
poolhandler . SpawnPool ( child_pool_id );
return true ;
}
// Method that does the respawn job on the specified creature
template <>
2009-02-19 18:52:03 -06:00
bool PoolGroup < Creature >:: ReSpawn1Object ( uint32 guid )
2009-02-19 18:50:12 -06:00
{
CreatureData const * data = objmgr . GetCreatureData ( guid );
if ( data )
{
if ( Creature * pCreature = ObjectAccessor :: Instance (). GetObjectInWorld ( MAKE_NEW_GUID ( guid , data -> id , HIGHGUID_UNIT ), ( Creature * ) NULL ))
pCreature -> GetMap () -> Add ( pCreature );
return true ;
}
return false ;
}
// Same for 1 gameobject
template <>
2009-02-19 18:52:03 -06:00
bool PoolGroup < GameObject >:: ReSpawn1Object ( uint32 guid )
2009-02-19 18:50:12 -06:00
{
GameObjectData const * data = objmgr . GetGOData ( guid );
if ( data )
{
if ( GameObject * pGameobject = ObjectAccessor :: Instance (). GetObjectInWorld ( MAKE_NEW_GUID ( guid , data -> id , HIGHGUID_GAMEOBJECT ), ( GameObject * ) NULL ))
pGameobject -> GetMap () -> Add ( pGameobject );
return true ;
}
return false ;
}
// Nothing to do for a child Pool
template <>
2009-05-03 22:21:46 -05:00
bool PoolGroup < Pool >:: ReSpawn1Object ( uint32 /*guid*/ )
2009-02-19 18:50:12 -06:00
{
return true ;
}
////////////////////////////////////////////////////////////
// Methods of class PoolHandler
PoolHandler :: PoolHandler ()
{
isSystemInit = false ;
}
void PoolHandler :: LoadFromDB ()
{
QueryResult * result = WorldDatabase . Query ( "SELECT MAX(entry) FROM pool_template" );
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
delete result ;
}
2009-02-19 18:50:12 -06:00
mPoolTemplate . resize ( max_pool_id + 1 );
2009-02-19 18:46:19 -06: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 ;
}
uint32 count = 0 ;
barGoLink bar ( result -> GetRowCount ());
do
{
++ count ;
Field * fields = result -> Fetch ();
bar . step ();
uint16 pool_id = fields [ 0 ]. GetUInt16 ();
PoolTemplateData & pPoolTemplate = mPoolTemplate [ pool_id ];
pPoolTemplate . MaxLimit = fields [ 1 ]. GetUInt32 ();
} while ( result -> NextRow ());
2009-04-03 16:36:20 -06:00
sLog . outString ();
2009-02-19 18:50:12 -06:00
sLog . outString ( ">> Loaded %u objects pools" , count );
delete result ;
// Creatures
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-02-19 18:46:19 -06:00
count = 0 ;
if ( ! result )
{
barGoLink bar2 ( 1 );
bar2 . step ();
2009-04-03 16:36:20 -06:00
sLog . outString ();
2009-02-19 18:50:12 -06:00
sLog . outString ( ">> Loaded %u creatures in pools" , count );
2009-02-19 18:46:19 -06:00
}
else
{
barGoLink bar2 ( result -> GetRowCount ());
do
{
Field * fields = result -> Fetch ();
bar2 . step ();
uint32 guid = fields [ 0 ]. GetUInt32 ();
uint16 pool_id = fields [ 1 ]. GetUInt16 ();
float chance = fields [ 2 ]. GetFloat ();
2009-02-19 18:50:12 -06:00
CreatureData const * data = objmgr . GetCreatureData ( guid );
2009-02-19 18:46:19 -06:00
if ( ! data )
{
2009-02-19 18:50:12 -06: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 ;
PoolObject plObject = PoolObject ( guid , chance );
2009-02-19 18:50:12 -06:00
PoolGroup < Creature >& cregroup = mPoolCreatureGroups [ pool_id ];
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-02-19 18:46:19 -06:00
2009-02-19 18:50:12 -06:00
} while ( result -> NextRow ());
2009-04-03 16:36:20 -06:00
sLog . outString ();
2009-02-19 18:50:12 -06:00
sLog . outString ( ">> Loaded %u creatures in pools" , count );
2009-02-19 18:46:19 -06:00
delete result ;
}
2009-02-19 18:50:12 -06:00
// Gameobjects
mPoolGameobjectGroups . resize ( max_pool_id + 1 );
mGameobjectSearchMap . clear ();
// 1 2 3
result = WorldDatabase . Query ( "SELECT guid, pool_entry, chance FROM pool_gameobject" );
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-04-03 16:36:20 -06:00
sLog . outString ();
2009-02-19 18:50:12 -06:00
sLog . outString ( ">> Loaded %u gameobject in pools" , count );
2009-02-19 18:46:19 -06:00
}
else
{
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 ();
bar2 . step ();
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-02-19 18:46:19 -06: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
{
2009-02-19 18:50:12 -06: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
{
2009-02-19 18:50:12 -06: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-02-19 18:46:19 -06:00
++ count ;
2009-02-19 18:50:12 -06:00
PoolObject plObject = PoolObject ( guid , chance );
PoolGroup < GameObject >& gogroup = mPoolGameobjectGroups [ pool_id ];
gogroup . AddEntry ( plObject , pPoolTemplate -> MaxLimit );
SearchPair p ( guid , pool_id );
mGameobjectSearchMap . insert ( p );
2009-02-19 18:46:19 -06:00
} while ( result -> NextRow () );
2009-04-03 16:36:20 -06:00
sLog . outString ();
2009-02-19 18:50:12 -06:00
sLog . outString ( ">> Loaded %u gameobject in pools" , count );
2009-02-19 18:46:19 -06:00
delete result ;
}
2009-02-19 18:50:12 -06:00
// Pool of pools
mPoolPoolGroups . resize ( max_pool_id + 1 );
// 1 2 3
result = WorldDatabase . Query ( "SELECT pool_id, mother_pool, chance FROM pool_pool" );
2009-02-19 18:46:58 -06:00
2009-02-19 18:50:12 -06:00
count = 0 ;
if ( ! result )
2009-02-19 18:46:19 -06:00
{
2009-02-19 18:50:12 -06:00
barGoLink bar2 ( 1 );
bar2 . step ();
2009-04-03 16:36:20 -06:00
sLog . outString ();
2009-02-19 18:50:12 -06: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-02-19 18:50:12 -06:00
barGoLink bar2 ( result -> GetRowCount () );
do
2009-02-19 18:46:19 -06:00
{
2009-02-19 18:50:12 -06:00
Field * fields = result -> Fetch ();
bar2 . step ();
uint16 child_pool_id = fields [ 0 ]. GetUInt16 ();
uint16 mother_pool_id = fields [ 1 ]. GetUInt16 ();
float chance = fields [ 2 ]. GetFloat ();
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-02-19 18:46:19 -06:00
2009-02-19 18:50:12 -06:00
++ count ;
2009-02-19 18:46:19 -06:00
2009-02-19 18:50:12 -06:00
PoolObject plObject = PoolObject ( child_pool_id , chance );
PoolGroup < Pool >& plgroup = mPoolPoolGroups [ mother_pool_id ];
plgroup . AddEntry ( plObject , pPoolTemplateMother -> MaxLimit );
SearchPair p ( child_pool_id , mother_pool_id );
mPoolSearchMap . insert ( p );
2009-02-19 18:46:19 -06:00
2009-02-19 18:50:12 -06:00
} while ( result -> NextRow () );
// Now check for circular reference
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 ;
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 );
if ( checkedPools . find ( poolItr -> second ) != checkedPools . end ())
{
std :: ostringstream ss ;
ss << "The pool(s) " ;
for ( std :: set < uint16 >:: const_iterator itr = checkedPools . begin (); itr != checkedPools . end (); ++ itr )
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
}
}
2009-04-03 16:36:20 -06:00
sLog . outString ();
2009-02-19 18:50:12 -06:00
sLog . outString ( ">> Loaded %u pools in mother pools" , count );
delete result ;
2009-02-19 18:46:19 -06: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
{
2009-02-19 18:50:12 -06:00
QueryResult * result = WorldDatabase . Query ( "SELECT DISTINCT pool_template.entry 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 AND pool_pool.pool_id IS NULL" );
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 ();
if ( ! CheckPool ( pool_entry ))
2009-02-19 18:46:19 -06:00
{
2009-02-19 18:50:12 -06:00
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 ;
2009-02-19 18:46:19 -06:00
}
2009-02-19 18:50:12 -06:00
SpawnPool ( pool_entry );
count ++ ;
} while ( result -> NextRow ());
2009-05-04 17:26:47 -05:00
delete result ;
2009-02-19 18:46:19 -06:00
}
2009-02-19 18:50:12 -06:00
sLog . outBasic ( "Pool handling system initialized, %u pools spawned." , count );
isSystemInit = true ;
2009-02-19 18:46:19 -06: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
// If it's same, the gameobject/creature is respawned only (added back to map)
void PoolHandler :: SpawnPool ( uint16 pool_id , bool cache )
2009-02-19 18:46:19 -06:00
{
2009-02-19 18:50:12 -06:00
if ( ! mPoolPoolGroups [ pool_id ]. isEmpty ())
mPoolPoolGroups [ pool_id ]. SpawnObject ( mPoolTemplate [ pool_id ]. MaxLimit , cache );
if ( ! mPoolGameobjectGroups [ pool_id ]. isEmpty ())
mPoolGameobjectGroups [ pool_id ]. SpawnObject ( mPoolTemplate [ pool_id ]. MaxLimit , cache );
if ( ! mPoolCreatureGroups [ pool_id ]. isEmpty ())
mPoolCreatureGroups [ pool_id ]. SpawnObject ( mPoolTemplate [ pool_id ]. MaxLimit , cache );
2009-02-19 18:46:19 -06:00
}
2009-02-19 18:50:12 -06:00
// Call to despawn a pool, all gameobjects/creatures in this pool are removed
void PoolHandler :: DespawnPool ( uint16 pool_id )
2009-02-19 18:46:19 -06:00
{
2009-02-19 18:50:12 -06:00
if ( ! mPoolPoolGroups [ pool_id ]. isEmpty ())
mPoolPoolGroups [ pool_id ]. DespawnObject ();
if ( ! mPoolGameobjectGroups [ pool_id ]. isEmpty ())
mPoolGameobjectGroups [ pool_id ]. DespawnObject ();
if ( ! mPoolCreatureGroups [ pool_id ]. isEmpty ())
mPoolCreatureGroups [ pool_id ]. DespawnObject ();
2009-02-19 18:46:19 -06:00
}
2009-02-19 18:50:12 -06: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
void PoolHandler :: UpdatePool ( uint16 pool_id , uint32 guid , uint32 type )
2009-02-19 18:46:19 -06:00
{
2009-02-19 18:50:12 -06:00
uint16 motherpoolid = IsPartOfAPool ( pool_id , 0 );
if ( motherpoolid )
mPoolPoolGroups [ motherpoolid ]. DespawnObject ( pool_id );
else if ( type == TYPEID_GAMEOBJECT && ! mPoolGameobjectGroups [ pool_id ]. isEmpty ())
mPoolGameobjectGroups [ pool_id ]. DespawnObject ( guid );
else if ( type != TYPEID_GAMEOBJECT && ! mPoolCreatureGroups [ pool_id ]. isEmpty ())
mPoolCreatureGroups [ pool_id ]. DespawnObject ( guid );
if ( motherpoolid )
SpawnPool ( motherpoolid , true );
else
SpawnPool ( pool_id , true );
}
// Method that tell if the gameobject/creature is part of a pool and return the pool id if yes
uint16 PoolHandler :: IsPartOfAPool ( uint32 guid , uint32 type )
{
if ( type == 0 ) // pool of pool
2009-02-19 18:46:19 -06:00
{
2009-02-19 18:50:12 -06:00
SearchMap :: const_iterator itr = mPoolSearchMap . find ( guid );
if ( itr != mPoolSearchMap . end ())
return itr -> second ;
2009-02-19 18:46:19 -06:00
}
2009-02-19 18:50:12 -06:00
else if ( type == TYPEID_GAMEOBJECT )
{
SearchMap :: const_iterator itr = mGameobjectSearchMap . find ( guid );
if ( itr != mGameobjectSearchMap . end ())
return itr -> second ;
}
else // creature
{
SearchMap :: const_iterator itr = mCreatureSearchMap . find ( guid );
if ( itr != mCreatureSearchMap . end ())
return itr -> second ;
}
return 0 ;
2009-02-19 18:46:19 -06:00
}
2009-02-19 18:50:12 -06:00
// Method that check chance integrity of the creatures and gameobjects in this pool
bool PoolHandler :: CheckPool ( uint16 pool_id )
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 ();
}
// Method that tell if a creature or gameobject in pool_id is spawned currently
bool PoolHandler :: IsSpawnedObject ( uint16 pool_id , uint32 guid , uint32 type )
{
if ( pool_id > max_pool_id )
return false ;
if ( type == 0 )
return mPoolPoolGroups [ pool_id ]. IsSpawnedObject ( guid );
else if ( type == TYPEID_GAMEOBJECT )
return mPoolGameobjectGroups [ pool_id ]. IsSpawnedObject ( guid );
else
return mPoolCreatureGroups [ pool_id ]. IsSpawnedObject ( guid );
2009-02-19 18:46:19 -06:00
}