2013-05-09 10:44:08 -04:00
/* EQEMu: Everquest Server Emulator
Copyright ( C ) 2001 - 2002 EQEMu Development Team ( http : //eqemu.org)
2013-02-16 16:14:39 -08:00
2013-05-09 10:44:08 -04: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 ; version 2 of the License .
2013-05-06 13:07:41 -04:00
2013-05-09 10:44:08 -04:00
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY except by those people which sell it , which
2013-02-16 16:14:39 -08:00
are required to give you total support for your newly bought product ;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
2013-05-09 10:44:08 -04:00
A PARTICULAR PURPOSE . See the GNU General Public License for more details .
2013-05-06 13:07:41 -04:00
2013-05-09 10:44:08 -04:00
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
2013-02-16 16:14:39 -08:00
*/
# include "../common/debug.h"
2014-08-21 19:33:02 -07:00
# include "../common/string_util.h"
2013-02-16 16:14:39 -08:00
# include <stdlib.h>
# include "spawn2.h"
# include "entity.h"
# include "masterentity.h"
# include "zone.h"
# include "spawngroup.h"
# include "zonedb.h"
# include "worldserver.h"
extern EntityList entity_list ;
extern Zone * zone ;
extern WorldServer worldserver ;
/*
CREATE TABLE spawn_conditions (
2013-11-11 15:37:20 -05:00
zone VARCHAR ( 16 ) NOT NULL ,
id MEDIUMINT UNSIGNED NOT NULL DEFAULT ' 1 ' ,
value MEDIUMINT NOT NULL DEFAULT ' 0 ' ,
onchange TINYINT UNSIGNED NOT NULL DEFAULT ' 0 ' ,
name VARCHAR ( 255 ) NOT NULL DEFAULT ' ' ,
2013-02-16 16:14:39 -08:00
PRIMARY KEY ( zone , id )
) ;
CREATE TABLE spawn_events (
# identifiers
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY ,
2013-11-11 15:37:20 -05:00
zone VARCHAR ( 16 ) NOT NULL ,
cond_id MEDIUMINT UNSIGNED NOT NULL ,
name VARCHAR ( 255 ) NOT NULL DEFAULT ' ' ,
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
# timing information
2013-11-11 15:37:20 -05:00
period INT UNSIGNED NOT NULL ,
next_minute TINYINT UNSIGNED NOT NULL ,
next_hour TINYINT UNSIGNED NOT NULL ,
next_day TINYINT UNSIGNED NOT NULL ,
next_month TINYINT UNSIGNED NOT NULL ,
next_year INT UNSIGNED NOT NULL ,
enabled TINYINT NOT NULL DEFAULT ' 1 ' ,
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
# action:
2013-11-11 15:37:20 -05:00
action TINYINT UNSIGNED NOT NULL DEFAULT ' 0 ' ,
argument MEDIUMINT NOT NULL DEFAULT ' 0 '
2013-02-16 16:14:39 -08:00
) ;
*/
2013-05-06 13:07:41 -04:00
Spawn2 : : Spawn2 ( uint32 in_spawn2_id , uint32 spawngroup_id ,
float in_x , float in_y , float in_z , float in_heading ,
2013-02-16 16:14:39 -08:00
uint32 respawn , uint32 variance , uint32 timeleft , uint32 grid ,
uint16 in_cond_id , int16 in_min_value , bool in_enabled , EmuAppearance anim )
2013-04-24 15:58:51 -05:00
: timer ( 100000 ) , killcount ( 0 )
2013-02-16 16:14:39 -08:00
{
spawn2_id = in_spawn2_id ;
spawngroup_id_ = spawngroup_id ;
x = in_x ;
y = in_y ;
z = in_z ;
heading = in_heading ;
2013-05-09 10:44:08 -04:00
respawn_ = respawn ;
2013-02-16 16:14:39 -08:00
variance_ = variance ;
grid_ = grid ;
condition_id = in_cond_id ;
condition_min_value = in_min_value ;
2013-05-04 18:06:58 -07:00
npcthis = nullptr ;
2013-02-16 16:14:39 -08:00
enabled = in_enabled ;
this - > anim = anim ;
if ( timeleft = = 0xFFFFFFFF ) {
//special disable timeleft
timer . Disable ( ) ;
} else if ( timeleft ! = 0 ) {
//we have a timeleft from the DB or something
timer . Start ( timeleft ) ;
} else {
2013-05-06 13:07:41 -04:00
//no timeleft at all, reset to
2013-02-16 16:14:39 -08:00
timer . Start ( resetTimer ( ) ) ;
timer . Trigger ( ) ;
}
}
Spawn2 : : ~ Spawn2 ( )
{
}
uint32 Spawn2 : : resetTimer ( )
{
uint32 rspawn = respawn_ * 1000 ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
if ( variance_ ! = 0 ) {
int var_over_2 = ( variance_ * 1000 ) / 2 ;
rspawn = MakeRandomInt ( rspawn - var_over_2 , rspawn + var_over_2 ) ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
//put a lower bound on it, not a lot of difference below 100, so set that as the bound.
if ( rspawn < 100 )
rspawn = 100 ;
}
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
return ( rspawn ) ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
}
uint32 Spawn2 : : despawnTimer ( uint32 despawn_timer )
{
uint32 dspawn = despawn_timer * 1000 ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
if ( variance_ ! = 0 ) {
int var_over_2 = ( variance_ * 1000 ) / 2 ;
dspawn = MakeRandomInt ( dspawn - var_over_2 , dspawn + var_over_2 ) ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
//put a lower bound on it, not a lot of difference below 100, so set that as the bound.
if ( dspawn < 100 )
dspawn = 100 ;
}
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
return ( dspawn ) ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
}
bool Spawn2 : : Process ( ) {
IsDespawned = false ;
if ( ! Enabled ( ) )
return true ;
//grab our spawn group
SpawnGroup * sg = zone - > spawn_group_list . GetSpawnGroup ( spawngroup_id_ ) ;
if ( NPCPointerValid ( ) & & ( sg - > despawn = = 0 | | condition_id ! = 0 ) )
return true ;
if ( timer . Check ( ) ) {
timer . Disable ( ) ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
_log ( SPAWNS__MAIN , " Spawn2 %d: Timer has triggered " , spawn2_id ) ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
//first check our spawn condition, if this isnt active
//then we reset the timer and try again next time.
2013-05-06 13:07:41 -04:00
if ( condition_id ! = SC_AlwaysEnabled
2013-02-16 16:14:39 -08:00
& & ! zone - > spawn_conditions . Check ( condition_id , condition_min_value ) ) {
_log ( SPAWNS__CONDITIONS , " Spawn2 %d: spawning prevented by spawn condition %d " , spawn2_id , condition_id ) ;
Reset ( ) ;
return ( true ) ;
}
2013-05-06 13:07:41 -04:00
2013-05-04 18:06:58 -07:00
if ( sg = = nullptr ) {
2013-02-16 16:14:39 -08:00
database . LoadSpawnGroupsByID ( spawngroup_id_ , & zone - > spawn_group_list ) ;
sg = zone - > spawn_group_list . GetSpawnGroup ( spawngroup_id_ ) ;
}
2013-05-04 18:06:58 -07:00
if ( sg = = nullptr ) {
2013-02-16 16:14:39 -08:00
_log ( SPAWNS__MAIN , " Spawn2 %d: Unable to locate spawn group %d. Disabling. " , spawn2_id , spawngroup_id_ ) ;
return false ;
}
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
//have the spawn group pick an NPC for us
uint32 npcid = sg - > GetNPCType ( ) ;
if ( npcid = = 0 ) {
_log ( SPAWNS__MAIN , " Spawn2 %d: Spawn group %d did not yeild an NPC! not spawning. " , spawn2_id , spawngroup_id_ ) ;
Reset ( ) ; //try again later (why?)
return ( true ) ;
}
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
//try to find our NPC type.
const NPCType * tmp = database . GetNPCType ( npcid ) ;
2013-05-04 18:06:58 -07:00
if ( tmp = = nullptr ) {
2013-02-16 16:14:39 -08:00
_log ( SPAWNS__MAIN , " Spawn2 %d: Spawn group %d yeilded an invalid NPC type %d " , spawn2_id , spawngroup_id_ , npcid ) ;
Reset ( ) ; //try again later
return ( true ) ;
}
if ( tmp - > unique_spawn_by_name )
{
2013-05-06 13:07:41 -04:00
if ( ! entity_list . LimitCheckName ( tmp - > name ) )
2013-02-16 16:14:39 -08:00
{
_log ( SPAWNS__MAIN , " Spawn2 %d: Spawn group %d yeilded NPC type %d, which is unique and one already exists. " , spawn2_id , spawngroup_id_ , npcid ) ;
timer . Start ( 5000 ) ; //try again in five seconds.
return ( true ) ;
}
}
if ( tmp - > spawn_limit > 0 ) {
if ( ! entity_list . LimitCheckType ( npcid , tmp - > spawn_limit ) ) {
_log ( SPAWNS__MAIN , " Spawn2 %d: Spawn group %d yeilded NPC type %d, which is over its spawn limit (%d) " , spawn2_id , spawngroup_id_ , npcid , tmp - > spawn_limit ) ;
timer . Start ( 5000 ) ; //try again in five seconds.
return ( true ) ;
}
}
if ( sg - > despawn ! = 0 & & condition_id = = 0 )
zone - > Despawn ( spawn2_id ) ;
if ( IsDespawned )
return true ;
if ( spawn2_id )
database . UpdateSpawn2Timeleft ( spawn2_id , zone - > GetInstanceID ( ) , 0 ) ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
currentnpcid = npcid ;
NPC * npc = new NPC ( tmp , this , x , y , z , heading , FlyMode3 ) ;
2013-04-24 15:58:51 -05:00
npc - > mod_prespawn ( this ) ;
2013-02-16 16:14:39 -08:00
npcthis = npc ;
npc - > AddLootTable ( ) ;
npc - > SetSp2 ( spawngroup_id_ ) ;
2013-05-09 10:44:08 -04:00
npc - > SaveGuardPointAnim ( anim ) ;
npc - > SetAppearance ( ( EmuAppearance ) anim ) ;
2013-02-16 16:14:39 -08:00
entity_list . AddNPC ( npc ) ;
//this limit add must be done after the AddNPC since we need the entity ID.
entity_list . LimitAddNPC ( npc ) ;
2014-02-26 18:06:16 -08:00
if ( sg - > roamdist & & sg - > roambox [ 0 ] & & sg - > roambox [ 1 ] & & sg - > roambox [ 2 ] & & sg - > roambox [ 3 ] & & sg - > delay & & sg - > min_delay )
npc - > AI_SetRoambox ( sg - > roamdist , sg - > roambox [ 0 ] , sg - > roambox [ 1 ] , sg - > roambox [ 2 ] , sg - > roambox [ 3 ] , sg - > delay , sg - > min_delay ) ;
2013-02-16 16:14:39 -08:00
if ( zone - > InstantGrids ( ) ) {
_log ( SPAWNS__MAIN , " Spawn2 %d: Group %d spawned %s (%d) at (%.3f, %.3f, %.3f). " , spawn2_id , spawngroup_id_ , npc - > GetName ( ) , npcid , x , y , z ) ;
LoadGrid ( ) ;
} else {
_log ( SPAWNS__MAIN , " Spawn2 %d: Group %d spawned %s (%d) at (%.3f, %.3f, %.3f). Grid loading delayed. " , spawn2_id , spawngroup_id_ , tmp - > name , npcid , x , y , z ) ;
}
}
return true ;
}
void Spawn2 : : Disable ( )
{
2013-05-06 13:07:41 -04:00
if ( npcthis )
2013-02-16 16:14:39 -08:00
{
npcthis - > Depop ( ) ;
2013-05-06 13:07:41 -04:00
}
2013-02-16 16:14:39 -08:00
enabled = false ;
}
void Spawn2 : : LoadGrid ( ) {
if ( ! npcthis )
return ;
if ( grid_ < 1 )
return ;
if ( ! entity_list . IsMobInZone ( npcthis ) )
return ;
//dont set an NPC's grid until its loaded for them.
npcthis - > SetGrid ( grid_ ) ;
npcthis - > AssignWaypoints ( grid_ ) ;
_log ( SPAWNS__MAIN , " Spawn2 %d: Loading grid %d for %s " , spawn2_id , grid_ , npcthis - > GetName ( ) ) ;
}
/*
All three of these actions basically say that the mob which was
associated with this spawn point is no longer relavent .
*/
void Spawn2 : : Reset ( ) {
timer . Start ( resetTimer ( ) ) ;
2013-05-04 18:06:58 -07:00
npcthis = nullptr ;
2013-02-16 16:14:39 -08:00
_log ( SPAWNS__MAIN , " Spawn2 %d: Spawn reset, repop in %d ms " , spawn2_id , timer . GetRemainingTime ( ) ) ;
}
void Spawn2 : : Depop ( ) {
timer . Disable ( ) ;
_log ( SPAWNS__MAIN , " Spawn2 %d: Spawn reset, repop disabled " , spawn2_id ) ;
2013-05-04 18:06:58 -07:00
npcthis = nullptr ;
2013-02-16 16:14:39 -08:00
}
void Spawn2 : : Repop ( uint32 delay ) {
if ( delay = = 0 ) {
timer . Trigger ( ) ;
_log ( SPAWNS__MAIN , " Spawn2 %d: Spawn reset, repop immediately. " , spawn2_id ) ;
} else {
_log ( SPAWNS__MAIN , " Spawn2 %d: Spawn reset for repop, repop in %d ms " , spawn2_id , delay ) ;
timer . Start ( delay ) ;
}
2013-05-04 18:06:58 -07:00
npcthis = nullptr ;
2013-02-16 16:14:39 -08:00
}
void Spawn2 : : ForceDespawn ( )
{
SpawnGroup * sg = zone - > spawn_group_list . GetSpawnGroup ( spawngroup_id_ ) ;
2013-05-04 18:06:58 -07:00
if ( npcthis ! = nullptr )
2013-02-16 16:14:39 -08:00
{
if ( ! npcthis - > IsEngaged ( ) )
{
if ( sg - > despawn = = 3 | | sg - > despawn = = 4 )
{
npcthis - > Depop ( true ) ;
IsDespawned = true ;
2014-04-25 12:40:25 -07:00
npcthis = nullptr ;
2013-02-16 16:14:39 -08:00
return ;
}
else
{
npcthis - > Depop ( false ) ;
2014-04-25 12:40:25 -07:00
npcthis = nullptr ;
2013-02-16 16:14:39 -08:00
}
}
}
uint32 cur = 100000 ;
uint32 dtimer = sg - > despawn_timer ;
if ( sg - > despawn = = 1 | | sg - > despawn = = 3 )
{
cur = resetTimer ( ) ;
}
if ( sg - > despawn = = 2 | | sg - > despawn = = 4 )
{
cur = despawnTimer ( dtimer ) ;
}
_log ( SPAWNS__MAIN , " Spawn2 %d: Spawn group %d set despawn timer to %d ms. " , spawn2_id , spawngroup_id_ , cur ) ;
timer . Start ( cur ) ;
}
//resets our spawn as if we just died
2013-04-24 15:58:51 -05:00
void Spawn2 : : DeathReset ( bool realdeath )
2013-02-16 16:14:39 -08:00
{
//get our reset based on variance etc and store it locally
uint32 cur = resetTimer ( ) ;
//set our timer to our reset local
timer . Start ( cur ) ;
//zero out our NPC since he is now gone
2013-05-04 18:06:58 -07:00
npcthis = nullptr ;
2013-02-16 16:14:39 -08:00
2013-04-24 15:58:51 -05:00
if ( realdeath ) { killcount + + ; }
2013-02-16 16:14:39 -08:00
//if we have a valid spawn id
if ( spawn2_id )
{
database . UpdateSpawn2Timeleft ( spawn2_id , zone - > GetInstanceID ( ) , ( cur / 1000 ) ) ;
_log ( SPAWNS__MAIN , " Spawn2 %d: Spawn reset by death, repop in %d ms " , spawn2_id , timer . GetRemainingTime ( ) ) ;
//store it to database too
}
}
bool ZoneDatabase : : PopulateZoneSpawnList ( uint32 zoneid , LinkedList < Spawn2 * > & spawn2_list , int16 version , uint32 repopdelay ) {
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
const char * zone_name = database . GetZoneName ( zoneid ) ;
2014-08-24 13:00:39 -07:00
std : : string query = StringFormat ( " SELECT id, spawngroupID, x, y, z, heading, "
" respawntime, variance, pathgrid, _condition, "
" cond_value, enabled, animation FROM spawn2 "
" WHERE zone = '%s' AND version = %u " ,
zone_name , version ) ;
auto results = QueryDatabase ( query ) ;
if ( ! results . Success ( ) ) {
LogFile - > write ( EQEMuLog : : Error , " Error in PopulateZoneLists query '%s': %s " , query . c_str ( ) , results . ErrorMessage ( ) . c_str ( ) ) ;
return false ;
}
2013-02-16 16:14:39 -08:00
2014-08-24 13:00:39 -07:00
for ( auto row = results . begin ( ) ; row ! = results . end ( ) ; + + row ) {
Spawn2 * newSpawn = 0 ;
2013-05-06 13:07:41 -04:00
2014-08-24 13:00:39 -07:00
bool perl_enabled = atoi ( row [ 11 ] ) = = 1 ? true : false ;
uint32 spawnLeft = ( GetSpawnTimeLeft ( atoi ( row [ 0 ] ) , zone - > GetInstanceID ( ) ) * 1000 ) ;
newSpawn = new Spawn2 ( atoi ( row [ 0 ] ) , atoi ( row [ 1 ] ) , atof ( row [ 2 ] ) , atof ( row [ 3 ] ) , atof ( row [ 4 ] ) ,
atof ( row [ 5 ] ) , atoi ( row [ 6 ] ) , atoi ( row [ 7 ] ) , spawnLeft , atoi ( row [ 8 ] ) ,
atoi ( row [ 9 ] ) , atoi ( row [ 10 ] ) , perl_enabled , ( EmuAppearance ) atoi ( row [ 12 ] ) ) ;
spawn2_list . Insert ( newSpawn ) ;
}
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
return true ;
}
Spawn2 * ZoneDatabase : : LoadSpawn2 ( LinkedList < Spawn2 * > & spawn2_list , uint32 spawn2id , uint32 timeleft ) {
2014-08-24 13:03:45 -07:00
std : : string query = StringFormat ( " SELECT id, spawngroupID, x, y, z, heading, "
" respawntime, variance, pathgrid, _condition, "
" cond_value, enabled, animation FROM spawn2 "
" WHERE id = %i " , spawn2id ) ;
auto results = QueryDatabase ( query ) ;
if ( ! results . Success ( ) ) {
LogFile - > write ( EQEMuLog : : Error , " Error in LoadSpawn2 query '%s': %s " , query . c_str ( ) , results . ErrorMessage ( ) . c_str ( ) ) ;
return nullptr ;
}
if ( results . RowCount ( ) ! = 1 ) {
LogFile - > write ( EQEMuLog : : Error , " Error in LoadSpawn2 query '%s': %s " , query . c_str ( ) , results . ErrorMessage ( ) . c_str ( ) ) ;
return nullptr ;
}
auto row = results . begin ( ) ;
bool perl_enabled = atoi ( row [ 11 ] ) = = 1 ? true : false ;
Spawn2 * newSpawn = new Spawn2 ( atoi ( row [ 0 ] ) , atoi ( row [ 1 ] ) , atof ( row [ 2 ] ) , atof ( row [ 3 ] ) , atof ( row [ 4 ] ) ,
atof ( row [ 5 ] ) , atoi ( row [ 6 ] ) , atoi ( row [ 7 ] ) , timeleft , atoi ( row [ 8 ] ) ,
atoi ( row [ 9 ] ) , atoi ( row [ 10 ] ) , perl_enabled , ( EmuAppearance ) atoi ( row [ 12 ] ) ) ;
spawn2_list . Insert ( newSpawn ) ;
2013-02-16 16:14:39 -08:00
2014-08-24 13:03:45 -07:00
return newSpawn ;
2013-02-16 16:14:39 -08:00
}
2014-08-24 13:07:15 -07:00
bool ZoneDatabase : : CreateSpawn2 ( Client * client , uint32 spawngroup , const char * zone , float heading , float x , float y , float z , uint32 respawn , uint32 variance , uint16 condition , int16 cond_value )
2013-02-16 16:14:39 -08:00
{
2014-08-24 13:07:15 -07:00
std : : string query = StringFormat ( " INSERT INTO spawn2 (spawngroupID, zone, x, y, z, heading, "
" respawntime, variance, _condition, cond_value) "
" VALUES (%i, '%s', %f, %f, %f, %f, %i, %i, %u, %i) " ,
spawngroup , zone , x , y , z , heading ,
respawn , variance , condition , cond_value ) ;
auto results = QueryDatabase ( query ) ;
if ( ! results . Success ( ) ) {
LogFile - > write ( EQEMuLog : : Error , " Error in CreateSpawn2 query '%s': %s " , query . c_str ( ) , results . ErrorMessage ( ) . c_str ( ) ) ;
2013-02-16 16:14:39 -08:00
return false ;
2014-08-24 13:07:15 -07:00
}
if ( results . RowsAffected ( ) ! = 1 )
return false ;
if ( client )
client - > LogSQL ( query . c_str ( ) ) ;
2013-05-06 13:07:41 -04:00
2014-08-24 13:07:15 -07:00
return true ;
2013-02-16 16:14:39 -08:00
}
uint32 Zone : : CountSpawn2 ( ) {
LinkedListIterator < Spawn2 * > iterator ( spawn2_list ) ;
uint32 count = 0 ;
iterator . Reset ( ) ;
while ( iterator . MoreElements ( ) )
{
count + + ;
iterator . Advance ( ) ;
}
return count ;
}
void Zone : : Despawn ( uint32 spawn2ID ) {
LinkedListIterator < Spawn2 * > iterator ( spawn2_list ) ;
iterator . Reset ( ) ;
while ( iterator . MoreElements ( ) ) {
Spawn2 * cur = iterator . GetData ( ) ;
if ( spawn2ID = = cur - > spawn2_id )
cur - > ForceDespawn ( ) ;
iterator . Advance ( ) ;
}
}
void Spawn2 : : SpawnConditionChanged ( const SpawnCondition & c , int16 old_value ) {
if ( GetSpawnCondition ( ) ! = c . condition_id )
return ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
_log ( SPAWNS__CONDITIONS , " Spawn2 %d: Notified that our spawn condition %d has changed from %d to %d. Our min value is %d. " , spawn2_id , c . condition_id , old_value , c . value , condition_min_value ) ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
bool old_state = ( old_value > = condition_min_value ) ;
bool new_state = ( c . value > = condition_min_value ) ;
if ( old_state = = new_state ) {
_log ( SPAWNS__CONDITIONS , " Spawn2 %d: Our threshold for this condition was not crossed. Doing nothing. " , spawn2_id ) ;
return ; //no change
}
2013-05-06 13:07:41 -04:00
2014-02-09 00:08:09 -06:00
uint32 timer_remaining = 0 ;
2013-02-16 16:14:39 -08:00
switch ( c . on_change ) {
case SpawnCondition : : DoNothing :
//that was easy.
2014-02-10 09:22:55 -06:00
_log ( SPAWNS__CONDITIONS , " Spawn2 %d: Our condition is now %s. Taking no action on existing spawn. " , spawn2_id , new_state ? " enabled " : " disabled " ) ;
2013-02-16 16:14:39 -08:00
break ;
case SpawnCondition : : DoDepop :
2014-02-10 09:22:55 -06:00
_log ( SPAWNS__CONDITIONS , " Spawn2 %d: Our condition is now %s. Depoping our mob. " , spawn2_id , new_state ? " enabled " : " disabled " ) ;
2013-05-04 18:06:58 -07:00
if ( npcthis ! = nullptr )
2013-02-16 16:14:39 -08:00
npcthis - > Depop ( false ) ; //remove the current mob
Reset ( ) ; //reset our spawn timer
break ;
case SpawnCondition : : DoRepop :
2014-02-10 09:22:55 -06:00
_log ( SPAWNS__CONDITIONS , " Spawn2 %d: Our condition is now %s. Forcing a repop. " , spawn2_id , new_state ? " enabled " : " disabled " ) ;
2013-05-04 18:06:58 -07:00
if ( npcthis ! = nullptr )
2013-02-16 16:14:39 -08:00
npcthis - > Depop ( false ) ; //remove the current mob
Repop ( ) ; //repop
break ;
2014-02-09 00:08:09 -06:00
case SpawnCondition : : DoRepopIfReady :
2014-02-10 09:22:55 -06:00
_log ( SPAWNS__CONDITIONS , " Spawn2 %d: Our condition is now %s. Forcing a repop if repsawn timer is expired. " , spawn2_id , new_state ? " enabled " : " disabled " ) ;
2014-02-10 15:13:54 -06:00
if ( npcthis ! = nullptr ) {
_log ( SPAWNS__CONDITIONS , " Spawn2 %d: Our npcthis is currently not null. The zone thinks it is %s. Forcing a depop. " , spawn2_id , npcthis - > GetName ( ) ) ;
2014-02-09 00:08:09 -06:00
npcthis - > Depop ( false ) ; //remove the current mob
2014-02-10 15:13:54 -06:00
npcthis = nullptr ;
}
2014-02-09 00:08:09 -06:00
if ( new_state ) { // only get repawn timer remaining when the SpawnCondition is enabled.
timer_remaining = database . GetSpawnTimeLeft ( spawn2_id , zone - > GetInstanceID ( ) ) ;
2014-02-10 09:22:55 -06:00
_log ( SPAWNS__CONDITIONS , " Spawn2 %d: Our condition is now %s. The respawn timer_remaining is %d. Forcing a repop if it is <= 0. " , spawn2_id , new_state ? " enabled " : " disabled " , timer_remaining ) ;
2014-02-09 00:08:09 -06:00
if ( timer_remaining < = 0 )
Repop ( ) ;
} else {
_log ( SPAWNS__CONDITIONS , " Spawn2 %d: Our condition is now %s. Not checking respawn timer. " , spawn2_id , new_state ? " enabled " : " disabled " ) ;
}
break ;
2013-02-16 16:14:39 -08:00
default :
if ( c . on_change < SpawnCondition : : DoSignalMin ) {
2014-02-10 09:22:55 -06:00
_log ( SPAWNS__CONDITIONS , " Spawn2 %d: Our condition is now %s. Invalid on-change action %d. " , spawn2_id , new_state ? " enabled " : " disabled " , c . on_change ) ;
2013-02-16 16:14:39 -08:00
return ; //unknown onchange action
}
int signal_id = c . on_change - SpawnCondition : : DoSignalMin ;
2014-02-10 09:22:55 -06:00
_log ( SPAWNS__CONDITIONS , " Spawn2 %d: Our condition is now %s. Signaling our mob with %d. " , spawn2_id , new_state ? " enabled " : " disabled " , signal_id ) ;
2013-05-04 18:06:58 -07:00
if ( npcthis ! = nullptr )
2013-02-16 16:14:39 -08:00
npcthis - > SignalNPC ( signal_id ) ;
}
}
void Zone : : SpawnConditionChanged ( const SpawnCondition & c , int16 old_value ) {
_log ( SPAWNS__CONDITIONS , " Zone notified that spawn condition %d has changed from %d to %d. Notifying all spawn points. " , c . condition_id , old_value , c . value ) ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
LinkedListIterator < Spawn2 * > iterator ( spawn2_list ) ;
iterator . Reset ( ) ;
while ( iterator . MoreElements ( ) ) {
Spawn2 * cur = iterator . GetData ( ) ;
if ( cur - > GetSpawnCondition ( ) = = c . condition_id )
cur - > SpawnConditionChanged ( c , old_value ) ;
iterator . Advance ( ) ;
}
}
SpawnCondition : : SpawnCondition ( ) {
condition_id = 0 ;
value = 0 ;
on_change = DoNothing ;
}
SpawnEvent : : SpawnEvent ( ) {
id = 0 ;
condition_id = 0 ;
enabled = false ;
action = ActionSet ;
argument = 0 ;
period = 0xFFFFFFFF ;
2014-04-25 12:40:25 -07:00
strict = false ;
2013-02-16 16:14:39 -08:00
memset ( & next , 0 , sizeof ( next ) ) ;
}
SpawnConditionManager : : SpawnConditionManager ( )
: minute_timer ( 3000 ) //1 eq minute
{
memset ( & next_event , 0 , sizeof ( next_event ) ) ;
}
void SpawnConditionManager : : Process ( ) {
if ( spawn_events . empty ( ) )
return ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
if ( minute_timer . Check ( ) ) {
//check each spawn event.
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
//get our current time
TimeOfDay_Struct tod ;
zone - > zone_time . getEQTimeOfDay ( & tod ) ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
//see if time is past our nearest event.
if ( EQTime : : IsTimeBefore ( & next_event , & tod ) )
return ;
2013-05-06 13:07:41 -04:00
//at least one event should get triggered,
2013-05-22 16:17:19 -04:00
std : : vector < SpawnEvent > : : iterator cur , end ;
2013-02-16 16:14:39 -08:00
cur = spawn_events . begin ( ) ;
end = spawn_events . end ( ) ;
2014-01-13 22:14:02 -05:00
for ( ; cur ! = end ; + + cur ) {
2013-02-16 16:14:39 -08:00
SpawnEvent & cevent = * cur ;
2013-05-06 13:07:41 -04:00
2014-04-25 12:40:25 -07:00
if ( cevent . enabled )
{
if ( EQTime : : IsTimeBefore ( & tod , & cevent . next ) ) {
//this event has been triggered.
//execute the event
if ( ! cevent . strict | | ( cevent . strict & & cevent . next . hour = = tod . hour & & cevent . next . day = = tod . day & & cevent . next . month = = tod . month & & cevent . next . year = = tod . year ) )
ExecEvent ( cevent , true ) ;
2013-05-06 13:07:41 -04:00
2014-04-25 12:40:25 -07:00
//add the period of the event to the trigger time
EQTime : : AddMinutes ( cevent . period , & cevent . next ) ;
std : : string t ;
EQTime : : ToString ( & cevent . next , t ) ;
_log ( SPAWNS__CONDITIONS , " Event %d: Will trigger again in %d EQ minutes at %s. " , cevent . id , cevent . period , t . c_str ( ) ) ;
//save the next event time in the DB
UpdateDBEvent ( cevent ) ;
//find the next closest event timer.
FindNearestEvent ( ) ;
//minor optimization, if theres no more possible events,
//then stop trying... I dunno how worth while this is.
if ( EQTime : : IsTimeBefore ( & next_event , & tod ) )
return ;
}
2013-02-16 16:14:39 -08:00
}
}
}
}
void SpawnConditionManager : : ExecEvent ( SpawnEvent & event , bool send_update ) {
2013-05-22 16:17:19 -04:00
std : : map < uint16 , SpawnCondition > : : iterator condi ;
2013-02-16 16:14:39 -08:00
condi = spawn_conditions . find ( event . condition_id ) ;
if ( condi = = spawn_conditions . end ( ) ) {
_log ( SPAWNS__CONDITIONS , " Event %d: Unable to find condition %d to execute on. " , event . id , event . condition_id ) ;
return ; //unable to find the spawn condition to operate on
}
2013-05-06 13:07:41 -04:00
2014-04-25 12:40:25 -07:00
TimeOfDay_Struct tod ;
zone - > zone_time . getEQTimeOfDay ( & tod ) ;
if ( event . strict & & ( event . next . hour ! = tod . hour | | event . next . day ! = tod . day | | event . next . month ! = tod . month | | event . next . year ! = tod . year ) )
{
_log ( SPAWNS__CONDITIONS , " Event %d: Unable to execute. Condition is strict, and event time has already passed. " , event . id ) ;
return ;
}
2013-02-16 16:14:39 -08:00
SpawnCondition & cond = condi - > second ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
int16 new_value = cond . value ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
//we have our event and our condition, do our stuff.
switch ( event . action ) {
case SpawnEvent : : ActionSet :
new_value = event . argument ;
_log ( SPAWNS__CONDITIONS , " Event %d: Executing. Setting condition %d to %d. " , event . id , event . condition_id , event . argument ) ;
break ;
case SpawnEvent : : ActionAdd :
new_value + = event . argument ;
_log ( SPAWNS__CONDITIONS , " Event %d: Executing. Adding %d to condition %d, yeilding %d. " , event . id , event . argument , event . condition_id , new_value ) ;
break ;
case SpawnEvent : : ActionSubtract :
new_value - = event . argument ;
_log ( SPAWNS__CONDITIONS , " Event %d: Executing. Subtracting %d from condition %d, yeilding %d. " , event . id , event . argument , event . condition_id , new_value ) ;
break ;
case SpawnEvent : : ActionMultiply :
new_value * = event . argument ;
_log ( SPAWNS__CONDITIONS , " Event %d: Executing. Multiplying condition %d by %d, yeilding %d. " , event . id , event . condition_id , event . argument , new_value ) ;
break ;
case SpawnEvent : : ActionDivide :
new_value / = event . argument ;
_log ( SPAWNS__CONDITIONS , " Event %d: Executing. Dividing condition %d by %d, yeilding %d. " , event . id , event . condition_id , event . argument , new_value ) ;
break ;
default :
_log ( SPAWNS__CONDITIONS , " Event %d: Invalid event action type %d " , event . id , event . action ) ;
return ;
}
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
//now set the condition to the new value
if ( send_update ) //full blown update
SetCondition ( zone - > GetShortName ( ) , zone - > GetInstanceID ( ) , cond . condition_id , new_value ) ;
else //minor update done while loading
cond . value = new_value ;
}
void SpawnConditionManager : : UpdateDBEvent ( SpawnEvent & event ) {
2013-05-06 13:07:41 -04:00
2014-08-24 13:10:15 -07:00
std : : string query = StringFormat ( " UPDATE spawn_events SET "
" next_minute = %d, next_hour = %d, "
" next_day = %d, next_month = %d, "
" next_year = %d, enabled = %d, "
" strict = %d WHERE id = %d " ,
event . next . minute , event . next . hour ,
event . next . day , event . next . month ,
event . next . year , event . enabled ? 1 : 0 ,
event . strict ? 1 : 0 , event . id ) ;
auto results = database . QueryDatabase ( query ) ;
if ( ! results . Success ( ) )
LogFile - > write ( EQEMuLog : : Error , " Unable to update spawn event '%s': %s \n " , query . c_str ( ) , results . ErrorMessage ( ) . c_str ( ) ) ;
2013-02-16 16:14:39 -08:00
}
void SpawnConditionManager : : UpdateDBCondition ( const char * zone_name , uint32 instance_id , uint16 cond_id , int16 value ) {
2013-05-06 13:07:41 -04:00
2014-08-24 13:13:11 -07:00
std : : string query = StringFormat ( " REPLACE INTO spawn_condition_values "
" (id, value, zone, instance_id) "
" VALUES( %u, %u, '%s', %u) " ,
cond_id , value , zone_name , instance_id ) ;
auto results = database . QueryDatabase ( query ) ;
if ( ! results . Success ( ) )
LogFile - > write ( EQEMuLog : : Error , " Unable to update spawn condition '%s': %s \n " , query . c_str ( ) , results . ErrorMessage ( ) . c_str ( ) ) ;
2013-02-16 16:14:39 -08:00
}
2013-05-22 16:17:19 -04:00
bool SpawnConditionManager : : LoadDBEvent ( uint32 event_id , SpawnEvent & event , std : : string & zone_name ) {
2013-05-06 13:07:41 -04:00
2014-08-24 13:18:51 -07:00
std : : string query = StringFormat ( " SELECT id, cond_id, period, "
" next_minute, next_hour, next_day, "
" next_month, next_year, enabled, "
" action, argument, strict, zone "
" FROM spawn_events WHERE id = %d " , event_id ) ;
auto results = database . QueryDatabase ( query ) ;
if ( ! results . Success ( ) ) {
LogFile - > write ( EQEMuLog : : Error , " Error in LoadDBEvent query '%s': %s " , query . c_str ( ) , results . ErrorMessage ( ) . c_str ( ) ) ;
return false ;
2013-02-16 16:14:39 -08:00
}
2014-08-24 13:18:51 -07:00
if ( results . RowCount ( ) = = 0 )
return false ;
auto row = results . begin ( ) ;
event . id = atoi ( row [ 0 ] ) ;
event . condition_id = atoi ( row [ 1 ] ) ;
event . period = atoi ( row [ 2 ] ) ;
event . next . minute = atoi ( row [ 3 ] ) ;
event . next . hour = atoi ( row [ 4 ] ) ;
event . next . day = atoi ( row [ 5 ] ) ;
event . next . month = atoi ( row [ 6 ] ) ;
event . next . year = atoi ( row [ 7 ] ) ;
event . enabled = atoi ( row [ 8 ] ) ! = 0 ;
event . action = ( SpawnEvent : : Action ) atoi ( row [ 9 ] ) ;
event . argument = atoi ( row [ 10 ] ) ;
event . strict = atoi ( row [ 11 ] ) ! = 0 ;
zone_name = row [ 12 ] ;
std : : string timeAsString ;
EQTime : : ToString ( & event . next , timeAsString ) ;
_log ( SPAWNS__CONDITIONS , " (LoadDBEvent) Loaded %s spawn event %d on condition %d with period %d, action %d, argument %d, strict %d. Will trigger at %s " , event . enabled ? " enabled " : " disabled " , event . id , event . condition_id , event . period , event . action , event . argument , event . strict , timeAsString . c_str ( ) ) ;
return true ;
2013-02-16 16:14:39 -08:00
}
2013-05-06 13:07:41 -04:00
bool SpawnConditionManager : : LoadSpawnConditions ( const char * zone_name , uint32 instance_id )
2013-02-16 16:14:39 -08:00
{
//clear out old stuff..
spawn_conditions . clear ( ) ;
2013-05-06 13:07:41 -04:00
2014-08-24 13:31:55 -07:00
std : : string query = StringFormat ( " SELECT id, onchange, value "
" FROM spawn_conditions "
" WHERE zone = '%s' " , zone_name ) ;
auto results = database . QueryDatabase ( query ) ;
if ( ! results . Success ( ) ) {
LogFile - > write ( EQEMuLog : : Error , " Error in LoadSpawnConditions query '%s': %s " , query . c_str ( ) , results . ErrorMessage ( ) . c_str ( ) ) ;
2013-02-16 16:14:39 -08:00
return false ;
2014-08-24 13:31:55 -07:00
}
for ( auto row = results . begin ( ) ; row ! = results . end ( ) ; + + row ) {
//load spawn conditions
SpawnCondition cond ;
cond . condition_id = atoi ( row [ 0 ] ) ;
cond . value = atoi ( row [ 2 ] ) ;
cond . on_change = ( SpawnCondition : : OnChange ) atoi ( row [ 1 ] ) ;
spawn_conditions [ cond . condition_id ] = cond ;
_log ( SPAWNS__CONDITIONS , " Loaded spawn condition %d with value %d and on_change %d " , cond . condition_id , cond . value , cond . on_change ) ;
}
2013-02-16 16:14:39 -08:00
//load values
2014-08-24 13:31:55 -07:00
query = StringFormat ( " SELECT id, value FROM spawn_condition_values "
" WHERE zone = '%s' AND instance_id = %u " ,
zone_name , instance_id ) ;
results = database . QueryDatabase ( query ) ;
if ( ! results . Success ( ) ) {
LogFile - > write ( EQEMuLog : : Error , " Error in LoadSpawnConditions query '%s': %s " , query . c_str ( ) , results . ErrorMessage ( ) . c_str ( ) ) ;
2013-02-16 16:14:39 -08:00
spawn_conditions . clear ( ) ;
return false ;
2014-08-24 13:31:55 -07:00
}
for ( auto row = results . begin ( ) ; row ! = results . end ( ) ; + + row ) {
auto iter = spawn_conditions . find ( atoi ( row [ 0 ] ) ) ;
if ( iter ! = spawn_conditions . end ( ) )
iter - > second . value = atoi ( row [ 1 ] ) ;
}
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
//load spawn events
2014-08-24 13:31:55 -07:00
query = StringFormat ( " SELECT id, cond_id, period, next_minute, next_hour, "
" next_day, next_month, next_year, enabled, action, argument, strict "
" FROM spawn_events WHERE zone = '%s' " , zone_name ) ;
results = database . QueryDatabase ( query ) ;
if ( ! results . Success ( ) ) {
LogFile - > write ( EQEMuLog : : Error , " Error in LoadSpawnConditions events query '%s': %s " , query . c_str ( ) , results . ErrorMessage ( ) . c_str ( ) ) ;
return false ;
}
2013-05-06 13:07:41 -04:00
2014-08-24 13:31:55 -07:00
for ( auto row = results . begin ( ) ; row ! = results . end ( ) ; + + row ) {
SpawnEvent event ;
2013-05-06 13:07:41 -04:00
2014-08-24 13:31:55 -07:00
event . id = atoi ( row [ 0 ] ) ;
event . condition_id = atoi ( row [ 1 ] ) ;
event . period = atoi ( row [ 2 ] ) ;
2013-05-06 13:07:41 -04:00
2014-08-24 13:31:55 -07:00
if ( event . period = = 0 ) {
LogFile - > write ( EQEMuLog : : Error , " Refusing to load spawn event #%d because it has a period of 0 \n " , event . id ) ;
continue ;
}
event . next . minute = atoi ( row [ 3 ] ) ;
event . next . hour = atoi ( row [ 4 ] ) ;
event . next . day = atoi ( row [ 5 ] ) ;
event . next . month = atoi ( row [ 6 ] ) ;
event . next . year = atoi ( row [ 7 ] ) ;
event . enabled = atoi ( row [ 8 ] ) = = 0 ? false : true ;
event . action = ( SpawnEvent : : Action ) atoi ( row [ 9 ] ) ;
event . argument = atoi ( row [ 10 ] ) ;
event . strict = atoi ( row [ 11 ] ) = = 0 ? false : true ;
spawn_events . push_back ( event ) ;
_log ( SPAWNS__CONDITIONS , " (LoadSpawnConditions) Loaded %s spawn event %d on condition %d with period %d, action %d, argument %d, strict %d " , event . enabled ? " enabled " : " disabled " , event . id , event . condition_id , event . period , event . action , event . argument , event . strict ) ;
}
2013-05-06 13:07:41 -04:00
2013-05-09 10:44:08 -04:00
//now we need to catch up on events that happened while we were away
2013-02-16 16:14:39 -08:00
//and use them to alter just the condition variables.
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
//each spawn2 will then use its correct condition value when
//it decides what to do. This essentially forces a 'depop' action
//on spawn points which are turned off, and a 'repop' action on
//spawn points which get turned on. Im too lazy to figure out a
//better solution, and I just dont care thats much.
//get our current time
TimeOfDay_Struct tod ;
zone - > zone_time . getEQTimeOfDay ( & tod ) ;
2013-05-06 13:07:41 -04:00
2014-08-24 13:31:55 -07:00
for ( auto cur = spawn_events . begin ( ) ; cur ! = spawn_events . end ( ) ; + + cur ) {
2013-02-16 16:14:39 -08:00
SpawnEvent & cevent = * cur ;
2013-05-06 13:07:41 -04:00
2014-04-25 12:40:25 -07:00
bool StrictCheck = false ;
2014-08-24 13:00:39 -07:00
if ( cevent . strict & &
cevent . next . hour = = tod . hour & &
cevent . next . day = = tod . day & &
cevent . next . month = = tod . month & &
2014-04-25 12:40:25 -07:00
cevent . next . year = = tod . year )
StrictCheck = true ;
2013-05-06 13:07:41 -04:00
2014-04-25 12:40:25 -07:00
//If event is disabled, or we failed the strict check, set initial spawn_condition to 0.
if ( ! cevent . enabled | | ! StrictCheck )
SetCondition ( zone - > GetShortName ( ) , zone - > GetInstanceID ( ) , cevent . condition_id , 0 ) ;
2014-08-24 13:31:55 -07:00
if ( ! cevent . enabled )
continue ;
//watch for special case of all 0s, which means to reset next to now
if ( cevent . next . year = = 0 & & cevent . next . month = = 0 & & cevent . next . day = = 0 & & cevent . next . hour = = 0 & & cevent . next . minute = = 0 ) {
_log ( SPAWNS__CONDITIONS , " Initial next trigger time set for spawn event %d " , cevent . id ) ;
memcpy ( & cevent . next , & tod , sizeof ( cevent . next ) ) ;
//add one period
EQTime : : AddMinutes ( cevent . period , & cevent . next ) ;
//save it in the db.
UpdateDBEvent ( cevent ) ;
continue ; //were done with this event.
}
bool ran = false ;
while ( EQTime : : IsTimeBefore ( & tod , & cevent . next ) ) {
_log ( SPAWNS__CONDITIONS , " Catch up triggering on event %d " , cevent . id ) ;
//this event has been triggered.
//execute the event
if ( ! cevent . strict | | StrictCheck )
ExecEvent ( cevent , false ) ;
//add the period of the event to the trigger time
EQTime : : AddMinutes ( cevent . period , & cevent . next ) ;
ran = true ;
}
//only write it out if the event actually ran
if ( ran )
UpdateDBEvent ( cevent ) ; //save the event in the DB
2013-02-16 16:14:39 -08:00
}
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
//now our event timers are all up to date, find our closest event.
FindNearestEvent ( ) ;
2013-05-06 13:07:41 -04:00
2014-08-24 13:31:55 -07:00
return true ;
2013-02-16 16:14:39 -08:00
}
void SpawnConditionManager : : FindNearestEvent ( ) {
//set a huge year which should never get reached normally
next_event . year = 0xFFFFFF ;
2013-05-06 13:07:41 -04:00
2013-05-22 16:17:19 -04:00
std : : vector < SpawnEvent > : : iterator cur , end ;
2013-02-16 16:14:39 -08:00
cur = spawn_events . begin ( ) ;
end = spawn_events . end ( ) ;
int next_id = - 1 ;
2014-01-13 22:14:02 -05:00
for ( ; cur ! = end ; + + cur ) {
2013-02-16 16:14:39 -08:00
SpawnEvent & cevent = * cur ;
2014-04-25 12:40:25 -07:00
if ( cevent . enabled )
{
//see if this event is before our last nearest
2014-08-24 13:00:39 -07:00
if ( EQTime : : IsTimeBefore ( & next_event , & cevent . next ) )
2014-04-25 12:40:25 -07:00
{
memcpy ( & next_event , & cevent . next , sizeof ( next_event ) ) ;
next_id = cevent . id ;
}
2013-02-16 16:14:39 -08:00
}
}
if ( next_id = = - 1 )
_log ( SPAWNS__CONDITIONS , " No spawn events enabled. Disabling next event. " ) ;
else
_log ( SPAWNS__CONDITIONS , " Next event determined to be event %d " , next_id ) ;
}
2013-05-06 13:07:41 -04:00
void SpawnConditionManager : : SetCondition ( const char * zone_short , uint32 instance_id , uint16 condition_id , int16 new_value , bool world_update )
2013-02-16 16:14:39 -08:00
{
if ( world_update ) {
//this is an update coming from another zone, they
//have allready updated the DB, just need to update our
//memory, and check for condition changes
2013-05-22 16:17:19 -04:00
std : : map < uint16 , SpawnCondition > : : iterator condi ;
2013-02-16 16:14:39 -08:00
condi = spawn_conditions . find ( condition_id ) ;
if ( condi = = spawn_conditions . end ( ) ) {
_log ( SPAWNS__CONDITIONS , " Condition update received from world for %d, but we do not have that conditon. " , condition_id ) ;
return ; //unable to find the spawn condition
}
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
SpawnCondition & cond = condi - > second ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
if ( cond . value = = new_value ) {
_log ( SPAWNS__CONDITIONS , " Condition update received from world for %d with value %d, which is what we already have. " , condition_id , new_value ) ;
return ;
}
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
int16 old_value = cond . value ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
//set our local value
cond . value = new_value ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
_log ( SPAWNS__CONDITIONS , " Condition update received from world for %d with value %d " , condition_id , new_value ) ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
//now we have to test each spawn point to see if it changed.
zone - > SpawnConditionChanged ( cond , old_value ) ;
2013-05-06 13:07:41 -04:00
} else if ( ! strcasecmp ( zone_short , zone - > GetShortName ( ) ) & & instance_id = = zone - > GetInstanceID ( ) )
2013-02-16 16:14:39 -08:00
{
//this is a local spawn condition, we need to update the DB,
//our memory, then notify spawn points of the change.
2013-05-22 16:17:19 -04:00
std : : map < uint16 , SpawnCondition > : : iterator condi ;
2013-02-16 16:14:39 -08:00
condi = spawn_conditions . find ( condition_id ) ;
if ( condi = = spawn_conditions . end ( ) ) {
_log ( SPAWNS__CONDITIONS , " Local Condition update requested for %d, but we do not have that conditon. " , condition_id ) ;
return ; //unable to find the spawn condition
}
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
SpawnCondition & cond = condi - > second ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
if ( cond . value = = new_value ) {
_log ( SPAWNS__CONDITIONS , " Local Condition update requested for %d with value %d, which is what we already have. " , condition_id , new_value ) ;
return ;
}
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
int16 old_value = cond . value ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
//set our local value
cond . value = new_value ;
//save it in the DB too
UpdateDBCondition ( zone_short , instance_id , condition_id , new_value ) ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
_log ( SPAWNS__CONDITIONS , " Local Condition update requested for %d with value %d " , condition_id , new_value ) ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
//now we have to test each spawn point to see if it changed.
zone - > SpawnConditionChanged ( cond , old_value ) ;
2013-05-06 13:07:41 -04:00
}
2013-02-16 16:14:39 -08:00
else
{
//this is a remote spawn condition, update the DB and send
//an update packet to the zone if its up
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
_log ( SPAWNS__CONDITIONS , " Remote spawn condition %d set to %d. Updating DB and notifying world. " , condition_id , new_value ) ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
UpdateDBCondition ( zone_short , instance_id , condition_id , new_value ) ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
ServerPacket * pack = new ServerPacket ( ServerOP_SpawnCondition , sizeof ( ServerSpawnCondition_Struct ) ) ;
ServerSpawnCondition_Struct * ssc = ( ServerSpawnCondition_Struct * ) pack - > pBuffer ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
ssc - > zoneID = database . GetZoneID ( zone_short ) ;
ssc - > instanceID = instance_id ;
ssc - > condition_id = condition_id ;
ssc - > value = new_value ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
worldserver . SendPacket ( pack ) ;
safe_delete ( pack ) ;
}
}
void SpawnConditionManager : : ReloadEvent ( uint32 event_id ) {
2013-05-22 16:17:19 -04:00
std : : string zone_short_name ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
_log ( SPAWNS__CONDITIONS , " Requested to reload event %d from the database. " , event_id ) ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
//first look for the event in our local event list
2013-05-22 16:17:19 -04:00
std : : vector < SpawnEvent > : : iterator cur , end ;
2013-02-16 16:14:39 -08:00
cur = spawn_events . begin ( ) ;
end = spawn_events . end ( ) ;
2014-01-13 22:14:02 -05:00
for ( ; cur ! = end ; + + cur ) {
2013-02-16 16:14:39 -08:00
SpawnEvent & cevent = * cur ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
if ( cevent . id = = event_id ) {
//load the event into the old event slot
if ( ! LoadDBEvent ( event_id , cevent , zone_short_name ) ) {
//unable to find the event in the database...
_log ( SPAWNS__CONDITIONS , " Failed to reload event %d from the database. " , event_id ) ;
return ;
}
//sync up our nearest event
FindNearestEvent ( ) ;
return ;
}
}
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
//if we get here, it is a new event...
SpawnEvent e ;
if ( ! LoadDBEvent ( event_id , e , zone_short_name ) ) {
//unable to find the event in the database...
_log ( SPAWNS__CONDITIONS , " Failed to reload event %d from the database. " , event_id ) ;
return ;
}
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
//we might want to check the next timer like we do on
//regular load events, but we are assuming this is a new event
//and anyways, this will get handled (albeit not optimally)
//naturally by the event handling code.
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
spawn_events . push_back ( e ) ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
//sync up our nearest event
FindNearestEvent ( ) ;
}
2014-04-25 12:40:25 -07:00
void SpawnConditionManager : : ToggleEvent ( uint32 event_id , bool enabled , bool strict , bool reset_base ) {
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
_log ( SPAWNS__CONDITIONS , " Request to %s spawn event %d %sresetting trigger time " , enabled ? " enable " : " disable " , event_id , reset_base ? " " : " without " ) ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
//first look for the event in our local event list
2013-05-22 16:17:19 -04:00
std : : vector < SpawnEvent > : : iterator cur , end ;
2013-02-16 16:14:39 -08:00
cur = spawn_events . begin ( ) ;
end = spawn_events . end ( ) ;
2014-01-13 22:14:02 -05:00
for ( ; cur ! = end ; + + cur ) {
2013-02-16 16:14:39 -08:00
SpawnEvent & cevent = * cur ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
if ( cevent . id = = event_id ) {
//make sure were actually changing something
2014-04-25 12:40:25 -07:00
if ( cevent . enabled ! = enabled | | reset_base | | cevent . strict ! = strict ) {
2013-02-16 16:14:39 -08:00
cevent . enabled = enabled ;
2014-04-25 12:40:25 -07:00
cevent . strict = strict ;
2013-02-16 16:14:39 -08:00
if ( reset_base ) {
_log ( SPAWNS__CONDITIONS , " Spawn event %d located in this zone. State set. Trigger time reset (period %d). " , event_id , cevent . period ) ;
//start with the time now
zone - > zone_time . getEQTimeOfDay ( & cevent . next ) ;
//advance the next time by our period
EQTime : : AddMinutes ( cevent . period , & cevent . next ) ;
} else {
_log ( SPAWNS__CONDITIONS , " Spawn event %d located in this zone. State changed. " , event_id ) ;
}
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
//save the event in the DB
UpdateDBEvent ( cevent ) ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
//sync up our nearest event
FindNearestEvent ( ) ;
} else {
_log ( SPAWNS__CONDITIONS , " Spawn event %d located in this zone but no change was needed. " , event_id ) ;
}
//even if we dont change anything, we still found it
return ;
}
}
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
//if we get here, the condition must be in another zone.
//first figure out what zone it applies to.
2013-05-06 13:07:41 -04:00
//update the DB and send and send an update packet to
2013-02-16 16:14:39 -08:00
//the zone if its up
2013-05-06 13:07:41 -04:00
//we need to load the event from the DB and then update
2013-02-16 16:14:39 -08:00
//the values in the DB, because we do not know if the zone
//is up or not. The message to the zone will just tell it to
//update its in-memory event list
SpawnEvent e ;
2013-05-22 16:17:19 -04:00
std : : string zone_short_name ;
2013-02-16 16:14:39 -08:00
if ( ! LoadDBEvent ( event_id , e , zone_short_name ) ) {
_log ( SPAWNS__CONDITIONS , " Unable to find spawn event %d in the database. " , event_id ) ;
//unable to find the event in the database...
return ;
}
if ( e . enabled = = enabled & & ! reset_base ) {
_log ( SPAWNS__CONDITIONS , " Spawn event %d is not located in this zone but no change was needed. " , event_id ) ;
return ; //no changes.
}
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
e . enabled = enabled ;
if ( reset_base ) {
_log ( SPAWNS__CONDITIONS , " Spawn event %d is in zone %s. State set. Trigger time reset (period %d). Notifying world. " , event_id , zone_short_name . c_str ( ) , e . period ) ;
//start with the time now
zone - > zone_time . getEQTimeOfDay ( & e . next ) ;
//advance the next time by our period
EQTime : : AddMinutes ( e . period , & e . next ) ;
} else {
2013-05-09 10:44:08 -04:00
_log ( SPAWNS__CONDITIONS , " Spawn event %d is in zone %s. State changed. Notifying world. " , event_id , zone_short_name . c_str ( ) , e . period ) ;
2013-02-16 16:14:39 -08:00
}
//save the event in the DB
UpdateDBEvent ( e ) ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
//now notify the zone
ServerPacket * pack = new ServerPacket ( ServerOP_SpawnEvent , sizeof ( ServerSpawnEvent_Struct ) ) ;
ServerSpawnEvent_Struct * sse = ( ServerSpawnEvent_Struct * ) pack - > pBuffer ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
sse - > zoneID = database . GetZoneID ( zone_short_name . c_str ( ) ) ;
sse - > event_id = event_id ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
worldserver . SendPacket ( pack ) ;
safe_delete ( pack ) ;
}
int16 SpawnConditionManager : : GetCondition ( const char * zone_short , uint32 instance_id , uint16 condition_id ) {
2013-05-06 13:07:41 -04:00
if ( ! strcasecmp ( zone_short , zone - > GetShortName ( ) ) & & instance_id = = zone - > GetInstanceID ( ) )
2013-02-16 16:14:39 -08:00
{
//this is a local spawn condition
2013-05-22 16:17:19 -04:00
std : : map < uint16 , SpawnCondition > : : iterator condi ;
2013-02-16 16:14:39 -08:00
condi = spawn_conditions . find ( condition_id ) ;
2013-05-06 13:07:41 -04:00
if ( condi = = spawn_conditions . end ( ) )
2013-02-16 16:14:39 -08:00
{
_log ( SPAWNS__CONDITIONS , " Unable to find local condition %d in Get request. " , condition_id ) ;
return ( 0 ) ; //unable to find the spawn condition
}
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
SpawnCondition & cond = condi - > second ;
2014-08-24 13:47:18 -07:00
return cond . value ;
2013-02-16 16:14:39 -08:00
}
2014-08-24 13:47:18 -07:00
//this is a remote spawn condition, grab it from the DB
//load spawn conditions
std : : string query = StringFormat ( " SELECT value FROM spawn_condition_values "
" WHERE zone = '%s' AND instance_id = %u AND id = %d " ,
zone_short , instance_id , condition_id ) ;
auto results = database . QueryDatabase ( query ) ;
if ( ! results . Success ( ) ) {
_log ( SPAWNS__CONDITIONS , " Unable to query remote condition %d from zone %s in Get request. " , condition_id , zone_short ) ;
return 0 ; //dunno a better thing to do...
}
if ( results . RowCount ( ) = = 0 ) {
_log ( SPAWNS__CONDITIONS , " Unable to load remote condition %d from zone %s in Get request. " , condition_id , zone_short ) ;
return 0 ; //dunno a better thing to do...
}
auto row = results . begin ( ) ;
return atoi ( row [ 0 ] ) ;
2013-02-16 16:14:39 -08:00
}
bool SpawnConditionManager : : Check ( uint16 condition , int16 min_value ) {
2013-05-22 16:17:19 -04:00
std : : map < uint16 , SpawnCondition > : : iterator condi ;
2013-02-16 16:14:39 -08:00
condi = spawn_conditions . find ( condition ) ;
if ( condi = = spawn_conditions . end ( ) )
return ( false ) ; //unable to find the spawn condition
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
SpawnCondition & cond = condi - > second ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
return ( cond . value > = min_value ) ;
}