diff --git a/common/version.h b/common/version.h index a4e987567..2fd8ea0bf 100644 --- a/common/version.h +++ b/common/version.h @@ -37,7 +37,7 @@ #define CURRENT_BINARY_DATABASE_VERSION 9212 #ifdef BOTS - #define CURRENT_BINARY_BOTS_DATABASE_VERSION 9033 + #define CURRENT_BINARY_BOTS_DATABASE_VERSION 9034 #else #define CURRENT_BINARY_BOTS_DATABASE_VERSION 0 // must be 0 #endif diff --git a/utils/sql/git/bots/bots_db_update_manifest.txt b/utils/sql/git/bots/bots_db_update_manifest.txt index 7dd8f2a71..3554ccce2 100644 --- a/utils/sql/git/bots/bots_db_update_manifest.txt +++ b/utils/sql/git/bots/bots_db_update_manifest.txt @@ -32,6 +32,7 @@ 9031|2022_11_13_bot_spells_entries.sql|SELECT * FROM db_version WHERE bots_version >= 9031|empty| 9032|2022_11_07_bot_expansion_bitmask.sql|SHOW COLUMNS FROM `bot_data` LIKE 'expansion_bitmask'|empty| 9033|2022_11_19_bot_spell_settings.sql|SHOW TABLES LIKE 'bot_spell_settings'|empty| +9034|2022_12_02_bot_spell_settings.sql|SHOW COLUMNS FROM `bot_data` LIKE 'enforce_spell_settings'|empty| # Upgrade conditions: # This won't be needed after this system is implemented, but it is used database that are not diff --git a/zone/bot.cpp b/zone/bot.cpp index 07de18015..7612f3156 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -10696,7 +10696,7 @@ void Bot::ListBotSpells(uint8 min_level) return; } - if (AIBot_spells.empty()) { + if (AIBot_spells.empty() && AIBot_spells_enforced.empty()) { bot_owner->Message( Chat::White, fmt::format( @@ -10710,7 +10710,7 @@ void Bot::ListBotSpells(uint8 min_level) auto spell_count = 0; auto spell_number = 1; - for (const auto& s : AIBot_spells) { + for (const auto& s : (AIBot_spells.size() > AIBot_spells_enforced.size()) ? AIBot_spells : AIBot_spells_enforced) { auto b = bot_spell_settings.find(s.spellid); if (b == bot_spell_settings.end() && s.minlevel >= min_level) { bot_owner->Message( diff --git a/zone/bot.h b/zone/bot.h index 98cdd072d..be44e5c87 100644 --- a/zone/bot.h +++ b/zone/bot.h @@ -323,6 +323,23 @@ public: std::string bucket_value, uint8 bucket_comparison ); + + void AddSpellToBotEnforceList( + int16 iPriority, + uint16 iSpellID, + uint32 iType, + int16 iManaCost, + int32 iRecastDelay, + int16 iResistAdjust, + uint8 min_level, + uint8 max_level, + int8 min_hp, + int8 max_hp, + std::string bucket_name, + std::string bucket_value, + uint8 bucket_comparison + ); + void AI_Bot_Event_SpellCastFinished(bool iCastSucceeded, uint16 slot); // AI Methods virtual bool AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes); @@ -726,6 +743,9 @@ protected: //void SetRaidDoter(bool flag = true) { m_CastingRoles.RaidDoter = flag; } std::deque bot_signal_q; + std::vector AIBot_spells; + std::vector AIBot_spells_enforced; + private: // Class Members uint32 _botID; diff --git a/zone/bot_command.cpp b/zone/bot_command.cpp index 6dfc0e22c..6e32e46bb 100644 --- a/zone/bot_command.cpp +++ b/zone/bot_command.cpp @@ -1363,7 +1363,7 @@ int bot_command_init(void) bot_command_add("cure", "Orders a bot to remove any ailments", AccountStatus::Player, bot_command_cure) || bot_command_add("defensive", "Orders a bot to use a defensive discipline", AccountStatus::Player, bot_command_defensive) || bot_command_add("depart", "Orders a bot to open a magical doorway to a specified destination", AccountStatus::Player, bot_command_depart) || - bot_command_add("enforcespelllist", "Toggles your Bot to cast only spells in their spell settings list.", AccountStatus::Player, bot_command_enforce_spell_list) || + bot_command_add("enforcespellsettings", "Toggles your Bot to cast only spells in their spell settings list.", AccountStatus::Player, bot_command_enforce_spell_list) || bot_command_add("escape", "Orders a bot to send a target group to a safe location within the zone", AccountStatus::Player, bot_command_escape) || bot_command_add("findaliases", "Find available aliases for a bot command", AccountStatus::Player, bot_command_find_aliases) || bot_command_add("follow", "Orders bots to follow a designated target (option 'chain' auto-links eligible spawned bots)", AccountStatus::Player, bot_command_follow) || @@ -1419,11 +1419,11 @@ int bot_command_init(void) bot_command_add("sendhome", "Orders a bot to open a magical doorway home", AccountStatus::Player, bot_command_send_home) || bot_command_add("size", "Orders a bot to change a player's size", AccountStatus::Player, bot_command_size) || bot_command_add("spellinfo", "Opens a dialogue window with spell info", AccountStatus::Player, bot_spell_info_dialogue_window) || - bot_command_add("spelllist", "Lists all Spells learned by the Bot.", AccountStatus::Player, bot_command_spell_list) || + bot_command_add("spells", "Lists all Spells learned by the Bot.", AccountStatus::Player, bot_command_spell_list) || + bot_command_add("spellsettings", "Lists a bot's spell setting entries", AccountStatus::Player, bot_command_spell_settings_list) || bot_command_add("spellsettingsadd", "Add a bot spell setting entry", AccountStatus::Player, bot_command_spell_settings_add) || bot_command_add("spellsettingsdelete", "Delete a bot spell setting entry", AccountStatus::Player, bot_command_spell_settings_delete) || - bot_command_add("spellsettingslist", "Lists a bot's spell setting entries", AccountStatus::Player, bot_command_spell_settings_list) || - bot_command_add("spellsettingstoggle", "Toggle a bot spells use", AccountStatus::Player, bot_command_spell_settings_toggle) || + bot_command_add("spellsettingstoggle", "Toggle a bot spell use", AccountStatus::Player, bot_command_spell_settings_toggle) || bot_command_add("spellsettingsupdate", "Update a bot spell setting entry", AccountStatus::Player, bot_command_spell_settings_update) || bot_command_add("summoncorpse", "Orders a bot to summon a corpse to its feet", AccountStatus::Player, bot_command_summon_corpse) || bot_command_add("suspend", "Suspends a bot's AI processing until released", AccountStatus::Player, bot_command_suspend) || @@ -10251,7 +10251,7 @@ bool helper_spell_list_fail(Client *bot_owner, bcst_list* spell_list, BCEnum::Sp void bot_command_spell_list(Client* c, const Seperator *sep) { - if (helper_command_alias_fail(c, "bot_command_spell_list", sep->arg[0], "spelllist")) { + if (helper_command_alias_fail(c, "bot_command_spell_list", sep->arg[0], "spells")) { return; } @@ -10483,7 +10483,7 @@ void bot_command_spell_settings_delete(Client *c, const Seperator *sep) void bot_command_spell_settings_list(Client *c, const Seperator *sep) { - if (helper_command_alias_fail(c, "bot_command_spell_settings_list", sep->arg[0], "spellsettingslist")) { + if (helper_command_alias_fail(c, "bot_command_spell_settings_list", sep->arg[0], "spellsettings")) { return; } @@ -10784,7 +10784,7 @@ void bot_spell_info_dialogue_window(Client* c, const Seperator *sep) void bot_command_enforce_spell_list(Client* c, const Seperator *sep) { - if (helper_command_alias_fail(c, "bot_command_enforce_spell_list", sep->arg[0], "enforcespelllist")) { + if (helper_command_alias_fail(c, "bot_command_enforce_spell_list", sep->arg[0], "enforcespellsettings")) { return; } diff --git a/zone/bot_structs.h b/zone/bot_structs.h index 936e66abf..15c135a17 100644 --- a/zone/bot_structs.h +++ b/zone/bot_structs.h @@ -88,6 +88,23 @@ struct BotSpellSetting { bool is_enabled; }; +struct BotSpells_Struct { + uint32 type; // 0 = never, must be one (and only one) of the defined values + int16 spellid; // <= 0 = no spell + int16 manacost; // -1 = use spdat, -2 = no cast time + uint32 time_cancast; // when we can cast this spell next + int32 recast_delay; + int16 priority; + int16 resist_adjust; + uint8 minlevel; + uint8 maxlevel; + int16 min_hp; // >0 won't cast if HP is below + int16 max_hp; // >0 won't cast if HP is above + std::string bucket_name; + std::string bucket_value; + uint8 bucket_comparison; +}; + #endif // BOTS #endif // BOT_STRUCTS diff --git a/zone/botspellsai.cpp b/zone/botspellsai.cpp index e56bded24..ec8c87ff1 100644 --- a/zone/botspellsai.cpp +++ b/zone/botspellsai.cpp @@ -2884,6 +2884,7 @@ bool Bot::AI_AddBotSpells(uint32 bot_spell_id) { // ok, this function should load the list, and the parent list then shove them into the struct and sort npc_spells_id = bot_spell_id; AIBot_spells.clear(); + AIBot_spells_enforced.clear(); if (!bot_spell_id) { AIautocastspell_timer->Disable(); return false; @@ -3037,6 +3038,22 @@ bool Bot::AI_AddBotSpells(uint32 bot_spell_id) { e.bucket_value, e.bucket_comparison ); + } else { + AddSpellToBotEnforceList( + e.priority, + e.spellid, + e.type, + e.manacost, + e.recast_delay, + e.resist_adjust, + e.minlevel, + e.maxlevel, + e.min_hp, + e.max_hp, + e.bucket_name, + e.bucket_value, + e.bucket_comparison + ); } } } @@ -3134,6 +3151,22 @@ bool Bot::AI_AddBotSpells(uint32 bot_spell_id) { e.bucket_value, e.bucket_comparison ); + } else { + AddSpellToBotEnforceList( + e.priority, + e.spellid, + e.type, + e.manacost, + e.recast_delay, + e.resist_adjust, + e.minlevel, + e.maxlevel, + e.min_hp, + e.max_hp, + e.bucket_name, + e.bucket_value, + e.bucket_comparison + ); } } } @@ -3329,6 +3362,47 @@ void Bot::AddSpellToBotList( } } +// adds spells to the list ^spells that are returned if ^enforce is enabled +void Bot::AddSpellToBotEnforceList( + int16 iPriority, + uint16 iSpellID, + uint32 iType, + int16 iManaCost, + int32 iRecastDelay, + int16 iResistAdjust, + uint8 min_level, + uint8 max_level, + int8 min_hp, + int8 max_hp, + std::string bucket_name, + std::string bucket_value, + uint8 bucket_comparison +) { + if (!IsValidSpell(iSpellID)) { + return; + } + + HasAISpell = true; + BotSpells_Struct t; + + t.priority = iPriority; + t.spellid = iSpellID; + t.type = iType; + t.manacost = iManaCost; + t.recast_delay = iRecastDelay; + t.time_cancast = 0; + t.resist_adjust = iResistAdjust; + t.minlevel = min_level; + t.maxlevel = maxlevel; + t.min_hp = min_hp; + t.max_hp = max_hp; + t.bucket_name = bucket_name; + t.bucket_value = bucket_value; + t.bucket_comparison = bucket_comparison; + + AIBot_spells_enforced.push_back(t); +} + //this gets called from InterruptSpell() for failure or SpellFinished() for success void Bot::AI_Bot_Event_SpellCastFinished(bool iCastSucceeded, uint16 slot) { if (slot == 1) { diff --git a/zone/npc.h b/zone/npc.h index 209703f3f..43eaec2f4 100644 --- a/zone/npc.h +++ b/zone/npc.h @@ -59,23 +59,6 @@ struct AISpells_Struct { int8 max_hp; // >0 won't cast if HP is above }; -struct BotSpells_Struct { - uint32 type; // 0 = never, must be one (and only one) of the defined values - int16 spellid; // <= 0 = no spell - int16 manacost; // -1 = use spdat, -2 = no cast time - uint32 time_cancast; // when we can cast this spell next - int32 recast_delay; - int16 priority; - int16 resist_adjust; - uint8 minlevel; - uint8 maxlevel; - int16 min_hp; // >0 won't cast if HP is below - int16 max_hp; // >0 won't cast if HP is above - std::string bucket_name; - std::string bucket_value; - uint8 bucket_comparison; -}; - struct AISpellsEffects_Struct { uint16 spelleffectid; int32 base_value; @@ -596,7 +579,6 @@ protected: uint32* pDontCastBefore_casting_spell; std::vector AIspells; - std::vector AIBot_spells; //Will eventually be moved to Bot Class once Bots are no longer reliant on NPC constructor bool HasAISpell; virtual bool AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes, bool bInnates = false); virtual bool AIDoSpellCast(uint8 i, Mob* tar, int32 mana_cost, uint32* oDontDoAgainBefore = 0);