From ded82ac6d666b9ac5aba9b4e4b33ab7987c69710 Mon Sep 17 00:00:00 2001 From: regneq Date: Sat, 18 Nov 2023 12:23:04 -0800 Subject: [PATCH] =?UTF-8?q?[Spawn]=20(imported=20from=20takp)=20Added=20mi?= =?UTF-8?q?n=5Ftime=20and=20max=5Ftime=20to=20spawnentry.=20This=20will=20?= =?UTF-8?q?prevent=20a=20NPC=20from=E2=80=A6=20(#3685)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Added mintime and maxtime to spawnentry. This will prevent a NPC from spawning outside of the times specified. NPCs spawned in this way will then behave like normal NPCs. They will not despawn on their own, unlike spawn_events/spawn_conditions. NPCs using this that are alone in their spawngroup will attempt to spawn after their respawn timer has expired if the time of day is outside their range. Otherwise, another NPC in the spawngroup will be chosen to spawn. The normal rules (chance, spawn_limit) still apply to these NPCs, this is just another rule added to the system. mintime and maxtime both represent the in-game EQ Hour. Valid values are 1-24. If either or both of the values are 0, then the NPC will not have any time restriction. Added a new rule World:BootHour. This allows server admins to specify the EQ hour the server will boot to. Valid options are 1-24. Setting this rule to 0 (default) disables it and world will use whatever time is specified in the DB. * generated base_spawnentry_repository.h from script * removed the rule insert from database_update_manifest.cpp. * Add logging, initializers, minor cleanup * Remove if/else branch * Update eqtime.cpp * Initializers, logging --------- Co-authored-by: Akkadius --- common/database.cpp | 50 ++++++++++------- common/database/database_update_manifest.cpp | 13 ++++- common/eqemu_logsys.cpp | 2 + common/eqemu_logsys.h | 2 + common/eqemu_logsys_log_aliases.h | 10 ++++ common/eqtime.cpp | 40 ++++++++++--- common/eqtime.h | 1 + .../base/base_spawnentry_repository.h | 56 +++++++++++++------ common/ruletypes.h | 1 + common/version.h | 2 +- world/main.cpp | 21 +++++-- zone/embparser.cpp | 2 +- zone/gm_commands/set/date.cpp | 8 +-- zone/gm_commands/set/time.cpp | 2 +- zone/lua_general.cpp | 2 +- zone/spawn2.cpp | 6 +- zone/spawngroup.cpp | 36 +++++++++--- zone/spawngroup.h | 4 +- zone/worldserver.cpp | 2 +- 19 files changed, 184 insertions(+), 76 deletions(-) diff --git a/common/database.cpp b/common/database.cpp index 738fc0d82..e9fb58dac 100644 --- a/common/database.cpp +++ b/common/database.cpp @@ -2097,37 +2097,45 @@ void Database::ClearInvSnapshots(bool from_now) { struct TimeOfDay_Struct Database::LoadTime(time_t &realtime) { - - TimeOfDay_Struct eqTime; - std::string query = StringFormat("SELECT minute,hour,day,month,year,realtime FROM eqtime limit 1"); + TimeOfDay_Struct t{}; + std::string query = StringFormat("SELECT minute,hour,day,month,year,realtime FROM eqtime limit 1"); auto results = QueryDatabase(query); - if (!results.Success() || results.RowCount() == 0){ + if (!results.Success() || results.RowCount() == 0) { LogInfo("Loading EQ time of day failed. Using defaults"); - eqTime.minute = 0; - eqTime.hour = 9; - eqTime.day = 1; - eqTime.month = 1; - eqTime.year = 3100; + t.minute = 0; + t.hour = 9; + t.day = 1; + t.month = 1; + t.year = 3100; realtime = time(nullptr); - } - else{ - auto row = results.begin(); - - eqTime.minute = Strings::ToUnsignedInt(row[0]); - eqTime.hour = Strings::ToUnsignedInt(row[1]); - eqTime.day = Strings::ToUnsignedInt(row[2]); - eqTime.month = Strings::ToUnsignedInt(row[3]); - eqTime.year = Strings::ToUnsignedInt(row[4]); - realtime = Strings::ToBigInt(row[5]); + return t; } - return eqTime; + auto row = results.begin(); + + uint8 hour = Strings::ToUnsignedInt(row[1]); + time_t realtime_ = Strings::ToBigInt(row[5]); + if (RuleI(World, BootHour) > 0 && RuleI(World, BootHour) <= 24) { + hour = RuleI(World, BootHour); + realtime_ = time(nullptr); + } + + t.minute = Strings::ToUnsignedInt(row[0]); + t.hour = hour; + t.day = Strings::ToUnsignedInt(row[2]); + t.month = Strings::ToUnsignedInt(row[3]); + t.year = Strings::ToUnsignedInt(row[4]); + realtime = realtime_; + + LogEqTime("Setting hour to [{}]", hour); + + return t; } bool Database::SaveTime(int8 minute, int8 hour, int8 day, int8 month, int16 year) { - std::string query = StringFormat("UPDATE eqtime set minute = %d, hour = %d, day = %d, month = %d, year = %d, realtime = %d limit 1", minute, hour, day, month, year, time(0)); + std::string query = StringFormat("UPDATE eqtime set minute = %d, hour = %d, day = %d, month = %d, year = %d, realtime = %d limit 1", minute, hour, day, month, year, time(nullptr)); auto results = QueryDatabase(query); return results.Success(); diff --git a/common/database/database_update_manifest.cpp b/common/database/database_update_manifest.cpp index 1787337a0..6121515a6 100644 --- a/common/database/database_update_manifest.cpp +++ b/common/database/database_update_manifest.cpp @@ -5018,7 +5018,18 @@ INSERT INTO spawn2_disabled (spawn2_id, disabled) SELECT id, 1 FROM spawn2 WHERE ALTER TABLE `spawn2` DROP COLUMN `enabled`; )" }, - + ManifestEntry{ + .version = 9242, + .description = "2023_11_7_mintime_maxtime_spawnentry.sql", + .check = "SHOW COLUMNS FROM `spawnentry` LIKE 'min_time'", + .condition = "empty", + .match = "", + .sql = R"( +ALTER TABLE `spawnentry` +ADD COLUMN `min_time` smallint(4) NOT NULL DEFAULT 0 AFTER `condition_value_filter`, +ADD COLUMN `max_time` smallint(4) NOT NULL DEFAULT 0 AFTER `min_time`; +)" + }, // -- template; copy/paste this when you need to create a new entry // ManifestEntry{ // .version = 9228, diff --git a/common/eqemu_logsys.cpp b/common/eqemu_logsys.cpp index df6508daf..3509baa7b 100644 --- a/common/eqemu_logsys.cpp +++ b/common/eqemu_logsys.cpp @@ -100,6 +100,8 @@ EQEmuLogSys *EQEmuLogSys::LoadLogSettingsDefaults() log_settings[Logs::Discord].log_to_console = static_cast(Logs::General); log_settings[Logs::QuestErrors].log_to_gmsay = static_cast(Logs::General); log_settings[Logs::QuestErrors].log_to_console = static_cast(Logs::General); + log_settings[Logs::EqTime].log_to_console = static_cast(Logs::General); + log_settings[Logs::EqTime].log_to_gmsay = static_cast(Logs::General); /** * RFC 5424 diff --git a/common/eqemu_logsys.h b/common/eqemu_logsys.h index cbbbd1e6f..d158fbc36 100644 --- a/common/eqemu_logsys.h +++ b/common/eqemu_logsys.h @@ -139,6 +139,7 @@ namespace Logs { PlayerEvents, DataBuckets, Zoning, + EqTime, MaxCategoryID /* Don't Remove this */ }; @@ -237,6 +238,7 @@ namespace Logs { "PlayerEvents", "DataBuckets", "Zoning", + "EqTime", }; } diff --git a/common/eqemu_logsys_log_aliases.h b/common/eqemu_logsys_log_aliases.h index 07b031c9c..b4c90bbbb 100644 --- a/common/eqemu_logsys_log_aliases.h +++ b/common/eqemu_logsys_log_aliases.h @@ -814,6 +814,16 @@ OutF(LogSys, Logs::Detail, Logs::Zoning, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\ } while (0) +#define LogEqTime(message, ...) do {\ + if (LogSys.IsLogEnabled(Logs::General, Logs::EqTime))\ + OutF(LogSys, Logs::General, Logs::EqTime, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\ +} while (0) + +#define LogEqTimeDetail(message, ...) do {\ + if (LogSys.IsLogEnabled(Logs::Detail, Logs::EqTime))\ + OutF(LogSys, Logs::Detail, Logs::EqTime, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\ +} while (0) + #define Log(debug_level, log_category, message, ...) do {\ if (LogSys.IsLogEnabled(debug_level, log_category))\ LogSys.Out(debug_level, log_category, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\ diff --git a/common/eqtime.cpp b/common/eqtime.cpp index 49d5f32c3..1478dafd8 100644 --- a/common/eqtime.cpp +++ b/common/eqtime.cpp @@ -46,16 +46,16 @@ EQTime::EQTime() timezone = 0; memset(&eqTime, 0, sizeof(eqTime)); //Defaults for time - TimeOfDay_Struct start; - start.day = 1; - start.hour = 9; - start.minute = 0; - start.month = 1; - start.year = 3100; + TimeOfDay_Struct t{}; + t.day = 1; + t.hour = 9; + t.minute = 0; + t.month = 1; + t.year = 3100; //Set default time zone timezone = 0; //Start EQTimer - SetCurrentEQTimeOfDay(start, time(0)); + SetCurrentEQTimeOfDay(t, time(nullptr)); } //getEQTimeOfDay - Reads timeConvert and writes the result to eqTimeOfDay @@ -202,7 +202,7 @@ void EQTime::ToString(TimeOfDay_Struct *t, std::string &str) { } bool EQTime::IsDayTime() { - TimeOfDay_Struct tod; //Day time is 5am to 6:59pm (14 hours in-game) + TimeOfDay_Struct tod{}; //Day time is 5am to 6:59pm (14 hours in-game) GetCurrentEQTimeOfDay(&tod); //TODO: what if it fails and returns zero? if (tod.hour >= 5 || tod.hour < 19) { @@ -213,7 +213,7 @@ bool EQTime::IsDayTime() { } bool EQTime::IsNightTime() { - TimeOfDay_Struct tod; //Night time is 7pm to 4:59am (10 hours in-game) + TimeOfDay_Struct tod{}; //Night time is 7pm to 4:59am (10 hours in-game) GetCurrentEQTimeOfDay(&tod); //TODO: what if it fails and returns zero? if (tod.hour >= 19 || tod.hour < 5) { @@ -222,3 +222,25 @@ bool EQTime::IsNightTime() { return false; } + +bool EQTime::IsInbetweenTime(uint8 min_time, uint8 max_time) { + TimeOfDay_Struct tod{}; + GetCurrentEQTimeOfDay(&tod); + + if (min_time == 0 || max_time == 0 || min_time > 24 || max_time > 24) { + return true; + } + + if (max_time < min_time) { + if ((tod.hour >= min_time && tod.hour > max_time) || (tod.hour < min_time && tod.hour <= max_time)) { + return true; + } + } + else { + if (tod.hour >= min_time && tod.hour <= max_time) { + return true; + } + } + + return false; +} diff --git a/common/eqtime.h b/common/eqtime.h index c55689a0f..f79d274f8 100644 --- a/common/eqtime.h +++ b/common/eqtime.h @@ -30,6 +30,7 @@ public: uint32 getEQTimeZoneMin() { return timezone%60; } bool IsDayTime(); bool IsNightTime(); + bool IsInbetweenTime(uint8 min_time, uint8 max_time); //Set functions int SetCurrentEQTimeOfDay(TimeOfDay_Struct start_eq, time_t start_real); diff --git a/common/repositories/base/base_spawnentry_repository.h b/common/repositories/base/base_spawnentry_repository.h index 1632a4c79..99f6c2ae0 100644 --- a/common/repositories/base/base_spawnentry_repository.h +++ b/common/repositories/base/base_spawnentry_repository.h @@ -16,6 +16,7 @@ #include "../../strings.h" #include + class BaseSpawnentryRepository { public: struct Spawnentry { @@ -23,6 +24,8 @@ public: int32_t npcID; int16_t chance; int32_t condition_value_filter; + int16_t min_time; + int16_t max_time; int8_t min_expansion; int8_t max_expansion; std::string content_flags; @@ -41,6 +44,8 @@ public: "npcID", "chance", "condition_value_filter", + "min_time", + "max_time", "min_expansion", "max_expansion", "content_flags", @@ -55,6 +60,8 @@ public: "npcID", "chance", "condition_value_filter", + "min_time", + "max_time", "min_expansion", "max_expansion", "content_flags", @@ -103,6 +110,8 @@ public: e.npcID = 0; e.chance = 0; e.condition_value_filter = 1; + e.min_time = 0; + e.max_time = 0; e.min_expansion = -1; e.max_expansion = -1; e.content_flags = ""; @@ -132,8 +141,9 @@ public: { auto results = db.QueryDatabase( fmt::format( - "{} WHERE id = {} LIMIT 1", + "{} WHERE {} = {} LIMIT 1", BaseSelect(), + PrimaryKey(), spawnentry_id ) ); @@ -146,10 +156,12 @@ public: e.npcID = static_cast(atoi(row[1])); e.chance = static_cast(atoi(row[2])); e.condition_value_filter = static_cast(atoi(row[3])); - e.min_expansion = static_cast(atoi(row[4])); - e.max_expansion = static_cast(atoi(row[5])); - e.content_flags = row[6] ? row[6] : ""; - e.content_flags_disabled = row[7] ? row[7] : ""; + e.min_time = static_cast(atoi(row[4])); + e.max_time = static_cast(atoi(row[5])); + e.min_expansion = static_cast(atoi(row[6])); + e.max_expansion = static_cast(atoi(row[7])); + e.content_flags = row[8] ? row[8] : ""; + e.content_flags_disabled = row[9] ? row[9] : ""; return e; } @@ -187,10 +199,12 @@ public: v.push_back(columns[1] + " = " + std::to_string(e.npcID)); v.push_back(columns[2] + " = " + std::to_string(e.chance)); v.push_back(columns[3] + " = " + std::to_string(e.condition_value_filter)); - v.push_back(columns[4] + " = " + std::to_string(e.min_expansion)); - v.push_back(columns[5] + " = " + std::to_string(e.max_expansion)); - v.push_back(columns[6] + " = '" + Strings::Escape(e.content_flags) + "'"); - v.push_back(columns[7] + " = '" + Strings::Escape(e.content_flags_disabled) + "'"); + v.push_back(columns[4] + " = " + std::to_string(e.min_time)); + v.push_back(columns[5] + " = " + std::to_string(e.max_time)); + v.push_back(columns[6] + " = " + std::to_string(e.min_expansion)); + v.push_back(columns[7] + " = " + std::to_string(e.max_expansion)); + v.push_back(columns[8] + " = '" + Strings::Escape(e.content_flags) + "'"); + v.push_back(columns[9] + " = '" + Strings::Escape(e.content_flags_disabled) + "'"); auto results = db.QueryDatabase( fmt::format( @@ -216,6 +230,8 @@ public: v.push_back(std::to_string(e.npcID)); v.push_back(std::to_string(e.chance)); v.push_back(std::to_string(e.condition_value_filter)); + v.push_back(std::to_string(e.min_time)); + v.push_back(std::to_string(e.max_time)); v.push_back(std::to_string(e.min_expansion)); v.push_back(std::to_string(e.max_expansion)); v.push_back("'" + Strings::Escape(e.content_flags) + "'"); @@ -253,6 +269,8 @@ public: v.push_back(std::to_string(e.npcID)); v.push_back(std::to_string(e.chance)); v.push_back(std::to_string(e.condition_value_filter)); + v.push_back(std::to_string(e.min_time)); + v.push_back(std::to_string(e.max_time)); v.push_back(std::to_string(e.min_expansion)); v.push_back(std::to_string(e.max_expansion)); v.push_back("'" + Strings::Escape(e.content_flags) + "'"); @@ -294,10 +312,12 @@ public: e.npcID = static_cast(atoi(row[1])); e.chance = static_cast(atoi(row[2])); e.condition_value_filter = static_cast(atoi(row[3])); - e.min_expansion = static_cast(atoi(row[4])); - e.max_expansion = static_cast(atoi(row[5])); - e.content_flags = row[6] ? row[6] : ""; - e.content_flags_disabled = row[7] ? row[7] : ""; + e.min_time = static_cast(atoi(row[4])); + e.max_time = static_cast(atoi(row[5])); + e.min_expansion = static_cast(atoi(row[6])); + e.max_expansion = static_cast(atoi(row[7])); + e.content_flags = row[8] ? row[8] : ""; + e.content_flags_disabled = row[9] ? row[9] : ""; all_entries.push_back(e); } @@ -326,10 +346,12 @@ public: e.npcID = static_cast(atoi(row[1])); e.chance = static_cast(atoi(row[2])); e.condition_value_filter = static_cast(atoi(row[3])); - e.min_expansion = static_cast(atoi(row[4])); - e.max_expansion = static_cast(atoi(row[5])); - e.content_flags = row[6] ? row[6] : ""; - e.content_flags_disabled = row[7] ? row[7] : ""; + e.min_time = static_cast(atoi(row[4])); + e.max_time = static_cast(atoi(row[5])); + e.min_expansion = static_cast(atoi(row[6])); + e.max_expansion = static_cast(atoi(row[7])); + e.content_flags = row[8] ? row[8] : ""; + e.content_flags_disabled = row[9] ? row[9] : ""; all_entries.push_back(e); } diff --git a/common/ruletypes.h b/common/ruletypes.h index 05e4ffbd6..179a12c21 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -303,6 +303,7 @@ RULE_BOOL(World, EnforceCharacterLimitAtLogin, false, "Enforce the limit for cha RULE_BOOL(World, EnableDevTools, true, "Enable or Disable the Developer Tools globally (Most of the time you want this enabled)") RULE_BOOL(World, EnableChecksumVerification, false, "Enable or Disable the Checksum Verification for eqgame.exe and spells_us.txt") RULE_INT(World, MaximumQuestErrors, 30, "Changes the maximum number of quest errors that can be displayed in #questerrors, default is 30") +RULE_INT(World, BootHour, 0, "Sets the in-game hour world will set when it first boots. 0-24 are valid options, where 0 disables this rule") RULE_CATEGORY_END() RULE_CATEGORY(Zone) diff --git a/common/version.h b/common/version.h index 79417407f..ac979a1a7 100644 --- a/common/version.h +++ b/common/version.h @@ -42,7 +42,7 @@ * Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt */ -#define CURRENT_BINARY_DATABASE_VERSION 9241 +#define CURRENT_BINARY_DATABASE_VERSION 9242 #define CURRENT_BINARY_BOTS_DATABASE_VERSION 9040 diff --git a/world/main.cpp b/world/main.cpp index a01c57ed1..4ad11a356 100644 --- a/world/main.cpp +++ b/world/main.cpp @@ -424,12 +424,21 @@ int main(int argc, char **argv) } if (EQTimeTimer.Check()) { - TimeOfDay_Struct tod; - zoneserver_list.worldclock.GetCurrentEQTimeOfDay(time(0), &tod); - if (!database.SaveTime(tod.minute, tod.hour, tod.day, tod.month, tod.year)) - LogError("Failed to save eqtime"); - else - LogDebug("EQTime successfully saved"); + TimeOfDay_Struct tod{}; + zoneserver_list.worldclock.GetCurrentEQTimeOfDay(time(nullptr), &tod); + if (!database.SaveTime(tod.minute, tod.hour, tod.day, tod.month, tod.year)) { + LogEqTime("Failed to save eqtime"); + } + else { + LogEqTime( + "EQTime successfully saved - time is now [{}:{}:{}:{}:{}]", + tod.year, + tod.month, + tod.day, + tod.hour, + tod.minute + ); + } } zoneserver_list.Process(); diff --git a/zone/embparser.cpp b/zone/embparser.cpp index b64c8d8f8..299810bd4 100644 --- a/zone/embparser.cpp +++ b/zone/embparser.cpp @@ -1440,7 +1440,7 @@ void PerlembParser::ExportZoneVariables(std::string &package_name) ExportVar(package_name.c_str(), "zonesn", zone->GetShortName()); ExportVar(package_name.c_str(), "instanceid", zone->GetInstanceID()); ExportVar(package_name.c_str(), "instanceversion", zone->GetInstanceVersion()); - TimeOfDay_Struct eqTime; + TimeOfDay_Struct eqTime{}; zone->zone_time.GetCurrentEQTimeOfDay(time(0), &eqTime); ExportVar(package_name.c_str(), "zonehour", eqTime.hour - 1); ExportVar(package_name.c_str(), "zonemin", eqTime.minute); diff --git a/zone/gm_commands/set/date.cpp b/zone/gm_commands/set/date.cpp index cac21e061..5531db20d 100755 --- a/zone/gm_commands/set/date.cpp +++ b/zone/gm_commands/set/date.cpp @@ -14,14 +14,14 @@ void SetDate(Client *c, const Seperator *sep) return; } - TimeOfDay_Struct eq_time; - zone->zone_time.GetCurrentEQTimeOfDay(time(0), &eq_time); + TimeOfDay_Struct t{}; + zone->zone_time.GetCurrentEQTimeOfDay(time(0), &t); const uint16 year = Strings::ToUnsignedInt(sep->arg[2]); const uint8 month = Strings::ToUnsignedInt(sep->arg[3]); const uint8 day = Strings::ToUnsignedInt(sep->arg[4]); - const uint8 hour = !sep->IsNumber(5) ? eq_time.hour : Strings::ToUnsignedInt(sep->arg[5]) + 1; - const uint8 minute = !sep->IsNumber(6) ? eq_time.minute : Strings::ToUnsignedInt(sep->arg[6]); + const uint8 hour = !sep->IsNumber(5) ? t.hour : Strings::ToUnsignedInt(sep->arg[5]) + 1; + const uint8 minute = !sep->IsNumber(6) ? t.minute : Strings::ToUnsignedInt(sep->arg[6]); c->Message( Chat::White, diff --git a/zone/gm_commands/set/time.cpp b/zone/gm_commands/set/time.cpp index 6cd3ab57b..228a69fcd 100755 --- a/zone/gm_commands/set/time.cpp +++ b/zone/gm_commands/set/time.cpp @@ -6,7 +6,7 @@ void SetTime(Client *c, const Seperator *sep) if (arguments < 2 || !sep->IsNumber(2)) { c->Message(Chat::White, "Usage: #set time [Hour] [Minute]"); - TimeOfDay_Struct world_time; + TimeOfDay_Struct world_time{}; zone->zone_time.GetCurrentEQTimeOfDay(time(0), &world_time); auto time_string = fmt::format( diff --git a/zone/lua_general.cpp b/zone/lua_general.cpp index 3604c146f..616376dcd 100644 --- a/zone/lua_general.cpp +++ b/zone/lua_general.cpp @@ -1273,7 +1273,7 @@ int lua_get_zone_weather() { } luabind::adl::object lua_get_zone_time(lua_State *L) { - TimeOfDay_Struct eqTime; + TimeOfDay_Struct eqTime{}; zone->zone_time.GetCurrentEQTimeOfDay(time(0), &eqTime); luabind::adl::object ret = luabind::newtable(L); diff --git a/zone/spawn2.cpp b/zone/spawn2.cpp index efb435c1d..7985cf42a 100644 --- a/zone/spawn2.cpp +++ b/zone/spawn2.cpp @@ -692,7 +692,7 @@ void SpawnConditionManager::Process() { //check each spawn event. //get our current time - TimeOfDay_Struct tod; + TimeOfDay_Struct tod{}; zone->zone_time.GetCurrentEQTimeOfDay(&tod); //see if time is past our nearest event. @@ -745,7 +745,7 @@ void SpawnConditionManager::ExecEvent(SpawnEvent &event, bool send_update) { return; //unable to find the spawn condition to operate on } - TimeOfDay_Struct tod; + TimeOfDay_Struct tod{}; zone->zone_time.GetCurrentEQTimeOfDay(&tod); if(event.strict && (event.next.hour != tod.hour || event.next.day != tod.day || event.next.month != tod.month || event.next.year != tod.year)) { @@ -956,7 +956,7 @@ bool SpawnConditionManager::LoadSpawnConditions(const char* zone_name, uint32 in //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; + TimeOfDay_Struct tod{}; zone->zone_time.GetCurrentEQTimeOfDay(&tod); for(auto cur = spawn_events.begin(); cur != spawn_events.end(); ++cur) { diff --git a/zone/spawngroup.cpp b/zone/spawngroup.cpp index a25fbedfc..acf03f071 100644 --- a/zone/spawngroup.cpp +++ b/zone/spawngroup.cpp @@ -29,12 +29,13 @@ extern EntityList entity_list; extern Zone *zone; -SpawnEntry::SpawnEntry(uint32 in_NPCType, int in_chance, uint16 in_filter, uint8 in_npc_spawn_limit) -{ +SpawnEntry::SpawnEntry(uint32 in_NPCType, int in_chance, uint16 in_filter, uint8 in_npc_spawn_limit, uint8 in_min_time, uint8 in_max_time) { NPCType = in_NPCType; chance = in_chance; condition_value_filter = in_filter; npc_spawn_limit = in_npc_spawn_limit; + min_time = in_min_time; + max_time = in_max_time; } SpawnGroup::SpawnGroup( @@ -85,8 +86,15 @@ uint32 SpawnGroup::GetNPCType(uint16 in_filter) continue; } - if (se->condition_value_filter != in_filter) + if (se->min_time != 0 && se->max_time != 0 && se->min_time <= 24 && se->max_time <= 24) { + if (!zone->zone_time.IsInbetweenTime(se->min_time, se->max_time)) { + continue; + } + } + + if (se->condition_value_filter != in_filter) { continue; + } totalchance += se->chance; possible.push_back(se); @@ -224,7 +232,9 @@ bool ZoneDatabase::LoadSpawnGroups(const char *zone_name, uint16 version, SpawnG chance, condition_value_filter, npc_types.spawn_limit - AS sl + AS sl, + min_time, + max_time FROM spawnentry, spawn2, @@ -251,7 +261,9 @@ bool ZoneDatabase::LoadSpawnGroups(const char *zone_name, uint16 version, SpawnG Strings::ToInt(row[1]), Strings::ToInt(row[2]), Strings::ToInt(row[3]), - (row[4] ? Strings::ToInt(row[4]) : 0) + (row[4] ? Strings::ToInt(row[4]) : 0), + Strings::ToInt(row[5]), + Strings::ToInt(row[6]) ); SpawnGroup *spawn_group = spawn_group_list->GetSpawnGroup(Strings::ToInt(row[0])); @@ -340,7 +352,9 @@ bool ZoneDatabase::LoadSpawnGroupsByID(int spawn_group_id, SpawnGroupList *spawn spawnentry.npcid, spawnentry.chance, spawnentry.condition_value_filter, - spawngroup.spawn_limit + spawngroup.spawn_limit, + spawnentry.min_time, + spawnentry.max_time FROM spawnentry, spawngroup @@ -361,16 +375,20 @@ bool ZoneDatabase::LoadSpawnGroupsByID(int spawn_group_id, SpawnGroupList *spawn Strings::ToInt(row[1]), Strings::ToInt(row[2]), Strings::ToInt(row[3]), - (row[4] ? Strings::ToInt(row[4]) : 0) + (row[4] ? Strings::ToInt(row[4]) : 0), + Strings::ToInt(row[5]), + Strings::ToInt(row[6]) ); LogSpawnsDetail( - "Loading spawn_entry spawn_group_id [{}] npc_id [{}] chance [{}] condition_value_filter [{}] spawn_limit [{}]", + "Loading spawn_entry spawn_group_id [{}] npc_id [{}] chance [{}] condition_value_filter [{}] spawn_limit [{}] min_time [{}] max_time [{}] ", row[0], row[1], row[2], row[3], - row[4] + row[4], + row[5], + row[6] ); SpawnGroup *spawn_group = spawn_group_list->GetSpawnGroup(Strings::ToInt(row[0])); diff --git a/zone/spawngroup.h b/zone/spawngroup.h index f5cf437df..9fee72996 100644 --- a/zone/spawngroup.h +++ b/zone/spawngroup.h @@ -26,10 +26,12 @@ class SpawnEntry { public: - SpawnEntry(uint32 in_NPCType, int in_chance, uint16 in_filter, uint8 in_npc_spawn_limit); + SpawnEntry(uint32 in_NPCType, int in_chance, uint16 in_filter, uint8 in_npc_spawn_limit, uint8 in_min_time, uint8 in_max_time); ~SpawnEntry() {} uint32 NPCType; int chance; + uint8 min_time; + uint8 max_time; uint16 condition_value_filter; //this is a cached value from npc_types, for speed diff --git a/zone/worldserver.cpp b/zone/worldserver.cpp index e1bc27cbe..290cf1a17 100644 --- a/zone/worldserver.cpp +++ b/zone/worldserver.cpp @@ -965,7 +965,7 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) char time_message[255]; time_t current_time = time(nullptr); - TimeOfDay_Struct eq_time; + TimeOfDay_Struct eq_time{}; zone->zone_time.GetCurrentEQTimeOfDay(current_time, &eq_time); sprintf(time_message, "EQTime [%02d:%s%d %s]",