From 657ff9f35db2954084b9073ff5dda6de39b1d57b Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 16 Jan 2025 21:01:58 +0100 Subject: [PATCH] Refactor + fix skill validation --- src/bot/Brokk/Brokk.vcxproj | 3 + src/bot/Brokk/Brokk.vcxproj.filters | 6 + src/bot/Brokk/brokk.cpp | 180 +++++++++++++++++++++++----- src/bot/Brokk/brokk.hpp | 3 +- src/bot/Brokk/helper_skills.cpp | 175 +++++++++++++-------------- src/bot/Brokk/helper_skills.hpp | 5 +- 6 files changed, 241 insertions(+), 131 deletions(-) diff --git a/src/bot/Brokk/Brokk.vcxproj b/src/bot/Brokk/Brokk.vcxproj index 84b8a78..0c005d7 100644 --- a/src/bot/Brokk/Brokk.vcxproj +++ b/src/bot/Brokk/Brokk.vcxproj @@ -115,6 +115,7 @@ MultiThreadedDebug $(SolutionDir)src;$(SolutionDir)3rdparty\rapidyaml\src;$(SolutionDir)3rdparty\rapidyaml\ext\c4core\src;$(SolutionDir)3rdparty\libconfig\;$(SolutionDir)src\login;$(SolutionDir)src\map;$(SolutionDir)src\char;%(AdditionalIncludeDirectories) true + /bigobj %(AdditionalOptions) Console @@ -144,6 +145,7 @@ + @@ -152,6 +154,7 @@ + diff --git a/src/bot/Brokk/Brokk.vcxproj.filters b/src/bot/Brokk/Brokk.vcxproj.filters index dae25ce..be66e61 100644 --- a/src/bot/Brokk/Brokk.vcxproj.filters +++ b/src/bot/Brokk/Brokk.vcxproj.filters @@ -33,6 +33,9 @@ Quelldateien + + Quelldateien + @@ -56,5 +59,8 @@ Headerdateien + + Headerdateien + \ No newline at end of file diff --git a/src/bot/Brokk/brokk.cpp b/src/bot/Brokk/brokk.cpp index 5b65ee3..6b997b8 100644 --- a/src/bot/Brokk/brokk.cpp +++ b/src/bot/Brokk/brokk.cpp @@ -41,6 +41,7 @@ #include "char_creation_helpers.hpp" #include "helper_skills.hpp" +#include "helper_inventory.hpp" using namespace rathena; using namespace rathena::server_brokk; @@ -54,11 +55,13 @@ AccountDB* login_accounts = nullptr; BotAccountDB* bot_accounts = nullptr; CharDB* charakters = nullptr; SkillDB* skills = nullptr; +InventoryDB* inventory = nullptr; // YAML DB Objects of all touched infrastucture BotStatPointDatabase bot_statpoint_db; BotJobDatabase bot_job_db; //BotSkillTreeDatabase bot_skill_tree_db; +//BotItemDatabase bot_item_db; // Advanced subnet check [LuzZza] struct s_subnet { @@ -166,7 +169,7 @@ int brokk_mmo_auth_new(const char* userid, const char* pass, const char sex, con // Check if the bot account already exists if (bot_accounts->load_num(bot_accounts, &bot_acc, acc.account_id)) { - ShowNotice("Attempt to create an already existing bot account (account: %s, sex: %c)\n", acc.account_id, sex); + ShowWarning("Attempt to create an already existing bot account (account: %s, sex: %c). Skipping...\n", acc.account_id, sex); return 1; // Account exists } @@ -185,7 +188,7 @@ int brokk_mmo_auth_new(const char* userid, const char* pass, const char sex, con if (!bot_accounts->create(bot_accounts, &bot_acc)) return 0; // Account creation failed - ShowNotice("Bot account creation successful (account %s, id: %d, sex: %c)\n", acc.userid, acc.account_id, acc.sex); + ShowStatus("Bot account creation successful (account %s, id: %d, sex: %c)\n", acc.userid, acc.account_id, acc.sex); // Registration rate limit logic if (DIFF_TICK(tick, new_reg_tick) > 0) { @@ -248,8 +251,10 @@ int brokk_mmo_auth_delete_num(uint32 account_id) { struct mmo_bot_account bot_acc; struct mmo_charakter charakter; struct bot_skill skill; + struct bot_inv_item item; std::vector char_ids_to_delete; std::vector skills_to_delete; + std::vector items_to_delete; // Check if the account exists if (!login_accounts->load_num(login_accounts, &acc, account_id)) { @@ -289,17 +294,15 @@ int brokk_mmo_auth_delete_num(uint32 account_id) { } } iter_chars->destroy(iter_chars); // Destroy the iterator after use - - ShowDebug("DelMarco\n"); + // Second pass: Delete the collected charakters - for (const auto& char_id : char_ids_to_delete) { - ShowDebug("DelPolo1\n"); + for (const auto& char_id : char_ids_to_delete) { ShowInfo("Deleting charakter with ID %d.\n", char_id); if (!charakters->remove(charakters, char_id)) { ShowError("Failed to delete charakter (char_id: %s)\n", char_id); continue; // Deletion failed } - ShowDebug("DelPolo2\n"); + // Step 3B: Attempt to delete skills of the char (if any) // First pass: Collect skill_ids to delete based on config SkillDBIterator* iter_skills = skills->iterator(skills, char_id); // Create the iterator @@ -309,19 +312,48 @@ int brokk_mmo_auth_delete_num(uint32 account_id) { skills_to_delete.push_back(skill); } iter_skills->destroy(iter_skills); // Destroy the iterator after use - ShowDebug("DelPolo3\n"); + // Second pass: Delete the collected skills - for (const auto& skill_entry : skills_to_delete) { + int skill_count = 0; + for (const auto& skill_entry : skills_to_delete) { //ShowInfo("Deleting skill with ID %d.\n", char_id); if (!skills->remove(skills, char_id, skill_entry.skill_id)) { ShowError("Failed to delete skill (skill_id: %s)\n", skill_entry.skill_id); continue; // Deletion failed } else { - ShowNotice("Deleting of skill %s from char_id %d was successful\n", convert_skill_id_to_str(skill_entry.skill_id), char_id); + //ShowNotice("Deleting of skill %s from char_id %d was successful\n", convert_skill_id_to_str(skill_entry.skill_id), char_id); + skill_count++; } } - ShowDebug("DelPolo4\n"); + + ShowNotice("Skill cleanup for char_id %d completed. %d skills cleaned.\n", char_id, skill_count); + + ShowDebug("Marco\n"); //TODO Prüfn warum hier iterator keine validen items wirft + // Step 3C: Attempt to delete inventory of the char (if any) + // First pass: Collect inv_item_ids to delete based on config + InventoryDBIterator* iter_inventory = inventory->iterator(inventory, char_id); // Create the iterator + ShowDebug("Polo1\n"); + while (iter_inventory->next(iter_inventory, char_id, &item)) { + ShowDebug("Polo iter loop\n"); + std::string id_str = convert_item_id_to_name(item.item_id); + ShowDebug("Item %s found. Schedule for deletion...\n", id_str.c_str()); + items_to_delete.push_back(item); + } + iter_inventory->destroy(iter_inventory); // Destroy the iterator after use + ShowDebug("Polo2\n"); + // Second pass: Delete the collected items + for (const auto& inv_item_entry : items_to_delete) { + ShowInfo("Deleting item with ID %d.\n", inv_item_entry.inventory_id); + if (!inventory->remove(inventory, char_id, inv_item_entry.inventory_id)) { + ShowError("Failed to delete item (item_id: %s)\n", inv_item_entry.item_id); + continue; // Deletion failed + } + else { + ShowNotice("Deleting of item %s from char_id %d was successful\n", convert_item_id_to_aegisname(inv_item_entry.item_id), char_id); + } + } + ShowDebug("Polo3\n"); } ShowNotice("Bot account deletion completed (account: %s, id: %d)\n\n", acc.userid, acc.account_id); @@ -563,6 +595,18 @@ bool brokk_initialize_dbs() } } + // Inventory database init (inventory table) + if (inventory == nullptr) { + ShowFatalError("do_init: inventory engine not found.\n"); + return false; + } + else { + if (!inventory->init(inventory)) { + ShowFatalError("do_init: Failed to initialize inventory engine.\n"); + return false; + } + } + return true; } @@ -636,7 +680,7 @@ bool brokk_create_character(mmo_charakter& charakter, int& char_id, const bool a } // Log success - ShowNotice("Character creation successful (name: %s, char_id: %d, sex: %c)\n", charakter.name, charakter.char_id, charakter.sex); + ShowStatus("Character creation successful (name: %s, char_id: %d, sex: %c)\n", charakter.name, charakter.char_id, charakter.sex); // Update registration limit if (DIFF_TICK(tick, new_reg_tick) > 0) { @@ -675,6 +719,13 @@ int brokk_teach_skills(bot_skill_bundle& skill_bundle, int& char_id) { std::string char_name = existing_char.name; + // TODO Define logic to handle session (on runtinme) added skills + // Those are added into the loaded skill tree on runtime by this function "void clif_addskill(map_session_data *sd, int skill_id)" + // A) There either needs to be a way to dynamicly change/create new skill trees depending on the demand from profiles (could be problematic because client code would be involved + // or + // B) There needs to be a way for brokk to communicate to sindri later, to tell sindri to add skills dynamicly to the skill tree of the logged in char + // Bottom line: Post-Pone decition for first polish iteration + for (auto& skill : skill_bundle.skills) { // Create entry in the skill database @@ -684,7 +735,7 @@ int brokk_teach_skills(bot_skill_bundle& skill_bundle, int& char_id) { } // Log success single skill - ShowNotice("Skill %s added to character char_id: %d)\n", convert_skill_id_to_str(skill.skill_id), skill.char_id); + //ShowNotice("Skill %s added to character char_id: %d)\n", convert_skill_id_to_str(skill.skill_id), skill.char_id); skill_count++; } @@ -694,11 +745,50 @@ int brokk_teach_skills(bot_skill_bundle& skill_bundle, int& char_id) { return -1; // Success } +/** + * Add an item to a charakters bundle in the database. + * @param item: Pre-configured bot_item object with all necessary fields populated. + * @return : + * -1: success + * 1: unregistered id (invalid char_id) + * 2: Error while writing into inventory table + */ +int brokk_apply_item_loadout(bot_item_bundle& item_bundle, int& char_id) { + int item_count = 0; + + // Check if the character exists + mmo_charakter existing_char; + if (!charakters->load_num(charakters, &existing_char, char_id)) { + ShowError("Attempt to add an item to non-existing character (char_id: %d)\n", char_id); + return 1; // Character does not exist + } + std::string char_name = existing_char.name; + + for (auto& item : item_bundle.items) { + // Create entry in the inventory database + if (!inventory->create(inventory, &item)) { + ShowError("Failed to create inventory entry (char_id: %d, item_id: %d)\n", item.char_id, item.item_id); + return 2; // inventory entry creation failed + } + // Log success single item + std::string aegisname = convert_item_id_to_aegisname(item.item_id); + ShowNotice("Item %s added to character char_id: %d)\n", aegisname.c_str(), item.char_id); + item_count++; + } + + // Log success + ShowStatus("Successfully added %d Items to characters inventory (name: %s, char_id: %d)\n", item_count, char_name.c_str(), char_id); + + return -1; // Success +} + + void BrokkServer::finalize() { AccountDB* db = login_accounts; BotAccountDB* bot_db = bot_accounts; CharDB* char_db = charakters; SkillDB* skill_db = skills; + InventoryDB* inventory_db = inventory; //brokk_log(0, "brokk server", 100, "brokk server shutdown"); ShowStatus("Terminating...\n"); @@ -728,10 +818,16 @@ void BrokkServer::finalize() { skill_db = nullptr; } + if (inventory_db) { // destroy inventory engine + inventory_db->destroy(inventory_db); + inventory_db = nullptr; + } + login_accounts = nullptr; // destroyed in account_engine bot_accounts = nullptr; // destroyed in bot account_engine charakters = nullptr;// destroyed in charakter engine skills = nullptr; //destroy in skills engine + inventory = nullptr; //destroy in inventory engine if (brokk_fd != -1) { @@ -761,6 +857,7 @@ bool BrokkServer::initialize(int argc, char* argv[]) { bot_accounts = bot_account_db_sql(); charakters = char_db_sql(); skills = skill_db_sql(); + inventory = inventory_db_sql(); // Initialize Yaml-DBs bot_read_yaml_dbs(); @@ -790,7 +887,6 @@ bool BrokkServer::initialize(int argc, char* argv[]) { /* //Demo-Skill tree - //TODO Eintragen in Job-Profil -> welche Skills gelernt werden sollen und Mechanik bauen für plausibles auto-skill erlernen std::shared_ptr tree = bot_skill_tree_db.find(JOB_MAGE); for (const auto& skill : tree->skills){ ShowDebug("Skill Found in tree: %s \n",convert_skill_id_to_str(skill.first)); @@ -833,7 +929,7 @@ bool BrokkServer::initialize(int argc, char* argv[]) { // Close file after done with it bot_accounts_file.close(); - ShowStatus("Starting to create bot accounts...\n"); + ShowInfo("Starting to create bot accounts...\n"); // Iterate over each bot entry in the JSON file for (const auto& bot : json_bot_accounts) { @@ -843,7 +939,7 @@ bool BrokkServer::initialize(int argc, char* argv[]) { const char sex = bot["sex"].get()[0]; // Extract single char from string // Debug: Print the entire bot entry - //ShowInfo("Processing bot: %s\n", bot.dump(4).c_str()); + ShowInfo("Processing bot account: %s ...\n", userid_str.c_str()); // Debug: Iterate over the keys in the bot object and print them //for (auto it = bot.begin(); it != bot.end(); ++it) { @@ -873,13 +969,13 @@ bool BrokkServer::initialize(int argc, char* argv[]) { const auto& json_characters = bot["characters"]; //ShowDebug("StartChar Parsing"); for (const auto& json_character : json_characters) { //Iterate every declared character and try to create it - //ShowDebug("char_json:\n%s", character.dump().c_str()); mmo_charakter new_char{}; //Step1 Meta-Data about character (allways have to be present/not bound to profile) const std::string char_name = json_character["name"]; safestrncpy(new_char.name, char_name.c_str(), NAME_LENGTH); + ShowInfo("Processing bot character %s ...\n", char_name.c_str()); std::string sex_str = json_character["sex"]; new_char.sex = sex_str[0]; @@ -888,21 +984,25 @@ bool BrokkServer::initialize(int argc, char* argv[]) { new_char.inventory_slots = 100; // Decode Job Value - std::string job_id = json_character["start_job"]; - new_char.class_ = convert_jobid_to_number(job_id.c_str()); + std::string job_id_str = json_character["start_job"]; + int job_id = convert_jobid_to_number(job_id_str.c_str()); + new_char.class_ = job_id; if (new_char.class_ == -1) { - job_id = "JOB_NOVICE"; + job_id_str = "JOB_NOVICE"; new_char.class_ = JOB_NOVICE; } // Step2: build data of character new_char.account_id = account_id; new_char.char_id = -1; + ShowInfo("Preparing build data for bot character %s ...\n", char_name.c_str()); prepare_character_build_data(new_char, json_character, bot_job_db); // Step3: appearance of character + ShowInfo("Preparing appearance of bot character %s ...\n", char_name.c_str()); prepare_character_appearance_data(new_char, json_character); // Step4: location data of character + ShowInfo("Preparing location data for bot character %s ...\n", char_name.c_str()); prepare_character_location_data(new_char, json_character); // All char table related data is collected and can be saved to allow further steps (skills/items/equip) @@ -924,14 +1024,14 @@ bool BrokkServer::initialize(int argc, char* argv[]) { ShowError("Character creation for '%s 'failed: %s\n",new_char.name, e.what()); continue; } - - //TODO Ab hier debuggen warum bei EvaExample bei neuanlage crashed - + // Step5: Skills // Prepare skills inside a skill bundle + ShowInfo("Preparing skill data of bot character %s ...\n", char_name.c_str()); bot_skill_bundle skill_bundle{}; prepare_skill_bundle(skill_bundle, new_char_id, json_character); + validate_skill_bundle(skill_bundle, job_id_str.c_str()); // All skill table related data is collected and can be saved try { @@ -945,18 +1045,34 @@ bool BrokkServer::initialize(int argc, char* argv[]) { continue; } - ShowNotice("Skills successfully teached to character (name: %s, char_id: %d, sex: %c)\n", new_char.name, new_char.char_id, new_char.sex); - - //Step4: Items - //TODO Testweise folgende ItemIDs einbauen für Debug: -// 1950, 2627 , 4040 - //ShowNotice("Items successfully handed out to character (name: %s, char_id: %d, sex: %c)\n", new_char.name, new_char.char_id, new_char.sex); + // ShowNotice("Skills successfully teached to character (name: %s, char_id: %d, sex: %c)\n", new_char.name, new_char.char_id, new_char.sex); - //Step5: Equipment + // Step6: Items + // Prepare items inside a item bundle + ShowInfo("Preparing inventory data for bot character %s ...\n", char_name.c_str()); - //ShowNotice("Gear/Weapons successfully equiped (name: %s, char_id: %d, sex: %c)\n", new_char.name, new_char.char_id, new_char.sex); + bot_item_bundle item_bundle{}; + + prepare_item_bundle(item_bundle, new_char_id, json_character); + + // All inventory table related data is collected and can be saved + try { + /* Lock-out while in debug + if (!brokk_apply_item_loadout(item_bundle, new_char_id)) { + ShowError("Failed to create inventory entry for: %s\n", new_char.name); + continue; + }*/ + } + catch (const std::exception& e) { + ShowError("skill creation for '%s 'failed: %s\n", new_char.name, e.what()); + continue; + } + ShowStatus("Items successfully handed out to character (name: %s, char_id: %d, sex: %c)\n", new_char.name, new_char.char_id, new_char.sex); - ShowStatus("Bot-Character creation and administration completed (name: %s, char_id: %d, sex: %c)\n", new_char.name, new_char.char_id, new_char.sex); + //Step5: Equipment + //ShowInfo("Preparing equipment for bot character %s ...\n", char_name.c_str()); + + ShowStatus("Bot-Character creation and administration completed (name: %s, char_id: %d, sex: %c)\n\n", new_char.name, new_char.char_id, new_char.sex); /***** * Validating/Applying skill build diff --git a/src/bot/Brokk/brokk.hpp b/src/bot/Brokk/brokk.hpp index 456f61f..643c8ef 100644 --- a/src/bot/Brokk/brokk.hpp +++ b/src/bot/Brokk/brokk.hpp @@ -14,6 +14,7 @@ #include "charakters.hpp" #include "char_creation_helpers.hpp" #include "helper_skills.hpp" +#include "helper_inventory.hpp" using rathena::server_core::Core; using rathena::server_core::e_core_type; @@ -70,7 +71,7 @@ void bot_account_cleanup(); bool brokk_initialize_dbs(); bool brokk_create_character(mmo_charakter& charakter, int& char_id, const bool auto_generated); int brokk_teach_skills(bot_skill_bundle& skill_bundle, int& char_id); -//int brokk_add_item(container_struct& container); +int brokk_apply_item_loadout(bot_item_bundle& item_bundle, int& char_id); //int brokk_apply_equip(container_struct& container); diff --git a/src/bot/Brokk/helper_skills.cpp b/src/bot/Brokk/helper_skills.cpp index ee74f97..d00af05 100644 --- a/src/bot/Brokk/helper_skills.cpp +++ b/src/bot/Brokk/helper_skills.cpp @@ -510,7 +510,7 @@ static bool bot_skill_db_tosql(SkillDB_SQL* db, const struct bot_skill* skill, c #endif db->skill_db, skill->char_id, skill->skill_id) || SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_INT, (void*)skill->level, sizeof(skill->level)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_INT, (void*)skill->flag, sizeof(skill->flag)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_SHORT, (void*)skill->flag, sizeof(skill->flag)) #ifdef VIP_ENABLE #endif || SQL_SUCCESS != SqlStmt_Execute(stmt) @@ -774,60 +774,7 @@ uint64 BotSkillTreeDatabase::parseBodyNode(const ryml::NodeRef& node) { return true; } -/* -* Checks if the required skills to a skill are met -*/ -bool check_skill_requirements(int job_id, int skill_id, bot_skill_bundle& skill_bundle) { - - if (is_skill_validation_exception(job_id, skill_id)) { - // Skill is exception for this job -> is not validated - std::string skill_name = convert_skill_id_to_str(skill_id); - ShowNotice("Skill %s is marked as exception to this job (%d)\n",skill_name.c_str(), job_id); - return true; - } - - std::shared_ptr tree = bot_skill_tree_db.find(job_id); - if (!tree) { - ShowError("Skill ID %d (%s) not found in bot_skill_tree_db\n", skill_id, convert_skill_id_to_str(skill_id)); - return false; - } - - // Check the size of skills before iterating - if (tree->skills.empty()) { - ShowError("Skill tree for ID %d is empty\n", skill_id); - return false; - } - - for (const auto& skill : tree->skills) { - //ShowDebug("Skill Found in tree: %s \n", convert_skill_id_to_str(skill.first)); - if (skill.first == skill_id) { - //ShowDebug("skill max lvl : %d \n", skill.second->max_lv); - bool requirements_met = true; - for (const auto needed_skill : skill.second->need) { - //ShowDebug("requires skill %s on level %d\n", convert_skill_id_to_str(needed_skill.first), needed_skill.second); - bool skill_found = false; - for (const auto bundled_skill : skill_bundle.skills) { - if (needed_skill.first == bundled_skill.skill_id && needed_skill.second <= bundled_skill.level) { - // Skill must be in bundle and at least smaller or same level as required - skill_found = true; - break; - } - } - if (!skill_found) { - requirements_met = false; - break; - } - } - if (requirements_met) { - ShowDebug("All skill requirements fullfilled"); - return true; //no missing skills, requirements are met - } - } - } - ShowDebug("One or more skill requirements not fullfilled"); - return false; //Skill_bundle misses at least a required skill -} void init_bot_skill_tree_db() { bot_skill_tree_db.reload(); @@ -924,20 +871,83 @@ std::unordered_map parse_skill_bundle(const nlohmann::json& skil return parsed_skill_bundle; } -bool validate_skills(uint16 start_job, bot_skill_bundle& skill_bundle) { +void dump_skill_bundle(const bot_skill_bundle& skill_bundle) { + ShowDebug("Dumping skill bundle contents...\n"); + if (skill_bundle.skills.empty()) { + ShowDebug("Skill bundle is empty.\n"); + return; + } + + for (const auto& skill : skill_bundle.skills) { + ShowDebug("Character ID: %u\n", skill.char_id); + ShowDebug(" Skill ID: %d\n", skill.skill_id); + std::string skill_name = convert_skill_id_to_str(skill.skill_id); + ShowDebug(" Skill Name: %s\n", skill_name.c_str()); + ShowDebug(" Skill Level: %u\n", skill.level); + ShowDebug(" Flag: %d\n", skill.flag); + } + ShowDebug("End of skill bundle dump.\n"); +} + +void validate_skill_bundle(bot_skill_bundle& skill_bundle, const char* job_id) { + ShowInfo("Validating skill bundle for job ID: %s...\n", job_id); + + // Retrieve the skill tree for the specified job ID + std::shared_ptr tree = bot_skill_tree_db.find(convert_jobid_to_number(job_id)); + + if (!tree) { + ShowWarning("Job ID %s not found in the skill tree database. Skipping validation.\n", job_id); + return; + } + + std::vector valid_skills; // Temporary vector to store valid skills + for (const auto& skill : skill_bundle.skills) { - int skill_id = skill.skill_id; - uint16 level = skill.level; - - // Check requirements - if (!check_skill_requirements(start_job, skill_id, skill_bundle)) { - std::string skill_name = convert_skill_id_to_str(skill_id); - ShowError("Skill %s(%d) at level %d does not meet requirements\n", skill_name.c_str(),skill_id, level); - return false; // Requirements not met + // Look up the skill in the job-specific skill tree + auto it = tree->skills.find(skill.skill_id); + if (it == tree->skills.end()) { + ShowWarning("Skill %s not found in the skill tree for job ID %s. Skipping.\n",convert_skill_id_to_str(skill.skill_id), job_id); + continue; + } + + std::shared_ptr skill_entry = it->second; + bool requirements_met = true; // Flag to track if requirements are met + + // Check required skills + for (const auto& required_skill : skill_entry->need) { + uint16 required_skill_id = required_skill.first; + uint16 required_skill_level = required_skill.second; + bool found = false; + + // Search for the required skill in the bundle + for (const auto& bundled_skill : skill_bundle.skills) { + if (bundled_skill.skill_id == required_skill_id && bundled_skill.level >= required_skill_level) { + found = true; + break; + } + } + + if (!found) { + //ShowDebug("Skill ID %s requires skill ID %d with minimum level %d, but it is not found in the bundle.\n", + // convert_skill_id_to_str(skill.skill_id), required_skill_id, required_skill_level); + requirements_met = false; + break; + } + } + + if (requirements_met) { + //ShowDebug("Skill ID %s validated successfully.\n", convert_skill_id_to_str(skill.skill_id)); + valid_skills.push_back(skill); // Add the valid skill to the temporary vector + } + else { + ShowWarning("Skill ID %s does not meet requirements and will be removed from the bundle.\n", convert_skill_id_to_str(skill.skill_id)); } } - return true; + // Update the skill bundle with valid skills + skill_bundle.skills = std::move(valid_skills); + + ShowStatus("Skill bundle validation completed for job ID: %s.\n", job_id); } void prepare_skill_bundle(bot_skill_bundle& bundle, uint32 char_id, const nlohmann::json& character) { @@ -968,7 +978,7 @@ void prepare_skill_bundle(bot_skill_bundle& bundle, uint32 char_id, const nlohma std::string job_str = character["start_job"]; uint16 related_job = convert_jobid_to_number(job_str.c_str()); - validate_skills(related_job, bundle); + //validate_skills(related_job, bundle); // Add the skill to the skill bundle bot_skill new_skill{}; @@ -978,7 +988,7 @@ void prepare_skill_bundle(bot_skill_bundle& bundle, uint32 char_id, const nlohma new_skill.flag = 0; // Default: 0 for permanent bundle.skills.push_back(new_skill); } - + //dump_skill_bundle(bundle); } else { // Load skill Profile @@ -990,7 +1000,7 @@ void prepare_skill_bundle(bot_skill_bundle& bundle, uint32 char_id, const nlohma // Try to Open skill Profile std::ifstream skill_profile_file(job_profile_file_path); if (!skill_profile_file.is_open()) { - ShowWarning("Failed to open skill_profile_file %s. Trying to load DEFAULT instead.", job_profile_file_path.c_str()); + ShowWarning("Failed to open skill_profile_file %s. Trying to load DEFAULT instead.\n", job_profile_file_path.c_str()); job_profile_file_path = "conf/bot_profiles/skill_profiles/DEFAULT_skills_profile.json"; skill_profile_file.open(job_profile_file_path); if (!skill_profile_file.is_open()) { @@ -1031,7 +1041,7 @@ void prepare_skill_bundle(bot_skill_bundle& bundle, uint32 char_id, const nlohma std::string job_str = character["start_job"]; uint16 related_job = convert_jobid_to_number(job_str.c_str()); - validate_skills(related_job, bundle); + //validate_skills(related_job, bundle); // Add the skill to the skill bundle bot_skill new_skill{}; @@ -1040,37 +1050,12 @@ void prepare_skill_bundle(bot_skill_bundle& bundle, uint32 char_id, const nlohma new_skill.level = static_cast(skill_level); new_skill.flag = 0; // Default: 0 for permanent bundle.skills.push_back(new_skill); - } - } - -} - -bool is_skill_validation_exception(int job_id, int skill_id) { - // Usually there should not be any exceptions for validation but in case you want to setup bots that have permanent soullink skills active or other temporaö skills, they should be added here - // A Exception is only needed if a skill should be added that is not present in the base skill tree but would use a slot in the jobs skill window like custom/item skills or soullink skills - - // Map job IDs to arrays of exception skill IDs - static const std::unordered_map> skill_map = { - {JOB_DANCER, {BA_WHISTLE, BA_ASSASSINCROSS, BA_POEMBRAGI, BA_APPLEIDUN}}, // Dancer exceptions - {JOB_KNIGHT, {KN_ONEHAND}}, // Knight exceptions - // Add more job-specific exceptions here - }; - - // Check if the job_id exists in the map - auto it = skill_map.find(job_id); - if (it != skill_map.end()) { - // Check if the skill_id exists in the exception list for the job_id - const auto& exception_skills = it->second; - if (std::find(exception_skills.begin(), exception_skills.end(), skill_id) != exception_skills.end()) { - return true; } + //dump_skill_bundle(bundle); } - - // If no match is found - return false; + } - /**********+ * Below this point there are only large converter functions. ************/ diff --git a/src/bot/Brokk/helper_skills.hpp b/src/bot/Brokk/helper_skills.hpp index 56b1bec..108a32d 100644 --- a/src/bot/Brokk/helper_skills.hpp +++ b/src/bot/Brokk/helper_skills.hpp @@ -124,8 +124,7 @@ struct SkillDB { int convert_skill_str_to_id(const char* skill_str); const char* convert_skill_id_to_str(int skill_id); -bool check_skill_requirements(int job_id, int skill_id, bot_skill_bundle& skill_bundle); -bool is_skill_validation_exception(int job_id, int skill_id); +void dump_skill_bundle(const bot_skill_bundle& skill_bundle); struct bot_skill_tree_entry { uint16 skill_id, max_lv; @@ -155,7 +154,7 @@ public: extern BotSkillTreeDatabase bot_skill_tree_db; void init_bot_skill_tree_db(); -bool validate_skills(uint16 start_job, const bot_skill_bundle& skill_bundle); +void validate_skill_bundle(bot_skill_bundle& skill_bundle, const char* job_id); void prepare_skill_bundle(bot_skill_bundle& bundle, uint32 char_id, const nlohmann::json& character); #endif /* HELPER_SKILLS_HPP */