From 84643ce9a15d4bafde69dd29e48d5a497cad3838 Mon Sep 17 00:00:00 2001 From: Uleat Date: Mon, 22 Oct 2018 22:27:05 -0400 Subject: [PATCH 01/27] Inventory update work-around [ci skip] --- utils/sql/db_update_manifest.txt | 4 +- .../required/2018_08_13_inventory_update.sql | 63 +++++++++++++++++++ .../2018_08_13_inventory_version_update.sql | 60 ------------------ 3 files changed, 65 insertions(+), 62 deletions(-) diff --git a/utils/sql/db_update_manifest.txt b/utils/sql/db_update_manifest.txt index dae319641..587839291 100644 --- a/utils/sql/db_update_manifest.txt +++ b/utils/sql/db_update_manifest.txt @@ -381,8 +381,8 @@ 9125|2018_07_20_task_emote.sql|SHOW COLUMNS FROM `tasks` LIKE 'completion_emote'|empty| 9126|2018_09_07_FastRegen.sql|SHOW COLUMNS FROM `zone` LIKE 'fast_regen_hp'|empty| 9127|2018_09_07_NPCMaxAggroDist.sql|SHOW COLUMNS FROM `zone` LIKE 'npc_max_aggro_dist'|empty| -9128|2018_08_13_inventory_version_update.sql|SHOW TABLES LIKE 'inventory_versions'|empty| -9129|2018_08_13_inventory_update.sql|SELECT * FROM `inventory_versions` WHERE `version` = 2 and `step` = 0|not_empty| +9128|2018_08_13_inventory_version_update.sql|SHOW TABLES LIKE 'inventory_version'|not_empty| +9129|2018_08_13_inventory_update.sql|SHOW TABLES LIKE 'inventory_versions'|empty| # Upgrade conditions: # This won't be needed after this system is implemented, but it is used database that are not diff --git a/utils/sql/git/required/2018_08_13_inventory_update.sql b/utils/sql/git/required/2018_08_13_inventory_update.sql index e02bc3ae0..4aeee6806 100644 --- a/utils/sql/git/required/2018_08_13_inventory_update.sql +++ b/utils/sql/git/required/2018_08_13_inventory_update.sql @@ -1,3 +1,66 @@ +DROP TABLE IF EXISTS `inventory_versions`; +DROP TABLE IF EXISTS `inventory_snapshots`; + + +CREATE TABLE `inventory_versions` ( + `version` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `step` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `bot_step` INT(11) UNSIGNED NOT NULL DEFAULT '0' +) +COLLATE='latin1_swedish_ci' +ENGINE=MyISAM; + +INSERT INTO `inventory_versions` VALUES (2, 0, 0); + + +CREATE TABLE `inventory_snapshots` ( + `time_index` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `charid` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `slotid` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', + `itemid` INT(11) UNSIGNED NULL DEFAULT '0', + `charges` SMALLINT(3) UNSIGNED NULL DEFAULT '0', + `color` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `augslot1` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', + `augslot2` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', + `augslot3` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', + `augslot4` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', + `augslot5` MEDIUMINT(7) UNSIGNED NULL DEFAULT '0', + `augslot6` MEDIUMINT(7) NOT NULL DEFAULT '0', + `instnodrop` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0', + `custom_data` TEXT NULL, + `ornamenticon` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `ornamentidfile` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `ornament_hero_model` INT(11) NOT NULL DEFAULT '0', + PRIMARY KEY (`time_index`, `charid`, `slotid`) +) +COLLATE='latin1_swedish_ci' +ENGINE=InnoDB; + + +CREATE TABLE `inventory_snapshots_v1_bak` ( + `time_index` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `charid` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `slotid` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', + `itemid` INT(11) UNSIGNED NULL DEFAULT '0', + `charges` SMALLINT(3) UNSIGNED NULL DEFAULT '0', + `color` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `augslot1` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', + `augslot2` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', + `augslot3` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', + `augslot4` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', + `augslot5` MEDIUMINT(7) UNSIGNED NULL DEFAULT '0', + `augslot6` MEDIUMINT(7) NOT NULL DEFAULT '0', + `instnodrop` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0', + `custom_data` TEXT NULL, + `ornamenticon` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `ornamentidfile` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `ornament_hero_model` INT(11) NOT NULL DEFAULT '0', + PRIMARY KEY (`time_index`, `charid`, `slotid`) +) +COLLATE='latin1_swedish_ci' +ENGINE=InnoDB; + + -- create inventory v1 backup SELECT @pre_timestamp := UNIX_TIMESTAMP(NOW()); INSERT INTO `inventory_snapshots_v1_bak` diff --git a/utils/sql/git/required/2018_08_13_inventory_version_update.sql b/utils/sql/git/required/2018_08_13_inventory_version_update.sql index f8fc33162..942544544 100644 --- a/utils/sql/git/required/2018_08_13_inventory_version_update.sql +++ b/utils/sql/git/required/2018_08_13_inventory_version_update.sql @@ -1,61 +1 @@ DROP TABLE IF EXISTS `inventory_version`; -DROP TABLE IF EXISTS `inventory_snapshots`; - - -CREATE TABLE `inventory_versions` ( - `version` INT(11) UNSIGNED NOT NULL DEFAULT '0', - `step` INT(11) UNSIGNED NOT NULL DEFAULT '0', - `bot_step` INT(11) UNSIGNED NOT NULL DEFAULT '0' -) -COLLATE='latin1_swedish_ci' -ENGINE=MyISAM; - -INSERT INTO `inventory_versions` VALUES (2, 0, 0); - - -CREATE TABLE `inventory_snapshots` ( - `time_index` INT(11) UNSIGNED NOT NULL DEFAULT '0', - `charid` INT(11) UNSIGNED NOT NULL DEFAULT '0', - `slotid` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', - `itemid` INT(11) UNSIGNED NULL DEFAULT '0', - `charges` SMALLINT(3) UNSIGNED NULL DEFAULT '0', - `color` INT(11) UNSIGNED NOT NULL DEFAULT '0', - `augslot1` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', - `augslot2` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', - `augslot3` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', - `augslot4` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', - `augslot5` MEDIUMINT(7) UNSIGNED NULL DEFAULT '0', - `augslot6` MEDIUMINT(7) NOT NULL DEFAULT '0', - `instnodrop` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0', - `custom_data` TEXT NULL, - `ornamenticon` INT(11) UNSIGNED NOT NULL DEFAULT '0', - `ornamentidfile` INT(11) UNSIGNED NOT NULL DEFAULT '0', - `ornament_hero_model` INT(11) NOT NULL DEFAULT '0', - PRIMARY KEY (`time_index`, `charid`, `slotid`) -) -COLLATE='latin1_swedish_ci' -ENGINE=InnoDB; - - -CREATE TABLE `inventory_snapshots_v1_bak` ( - `time_index` INT(11) UNSIGNED NOT NULL DEFAULT '0', - `charid` INT(11) UNSIGNED NOT NULL DEFAULT '0', - `slotid` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', - `itemid` INT(11) UNSIGNED NULL DEFAULT '0', - `charges` SMALLINT(3) UNSIGNED NULL DEFAULT '0', - `color` INT(11) UNSIGNED NOT NULL DEFAULT '0', - `augslot1` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', - `augslot2` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', - `augslot3` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', - `augslot4` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', - `augslot5` MEDIUMINT(7) UNSIGNED NULL DEFAULT '0', - `augslot6` MEDIUMINT(7) NOT NULL DEFAULT '0', - `instnodrop` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0', - `custom_data` TEXT NULL, - `ornamenticon` INT(11) UNSIGNED NOT NULL DEFAULT '0', - `ornamentidfile` INT(11) UNSIGNED NOT NULL DEFAULT '0', - `ornament_hero_model` INT(11) NOT NULL DEFAULT '0', - PRIMARY KEY (`time_index`, `charid`, `slotid`) -) -COLLATE='latin1_swedish_ci' -ENGINE=InnoDB; From 2a9f38de2a618a9d1c1dbe3f97d624bd07c26d84 Mon Sep 17 00:00:00 2001 From: Paul Coene Date: Sun, 28 Oct 2018 12:44:13 -0400 Subject: [PATCH 02/27] Fix Get Corpse to fetch the corpse indicated. --- zone/zonedb.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index 027225243..5fe6560f1 100644 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -4356,15 +4356,15 @@ uint32 ZoneDatabase::GetCharacterCorpseCount(uint32 char_id) { } uint32 ZoneDatabase::GetCharacterCorpseID(uint32 char_id, uint8 corpse) { - std::string query = StringFormat("SELECT `id` FROM `character_corpses` WHERE `charid` = '%u'", char_id); - auto results = QueryDatabase(query); + std::string query = StringFormat("SELECT `id` FROM `character_corpses` WHERE `charid` = '%u' limit %d, 1", char_id, corpse); - for (auto row = results.begin(); row != results.end(); ++row) { - for (int i = 0; i < corpse; i++) { - return atoul(row[0]); - } - } - return 0; + auto results = QueryDatabase(query); + auto row = results.begin(); + + if (row != results.end()) + return atoul(row[0]); + else + return 0; } uint32 ZoneDatabase::GetCharacterCorpseItemCount(uint32 corpse_id){ From dbb368865c840542ba4d6099ea3d412e58fbcb14 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Sat, 3 Nov 2018 17:44:19 -0400 Subject: [PATCH 03/27] Add some Follow stuff to lua You can also disallow following code from allowing the NPC to run if they're far enough away --- zone/lua_npc.cpp | 18 ++++++++++++++++++ zone/lua_npc.h | 3 +++ zone/mob.cpp | 3 ++- zone/mob.h | 9 ++++++--- zone/mob_ai.cpp | 3 ++- 5 files changed, 31 insertions(+), 5 deletions(-) diff --git a/zone/lua_npc.cpp b/zone/lua_npc.cpp index a16d78361..9079049b7 100644 --- a/zone/lua_npc.cpp +++ b/zone/lua_npc.cpp @@ -333,6 +333,21 @@ void Lua_NPC::AI_SetRoambox(float dist, float max_x, float min_x, float max_y, f self->AI_SetRoambox(dist, max_x, min_x, max_y, min_y, delay, mindelay); } +void Lua_NPC::SetFollowID(int id) { + Lua_Safe_Call_Void(); + self->SetFollowID(id); +} + +void Lua_NPC::SetFollowDistance(int dist) { + Lua_Safe_Call_Void(); + self->SetFollowDistance(dist); +} + +void Lua_NPC::SetFollowCanRun(bool v) { + Lua_Safe_Call_Void(); + self->SetFollowCanRun(v); +} + int Lua_NPC::GetNPCSpellsID() { Lua_Safe_Call_Int(); return self->GetNPCSpellsID(); @@ -572,6 +587,9 @@ luabind::scope lua_register_npc() { .def("IsGuarding", (bool(Lua_NPC::*)(void))&Lua_NPC::IsGuarding) .def("AI_SetRoambox", (void(Lua_NPC::*)(float,float,float,float,float))&Lua_NPC::AI_SetRoambox) .def("AI_SetRoambox", (void(Lua_NPC::*)(float,float,float,float,float,uint32,uint32))&Lua_NPC::AI_SetRoambox) + .def("SetFollowID", (void(Lua_NPC::*)(int))&Lua_NPC::SetFollowID) + .def("SetFollowDistance", (void(Lua_NPC::*)(int))&Lua_NPC::SetFollowDistance) + .def("SetFollowCanRun", (void(Lua_NPC::*)(bool))&Lua_NPC::SetFollowCanRun) .def("GetNPCSpellsID", (int(Lua_NPC::*)(void))&Lua_NPC::GetNPCSpellsID) .def("GetSpawnPointID", (int(Lua_NPC::*)(void))&Lua_NPC::GetSpawnPointID) .def("GetSpawnPointX", (float(Lua_NPC::*)(void))&Lua_NPC::GetSpawnPointX) diff --git a/zone/lua_npc.h b/zone/lua_npc.h index 972adee90..a0097eb90 100644 --- a/zone/lua_npc.h +++ b/zone/lua_npc.h @@ -92,6 +92,9 @@ public: bool IsGuarding(); void AI_SetRoambox(float dist, float max_x, float min_x, float max_y, float min_y); void AI_SetRoambox(float dist, float max_x, float min_x, float max_y, float min_y, uint32 delay, uint32 mindelay); + void SetFollowID(int id); + void SetFollowDistance(int dist); + void SetFollowCanRun(bool v); int GetNPCSpellsID(); int GetSpawnPointID(); float GetSpawnPointX(); diff --git a/zone/mob.cpp b/zone/mob.cpp index 45a41df6e..e4c7b5f26 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -383,8 +383,9 @@ Mob::Mob(const char* in_name, m_CurrentWayPoint = glm::vec4(); cur_wp_pause = 0; patrol = 0; - follow = 0; + follow_id = 0; follow_dist = 100; // Default Distance for Follow + follow_run = true; // We can run if distance great enough no_target_hotkey = false; flee_mode = false; currently_fleeing = false; diff --git a/zone/mob.h b/zone/mob.h index 30464822c..59b4a5079 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -695,10 +695,12 @@ public: virtual bool IsAttackAllowed(Mob *target, bool isSpellAttack = false); bool IsTargeted() const { return (targeted > 0); } inline void IsTargeted(int in_tar) { targeted += in_tar; if(targeted < 0) targeted = 0;} - void SetFollowID(uint32 id) { follow = id; } + void SetFollowID(uint32 id) { follow_id = id; } void SetFollowDistance(uint32 dist) { follow_dist = dist; } - uint32 GetFollowID() const { return follow; } + void SetFollowCanRun(bool v) { follow_run = v; } + uint32 GetFollowID() const { return follow_id; } uint32 GetFollowDistance() const { return follow_dist; } + bool GetFollowCanRun() const { return follow_run; } inline bool IsRareSpawn() const { return rare_spawn; } inline void SetRareSpawn(bool in) { rare_spawn = in; } @@ -1235,8 +1237,9 @@ protected: uint16 ownerid; PetType typeofpet; int16 petpower; - uint32 follow; + uint32 follow_id; uint32 follow_dist; + bool follow_run; bool no_target_hotkey; bool rare_spawn; diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index e4066e2cc..bab3b78d2 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -1647,7 +1647,8 @@ void Mob::AI_Process() { if (distance >= follow_distance) { int speed = GetWalkspeed(); - if (distance >= follow_distance + 150) { + // maybe we want the NPC to only walk doing follow logic + if (GetFollowCanRun() && distance >= follow_distance + 150) { speed = GetRunspeed(); } From 467e2d3114fe010712efa2bfbdd6fd7fe1f84961 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Sat, 3 Nov 2018 18:10:36 -0400 Subject: [PATCH 04/27] Add follow getters to lua just in case --- zone/lua_npc.cpp | 19 +++++++++++++++++++ zone/lua_npc.h | 3 +++ 2 files changed, 22 insertions(+) diff --git a/zone/lua_npc.cpp b/zone/lua_npc.cpp index 9079049b7..02e9b9795 100644 --- a/zone/lua_npc.cpp +++ b/zone/lua_npc.cpp @@ -348,6 +348,21 @@ void Lua_NPC::SetFollowCanRun(bool v) { self->SetFollowCanRun(v); } +int Lua_NPC::GetFollowID() { + Lua_Safe_Call_Int(); + return self->GetFollowID(); +} + +int Lua_NPC::GetFollowDistance() { + Lua_Safe_Call_Int(); + return self->GetFollowDistance(); +} + +bool Lua_NPC::GetFollowCanRun() { + Lua_Safe_Call_Bool(); + return self->GetFollowCanRun(); +} + int Lua_NPC::GetNPCSpellsID() { Lua_Safe_Call_Int(); return self->GetNPCSpellsID(); @@ -590,6 +605,10 @@ luabind::scope lua_register_npc() { .def("SetFollowID", (void(Lua_NPC::*)(int))&Lua_NPC::SetFollowID) .def("SetFollowDistance", (void(Lua_NPC::*)(int))&Lua_NPC::SetFollowDistance) .def("SetFollowCanRun", (void(Lua_NPC::*)(bool))&Lua_NPC::SetFollowCanRun) + .def("GetFollowID", (int(Lua_NPC::*)(void))&Lua_NPC::GetFollowID) + .def("GetFollowDistance", (int(Lua_NPC::*)(void))&Lua_NPC::GetFollowDistance) + .def("GetFollowCanRun", (bool(Lua_NPC::*)(void))&Lua_NPC::GetFollowCanRun) + .def("GetNPCSpellsID", (int(Lua_NPC::*)(void))&Lua_NPC::GetNPCSpellsID) .def("GetNPCSpellsID", (int(Lua_NPC::*)(void))&Lua_NPC::GetNPCSpellsID) .def("GetSpawnPointID", (int(Lua_NPC::*)(void))&Lua_NPC::GetSpawnPointID) .def("GetSpawnPointX", (float(Lua_NPC::*)(void))&Lua_NPC::GetSpawnPointX) diff --git a/zone/lua_npc.h b/zone/lua_npc.h index a0097eb90..4b567eb1b 100644 --- a/zone/lua_npc.h +++ b/zone/lua_npc.h @@ -95,6 +95,9 @@ public: void SetFollowID(int id); void SetFollowDistance(int dist); void SetFollowCanRun(bool v); + int GetFollowID(); + int GetFollowDistance(); + bool GetFollowCanRun(); int GetNPCSpellsID(); int GetSpawnPointID(); float GetSpawnPointX(); From cc920e60d9b0a39c6bc5be559a81aab3666ee30f Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Sat, 3 Nov 2018 18:14:54 -0400 Subject: [PATCH 05/27] Reset all follow variables when follow target is gone --- zone/mob_ai.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index bab3b78d2..05e53c7e8 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -1635,6 +1635,8 @@ void Mob::AI_Process() { Mob *follow = entity_list.GetMob(static_cast(GetFollowID())); if (!follow) { SetFollowID(0); + SetFollowDistance(100); + SetFollowCanRun(true); } else { From 4e0d85534e5bee80caa5ea778b657fa99a6b353b Mon Sep 17 00:00:00 2001 From: Akkadius Date: Mon, 5 Nov 2018 00:43:52 -0600 Subject: [PATCH 06/27] Fix issue where new log category settings were getting injected into the database with all settings turned on --- common/database.cpp | 7 +++---- common/eqemu_logsys.cpp | 9 +++++++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/common/database.cpp b/common/database.cpp index a9496b6e3..8ff79a44c 100644 --- a/common/database.cpp +++ b/common/database.cpp @@ -2080,7 +2080,6 @@ void Database::LoadLogSettings(EQEmuLogSys::LogSettings* log_settings) { auto results = QueryDatabase(query); int log_category_id = 0; - LogSys.file_logs_enabled = false; int categories_in_database[1000] = {}; @@ -2090,9 +2089,9 @@ void Database::LoadLogSettings(EQEmuLogSys::LogSettings* log_settings) { continue; } - log_settings[log_category_id].log_to_console = atoi(row[2]); - log_settings[log_category_id].log_to_file = atoi(row[3]); - log_settings[log_category_id].log_to_gmsay = atoi(row[4]); + log_settings[log_category_id].log_to_console = static_cast(atoi(row[2])); + log_settings[log_category_id].log_to_file = static_cast(atoi(row[3])); + log_settings[log_category_id].log_to_gmsay = static_cast(atoi(row[4])); /** * Determine if any output method is enabled for the category diff --git a/common/eqemu_logsys.cpp b/common/eqemu_logsys.cpp index f4d36e5d5..9e99e6cbe 100644 --- a/common/eqemu_logsys.cpp +++ b/common/eqemu_logsys.cpp @@ -113,6 +113,15 @@ void EQEmuLogSys::LoadLogSettingsDefaults() */ log_platform = GetExecutablePlatformInt(); + for (int log_category_id = Logs::AA; log_category_id != Logs::MaxCategoryID; log_category_id++) { + log_settings[log_category_id].log_to_console = 0; + log_settings[log_category_id].log_to_file = 0; + log_settings[log_category_id].log_to_gmsay = 0; + log_settings[log_category_id].is_category_enabled = 0; + } + + file_logs_enabled = false; + /** * Zero out Array */ From d4395a6f0aff866bed6f648aaa8dec97c44cc679 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Wed, 14 Nov 2018 20:37:57 -0500 Subject: [PATCH 07/27] Client doesn't check AA casting standstate Fixes an exploit and makes you stand if you're just sitting --- zone/aa.cpp | 11 +++++++++++ zone/string_ids.h | 1 + 2 files changed, 12 insertions(+) diff --git a/zone/aa.cpp b/zone/aa.cpp index 9fa76a9d4..1ec78e769 100644 --- a/zone/aa.cpp +++ b/zone/aa.cpp @@ -1208,6 +1208,17 @@ void Client::ActivateAlternateAdvancementAbility(int rank_id, int target_id) { if (spells[rank->spell].targettype == ST_Pet || spells[rank->spell].targettype == ST_SummonedPet) target_id = GetPetID(); + // extra handling for cast_not_standing spells + if (!spells[rank->spell].cast_not_standing) { + if (GetAppearance() == eaSitting) // we need to stand! + SetAppearance(eaStanding, false); + + if (GetAppearance() != eaStanding) { + Message_StringID(MT_SpellFailure, STAND_TO_CAST); + return; + } + } + // Bards can cast instant cast AAs while they are casting another song if(spells[rank->spell].cast_time == 0 && GetClass() == BARD && IsBardSong(casting_spell_id)) { if(!SpellFinished(rank->spell, entity_list.GetMob(target_id), EQEmu::CastingSlot::AltAbility, spells[rank->spell].mana, -1, spells[rank->spell].ResistDiff, false)) { diff --git a/zone/string_ids.h b/zone/string_ids.h index 2c223ffbd..acab3df22 100644 --- a/zone/string_ids.h +++ b/zone/string_ids.h @@ -418,6 +418,7 @@ #define NO_LONGER_HIDDEN 12337 //You are no longer hidden. #define STOP_SNEAKING 12338 //You stop sneaking #define NOT_IN_CONTROL 12368 //You do not have control of yourself right now. +#define STAND_TO_CAST 12441 //You must be standing to cast a spell. #define ALREADY_CASTING 12442 //You are already casting a spell! #define SHIMMERS_BRIEFLY 12444 //Your %1 shimmers briefly. #define SENSE_CORPSE_NOT_NAME 12446 //You don't sense any corpses of that name. From a1b384c2543be632a2a8783af3ecd8dbfebc7fbd Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Wed, 14 Nov 2018 20:39:18 -0500 Subject: [PATCH 08/27] Don't reset AA timers --- zone/aa.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zone/aa.cpp b/zone/aa.cpp index 1ec78e769..648545dd3 100644 --- a/zone/aa.cpp +++ b/zone/aa.cpp @@ -1172,7 +1172,7 @@ void Client::ActivateAlternateAdvancementAbility(int rank_id, int target_id) { return; //check cooldown - if(!p_timers.Expired(&database, rank->spell_type + pTimerAAStart)) { + if(!p_timers.Expired(&database, rank->spell_type + pTimerAAStart, false)) { uint32 aaremain = p_timers.GetRemainingTime(rank->spell_type + pTimerAAStart); uint32 aaremain_hr = aaremain / (60 * 60); uint32 aaremain_min = (aaremain / 60) % 60; From 8302f7cc268556fd83e912f9f4a40573f57771ac Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Wed, 14 Nov 2018 22:59:07 -0500 Subject: [PATCH 09/27] Add a level cap to gray con flee --- common/ruletypes.h | 1 + zone/fearpath.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/common/ruletypes.h b/common/ruletypes.h index 16e85805d..ab9acecf1 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -419,6 +419,7 @@ RULE_BOOL(Combat, EnableFearPathing, true) RULE_REAL(Combat, FleeMultiplier, 2.0) // Determines how quickly a NPC will slow down while fleeing. Decrease multiplier to slow NPC down quicker. RULE_BOOL(Combat, FleeGray, true) // If true FleeGrayHPRatio will be used. RULE_INT(Combat, FleeGrayHPRatio, 50) //HP % when a Gray NPC begins to flee. +RULE_INT(Combat, FleeGrayMaxLevel, 18) // NPC's above this level won't do gray/green con flee RULE_INT(Combat, FleeHPRatio, 25) //HP % when a NPC begins to flee. RULE_BOOL(Combat, FleeIfNotAlone, false) // If false, mobs won't flee if other mobs are in combat with it. RULE_BOOL(Combat, AdjustProcPerMinute, true) diff --git a/zone/fearpath.cpp b/zone/fearpath.cpp index c73ec448e..de65f4e8a 100644 --- a/zone/fearpath.cpp +++ b/zone/fearpath.cpp @@ -62,7 +62,7 @@ void Mob::CheckFlee() { } // If no special flee_percent check for Gray or Other con rates - if(GetLevelCon(hate_top->GetLevel(), GetLevel()) == CON_GRAY && fleeratio == 0 && RuleB(Combat, FleeGray)) { + if(GetLevelCon(hate_top->GetLevel(), GetLevel()) == CON_GRAY && fleeratio == 0 && RuleB(Combat, FleeGray) && GetLevel() <= RuleI(Combat, FleeGrayMaxLevel)) { fleeratio = RuleI(Combat, FleeGrayHPRatio); } else if(fleeratio == 0) { fleeratio = RuleI(Combat, FleeHPRatio ); From 2c0714b5d8a2c7a1f631611cf02276f8910a5ecd Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Sun, 18 Nov 2018 16:02:59 -0500 Subject: [PATCH 10/27] Fix cap bug in ZoneDatabase::GetDecayTimes() --- zone/zone.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/zone/zone.cpp b/zone/zone.cpp index 3b9e5e513..9a3446061 100644 --- a/zone/zone.cpp +++ b/zone/zone.cpp @@ -1875,10 +1875,7 @@ bool ZoneDatabase::GetDecayTimes(npcDecayTimes_Struct* npcCorpseDecayTimes) { npcCorpseDecayTimes[index].minlvl = atoi(sep.arg[1]); npcCorpseDecayTimes[index].maxlvl = atoi(sep.arg[2]); - if (atoi(row[1]) > 7200) - npcCorpseDecayTimes[index].seconds = 720; - else - npcCorpseDecayTimes[index].seconds = atoi(row[1]); + npcCorpseDecayTimes[index].seconds = std::min(7200, atoi(row[1])); } return true; From aae316c171c9504eaa7c5866caef1609f3cddf3d Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Sun, 18 Nov 2018 16:03:38 -0500 Subject: [PATCH 11/27] Fix formating in ZoneDatabase::GetDecayTimes() --- zone/zone.cpp | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/zone/zone.cpp b/zone/zone.cpp index 9a3446061..370e18723 100644 --- a/zone/zone.cpp +++ b/zone/zone.cpp @@ -1860,23 +1860,22 @@ bool Zone::RemoveSpawnGroup(uint32 in_id) { return false; } - -// Added By Hogie -bool ZoneDatabase::GetDecayTimes(npcDecayTimes_Struct* npcCorpseDecayTimes) { - - const std::string query = "SELECT varname, value FROM variables WHERE varname LIKE 'decaytime%%' ORDER BY varname"; +bool ZoneDatabase::GetDecayTimes(npcDecayTimes_Struct *npcCorpseDecayTimes) +{ + const std::string query = + "SELECT varname, value FROM variables WHERE varname LIKE 'decaytime%%' ORDER BY varname"; auto results = QueryDatabase(query); if (!results.Success()) - return false; + return false; int index = 0; - for (auto row = results.begin(); row != results.end(); ++row, ++index) { - Seperator sep(row[0]); - npcCorpseDecayTimes[index].minlvl = atoi(sep.arg[1]); - npcCorpseDecayTimes[index].maxlvl = atoi(sep.arg[2]); + for (auto row = results.begin(); row != results.end(); ++row, ++index) { + Seperator sep(row[0]); + npcCorpseDecayTimes[index].minlvl = atoi(sep.arg[1]); + npcCorpseDecayTimes[index].maxlvl = atoi(sep.arg[2]); npcCorpseDecayTimes[index].seconds = std::min(7200, atoi(row[1])); - } + } return true; } From 0d0c22b5e5ba0de7af879137e8989cabef368209 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Sun, 18 Nov 2018 16:06:31 -0500 Subject: [PATCH 12/27] Update corpse decay cap to 24 hours I guess Some people were wanting higher, w/e --- zone/zone.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zone/zone.cpp b/zone/zone.cpp index 370e18723..8fdd26fbf 100644 --- a/zone/zone.cpp +++ b/zone/zone.cpp @@ -1874,7 +1874,7 @@ bool ZoneDatabase::GetDecayTimes(npcDecayTimes_Struct *npcCorpseDecayTimes) npcCorpseDecayTimes[index].minlvl = atoi(sep.arg[1]); npcCorpseDecayTimes[index].maxlvl = atoi(sep.arg[2]); - npcCorpseDecayTimes[index].seconds = std::min(7200, atoi(row[1])); + npcCorpseDecayTimes[index].seconds = std::min(24 * 60 * 60, atoi(row[1])); } return true; From e43b8d84639e9944bed70e9cd4b3fe3af1cb0523 Mon Sep 17 00:00:00 2001 From: Uleat Date: Sun, 18 Nov 2018 21:11:22 -0500 Subject: [PATCH 13/27] Limited Client::GetTraderItems() to 80-item return --- zone/trading.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/zone/trading.cpp b/zone/trading.cpp index 8c07db9fc..154fdf148 100644 --- a/zone/trading.cpp +++ b/zone/trading.cpp @@ -1295,7 +1295,7 @@ EQEmu::ItemInstance* Client::FindTraderItemBySerialNumber(int32 SerialNumber){ GetItems_Struct* Client::GetTraderItems(){ const EQEmu::ItemInstance* item = nullptr; - uint16 SlotID = 0; + uint16 SlotID = INVALID_INDEX; auto gis = new GetItems_Struct; @@ -1304,9 +1304,14 @@ GetItems_Struct* Client::GetTraderItems(){ uint8 ndx = 0; for (int i = EQEmu::invslot::GENERAL_BEGIN; i <= EQEmu::invslot::GENERAL_END; i++) { + if (ndx >= 80) + break; item = this->GetInv().GetItem(i); if(item && item->GetItem()->ID == 17899){ //Traders Satchel for (int x = EQEmu::invbag::SLOT_BEGIN; x <= EQEmu::invbag::SLOT_END; x++) { + if (ndx >= 80) + break; + SlotID = EQEmu::InventoryProfile::CalcSlotId(i, x); item = this->GetInv().GetItem(SlotID); From c6bb4cd44ad8e302e2c514d29b1bfcd46bff2088 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Mon, 19 Nov 2018 20:40:52 -0500 Subject: [PATCH 14/27] Update system_tables.txt [skip ci] --- utils/sql/system_tables.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/utils/sql/system_tables.txt b/utils/sql/system_tables.txt index a5692dabd..4822f8f97 100644 --- a/utils/sql/system_tables.txt +++ b/utils/sql/system_tables.txt @@ -10,6 +10,7 @@ adventure_template_entry adventure_template_entry_flavor altadv_vars alternate_currency +auras base_data blocked_spells books From ecf3c47968ddfb11d367445023fcff5408f7a74d Mon Sep 17 00:00:00 2001 From: Matt Hogan Date: Wed, 21 Nov 2018 09:38:34 -0500 Subject: [PATCH 15/27] Fix omission for Perl/Lua binds for get_data_expires() --- zone/embparser_api.cpp | 1 + zone/lua_general.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/zone/embparser_api.cpp b/zone/embparser_api.cpp index 633bcda53..8d4857d5e 100644 --- a/zone/embparser_api.cpp +++ b/zone/embparser_api.cpp @@ -3692,6 +3692,7 @@ EXTERN_C XS(boot_quest) { newXS(strcpy(buf, "GetZoneID"), XS__GetZoneID, file); newXS(strcpy(buf, "GetZoneLongName"), XS__GetZoneLongName, file); newXS(strcpy(buf, "get_data"), XS__get_data, file); + newXS(strcpy(buf, "get_data_expires"), XS__get_data_expires, file); newXS(strcpy(buf, "set_data"), XS__set_data, file); newXS(strcpy(buf, "delete_data"), XS__delete_data, file); newXS(strcpy(buf, "IsBeneficialSpell"), XS__IsBeneficialSpell, file); diff --git a/zone/lua_general.cpp b/zone/lua_general.cpp index 955b69d5e..6eb8ddf52 100644 --- a/zone/lua_general.cpp +++ b/zone/lua_general.cpp @@ -1680,6 +1680,7 @@ luabind::scope lua_register_general() { luabind::def("say_link", (std::string(*)(const char*,bool))&lua_say_link), luabind::def("say_link", (std::string(*)(const char*))&lua_say_link), luabind::def("get_data", (std::string(*)(std::string))&lua_get_data), + luabind::def("get_data_expires", (std::string(*)(std::string))&lua_get_data_expires), luabind::def("set_data", (void(*)(std::string, std::string))&lua_set_data), luabind::def("set_data", (void(*)(std::string, std::string, std::string))&lua_set_data), luabind::def("delete_data", (bool(*)(std::string))&lua_delete_data), From be17d21149e840a3df7447d7d76a91e6247b9376 Mon Sep 17 00:00:00 2001 From: JJ Date: Sun, 25 Nov 2018 16:46:42 -0500 Subject: [PATCH 16/27] Add primary key to name_filter table. [skip ci] --- utils/sql/db_update_manifest.txt | 1 + utils/sql/git/required/2018_11_25_name_filter_update.sql | 1 + 2 files changed, 2 insertions(+) create mode 100644 utils/sql/git/required/2018_11_25_name_filter_update.sql diff --git a/utils/sql/db_update_manifest.txt b/utils/sql/db_update_manifest.txt index 587839291..0c90308f9 100644 --- a/utils/sql/db_update_manifest.txt +++ b/utils/sql/db_update_manifest.txt @@ -383,6 +383,7 @@ 9127|2018_09_07_NPCMaxAggroDist.sql|SHOW COLUMNS FROM `zone` LIKE 'npc_max_aggro_dist'|empty| 9128|2018_08_13_inventory_version_update.sql|SHOW TABLES LIKE 'inventory_version'|not_empty| 9129|2018_08_13_inventory_update.sql|SHOW TABLES LIKE 'inventory_versions'|empty| +9130|2018_11_25_name_filter_update.sql|SHOW COLUMS FROM `name_filter` LIKE 'id'|empty| # Upgrade conditions: # This won't be needed after this system is implemented, but it is used database that are not diff --git a/utils/sql/git/required/2018_11_25_name_filter_update.sql b/utils/sql/git/required/2018_11_25_name_filter_update.sql new file mode 100644 index 000000000..239a483a5 --- /dev/null +++ b/utils/sql/git/required/2018_11_25_name_filter_update.sql @@ -0,0 +1 @@ +ALTER TABLE `zone` ADD `npc_max_aggro_dist` INT NOT NULL DEFAULT '600'; From fc69824a3f2b6c185813acdaf0dd559069afecea Mon Sep 17 00:00:00 2001 From: JJ Date: Sun, 25 Nov 2018 16:53:00 -0500 Subject: [PATCH 17/27] Oops. https://github.com/EQEmu/Server/commit/be17d21149e840a3df7447d7d76a91e6247b9376 --- utils/sql/git/required/2018_11_25_name_filter_update.sql | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/utils/sql/git/required/2018_11_25_name_filter_update.sql b/utils/sql/git/required/2018_11_25_name_filter_update.sql index 239a483a5..51a6ca86d 100644 --- a/utils/sql/git/required/2018_11_25_name_filter_update.sql +++ b/utils/sql/git/required/2018_11_25_name_filter_update.sql @@ -1 +1,5 @@ -ALTER TABLE `zone` ADD `npc_max_aggro_dist` INT NOT NULL DEFAULT '600'; +ALTER TABLE `name_filter` +ADD COLUMN `id` INT(11) NULL AUTO_INCREMENT FIRST, +DROP PRIMARY KEY, +ADD PRIMARY KEY (`id`) USING BTREE, +ADD INDEX `name_search_index`(`name`); From e46b9043eed0687e1cacbdc2b2aa6ecdb43d6733 Mon Sep 17 00:00:00 2001 From: JJ Date: Sun, 25 Nov 2018 16:55:56 -0500 Subject: [PATCH 18/27] And the version. [skip ci] --- common/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/version.h b/common/version.h index 4caca5b38..e5603c247 100644 --- a/common/version.h +++ b/common/version.h @@ -30,7 +30,7 @@ Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt */ -#define CURRENT_BINARY_DATABASE_VERSION 9129 +#define CURRENT_BINARY_DATABASE_VERSION 9130 #ifdef BOTS #define CURRENT_BINARY_BOTS_DATABASE_VERSION 9021 #else From 86ade2261bffa7bda505f38eb6928d1128855969 Mon Sep 17 00:00:00 2001 From: JJ Date: Mon, 26 Nov 2018 18:08:34 -0500 Subject: [PATCH 19/27] Move name_filter table from user_tables.txt to system_tables.txt [skip ci] --- utils/sql/system_tables.txt | 1 + utils/sql/user_tables.txt | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/sql/system_tables.txt b/utils/sql/system_tables.txt index 4822f8f97..fccb0e0c8 100644 --- a/utils/sql/system_tables.txt +++ b/utils/sql/system_tables.txt @@ -60,6 +60,7 @@ merc_types merc_weaponinfo merchantlist mercs +name_filter npc_emotes npc_faction npc_faction_entries diff --git a/utils/sql/user_tables.txt b/utils/sql/user_tables.txt index 941e30c47..4d77be3a1 100644 --- a/utils/sql/user_tables.txt +++ b/utils/sql/user_tables.txt @@ -59,7 +59,6 @@ launcher_zones lfguild mail merchantlist_temp -name_filter object_contents petitions player_titlesets From df2e68ad3106ed3727617cff1a860843e1f382b4 Mon Sep 17 00:00:00 2001 From: Uleat Date: Thu, 29 Nov 2018 22:55:04 -0500 Subject: [PATCH 20/27] Added missing return value --- common/net/packet.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common/net/packet.cpp b/common/net/packet.cpp index 4c7dc74b6..deaa07843 100644 --- a/common/net/packet.cpp +++ b/common/net/packet.cpp @@ -350,4 +350,5 @@ bool EQ::Net::StaticPacket::Resize(size_t new_size) } m_data_length = new_size; -} \ No newline at end of file + return true; +} From 9bf23a131b9cd6774d2ab75c20ef5e886f40629e Mon Sep 17 00:00:00 2001 From: Noudess Date: Thu, 6 Dec 2018 14:25:58 -0500 Subject: [PATCH 21/27] Small fix for an NPC on a faction but with no entries in npc_faction_entries. --- zone/npc.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/zone/npc.cpp b/zone/npc.cpp index 2b1af6de9..dbbd3772d 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -2632,7 +2632,16 @@ FACTION_VALUE NPC::CheckNPCFactionAlly(int32 other_faction) { return FACTION_INDIFFERENT; } } - return FACTION_INDIFFERENT; + + // I believe that the assumption is, barring no entry in npc_faction_entries + // that two npcs on like faction con ally to each other. This catches cases + // where an npc is on a faction but has no hits (hence no entry in + // npc_faction_entries). + + if (GetPrimaryFaction() == other_faction) + return FACTION_ALLY; + else + return FACTION_INDIFFERENT; } bool NPC::IsFactionListAlly(uint32 other_faction) { @@ -2820,4 +2829,4 @@ void NPC::ModifyStatsOnCharm(bool bRemoved) // the rest of the stats aren't cached, so lets just do these two instead of full CalcBonuses() SetAttackTimer(); CalcAC(); -} \ No newline at end of file +} From 58d0aef90de67d2fd08a3e13bd6749fcae0235a2 Mon Sep 17 00:00:00 2001 From: Noudess Date: Fri, 7 Dec 2018 12:17:27 -0500 Subject: [PATCH 22/27] Fix the LoadGFG function to no longer have the unused parameter. Fixed the command that was passing the wrong second parameter. --- zone/command.cpp | 2 +- zone/zone.cpp | 39 ++++++++++++++++----------------------- zone/zone.h | 2 +- 3 files changed, 18 insertions(+), 25 deletions(-) mode change 100644 => 100755 zone/command.cpp mode change 100644 => 100755 zone/zone.cpp mode change 100644 => 100755 zone/zone.h diff --git a/zone/command.cpp b/zone/command.cpp old mode 100644 new mode 100755 index 98faec71a..2a52b02d2 --- a/zone/command.cpp +++ b/zone/command.cpp @@ -1688,7 +1688,7 @@ void command_zheader(Client *c, const Seperator *sep) c->Message(0, "Invalid Zone Name: %s", sep->argplus[1]); else { - if (zone->LoadZoneCFG(sep->argplus[1], true)) + if (zone->LoadZoneCFG(sep->argplus[1], 0)) c->Message(0, "Successfully loaded zone header for %s from database.", sep->argplus[1]); else c->Message(0, "Failed to load zone header %s from database", sep->argplus[1]); diff --git a/zone/zone.cpp b/zone/zone.cpp old mode 100644 new mode 100755 index 3b9e5e513..b0e18b26c --- a/zone/zone.cpp +++ b/zone/zone.cpp @@ -893,7 +893,7 @@ bool Zone::Init(bool iStaticZone) { SetStaticZone(iStaticZone); //load the zone config file. - if (!LoadZoneCFG(zone->GetShortName(), zone->GetInstanceVersion(), true)) // try loading the zone name... + if (!LoadZoneCFG(zone->GetShortName(), zone->GetInstanceVersion())) // try loading the zone name... LoadZoneCFG(zone->GetFileName(), zone->GetInstanceVersion()); // if that fails, try the file name, then load defaults if(RuleManager::Instance()->GetActiveRulesetID() != default_ruleset) @@ -1054,39 +1054,31 @@ void Zone::ReloadStaticData() { zone->LoadNPCEmotes(&NPCEmoteList); //load the zone config file. - if (!LoadZoneCFG(zone->GetShortName(), zone->GetInstanceVersion(), true)) // try loading the zone name... + if (!LoadZoneCFG(zone->GetShortName(), zone->GetInstanceVersion())) // try loading the zone name... LoadZoneCFG(zone->GetFileName(), zone->GetInstanceVersion()); // if that fails, try the file name, then load defaults Log(Logs::General, Logs::Status, "Zone Static Data Reloaded."); } -bool Zone::LoadZoneCFG(const char* filename, uint16 instance_id, bool DontLoadDefault) +bool Zone::LoadZoneCFG(const char* filename, uint16 instance_id) { + memset(&newzone_data, 0, sizeof(NewZone_Struct)); - if(instance_id == 0) + map_name = nullptr; + + if(!database.GetZoneCFG(database.GetZoneID(filename), instance_id, &newzone_data, can_bind, + can_combat, can_levitate, can_castoutdoor, is_city, is_hotzone, allow_mercs, zone_type, default_ruleset, &map_name)) { - map_name = nullptr; - if(!database.GetZoneCFG(database.GetZoneID(filename), 0, &newzone_data, can_bind, - can_combat, can_levitate, can_castoutdoor, is_city, is_hotzone, allow_mercs, zone_type, default_ruleset, &map_name)) - { - Log(Logs::General, Logs::Error, "Error loading the Zone Config."); - return false; - } - } - else - { - //Fall back to base zone if we don't find the instance version. - map_name = nullptr; - if(!database.GetZoneCFG(database.GetZoneID(filename), instance_id, &newzone_data, can_bind, - can_combat, can_levitate, can_castoutdoor, is_city, is_hotzone, allow_mercs, zone_type, default_ruleset, &map_name)) + // If loading a non-zero instance failed, try loading the default + if (instance_id != 0) { safe_delete_array(map_name); - if(!database.GetZoneCFG(database.GetZoneID(filename), 0, &newzone_data, can_bind, - can_combat, can_levitate, can_castoutdoor, is_city, is_hotzone, allow_mercs, zone_type, default_ruleset, &map_name)) - { + if(!database.GetZoneCFG(database.GetZoneID(filename), 0, &newzone_data, can_bind, can_combat, can_levitate, + can_castoutdoor, is_city, is_hotzone, allow_mercs, zone_type, default_ruleset, &map_name)) + { Log(Logs::General, Logs::Error, "Error loading the Zone Config."); return false; - } + } } } @@ -1274,7 +1266,8 @@ bool Zone::Process() { } } - if(Weather_Timer->Check()){ + if(Weather_Timer->Check()) + { Weather_Timer->Disable(); this->ChangeWeather(); } diff --git a/zone/zone.h b/zone/zone.h old mode 100644 new mode 100755 index 5f8651d8b..ae0d93332 --- a/zone/zone.h +++ b/zone/zone.h @@ -93,7 +93,7 @@ public: bool is_zone_time_localized; bool Init(bool iStaticZone); - bool LoadZoneCFG(const char* filename, uint16 instance_id, bool DontLoadDefault = false); + bool LoadZoneCFG(const char* filename, uint16 instance_id); bool SaveZoneCFG(); bool IsLoaded(); bool IsPVPZone() { return pvpzone; } From cfbd8e727a486859db00b1e590455bfe9dad4949 Mon Sep 17 00:00:00 2001 From: Noudess Date: Wed, 12 Dec 2018 09:15:54 -0500 Subject: [PATCH 23/27] Fix typo in manifest. --- utils/sql/db_update_manifest.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/sql/db_update_manifest.txt b/utils/sql/db_update_manifest.txt index 0c90308f9..81a8fa2d8 100644 --- a/utils/sql/db_update_manifest.txt +++ b/utils/sql/db_update_manifest.txt @@ -383,7 +383,7 @@ 9127|2018_09_07_NPCMaxAggroDist.sql|SHOW COLUMNS FROM `zone` LIKE 'npc_max_aggro_dist'|empty| 9128|2018_08_13_inventory_version_update.sql|SHOW TABLES LIKE 'inventory_version'|not_empty| 9129|2018_08_13_inventory_update.sql|SHOW TABLES LIKE 'inventory_versions'|empty| -9130|2018_11_25_name_filter_update.sql|SHOW COLUMS FROM `name_filter` LIKE 'id'|empty| +9130|2018_11_25_name_filter_update.sql|SHOW COLUMNS FROM `name_filter` LIKE 'id'|empty| # Upgrade conditions: # This won't be needed after this system is implemented, but it is used database that are not From 8ae9c99f3d29e4f67fae96e15703229bbc92611b Mon Sep 17 00:00:00 2001 From: Kinglykrab Date: Thu, 13 Dec 2018 19:41:19 -0500 Subject: [PATCH 24/27] Added new data bucket and quest functionality. Added multiple new instance related quest functions. 1. quest::GetInstanceIDByCharID(const char *zone, int16 version, uint32 char_id) - Allows you to pull the instance ID of a client by character ID. 2. quest::AssignToInstanceByCharID(uint16 instance_id, uint32 char_id) - Allows you to assign an instance to a client by character ID. 3. quest::RemoveFromInstanceByCharID(uint16 instance_id, uint32 char_id) - Allows you to remove a client from an instance by character ID. Added spell buckets, similar to spell globals. - Uses a new spell_buckets table and the Spells:EnableSpellBuckets rule. Added max level by data bucket. - Uses data bucket char_id-CharMaxLevel and Character:PerCharacterBucketMaxLevel rule. --- common/ruletypes.h | 4 +- common/version.h | 2 +- utils/sql/db_update_manifest.txt | 1 + .../git/required/2018_12_13_spell_buckets.sql | 10 +++ utils/sql/user_tables.txt | 1 + zone/client.h | 4 +- zone/exp.cpp | 28 ++++++ zone/questmgr.cpp | 90 +++++++++++++------ zone/questmgr.h | 3 + zone/spells.cpp | 79 +++++++++++----- 10 files changed, 170 insertions(+), 52 deletions(-) create mode 100644 utils/sql/git/required/2018_12_13_spell_buckets.sql diff --git a/common/ruletypes.h b/common/ruletypes.h index ab9acecf1..21c006099 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -38,6 +38,7 @@ RULE_CATEGORY(Character) RULE_INT(Character, MaxLevel, 65) RULE_BOOL(Character, PerCharacterQglobalMaxLevel, false) // This will check for qglobal 'CharMaxLevel' character qglobal (Type 5), if player tries to level beyond that point, it will not go beyond that level +RULE_BOOL(Character, PerCharacterBucketMaxLevel, false) // This will check for data bucket 'CharMaxLevel', if player tries to level beyond that point, it will not go beyond that level RULE_INT(Character, MaxExpLevel, 0) //Sets the Max Level attainable via Experience RULE_INT(Character, DeathExpLossLevel, 10) // Any level greater than this will lose exp on death RULE_INT(Character, DeathExpLossMaxLevel, 255) // Any level greater than this will no longer lose exp on death @@ -342,7 +343,8 @@ RULE_INT(Spells, TranslocateTimeLimit, 0) // If not zero, time in seconds to acc RULE_INT(Spells, SacrificeMinLevel, 46) //first level Sacrifice will work on RULE_INT(Spells, SacrificeMaxLevel, 69) //last level Sacrifice will work on RULE_INT(Spells, SacrificeItemID, 9963) //Item ID of the item Sacrifice will return (defaults to an EE) -RULE_BOOL(Spells, EnableSpellGlobals, false) // If Enabled, spells check the spell_globals table and compare character data from the quest globals before allowing that spell to scribe with scribespells +RULE_BOOL(Spells, EnableSpellGlobals, false) // If Enabled, spells check the spell_globals table and compare character data from their quest globals before allowing the spell to scribe with scribespells/traindiscs +RULE_BOOL(Spells, EnableSpellBuckets, false) // If Enabled, spells check the spell_buckets table and compare character data from their data buckets before allowing the spell to scribe with scribespells/traindiscs RULE_INT(Spells, MaxBuffSlotsNPC, 60) // default to Tit's limit RULE_INT(Spells, MaxSongSlotsNPC, 0) // NPCs don't have songs ... RULE_INT(Spells, MaxDiscSlotsNPC, 0) // NPCs don't have discs ... diff --git a/common/version.h b/common/version.h index e5603c247..baead2fe2 100644 --- a/common/version.h +++ b/common/version.h @@ -30,7 +30,7 @@ Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt */ -#define CURRENT_BINARY_DATABASE_VERSION 9130 +#define CURRENT_BINARY_DATABASE_VERSION 9131 #ifdef BOTS #define CURRENT_BINARY_BOTS_DATABASE_VERSION 9021 #else diff --git a/utils/sql/db_update_manifest.txt b/utils/sql/db_update_manifest.txt index 81a8fa2d8..a203b825b 100644 --- a/utils/sql/db_update_manifest.txt +++ b/utils/sql/db_update_manifest.txt @@ -384,6 +384,7 @@ 9128|2018_08_13_inventory_version_update.sql|SHOW TABLES LIKE 'inventory_version'|not_empty| 9129|2018_08_13_inventory_update.sql|SHOW TABLES LIKE 'inventory_versions'|empty| 9130|2018_11_25_name_filter_update.sql|SHOW COLUMNS FROM `name_filter` LIKE 'id'|empty| +9131|2018_12_13_spell_buckets.sql|SHOW TABLES LIKE 'spell_buckets'|empty| # Upgrade conditions: # This won't be needed after this system is implemented, but it is used database that are not diff --git a/utils/sql/git/required/2018_12_13_spell_buckets.sql b/utils/sql/git/required/2018_12_13_spell_buckets.sql new file mode 100644 index 000000000..1c56799f0 --- /dev/null +++ b/utils/sql/git/required/2018_12_13_spell_buckets.sql @@ -0,0 +1,10 @@ +CREATE TABLE `spell_buckets` ( + `spellid` bigint(11) unsigned NOT NULL, + `key` varchar(100) DEFAULT NULL, + `value` text, + PRIMARY KEY (`spellid`), + KEY `key_index` (`key`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Spells:EnableSpellBuckets', 'false', 'Enables spell buckets'); +INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Character:PerCharacterBucketMaxLevel', 'false', 'Enables data bucket-based max level.'); \ No newline at end of file diff --git a/utils/sql/user_tables.txt b/utils/sql/user_tables.txt index 4d77be3a1..a76e110f3 100644 --- a/utils/sql/user_tables.txt +++ b/utils/sql/user_tables.txt @@ -85,6 +85,7 @@ reports respawn_times sharedbank spell_globals +spell_buckets timers trader trader_audit diff --git a/zone/client.h b/zone/client.h index 023367e50..f7848202d 100644 --- a/zone/client.h +++ b/zone/client.h @@ -773,8 +773,10 @@ public: void UnscribeSpellAll(bool update_client = true); void UntrainDisc(int slot, bool update_client = true); void UntrainDiscAll(bool update_client = true); - bool SpellGlobalCheck(uint16 Spell_ID, uint32 Char_ID); + bool SpellGlobalCheck(uint16 spell_id, uint32 char_id); + bool SpellBucketCheck(uint16 spell_id, uint32 char_id); uint32 GetCharMaxLevelFromQGlobal(); + uint32 GetCharMaxLevelFromBucket(); inline bool IsSitting() const {return (playeraction == 1);} inline bool IsBecomeNPC() const { return npcflag; } diff --git a/zone/exp.cpp b/zone/exp.cpp index 94f36197d..302e29279 100644 --- a/zone/exp.cpp +++ b/zone/exp.cpp @@ -695,6 +695,18 @@ void Client::SetEXP(uint32 set_exp, uint32 set_aaxp, bool isrezzexp) { } } } + + if(RuleB(Character, PerCharacterBucketMaxLevel)){ + uint32 MaxLevel = GetCharMaxLevelFromBucket(); + if(MaxLevel){ + if(GetLevel() >= MaxLevel){ + uint32 expneeded = GetEXPForLevel(MaxLevel); + if(set_exp > expneeded) { + set_exp = expneeded; + } + } + } + } if ((GetLevel() != check_level) && !(check_level >= maxlevel)) { char val1[20]={0}; @@ -1133,6 +1145,22 @@ uint32 Client::GetCharMaxLevelFromQGlobal() { return false; } +uint32 Client::GetCharMaxLevelFromBucket() { + uint32 char_id = this->CharacterID(); + std::string query = StringFormat("SELECT value FROM data_buckets WHERE key = '%i-CharMaxLevel'", char_id); + auto results = database.QueryDatabase(query); + if (!results.Success()) { + Log(Logs::General, Logs::Error, "Data bucket for CharMaxLevel for char ID %i failed.", char_id); + return false; + } + + if (results.RowCount() > 0) { + auto row = results.begin(); + return atoi(row[0]); + } + return false; +} + uint32 Client::GetRequiredAAExperience() { #ifdef LUA_EQEMU uint32 lua_ret = 0; diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp index 1393b0221..e775fa368 100644 --- a/zone/questmgr.cpp +++ b/zone/questmgr.cpp @@ -976,37 +976,44 @@ void QuestManager::permagender(int gender_id) { uint16 QuestManager::scribespells(uint8 max_level, uint8 min_level) { QuestManagerCurrentQuestVars(); uint16 book_slot, count; - uint16 curspell; + uint16 spell_id; - uint32 Char_ID = initiator->CharacterID(); + uint32 char_id = initiator->CharacterID(); bool SpellGlobalRule = RuleB(Spells, EnableSpellGlobals); + bool SpellBucketRule = RuleB(Spells, EnableSpellBuckets); bool SpellGlobalCheckResult = 0; + bool SpellBucketCheckResult = 0; - for(curspell = 0, book_slot = initiator->GetNextAvailableSpellBookSlot(), count = 0; curspell < SPDAT_RECORDS && book_slot < MAX_PP_SPELLBOOK; curspell++, book_slot = initiator->GetNextAvailableSpellBookSlot(book_slot)) + for(spell_id = 0, book_slot = initiator->GetNextAvailableSpellBookSlot(), count = 0; spell_id < SPDAT_RECORDS && book_slot < MAX_PP_SPELLBOOK; spell_id++, book_slot = initiator->GetNextAvailableSpellBookSlot(book_slot)) { if ( - spells[curspell].classes[WARRIOR] != 0 && //check if spell exists - spells[curspell].classes[initiator->GetPP().class_-1] <= max_level && //maximum level - spells[curspell].classes[initiator->GetPP().class_-1] >= min_level && //minimum level - spells[curspell].skill != 52 && - spells[curspell].effectid[EFFECT_COUNT - 1] != 10 + spells[spell_id].classes[WARRIOR] != 0 && //check if spell exists + spells[spell_id].classes[initiator->GetPP().class_-1] <= max_level && //maximum level + spells[spell_id].classes[initiator->GetPP().class_-1] >= min_level && //minimum level + spells[spell_id].skill != 52 && + spells[spell_id].effectid[EFFECT_COUNT - 1] != 10 ) { if (book_slot == -1) //no more book slots break; - if(!IsDiscipline(curspell) && !initiator->HasSpellScribed(curspell)) { //isn't a discipline & we don't already have it scribed + if(!IsDiscipline(spell_id) && !initiator->HasSpellScribed(spell_id)) { //isn't a discipline & we don't already have it scribed if (SpellGlobalRule) { // Bool to see if the character has the required QGlobal to scribe it if one exists in the Spell_Globals table - SpellGlobalCheckResult = initiator->SpellGlobalCheck(curspell, Char_ID); + SpellGlobalCheckResult = initiator->SpellGlobalCheck(spell_id, char_id); if (SpellGlobalCheckResult) { - initiator->ScribeSpell(curspell, book_slot); + initiator->ScribeSpell(spell_id, book_slot); count++; } - } - else { - initiator->ScribeSpell(curspell, book_slot); + } else if (SpellBucketRule) { + SpellBucketCheckResult = initiator->SpellBucketCheck(spell_id, char_id); + if (SpellBucketCheckResult) { + initiator->ScribeSpell(spell_id, book_slot); + count++; + } + } else { + initiator->ScribeSpell(spell_id, book_slot); count++; } } @@ -1018,46 +1025,59 @@ uint16 QuestManager::scribespells(uint8 max_level, uint8 min_level) { uint16 QuestManager::traindiscs(uint8 max_level, uint8 min_level) { QuestManagerCurrentQuestVars(); uint16 count; - uint16 curspell; + uint16 spell_id; - uint32 Char_ID = initiator->CharacterID(); + uint32 char_id = initiator->CharacterID(); bool SpellGlobalRule = RuleB(Spells, EnableSpellGlobals); + bool SpellBucketRule = RuleB(Spells, EnableSpellBuckets); bool SpellGlobalCheckResult = 0; + bool SpellBucketCheckResult = 0; - for(curspell = 0, count = 0; curspell < SPDAT_RECORDS; curspell++) + for(spell_id = 0, count = 0; spell_id < SPDAT_RECORDS; spell_id++) { if ( - spells[curspell].classes[WARRIOR] != 0 && //check if spell exists - spells[curspell].classes[initiator->GetPP().class_-1] <= max_level && //maximum level - spells[curspell].classes[initiator->GetPP().class_-1] >= min_level && //minimum level - spells[curspell].skill != 52 && - ( !RuleB(Spells, UseCHAScribeHack) || spells[curspell].effectid[EFFECT_COUNT - 1] != 10 ) + spells[spell_id].classes[WARRIOR] != 0 && //check if spell exists + spells[spell_id].classes[initiator->GetPP().class_-1] <= max_level && //maximum level + spells[spell_id].classes[initiator->GetPP().class_-1] >= min_level && //minimum level + spells[spell_id].skill != 52 && + ( !RuleB(Spells, UseCHAScribeHack) || spells[spell_id].effectid[EFFECT_COUNT - 1] != 10 ) ) { - if(IsDiscipline(curspell)){ + if(IsDiscipline(spell_id)){ //we may want to come up with a function like Client::GetNextAvailableSpellBookSlot() to help speed this up a little for(uint32 r = 0; r < MAX_PP_DISCIPLINES; r++) { - if(initiator->GetPP().disciplines.values[r] == curspell) { + if(initiator->GetPP().disciplines.values[r] == spell_id) { initiator->Message(13, "You already know this discipline."); break; //continue the 1st loop } else if(initiator->GetPP().disciplines.values[r] == 0) { if (SpellGlobalRule) { // Bool to see if the character has the required QGlobal to train it if one exists in the Spell_Globals table - SpellGlobalCheckResult = initiator->SpellGlobalCheck(curspell, Char_ID); + SpellGlobalCheckResult = initiator->SpellGlobalCheck(spell_id, char_id); if (SpellGlobalCheckResult) { - initiator->GetPP().disciplines.values[r] = curspell; - database.SaveCharacterDisc(Char_ID, r, curspell); + initiator->GetPP().disciplines.values[r] = spell_id; + database.SaveCharacterDisc(char_id, r, spell_id); initiator->SendDisciplineUpdate(); initiator->Message(0, "You have learned a new discipline!"); count++; //success counter } break; //continue the 1st loop + } else if (SpellBucketRule) { + // Bool to see if the character has the required bucket to train it if one exists in the spell_buckets table + SpellBucketCheckResult = initiator->SpellBucketCheck(spell_id, char_id); + if (SpellBucketCheckResult) { + initiator->GetPP().disciplines.values[r] = spell_id; + database.SaveCharacterDisc(char_id, r, spell_id); + initiator->SendDisciplineUpdate(); + initiator->Message(0, "You have learned a new discipline!"); + count++; + } + break; } else { - initiator->GetPP().disciplines.values[r] = curspell; - database.SaveCharacterDisc(Char_ID, r, curspell); + initiator->GetPP().disciplines.values[r] = spell_id; + database.SaveCharacterDisc(char_id, r, spell_id); initiator->SendDisciplineUpdate(); initiator->Message(0, "You have learned a new discipline!"); count++; //success counter @@ -2661,6 +2681,10 @@ uint16 QuestManager::GetInstanceID(const char *zone, int16 version) return 0; } +uint16 QuestManager::GetInstanceIDByCharID(const char *zone, int16 version, uint32 char_id) { + return database.GetInstanceID(zone, char_id, version); +} + void QuestManager::AssignToInstance(uint16 instance_id) { QuestManagerCurrentQuestVars(); @@ -2670,6 +2694,10 @@ void QuestManager::AssignToInstance(uint16 instance_id) } } +void QuestManager::AssignToInstanceByCharID(uint16 instance_id, uint32 char_id) { + database.AddClientToInstance(instance_id, char_id); +} + void QuestManager::AssignGroupToInstance(uint16 instance_id) { QuestManagerCurrentQuestVars(); @@ -2710,6 +2738,10 @@ void QuestManager::RemoveFromInstance(uint16 instance_id) } } +void QuestManager::RemoveFromInstanceByCharID(uint16 instance_id, uint32 char_id) { + database.RemoveClientFromInstance(instance_id, char_id); +} + void QuestManager::RemoveAllFromInstance(uint16 instance_id) { QuestManagerCurrentQuestVars(); diff --git a/zone/questmgr.h b/zone/questmgr.h index a3b9fac43..6818ae09b 100644 --- a/zone/questmgr.h +++ b/zone/questmgr.h @@ -234,10 +234,13 @@ public: uint32 GetInstanceTimerByID(uint16 instance_id = 0); void DestroyInstance(uint16 instance_id); uint16 GetInstanceID(const char *zone, int16 version); + uint16 GetInstanceIDByCharID(const char *zone, int16 version, uint32 char_id); void AssignToInstance(uint16 instance_id); + void AssignToInstanceByCharID(uint16 instance_id, uint32 char_id); void AssignGroupToInstance(uint16 instance_id); void AssignRaidToInstance(uint16 instance_id); void RemoveFromInstance(uint16 instance_id); + void RemoveFromInstanceByCharID(uint16 instance_id, uint32 char_id); //void RemoveGroupFromInstance(uint16 instance_id); //potentially useful but not implmented at this time. //void RemoveRaidFromInstance(uint16 instance_id); //potentially useful but not implmented at this time. void RemoveAllFromInstance(uint16 instance_id); diff --git a/zone/spells.cpp b/zone/spells.cpp index 0fcb7fe2b..1cb920786 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -5154,14 +5154,11 @@ int Client::FindSpellBookSlotBySpellID(uint16 spellid) { return -1; //default } -bool Client::SpellGlobalCheck(uint16 spell_ID, uint32 char_ID) { - - std::string spell_Global_Name; - int spell_Global_Value; - int global_Value; - - std::string query = StringFormat("SELECT qglobal, value FROM spell_globals " - "WHERE spellid = %i", spell_ID); +bool Client::SpellGlobalCheck(uint16 spell_id, uint32 char_id) { + std::string spell_global_name; + int spell_global_value; + int global_value; + std::string query = StringFormat("SELECT qglobal, value FROM spell_globals WHERE spellid = %i", spell_id); auto results = database.QueryDatabase(query); if (!results.Success()) { return false; // Query failed, so prevent spell from scribing just in case @@ -5171,37 +5168,79 @@ bool Client::SpellGlobalCheck(uint16 spell_ID, uint32 char_ID) { return true; // Spell ID isn't listed in the spells_global table, so it is not restricted from scribing auto row = results.begin(); - spell_Global_Name = row[0]; - spell_Global_Value = atoi(row[1]); + spell_global_name = row[0]; + spell_global_value = atoi(row[1]); - if (spell_Global_Name.empty()) + if (spell_global_name.empty()) return true; // If the entry in the spell_globals table has nothing set for the qglobal name query = StringFormat("SELECT value FROM quest_globals " "WHERE charid = %i AND name = '%s'", - char_ID, spell_Global_Name.c_str()); + char_id, spell_global_name.c_str()); results = database.QueryDatabase(query); if (!results.Success()) { - Log(Logs::General, Logs::Error, "Spell ID %i query of spell_globals with Name: '%s' Value: '%i' failed", spell_ID, spell_Global_Name.c_str(), spell_Global_Value); + Log(Logs::General, Logs::Error, "Spell ID %i query of spell_globals with Name: '%s' Value: '%i' failed", spell_id, spell_global_name.c_str(), spell_global_value); return false; } if (results.RowCount() != 1) { - Log(Logs::General, Logs::Error, "Char ID: %i does not have the Qglobal Name: '%s' for Spell ID %i", char_ID, spell_Global_Name.c_str(), spell_ID); + Log(Logs::General, Logs::Error, "Char ID: %i does not have the Qglobal Name: '%s' for Spell ID %i", char_id, spell_global_name.c_str(), spell_id); + return false; + } + + row = results.begin(); + global_value = atoi(row[0]); + if (global_value == spell_global_value) + return true; // If the values match from both tables, allow the spell to be scribed + else if (global_value > spell_global_value) + return true; // Check if the qglobal value is greater than the require spellglobal value + + // If no matching result found in qglobals, don't scribe this spell + Log(Logs::General, Logs::Error, "Char ID: %i Spell_globals Name: '%s' Value: '%i' did not match QGlobal Value: '%i' for Spell ID %i", char_id, spell_global_name.c_str(), spell_global_value, global_value, spell_id); + return false; +} + +bool Client::SpellBucketCheck(uint16 spell_id, uint32 char_id) { + std::string spell_bucket_name; + int spell_bucket_value; + int bucket_value; + std::string query = StringFormat("SELECT key, value FROM spell_buckets WHERE spellid = %i", spell_id); + auto results = database.QueryDatabase(query); + if (!results.Success()) + return false; + + if (results.RowCount() != 1) + return true; + + auto row = results.begin(); + spell_bucket_name = row[0]; + spell_bucket_value = atoi(row[1]); + if (spell_bucket_name.empty()) + return true; + + query = StringFormat("SELECT value FROM data_buckets WHERE key = '%i-%s'", char_id, spell_bucket_name.c_str()); + results = database.QueryDatabase(query); + if (!results.Success()) { + Log(Logs::General, Logs::Error, "Spell bucket %s for spell ID %i for char ID %i failed.", spell_bucket_name.c_str(), spell_id, char_id); + return false; + } + + if (results.RowCount() != 1) { + Log(Logs::General, Logs::Error, "Spell bucket %s does not exist for spell ID %i for char ID %i.", spell_bucket_name.c_str(), spell_id, char_id); return false; } row = results.begin(); - global_Value = atoi(row[0]); + bucket_value = atoi(row[0]); - if (global_Value == spell_Global_Value) + if (bucket_value == spell_bucket_value) return true; // If the values match from both tables, allow the spell to be scribed - else if (global_Value > spell_Global_Value) - return true; // Check if the qglobal value is greater than the require spellglobal value + else if (bucket_value > spell_bucket_value) + return true; // Check if the data bucket value is greater than the required spell bucket value - // If no matching result found in qglobals, don't scribe this spell - Log(Logs::General, Logs::Error, "Char ID: %i Spell_globals Name: '%s' Value: '%i' did not match QGlobal Value: '%i' for Spell ID %i", char_ID, spell_Global_Name.c_str(), spell_Global_Value, global_Value, spell_ID); + // If no matching result found in spell buckets, don't scribe this spell + Log(Logs::General, Logs::Error, "Spell bucket %s for spell ID %i for char ID %i did not match value %i.", spell_bucket_name.c_str(), spell_id, char_id, spell_bucket_value); return false; } From 838ab5b77e3bf5204b891dc672ef73e17fbfd06d Mon Sep 17 00:00:00 2001 From: Kinglykrab Date: Thu, 13 Dec 2018 20:22:14 -0500 Subject: [PATCH 25/27] Missed embparser_api.cpp and lua_general.cpp. Sorry. --- zone/embparser_api.cpp | 43 ++++++++++++++++++++++++++++++++++++++++++ zone/lua_general.cpp | 15 +++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/zone/embparser_api.cpp b/zone/embparser_api.cpp index 8d4857d5e..a1174ae50 100644 --- a/zone/embparser_api.cpp +++ b/zone/embparser_api.cpp @@ -2870,6 +2870,20 @@ XS(XS__GetInstanceID) { XSRETURN_UV(id); } +XS(XS__GetInstanceIDByCharID); +XS(XS__GetInstanceIDByCharID) { + dXSARGS; + if (items != 3) + Perl_croak(aTHX_ "Usage: quest::GetInstanceIDByCharID(string zone_name, uint16 version, uint32 char_id)"); + + char *zone = (char *) SvPV_nolen(ST(0)); + uint16 version = (int) SvUV(ST(1)); + uint32 char_id = (int) SvUV(ST(2)); + uint16 id = quest_manager.GetInstanceIDByCharID(zone, version, char_id); + + XSRETURN_UV(id); +} + XS(XS__GetCharactersInInstance); XS(XS__GetCharactersInInstance) { dXSARGS; @@ -2921,6 +2935,19 @@ XS(XS__AssignToInstance) { XSRETURN_EMPTY; } +XS(XS__AssignToInstanceByCharID); +XS(XS__AssignToInstanceByCharID) { + dXSARGS; + if (items != 2) + Perl_croak(aTHX_ "Usage: quest::AssignToInstanceByCharID(uint16 instance_id, uint32 char_id)"); + + uint16 instance_id = (int) SvUV(ST(0)); + uint32 char_id = (int) SvUV(ST(1)); + quest_manager.AssignToInstanceByCharID(instance_id, char_id); + + XSRETURN_EMPTY; +} + XS(XS__AssignGroupToInstance); XS(XS__AssignGroupToInstance) { dXSARGS; @@ -2957,6 +2984,19 @@ XS(XS__RemoveFromInstance) { XSRETURN_EMPTY; } +XS(XS__RemoveFromInstanceByCharID); +XS(XS__RemoveFromInstanceByCharID) { + dXSARGS; + if (items != 2) + Perl_croak(aTHX_ "Usage: quest::RemoveFromInstanceByCharID(uint16 instance_id, uint32 char_id)"); + + uint16 instance_id = (int) SvUV(ST(0)); + uint32 char_id = (int) SvUV(ST(1)); + quest_manager.RemoveFromInstanceByCharID(instance_id, char_id); + + XSRETURN_EMPTY; +} + XS(XS__RemoveAllFromInstance); XS(XS__RemoveAllFromInstance) { dXSARGS; @@ -3675,6 +3715,7 @@ EXTERN_C XS(boot_quest) { newXS(strcpy(buf, "AssignGroupToInstance"), XS__AssignGroupToInstance, file); newXS(strcpy(buf, "AssignRaidToInstance"), XS__AssignRaidToInstance, file); newXS(strcpy(buf, "AssignToInstance"), XS__AssignToInstance, file); + newXS(strcpy(buf, "AssignToInstanceByCharID"), XS__AssignToInstanceByCharID, file); newXS(strcpy(buf, "ChooseRandom"), XS__ChooseRandom, file); newXS(strcpy(buf, "CreateInstance"), XS__CreateInstance, file); newXS(strcpy(buf, "DestroyInstance"), XS__DestroyInstance, file); @@ -3686,6 +3727,7 @@ EXTERN_C XS(boot_quest) { newXS(strcpy(buf, "FlyMode"), XS__FlyMode, file); newXS(strcpy(buf, "GetCharactersInInstance"), XS__GetCharactersInInstance, file); newXS(strcpy(buf, "GetInstanceID"), XS__GetInstanceID, file); + newXS(strcpy(buf, "GetInstanceIDByCharID"), XS__GetInstanceIDByCharID, file); newXS(strcpy(buf, "GetSpellResistType"), XS__GetSpellResistType, file); newXS(strcpy(buf, "GetSpellTargetType"), XS__GetSpellTargetType, file); newXS(strcpy(buf, "GetTimeSeconds"), XS__GetTimeSeconds, file); @@ -3704,6 +3746,7 @@ EXTERN_C XS(boot_quest) { newXS(strcpy(buf, "MovePCInstance"), XS__MovePCInstance, file); newXS(strcpy(buf, "RemoveAllFromInstance"), XS__RemoveAllFromInstance, file); newXS(strcpy(buf, "RemoveFromInstance"), XS__RemoveFromInstance, file); + newXS(strcpy(buf, "RemoveFromInstanceByCharID"), XS__RemoveFromInstanceByCharID, file); newXS(strcpy(buf, "SendMail"), XS__SendMail, file); newXS(strcpy(buf, "SetRunning"), XS__SetRunning, file); newXS(strcpy(buf, "activespeakactivity"), XS__activespeakactivity, file); diff --git a/zone/lua_general.cpp b/zone/lua_general.cpp index 6eb8ddf52..2bc769669 100644 --- a/zone/lua_general.cpp +++ b/zone/lua_general.cpp @@ -866,10 +866,18 @@ int lua_get_instance_id(const char *zone, uint32 version) { return quest_manager.GetInstanceID(zone, version); } +int lua_get_instance_id_by_char_id(const char *zone, uint32 version, uint32 char_id) { + return quest_manager.GetInstanceIDByCharID(zone, version, char_id); +} + void lua_assign_to_instance(uint32 instance_id) { quest_manager.AssignToInstance(instance_id); } +void lua_assign_to_instance_by_char_id(uint32 instance_id, uint32 char_id) { + quest_manager.AssignToInstanceByCharID(instance_id, char_id); +} + void lua_assign_group_to_instance(uint32 instance_id) { quest_manager.AssignGroupToInstance(instance_id); } @@ -882,6 +890,10 @@ void lua_remove_from_instance(uint32 instance_id) { quest_manager.RemoveFromInstance(instance_id); } +void lua_remove_from_instance_by_char_id(uint32 instance_id, uint32 char_id) { + quest_manager.RemoveFromInstanceByCharID(instance_id, char_id); +} + void lua_remove_all_from_instance(uint32 instance_id) { quest_manager.RemoveAllFromInstance(instance_id); } @@ -1689,13 +1701,16 @@ luabind::scope lua_register_general() { luabind::def("destroy_instance", &lua_destroy_instance), luabind::def("update_instance_timer", &lua_update_instance_timer), luabind::def("get_instance_id", &lua_get_instance_id), + luabind::def("get_instance_id_by_char_id", &lua_get_instance_id_by_char_id), luabind::def("get_instance_timer", &lua_get_instance_timer), luabind::def("get_instance_timer_by_id", &lua_get_instance_timer_by_id), luabind::def("get_characters_in_instance", &lua_get_characters_in_instance), luabind::def("assign_to_instance", &lua_assign_to_instance), + luabind::def("assign_to_instance_by_char_id", &lua_assign_to_instance_by_char_id), luabind::def("assign_group_to_instance", &lua_assign_group_to_instance), luabind::def("assign_raid_to_instance", &lua_assign_raid_to_instance), luabind::def("remove_from_instance", &lua_remove_from_instance), + luabind::def("remove_from_instance_by_char_id", &lua_remove_from_instance_by_char_id), luabind::def("remove_all_from_instance", &lua_remove_all_from_instance), luabind::def("flag_instance_by_group_leader", &lua_flag_instance_by_group_leader), luabind::def("flag_instance_by_raid_leader", &lua_flag_instance_by_raid_leader), From e367fee4bc23ec4001399820ecfc3a2ad53da48a Mon Sep 17 00:00:00 2001 From: kentai Date: Fri, 14 Dec 2018 16:24:15 +1100 Subject: [PATCH 26/27] Tidied Comments --- loginserver/options.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/loginserver/options.h b/loginserver/options.h index f215e443b..5aecbad0a 100644 --- a/loginserver/options.h +++ b/loginserver/options.h @@ -116,17 +116,17 @@ public: inline void AccountTable(std::string t) { account_table = t; } /** - * Return the value of local_network. + * Return the value of world account table. */ inline std::string GetAccountTable() const { return account_table; } /** - * Sets world account table. + * Sets world registration table. */ inline void WorldRegistrationTable(std::string t) { world_registration_table = t; } /** - * Return the value of world account table. + * Return the value of world registration table. */ inline std::string GetWorldRegistrationTable() const { return world_registration_table; } @@ -146,7 +146,7 @@ public: inline void WorldServerTypeTable(std::string t) { world_server_type_table = t; } /** - * Return the value of world admin account table. + * Return the value of world server type table. */ inline std::string GetWorldServerTypeTable() const { return world_server_type_table; } From 3a757a7a85b6ab051517b1cdcda510a465a0c317 Mon Sep 17 00:00:00 2001 From: Kinglykrab Date: Thu, 13 Dec 2018 21:44:52 -0500 Subject: [PATCH 27/27] Resolved a possible scaling issue with the way CharMaxLevel works with quest globals and data buckets. --- changelog.txt | 15 +++++++++++++++ common/eq_packet_structs.h | 1 - zone/client.cpp | 11 ++++++++++- zone/client.h | 6 +++++- zone/client_packet.cpp | 9 +++++++++ zone/exp.cpp | 32 +++++++++----------------------- 6 files changed, 48 insertions(+), 26 deletions(-) diff --git a/changelog.txt b/changelog.txt index 4b717ed5b..af3d6e7a8 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,20 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 12/15/2018 == +Kinglykrab: Added multiple new instance related quest functions. + 1. quest::GetInstanceIDByCharID(const char *zone, int16 version, uint32 char_id) + - Allows you to pull the instance ID of a client by character ID. + 2. quest::AssignToInstanceByCharID(uint16 instance_id, uint32 char_id) + - Allows you to assign an instance to a client by character ID. + 3. quest::RemoveFromInstanceByCharID(uint16 instance_id, uint32 char_id) + - Allows you to remove a client from an instance by character ID. + + Added spell buckets, similar to spell globals. + - Uses a new spell_buckets table and the Spells:EnableSpellBuckets rule. + + Added max level by data bucket. + - Uses data bucket char_id-CharMaxLevel and Character:PerCharacterBucketMaxLevel rule. + == 10/09/2018 == Uleat: Added bot owner options - usage: ^owneroption [option] (or aliased as: ^oo [option]) diff --git a/common/eq_packet_structs.h b/common/eq_packet_structs.h index bde77822b..db97818a5 100644 --- a/common/eq_packet_structs.h +++ b/common/eq_packet_structs.h @@ -306,7 +306,6 @@ union uint32 DestructibleUnk9; bool targetable_with_hotkey; bool show_name; - }; struct PlayerState_Struct { diff --git a/zone/client.cpp b/zone/client.cpp index 18940d58a..0d5ee036d 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -263,6 +263,16 @@ Client::Client(EQStreamInterface* ieqs) PendingSacrifice = false; controlling_boat_id = 0; + if (!RuleB(Character, PerCharacterQglobalMaxLevel) && !RuleB(Character, PerCharacterBucketMaxLevel)) { + SetClientMaxLevel(0); + } else if (RuleB(Character, PerCharacterQglobalMaxLevel)) { + int client_max_level = GetCharMaxLevelFromQGlobal(); + SetClientMaxLevel(client_max_level); + } else if (RuleB(Character, PerCharacterBucketMaxLevel)) { + int client_max_level = GetCharMaxLevelFromBucket(); + SetClientMaxLevel(client_max_level); + } + KarmaUpdateTimer = new Timer(RuleI(Chat, KarmaUpdateIntervalMS)); GlobalChatLimiterTimer = new Timer(RuleI(Chat, IntervalDurationMS)); AttemptedMessages = 0; @@ -1966,7 +1976,6 @@ void Client::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho) // ns->spawn.pvp = GetPVP(false) ? 1 : 0; ns->spawn.show_name = true; - strcpy(ns->spawn.title, m_pp.title); strcpy(ns->spawn.suffix, m_pp.suffix); diff --git a/zone/client.h b/zone/client.h index f7848202d..8bdb33477 100644 --- a/zone/client.h +++ b/zone/client.h @@ -697,7 +697,9 @@ public: void SendGuildJoin(GuildJoin_Struct* gj); void RefreshGuildInfo(); - + int GetClientMaxLevel() const { return client_max_level; } + void SetClientMaxLevel(int max_level) { client_max_level = max_level; } + void CheckManaEndUpdate(); void SendManaUpdate(); void SendEnduranceUpdate(); @@ -1644,6 +1646,8 @@ private: void InterrogateInventory_(bool errorcheck, Client* requester, int16 head, int16 index, const EQEmu::ItemInstance* inst, const EQEmu::ItemInstance* parent, bool log, bool silent, bool &error, int depth); bool InterrogateInventory_error(int16 head, int16 index, const EQEmu::ItemInstance* inst, const EQEmu::ItemInstance* parent, int depth); + int client_max_level; + #ifdef BOTS struct BotOwnerOptions { bool death_marquee; diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index ceb242890..18862ee1f 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -1419,6 +1419,15 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) drakkin_tattoo = m_pp.drakkin_tattoo; drakkin_details = m_pp.drakkin_details; + // Max Level for Character:PerCharacterQglobalMaxLevel and Character:PerCharacterBucketMaxLevel + int client_max_level = 0; + if (RuleB(Character, PerCharacterQglobalMaxLevel)) { + client_max_level = GetCharMaxLevelFromQGlobal(); + } else if (RuleB(Character, PerCharacterBucketMaxLevel)) { + client_max_level = GetCharMaxLevelFromBucket(); + } + SetClientMaxLevel(client_max_level); + // we know our class now, so we might have to fix our consume timer! if (class_ == MONK) consume_food_timer.SetTimer(CONSUMPTION_MNK_TIMER); diff --git a/zone/exp.cpp b/zone/exp.cpp index 302e29279..5ffdd5690 100644 --- a/zone/exp.cpp +++ b/zone/exp.cpp @@ -684,26 +684,12 @@ void Client::SetEXP(uint32 set_exp, uint32 set_aaxp, bool isrezzexp) { } } - if(RuleB(Character, PerCharacterQglobalMaxLevel)){ - uint32 MaxLevel = GetCharMaxLevelFromQGlobal(); - if(MaxLevel){ - if(GetLevel() >= MaxLevel){ - uint32 expneeded = GetEXPForLevel(MaxLevel); - if(set_exp > expneeded) { - set_exp = expneeded; - } - } - } - } - - if(RuleB(Character, PerCharacterBucketMaxLevel)){ - uint32 MaxLevel = GetCharMaxLevelFromBucket(); - if(MaxLevel){ - if(GetLevel() >= MaxLevel){ - uint32 expneeded = GetEXPForLevel(MaxLevel); - if(set_exp > expneeded) { - set_exp = expneeded; - } + if (GetClientMaxLevel() > 0) { + int client_max_level = GetClientMaxLevel(); + if (GetLevel() >= client_max_level) { + uint32 expneeded = GetEXPForLevel(client_max_level); + if(set_exp > expneeded) { + set_exp = expneeded; } } } @@ -1142,7 +1128,7 @@ uint32 Client::GetCharMaxLevelFromQGlobal() { ++gcount; } - return false; + return 0; } uint32 Client::GetCharMaxLevelFromBucket() { @@ -1151,14 +1137,14 @@ uint32 Client::GetCharMaxLevelFromBucket() { auto results = database.QueryDatabase(query); if (!results.Success()) { Log(Logs::General, Logs::Error, "Data bucket for CharMaxLevel for char ID %i failed.", char_id); - return false; + return 0; } if (results.RowCount() > 0) { auto row = results.begin(); return atoi(row[0]); } - return false; + return 0; } uint32 Client::GetRequiredAAExperience() {