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
*/
2014-12-15 18:42:14 -06:00
2015-01-19 04:12:09 -06:00
# include "../common/global_define.h"
2014-08-21 19:33:02 -07:00
# include "../common/string_util.h"
2014-12-15 18:42:14 -06:00
# include "client.h"
2013-02-16 16:14:39 -08:00
# include "entity.h"
2014-12-15 18:42:14 -06:00
# include "spawn2.h"
2013-02-16 16:14:39 -08:00
# include "spawngroup.h"
# include "worldserver.h"
2014-12-15 18:42:14 -06:00
# include "zone.h"
# include "zonedb.h"
2020-04-19 04:36:39 -05:00
# include "zone_store.h"
2013-02-16 16:14:39 -08:00
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 ,
2021-05-10 02:21:43 -04:00
bool in_path_when_zone_idle , 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 ;
2021-05-10 02:21:43 -04:00
path_when_zone_idle = in_path_when_zone_idle ;
2013-02-16 16:14:39 -08:00
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 ;
2014-12-01 18:13:12 -05:00
rspawn = zone - > random . Int ( 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 ;
2014-12-01 18:13:12 -05:00
dspawn = zone - > random . Int ( 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 ;
2018-08-18 18:12:18 -05:00
if ( ! Enabled ( ) )
2013-02-16 16:14:39 -08:00
return true ;
//grab our spawn group
2018-08-18 18:12:18 -05:00
SpawnGroup * spawn_group = zone - > spawn_group_list . GetSpawnGroup ( spawngroup_id_ ) ;
2013-02-16 16:14:39 -08:00
2018-08-18 18:12:18 -05:00
if ( NPCPointerValid ( ) & & ( spawn_group - > despawn = = 0 | | condition_id ! = 0 ) ) {
2013-02-16 16:14:39 -08:00
return true ;
2018-08-18 18:12:18 -05:00
}
2013-02-16 16:14:39 -08:00
2018-08-18 18:12:18 -05:00
if ( timer . Check ( ) ) {
2013-02-16 16:14:39 -08:00
timer . Disable ( ) ;
2013-05-06 13:07:41 -04:00
2019-09-02 04:10:43 -05:00
LogSpawns ( " Spawn2 [{}]: 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.
2018-08-18 18:12:18 -05:00
if ( condition_id ! = SC_AlwaysEnabled
2013-02-16 16:14:39 -08:00
& & ! zone - > spawn_conditions . Check ( condition_id , condition_min_value ) ) {
2019-09-02 04:10:43 -05:00
LogSpawns ( " Spawn2 [{}]: spawning prevented by spawn condition [{}] " , spawn2_id , condition_id ) ;
2013-02-16 16:14:39 -08:00
Reset ( ) ;
2018-08-18 18:12:18 -05:00
return ( true ) ;
2013-02-16 16:14:39 -08:00
}
2013-05-06 13:07:41 -04:00
2020-03-30 23:25:32 -05:00
/**
* Wait for init grids timer because we bulk load this data before trying to fetch it individually
*/
if ( spawn_group = = nullptr & & zone - > GetInitgridsTimer ( ) . Check ( ) ) {
2020-03-12 03:15:14 -05:00
content_db . LoadSpawnGroupsByID ( spawngroup_id_ , & zone - > spawn_group_list ) ;
2018-08-18 18:12:18 -05:00
spawn_group = zone - > spawn_group_list . GetSpawnGroup ( spawngroup_id_ ) ;
2013-02-16 16:14:39 -08:00
}
2018-08-18 18:12:18 -05:00
if ( spawn_group = = nullptr ) {
2019-09-02 04:10:43 -05:00
LogSpawns ( " Spawn2 [{}]: Unable to locate spawn group [{}]. Disabling " , spawn2_id , spawngroup_id_ ) ;
2018-08-18 18:12:18 -05:00
2013-02-16 16:14:39 -08:00
return false ;
}
2013-05-06 13:07:41 -04:00
2019-09-02 10:34:09 -04:00
uint16 condition_value = 1 ;
if ( condition_id > 0 ) {
condition_value = zone - > spawn_conditions . GetCondition ( zone - > GetShortName ( ) , zone - > GetInstanceID ( ) , condition_id ) ;
}
2013-02-16 16:14:39 -08:00
//have the spawn group pick an NPC for us
2019-09-02 10:34:09 -04:00
uint32 npcid = spawn_group - > GetNPCType ( condition_value ) ;
2013-02-16 16:14:39 -08:00
if ( npcid = = 0 ) {
2019-09-02 04:10:43 -05:00
LogSpawns ( " Spawn2 [{}]: Spawn group [{}] did not yeild an NPC! not spawning " , spawn2_id , spawngroup_id_ ) ;
2018-08-18 18:12:18 -05:00
Reset ( ) ; //try again later (why?)
return ( true ) ;
2013-02-16 16:14:39 -08:00
}
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
//try to find our NPC type.
2020-03-12 00:00:39 -05:00
const NPCType * tmp = content_db . LoadNPCTypesData ( npcid ) ;
2013-05-04 18:06:58 -07:00
if ( tmp = = nullptr ) {
2019-09-02 04:10:43 -05:00
LogSpawns ( " Spawn2 [{}]: Spawn group [{}] yeilded an invalid NPC type [{}] " , spawn2_id , spawngroup_id_ , npcid ) ;
2018-08-18 18:12:18 -05:00
Reset ( ) ; //try again later
return ( true ) ;
2013-02-16 16:14:39 -08:00
}
2018-08-18 18:12:18 -05:00
if ( tmp - > unique_spawn_by_name ) {
if ( ! entity_list . LimitCheckName ( tmp - > name ) ) {
2019-09-02 04:10:43 -05:00
LogSpawns ( " Spawn2 [{}]: Spawn group [{}] yeilded NPC type [{}], which is unique and one already exists " , spawn2_id , spawngroup_id_ , npcid ) ;
2018-08-18 18:12:18 -05:00
timer . Start ( 5000 ) ; //try again in five seconds.
return ( true ) ;
2013-02-16 16:14:39 -08:00
}
}
2018-08-18 18:12:18 -05:00
if ( tmp - > spawn_limit > 0 ) {
if ( ! entity_list . LimitCheckType ( npcid , tmp - > spawn_limit ) ) {
2019-09-02 04:10:43 -05:00
LogSpawns ( " Spawn2 [{}]: Spawn group [{}] yeilded NPC type [{}], which is over its spawn limit ([{}]) " , spawn2_id , spawngroup_id_ , npcid , tmp - > spawn_limit ) ;
2018-08-18 18:12:18 -05:00
timer . Start ( 5000 ) ; //try again in five seconds.
return ( true ) ;
2013-02-16 16:14:39 -08:00
}
}
2017-04-07 19:45:26 -07:00
bool ignore_despawn = false ;
2018-08-18 18:12:18 -05:00
if ( npcthis ) {
2017-04-07 19:45:26 -07:00
ignore_despawn = npcthis - > IgnoreDespawn ( ) ;
}
2018-08-18 18:12:18 -05:00
if ( ignore_despawn ) {
2017-04-07 19:45:26 -07:00
return true ;
}
2018-08-18 18:12:18 -05:00
if ( spawn_group - > despawn ! = 0 & & condition_id = = 0 & & ! ignore_despawn ) {
2013-02-16 16:14:39 -08:00
zone - > Despawn ( spawn2_id ) ;
2017-04-07 19:45:26 -07:00
}
2013-02-16 16:14:39 -08:00
2018-08-18 18:12:18 -05:00
if ( IsDespawned ) {
2013-02-16 16:14:39 -08:00
return true ;
2017-04-07 19:45:26 -07:00
}
2013-02-16 16:14:39 -08:00
currentnpcid = npcid ;
2020-01-24 15:11:08 -08:00
glm : : vec4 loc ( x , y , z , heading ) ;
int starting_wp = 0 ;
if ( spawn_group - > wp_spawns & & grid_ > 0 )
{
glm : : vec4 wploc ;
2020-03-11 04:10:21 -05:00
starting_wp = content_db . GetRandomWaypointLocFromGrid ( wploc , zone - > GetZoneID ( ) , grid_ ) ;
2020-01-24 15:11:08 -08:00
if ( wploc . x ! = 0.0f | | wploc . y ! = 0.0f | | wploc . z ! = 0.0f )
{
loc = wploc ;
Log ( Logs : : General , Logs : : Spawns , " spawning at random waypoint #%i loc: (%.3f, %.3f, %.3f). " , starting_wp , loc . x , loc . y , loc . z ) ;
}
}
2018-11-09 00:54:51 -08:00
NPC * npc = new NPC ( tmp , this , glm : : vec4 ( x , y , z , heading ) , GravityBehavior : : Water ) ;
2013-04-24 15:58:51 -05:00
npc - > mod_prespawn ( this ) ;
2013-02-16 16:14:39 -08:00
npcthis = npc ;
npc - > AddLootTable ( ) ;
2018-08-18 18:12:18 -05:00
if ( npc - > DropsGlobalLoot ( ) ) {
Implement global loot system Fixes #619
This should allow us to emulate lives global tables
The options available to filter tables are min_level, max_level, race,
rare, raid, race, class, bodytype, and zone.
race, class, bodytype, and zone are a pipe | separated list of IDs
2018-02-10 22:15:21 -05:00
npc - > CheckGlobalLootTables ( ) ;
2018-08-18 18:12:18 -05:00
}
2019-08-16 03:25:34 -05:00
npc - > SetSpawnGroupId ( spawngroup_id_ ) ;
2013-05-09 10:44:08 -04:00
npc - > SaveGuardPointAnim ( anim ) ;
2018-08-18 18:12:18 -05:00
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 ) ;
2018-08-18 18:12:18 -05:00
/**
* Roambox init
*/
2019-08-16 03:25:34 -05:00
if ( spawn_group - > roamdist > 0 ) {
2018-08-18 18:12:18 -05:00
npc - > AI_SetRoambox (
spawn_group - > roamdist ,
spawn_group - > roambox [ 0 ] ,
spawn_group - > roambox [ 1 ] ,
spawn_group - > roambox [ 2 ] ,
spawn_group - > roambox [ 3 ] ,
spawn_group - > delay ,
spawn_group - > min_delay
) ;
}
if ( zone - > InstantGrids ( ) ) {
2019-09-02 04:10:43 -05:00
LogSpawns ( " Spawn2 [{}]: Group [{}] spawned [{}] ([{}]) at ([{}], [{}], [{}]) " ,
2018-08-18 18:12:18 -05:00
spawn2_id ,
spawngroup_id_ ,
npc - > GetName ( ) ,
npcid ,
x ,
y ,
2019-08-16 03:25:34 -05:00
z
) ;
2018-08-18 18:12:18 -05:00
2020-01-24 15:11:08 -08:00
LoadGrid ( starting_wp ) ;
2018-08-18 18:12:18 -05:00
}
else {
2019-09-02 04:10:43 -05:00
LogSpawns ( " Spawn2 [{}]: Group [{}] spawned [{}] ([{}]) at ([{}], [{}], [{}]). Grid loading delayed " ,
2018-08-18 18:12:18 -05:00
spawn2_id ,
spawngroup_id_ ,
tmp - > name ,
npcid ,
x ,
y ,
2019-09-02 04:10:43 -05:00
z
) ;
2013-02-16 16:14:39 -08:00
}
}
2018-08-18 18:12:18 -05:00
2013-02-16 16:14:39 -08:00
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 ;
}
2020-01-24 15:11:08 -08:00
void Spawn2 : : LoadGrid ( int start_wp ) {
2018-08-18 18:12:18 -05:00
if ( ! npcthis )
2013-02-16 16:14:39 -08:00
return ;
2018-08-18 18:12:18 -05:00
if ( grid_ < 1 )
2013-02-16 16:14:39 -08:00
return ;
2018-08-18 18:12:18 -05:00
if ( ! entity_list . IsMobInZone ( npcthis ) )
2013-02-16 16:14:39 -08:00
return ;
//dont set an NPC's grid until its loaded for them.
npcthis - > SetGrid ( grid_ ) ;
2020-01-24 15:11:08 -08:00
npcthis - > AssignWaypoints ( grid_ , start_wp ) ;
LogSpawns ( " Spawn2 [{}]: Loading grid [{}] for [{}]; starting wp is [{}] " , spawn2_id , grid_ , npcthis - > GetName ( ) , start_wp ) ;
2013-02-16 16:14:39 -08:00
}
/*
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 ;
2019-09-02 04:10:43 -05:00
LogSpawns ( " Spawn2 [{}]: Spawn reset, repop in [{}] ms " , spawn2_id , timer . GetRemainingTime ( ) ) ;
2013-02-16 16:14:39 -08:00
}
void Spawn2 : : Depop ( ) {
timer . Disable ( ) ;
2019-09-02 04:10:43 -05:00
LogSpawns ( " Spawn2 [{}]: 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 ( ) ;
2019-09-02 04:10:43 -05:00
LogSpawns ( " Spawn2 [{}]: Spawn reset, repop immediately " , spawn2_id ) ;
2013-02-16 16:14:39 -08:00
} else {
2019-09-02 04:10:43 -05:00
LogSpawns ( " Spawn2 [{}]: Spawn reset for repop, repop in [{}] ms " , spawn2_id , delay ) ;
2013-02-16 16:14:39 -08:00
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
{
2017-04-07 19:45:26 -07:00
if ( npcthis - > IgnoreDespawn ( ) )
return ;
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 ) ;
}
2019-09-02 04:10:43 -05:00
LogSpawns ( " Spawn2 [{}]: Spawn group [{}] set despawn timer to [{}] ms " , spawn2_id , spawngroup_id_ , cur ) ;
2013-02-16 16:14:39 -08:00
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 )
{
2015-02-08 05:01:58 -06:00
database . UpdateRespawnTime ( spawn2_id , zone - > GetInstanceID ( ) , ( cur / 1000 ) ) ;
2019-09-02 04:10:43 -05:00
LogSpawns ( " Spawn2 [{}]: Spawn reset by death, repop in [{}] ms " , spawn2_id , timer . GetRemainingTime ( ) ) ;
2013-02-16 16:14:39 -08:00
//store it to database too
}
}
2015-11-07 13:20:24 -06:00
bool ZoneDatabase : : PopulateZoneSpawnListClose ( uint32 zoneid , LinkedList < Spawn2 * > & spawn2_list , int16 version , const glm : : vec4 & client_position , uint32 repop_distance )
{
std : : unordered_map < uint32 , uint32 > spawn_times ;
float mob_distance = 0 ;
timeval tv ;
gettimeofday ( & tv , nullptr ) ;
/* Bulk Load NPC Types Data into the cache */
2020-03-12 00:00:39 -05:00
content_db . LoadNPCTypesData ( 0 , true ) ;
2015-11-07 13:20:24 -06:00
std : : string spawn_query = StringFormat (
" SELECT "
" respawn_times.id, "
" respawn_times.`start`, "
" respawn_times.duration "
" FROM "
" respawn_times "
" WHERE instance_id = %u " ,
zone - > GetInstanceID ( )
) ;
auto results = QueryDatabase ( spawn_query ) ;
for ( auto row = results . begin ( ) ; row ! = results . end ( ) ; + + row ) {
uint32 start_duration = atoi ( row [ 1 ] ) > 0 ? atoi ( row [ 1 ] ) : 0 ;
uint32 end_duration = atoi ( row [ 2 ] ) > 0 ? atoi ( row [ 2 ] ) : 0 ;
/* Our current time was expired */
if ( ( start_duration + end_duration ) < = tv . tv_sec ) {
spawn_times [ atoi ( row [ 0 ] ) ] = 0 ;
}
/* We still have time left on this timer */
else {
spawn_times [ atoi ( row [ 0 ] ) ] = ( ( start_duration + end_duration ) - tv . tv_sec ) * 1000 ;
}
}
2020-04-19 04:36:39 -05:00
const char * zone_name = ZoneName ( zoneid ) ;
2015-11-07 13:20:24 -06:00
std : : string query = StringFormat (
" SELECT "
" id, "
" spawngroupID, "
" x, "
" y, "
" z, "
" heading, "
" respawntime, "
" variance, "
" pathgrid, "
2021-05-10 02:21:43 -04:00
" path_when_zone_idle, "
2015-11-07 13:20:24 -06:00
" _condition, "
" cond_value, "
" enabled, "
" animation "
" FROM "
" spawn2 "
2019-01-10 19:55:59 -05:00
" WHERE zone = '%s' AND (version = %u OR version = -1) " ,
2015-11-07 13:20:24 -06:00
zone_name ,
version
) ;
2020-03-30 21:32:59 -05:00
results = database . QueryDatabase ( query ) ;
2015-11-07 13:20:24 -06:00
if ( ! results . Success ( ) ) {
return false ;
}
for ( auto row = results . begin ( ) ; row ! = results . end ( ) ; + + row ) {
uint32 spawn_time_left = 0 ;
Spawn2 * new_spawn = 0 ;
2021-05-10 02:21:43 -04:00
bool perl_enabled = atoi ( row [ 12 ] ) = = 1 ? true : false ;
2015-11-07 13:20:24 -06:00
if ( spawn_times . count ( atoi ( row [ 0 ] ) ) ! = 0 )
spawn_time_left = spawn_times [ atoi ( row [ 0 ] ) ] ;
glm : : vec4 point ;
point . x = atof ( row [ 2 ] ) ;
point . y = atof ( row [ 3 ] ) ;
mob_distance = DistanceNoZ ( client_position , point ) ;
if ( mob_distance > repop_distance )
continue ;
2021-05-10 02:21:43 -04:00
new_spawn = new Spawn2 (
atoi ( row [ 0 ] ) , // uint32 in_spawn2_id
atoi ( row [ 1 ] ) , // uint32 spawngroup_id
atof ( row [ 2 ] ) , // float in_x
atof ( row [ 3 ] ) , // float in_y
atof ( row [ 4 ] ) , // float in_z
atof ( row [ 5 ] ) , // float in_heading
atoi ( row [ 6 ] ) , // uint32 respawn
atoi ( row [ 7 ] ) , // uint32 variance
spawn_time_left , // uint32 timeleft
atoi ( row [ 8 ] ) , // uint32 grid
( bool ) atoi ( row [ 9 ] ) , // bool path_when_zone_idle
atoi ( row [ 10 ] ) , // uint16 in_cond_id
atoi ( row [ 11 ] ) , // int16 in_min_value
perl_enabled , // bool in_enabled
( EmuAppearance ) atoi ( row [ 13 ] ) // EmuAppearance anim
2015-11-07 13:20:24 -06:00
) ;
spawn2_list . Insert ( new_spawn ) ;
}
return true ;
}
2013-02-16 16:14:39 -08:00
bool ZoneDatabase : : PopulateZoneSpawnList ( uint32 zoneid , LinkedList < Spawn2 * > & spawn2_list , int16 version , uint32 repopdelay ) {
2013-05-06 13:07:41 -04:00
2015-02-08 05:01:58 -06:00
std : : unordered_map < uint32 , uint32 > spawn_times ;
timeval tv ;
gettimeofday ( & tv , nullptr ) ;
2015-02-12 19:57:24 -06:00
/* Bulk Load NPC Types Data into the cache */
2020-03-12 00:00:39 -05:00
content_db . LoadNPCTypesData ( 0 , true ) ;
2015-02-12 19:57:24 -06:00
2015-02-08 05:01:58 -06:00
std : : string spawn_query = StringFormat (
" SELECT "
" respawn_times.id, "
" respawn_times.`start`, "
" respawn_times.duration "
" FROM "
" respawn_times "
" WHERE instance_id = %u " ,
zone - > GetInstanceID ( )
) ;
2020-03-30 21:32:59 -05:00
auto results = database . QueryDatabase ( spawn_query ) ;
2015-02-08 05:01:58 -06:00
for ( auto row = results . begin ( ) ; row ! = results . end ( ) ; + + row ) {
uint32 start_duration = atoi ( row [ 1 ] ) > 0 ? atoi ( row [ 1 ] ) : 0 ;
uint32 end_duration = atoi ( row [ 2 ] ) > 0 ? atoi ( row [ 2 ] ) : 0 ;
/* Our current time was expired */
if ( ( start_duration + end_duration ) < = tv . tv_sec ) {
spawn_times [ atoi ( row [ 0 ] ) ] = 0 ;
}
/* We still have time left on this timer */
else {
spawn_times [ atoi ( row [ 0 ] ) ] = ( ( start_duration + end_duration ) - tv . tv_sec ) * 1000 ;
}
}
2020-04-19 04:36:39 -05:00
const char * zone_name = ZoneName ( zoneid ) ;
2015-02-08 05:01:58 -06:00
std : : string query = StringFormat (
" SELECT "
" id, "
" spawngroupID, "
" x, "
" y, "
" z, "
" heading, "
" respawntime, "
" variance, "
" pathgrid, "
2021-05-10 02:21:43 -04:00
" path_when_zone_idle, "
2015-02-08 05:01:58 -06:00
" _condition, "
" cond_value, "
" enabled, "
" animation "
" FROM "
" spawn2 "
2019-01-10 19:55:59 -05:00
" WHERE zone = '%s' AND (version = %u OR version = -1) " ,
2015-02-08 05:01:58 -06:00
zone_name ,
version
) ;
results = QueryDatabase ( query ) ;
if ( ! results . Success ( ) ) {
2014-08-24 13:00:39 -07:00
return false ;
2015-02-08 05:01:58 -06:00
}
2014-08-24 13:00:39 -07:00
2015-02-08 05:01:58 -06:00
for ( auto row = results . begin ( ) ; row ! = results . end ( ) ; + + row ) {
2020-04-18 23:26:53 -05:00
uint32 spawn_time_left = 0 ;
Spawn2 * new_spawn = 0 ;
2021-05-10 02:21:43 -04:00
bool perl_enabled = atoi ( row [ 12 ] ) = = 1 ? true : false ;
2015-02-08 05:01:58 -06:00
if ( spawn_times . count ( atoi ( row [ 0 ] ) ) ! = 0 )
spawn_time_left = spawn_times [ atoi ( row [ 0 ] ) ] ;
2021-05-10 02:21:43 -04:00
new_spawn = new Spawn2 (
atoi ( row [ 0 ] ) , // uint32 in_spawn2_id
atoi ( row [ 1 ] ) , // uint32 spawngroup_id
atof ( row [ 2 ] ) , // float in_x
atof ( row [ 3 ] ) , // float in_y
atof ( row [ 4 ] ) , // float in_z
atof ( row [ 5 ] ) , // float in_heading
atoi ( row [ 6 ] ) , // uint32 respawn
atoi ( row [ 7 ] ) , // uint32 variance
spawn_time_left , // uint32 timeleft
atoi ( row [ 8 ] ) , // uint32 grid
( bool ) atoi ( row [ 9 ] ) , // bool path_when_zone_idle
atoi ( row [ 10 ] ) , // uint16 in_cond_id
atoi ( row [ 11 ] ) , // int16 in_min_value
perl_enabled , // bool in_enabled
( EmuAppearance ) atoi ( row [ 13 ] ) // EmuAppearance anim
2015-02-08 05:01:58 -06:00
) ;
spawn2_list . Insert ( new_spawn ) ;
}
2013-05-06 13:07:41 -04:00
2015-12-29 01:30:20 -06:00
NPC : : SpawnZoneController ( ) ;
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, "
2021-05-10 02:21:43 -04:00
" respawntime, variance, pathgrid, "
" path_when_zone_idle, _condition, "
" cond_value, enabled, animation FROM spawn2 "
" WHERE id = %i " , spawn2id ) ;
2014-08-24 13:03:45 -07:00
auto results = QueryDatabase ( query ) ;
if ( ! results . Success ( ) ) {
return nullptr ;
}
if ( results . RowCount ( ) ! = 1 ) {
return nullptr ;
}
auto row = results . begin ( ) ;
2021-05-10 02:21:43 -04:00
bool perl_enabled = atoi ( row [ 12 ] ) = = 1 ? true : false ;
2014-08-24 13:03:45 -07:00
2021-05-10 02:21:43 -04:00
auto 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 ] ) , ( bool ) atoi ( row [ 9 ] ) , atoi ( row [ 10 ] ) ,
atoi ( row [ 11 ] ) , perl_enabled , ( EmuAppearance ) atoi ( row [ 13 ] ) ) ;
2014-08-24 13:03:45 -07:00
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
}
2015-01-23 00:01:10 -08:00
bool ZoneDatabase : : CreateSpawn2 ( Client * client , uint32 spawngroup , const char * zone , const glm : : vec4 & position , 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) " ,
2015-01-23 00:01:10 -08:00
spawngroup , zone , position . x , position . y , position . z , position . w ,
2014-08-24 13:07:15 -07:00
respawn , variance , condition , cond_value ) ;
auto results = QueryDatabase ( query ) ;
if ( ! results . Success ( ) ) {
2013-02-16 16:14:39 -08:00
return false ;
2014-08-24 13:07:15 -07:00
}
if ( results . RowsAffected ( ) ! = 1 )
return false ;
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
2019-09-02 04:10:43 -05:00
LogSpawns ( " Spawn2 [{}]: Notified that our spawn condition [{}] has changed from [{}] to [{}]. Our min value is [{}] " , 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 ) {
2019-09-02 04:10:43 -05:00
LogSpawns ( " Spawn2 [{}]: Our threshold for this condition was not crossed. Doing nothing " , spawn2_id ) ;
2013-02-16 16:14:39 -08:00
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.
2019-09-02 04:10:43 -05:00
LogSpawns ( " Spawn2 [{}]: Our condition is now [{}]. Taking no action on existing spawn " , spawn2_id , new_state ? " enabled " : " disabled " ) ;
2013-02-16 16:14:39 -08:00
break ;
case SpawnCondition : : DoDepop :
2019-09-02 04:10:43 -05:00
LogSpawns ( " Spawn2 [{}]: Our condition is now [{}]. 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 :
2019-09-02 04:10:43 -05:00
LogSpawns ( " Spawn2 [{}]: Our condition is now [{}]. 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 :
2019-09-02 04:10:43 -05:00
LogSpawns ( " Spawn2 [{}]: Our condition is now [{}]. 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 ) {
2019-09-02 04:10:43 -05:00
LogSpawns ( " Spawn2 [{}]: Our npcthis is currently not null. The zone thinks it is [{}]. 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 ( ) ) ;
2019-09-02 04:10:43 -05:00
LogSpawns ( " Spawn2 [{}]: Our condition is now [{}]. The respawn timer_remaining is [{}]. 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 {
2019-09-02 04:10:43 -05:00
LogSpawns ( " Spawn2 [{}]: Our condition is now [{}]. Not checking respawn timer " , spawn2_id , new_state ? " enabled " : " disabled " ) ;
2014-02-09 00:08:09 -06:00
}
break ;
2013-02-16 16:14:39 -08:00
default :
if ( c . on_change < SpawnCondition : : DoSignalMin ) {
2019-09-02 04:10:43 -05:00
LogSpawns ( " Spawn2 [{}]: Our condition is now [{}]. Invalid on-change action [{}] " , 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 ;
2019-09-02 04:10:43 -05:00
LogSpawns ( " Spawn2 [{}]: Our condition is now [{}]. Signaling our mob with [{}] " , 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 ) {
2019-09-02 04:10:43 -05:00
LogSpawns ( " Zone notified that spawn condition [{}] has changed from [{}] to [{}]. 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 ;
2015-05-25 23:48:11 -05:00
zone - > zone_time . GetCurrentEQTimeOfDay ( & 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 ) ;
2019-09-02 04:10:43 -05:00
LogSpawns ( " Event [{}]: Will trigger again in [{}] EQ minutes at [{}] " , cevent . id , cevent . period , t . c_str ( ) ) ;
2014-04-25 12:40:25 -07:00
//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 ( ) ) {
2019-09-02 04:10:43 -05:00
LogSpawns ( " Event [{}]: Unable to find condition [{}] to execute on " , event . id , event . condition_id ) ;
2013-02-16 16:14:39 -08:00
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 ;
2015-05-25 23:48:11 -05:00
zone - > zone_time . GetCurrentEQTimeOfDay ( & tod ) ;
2014-04-25 12:40:25 -07:00
if ( event . strict & & ( event . next . hour ! = tod . hour | | event . next . day ! = tod . day | | event . next . month ! = tod . month | | event . next . year ! = tod . year ) )
{
2019-09-02 04:10:43 -05:00
LogSpawns ( " Event [{}]: Unable to execute. Condition is strict, and event time has already passed " , event . id ) ;
2014-04-25 12:40:25 -07:00
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 ;
2019-09-02 04:10:43 -05:00
LogSpawns ( " Event [{}]: Executing. Setting condition [{}] to [{}] " , event . id , event . condition_id , event . argument ) ;
2013-02-16 16:14:39 -08:00
break ;
case SpawnEvent : : ActionAdd :
new_value + = event . argument ;
2019-09-03 23:37:57 -05:00
LogSpawns ( " Event [{}]: Executing. Adding [{}] to condition [{}], yielding [{}] " , event . id , event . argument , event . condition_id , new_value ) ;
2013-02-16 16:14:39 -08:00
break ;
case SpawnEvent : : ActionSubtract :
new_value - = event . argument ;
2019-09-03 23:37:57 -05:00
LogSpawns ( " Event [{}]: Executing. Subtracting [{}] from condition [{}], yielding [{}] " , event . id , event . argument , event . condition_id , new_value ) ;
2013-02-16 16:14:39 -08:00
break ;
case SpawnEvent : : ActionMultiply :
new_value * = event . argument ;
2019-09-03 23:37:57 -05:00
LogSpawns ( " Event [{}]: Executing. Multiplying condition [{}] by [{}], yielding [{}] " , event . id , event . condition_id , event . argument , new_value ) ;
2013-02-16 16:14:39 -08:00
break ;
case SpawnEvent : : ActionDivide :
new_value / = event . argument ;
2019-09-03 23:37:57 -05:00
LogSpawns ( " Event [{}]: Executing. Dividing condition [{}] by [{}], yielding [{}] " , event . id , event . condition_id , event . argument , new_value ) ;
2013-02-16 16:14:39 -08:00
break ;
default :
2019-09-02 04:10:43 -05:00
LogSpawns ( " Event [{}]: Invalid event action type [{}] " , event . id , event . action ) ;
2013-02-16 16:14:39 -08:00
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 ) ;
2020-04-18 23:26:53 -05:00
database . QueryDatabase ( query ) ;
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 ) ;
2020-03-30 23:25:32 -05:00
database . QueryDatabase ( query ) ;
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 ) ;
2020-04-18 23:26:53 -05:00
auto results = database . QueryDatabase ( query ) ;
2014-08-24 13:18:51 -07:00
if ( ! results . Success ( ) ) {
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 ) ;
2019-09-02 04:10:43 -05:00
LogSpawns ( " (LoadDBEvent) Loaded [{}] spawn event [{}] on condition [{}] with period [{}], action [{}], argument [{}], strict [{}]. Will trigger at [{}] " , event . enabled ? " enabled " : " disabled " , event . id , event . condition_id , event . period , event . action , event . argument , event . strict , timeAsString . c_str ( ) ) ;
2014-08-24 13:18:51 -07:00
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 ) ;
2020-03-12 00:00:39 -05:00
auto results = content_db . QueryDatabase ( query ) ;
2014-08-24 13:31:55 -07:00
if ( ! results . Success ( ) ) {
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 ;
2019-09-02 04:10:43 -05:00
LogSpawns ( " Loaded spawn condition [{}] with value [{}] and on_change [{}] " , cond . condition_id , cond . value , cond . on_change ) ;
2014-08-24 13:31:55 -07:00
}
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 ) ;
2020-03-30 21:32:59 -05:00
results = database . QueryDatabase ( query ) ;
2014-08-24 13:31:55 -07:00
if ( ! results . Success ( ) ) {
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 ) ;
2020-04-18 23:26:53 -05:00
results = database . QueryDatabase ( query ) ;
2014-08-24 13:31:55 -07:00
if ( ! results . Success ( ) ) {
return false ;
}
2013-05-06 13:07:41 -04:00
2019-09-02 04:10:43 -05:00
for ( auto row = results . begin ( ) ; row ! = results . end ( ) ; + + row ) {
SpawnEvent event ;
2013-05-06 13:07:41 -04:00
2019-09-02 04:10:43 -05: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
2019-09-01 22:05:44 -05:00
if ( event . period = = 0 ) {
LogError ( " Refusing to load spawn event #[{}] because it has a period of 0 \n " , event . id ) ;
continue ;
}
2014-08-24 13:31:55 -07:00
2019-09-02 04:10:43 -05:00
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 ) ;
LogSpawns (
" (LoadSpawnConditions) Loaded [{}] spawn event [{}] on condition [{}] with period [{}], action [{}], argument [{}], strict [{}] " ,
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 ;
2015-05-25 23:48:11 -05:00
zone - > zone_time . GetCurrentEQTimeOfDay ( & 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 ;
2019-09-02 04:10:43 -05:00
//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 ) {
LogSpawns ( " Initial next trigger time set for spawn event [{}] " , 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 ) ) {
LogSpawns ( " Catch up triggering on event [{}] " , 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
2014-08-24 13:31:55 -07:00
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
}
}
2017-04-01 03:51:46 -05:00
if ( next_id = = - 1 ) {
2019-09-02 04:10:43 -05:00
LogSpawns ( " No spawn events enabled. Disabling next event " ) ;
2017-04-01 03:51:46 -05:00
}
else {
2019-09-02 04:10:43 -05:00
LogSpawns ( " Next event determined to be event [{}] " , next_id ) ;
2017-04-01 03:51:46 -05:00
}
2013-02-16 16:14:39 -08:00
}
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 ( ) ) {
2019-09-02 04:10:43 -05:00
LogSpawns ( " Condition update received from world for [{}], but we do not have that conditon " , condition_id ) ;
2013-02-16 16:14:39 -08:00
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 ) {
2019-09-02 04:10:43 -05:00
LogSpawns ( " Condition update received from world for [{}] with value [{}], which is what we already have " , condition_id , new_value ) ;
2013-02-16 16:14:39 -08:00
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
2019-09-02 04:10:43 -05:00
LogSpawns ( " Condition update received from world for [{}] with value [{}] " , 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 ( ) ) {
2019-09-02 04:10:43 -05:00
LogSpawns ( " Local Condition update requested for [{}], but we do not have that conditon " , condition_id ) ;
2013-02-16 16:14:39 -08:00
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 ) {
2019-09-02 04:10:43 -05:00
LogSpawns ( " Local Condition update requested for [{}] with value [{}], which is what we already have " , condition_id , new_value ) ;
2013-02-16 16:14:39 -08:00
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
2019-09-02 04:10:43 -05:00
LogSpawns ( " Local Condition update requested for [{}] with value [{}] " , 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
2019-09-02 04:10:43 -05:00
LogSpawns ( " Remote spawn condition [{}] set to [{}]. 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
2016-05-25 16:10:28 -04:00
auto pack = new ServerPacket ( ServerOP_SpawnCondition , sizeof ( ServerSpawnCondition_Struct ) ) ;
2013-02-16 16:14:39 -08:00
ServerSpawnCondition_Struct * ssc = ( ServerSpawnCondition_Struct * ) pack - > pBuffer ;
2013-05-06 13:07:41 -04:00
2020-04-19 04:36:39 -05:00
ssc - > zoneID = ZoneID ( zone_short ) ;
2013-02-16 16:14:39 -08:00
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
2019-09-02 04:10:43 -05:00
LogSpawns ( " Requested to reload event [{}] 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...
2019-09-02 04:10:43 -05:00
LogSpawns ( " Failed to reload event [{}] from the database " , event_id ) ;
2013-02-16 16:14:39 -08:00
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...
2019-09-02 04:10:43 -05:00
LogSpawns ( " Failed to reload event [{}] from the database " , event_id ) ;
2013-02-16 16:14:39 -08:00
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
2019-09-02 04:10:43 -05:00
LogSpawns ( " Request to [{}] spawn event [{}] [{}]resetting 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 ) {
2019-09-02 04:10:43 -05:00
LogSpawns ( " Spawn event [{}] located in this zone. State set. Trigger time reset (period [{}]) " , event_id , cevent . period ) ;
2013-02-16 16:14:39 -08:00
//start with the time now
2015-05-25 23:48:11 -05:00
zone - > zone_time . GetCurrentEQTimeOfDay ( & cevent . next ) ;
2013-02-16 16:14:39 -08:00
//advance the next time by our period
EQTime : : AddMinutes ( cevent . period , & cevent . next ) ;
} else {
2019-09-02 04:10:43 -05:00
LogSpawns ( " Spawn event [{}] located in this zone. State changed " , event_id ) ;
2013-02-16 16:14:39 -08:00
}
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 {
2019-09-02 04:10:43 -05:00
LogSpawns ( " Spawn event [{}] located in this zone but no change was needed " , event_id ) ;
2013-02-16 16:14:39 -08:00
}
//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 ) ) {
2019-09-02 04:10:43 -05:00
LogSpawns ( " Unable to find spawn event [{}] in the database " , event_id ) ;
2013-02-16 16:14:39 -08:00
//unable to find the event in the database...
return ;
}
if ( e . enabled = = enabled & & ! reset_base ) {
2019-09-02 04:10:43 -05:00
LogSpawns ( " Spawn event [{}] is not located in this zone but no change was needed " , event_id ) ;
2013-02-16 16:14:39 -08:00
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 ) {
2019-09-02 04:10:43 -05:00
LogSpawns ( " Spawn event [{}] is in zone [{}]. State set. Trigger time reset (period [{}]). Notifying world " , event_id , zone_short_name . c_str ( ) , e . period ) ;
2013-02-16 16:14:39 -08:00
//start with the time now
2015-05-25 23:48:11 -05:00
zone - > zone_time . GetCurrentEQTimeOfDay ( & e . next ) ;
2013-02-16 16:14:39 -08:00
//advance the next time by our period
EQTime : : AddMinutes ( e . period , & e . next ) ;
} else {
2019-09-02 04:10:43 -05:00
LogSpawns ( " Spawn event [{}] is in zone [{}]. 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
2016-05-25 16:10:28 -04:00
auto pack = new ServerPacket ( ServerOP_SpawnEvent , sizeof ( ServerSpawnEvent_Struct ) ) ;
2013-02-16 16:14:39 -08:00
ServerSpawnEvent_Struct * sse = ( ServerSpawnEvent_Struct * ) pack - > pBuffer ;
2013-05-06 13:07:41 -04:00
2020-04-19 04:36:39 -05:00
sse - > zoneID = ZoneID ( zone_short_name . c_str ( ) ) ;
2013-02-16 16:14:39 -08:00
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
{
2019-09-02 04:10:43 -05:00
LogSpawns ( " Unable to find local condition [{}] in Get request " , condition_id ) ;
2013-02-16 16:14:39 -08:00
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
2019-09-02 04:10:43 -05:00
//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
) ;
2020-03-30 23:25:32 -05:00
auto results = database . QueryDatabase ( query ) ;
2019-09-02 04:10:43 -05:00
if ( ! results . Success ( ) ) {
LogSpawns ( " Unable to query remote condition [{}] from zone [{}] in Get request " , condition_id , zone_short ) ;
return 0 ; //dunno a better thing to do...
}
2014-08-24 13:47:18 -07:00
2019-09-02 04:10:43 -05:00
if ( results . RowCount ( ) = = 0 ) {
LogSpawns ( " Unable to load remote condition [{}] from zone [{}] in Get request " , condition_id , zone_short ) ;
return 0 ; //dunno a better thing to do...
}
2014-08-24 13:47:18 -07:00
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 ) ;
}