diff --git a/common/eq_packet_structs.h b/common/eq_packet_structs.h index 21745ecc3..cd26fe79a 100644 --- a/common/eq_packet_structs.h +++ b/common/eq_packet_structs.h @@ -3632,17 +3632,19 @@ struct LevelAppearance_Struct { //Sends a little graphic on level up }; struct MerchantList { - uint32 id; - uint32 slot; - uint32 item; - int16 faction_required; - int8 level_required; - uint16 alt_currency_cost; - uint32 classes_required; - uint8 probability; + uint32 id; + uint32 slot; + uint32 item; + int16 faction_required; + int8 level_required; + uint8 min_status; + uint8 max_status; + uint16 alt_currency_cost; + uint32 classes_required; + uint8 probability; std::string bucket_name; std::string bucket_value; - uint8 bucket_comparison; + uint8 bucket_comparison; }; struct TempMerchantList { diff --git a/common/repositories/base/base_merchantlist_repository.h b/common/repositories/base/base_merchantlist_repository.h index 014a48919..7c9a3e8da 100644 --- a/common/repositories/base/base_merchantlist_repository.h +++ b/common/repositories/base/base_merchantlist_repository.h @@ -16,6 +16,7 @@ #include "../../strings.h" #include + class BaseMerchantlistRepository { public: struct Merchantlist { @@ -24,6 +25,8 @@ public: int32_t item; int16_t faction_required; uint8_t level_required; + uint8_t min_status; + uint8_t max_status; uint16_t alt_currency_cost; int32_t classes_required; int32_t probability; @@ -49,6 +52,8 @@ public: "item", "faction_required", "level_required", + "min_status", + "max_status", "alt_currency_cost", "classes_required", "probability", @@ -70,6 +75,8 @@ public: "item", "faction_required", "level_required", + "min_status", + "max_status", "alt_currency_cost", "classes_required", "probability", @@ -125,6 +132,8 @@ public: e.item = 0; e.faction_required = -100; e.level_required = 0; + e.min_status = 0; + e.max_status = 255; e.alt_currency_cost = 0; e.classes_required = 65535; e.probability = 100; @@ -160,8 +169,9 @@ public: { auto results = db.QueryDatabase( fmt::format( - "{} WHERE id = {} LIMIT 1", + "{} WHERE {} = {} LIMIT 1", BaseSelect(), + PrimaryKey(), merchantlist_id ) ); @@ -175,16 +185,18 @@ public: e.item = static_cast(atoi(row[2])); e.faction_required = static_cast(atoi(row[3])); e.level_required = static_cast(strtoul(row[4], nullptr, 10)); - e.alt_currency_cost = static_cast(strtoul(row[5], nullptr, 10)); - e.classes_required = static_cast(atoi(row[6])); - e.probability = static_cast(atoi(row[7])); - e.bucket_name = row[8] ? row[8] : ""; - e.bucket_value = row[9] ? row[9] : ""; - e.bucket_comparison = static_cast(strtoul(row[10], nullptr, 10)); - e.min_expansion = static_cast(atoi(row[11])); - e.max_expansion = static_cast(atoi(row[12])); - e.content_flags = row[13] ? row[13] : ""; - e.content_flags_disabled = row[14] ? row[14] : ""; + e.min_status = static_cast(strtoul(row[5], nullptr, 10)); + e.max_status = static_cast(strtoul(row[6], nullptr, 10)); + e.alt_currency_cost = static_cast(strtoul(row[7], nullptr, 10)); + e.classes_required = static_cast(atoi(row[8])); + e.probability = static_cast(atoi(row[9])); + e.bucket_name = row[10] ? row[10] : ""; + e.bucket_value = row[11] ? row[11] : ""; + e.bucket_comparison = static_cast(strtoul(row[12], nullptr, 10)); + e.min_expansion = static_cast(atoi(row[13])); + e.max_expansion = static_cast(atoi(row[14])); + e.content_flags = row[15] ? row[15] : ""; + e.content_flags_disabled = row[16] ? row[16] : ""; return e; } @@ -223,16 +235,18 @@ public: v.push_back(columns[2] + " = " + std::to_string(e.item)); v.push_back(columns[3] + " = " + std::to_string(e.faction_required)); v.push_back(columns[4] + " = " + std::to_string(e.level_required)); - v.push_back(columns[5] + " = " + std::to_string(e.alt_currency_cost)); - v.push_back(columns[6] + " = " + std::to_string(e.classes_required)); - v.push_back(columns[7] + " = " + std::to_string(e.probability)); - v.push_back(columns[8] + " = '" + Strings::Escape(e.bucket_name) + "'"); - v.push_back(columns[9] + " = '" + Strings::Escape(e.bucket_value) + "'"); - v.push_back(columns[10] + " = " + std::to_string(e.bucket_comparison)); - v.push_back(columns[11] + " = " + std::to_string(e.min_expansion)); - v.push_back(columns[12] + " = " + std::to_string(e.max_expansion)); - v.push_back(columns[13] + " = '" + Strings::Escape(e.content_flags) + "'"); - v.push_back(columns[14] + " = '" + Strings::Escape(e.content_flags_disabled) + "'"); + v.push_back(columns[5] + " = " + std::to_string(e.min_status)); + v.push_back(columns[6] + " = " + std::to_string(e.max_status)); + v.push_back(columns[7] + " = " + std::to_string(e.alt_currency_cost)); + v.push_back(columns[8] + " = " + std::to_string(e.classes_required)); + v.push_back(columns[9] + " = " + std::to_string(e.probability)); + v.push_back(columns[10] + " = '" + Strings::Escape(e.bucket_name) + "'"); + v.push_back(columns[11] + " = '" + Strings::Escape(e.bucket_value) + "'"); + v.push_back(columns[12] + " = " + std::to_string(e.bucket_comparison)); + v.push_back(columns[13] + " = " + std::to_string(e.min_expansion)); + v.push_back(columns[14] + " = " + std::to_string(e.max_expansion)); + v.push_back(columns[15] + " = '" + Strings::Escape(e.content_flags) + "'"); + v.push_back(columns[16] + " = '" + Strings::Escape(e.content_flags_disabled) + "'"); auto results = db.QueryDatabase( fmt::format( @@ -259,6 +273,8 @@ public: v.push_back(std::to_string(e.item)); v.push_back(std::to_string(e.faction_required)); v.push_back(std::to_string(e.level_required)); + v.push_back(std::to_string(e.min_status)); + v.push_back(std::to_string(e.max_status)); v.push_back(std::to_string(e.alt_currency_cost)); v.push_back(std::to_string(e.classes_required)); v.push_back(std::to_string(e.probability)); @@ -303,6 +319,8 @@ public: v.push_back(std::to_string(e.item)); v.push_back(std::to_string(e.faction_required)); v.push_back(std::to_string(e.level_required)); + v.push_back(std::to_string(e.min_status)); + v.push_back(std::to_string(e.max_status)); v.push_back(std::to_string(e.alt_currency_cost)); v.push_back(std::to_string(e.classes_required)); v.push_back(std::to_string(e.probability)); @@ -351,16 +369,18 @@ public: e.item = static_cast(atoi(row[2])); e.faction_required = static_cast(atoi(row[3])); e.level_required = static_cast(strtoul(row[4], nullptr, 10)); - e.alt_currency_cost = static_cast(strtoul(row[5], nullptr, 10)); - e.classes_required = static_cast(atoi(row[6])); - e.probability = static_cast(atoi(row[7])); - e.bucket_name = row[8] ? row[8] : ""; - e.bucket_value = row[9] ? row[9] : ""; - e.bucket_comparison = static_cast(strtoul(row[10], nullptr, 10)); - e.min_expansion = static_cast(atoi(row[11])); - e.max_expansion = static_cast(atoi(row[12])); - e.content_flags = row[13] ? row[13] : ""; - e.content_flags_disabled = row[14] ? row[14] : ""; + e.min_status = static_cast(strtoul(row[5], nullptr, 10)); + e.max_status = static_cast(strtoul(row[6], nullptr, 10)); + e.alt_currency_cost = static_cast(strtoul(row[7], nullptr, 10)); + e.classes_required = static_cast(atoi(row[8])); + e.probability = static_cast(atoi(row[9])); + e.bucket_name = row[10] ? row[10] : ""; + e.bucket_value = row[11] ? row[11] : ""; + e.bucket_comparison = static_cast(strtoul(row[12], nullptr, 10)); + e.min_expansion = static_cast(atoi(row[13])); + e.max_expansion = static_cast(atoi(row[14])); + e.content_flags = row[15] ? row[15] : ""; + e.content_flags_disabled = row[16] ? row[16] : ""; all_entries.push_back(e); } @@ -390,16 +410,18 @@ public: e.item = static_cast(atoi(row[2])); e.faction_required = static_cast(atoi(row[3])); e.level_required = static_cast(strtoul(row[4], nullptr, 10)); - e.alt_currency_cost = static_cast(strtoul(row[5], nullptr, 10)); - e.classes_required = static_cast(atoi(row[6])); - e.probability = static_cast(atoi(row[7])); - e.bucket_name = row[8] ? row[8] : ""; - e.bucket_value = row[9] ? row[9] : ""; - e.bucket_comparison = static_cast(strtoul(row[10], nullptr, 10)); - e.min_expansion = static_cast(atoi(row[11])); - e.max_expansion = static_cast(atoi(row[12])); - e.content_flags = row[13] ? row[13] : ""; - e.content_flags_disabled = row[14] ? row[14] : ""; + e.min_status = static_cast(strtoul(row[5], nullptr, 10)); + e.max_status = static_cast(strtoul(row[6], nullptr, 10)); + e.alt_currency_cost = static_cast(strtoul(row[7], nullptr, 10)); + e.classes_required = static_cast(atoi(row[8])); + e.probability = static_cast(atoi(row[9])); + e.bucket_name = row[10] ? row[10] : ""; + e.bucket_value = row[11] ? row[11] : ""; + e.bucket_comparison = static_cast(strtoul(row[12], nullptr, 10)); + e.min_expansion = static_cast(atoi(row[13])); + e.max_expansion = static_cast(atoi(row[14])); + e.content_flags = row[15] ? row[15] : ""; + e.content_flags_disabled = row[16] ? row[16] : ""; all_entries.push_back(e); } diff --git a/common/version.h b/common/version.h index 4088ac73c..0b7cbbecb 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 9218 +#define CURRENT_BINARY_DATABASE_VERSION 9219 #define CURRENT_BINARY_BOTS_DATABASE_VERSION 9037 #endif diff --git a/utils/sql/db_update_manifest.txt b/utils/sql/db_update_manifest.txt index 8ed8d0a12..9d58be4d9 100644 --- a/utils/sql/db_update_manifest.txt +++ b/utils/sql/db_update_manifest.txt @@ -472,6 +472,7 @@ 9216|2023_01_15_merc_data.sql|SHOW TABLES LIKE 'mercs'|empty| 9217|2023_01_15_chatchannel_reserved_names.sql|SHOW TABLES LIKE 'chatchannel_reserved_names'|empty| 9218|2023_01_24_item_recast.sql|show columns from character_item_recast like '%recast_type%'|contains|smallint +9219|2023_01_29_merchant_status_requirements.sql|SHOW COLUMNS FROM merchantlist LIKE 'min_status'|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/2023_01_29_merchant_status_requirements.sql b/utils/sql/git/required/2023_01_29_merchant_status_requirements.sql new file mode 100644 index 000000000..caedaa638 --- /dev/null +++ b/utils/sql/git/required/2023_01_29_merchant_status_requirements.sql @@ -0,0 +1,3 @@ +ALTER TABLE `merchantlist` +ADD COLUMN `min_status` tinyint(3) UNSIGNED NOT NULL DEFAULT 0 AFTER `level_required`, +ADD COLUMN `max_status` tinyint(3) UNSIGNED NOT NULL DEFAULT 255 AFTER `min_status`; \ No newline at end of file diff --git a/zone/client_process.cpp b/zone/client_process.cpp index ef2fe1b9e..c6ff4e02f 100644 --- a/zone/client_process.cpp +++ b/zone/client_process.cpp @@ -872,6 +872,9 @@ void Client::BulkSendMerchantInventory(int merchant_id, int npcid) { continue; } + if (!EQ::ValueWithin(Admin(), static_cast(ml.min_status), static_cast(ml.max_status))) { + continue; + } int32 faction_id = npc ? npc->GetPrimaryFaction() : 0; int32 faction_level = ( diff --git a/zone/zone.cpp b/zone/zone.cpp index 8444b1e95..0cc99481c 100644 --- a/zone/zone.cpp +++ b/zone/zone.cpp @@ -59,6 +59,7 @@ #include "zone_reload.h" #include "../common/repositories/criteria/content_filter_criteria.h" #include "../common/repositories/content_flags_repository.h" +#include "../common/repositories/merchantlist_repository.h" #include "../common/repositories/rule_sets_repository.h" #include "../common/repositories/zone_points_repository.h" #include "../common/serverinfo.h" @@ -611,45 +612,34 @@ void Zone::LoadNewMerchantData(uint32 merchantid) { std::list merchant_list; - auto query = fmt::format( - SQL( - SELECT - item, - slot, - faction_required, - level_required, - alt_currency_cost, - classes_required, - probability, - bucket_name, - bucket_value, - bucket_comparison - FROM merchantlist - WHERE merchantid = {} {} - ORDER BY slot - ), - merchantid, - ContentFilterCriteria::apply() + const auto& l = MerchantlistRepository::GetWhere( + content_db, + fmt::format( + "merchantid = {} {} ORDER BY slot", + merchantid, + ContentFilterCriteria::apply() + ) ); - auto results = content_db.QueryDatabase(query); - if (!results.Success()) { - return; + if (l.empty()) { + return; } - for (auto row : results) { + for (const auto& e : l) { MerchantList ml; - ml.id = merchantid; - ml.item = std::stoul(row[0]); - ml.slot = std::stoul(row[1]); - ml.faction_required = static_cast(std::stoi(row[2])); - ml.level_required = static_cast(std::stoul(row[3])); - ml.alt_currency_cost = static_cast(std::stoul(row[4])); - ml.classes_required = std::stoul(row[5]); - ml.probability = static_cast(std::stoul(row[6])); - ml.bucket_name = row[7]; - ml.bucket_value = row[8]; - ml.bucket_comparison = static_cast(std::stoul(row[9])); + ml.id = merchantid; + ml.item = e.item; + ml.slot = e.slot; + ml.faction_required = e.faction_required; + ml.level_required = e.level_required; + ml.min_status = e.min_status; + ml.max_status = e.max_status; + ml.alt_currency_cost = e.alt_currency_cost; + ml.classes_required = e.classes_required; + ml.probability = e.probability; + ml.bucket_name = e.bucket_name; + ml.bucket_value = e.bucket_value; + ml.bucket_comparison = e.bucket_comparison; merchant_list.push_back(ml); } @@ -665,6 +655,8 @@ void Zone::GetMerchantDataForZoneLoad() { item, faction_required, level_required, + min_status, + max_status, alt_currency_cost, classes_required, probability, @@ -725,16 +717,18 @@ void Zone::GetMerchantDataForZoneLoad() { continue; } - mle.slot = std::stoul(row[1]); - mle.item = std::stoul(row[2]); - mle.faction_required = static_cast(std::stoi(row[3])); - mle.level_required = static_cast(std::stoul(row[4])); - mle.alt_currency_cost = static_cast(std::stoul(row[5])); - mle.classes_required = std::stoul(row[6]); - mle.probability = static_cast(std::stoul(row[7])); - mle.bucket_name = row[8]; - mle.bucket_value = row[9]; - mle.bucket_comparison = static_cast(std::stoul(row[10])); + mle.slot = std::stoul(row[1]); + mle.item = std::stoul(row[2]); + mle.faction_required = static_cast(std::stoi(row[3])); + mle.level_required = static_cast(std::stoul(row[4])); + mle.min_status = static_cast(std::stoul(row[5])); + mle.max_status = static_cast(std::stoul(row[6])); + mle.alt_currency_cost = static_cast(std::stoul(row[7])); + mle.classes_required = std::stoul(row[8]); + mle.probability = static_cast(std::stoul(row[9])); + mle.bucket_name = row[10]; + mle.bucket_value = row[11]; + mle.bucket_comparison = static_cast(std::stoul(row[12])); merchant_list->second.push_back(mle); }