diff --git a/common/repositories/base/base_merc_armorinfo_repository.h b/common/repositories/base/base_merc_armorinfo_repository.h index 99e57ae08..0700ef166 100644 --- a/common/repositories/base/base_merc_armorinfo_repository.h +++ b/common/repositories/base/base_merc_armorinfo_repository.h @@ -6,7 +6,7 @@ * Any modifications to base repositories are to be made by the generator only * * @generator ./utils/scripts/generators/repository-generator.pl - * @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories + * @docs https://docs.eqemu.io/developer/repositories */ #ifndef EQEMU_BASE_MERC_ARMORINFO_REPOSITORY_H @@ -409,6 +409,80 @@ public: return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0); } + static std::string BaseReplace() + { + return fmt::format( + "REPLACE INTO {} ({}) ", + TableName(), + ColumnsRaw() + ); + } + + static int ReplaceOne( + Database& db, + const MercArmorinfo &e + ) + { + std::vector v; + + v.push_back(std::to_string(e.id)); + v.push_back(std::to_string(e.merc_npc_type_id)); + v.push_back(std::to_string(e.minlevel)); + v.push_back(std::to_string(e.maxlevel)); + v.push_back(std::to_string(e.texture)); + v.push_back(std::to_string(e.helmtexture)); + v.push_back(std::to_string(e.armortint_id)); + v.push_back(std::to_string(e.armortint_red)); + v.push_back(std::to_string(e.armortint_green)); + v.push_back(std::to_string(e.armortint_blue)); + + auto results = db.QueryDatabase( + fmt::format( + "{} VALUES ({})", + BaseReplace(), + Strings::Implode(",", v) + ) + ); + + return (results.Success() ? results.RowsAffected() : 0); + } + + static int ReplaceMany( + Database& db, + const std::vector &entries + ) + { + std::vector insert_chunks; + + for (auto &e: entries) { + std::vector v; + + v.push_back(std::to_string(e.id)); + v.push_back(std::to_string(e.merc_npc_type_id)); + v.push_back(std::to_string(e.minlevel)); + v.push_back(std::to_string(e.maxlevel)); + v.push_back(std::to_string(e.texture)); + v.push_back(std::to_string(e.helmtexture)); + v.push_back(std::to_string(e.armortint_id)); + v.push_back(std::to_string(e.armortint_red)); + v.push_back(std::to_string(e.armortint_green)); + v.push_back(std::to_string(e.armortint_blue)); + + insert_chunks.push_back("(" + Strings::Implode(",", v) + ")"); + } + + std::vector v; + + auto results = db.QueryDatabase( + fmt::format( + "{} VALUES {}", + BaseReplace(), + Strings::Implode(",", insert_chunks) + ) + ); + + return (results.Success() ? results.RowsAffected() : 0); + } }; #endif //EQEMU_BASE_MERC_ARMORINFO_REPOSITORY_H diff --git a/common/repositories/base/base_merc_inventory_repository.h b/common/repositories/base/base_merc_inventory_repository.h index 216d0c5d6..abb677843 100644 --- a/common/repositories/base/base_merc_inventory_repository.h +++ b/common/repositories/base/base_merc_inventory_repository.h @@ -6,7 +6,7 @@ * Any modifications to base repositories are to be made by the generator only * * @generator ./utils/scripts/generators/repository-generator.pl - * @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories + * @docs https://docs.eqemu.io/developer/repositories */ #ifndef EQEMU_BASE_MERC_INVENTORY_REPOSITORY_H @@ -359,6 +359,70 @@ public: return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0); } + static std::string BaseReplace() + { + return fmt::format( + "REPLACE INTO {} ({}) ", + TableName(), + ColumnsRaw() + ); + } + + static int ReplaceOne( + Database& db, + const MercInventory &e + ) + { + std::vector v; + + v.push_back(std::to_string(e.merc_inventory_id)); + v.push_back(std::to_string(e.merc_subtype_id)); + v.push_back(std::to_string(e.item_id)); + v.push_back(std::to_string(e.min_level)); + v.push_back(std::to_string(e.max_level)); + + auto results = db.QueryDatabase( + fmt::format( + "{} VALUES ({})", + BaseReplace(), + Strings::Implode(",", v) + ) + ); + + return (results.Success() ? results.RowsAffected() : 0); + } + + static int ReplaceMany( + Database& db, + const std::vector &entries + ) + { + std::vector insert_chunks; + + for (auto &e: entries) { + std::vector v; + + v.push_back(std::to_string(e.merc_inventory_id)); + v.push_back(std::to_string(e.merc_subtype_id)); + v.push_back(std::to_string(e.item_id)); + v.push_back(std::to_string(e.min_level)); + v.push_back(std::to_string(e.max_level)); + + insert_chunks.push_back("(" + Strings::Implode(",", v) + ")"); + } + + std::vector v; + + auto results = db.QueryDatabase( + fmt::format( + "{} VALUES {}", + BaseReplace(), + Strings::Implode(",", insert_chunks) + ) + ); + + return (results.Success() ? results.RowsAffected() : 0); + } }; #endif //EQEMU_BASE_MERC_INVENTORY_REPOSITORY_H diff --git a/common/repositories/base/base_merc_merchant_entries_repository.h b/common/repositories/base/base_merc_merchant_entries_repository.h index b6ba9ebcf..5816a37bc 100644 --- a/common/repositories/base/base_merc_merchant_entries_repository.h +++ b/common/repositories/base/base_merc_merchant_entries_repository.h @@ -6,7 +6,7 @@ * Any modifications to base repositories are to be made by the generator only * * @generator ./utils/scripts/generators/repository-generator.pl - * @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories + * @docs https://docs.eqemu.io/developer/repositories */ #ifndef EQEMU_BASE_MERC_MERCHANT_ENTRIES_REPOSITORY_H @@ -339,6 +339,66 @@ public: return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0); } + static std::string BaseReplace() + { + return fmt::format( + "REPLACE INTO {} ({}) ", + TableName(), + ColumnsRaw() + ); + } + + static int ReplaceOne( + Database& db, + const MercMerchantEntries &e + ) + { + std::vector v; + + v.push_back(std::to_string(e.merc_merchant_entry_id)); + v.push_back(std::to_string(e.merc_merchant_template_id)); + v.push_back(std::to_string(e.merchant_id)); + + auto results = db.QueryDatabase( + fmt::format( + "{} VALUES ({})", + BaseReplace(), + Strings::Implode(",", v) + ) + ); + + return (results.Success() ? results.RowsAffected() : 0); + } + + static int ReplaceMany( + Database& db, + const std::vector &entries + ) + { + std::vector insert_chunks; + + for (auto &e: entries) { + std::vector v; + + v.push_back(std::to_string(e.merc_merchant_entry_id)); + v.push_back(std::to_string(e.merc_merchant_template_id)); + v.push_back(std::to_string(e.merchant_id)); + + insert_chunks.push_back("(" + Strings::Implode(",", v) + ")"); + } + + std::vector v; + + auto results = db.QueryDatabase( + fmt::format( + "{} VALUES {}", + BaseReplace(), + Strings::Implode(",", insert_chunks) + ) + ); + + return (results.Success() ? results.RowsAffected() : 0); + } }; #endif //EQEMU_BASE_MERC_MERCHANT_ENTRIES_REPOSITORY_H diff --git a/common/repositories/base/base_merc_merchant_template_entries_repository.h b/common/repositories/base/base_merc_merchant_template_entries_repository.h index 26ed3b9d6..0d863a7d7 100644 --- a/common/repositories/base/base_merc_merchant_template_entries_repository.h +++ b/common/repositories/base/base_merc_merchant_template_entries_repository.h @@ -6,7 +6,7 @@ * Any modifications to base repositories are to be made by the generator only * * @generator ./utils/scripts/generators/repository-generator.pl - * @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories + * @docs https://docs.eqemu.io/developer/repositories */ #ifndef EQEMU_BASE_MERC_MERCHANT_TEMPLATE_ENTRIES_REPOSITORY_H @@ -339,6 +339,66 @@ public: return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0); } + static std::string BaseReplace() + { + return fmt::format( + "REPLACE INTO {} ({}) ", + TableName(), + ColumnsRaw() + ); + } + + static int ReplaceOne( + Database& db, + const MercMerchantTemplateEntries &e + ) + { + std::vector v; + + v.push_back(std::to_string(e.merc_merchant_template_entry_id)); + v.push_back(std::to_string(e.merc_merchant_template_id)); + v.push_back(std::to_string(e.merc_template_id)); + + auto results = db.QueryDatabase( + fmt::format( + "{} VALUES ({})", + BaseReplace(), + Strings::Implode(",", v) + ) + ); + + return (results.Success() ? results.RowsAffected() : 0); + } + + static int ReplaceMany( + Database& db, + const std::vector &entries + ) + { + std::vector insert_chunks; + + for (auto &e: entries) { + std::vector v; + + v.push_back(std::to_string(e.merc_merchant_template_entry_id)); + v.push_back(std::to_string(e.merc_merchant_template_id)); + v.push_back(std::to_string(e.merc_template_id)); + + insert_chunks.push_back("(" + Strings::Implode(",", v) + ")"); + } + + std::vector v; + + auto results = db.QueryDatabase( + fmt::format( + "{} VALUES {}", + BaseReplace(), + Strings::Implode(",", insert_chunks) + ) + ); + + return (results.Success() ? results.RowsAffected() : 0); + } }; #endif //EQEMU_BASE_MERC_MERCHANT_TEMPLATE_ENTRIES_REPOSITORY_H diff --git a/common/repositories/base/base_merc_merchant_templates_repository.h b/common/repositories/base/base_merc_merchant_templates_repository.h index 84b61815f..f009a04c2 100644 --- a/common/repositories/base/base_merc_merchant_templates_repository.h +++ b/common/repositories/base/base_merc_merchant_templates_repository.h @@ -6,7 +6,7 @@ * Any modifications to base repositories are to be made by the generator only * * @generator ./utils/scripts/generators/repository-generator.pl - * @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories + * @docs https://docs.eqemu.io/developer/repositories */ #ifndef EQEMU_BASE_MERC_MERCHANT_TEMPLATES_REPOSITORY_H @@ -339,6 +339,66 @@ public: return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0); } + static std::string BaseReplace() + { + return fmt::format( + "REPLACE INTO {} ({}) ", + TableName(), + ColumnsRaw() + ); + } + + static int ReplaceOne( + Database& db, + const MercMerchantTemplates &e + ) + { + std::vector v; + + v.push_back(std::to_string(e.merc_merchant_template_id)); + v.push_back("'" + Strings::Escape(e.name) + "'"); + v.push_back("'" + Strings::Escape(e.qglobal) + "'"); + + auto results = db.QueryDatabase( + fmt::format( + "{} VALUES ({})", + BaseReplace(), + Strings::Implode(",", v) + ) + ); + + return (results.Success() ? results.RowsAffected() : 0); + } + + static int ReplaceMany( + Database& db, + const std::vector &entries + ) + { + std::vector insert_chunks; + + for (auto &e: entries) { + std::vector v; + + v.push_back(std::to_string(e.merc_merchant_template_id)); + v.push_back("'" + Strings::Escape(e.name) + "'"); + v.push_back("'" + Strings::Escape(e.qglobal) + "'"); + + insert_chunks.push_back("(" + Strings::Implode(",", v) + ")"); + } + + std::vector v; + + auto results = db.QueryDatabase( + fmt::format( + "{} VALUES {}", + BaseReplace(), + Strings::Implode(",", insert_chunks) + ) + ); + + return (results.Success() ? results.RowsAffected() : 0); + } }; #endif //EQEMU_BASE_MERC_MERCHANT_TEMPLATES_REPOSITORY_H diff --git a/common/repositories/base/base_merc_name_types_repository.h b/common/repositories/base/base_merc_name_types_repository.h index 9ed66f376..281450cc7 100644 --- a/common/repositories/base/base_merc_name_types_repository.h +++ b/common/repositories/base/base_merc_name_types_repository.h @@ -6,7 +6,7 @@ * Any modifications to base repositories are to be made by the generator only * * @generator ./utils/scripts/generators/repository-generator.pl - * @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories + * @docs https://docs.eqemu.io/developer/repositories */ #ifndef EQEMU_BASE_MERC_NAME_TYPES_REPOSITORY_H @@ -350,6 +350,68 @@ public: return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0); } + static std::string BaseReplace() + { + return fmt::format( + "REPLACE INTO {} ({}) ", + TableName(), + ColumnsRaw() + ); + } + + static int ReplaceOne( + Database& db, + const MercNameTypes &e + ) + { + std::vector v; + + v.push_back(std::to_string(e.name_type_id)); + v.push_back(std::to_string(e.class_id)); + v.push_back("'" + Strings::Escape(e.prefix) + "'"); + v.push_back("'" + Strings::Escape(e.suffix) + "'"); + + auto results = db.QueryDatabase( + fmt::format( + "{} VALUES ({})", + BaseReplace(), + Strings::Implode(",", v) + ) + ); + + return (results.Success() ? results.RowsAffected() : 0); + } + + static int ReplaceMany( + Database& db, + const std::vector &entries + ) + { + std::vector insert_chunks; + + for (auto &e: entries) { + std::vector v; + + v.push_back(std::to_string(e.name_type_id)); + v.push_back(std::to_string(e.class_id)); + v.push_back("'" + Strings::Escape(e.prefix) + "'"); + v.push_back("'" + Strings::Escape(e.suffix) + "'"); + + insert_chunks.push_back("(" + Strings::Implode(",", v) + ")"); + } + + std::vector v; + + auto results = db.QueryDatabase( + fmt::format( + "{} VALUES {}", + BaseReplace(), + Strings::Implode(",", insert_chunks) + ) + ); + + return (results.Success() ? results.RowsAffected() : 0); + } }; #endif //EQEMU_BASE_MERC_NAME_TYPES_REPOSITORY_H diff --git a/common/repositories/base/base_merc_npc_types_repository.h b/common/repositories/base/base_merc_npc_types_repository.h index c224656dd..6209dd171 100644 --- a/common/repositories/base/base_merc_npc_types_repository.h +++ b/common/repositories/base/base_merc_npc_types_repository.h @@ -6,7 +6,7 @@ * Any modifications to base repositories are to be made by the generator only * * @generator ./utils/scripts/generators/repository-generator.pl - * @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories + * @docs https://docs.eqemu.io/developer/repositories */ #ifndef EQEMU_BASE_MERC_NPC_TYPES_REPOSITORY_H @@ -359,6 +359,70 @@ public: return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0); } + static std::string BaseReplace() + { + return fmt::format( + "REPLACE INTO {} ({}) ", + TableName(), + ColumnsRaw() + ); + } + + static int ReplaceOne( + Database& db, + const MercNpcTypes &e + ) + { + std::vector v; + + v.push_back(std::to_string(e.merc_npc_type_id)); + v.push_back(std::to_string(e.proficiency_id)); + v.push_back(std::to_string(e.tier_id)); + v.push_back(std::to_string(e.class_id)); + v.push_back("'" + Strings::Escape(e.name) + "'"); + + auto results = db.QueryDatabase( + fmt::format( + "{} VALUES ({})", + BaseReplace(), + Strings::Implode(",", v) + ) + ); + + return (results.Success() ? results.RowsAffected() : 0); + } + + static int ReplaceMany( + Database& db, + const std::vector &entries + ) + { + std::vector insert_chunks; + + for (auto &e: entries) { + std::vector v; + + v.push_back(std::to_string(e.merc_npc_type_id)); + v.push_back(std::to_string(e.proficiency_id)); + v.push_back(std::to_string(e.tier_id)); + v.push_back(std::to_string(e.class_id)); + v.push_back("'" + Strings::Escape(e.name) + "'"); + + insert_chunks.push_back("(" + Strings::Implode(",", v) + ")"); + } + + std::vector v; + + auto results = db.QueryDatabase( + fmt::format( + "{} VALUES {}", + BaseReplace(), + Strings::Implode(",", insert_chunks) + ) + ); + + return (results.Success() ? results.RowsAffected() : 0); + } }; #endif //EQEMU_BASE_MERC_NPC_TYPES_REPOSITORY_H diff --git a/common/repositories/base/base_merc_spell_list_entries_repository.h b/common/repositories/base/base_merc_spell_list_entries_repository.h index 8c8e249ce..ebb9b71c6 100644 --- a/common/repositories/base/base_merc_spell_list_entries_repository.h +++ b/common/repositories/base/base_merc_spell_list_entries_repository.h @@ -6,7 +6,7 @@ * Any modifications to base repositories are to be made by the generator only * * @generator ./utils/scripts/generators/repository-generator.pl - * @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories + * @docs https://docs.eqemu.io/developer/repositories */ #ifndef EQEMU_BASE_MERC_SPELL_LIST_ENTRIES_REPOSITORY_H @@ -399,6 +399,78 @@ public: return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0); } + static std::string BaseReplace() + { + return fmt::format( + "REPLACE INTO {} ({}) ", + TableName(), + ColumnsRaw() + ); + } + + static int ReplaceOne( + Database& db, + const MercSpellListEntries &e + ) + { + std::vector v; + + v.push_back(std::to_string(e.merc_spell_list_entry_id)); + v.push_back(std::to_string(e.merc_spell_list_id)); + v.push_back(std::to_string(e.spell_id)); + v.push_back(std::to_string(e.spell_type)); + v.push_back(std::to_string(e.stance_id)); + v.push_back(std::to_string(e.minlevel)); + v.push_back(std::to_string(e.maxlevel)); + v.push_back(std::to_string(e.slot)); + v.push_back(std::to_string(e.procChance)); + + auto results = db.QueryDatabase( + fmt::format( + "{} VALUES ({})", + BaseReplace(), + Strings::Implode(",", v) + ) + ); + + return (results.Success() ? results.RowsAffected() : 0); + } + + static int ReplaceMany( + Database& db, + const std::vector &entries + ) + { + std::vector insert_chunks; + + for (auto &e: entries) { + std::vector v; + + v.push_back(std::to_string(e.merc_spell_list_entry_id)); + v.push_back(std::to_string(e.merc_spell_list_id)); + v.push_back(std::to_string(e.spell_id)); + v.push_back(std::to_string(e.spell_type)); + v.push_back(std::to_string(e.stance_id)); + v.push_back(std::to_string(e.minlevel)); + v.push_back(std::to_string(e.maxlevel)); + v.push_back(std::to_string(e.slot)); + v.push_back(std::to_string(e.procChance)); + + insert_chunks.push_back("(" + Strings::Implode(",", v) + ")"); + } + + std::vector v; + + auto results = db.QueryDatabase( + fmt::format( + "{} VALUES {}", + BaseReplace(), + Strings::Implode(",", insert_chunks) + ) + ); + + return (results.Success() ? results.RowsAffected() : 0); + } }; #endif //EQEMU_BASE_MERC_SPELL_LIST_ENTRIES_REPOSITORY_H diff --git a/common/repositories/base/base_merc_spell_lists_repository.h b/common/repositories/base/base_merc_spell_lists_repository.h index 36b560d5d..093fb66cc 100644 --- a/common/repositories/base/base_merc_spell_lists_repository.h +++ b/common/repositories/base/base_merc_spell_lists_repository.h @@ -6,7 +6,7 @@ * Any modifications to base repositories are to be made by the generator only * * @generator ./utils/scripts/generators/repository-generator.pl - * @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories + * @docs https://docs.eqemu.io/developer/repositories */ #ifndef EQEMU_BASE_MERC_SPELL_LISTS_REPOSITORY_H @@ -349,6 +349,68 @@ public: return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0); } + static std::string BaseReplace() + { + return fmt::format( + "REPLACE INTO {} ({}) ", + TableName(), + ColumnsRaw() + ); + } + + static int ReplaceOne( + Database& db, + const MercSpellLists &e + ) + { + std::vector v; + + v.push_back(std::to_string(e.merc_spell_list_id)); + v.push_back(std::to_string(e.class_id)); + v.push_back(std::to_string(e.proficiency_id)); + v.push_back("'" + Strings::Escape(e.name) + "'"); + + auto results = db.QueryDatabase( + fmt::format( + "{} VALUES ({})", + BaseReplace(), + Strings::Implode(",", v) + ) + ); + + return (results.Success() ? results.RowsAffected() : 0); + } + + static int ReplaceMany( + Database& db, + const std::vector &entries + ) + { + std::vector insert_chunks; + + for (auto &e: entries) { + std::vector v; + + v.push_back(std::to_string(e.merc_spell_list_id)); + v.push_back(std::to_string(e.class_id)); + v.push_back(std::to_string(e.proficiency_id)); + v.push_back("'" + Strings::Escape(e.name) + "'"); + + insert_chunks.push_back("(" + Strings::Implode(",", v) + ")"); + } + + std::vector v; + + auto results = db.QueryDatabase( + fmt::format( + "{} VALUES {}", + BaseReplace(), + Strings::Implode(",", insert_chunks) + ) + ); + + return (results.Success() ? results.RowsAffected() : 0); + } }; #endif //EQEMU_BASE_MERC_SPELL_LISTS_REPOSITORY_H diff --git a/common/repositories/base/base_merc_stance_entries_repository.h b/common/repositories/base/base_merc_stance_entries_repository.h index f2d96e7bd..6655bdf8f 100644 --- a/common/repositories/base/base_merc_stance_entries_repository.h +++ b/common/repositories/base/base_merc_stance_entries_repository.h @@ -6,7 +6,7 @@ * Any modifications to base repositories are to be made by the generator only * * @generator ./utils/scripts/generators/repository-generator.pl - * @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories + * @docs https://docs.eqemu.io/developer/repositories */ #ifndef EQEMU_BASE_MERC_STANCE_ENTRIES_REPOSITORY_H @@ -359,6 +359,70 @@ public: return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0); } + static std::string BaseReplace() + { + return fmt::format( + "REPLACE INTO {} ({}) ", + TableName(), + ColumnsRaw() + ); + } + + static int ReplaceOne( + Database& db, + const MercStanceEntries &e + ) + { + std::vector v; + + v.push_back(std::to_string(e.merc_stance_entry_id)); + v.push_back(std::to_string(e.class_id)); + v.push_back(std::to_string(e.proficiency_id)); + v.push_back(std::to_string(e.stance_id)); + v.push_back(std::to_string(e.isdefault)); + + auto results = db.QueryDatabase( + fmt::format( + "{} VALUES ({})", + BaseReplace(), + Strings::Implode(",", v) + ) + ); + + return (results.Success() ? results.RowsAffected() : 0); + } + + static int ReplaceMany( + Database& db, + const std::vector &entries + ) + { + std::vector insert_chunks; + + for (auto &e: entries) { + std::vector v; + + v.push_back(std::to_string(e.merc_stance_entry_id)); + v.push_back(std::to_string(e.class_id)); + v.push_back(std::to_string(e.proficiency_id)); + v.push_back(std::to_string(e.stance_id)); + v.push_back(std::to_string(e.isdefault)); + + insert_chunks.push_back("(" + Strings::Implode(",", v) + ")"); + } + + std::vector v; + + auto results = db.QueryDatabase( + fmt::format( + "{} VALUES {}", + BaseReplace(), + Strings::Implode(",", insert_chunks) + ) + ); + + return (results.Success() ? results.RowsAffected() : 0); + } }; #endif //EQEMU_BASE_MERC_STANCE_ENTRIES_REPOSITORY_H diff --git a/common/repositories/base/base_merc_stats_repository.h b/common/repositories/base/base_merc_stats_repository.h index 55ada42e9..eb082b689 100644 --- a/common/repositories/base/base_merc_stats_repository.h +++ b/common/repositories/base/base_merc_stats_repository.h @@ -6,7 +6,7 @@ * Any modifications to base repositories are to be made by the generator only * * @generator ./utils/scripts/generators/repository-generator.pl - * @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories + * @docs https://docs.eqemu.io/developer/repositories */ #ifndef EQEMU_BASE_MERC_STATS_REPOSITORY_H @@ -640,6 +640,126 @@ public: return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0); } + static std::string BaseReplace() + { + return fmt::format( + "REPLACE INTO {} ({}) ", + TableName(), + ColumnsRaw() + ); + } + + static int ReplaceOne( + Database& db, + const MercStats &e + ) + { + std::vector v; + + v.push_back(std::to_string(e.merc_npc_type_id)); + v.push_back(std::to_string(e.clientlevel)); + v.push_back(std::to_string(e.level)); + v.push_back(std::to_string(e.hp)); + v.push_back(std::to_string(e.mana)); + v.push_back(std::to_string(e.AC)); + v.push_back(std::to_string(e.ATK)); + v.push_back(std::to_string(e.STR)); + v.push_back(std::to_string(e.STA)); + v.push_back(std::to_string(e.DEX)); + v.push_back(std::to_string(e.AGI)); + v.push_back(std::to_string(e._INT)); + v.push_back(std::to_string(e.WIS)); + v.push_back(std::to_string(e.CHA)); + v.push_back(std::to_string(e.MR)); + v.push_back(std::to_string(e.CR)); + v.push_back(std::to_string(e.DR)); + v.push_back(std::to_string(e.FR)); + v.push_back(std::to_string(e.PR)); + v.push_back(std::to_string(e.Corrup)); + v.push_back(std::to_string(e.mindmg)); + v.push_back(std::to_string(e.maxdmg)); + v.push_back(std::to_string(e.attack_count)); + v.push_back(std::to_string(e.attack_speed)); + v.push_back(std::to_string(e.attack_delay)); + v.push_back("'" + Strings::Escape(e.special_abilities) + "'"); + v.push_back(std::to_string(e.Accuracy)); + v.push_back(std::to_string(e.hp_regen_rate)); + v.push_back(std::to_string(e.mana_regen_rate)); + v.push_back(std::to_string(e.runspeed)); + v.push_back(std::to_string(e.statscale)); + v.push_back(std::to_string(e.spellscale)); + v.push_back(std::to_string(e.healscale)); + + auto results = db.QueryDatabase( + fmt::format( + "{} VALUES ({})", + BaseReplace(), + Strings::Implode(",", v) + ) + ); + + return (results.Success() ? results.RowsAffected() : 0); + } + + static int ReplaceMany( + Database& db, + const std::vector &entries + ) + { + std::vector insert_chunks; + + for (auto &e: entries) { + std::vector v; + + v.push_back(std::to_string(e.merc_npc_type_id)); + v.push_back(std::to_string(e.clientlevel)); + v.push_back(std::to_string(e.level)); + v.push_back(std::to_string(e.hp)); + v.push_back(std::to_string(e.mana)); + v.push_back(std::to_string(e.AC)); + v.push_back(std::to_string(e.ATK)); + v.push_back(std::to_string(e.STR)); + v.push_back(std::to_string(e.STA)); + v.push_back(std::to_string(e.DEX)); + v.push_back(std::to_string(e.AGI)); + v.push_back(std::to_string(e._INT)); + v.push_back(std::to_string(e.WIS)); + v.push_back(std::to_string(e.CHA)); + v.push_back(std::to_string(e.MR)); + v.push_back(std::to_string(e.CR)); + v.push_back(std::to_string(e.DR)); + v.push_back(std::to_string(e.FR)); + v.push_back(std::to_string(e.PR)); + v.push_back(std::to_string(e.Corrup)); + v.push_back(std::to_string(e.mindmg)); + v.push_back(std::to_string(e.maxdmg)); + v.push_back(std::to_string(e.attack_count)); + v.push_back(std::to_string(e.attack_speed)); + v.push_back(std::to_string(e.attack_delay)); + v.push_back("'" + Strings::Escape(e.special_abilities) + "'"); + v.push_back(std::to_string(e.Accuracy)); + v.push_back(std::to_string(e.hp_regen_rate)); + v.push_back(std::to_string(e.mana_regen_rate)); + v.push_back(std::to_string(e.runspeed)); + v.push_back(std::to_string(e.statscale)); + v.push_back(std::to_string(e.spellscale)); + v.push_back(std::to_string(e.healscale)); + + insert_chunks.push_back("(" + Strings::Implode(",", v) + ")"); + } + + std::vector v; + + auto results = db.QueryDatabase( + fmt::format( + "{} VALUES {}", + BaseReplace(), + Strings::Implode(",", insert_chunks) + ) + ); + + return (results.Success() ? results.RowsAffected() : 0); + } }; #endif //EQEMU_BASE_MERC_STATS_REPOSITORY_H diff --git a/common/repositories/base/base_merc_subtypes_repository.h b/common/repositories/base/base_merc_subtypes_repository.h index 6dca32444..84b828b43 100644 --- a/common/repositories/base/base_merc_subtypes_repository.h +++ b/common/repositories/base/base_merc_subtypes_repository.h @@ -6,7 +6,7 @@ * Any modifications to base repositories are to be made by the generator only * * @generator ./utils/scripts/generators/repository-generator.pl - * @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories + * @docs https://docs.eqemu.io/developer/repositories */ #ifndef EQEMU_BASE_MERC_SUBTYPES_REPOSITORY_H @@ -349,6 +349,68 @@ public: return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0); } + static std::string BaseReplace() + { + return fmt::format( + "REPLACE INTO {} ({}) ", + TableName(), + ColumnsRaw() + ); + } + + static int ReplaceOne( + Database& db, + const MercSubtypes &e + ) + { + std::vector v; + + v.push_back(std::to_string(e.merc_subtype_id)); + v.push_back(std::to_string(e.class_id)); + v.push_back(std::to_string(e.tier_id)); + v.push_back(std::to_string(e.confidence_id)); + + auto results = db.QueryDatabase( + fmt::format( + "{} VALUES ({})", + BaseReplace(), + Strings::Implode(",", v) + ) + ); + + return (results.Success() ? results.RowsAffected() : 0); + } + + static int ReplaceMany( + Database& db, + const std::vector &entries + ) + { + std::vector insert_chunks; + + for (auto &e: entries) { + std::vector v; + + v.push_back(std::to_string(e.merc_subtype_id)); + v.push_back(std::to_string(e.class_id)); + v.push_back(std::to_string(e.tier_id)); + v.push_back(std::to_string(e.confidence_id)); + + insert_chunks.push_back("(" + Strings::Implode(",", v) + ")"); + } + + std::vector v; + + auto results = db.QueryDatabase( + fmt::format( + "{} VALUES {}", + BaseReplace(), + Strings::Implode(",", insert_chunks) + ) + ); + + return (results.Success() ? results.RowsAffected() : 0); + } }; #endif //EQEMU_BASE_MERC_SUBTYPES_REPOSITORY_H diff --git a/common/repositories/base/base_merc_templates_repository.h b/common/repositories/base/base_merc_templates_repository.h index bf63c8554..41d207429 100644 --- a/common/repositories/base/base_merc_templates_repository.h +++ b/common/repositories/base/base_merc_templates_repository.h @@ -6,7 +6,7 @@ * Any modifications to base repositories are to be made by the generator only * * @generator ./utils/scripts/generators/repository-generator.pl - * @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories + * @docs https://docs.eqemu.io/developer/repositories */ #ifndef EQEMU_BASE_MERC_TEMPLATES_REPOSITORY_H @@ -379,6 +379,74 @@ public: return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0); } + static std::string BaseReplace() + { + return fmt::format( + "REPLACE INTO {} ({}) ", + TableName(), + ColumnsRaw() + ); + } + + static int ReplaceOne( + Database& db, + const MercTemplates &e + ) + { + std::vector v; + + v.push_back(std::to_string(e.merc_template_id)); + v.push_back(std::to_string(e.merc_type_id)); + v.push_back(std::to_string(e.merc_subtype_id)); + v.push_back(std::to_string(e.merc_npc_type_id)); + v.push_back("'" + Strings::Escape(e.dbstring) + "'"); + v.push_back(std::to_string(e.name_type_id)); + v.push_back(std::to_string(e.clientversion)); + + auto results = db.QueryDatabase( + fmt::format( + "{} VALUES ({})", + BaseReplace(), + Strings::Implode(",", v) + ) + ); + + return (results.Success() ? results.RowsAffected() : 0); + } + + static int ReplaceMany( + Database& db, + const std::vector &entries + ) + { + std::vector insert_chunks; + + for (auto &e: entries) { + std::vector v; + + v.push_back(std::to_string(e.merc_template_id)); + v.push_back(std::to_string(e.merc_type_id)); + v.push_back(std::to_string(e.merc_subtype_id)); + v.push_back(std::to_string(e.merc_npc_type_id)); + v.push_back("'" + Strings::Escape(e.dbstring) + "'"); + v.push_back(std::to_string(e.name_type_id)); + v.push_back(std::to_string(e.clientversion)); + + insert_chunks.push_back("(" + Strings::Implode(",", v) + ")"); + } + + std::vector v; + + auto results = db.QueryDatabase( + fmt::format( + "{} VALUES {}", + BaseReplace(), + Strings::Implode(",", insert_chunks) + ) + ); + + return (results.Success() ? results.RowsAffected() : 0); + } }; #endif //EQEMU_BASE_MERC_TEMPLATES_REPOSITORY_H diff --git a/common/repositories/base/base_merc_types_repository.h b/common/repositories/base/base_merc_types_repository.h index 35fa5735b..aeb47806d 100644 --- a/common/repositories/base/base_merc_types_repository.h +++ b/common/repositories/base/base_merc_types_repository.h @@ -6,7 +6,7 @@ * Any modifications to base repositories are to be made by the generator only * * @generator ./utils/scripts/generators/repository-generator.pl - * @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories + * @docs https://docs.eqemu.io/developer/repositories */ #ifndef EQEMU_BASE_MERC_TYPES_REPOSITORY_H @@ -359,6 +359,70 @@ public: return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0); } + static std::string BaseReplace() + { + return fmt::format( + "REPLACE INTO {} ({}) ", + TableName(), + ColumnsRaw() + ); + } + + static int ReplaceOne( + Database& db, + const MercTypes &e + ) + { + std::vector v; + + v.push_back(std::to_string(e.merc_type_id)); + v.push_back(std::to_string(e.race_id)); + v.push_back(std::to_string(e.proficiency_id)); + v.push_back("'" + Strings::Escape(e.dbstring) + "'"); + v.push_back(std::to_string(e.clientversion)); + + auto results = db.QueryDatabase( + fmt::format( + "{} VALUES ({})", + BaseReplace(), + Strings::Implode(",", v) + ) + ); + + return (results.Success() ? results.RowsAffected() : 0); + } + + static int ReplaceMany( + Database& db, + const std::vector &entries + ) + { + std::vector insert_chunks; + + for (auto &e: entries) { + std::vector v; + + v.push_back(std::to_string(e.merc_type_id)); + v.push_back(std::to_string(e.race_id)); + v.push_back(std::to_string(e.proficiency_id)); + v.push_back("'" + Strings::Escape(e.dbstring) + "'"); + v.push_back(std::to_string(e.clientversion)); + + insert_chunks.push_back("(" + Strings::Implode(",", v) + ")"); + } + + std::vector v; + + auto results = db.QueryDatabase( + fmt::format( + "{} VALUES {}", + BaseReplace(), + Strings::Implode(",", insert_chunks) + ) + ); + + return (results.Success() ? results.RowsAffected() : 0); + } }; #endif //EQEMU_BASE_MERC_TYPES_REPOSITORY_H diff --git a/common/repositories/base/base_merc_weaponinfo_repository.h b/common/repositories/base/base_merc_weaponinfo_repository.h index 6ebe444bc..07a7b86c6 100644 --- a/common/repositories/base/base_merc_weaponinfo_repository.h +++ b/common/repositories/base/base_merc_weaponinfo_repository.h @@ -6,7 +6,7 @@ * Any modifications to base repositories are to be made by the generator only * * @generator ./utils/scripts/generators/repository-generator.pl - * @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories + * @docs https://docs.eqemu.io/developer/repositories */ #ifndef EQEMU_BASE_MERC_WEAPONINFO_REPOSITORY_H @@ -389,6 +389,76 @@ public: return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0); } + static std::string BaseReplace() + { + return fmt::format( + "REPLACE INTO {} ({}) ", + TableName(), + ColumnsRaw() + ); + } + + static int ReplaceOne( + Database& db, + const MercWeaponinfo &e + ) + { + std::vector v; + + v.push_back(std::to_string(e.id)); + v.push_back(std::to_string(e.merc_npc_type_id)); + v.push_back(std::to_string(e.minlevel)); + v.push_back(std::to_string(e.maxlevel)); + v.push_back(std::to_string(e.d_melee_texture1)); + v.push_back(std::to_string(e.d_melee_texture2)); + v.push_back(std::to_string(e.prim_melee_type)); + v.push_back(std::to_string(e.sec_melee_type)); + + auto results = db.QueryDatabase( + fmt::format( + "{} VALUES ({})", + BaseReplace(), + Strings::Implode(",", v) + ) + ); + + return (results.Success() ? results.RowsAffected() : 0); + } + + static int ReplaceMany( + Database& db, + const std::vector &entries + ) + { + std::vector insert_chunks; + + for (auto &e: entries) { + std::vector v; + + v.push_back(std::to_string(e.id)); + v.push_back(std::to_string(e.merc_npc_type_id)); + v.push_back(std::to_string(e.minlevel)); + v.push_back(std::to_string(e.maxlevel)); + v.push_back(std::to_string(e.d_melee_texture1)); + v.push_back(std::to_string(e.d_melee_texture2)); + v.push_back(std::to_string(e.prim_melee_type)); + v.push_back(std::to_string(e.sec_melee_type)); + + insert_chunks.push_back("(" + Strings::Implode(",", v) + ")"); + } + + std::vector v; + + auto results = db.QueryDatabase( + fmt::format( + "{} VALUES {}", + BaseReplace(), + Strings::Implode(",", insert_chunks) + ) + ); + + return (results.Success() ? results.RowsAffected() : 0); + } }; #endif //EQEMU_BASE_MERC_WEAPONINFO_REPOSITORY_H diff --git a/common/repositories/merc_stance_entries_repository.h b/common/repositories/merc_stance_entries_repository.h index 81ec095d1..25816bb93 100644 --- a/common/repositories/merc_stance_entries_repository.h +++ b/common/repositories/merc_stance_entries_repository.h @@ -44,7 +44,38 @@ public: */ // Custom extended repository methods here + static std::vector GetAllOrdered(Database& db) + { + std::vector v; + auto results = db.QueryDatabase( + fmt::format( + "SELECT {} FROM {} ORDER BY `class_id`, `proficiency_id`, `stance_id`", + SelectColumnsRaw(), + TableName() + ) + ); + + if (!results.Success() || !results.RowCount()) { + return v; + } + + v.reserve(results.RowCount()); + + auto e = MercStanceEntriesRepository::NewEntity(); + + for (auto row : results) { + e.merc_stance_entry_id = Strings::ToUnsignedInt(row[0]); + e.class_id = Strings::ToUnsignedInt(row[1]); + e.proficiency_id = static_cast(Strings::ToUnsignedInt(row[2])); + e.stance_id = static_cast(Strings::ToUnsignedInt(row[3])); + e.isdefault = static_cast(Strings::ToInt(row[4])); + + v.emplace_back(e); + } + + return v; + } }; #endif //EQEMU_MERC_STANCE_ENTRIES_REPOSITORY_H diff --git a/common/repositories/merc_subtypes_repository.h b/common/repositories/merc_subtypes_repository.h index 8bad2d198..1a5f365a9 100644 --- a/common/repositories/merc_subtypes_repository.h +++ b/common/repositories/merc_subtypes_repository.h @@ -44,7 +44,27 @@ public: */ // Custom extended repository methods here + static int GetSubtype( + Database& db, + uint8 class_id, + uint8 tier_id + ) + { + const auto& l = GetWhere( + db, + fmt::format( + "`class_id` = {} AND `tier_id` = {}", + class_id, + tier_id + ) + ); + if (l.empty()) { + return 0; + } + + return l[0].merc_subtype_id; + } }; #endif //EQEMU_MERC_SUBTYPES_REPOSITORY_H diff --git a/common/repositories/mercs_repository.h b/common/repositories/mercs_repository.h index f339ae82c..b2d1ea199 100644 --- a/common/repositories/mercs_repository.h +++ b/common/repositories/mercs_repository.h @@ -44,7 +44,23 @@ public: */ // Custom extended repository methods here + static MercsRepository::Mercs GetMercenaryBySlot(Database& db, Client* c) + { + const auto& l = MercsRepository::GetWhere( + db, + fmt::format( + "`OwnerCharacterID` = {} AND `Slot` = {}", + c->CharacterID(), + c->GetMercSlot() + ) + ); + if (l.empty()) { + return MercsRepository::NewEntity(); + } + + return l[0]; + } }; #endif //EQEMU_MERCS_REPOSITORY_H diff --git a/zone/api_service.cpp b/zone/api_service.cpp index 22a892a16..c7935b6e5 100644 --- a/zone/api_service.cpp +++ b/zone/api_service.cpp @@ -220,8 +220,8 @@ Json::Value ApiGetNpcListDetail(EQ::Net::WebsocketServerConnection *connection, row["npc_spells_effects_id"] = npc->GetNPCSpellsEffectsID(); row["npc_spells_id"] = npc->GetNPCSpellsID(); row["npchp_regen"] = npc->GetNPCHPRegen(); - row["num_merc_types"] = npc->GetNumMercTypes(); - row["num_mercs"] = npc->GetNumMercs(); + row["num_merc_types"] = npc->GetNumMercenaryTypes(); + row["num_mercs"] = npc->GetNumberOfMercenaries(); row["number_of_attacks"] = npc->GetNumberOfAttacks(); row["pet_spell_id"] = npc->GetPetSpellID(); row["platinum"] = npc->GetPlatinum(); @@ -734,11 +734,11 @@ Json::Value ApiGetClientListDetail(EQ::Net::WebsocketServerConnection *connectio row["ls_account_id"] = client->LSAccountID(); row["max_endurance"] = client->GetMaxEndurance(); row["max_x_tars"] = client->GetMaxXTargets(); - row["merc_id"] = client->GetMercID(); + row["merc_id"] = client->GetMercenaryID(); row["merc_only_or_no_group"] = client->MercOnlyOrNoGroup(); row["merc_slot"] = client->GetMercSlot(); row["next_inv_snapshot_time"] = client->GetNextInvSnapshotTime(); - row["num_mercs"] = client->GetNumMercs(); + row["num_mercs"] = client->GetNumberOfMercenaries(); row["pending_adventure_create"] = client->GetPendingAdventureCreate(); row["pending_adventure_door_click"] = client->GetPendingAdventureDoorClick(); row["pending_adventure_leave"] = client->GetPendingAdventureLeave(); diff --git a/zone/attack.cpp b/zone/attack.cpp index 1dd800a43..a15425309 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -3036,12 +3036,12 @@ void Mob::AddToHateList(Mob* other, int64 hate /*= 0*/, int64 damage /*= 0*/, bo // if other is a merc, add the merc client to the hate list if (other->IsMerc()) { - if (other->CastToMerc()->GetMercOwner() && other->CastToMerc()->GetMercOwner()->CastToClient()->GetFeigned()) { - AddFeignMemory(other->CastToMerc()->GetMercOwner()->CastToClient()); + if (other->CastToMerc()->GetMercenaryOwner() && other->CastToMerc()->GetMercenaryOwner()->CastToClient()->GetFeigned()) { + AddFeignMemory(other->CastToMerc()->GetMercenaryOwner()->CastToClient()); } else { - if (!hate_list.IsEntOnHateList(other->CastToMerc()->GetMercOwner())) - hate_list.AddEntToHateList(other->CastToMerc()->GetMercOwner(), 0, 0, false, true); + if (!hate_list.IsEntOnHateList(other->CastToMerc()->GetMercenaryOwner())) + hate_list.AddEntToHateList(other->CastToMerc()->GetMercenaryOwner(), 0, 0, false, true); // if mercs are reworked to include adding 'this' to owner's xtarget list, this should reflect bots code above } } //MERC diff --git a/zone/client.cpp b/zone/client.cpp index ee30ca17c..f8418f767 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -395,7 +395,7 @@ Client::~Client() { if (horse) horse->Depop(); - Mob* merc = entity_list.GetMob(GetMercID()); + Mob* merc = entity_list.GetMob(GetMercenaryID()); if (merc) merc->Depop(); diff --git a/zone/client.h b/zone/client.h index a44968ca6..a69db86fd 100644 --- a/zone/client.h +++ b/zone/client.h @@ -1554,14 +1554,14 @@ public: bool CheckCanUnsuspendMerc(); bool DismissMerc(uint32 MercID); bool MercOnlyOrNoGroup(); - inline uint32 GetMercID() const { return mercid; } + inline uint32 GetMercenaryID() const { return mercid; } inline uint8 GetMercSlot() const { return mercSlot; } void SetMercID( uint32 newmercid) { mercid = newmercid; } void SetMercSlot( uint8 newmercslot) { mercSlot = newmercslot; } Merc* GetMerc(); MercInfo& GetMercInfo(uint8 slot) { return m_mercinfo[slot]; } MercInfo& GetMercInfo() { return m_mercinfo[mercSlot]; } - uint8 GetNumMercs(); + uint8 GetNumberOfMercenaries(); void SetMerc(Merc* newmerc); void SendMercResponsePackets(uint32 ResponseType); void SendMercMerchantResponsePacket(int32 response_type); diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index a660360b5..5fe13c526 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -6257,7 +6257,7 @@ void Client::Handle_OP_EnvDamage(const EQApplicationPacket *app) return; } } - + uint32 mod = spellbonuses.ReduceFallDamage + itembonuses.ReduceFallDamage + aabonuses.ReduceFallDamage; damage -= damage * mod / 100; } @@ -7337,7 +7337,7 @@ void Client::Handle_OP_GroupInvite2(const EQApplicationPacket *app) } GroupInvite_Struct* gis = (GroupInvite_Struct*)app->pBuffer; - + Mob* invitee = nullptr; if (RuleB(Character, GroupInvitesRequireTarget)) { @@ -7385,7 +7385,7 @@ void Client::Handle_OP_GroupInvite2(const EQApplicationPacket *app) } return; - + } else { if (RuleB(Character, OnInviteReceiveAlreadyinGroupMessage)) { if (!invitee->CastToClient()->MercOnlyOrNoGroup()) { @@ -10191,14 +10191,14 @@ void Client::Handle_OP_MercenaryCommand(const EQApplicationPacket *app) uint8 numStances = 0; //get number of available stances for the current merc - std::list mercStanceList = zone->merc_stance_list[merc->GetMercTemplateID()]; + std::list mercStanceList = zone->merc_stance_list[merc->GetMercenaryTemplateID()]; auto iter = mercStanceList.begin(); while (iter != mercStanceList.end()) { numStances++; ++iter; } - MercTemplate* mercTemplate = zone->GetMercTemplate(GetMerc()->GetMercTemplateID()); + MercTemplate* mercTemplate = zone->GetMercTemplate(GetMerc()->GetMercenaryTemplateID()); if (mercTemplate) { //check to see if selected option is a valid stance slot (option is the slot the stance is in, not the actual stance) @@ -10264,14 +10264,14 @@ void Client::Handle_OP_MercenaryDataRequest(const EQApplicationPacket *app) return; } - mercTypeCount = tar->GetNumMercTypes(static_cast(ClientVersion())); - mercCount = tar->GetNumMercs(static_cast(ClientVersion())); + mercTypeCount = tar->GetNumMercenaryTypes(static_cast(ClientVersion())); + mercCount = tar->GetNumberOfMercenaries(static_cast(ClientVersion())); if (mercCount > MAX_MERC) return; - std::list mercTypeList = tar->GetMercTypesList(static_cast(ClientVersion())); - std::list mercDataList = tar->GetMercsList(static_cast(ClientVersion())); + std::list mercTypeList = tar->GetMercenaryTypesList(static_cast(ClientVersion())); + std::list mercDataList = tar->GetMercenariesList(static_cast(ClientVersion())); int i = 0; int StanceCount = 0; @@ -10358,7 +10358,7 @@ void Client::Handle_OP_MercenaryDataUpdateRequest(const EQApplicationPacket *app Log(Logs::General, Logs::Mercenaries, "Data Update Request Received for %s.", GetName()); - if (GetMercID()) + if (GetMercenaryID()) { SendMercPersonalInfo(); } @@ -10431,7 +10431,7 @@ void Client::Handle_OP_MercenaryHire(const EQApplicationPacket *app) GetMercInfo().MercTimerRemaining = RuleI(Mercs, UpkeepIntervalMS); // Get merc, assign it to client & spawn - Merc* merc = Merc::LoadMerc(this, merc_template, merchant_id, false); + Merc* merc = Merc::LoadMercenary(this, merc_template, merchant_id, false); if (merc) { @@ -10504,7 +10504,7 @@ void Client::Handle_OP_MercenaryTimerRequest(const EQApplicationPacket *app) uint32 entityID = 0; uint32 mercState = 5; uint32 suspendedTime = 0; - if (GetMercID()) { + if (GetMercenaryID()) { Merc* merc = GetMerc(); if (merc) { diff --git a/zone/exp.cpp b/zone/exp.cpp index 8432b7c5c..1bf1664d1 100644 --- a/zone/exp.cpp +++ b/zone/exp.cpp @@ -665,7 +665,7 @@ void Client::SetEXP(uint64 set_exp, uint64 set_aaxp, bool isrezzexp) { } level_count++; - if(GetMercID()) + if(GetMercenaryID()) UpdateMercLevel(); } //see if we lost any levels @@ -676,7 +676,7 @@ void Client::SetEXP(uint64 set_exp, uint64 set_aaxp, bool isrezzexp) { break; } level_increase = false; - if(GetMercID()) + if(GetMercenaryID()) UpdateMercLevel(); } check_level--; diff --git a/zone/groups.cpp b/zone/groups.cpp index dc94efb88..913c0fdfd 100644 --- a/zone/groups.cpp +++ b/zone/groups.cpp @@ -233,7 +233,7 @@ bool Group::AddMember(Mob* newmember, const char *NewMemberName, uint32 Characte } if(newmember->IsMerc()) { - Client* owner = newmember->CastToMerc()->GetMercOwner(); + Client* owner = newmember->CastToMerc()->GetMercenaryOwner(); if(owner) { CharacterID = owner->CastToClient()->CharacterID(); @@ -331,7 +331,7 @@ bool Group::AddMember(Mob* newmember, const char *NewMemberName, uint32 Characte if(newmember->IsMerc()) { - Client* owner = newmember->CastToMerc()->GetMercOwner(); + Client* owner = newmember->CastToMerc()->GetMercenaryOwner(); if(owner) { database.SetGroupID(NewMemberName, GetID(), owner->CharacterID(), true); @@ -757,7 +757,7 @@ bool Group::DelMember(Mob* oldmember, bool ignoresender) if(oldmember->IsMerc()) { - Client* owner = oldmember->CastToMerc()->GetMercOwner(); + Client* owner = oldmember->CastToMerc()->GetMercenaryOwner(); if(owner) { database.SetGroupID(oldmember->GetCleanName(), 0, owner->CharacterID(), true); @@ -952,7 +952,7 @@ void Group::DisbandGroup(bool joinraid) { if (members[i]->IsMerc()) { - Client* owner = members[i]->CastToMerc()->GetMercOwner(); + Client* owner = members[i]->CastToMerc()->GetMercenaryOwner(); if(owner) { database.SetGroupID(members[i]->GetCleanName(), 0, owner->CharacterID(), true); diff --git a/zone/merc.cpp b/zone/merc.cpp index 034d4eac7..f8f9f0d06 100644 --- a/zone/merc.cpp +++ b/zone/merc.cpp @@ -857,7 +857,7 @@ bool Merc::Process() return false; } - if(!GetMercOwner()) { + if(!GetMercenaryOwner()) { //p_depop = true; //this was causing a crash - removed merc from entity list, but not group //return false; //merc can live after client dies, not sure how long } @@ -867,8 +867,8 @@ bool Merc::Process() return false; } - if (HasGroup() && GetMercOwner() && GetFollowID() == 0) { - SetFollowID(GetMercOwner()->GetID()); + if (HasGroup() && GetMercenaryOwner() && GetFollowID() == 0) { + SetFollowID(GetMercenaryOwner()->GetID()); } SpellProcess(); @@ -1691,7 +1691,7 @@ bool Merc::AICastSpell(int8 iChance, uint32 iSpellTypes) { continue; } - if(hpr < checkHPR && g->members[i] == GetMercOwner()) { + if(hpr < checkHPR && g->members[i] == GetMercenaryOwner()) { if(!tar || (hpr < tar->GetHPRatio() || (tar->IsPet() && hpr < checkPetHPR))) tar = g->members[i]; //check owner first } @@ -4076,8 +4076,8 @@ void Merc::SetTarget(Mob* mob) { Mob* Merc::GetOwnerOrSelf() { Mob* Result = nullptr; - if(GetMercOwner()) - Result = GetMercOwner(); + if(GetMercenaryOwner()) + Result = GetMercenaryOwner(); else Result = this; @@ -4108,7 +4108,7 @@ bool Merc::Death(Mob* killerMob, int64 damage, uint16 spell, EQ::skills::SkillTy return true; } -Client* Merc::GetMercOwner() { +Client* Merc::GetMercenaryOwner() { Client* mercOwner = nullptr; if(GetOwner()) @@ -4230,7 +4230,7 @@ const char* Merc::GetRandomName(){ return name; } -bool Merc::LoadMercSpells() { +bool Merc::LoadMercenarySpells() { // loads mercs spells into list merc_spells.clear(); @@ -4278,18 +4278,18 @@ bool Merc::LoadMercSpells() { bool Merc::Save() { - if(database.SaveMerc(this)){ + if(database.SaveMercenary(this)){ return true; } return false; } -Merc* Merc::LoadMerc(Client *c, MercTemplate* merc_template, uint32 merchant_id, bool updateFromDB) { +Merc* Merc::LoadMercenary(Client *c, MercTemplate* merc_template, uint32 merchant_id, bool updateFromDB) { if(c) { - if(c->GetMercID()) + if(c->GetMercenaryID()) { merc_template = zone->GetMercTemplate(c->GetMercInfo().MercTemplateID); } @@ -4302,7 +4302,7 @@ Merc* Merc::LoadMerc(Client *c, MercTemplate* merc_template, uint32 merchant_id, const NPCType* npc_type_to_copy = nullptr; if (c) { - npc_type_to_copy = content_db.GetMercType(merc_template->MercNPCID, merc_template->RaceID, c->GetLevel()); + npc_type_to_copy = content_db.GetMercenaryType(merc_template->MercNPCID, merc_template->RaceID, c->GetLevel()); } if(npc_type_to_copy != nullptr) @@ -4365,12 +4365,12 @@ Merc* Merc::LoadMerc(Client *c, MercTemplate* merc_template, uint32 merchant_id, if(merc) { merc->SetMercData( merc_template->MercTemplateID ); - database.LoadMercEquipment(merc); + database.LoadMercenaryEquipment(merc); merc->UpdateMercStats(c, true); if(updateFromDB) { - database.LoadCurrentMerc(c); + database.LoadCurrentMercenary(c); merc->SetMercID(c->GetMercInfo().mercid); snprintf(merc->name, 64, "%s", c->GetMercInfo().merc_name); @@ -4397,11 +4397,11 @@ Merc* Merc::LoadMerc(Client *c, MercTemplate* merc_template, uint32 merchant_id, merc->RandomizeFeatures(false, true); } - if(merc->GetMercID()) { - database.LoadMercBuffs(merc); + if(merc->GetMercenaryID()) { + database.LoadMercenaryBuffs(merc); } - merc->LoadMercSpells(); + merc->LoadMercenarySpells(); } Log(Logs::General, Logs::Mercenaries, "LoadMerc Successful for %s (%s).", merc->GetName(), c->GetName()); @@ -4414,7 +4414,7 @@ Merc* Merc::LoadMerc(Client *c, MercTemplate* merc_template, uint32 merchant_id, void Merc::UpdateMercInfo(Client *c) { snprintf(c->GetMercInfo().merc_name, 64, "%s", name); - c->GetMercInfo().mercid = GetMercID(); + c->GetMercInfo().mercid = GetMercenaryID(); c->GetMercInfo().IsSuspended = IsSuspended(); c->GetMercInfo().Gender = GetGender(); c->GetMercInfo().MercSize = GetSize(); @@ -4438,7 +4438,7 @@ void Merc::UpdateMercStats(Client *c, bool setmax) if (c->GetMercInfo().MercTemplateID > 0) { Log(Logs::General, Logs::Mercenaries, "Updating Mercenary Stats for %s (%s).", GetName(), c->GetName()); - const NPCType *npc_type = content_db.GetMercType( + const NPCType *npc_type = content_db.GetMercenaryType( zone->GetMercTemplate(c->GetMercInfo().MercTemplateID)->MercNPCID, GetRace(), c->GetLevel()); if (npc_type) { max_hp = npc_type->max_hp; @@ -4674,7 +4674,7 @@ bool Merc::Spawn(Client *owner) { if(!owner) return false; - MercTemplate* merc_template = zone->GetMercTemplate(GetMercTemplateID()); + MercTemplate* merc_template = zone->GetMercTemplate(GetMercenaryTemplateID()); if(!merc_template) return false; @@ -4841,7 +4841,7 @@ void Client::UpdateMercTimer() { if(GetMercTimer()->Check()) { - uint32 upkeep = merc->CalcUpkeepCost(merc->GetMercTemplateID(), GetLevel()); + uint32 upkeep = merc->CalcUpkeepCost(merc->GetMercenaryTemplateID(), GetLevel()); if(CheckCanRetainMerc(upkeep)) { @@ -4898,7 +4898,7 @@ bool Client::CheckCanHireMerc(Mob* merchant, uint32 template_id) { } // Check if max number of mercs is already reached - if(GetNumMercs() >= MAXMERCS) { + if(GetNumberOfMercenaries() >= MAXMERCS) { SendMercResponsePackets(6); return false; } @@ -5053,7 +5053,7 @@ void Client::SuspendMercCommand() { } // Get merc, assign it to client & spawn - Merc* merc = Merc::LoadMerc(this, &zone->merc_templates[GetMercInfo().MercTemplateID], 0, true); + Merc* merc = Merc::LoadMercenary(this, &zone->merc_templates[GetMercInfo().MercTemplateID], 0, true); if(merc) { SpawnMerc(merc, false); @@ -5079,7 +5079,7 @@ void Client::SuspendMercCommand() { } } - if(CurrentMerc && GetMercID()) + if(CurrentMerc && GetMercenaryID()) { CurrentMerc->Suspend(); Log(Logs::General, Logs::Mercenaries, "SuspendMercCommand Successful Suspend for %s.", GetName()); @@ -5123,13 +5123,13 @@ void Client::SpawnMercOnZone() { if (GetMerc()) return; - if(database.LoadMercInfo(this)) + if(database.LoadMercenaryInfo(this)) { if(!GetMercInfo().IsSuspended) { GetMercInfo().SuspendedTime = 0; // Get merc, assign it to client & spawn - Merc* merc = Merc::LoadMerc(this, &zone->merc_templates[GetMercInfo().MercTemplateID], 0, true); + Merc* merc = Merc::LoadMercenary(this, &zone->merc_templates[GetMercInfo().MercTemplateID], 0, true); if(merc) { SpawnMerc(merc, false); @@ -5189,7 +5189,7 @@ void Client::SendMercTimer(Merc* merc) { void Client::SpawnMerc(Merc* merc, bool setMaxStats) { - if (!merc || !CheckCanSpawnMerc(merc->GetMercTemplateID())) + if (!merc || !CheckCanSpawnMerc(merc->GetMercenaryTemplateID())) { if (merc) { @@ -5212,7 +5212,7 @@ void Client::SpawnMerc(Merc* merc, bool setMaxStats) { bool Merc::Suspend() { - Client* mercOwner = GetMercOwner(); + Client* mercOwner = GetMercenaryOwner(); if(!mercOwner) return false; @@ -5261,8 +5261,8 @@ bool Merc::Unsuspend(bool setMaxStats) { Client* mercOwner = nullptr; - if(GetMercOwner()) { - mercOwner = GetMercOwner(); + if(GetMercenaryOwner()) { + mercOwner = GetMercenaryOwner(); } if(!mercOwner) @@ -5273,7 +5273,7 @@ bool Merc::Unsuspend(bool setMaxStats) { // Set time remaining to max on unsuspend - there is a charge for unsuspending as well SetSuspended(false); - mercOwner->GetMercInfo().mercid = GetMercID(); + mercOwner->GetMercInfo().mercid = GetMercenaryID(); mercOwner->GetMercInfo().IsSuspended = false; mercOwner->SendMercenaryUnsuspendPacket(0); @@ -5299,7 +5299,7 @@ bool Merc::Unsuspend(bool setMaxStats) { //check for sufficient funds and remove them last if(RuleB(Mercs, ChargeMercUpkeepCost)) { - uint32 cost = CalcUpkeepCost(GetMercTemplateID(), GetLevel()) * 100; // Cost is in gold + uint32 cost = CalcUpkeepCost(GetMercenaryTemplateID(), GetLevel()) * 100; // Cost is in gold if(cost > 0 && !mercOwner->HasMoney(cost)) { mercOwner->SendMercResponsePackets(1); @@ -5317,7 +5317,7 @@ bool Merc::Unsuspend(bool setMaxStats) { bool Client::DismissMerc(uint32 MercID) { bool Dismissed = true; - if (!database.DeleteMerc(MercID)) + if (!database.DeleteMercenary(MercID)) { Log(Logs::General, Logs::Mercenaries, "Dismiss Failed Database Query for MercID: %i, Client: %s.", MercID, GetName()); Dismissed = false; @@ -5390,9 +5390,9 @@ bool Merc::RemoveMercFromGroup(Merc* merc, Group* group) { } else if(group->DelMember(merc, true)) { - if(merc->GetMercCharacterID() != 0) + if(merc->GetMercenaryCharacterID() != 0) { - database.SetGroupID(merc->GetName(), 0, merc->GetMercCharacterID(), true); + database.SetGroupID(merc->GetName(), 0, merc->GetMercenaryCharacterID(), true); } } } @@ -5433,9 +5433,9 @@ bool Merc::MercJoinClientGroup() { Client* mercOwner = nullptr; - if(GetMercOwner()) + if(GetMercenaryOwner()) { - mercOwner = GetMercOwner(); + mercOwner = GetMercenaryOwner(); } if(!mercOwner) @@ -5516,18 +5516,18 @@ bool Merc::AddMercToGroup(Merc* merc, Group* group) { // Remove merc from current group if it's not the destination group if(merc->HasGroup()) { - if(merc->GetGroup() == group && merc->GetMercOwner()) + if(merc->GetGroup() == group && merc->GetMercenaryOwner()) { // Merc is already in the destination group - merc->SetFollowID(merc->GetMercOwner()->GetID()); + merc->SetFollowID(merc->GetMercenaryOwner()->GetID()); return true; } merc->RemoveMercFromGroup(merc, merc->GetGroup()); } //Try and add the member, followed by checking if the merc owner exists. - if(group->AddMember(merc) && merc->GetMercOwner()) + if(group->AddMember(merc) && merc->GetMercenaryOwner()) { - merc->SetFollowID(merc->GetMercOwner()->GetID()); + merc->SetFollowID(merc->GetMercenaryOwner()->GetID()); Result = true; } else @@ -5551,13 +5551,13 @@ void Client::InitializeMercInfo() { Merc* Client::GetMerc() { - if(GetMercID() == 0) + if(GetMercenaryID() == 0) { - Log(Logs::Detail, Logs::Mercenaries, "GetMerc - GetMercID: 0 for %s.", GetName()); + Log(Logs::Detail, Logs::Mercenaries, "GetMerc - GetMercenaryID: 0 for %s.", GetName()); return (nullptr); } - Merc* tmp = entity_list.GetMercByID(GetMercID()); + Merc* tmp = entity_list.GetMercByID(GetMercenaryID()); if(tmp == nullptr) { SetMercID(0); @@ -5575,7 +5575,7 @@ Merc* Client::GetMerc() { return (tmp); } -uint8 Client::GetNumMercs() { +uint8 Client::GetNumberOfMercenaries() { uint8 numMercs = 0; @@ -5586,7 +5586,7 @@ uint8 Client::GetNumMercs() { numMercs++; } } - Log(Logs::General, Logs::Mercenaries, "GetNumMercs Number: %i for %s.", numMercs, GetName()); + Log(Logs::General, Logs::Mercenaries, "GetNumberOfMercenaries Number: %i for %s.", numMercs, GetName()); return numMercs; } @@ -5636,8 +5636,8 @@ void Client::SetMerc(Merc* newmerc) { newmerc->SetOwnerID(GetID()); newmerc->SetMercCharacterID(CharacterID()); newmerc->SetClientVersion((uint8)ClientVersion()); - GetMercInfo().mercid = newmerc->GetMercID(); - GetMercInfo().MercTemplateID = newmerc->GetMercTemplateID(); + GetMercInfo().mercid = newmerc->GetMercenaryID(); + GetMercInfo().MercTemplateID = newmerc->GetMercenaryTemplateID(); GetMercInfo().myTemplate = zone->GetMercTemplate(GetMercInfo().MercTemplateID); GetMercInfo().IsSuspended = newmerc->IsSuspended(); GetMercInfo().SuspendedTime = 0; @@ -5722,75 +5722,78 @@ void Client::SendMercAssignPacket(uint32 entityID, uint32 unk01, uint32 unk02) { Log(Logs::Detail, Logs::Mercenaries, "Sent SendMercAssignPacket EndID: %i, Unk1: %i, Unk2: %i, Client: %s.", entityID, unk01, unk02, GetName()); } -void NPC::LoadMercTypes() { +void NPC::LoadMercenaryTypes() +{ + const std::string& query = fmt::format( + SQL( + SELECT DISTINCT MTyp.dbstring, MTyp.clientversion + FROM merc_merchant_entries MME, merc_merchant_template_entries MMTE, + merc_types MTyp, merc_templates MTem + WHERE MME.merchant_id = {} + AND MME.merc_merchant_template_id = MMTE.merc_merchant_template_id + AND MMTE.merc_template_id = MTem.merc_template_id + AND MTem.merc_type_id = MTyp.merc_type_id + ), + GetNPCTypeID() + ); - std::string query = StringFormat("SELECT DISTINCT MTyp.dbstring, MTyp.clientversion " - "FROM merc_merchant_entries MME, merc_merchant_template_entries MMTE, " - "merc_types MTyp, merc_templates MTem " - "WHERE MME.merchant_id = %i " - "AND MME.merc_merchant_template_id = MMTE.merc_merchant_template_id " - "AND MMTE.merc_template_id = MTem.merc_template_id " - "AND MTem.merc_type_id = MTyp.merc_type_id;", GetNPCTypeID()); auto results = database.QueryDatabase(query); - if (!results.Success()) - { - LogError("Error in NPC::LoadMercTypes()"); + if (!results.Success()) { return; } - for (auto row = results.begin(); row != results.end(); ++row) - { - MercType tempMercType; + for (auto row = results.begin(); row != results.end(); ++row) { + MercType t; - tempMercType.Type = Strings::ToInt(row[0]); - tempMercType.ClientVersion = Strings::ToInt(row[1]); + t.Type = Strings::ToInt(row[0]); + t.ClientVersion = Strings::ToInt(row[1]); - mercTypeList.push_back(tempMercType); + mercTypeList.push_back(t); } - } -void NPC::LoadMercs() { +void NPC::LoadMercenaries() +{ + const std::string& query = fmt::format( + SQL( + SELECT DISTINCT MTem.merc_template_id, MTyp.dbstring AS merc_type_id, + MTem.dbstring AS merc_subtype_id, 0 AS CostFormula, + CASE WHEN MTem.clientversion > MTyp.clientversion + THEN MTem.clientversion + ELSE MTyp.clientversion END AS clientversion, MTem.merc_npc_type_id + FROM merc_merchant_entries MME, merc_merchant_template_entries MMTE, + merc_types MTyp, merc_templates MTem + WHERE MME.merchant_id = {} AND + MME.merc_merchant_template_id = MMTE.merc_merchant_template_id + AND MMTE.merc_template_id = MTem.merc_template_id + AND MTem.merc_type_id = MTyp.merc_type_id + ), + GetNPCTypeID() + ); - std::string query = StringFormat("SELECT DISTINCT MTem.merc_template_id, MTyp.dbstring AS merc_type_id, " - "MTem.dbstring AS merc_subtype_id, 0 AS CostFormula, " - "CASE WHEN MTem.clientversion > MTyp.clientversion " - "THEN MTem.clientversion " - "ELSE MTyp.clientversion END AS clientversion, MTem.merc_npc_type_id " - "FROM merc_merchant_entries MME, merc_merchant_template_entries MMTE, " - "merc_types MTyp, merc_templates MTem " - "WHERE MME.merchant_id = %i AND " - "MME.merc_merchant_template_id = MMTE.merc_merchant_template_id " - "AND MMTE.merc_template_id = MTem.merc_template_id " - "AND MTem.merc_type_id = MTyp.merc_type_id;", GetNPCTypeID()); auto results = database.QueryDatabase(query); - - if (!results.Success()) - { - LogError("Error in NPC::LoadMercTypes()"); + if (!results.Success()) { return; } - for (auto row = results.begin(); row != results.end(); ++row) - { - MercData tempMerc; + for (auto row = results.begin(); row != results.end(); ++row) { + MercData t; - tempMerc.MercTemplateID = Strings::ToInt(row[0]); - tempMerc.MercType = Strings::ToInt(row[1]); - tempMerc.MercSubType = Strings::ToInt(row[2]); - tempMerc.CostFormula = Strings::ToInt(row[3]); - tempMerc.ClientVersion = Strings::ToInt(row[4]); - tempMerc.NPCID = Strings::ToInt(row[5]); + t.MercTemplateID = Strings::ToInt(row[0]); + t.MercType = Strings::ToInt(row[1]); + t.MercSubType = Strings::ToInt(row[2]); + t.CostFormula = Strings::ToInt(row[3]); + t.ClientVersion = Strings::ToInt(row[4]); + t.NPCID = Strings::ToInt(row[5]); - mercDataList.push_back(tempMerc); + mercDataList.push_back(t); } - } -int NPC::GetNumMercTypes(uint32 clientVersion) { +int NPC::GetNumMercenaryTypes(uint32 clientVersion) { int count = 0; - std::list mercTypeList = GetMercTypesList(); + std::list mercTypeList = GetMercenaryTypesList(); for (auto mercTypeListItr = mercTypeList.begin(); mercTypeListItr != mercTypeList.end(); ++mercTypeListItr) { if(mercTypeListItr->ClientVersion <= clientVersion) @@ -5800,10 +5803,10 @@ int NPC::GetNumMercTypes(uint32 clientVersion) { return count; } -int NPC::GetNumMercs(uint32 clientVersion) { +int NPC::GetNumberOfMercenaries(uint32 clientVersion) { int count = 0; - std::list mercDataList = GetMercsList(); + std::list mercDataList = GetMercenariesList(); for (auto mercListItr = mercDataList.begin(); mercListItr != mercDataList.end(); ++mercListItr) { if(mercListItr->ClientVersion <= clientVersion) @@ -5813,11 +5816,11 @@ int NPC::GetNumMercs(uint32 clientVersion) { return count; } -std::list NPC::GetMercTypesList(uint32 clientVersion) { +std::list NPC::GetMercenaryTypesList(uint32 clientVersion) { std::list result; - if(GetNumMercTypes() > 0) + if(GetNumMercenaryTypes() > 0) { for (auto mercTypeListItr = mercTypeList.begin(); mercTypeListItr != mercTypeList.end(); ++mercTypeListItr) { @@ -5834,11 +5837,11 @@ std::list NPC::GetMercTypesList(uint32 clientVersion) { return result; } -std::list NPC::GetMercsList(uint32 clientVersion) { +std::list NPC::GetMercenariesList(uint32 clientVersion) { std::list result; - if(GetNumMercs() > 0) + if(GetNumberOfMercenaries() > 0) { for (auto mercListItr = mercDataList.begin(); mercListItr != mercDataList.end(); ++mercListItr) { if(mercListItr->ClientVersion <= clientVersion) diff --git a/zone/merc.h b/zone/merc.h index 127d15a53..07b0fd5d5 100644 --- a/zone/merc.h +++ b/zone/merc.h @@ -126,7 +126,7 @@ public: bool IsOfClientBotMerc() const override { return true; } virtual void FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho); - static Merc* LoadMerc(Client *c, MercTemplate* merc_template, uint32 merchant_id, bool updateFromDB = false); + static Merc* LoadMercenary(Client *c, MercTemplate* merc_template, uint32 merchant_id, bool updateFromDB = false); void UpdateMercInfo(Client *c); void UpdateMercStats(Client *c, bool setmax = false); void UpdateMercAppearance(); @@ -151,13 +151,13 @@ public: // "GET" Class Methods virtual Mob* GetOwner(); - Client* GetMercOwner(); + Client* GetMercenaryOwner(); virtual Mob* GetOwnerOrSelf(); - uint32 GetMercID() { return _MercID; } - uint32 GetMercCharacterID( ) { return owner_char_id; } - uint32 GetMercTemplateID() { return _MercTemplateID; } - uint32 GetMercType() { return _MercType; } - uint32 GetMercSubType() { return _MercSubType; } + uint32 GetMercenaryID() { return _MercID; } + uint32 GetMercenaryCharacterID( ) { return owner_char_id; } + uint32 GetMercenaryTemplateID() { return _MercTemplateID; } + uint32 GetMercenaryType() { return _MercType; } + uint32 GetMercenarySubType() { return _MercSubType; } uint8 GetProficiencyID() { return _ProficiencyID; } uint8 GetTierID() { return _TierID; } uint32 GetCostFormula() { return _CostFormula; } @@ -327,7 +327,7 @@ private: float GetDefaultSize(); - bool LoadMercSpells(); + bool LoadMercenarySpells(); bool CheckStance(int16 stance); std::vector GetMercSpells() { return merc_spells; } diff --git a/zone/npc.cpp b/zone/npc.cpp index d23ce670a..abfdbceea 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -300,8 +300,8 @@ NPC::NPC(const NPCType *npc_type_data, Spawn2 *in_respawn, const glm::vec4 &posi m_record_loot_stats = false; if (GetClass() == Class::MercenaryLiaison && RuleB(Mercs, AllowMercs)) { - LoadMercTypes(); - LoadMercs(); + LoadMercenaryTypes(); + LoadMercenaries(); } SpellFocusDMG = 0; diff --git a/zone/npc.h b/zone/npc.h index 4ee0c5ad0..fcacc8fbc 100644 --- a/zone/npc.h +++ b/zone/npc.h @@ -383,16 +383,16 @@ public: void AI_SetRoambox(float distance, float max_x, float min_x, float max_y, float min_y, uint32 delay = 2500, uint32 min_delay = 2500); //mercenary stuff - void LoadMercTypes(); - void LoadMercs(); - std::list GetMercTypesList() {return mercTypeList; }; - std::list GetMercTypesList( uint32 expansion ); - std::list GetMercsList() {return mercDataList; }; - std::list GetMercsList( uint32 expansion ); - int GetNumMercTypes() { return static_cast(mercTypeList.size()); }; - int GetNumMercTypes( uint32 expansion ); - int GetNumMercs() { return static_cast(mercDataList.size()); }; - int GetNumMercs( uint32 expansion ); + void LoadMercenaryTypes(); + void LoadMercenaries(); + std::list GetMercenaryTypesList() {return mercTypeList; }; + std::list GetMercenaryTypesList( uint32 expansion ); + std::list GetMercenariesList() {return mercDataList; }; + std::list GetMercenariesList( uint32 expansion ); + int GetNumMercenaryTypes() { return static_cast(mercTypeList.size()); }; + int GetNumMercenaryTypes( uint32 expansion ); + int GetNumberOfMercenaries() { return static_cast(mercDataList.size()); }; + int GetNumberOfMercenaries( uint32 expansion ); inline bool GetNPCAggro() const { return npc_aggro; } inline void SetNPCAggro(bool in_npc_aggro) { npc_aggro = in_npc_aggro; } diff --git a/zone/zone.cpp b/zone/zone.cpp index 9a6b2a099..28a8a0435 100644 --- a/zone/zone.cpp +++ b/zone/zone.cpp @@ -64,6 +64,7 @@ #include "../common/repositories/respawn_times_repository.h" #include "../common/repositories/npc_emotes_repository.h" #include "../common/serverinfo.h" +#include "../common/repositories/merc_stance_entries_repository.h" #include @@ -746,74 +747,74 @@ void Zone::GetMerchantDataForZoneLoad() { } } -void Zone::LoadMercTemplates(){ +void Zone::LoadMercenaryTemplates() +{ + std::list mercenary_stances; - std::list merc_stances; merc_templates.clear(); - std::string query = "SELECT `class_id`, `proficiency_id`, `stance_id`, `isdefault` FROM " - "`merc_stance_entries` ORDER BY `class_id`, `proficiency_id`, `stance_id`"; - auto results = database.QueryDatabase(query); - if (!results.Success()) { - LogError("Error in ZoneDatabase::LoadMercTemplates()"); - } - else { - for (auto row = results.begin(); row != results.end(); ++row) { - MercStanceInfo tempMercStanceInfo; - tempMercStanceInfo.ClassID = Strings::ToInt(row[0]); - tempMercStanceInfo.ProficiencyID = Strings::ToInt(row[1]); - tempMercStanceInfo.StanceID = Strings::ToInt(row[2]); - tempMercStanceInfo.IsDefault = Strings::ToInt(row[3]); - - merc_stances.push_back(tempMercStanceInfo); - } - } - - query = "SELECT DISTINCT MTem.merc_template_id, MTyp.dbstring " - "AS merc_type_id, MTem.dbstring " - "AS merc_subtype_id, MTyp.race_id, MS.class_id, MTyp.proficiency_id, MS.tier_id, 0 " - "AS CostFormula, MTem.clientversion, MTem.merc_npc_type_id " - "FROM merc_types MTyp, merc_templates MTem, merc_subtypes MS " - "WHERE MTem.merc_type_id = MTyp.merc_type_id AND MTem.merc_subtype_id = MS.merc_subtype_id " - "ORDER BY MTyp.race_id, MS.class_id, MTyp.proficiency_id;"; - results = database.QueryDatabase(query); - if (!results.Success()) { - LogError("Error in ZoneDatabase::LoadMercTemplates()"); + const auto& l = MercStanceEntriesRepository::GetAllOrdered(database); + if (l.empty()) { return; } - for (auto row = results.begin(); row != results.end(); ++row) { + for (const auto& e : l) { + MercStanceInfo t{ + .ProficiencyID = e.proficiency_id, + .ClassID = static_cast(e.class_id), + .StanceID = e.stance_id, + .IsDefault = static_cast(e.isdefault) + }; - MercTemplate tempMercTemplate; + mercenary_stances.push_back(t); + } - tempMercTemplate.MercTemplateID = Strings::ToInt(row[0]); - tempMercTemplate.MercType = Strings::ToInt(row[1]); - tempMercTemplate.MercSubType = Strings::ToInt(row[2]); - tempMercTemplate.RaceID = Strings::ToInt(row[3]); - tempMercTemplate.ClassID = Strings::ToInt(row[4]); - tempMercTemplate.ProficiencyID = Strings::ToInt(row[5]); - tempMercTemplate.TierID = Strings::ToInt(row[6]); - tempMercTemplate.CostFormula = Strings::ToInt(row[7]); - tempMercTemplate.ClientVersion = Strings::ToInt(row[8]); - tempMercTemplate.MercNPCID = Strings::ToInt(row[9]); + const std::string& query = SQL( + SELECT DISTINCT MTem.merc_template_id, MTyp.dbstring + AS merc_type_id, MTem.dbstring + AS merc_subtype_id, MTyp.race_id, MS.class_id, MTyp.proficiency_id, MS.tier_id, 0 + AS CostFormula, MTem.clientversion, MTem.merc_npc_type_id + FROM merc_types MTyp, merc_templates MTem, merc_subtypes MS + WHERE MTem.merc_type_id = MTyp.merc_type_id AND MTem.merc_subtype_id = MS.merc_subtype_id + ORDER BY MTyp.race_id, MS.class_id, MTyp.proficiency_id + ); + auto results = database.QueryDatabase(query); + if (!results.Success() || !results.RowCount()) { + return; + } - for(int i = 0; i < MaxMercStanceID; i++) - tempMercTemplate.Stances[i] = 0; + for (auto row: results) { + MercTemplate t{ + .MercTemplateID = Strings::ToUnsignedInt(row[0]), + .MercType = Strings::ToUnsignedInt(row[1]), + .MercSubType = Strings::ToUnsignedInt(row[2]), + .RaceID = static_cast(Strings::ToUnsignedInt(row[3])), + .ClassID = static_cast(Strings::ToUnsignedInt(row[4])), + .MercNPCID = Strings::ToUnsignedInt(row[9]), + .ProficiencyID = static_cast(Strings::ToUnsignedInt(row[5])), + .TierID = static_cast(Strings::ToUnsignedInt(row[6])), + .CostFormula = static_cast(Strings::ToUnsignedInt(row[7])), + .ClientVersion = Strings::ToUnsignedInt(row[8]) + }; - int stanceIndex = 0; - for (auto mercStanceListItr = merc_stances.begin(); mercStanceListItr != merc_stances.end(); ++mercStanceListItr) { - if(mercStanceListItr->ClassID != tempMercTemplate.ClassID || mercStanceListItr->ProficiencyID != tempMercTemplate.ProficiencyID) - continue; + for (int i = 0; i < MaxMercStanceID; i++) { + t.Stances[i] = 0; + } - zone->merc_stance_list[tempMercTemplate.MercTemplateID].push_back((*mercStanceListItr)); - tempMercTemplate.Stances[stanceIndex] = mercStanceListItr->StanceID; - ++stanceIndex; - } + int stance_index = 0; - merc_templates[tempMercTemplate.MercTemplateID] = tempMercTemplate; + for (auto i = mercenary_stances.begin(); i != mercenary_stances.end(); ++i) { + if (i->ClassID != t.ClassID || i->ProficiencyID != t.ProficiencyID) { + continue; + } - } + zone->merc_stance_list[t.MercTemplateID].push_back((*i)); + t.Stances[stance_index] = i->StanceID; + ++stance_index; + } + merc_templates[t.MercTemplateID] = t; + } } void Zone::LoadLevelEXPMods() @@ -828,39 +829,39 @@ void Zone::LoadLevelEXPMods() } } -void Zone::LoadMercSpells(){ - +void Zone::LoadMercenarySpells() +{ merc_spells_list.clear(); - const std::string query = "SELECT msl.class_id, msl.proficiency_id, msle.spell_id, msle.spell_type, " - "msle.stance_id, msle.minlevel, msle.maxlevel, msle.slot, msle.procChance " - "FROM merc_spell_lists msl, merc_spell_list_entries msle " - "WHERE msle.merc_spell_list_id = msl.merc_spell_list_id " - "ORDER BY msl.class_id, msl.proficiency_id, msle.spell_type, msle.minlevel, msle.slot;"; + + const std::string& query = SQL( + SELECT msl.class_id, msl.proficiency_id, msle.spell_id, msle.spell_type, + msle.stance_id, msle.minlevel, msle.maxlevel, msle.slot, msle.procChance + FROM merc_spell_lists msl, merc_spell_list_entries msle + WHERE msle.merc_spell_list_id = msl.merc_spell_list_id + ORDER BY msl.class_id, msl.proficiency_id, msle.spell_type, msle.minlevel, msle.slot + ); + auto results = database.QueryDatabase(query); - if (!results.Success()) { - LogError("Error in Zone::LoadMercSpells()"); + if (!results.Success() || !results.RowCount()) { return; } - for (auto row = results.begin(); row != results.end(); ++row) { - uint32 classid; - MercSpellEntry tempMercSpellEntry; - - classid = Strings::ToInt(row[0]); - tempMercSpellEntry.proficiencyid = Strings::ToInt(row[1]); - tempMercSpellEntry.spellid = Strings::ToInt(row[2]); - tempMercSpellEntry.type = Strings::ToInt(row[3]); - tempMercSpellEntry.stance = Strings::ToInt(row[4]); - tempMercSpellEntry.minlevel = Strings::ToInt(row[5]); - tempMercSpellEntry.maxlevel = Strings::ToInt(row[6]); - tempMercSpellEntry.slot = Strings::ToInt(row[7]); - tempMercSpellEntry.proc_chance = Strings::ToInt(row[8]); - - merc_spells_list[classid].push_back(tempMercSpellEntry); - } - - Log(Logs::General, Logs::Mercenaries, "Loaded %i merc spells.", merc_spells_list[1].size() + merc_spells_list[2].size() + merc_spells_list[9].size() + merc_spells_list[12].size()); + for (auto row: results) { + const uint32 class_id = Strings::ToUnsignedInt(row[0]); + merc_spells_list[class_id].push_back( + MercSpellEntry{ + .proficiencyid = static_cast(Strings::ToUnsignedInt(row[1])), + .spellid = static_cast(Strings::ToUnsignedInt(row[2])), + .type = Strings::ToUnsignedInt(row[3]), + .stance = static_cast(Strings::ToInt(row[4])), + .minlevel = static_cast(Strings::ToUnsignedInt(row[5])), + .maxlevel = static_cast(Strings::ToUnsignedInt(row[6])), + .slot = static_cast(Strings::ToInt(row[7])), + .proc_chance = static_cast(Strings::ToUnsignedInt(row[8])) + } + ); + } } bool Zone::IsLoaded() { @@ -1198,8 +1199,8 @@ bool Zone::Init(bool is_static) { // Merc data if (RuleB(Mercs, AllowMercs)) { - LoadMercTemplates(); - LoadMercSpells(); + LoadMercenaryTemplates(); + LoadMercenarySpells(); } if (RuleB(Zone, LevelBasedEXPMods)) { diff --git a/zone/zone.h b/zone/zone.h index 66fcebf2f..3e7cd4f1d 100755 --- a/zone/zone.h +++ b/zone/zone.h @@ -271,8 +271,8 @@ public: void LoadLDoNTraps(); void LoadLevelEXPMods(); void LoadGrids(); - void LoadMercSpells(); - void LoadMercTemplates(); + void LoadMercenarySpells(); + void LoadMercenaryTemplates(); void LoadNewMerchantData(uint32 merchantid); void LoadNPCEmotes(std::vector* v); void LoadTempMerchantData(); diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index 721cad1b0..ecd9d7580 100755 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -39,6 +39,11 @@ #include "../common/repositories/account_repository.h" #include "../common/repositories/respawn_times_repository.h" #include "../common/repositories/object_contents_repository.h" +#include "../common/repositories/mercs_repository.h" +#include "../common/repositories/merc_buffs_repository.h" +#include "../common/repositories/merc_inventory_repository.h" +#include "../common/repositories/merc_subtypes_repository.h" +#include "../common/repositories/npc_types_tint_repository.h" #include #include @@ -1959,545 +1964,574 @@ const NPCType *ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load return npc; } -const NPCType* ZoneDatabase::GetMercType(uint32 id, uint16 raceid, uint32 clientlevel) +const NPCType* ZoneDatabase::GetMercenaryType(uint32 merc_npc_type_id, uint16 race_id, uint32 owner_level) { - //need to save based on merc_npc_type & client level - uint32 merc_type_id = id * 100 + clientlevel; + const uint32 merc_type_id = merc_npc_type_id * 100 + owner_level; - // If Merc is already in tree, return it. - auto itr = zone->merctable.find(merc_type_id); - if(itr != zone->merctable.end()) - return itr->second; + auto i = zone->merctable.find(merc_type_id); + if (i != zone->merctable.end()) { + return i->second; + } - //If the id is 0, return nullptr. (sanity check) - if(id == 0) - return nullptr; - - // Otherwise, load Merc data on demand - std::string query = StringFormat("SELECT " - "m_stats.merc_npc_type_id, " - "'' AS name, " - "m_stats.level, " - "m_types.race_id, " - "m_subtypes.class_id, " - "m_stats.hp, " - "m_stats.mana, " - "0 AS gender, " - "m_armorinfo.texture, " - "m_armorinfo.helmtexture, " - "m_stats.attack_delay, " - "m_stats.STR, " - "m_stats.STA, " - "m_stats.DEX, " - "m_stats.AGI, " - "m_stats._INT, " - "m_stats.WIS, " - "m_stats.CHA, " - "m_stats.MR, " - "m_stats.CR, " - "m_stats.DR, " - "m_stats.FR, " - "m_stats.PR, " - "m_stats.Corrup, " - "m_stats.mindmg, " - "m_stats.maxdmg, " - "m_stats.attack_count, " - "m_stats.special_abilities, " - "m_weaponinfo.d_melee_texture1, " - "m_weaponinfo.d_melee_texture2, " - "m_weaponinfo.prim_melee_type, " - "m_weaponinfo.sec_melee_type, " - "m_stats.runspeed, " - "m_stats.hp_regen_rate, " - "m_stats.mana_regen_rate, " - "1 AS bodytype, " - "m_armorinfo.armortint_id, " - "m_armorinfo.armortint_red, " - "m_armorinfo.armortint_green, " - "m_armorinfo.armortint_blue, " - "m_stats.AC, " - "m_stats.ATK, " - "m_stats.Accuracy, " - "m_stats.statscale, " - "m_stats.spellscale, " - "m_stats.healscale " - "FROM merc_stats m_stats " - "INNER JOIN merc_armorinfo m_armorinfo " - "ON m_stats.merc_npc_type_id = m_armorinfo.merc_npc_type_id " - "AND m_armorinfo.minlevel <= m_stats.level AND m_armorinfo.maxlevel >= m_stats.level " - "INNER JOIN merc_weaponinfo m_weaponinfo " - "ON m_stats.merc_npc_type_id = m_weaponinfo.merc_npc_type_id " - "AND m_weaponinfo.minlevel <= m_stats.level AND m_weaponinfo.maxlevel >= m_stats.level " - "INNER JOIN merc_templates m_templates " - "ON m_templates.merc_npc_type_id = m_stats.merc_npc_type_id " - "INNER JOIN merc_types m_types " - "ON m_templates.merc_type_id = m_types.merc_type_id " - "INNER JOIN merc_subtypes m_subtypes " - "ON m_templates.merc_subtype_id = m_subtypes.merc_subtype_id " - "WHERE m_templates.merc_npc_type_id = %d AND m_stats.clientlevel = %d AND m_types.race_id = %d", - id, clientlevel, raceid); //dual primary keys. one is ID, one is level. - - auto results = QueryDatabase(query); - if (!results.Success()) { + if (!merc_npc_type_id) { return nullptr; } - const NPCType *npc = nullptr; + const std::string& query = fmt::format( + SQL( + SELECT + m_stats.merc_npc_type_id, + '' AS name, + m_stats.level, + m_types.race_id, + m_subtypes.class_id, + m_stats.hp, + m_stats.mana, + 0 AS gender, + m_armorinfo.texture, + m_armorinfo.helmtexture, + m_stats.attack_delay, + m_stats.STR, + m_stats.STA, + m_stats.DEX, + m_stats.AGI, + m_stats._INT, + m_stats.WIS, + m_stats.CHA, + m_stats.MR, + m_stats.CR, + m_stats.DR, + m_stats.FR, + m_stats.PR, + m_stats.Corrup, + m_stats.mindmg, + m_stats.maxdmg, + m_stats.attack_count, + m_stats.special_abilities, + m_weaponinfo.d_melee_texture1, + m_weaponinfo.d_melee_texture2, + m_weaponinfo.prim_melee_type, + m_weaponinfo.sec_melee_type, + m_stats.runspeed, + m_stats.hp_regen_rate, + m_stats.mana_regen_rate, + 1 AS bodytype, + m_armorinfo.armortint_id, + m_armorinfo.armortint_red, + m_armorinfo.armortint_green, + m_armorinfo.armortint_blue, + m_stats.AC, + m_stats.ATK, + m_stats.Accuracy, + m_stats.statscale, + m_stats.spellscale, + m_stats.healscale + FROM merc_stats m_stats + INNER JOIN merc_armorinfo m_armorinfo + ON m_stats.merc_npc_type_id = m_armorinfo.merc_npc_type_id + AND m_armorinfo.minlevel <= m_stats.level AND m_armorinfo.maxlevel >= m_stats.level + INNER JOIN merc_weaponinfo m_weaponinfo + ON m_stats.merc_npc_type_id = m_weaponinfo.merc_npc_type_id + AND m_weaponinfo.minlevel <= m_stats.level AND m_weaponinfo.maxlevel >= m_stats.level + INNER JOIN merc_templates m_templates + ON m_templates.merc_npc_type_id = m_stats.merc_npc_type_id + INNER JOIN merc_types m_types + ON m_templates.merc_type_id = m_types.merc_type_id + INNER JOIN merc_subtypes m_subtypes + ON m_templates.merc_subtype_id = m_subtypes.merc_subtype_id + WHERE m_templates.merc_npc_type_id = {} AND m_types.race_id = {} AND m_stats.clientlevel = {} + ), + merc_npc_type_id, + race_id, + owner_level + ); - // Process each row returned. - for (auto& row = results.begin(); row != results.end(); ++row) { - NPCType *tmpNPCType; - tmpNPCType = new NPCType; - memset(tmpNPCType, 0, sizeof *tmpNPCType); + auto results = QueryDatabase(query); + if (!results.Success() || !results.RowCount()) { + return nullptr; + } - tmpNPCType->npc_id = Strings::ToInt(row[0]); + const NPCType* n = nullptr; - strn0cpy(tmpNPCType->name, row[1], 50); + auto row = results.begin(); - tmpNPCType->level = Strings::ToInt(row[2]); - tmpNPCType->race = Strings::ToInt(row[3]); - tmpNPCType->class_ = Strings::ToInt(row[4]); - tmpNPCType->max_hp = Strings::ToInt(row[5]); - tmpNPCType->current_hp = tmpNPCType->max_hp; - tmpNPCType->Mana = Strings::ToInt(row[6]); - tmpNPCType->gender = Strings::ToInt(row[7]); - tmpNPCType->texture = Strings::ToInt(row[8]); - tmpNPCType->helmtexture = Strings::ToInt(row[9]); - tmpNPCType->attack_delay = Strings::ToInt(row[10]) * 100; // TODO: fix DB - tmpNPCType->STR = Strings::ToInt(row[11]); - tmpNPCType->STA = Strings::ToInt(row[12]); - tmpNPCType->DEX = Strings::ToInt(row[13]); - tmpNPCType->AGI = Strings::ToInt(row[14]); - tmpNPCType->INT = Strings::ToInt(row[15]); - tmpNPCType->WIS = Strings::ToInt(row[16]); - tmpNPCType->CHA = Strings::ToInt(row[17]); - tmpNPCType->MR = Strings::ToInt(row[18]); - tmpNPCType->CR = Strings::ToInt(row[19]); - tmpNPCType->DR = Strings::ToInt(row[20]); - tmpNPCType->FR = Strings::ToInt(row[21]); - tmpNPCType->PR = Strings::ToInt(row[22]); - tmpNPCType->Corrup = Strings::ToInt(row[23]); - tmpNPCType->min_dmg = Strings::ToInt(row[24]); - tmpNPCType->max_dmg = Strings::ToInt(row[25]); - tmpNPCType->attack_count = Strings::ToInt(row[26]); + NPCType* t = new NPCType; - if (row[27] != nullptr) - strn0cpy(tmpNPCType->special_abilities, row[27], 512); - else - tmpNPCType->special_abilities[0] = '\0'; + memset(t, 0, sizeof *t); - tmpNPCType->d_melee_texture1 = Strings::ToUnsignedInt(row[28]); - tmpNPCType->d_melee_texture2 = Strings::ToUnsignedInt(row[29]); - tmpNPCType->prim_melee_type = Strings::ToInt(row[30]); - tmpNPCType->sec_melee_type = Strings::ToInt(row[31]); - tmpNPCType->runspeed = Strings::ToFloat(row[32]); + t->npc_id = Strings::ToInt(row[0]); - tmpNPCType->hp_regen = Strings::ToInt(row[33]); - tmpNPCType->mana_regen = Strings::ToInt(row[34]); + strn0cpy(t->name, row[1], sizeof(t->name)); - tmpNPCType->aggroradius = RuleI(Mercs, AggroRadius); + t->level = Strings::ToInt(row[2]); + t->race = Strings::ToInt(row[3]); + t->class_ = Strings::ToInt(row[4]); + t->max_hp = Strings::ToInt(row[5]); + t->current_hp = t->max_hp; + t->Mana = Strings::ToInt(row[6]); + t->gender = Strings::ToInt(row[7]); + t->texture = Strings::ToInt(row[8]); + t->helmtexture = Strings::ToInt(row[9]); + t->attack_delay = Strings::ToInt(row[10]) * 100; // TODO: fix DB + t->STR = Strings::ToInt(row[11]); + t->STA = Strings::ToInt(row[12]); + t->DEX = Strings::ToInt(row[13]); + t->AGI = Strings::ToInt(row[14]); + t->INT = Strings::ToInt(row[15]); + t->WIS = Strings::ToInt(row[16]); + t->CHA = Strings::ToInt(row[17]); + t->MR = Strings::ToInt(row[18]); + t->CR = Strings::ToInt(row[19]); + t->DR = Strings::ToInt(row[20]); + t->FR = Strings::ToInt(row[21]); + t->PR = Strings::ToInt(row[22]); + t->Corrup = Strings::ToInt(row[23]); + t->min_dmg = Strings::ToInt(row[24]); + t->max_dmg = Strings::ToInt(row[25]); + t->attack_count = Strings::ToInt(row[26]); - if (row[35] && strlen(row[35])) - tmpNPCType->bodytype = (uint8)Strings::ToInt(row[35]); - else - tmpNPCType->bodytype = 1; + if (row[27]) { + strn0cpy(t->special_abilities, row[27], sizeof(t->special_abilities)); + } else { + t->special_abilities[0] = '\0'; + } - uint32 armor_tint_id = Strings::ToInt(row[36]); - tmpNPCType->armor_tint.Slot[0].Color = (Strings::ToInt(row[37]) & 0xFF) << 16; - tmpNPCType->armor_tint.Slot[0].Color |= (Strings::ToInt(row[38]) & 0xFF) << 8; - tmpNPCType->armor_tint.Slot[0].Color |= (Strings::ToInt(row[39]) & 0xFF); - tmpNPCType->armor_tint.Slot[0].Color |= (tmpNPCType->armor_tint.Slot[0].Color) ? (0xFF << 24) : 0; + t->d_melee_texture1 = Strings::ToUnsignedInt(row[28]); + t->d_melee_texture2 = Strings::ToUnsignedInt(row[29]); + t->prim_melee_type = Strings::ToInt(row[30]); + t->sec_melee_type = Strings::ToInt(row[31]); + t->runspeed = Strings::ToFloat(row[32]); + t->hp_regen = Strings::ToInt(row[33]); + t->mana_regen = Strings::ToInt(row[34]); + t->aggroradius = RuleI(Mercs, AggroRadius); + t->bodytype = row[35] && strlen(row[35]) ? static_cast(Strings::ToUnsignedInt(row[35])) : 1; - if (armor_tint_id == 0) - for (int index = EQ::textures::armorChest; index <= EQ::textures::LastTexture; index++) - tmpNPCType->armor_tint.Slot[index].Color = tmpNPCType->armor_tint.Slot[0].Color; - else if (tmpNPCType->armor_tint.Slot[0].Color == 0) { - std::string armorTint_query = StringFormat("SELECT red1h, grn1h, blu1h, " - "red2c, grn2c, blu2c, " - "red3a, grn3a, blu3a, " - "red4b, grn4b, blu4b, " - "red5g, grn5g, blu5g, " - "red6l, grn6l, blu6l, " - "red7f, grn7f, blu7f, " - "red8x, grn8x, blu8x, " - "red9x, grn9x, blu9x " - "FROM npc_types_tint WHERE id = %d", - armor_tint_id); - auto armorTint_results = QueryDatabase(armorTint_query); - if (!results.Success() || results.RowCount() == 0) - armor_tint_id = 0; - else { - auto& armorTint_row = results.begin(); + uint32 armor_tint_id = Strings::ToInt(row[36]); - for (int index = EQ::textures::textureBegin; index <= EQ::textures::LastTexture; index++) { - tmpNPCType->armor_tint.Slot[index].Color = Strings::ToInt(armorTint_row[index * 3]) << 16; - tmpNPCType->armor_tint.Slot[index].Color |= Strings::ToInt(armorTint_row[index * 3 + 1]) << 8; - tmpNPCType->armor_tint.Slot[index].Color |= Strings::ToInt(armorTint_row[index * 3 + 2]); - tmpNPCType->armor_tint.Slot[index].Color |= (tmpNPCType->armor_tint.Slot[index].Color) ? (0xFF << 24) : 0; - } - } - } else + t->armor_tint.Slot[0].Color = (Strings::ToInt(row[37]) & 0xFF) << 16; + t->armor_tint.Slot[0].Color |= (Strings::ToInt(row[38]) & 0xFF) << 8; + t->armor_tint.Slot[0].Color |= (Strings::ToInt(row[39]) & 0xFF); + t->armor_tint.Slot[0].Color |= (t->armor_tint.Slot[0].Color) ? (0xFF << 24) : 0; + + if (armor_tint_id == 0) { + for (int index = EQ::textures::armorChest; index <= EQ::textures::LastTexture; index++) { + t->armor_tint.Slot[index].Color = t->armor_tint.Slot[0].Color; + } + } else if (t->armor_tint.Slot[0].Color == 0) { + const auto& e = NpcTypesTintRepository::FindOne(*this, armor_tint_id); + if (!e.id) { armor_tint_id = 0; + } else { + t->armor_tint.Slot[EQ::textures::armorHead].Color = e.red1h << 16; + t->armor_tint.Slot[EQ::textures::armorHead].Color = e.grn1h << 8; + t->armor_tint.Slot[EQ::textures::armorHead].Color = e.blu1h; - tmpNPCType->AC = Strings::ToInt(row[40]); - tmpNPCType->ATK = Strings::ToInt(row[41]); - tmpNPCType->accuracy_rating = Strings::ToInt(row[42]); - tmpNPCType->scalerate = Strings::ToInt(row[43]); - tmpNPCType->spellscale = Strings::ToInt(row[44]); - tmpNPCType->healscale = Strings::ToInt(row[45]); - tmpNPCType->skip_global_loot = true; - tmpNPCType->skip_auto_scale = true; + t->armor_tint.Slot[EQ::textures::armorChest].Color = e.red2c << 16; + t->armor_tint.Slot[EQ::textures::armorChest].Color = e.grn2c << 8; + t->armor_tint.Slot[EQ::textures::armorChest].Color = e.blu2c; - // If Merc with duplicate NPC id already in table, - // free item we attempted to add. - if (zone->merctable.find(merc_type_id) != zone->merctable.end()) { - delete tmpNPCType; - return nullptr; + t->armor_tint.Slot[EQ::textures::armorArms].Color = e.red3a << 16; + t->armor_tint.Slot[EQ::textures::armorArms].Color = e.grn3a << 8; + t->armor_tint.Slot[EQ::textures::armorArms].Color = e.blu3a; + + t->armor_tint.Slot[EQ::textures::armorWrist].Color = e.red4b << 16; + t->armor_tint.Slot[EQ::textures::armorWrist].Color = e.grn4b << 8; + t->armor_tint.Slot[EQ::textures::armorWrist].Color = e.blu4b; + + t->armor_tint.Slot[EQ::textures::armorHands].Color = e.red5g << 16; + t->armor_tint.Slot[EQ::textures::armorHands].Color = e.grn5g << 8; + t->armor_tint.Slot[EQ::textures::armorHands].Color = e.blu5g; + + t->armor_tint.Slot[EQ::textures::armorLegs].Color = e.red6l << 16; + t->armor_tint.Slot[EQ::textures::armorLegs].Color = e.grn6l << 8; + t->armor_tint.Slot[EQ::textures::armorLegs].Color = e.blu6l; + + t->armor_tint.Slot[EQ::textures::armorFeet].Color = e.red7f << 16; + t->armor_tint.Slot[EQ::textures::armorFeet].Color = e.grn7f << 8; + t->armor_tint.Slot[EQ::textures::armorFeet].Color = e.blu7f; + + t->armor_tint.Slot[EQ::textures::weaponPrimary].Color = e.red8x << 16; + t->armor_tint.Slot[EQ::textures::weaponPrimary].Color = e.grn8x << 8; + t->armor_tint.Slot[EQ::textures::weaponPrimary].Color = e.blu8x; + + t->armor_tint.Slot[EQ::textures::weaponSecondary].Color = e.red9x << 16; + t->armor_tint.Slot[EQ::textures::weaponSecondary].Color = e.grn9x << 8; + t->armor_tint.Slot[EQ::textures::weaponSecondary].Color = e.blu9x; } - - zone->merctable[merc_type_id] = tmpNPCType; - npc = tmpNPCType; } - return npc; + t->AC = Strings::ToInt(row[40]); + t->ATK = Strings::ToInt(row[41]); + t->accuracy_rating = Strings::ToInt(row[42]); + t->scalerate = Strings::ToInt(row[43]); + t->spellscale = Strings::ToInt(row[44]); + t->healscale = Strings::ToInt(row[45]); + t->skip_global_loot = true; + t->skip_auto_scale = true; + + // If Merc with duplicate NPC id already in table, + // free item we attempted to add. + if (zone->merctable.find(merc_type_id) != zone->merctable.end()) { + delete t; + return nullptr; + } + + zone->merctable[merc_type_id] = t; + n = t; + + return n; } -bool ZoneDatabase::LoadMercInfo(Client *client) { +bool ZoneDatabase::LoadMercenaryInfo(Client* c) +{ + const auto& l = MercsRepository::GetWhere( + *this, + fmt::format( + "`OwnerCharacterID` = {} ORDER BY `Slot`", + c->CharacterID() + ) + ); - std::string query = StringFormat("SELECT MercID, Slot, Name, TemplateID, SuspendedTime, " - "IsSuspended, TimerRemaining, Gender, MercSize, StanceID, HP, Mana, " - "Endurance, Face, LuclinHairStyle, LuclinHairColor, " - "LuclinEyeColor, LuclinEyeColor2, LuclinBeardColor, LuclinBeard, " - "DrakkinHeritage, DrakkinTattoo, DrakkinDetails " - "FROM mercs WHERE OwnerCharacterID = '%i' ORDER BY Slot", client->CharacterID()); - auto results = QueryDatabase(query); - if (!results.Success()) - return false; - - if(results.RowCount() == 0) - return false; - - for (auto& row = results.begin(); row != results.end(); ++row) { - uint8 slot = Strings::ToInt(row[1]); - - if(slot >= MAXMERCS) - continue; - - client->GetMercInfo(slot).mercid = Strings::ToInt(row[0]); - client->GetMercInfo(slot).slot = slot; - snprintf(client->GetMercInfo(slot).merc_name, 64, "%s", row[2]); - client->GetMercInfo(slot).MercTemplateID = Strings::ToInt(row[3]); - client->GetMercInfo(slot).SuspendedTime = Strings::ToInt(row[4]); - client->GetMercInfo(slot).IsSuspended = Strings::ToInt(row[5]) == 1 ? true : false; - client->GetMercInfo(slot).MercTimerRemaining = Strings::ToInt(row[6]); - client->GetMercInfo(slot).Gender = Strings::ToInt(row[7]); - client->GetMercInfo(slot).MercSize = Strings::ToFloat(row[8]); - client->GetMercInfo(slot).State = 5; - client->GetMercInfo(slot).Stance = Strings::ToInt(row[9]); - client->GetMercInfo(slot).hp = Strings::ToInt(row[10]); - client->GetMercInfo(slot).mana = Strings::ToInt(row[11]); - client->GetMercInfo(slot).endurance = Strings::ToInt(row[12]); - client->GetMercInfo(slot).face = Strings::ToInt(row[13]); - client->GetMercInfo(slot).luclinHairStyle = Strings::ToInt(row[14]); - client->GetMercInfo(slot).luclinHairColor = Strings::ToInt(row[15]); - client->GetMercInfo(slot).luclinEyeColor = Strings::ToInt(row[16]); - client->GetMercInfo(slot).luclinEyeColor2 = Strings::ToInt(row[17]); - client->GetMercInfo(slot).luclinBeardColor = Strings::ToInt(row[18]); - client->GetMercInfo(slot).luclinBeard = Strings::ToInt(row[19]); - client->GetMercInfo(slot).drakkinHeritage = Strings::ToInt(row[20]); - client->GetMercInfo(slot).drakkinTattoo = Strings::ToInt(row[21]); - client->GetMercInfo(slot).drakkinDetails = Strings::ToInt(row[22]); - } - - return true; -} - -bool ZoneDatabase::LoadCurrentMerc(Client *client) { - - uint8 slot = client->GetMercSlot(); - - if(slot > MAXMERCS) - return false; - - std::string query = StringFormat("SELECT MercID, Name, TemplateID, SuspendedTime, " - "IsSuspended, TimerRemaining, Gender, MercSize, StanceID, HP, " - "Mana, Endurance, Face, LuclinHairStyle, LuclinHairColor, " - "LuclinEyeColor, LuclinEyeColor2, LuclinBeardColor, " - "LuclinBeard, DrakkinHeritage, DrakkinTattoo, DrakkinDetails " - "FROM mercs WHERE OwnerCharacterID = '%i' AND Slot = '%u'", - client->CharacterID(), slot); - auto results = database.QueryDatabase(query); - - if(!results.Success()) - return false; - - if(results.RowCount() == 0) - return false; - - - for (auto& row = results.begin(); row != results.end(); ++row) { - client->GetMercInfo(slot).mercid = Strings::ToInt(row[0]); - client->GetMercInfo(slot).slot = slot; - snprintf(client->GetMercInfo(slot).merc_name, 64, "%s", row[1]); - client->GetMercInfo(slot).MercTemplateID = Strings::ToInt(row[2]); - client->GetMercInfo(slot).SuspendedTime = Strings::ToInt(row[3]); - client->GetMercInfo(slot).IsSuspended = Strings::ToInt(row[4]) == 1? true: false; - client->GetMercInfo(slot).MercTimerRemaining = Strings::ToInt(row[5]); - client->GetMercInfo(slot).Gender = Strings::ToInt(row[6]); - client->GetMercInfo(slot).MercSize = Strings::ToFloat(row[7]); - client->GetMercInfo(slot).State = Strings::ToInt(row[8]); - client->GetMercInfo(slot).hp = Strings::ToInt(row[9]); - client->GetMercInfo(slot).mana = Strings::ToInt(row[10]); - client->GetMercInfo(slot).endurance = Strings::ToInt(row[11]); - client->GetMercInfo(slot).face = Strings::ToInt(row[12]); - client->GetMercInfo(slot).luclinHairStyle = Strings::ToInt(row[13]); - client->GetMercInfo(slot).luclinHairColor = Strings::ToInt(row[14]); - client->GetMercInfo(slot).luclinEyeColor = Strings::ToInt(row[15]); - client->GetMercInfo(slot).luclinEyeColor2 = Strings::ToInt(row[16]); - client->GetMercInfo(slot).luclinBeardColor = Strings::ToInt(row[17]); - client->GetMercInfo(slot).luclinBeard = Strings::ToInt(row[18]); - client->GetMercInfo(slot).drakkinHeritage = Strings::ToInt(row[19]); - client->GetMercInfo(slot).drakkinTattoo = Strings::ToInt(row[20]); - client->GetMercInfo(slot).drakkinDetails = Strings::ToInt(row[21]); - } - - return true; -} - -bool ZoneDatabase::SaveMerc(Merc *merc) { - Client *owner = merc->GetMercOwner(); - - if(!owner) - return false; - - if(merc->GetMercID() == 0) - { - // New merc record - std::string query = StringFormat("INSERT INTO mercs " - "(OwnerCharacterID, Slot, Name, TemplateID, " - "SuspendedTime, IsSuspended, TimerRemaining, " - "Gender, MercSize, StanceID, HP, Mana, Endurance, Face, " - "LuclinHairStyle, LuclinHairColor, LuclinEyeColor, " - "LuclinEyeColor2, LuclinBeardColor, LuclinBeard, " - "DrakkinHeritage, DrakkinTattoo, DrakkinDetails) " - "VALUES('%u', '%u', '%s', '%u', '%u', '%u', '%u', " - "'%u', '%u', '%f', '%u', '%u', '%u', '%i', '%i', '%i', " - "'%i', '%i', '%i', '%i', '%i', '%i', '%i')", - merc->GetMercCharacterID(), owner->GetNumMercs(), - merc->GetCleanName(), merc->GetMercTemplateID(), - owner->GetMercInfo().SuspendedTime, merc->IsSuspended(), - owner->GetMercInfo().MercTimerRemaining, merc->GetGender(), - merc->GetSize(), merc->GetStance(), merc->GetHP(), - merc->GetMana(), merc->GetEndurance(), merc->GetLuclinFace(), - merc->GetHairStyle(), merc->GetHairColor(), merc->GetEyeColor1(), - merc->GetEyeColor2(), merc->GetBeardColor(), - merc->GetBeard(), merc->GetDrakkinHeritage(), - merc->GetDrakkinTattoo(), merc->GetDrakkinDetails()); - - auto results = database.QueryDatabase(query); - if(!results.Success()) { - owner->Message(Chat::Red, results.ErrorMessage().c_str()); - return false; - } else if (results.RowsAffected() != 1) { - owner->Message(Chat::Red, "Unable to save merc to the database."); - return false; - } - - merc->SetMercID(results.LastInsertedID()); - merc->UpdateMercInfo(owner); - database.SaveMercBuffs(merc); - return true; - } - - // Update existing merc record - std::string query = StringFormat("UPDATE mercs SET OwnerCharacterID = '%u', Slot = '%u', " - "Name = '%s', TemplateID = '%u', SuspendedTime = '%u', " - "IsSuspended = '%u', TimerRemaining = '%u', Gender = '%u', MercSize = '%f', " - "StanceID = '%u', HP = '%u', Mana = '%u', Endurance = '%u', " - "Face = '%i', LuclinHairStyle = '%i', LuclinHairColor = '%i', " - "LuclinEyeColor = '%i', LuclinEyeColor2 = '%i', LuclinBeardColor = '%i', " - "LuclinBeard = '%i', DrakkinHeritage = '%i', DrakkinTattoo = '%i', " - "DrakkinDetails = '%i' WHERE MercID = '%u'", - merc->GetMercCharacterID(), owner->GetMercSlot(), merc->GetCleanName(), - merc->GetMercTemplateID(), owner->GetMercInfo().SuspendedTime, - merc->IsSuspended(), owner->GetMercInfo().MercTimerRemaining, - merc->GetGender(), merc->GetSize(), merc->GetStance(), merc->GetHP(), - merc->GetMana(), merc->GetEndurance(), merc->GetLuclinFace(), - merc->GetHairStyle(), merc->GetHairColor(), merc->GetEyeColor1(), - merc->GetEyeColor2(), merc->GetBeardColor(), merc->GetBeard(), - merc->GetDrakkinHeritage(), merc->GetDrakkinTattoo(), merc->GetDrakkinDetails(), - merc->GetMercID()); - - auto results = database.QueryDatabase(query); - if (!results.Success()) { - owner->Message(Chat::Red, results.ErrorMessage().c_str()); - return false; - } else if (results.RowsAffected() != 1) { - owner->Message(Chat::Red, "Unable to save merc to the database."); + if (l.empty()) { return false; } - merc->UpdateMercInfo(owner); - database.SaveMercBuffs(merc); - - return true; -} - -void ZoneDatabase::SaveMercBuffs(Merc *merc) { - - Buffs_Struct *buffs = merc->GetBuffs(); - - // Remove any existing buff saves - std::string query = StringFormat("DELETE FROM merc_buffs WHERE MercId = %u", merc->GetMercID()); - auto results = database.QueryDatabase(query); - if (!results.Success()) { - LogError("Error While Deleting Merc Buffs before save: [{}]", results.ErrorMessage().c_str()); - return; - } - - for (int buffCount = 0; buffCount <= BUFF_COUNT; buffCount++) { - if (!IsValidSpell(buffs[buffCount].spellid)) { + for (const auto& e : l) { + if (e.Slot >= MAXMERCS) { continue; } - int IsPersistent = buffs[buffCount].persistant_buff? 1: 0; + auto& m = c->GetMercInfo(e.Slot); - query = StringFormat("INSERT INTO merc_buffs (MercId, SpellId, CasterLevel, DurationFormula, " - "TicsRemaining, PoisonCounters, DiseaseCounters, CurseCounters, " - "CorruptionCounters, HitCount, MeleeRune, MagicRune, dot_rune, " - "caston_x, Persistent, caston_y, caston_z, ExtraDIChance) " - "VALUES (%u, %u, %u, %u, %u, %d, %u, %u, %u, %u, %u, %u, %u, %i, %u, %i, %i, %i);", - merc->GetMercID(), buffs[buffCount].spellid, buffs[buffCount].casterlevel, - spells[buffs[buffCount].spellid].buff_duration_formula, buffs[buffCount].ticsremaining, - CalculatePoisonCounters(buffs[buffCount].spellid) > 0 ? buffs[buffCount].counters : 0, - CalculateDiseaseCounters(buffs[buffCount].spellid) > 0 ? buffs[buffCount].counters : 0, - CalculateCurseCounters(buffs[buffCount].spellid) > 0 ? buffs[buffCount].counters : 0, - CalculateCorruptionCounters(buffs[buffCount].spellid) > 0 ? buffs[buffCount].counters : 0, - buffs[buffCount].hit_number, buffs[buffCount].melee_rune, buffs[buffCount].magic_rune, - buffs[buffCount].dot_rune, buffs[buffCount].caston_x, IsPersistent, buffs[buffCount].caston_y, - buffs[buffCount].caston_z, buffs[buffCount].ExtraDIChance); - results = database.QueryDatabase(query); - if(!results.Success()) { - LogError("Error Saving Merc Buffs: [{}]", results.ErrorMessage().c_str()); - break; - } + strn0cpy(m.merc_name, e.Name.c_str(), sizeof(m.merc_name)); + + m.mercid = e.MercID; + m.slot = e.Slot; + m.MercTemplateID = e.TemplateID; + m.SuspendedTime = e.SuspendedTime; + m.IsSuspended = e.IsSuspended; + m.MercTimerRemaining = e.TimerRemaining; + m.Gender = e.Gender; + m.MercSize = e.MercSize; + m.State = 5; + m.Stance = e.StanceID; + m.hp = e.HP; + m.mana = e.Mana; + m.endurance = e.Endurance; + m.face = e.Face; + m.luclinHairStyle = e.LuclinHairStyle; + m.luclinHairColor = e.LuclinHairColor; + m.luclinEyeColor = e.LuclinEyeColor; + m.luclinEyeColor2 = e.LuclinEyeColor2; + m.luclinBeardColor = e.LuclinBeardColor; + m.luclinBeard = e.LuclinBeard; + m.drakkinHeritage = e.DrakkinHeritage; + m.drakkinTattoo = e.DrakkinTattoo; + m.drakkinDetails = e.DrakkinDetails; } + + return true; } -void ZoneDatabase::LoadMercBuffs(Merc *merc) { - Buffs_Struct *buffs = merc->GetBuffs(); - uint32 max_slots = merc->GetMaxBuffSlots(); +bool ZoneDatabase::LoadCurrentMercenary(Client* c) +{ + const uint8 mercenary_slot = c->GetMercSlot(); + if (mercenary_slot > MAXMERCS) { + return false; + } - bool BuffsLoaded = false; - std::string query = StringFormat("SELECT SpellId, CasterLevel, DurationFormula, TicsRemaining, " - "PoisonCounters, DiseaseCounters, CurseCounters, CorruptionCounters, " - "HitCount, MeleeRune, MagicRune, dot_rune, caston_x, Persistent, " - "caston_y, caston_z, ExtraDIChance FROM merc_buffs WHERE MercId = %u", - merc->GetMercID()); - auto results = database.QueryDatabase(query); - if(!results.Success()) { - LogError("Error Loading Merc Buffs: [{}]", results.ErrorMessage().c_str()); + const auto& e = MercsRepository::GetMercenaryBySlot(*this, c); + + if (!e.MercID) { + return false; + } + + auto& m = c->GetMercInfo(mercenary_slot); + + strn0cpy(m.merc_name, e.Name.c_str(), sizeof(m.merc_name)); + + m.mercid = e.MercID; + m.slot = e.Slot; + m.MercTemplateID = e.TemplateID; + m.SuspendedTime = e.SuspendedTime; + m.IsSuspended = e.IsSuspended; + m.MercTimerRemaining = e.TimerRemaining; + m.Gender = e.Gender; + m.MercSize = e.MercSize; + m.State = e.StanceID; + m.hp = e.HP; + m.mana = e.Mana; + m.endurance = e.Endurance; + m.face = e.Face; + m.luclinHairStyle = e.LuclinHairStyle; + m.luclinHairColor = e.LuclinHairColor; + m.luclinEyeColor = e.LuclinEyeColor; + m.luclinEyeColor2 = e.LuclinEyeColor2; + m.luclinBeardColor = e.LuclinBeardColor; + m.luclinBeard = e.LuclinBeard; + m.drakkinHeritage = e.DrakkinHeritage; + m.drakkinTattoo = e.DrakkinTattoo; + m.drakkinDetails = e.DrakkinDetails; + + return true; +} + +bool ZoneDatabase::SaveMercenary(Merc* m) +{ + Client* c = m->GetMercenaryOwner(); + + if (!c) { + return false; + } + + if (!m->GetMercenaryID()) { + auto e = MercsRepository::NewEntity(); + + e.OwnerCharacterID = m->GetMercenaryCharacterID(); + e.Slot = c->GetNumberOfMercenaries(); + e.Name = m->GetCleanName(); + e.TemplateID = m->GetMercenaryTemplateID(); + e.SuspendedTime = c->GetMercInfo().SuspendedTime; + e.IsSuspended = m->IsSuspended(); + e.TimerRemaining = c->GetMercInfo().MercTimerRemaining; + e.Gender = m->GetGender(); + e.MercSize = m->GetSize(); + e.StanceID = m->GetStance(); + e.HP = m->GetHP(); + e.Mana = m->GetMana(); + e.Endurance = m->GetEndurance(); + e.Face = m->GetLuclinFace(); + e.LuclinHairStyle = m->GetHairStyle(); + e.LuclinHairColor = m->GetHairColor(); + e.LuclinEyeColor = m->GetEyeColor1(); + e.LuclinEyeColor2 = m->GetEyeColor2(); + e.LuclinBeardColor = m->GetBeardColor(); + e.LuclinBeard = m->GetBeard(); + e.DrakkinHeritage = m->GetDrakkinHeritage(); + e.DrakkinTattoo = m->GetDrakkinTattoo(); + e.DrakkinDetails = m->GetDrakkinDetails(); + + e = MercsRepository::InsertOne(*this, e); + + if (!e.MercID) { + c->Message(Chat::Red, "Unable to save mercenary to the database."); + return false; + } + + m->SetMercID(e.MercID); + m->UpdateMercInfo(c); + + database.SaveMercenaryBuffs(m); + + return true; + } + + auto e = MercsRepository::FindOne(*this, m->GetMercenaryID()); + + e.OwnerCharacterID = m->GetMercenaryCharacterID(); + e.Slot = c->GetNumberOfMercenaries(); + e.Name = m->GetCleanName(); + e.TemplateID = m->GetMercenaryTemplateID(); + e.SuspendedTime = c->GetMercInfo().SuspendedTime; + e.IsSuspended = m->IsSuspended(); + e.TimerRemaining = c->GetMercInfo().MercTimerRemaining; + e.Gender = m->GetGender(); + e.MercSize = m->GetSize(); + e.StanceID = m->GetStance(); + e.HP = m->GetHP(); + e.Mana = m->GetMana(); + e.Endurance = m->GetEndurance(); + e.Face = m->GetLuclinFace(); + e.LuclinHairStyle = m->GetHairStyle(); + e.LuclinHairColor = m->GetHairColor(); + e.LuclinEyeColor = m->GetEyeColor1(); + e.LuclinEyeColor2 = m->GetEyeColor2(); + e.LuclinBeardColor = m->GetBeardColor(); + e.LuclinBeard = m->GetBeard(); + e.DrakkinHeritage = m->GetDrakkinHeritage(); + e.DrakkinTattoo = m->GetDrakkinTattoo(); + e.DrakkinDetails = m->GetDrakkinDetails(); + + const int updated = MercsRepository::UpdateOne(*this, e); + + if (!updated) { + c->Message(Chat::Red, "Unable to save mercenary to the database."); + return false; + } + + m->UpdateMercInfo(c); + + database.SaveMercenaryBuffs(m); + + return true; +} + +void ZoneDatabase::SaveMercenaryBuffs(Merc* m) +{ + auto buffs = m->GetBuffs(); + + MercBuffsRepository::DeleteWhere( + *this, + fmt::format( + "`MercID` = {}", + m->GetMercenaryID() + ) + ); + + std::vector v; + + auto e = MercBuffsRepository::NewEntity(); + + for (uint32 slot_id = 0; slot_id <= BUFF_COUNT; slot_id++) { + if (!IsValidSpell(buffs[slot_id].spellid)) { + continue; + } + + e.MercId = m->GetMercenaryID(); + e.SpellId = buffs[slot_id].spellid; + e.CasterLevel = buffs[slot_id].casterlevel; + e.DurationFormula = spells[buffs[slot_id].spellid].buff_duration_formula; + e.TicsRemaining = buffs[slot_id].ticsremaining; + e.PoisonCounters = CalculatePoisonCounters(buffs[slot_id].spellid) > 0 ? buffs[slot_id].counters : 0; + e.DiseaseCounters = CalculateDiseaseCounters(buffs[slot_id].spellid) > 0 ? buffs[slot_id].counters : 0; + e.CurseCounters = CalculateCurseCounters(buffs[slot_id].spellid) > 0 ? buffs[slot_id].counters : 0; + e.CorruptionCounters = CalculateCorruptionCounters(buffs[slot_id].spellid) > 0 ? buffs[slot_id].counters : 0; + e.HitCount = buffs[slot_id].hit_number; + e.MeleeRune = buffs[slot_id].melee_rune; + e.MagicRune = buffs[slot_id].magic_rune; + e.dot_rune = buffs[slot_id].dot_rune; + e.caston_x = buffs[slot_id].caston_x; + e.caston_y = buffs[slot_id].caston_y; + e.caston_z = buffs[slot_id].caston_z; + e.Persistent = buffs[slot_id].persistant_buff ? 1 : 0; + e.ExtraDIChance = buffs[slot_id].ExtraDIChance; + + v.emplace_back(e); + } + + MercBuffsRepository::InsertMany(*this, v); +} + +void ZoneDatabase::LoadMercenaryBuffs(Merc* m) +{ + auto buffs = m->GetBuffs(); + const int max_slots = m->GetMaxBuffSlots(); + + const auto& l = MercBuffsRepository::GetWhere( + *this, + fmt::format( + "`MercID` = {}", + m->GetMercenaryID() + ) + ); + + if (l.empty()) { return; } - int buffCount = 0; - for (auto& row = results.begin(); row != results.end(); ++row, ++buffCount) { - if(buffCount == BUFF_COUNT) - break; + uint32 slot_id = 0; - buffs[buffCount].spellid = Strings::ToInt(row[0]); - buffs[buffCount].casterlevel = Strings::ToInt(row[1]); - buffs[buffCount].ticsremaining = Strings::ToInt(row[3]); + for (const auto& e : l) { + if (slot_id == BUFF_COUNT) { + break; + } - if(CalculatePoisonCounters(buffs[buffCount].spellid) > 0) - buffs[buffCount].counters = Strings::ToInt(row[4]); + buffs[slot_id].spellid = e.SpellId; + buffs[slot_id].casterlevel = e.CasterLevel; + buffs[slot_id].ticsremaining = e.TicsRemaining; + buffs[slot_id].hit_number = e.HitCount; + buffs[slot_id].melee_rune = e.MeleeRune; + buffs[slot_id].magic_rune = e.MagicRune; + buffs[slot_id].dot_rune = e.dot_rune; + buffs[slot_id].caston_x = e.caston_x; + buffs[slot_id].caston_y = e.caston_y; + buffs[slot_id].caston_z = e.caston_z; + buffs[slot_id].casterid = 0; + buffs[slot_id].ExtraDIChance = e.ExtraDIChance; + buffs[slot_id].persistant_buff = e.Persistent; - if(CalculateDiseaseCounters(buffs[buffCount].spellid) > 0) - buffs[buffCount].counters = Strings::ToInt(row[5]); + if (CalculatePoisonCounters(buffs[slot_id].spellid) > 0) { + buffs[slot_id].counters = e.PoisonCounters; + } - if(CalculateCurseCounters(buffs[buffCount].spellid) > 0) - buffs[buffCount].counters = Strings::ToInt(row[6]); + if (CalculateDiseaseCounters(buffs[slot_id].spellid) > 0) { + buffs[slot_id].counters = e.DiseaseCounters; + } - if(CalculateCorruptionCounters(buffs[buffCount].spellid) > 0) - buffs[buffCount].counters = Strings::ToInt(row[7]); + if (CalculateCurseCounters(buffs[slot_id].spellid) > 0) { + buffs[slot_id].counters = e.CurseCounters; + } - buffs[buffCount].hit_number = Strings::ToInt(row[8]); - buffs[buffCount].melee_rune = Strings::ToInt(row[9]); - buffs[buffCount].magic_rune = Strings::ToInt(row[10]); - buffs[buffCount].dot_rune = Strings::ToInt(row[11]); - buffs[buffCount].caston_x = Strings::ToInt(row[12]); - buffs[buffCount].casterid = 0; - - bool IsPersistent = Strings::ToInt(row[13])? true: false; - - buffs[buffCount].caston_y = Strings::ToInt(row[13]); - buffs[buffCount].caston_z = Strings::ToInt(row[14]); - buffs[buffCount].ExtraDIChance = Strings::ToInt(row[15]); - - buffs[buffCount].persistant_buff = IsPersistent; - - } - - query = StringFormat("DELETE FROM merc_buffs WHERE MercId = %u", merc->GetMercID()); - results = database.QueryDatabase(query); - if(!results.Success()) - LogError("Error Loading Merc Buffs: [{}]", results.ErrorMessage().c_str()); - -} - -bool ZoneDatabase::DeleteMerc(uint32 merc_id) { - - if(merc_id == 0) - return false; - - // TODO: These queries need to be ran together as a transaction.. ie, - // if one or more fail then they all will fail to commit to the database. - // ...Not all mercs will have buffs, so why is it required that both deletes succeed? - std::string query = StringFormat("DELETE FROM merc_buffs WHERE MercId = '%u'", merc_id); - auto results = database.QueryDatabase(query); - if(!results.Success()) - { - LogError("Error Deleting Merc Buffs: [{}]", results.ErrorMessage().c_str()); + if (CalculateCorruptionCounters(buffs[slot_id].spellid) > 0) { + buffs[slot_id].counters = e.CorruptionCounters; + } } - query = StringFormat("DELETE FROM mercs WHERE MercID = '%u'", merc_id); - results = database.QueryDatabase(query); - if(!results.Success()) - { - LogError("Error Deleting Merc: [{}]", results.ErrorMessage().c_str()); + MercBuffsRepository::DeleteWhere( + *this, + fmt::format( + "`MercID` = {}", + m->GetMercenaryID() + ) + ); +} + +bool ZoneDatabase::DeleteMercenary(uint32 mercenary_id) +{ + if (!mercenary_id) { + return false; + } + + MercBuffsRepository::DeleteWhere( + *this, + fmt::format( + "`MercID` = {}", + mercenary_id + ) + ); + + const int deleted = MercsRepository::DeleteOne(*this, mercenary_id); + if (!deleted) { return false; } return true; } -void ZoneDatabase::LoadMercEquipment(Merc *merc) { +void ZoneDatabase::LoadMercenaryEquipment(Merc* m) +{ + const int merc_subtype_id = MercSubtypesRepository::GetSubtype(*this, m->GetClass(), m->GetTierID()); - std::string query = StringFormat("SELECT item_id FROM merc_inventory " - "WHERE merc_subtype_id = (" - "SELECT merc_subtype_id FROM merc_subtypes " - "WHERE class_id = '%u' AND tier_id = '%u') " - "AND min_level <= %u AND max_level >= %u", - merc->GetClass(), merc->GetTierID(), - merc->GetLevel(), merc->GetLevel()); - auto results = database.QueryDatabase(query); - if(!results.Success()) { - LogError("Error Loading Merc Inventory: [{}]", results.ErrorMessage().c_str()); + const auto& l = MercInventoryRepository::GetWhere( + *this, + fmt::format( + "`merc_subtype_id` = {} AND `min_level` <= {} AND `max_level` >= {}", + merc_subtype_id, + m->GetLevel(), + m->GetLevel() + ) + ); + + if (l.empty()) { return; } - int itemCount = 0; - for(auto& row = results.begin(); row != results.end(); ++row) { - if (itemCount == EQ::invslot::EQUIPMENT_COUNT) - break; + uint32 item_count = 0; - if(Strings::ToInt(row[0]) == 0) - continue; + for (const auto& e: l) { + if (item_count == EQ::invslot::EQUIPMENT_COUNT) { + break; + } - merc->AddItem(itemCount, Strings::ToInt(row[0])); - itemCount++; - } + if (!e.item_id) { + continue; + } + + m->AddItem(item_count, e.item_id); + + item_count++; + } } uint8 ZoneDatabase::GetGridType(uint32 grid, uint32 zoneid ) { diff --git a/zone/zonedb.h b/zone/zonedb.h index 5c8161782..38e0df95a 100644 --- a/zone/zonedb.h +++ b/zone/zonedb.h @@ -581,14 +581,14 @@ public: void ClearBotSpells() { bot_spells_cache.clear(); bot_spells_loadtried.clear(); } /* Mercs */ - const NPCType* GetMercType(uint32 id, uint16 raceid, uint32 clientlevel); - void LoadMercEquipment(Merc *merc); - void SaveMercBuffs(Merc *merc); - void LoadMercBuffs(Merc *merc); - bool LoadMercInfo(Client *c); - bool LoadCurrentMerc(Client *c); - bool SaveMerc(Merc *merc); - bool DeleteMerc(uint32 merc_id); + const NPCType* GetMercenaryType(uint32 id, uint16 race_id, uint32 owner_level); + void LoadMercenaryEquipment(Merc* m); + void SaveMercenaryBuffs(Merc* m); + void LoadMercenaryBuffs(Merc* m); + bool LoadMercenaryInfo(Client* c); + bool LoadCurrentMercenary(Client* c); + bool SaveMercenary(Merc* m); + bool DeleteMercenary(uint32 mercenary_id); /* Petitions */ void DeletePetitionFromDB(Petition* wpet);