From 99ee4e04d997dd0011645cddbed5f3d2b855f607 Mon Sep 17 00:00:00 2001 From: Uleat Date: Sun, 13 Oct 2019 22:24:06 -0400 Subject: [PATCH] Added bot command 'precombat' to manually set pre-combat mode rather than the 'assumption' process used before; Added rule Bot:AllowOwnerOptionAltCombat to allow admins control over its use --- common/ruletypes.h | 3 +- zone/bot.cpp | 4 +-- zone/bot_command.cpp | 65 +++++++++++++++++++++++++++++++++++--------- zone/bot_command.h | 1 + zone/botspellsai.cpp | 17 +++++++----- zone/client.cpp | 5 ++-- zone/client.h | 4 +++ zone/mob.cpp | 4 +++ 8 files changed, 78 insertions(+), 25 deletions(-) diff --git a/common/ruletypes.h b/common/ruletypes.h index b3c19ddbc..d33aaf71b 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -596,7 +596,8 @@ RULE_INT(Bots, CasterStopMeleeLevel, 13, "Level at which caster bots stop melee RULE_INT(Bots, AllowedClasses, 0xFFFFFFFF, "Bitmask of allowed bot classes") RULE_INT(Bots, AllowedRaces, 0xFFFFFFFF, "Bitmask of allowed bot races") RULE_INT(Bots, AllowedGenders, 0x3, "Bitmask of allowed bot genders") -RULE_BOOL(Bots, AllowOwnerAutoDefend, false, "When active, bots will defend their owner on enemy aggro") +RULE_BOOL(Bots, AllowOwnerOptionAltCombat, true, "When option is enabled, bots will use an auto-/shared-aggro combat model") +RULE_BOOL(Bots, AllowOwnerOptionAutoDefend, true, "When option is enabled, bots will defend their owner on enemy aggro") RULE_REAL(Bots, LeashDistance, 562500.0f, "Distance a bot is allowed to travel from leash owner before being pulled back (squared value)") RULE_CATEGORY_END() #endif diff --git a/zone/bot.cpp b/zone/bot.cpp index 428472fac..b9e329292 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -2465,7 +2465,7 @@ void Bot::AI_Process() //#pragma endregion - bool bo_alt_combat = bot_owner->GetBotOption(Client::booAltCombat); + bool bo_alt_combat = (RuleB(Bots, AllowOwnerOptionAltCombat) && bot_owner->GetBotOption(Client::booAltCombat)); //#pragma region ATTACK FLAG @@ -3402,7 +3402,7 @@ void Bot::AI_Process() // 'class Client' doesn't make use of hate_list... if (bot_owner->GetAggroCount() && bot_owner->GetBotOption(Client::booAutoDefend)) { - if (RuleB(Bots, AllowOwnerAutoDefend)) { + if (RuleB(Bots, AllowOwnerOptionAutoDefend)) { if (NOT_HOLDING && NOT_PASSIVE) { diff --git a/zone/bot_command.cpp b/zone/bot_command.cpp index 8ca5878ce..6a0ae2ff0 100644 --- a/zone/bot_command.cpp +++ b/zone/bot_command.cpp @@ -1411,6 +1411,7 @@ int bot_command_init(void) bot_command_add("petremove", "Orders a bot to remove its charmed pet", 0, bot_subcommand_pet_remove) || bot_command_add("petsettype", "Orders a Magician bot to use a specified pet type", 0, bot_subcommand_pet_set_type) || bot_command_add("picklock", "Orders a capable bot to pick the lock of the closest door", 0, bot_command_pick_lock) || + bot_command_add("precombat", "Sets flag used to determine pre-combat behavior", 0, bot_command_precombat) || bot_command_add("portal", "Orders a Wizard bot to open a magical doorway to a specified destination", 0, bot_subcommand_portal) || bot_command_add("pull", "Orders a designated bot to 'pull' an enemy", 0, bot_command_pull) || bot_command_add("release", "Releases a suspended bot's AI processing (with hate list wipe)", 0, bot_command_release) || @@ -3752,24 +3753,30 @@ void bot_command_owner_option(Client *c, const Seperator *sep) c->Message(m_action, "Bot 'spawn message' is now %s.", argument.c_str()); } else if (!owner_option.compare("altcombat")) { + + if (RuleB(Bots, AllowOwnerOptionAltCombat)) { - if (!argument.compare("enable")) { - c->SetBotOption(Client::booAltCombat, true); - } - else if (!argument.compare("disable")) { - c->SetBotOption(Client::booAltCombat, false); + if (!argument.compare("enable")) { + c->SetBotOption(Client::booAltCombat, true); + } + else if (!argument.compare("disable")) { + c->SetBotOption(Client::booAltCombat, false); + } + else { + c->SetBotOption(Client::booAltCombat, !c->GetBotOption(Client::booAltCombat)); + } + + database.botdb.SaveOwnerOption(c->CharacterID(), Client::booAltCombat, c->GetBotOption(Client::booAltCombat)); + + c->Message(m_action, "Bot 'alt combat' is now %s.", (c->GetBotOption(Client::booAltCombat) == true ? "enabled" : "disabled")); } else { - c->SetBotOption(Client::booAltCombat, !c->GetBotOption(Client::booAltCombat)); + c->Message(m_fail, "Bot owner option 'altcombat' is not allowed on this server."); } - - database.botdb.SaveOwnerOption(c->CharacterID(), Client::booAltCombat, c->GetBotOption(Client::booAltCombat)); - - c->Message(m_action, "Bot 'alt combat' is now %s.", (c->GetBotOption(Client::booAltCombat) == true ? "enabled" : "disabled")); } else if (!owner_option.compare("autodefend")) { - if (RuleB(Bots, AllowOwnerAutoDefend)) { + if (RuleB(Bots, AllowOwnerOptionAutoDefend)) { if (!argument.compare("enable")) { c->SetBotOption(Client::booAutoDefend, true); @@ -3809,8 +3816,8 @@ void bot_command_owner_option(Client *c, const Seperator *sep) (c->GetBotOption(Client::booStatsUpdate) ? "enabled" : "disabled"), (c->GetBotOption(Client::booSpawnMessageSay) ? "say" : (c->GetBotOption(Client::booSpawnMessageTell) ? "tell" : "silent")), (c->GetBotOption(Client::booSpawnMessageClassSpecific) ? "class" : "default"), - (c->GetBotOption(Client::booAltCombat) ? "enabled" : "disabled"), - (c->GetBotOption(Client::booAutoDefend) ? "enabled" : "disabled") + (RuleB(Bots, AllowOwnerOptionAltCombat) ? (c->GetBotOption(Client::booAltCombat) ? "enabled" : "disabled") : "restricted"), + (RuleB(Bots, AllowOwnerOptionAutoDefend) ? (c->GetBotOption(Client::booAutoDefend) ? "enabled" : "disabled") : "restricted") ); c->SendPopupToClient(window_title.c_str(), window_text.c_str()); @@ -3896,6 +3903,38 @@ void bot_command_pick_lock(Client *c, const Seperator *sep) c->Message(m_action, "%i door%s attempted - %i door%s successful", door_count, ((door_count != 1) ? ("s") : ("")), open_count, ((open_count != 1) ? ("s") : (""))); } +void bot_command_precombat(Client* c, const Seperator* sep) +{ + if (helper_command_alias_fail(c, "bot_command_precombat", sep->arg[0], "precombat")) { + return; + } + if (helper_is_help_or_usage(sep->arg[1])) { + + c->Message(m_usage, "usage: %s ([set | clear])", sep->arg[0]); + return; + } + + if (!c->GetTarget() || !c->IsAttackAllowed(c->GetTarget())) { + + c->Message(m_fail, "This command requires an attackable target."); + return; + } + + std::string argument(sep->arg[1]); + + if (!argument.compare("set")) { + c->SetBotPrecombat(true); + } + else if (!argument.compare("clear")) { + c->SetBotPrecombat(false); + } + else { + c->SetBotPrecombat(!c->GetBotPrecombat()); + } + + c->Message(m_action, "Precombat flag is now %s.", (c->GetBotPrecombat() == true ? "set" : "clear")); +} + // TODO: Rework to allow owner specificed criteria for puller void bot_command_pull(Client *c, const Seperator *sep) { diff --git a/zone/bot_command.h b/zone/bot_command.h index 0f0fab0ef..d710e106f 100644 --- a/zone/bot_command.h +++ b/zone/bot_command.h @@ -578,6 +578,7 @@ void bot_command_movement_speed(Client *c, const Seperator *sep); void bot_command_owner_option(Client *c, const Seperator *sep); void bot_command_pet(Client *c, const Seperator *sep); void bot_command_pick_lock(Client *c, const Seperator *sep); +void bot_command_precombat(Client* c, const Seperator* sep); void bot_command_pull(Client *c, const Seperator *sep); void bot_command_release(Client *c, const Seperator *sep); void bot_command_resistance(Client *c, const Seperator *sep); diff --git a/zone/botspellsai.cpp b/zone/botspellsai.cpp index 1839e91e4..9acc8ac8b 100644 --- a/zone/botspellsai.cpp +++ b/zone/botspellsai.cpp @@ -1167,15 +1167,18 @@ bool Bot::AI_IdleCastCheck() { AIautocastspell_timer->Disable(); //prevent the timer from going off AGAIN while we are casting. bool pre_combat = false; - Mob* test_against = nullptr; + Client* test_against = nullptr; - if (HasGroup() && GetGroup()->GetLeader() && GetGroup()->GetLeader()->IsClient()) - test_against = GetGroup()->GetLeader(); - else if (GetOwner() && GetOwner()->IsClient()) - test_against = GetOwner(); + if (HasGroup() && GetGroup()->GetLeader() && GetGroup()->GetLeader()->IsClient()) { + test_against = GetGroup()->GetLeader()->CastToClient(); + } + else if (GetOwner() && GetOwner()->IsClient()) { + test_against = GetOwner()->CastToClient(); + } - if (test_against && test_against->GetTarget() && test_against->GetTarget()->IsNPC() && !test_against->GetTarget()->IsPet()) - pre_combat = true; + if (test_against) { + pre_combat = test_against->GetBotPrecombat(); + } //Ok, IdleCastCheck depends of class. switch (GetClass()) { diff --git a/zone/client.cpp b/zone/client.cpp index 3c16b8a9b..2e128d66c 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -352,10 +352,11 @@ Client::Client(EQStreamInterface* ieqs) bot_owner_options[booSpawnMessageSay] = false; bot_owner_options[booSpawnMessageTell] = true; bot_owner_options[booSpawnMessageClassSpecific] = true; - bot_owner_options[booAltCombat] = false; - bot_owner_options[booAutoDefend] = RuleB(Bots, AllowOwnerAutoDefend); + bot_owner_options[booAltCombat] = RuleB(Bots, AllowOwnerOptionAltCombat); + bot_owner_options[booAutoDefend] = RuleB(Bots, AllowOwnerOptionAutoDefend); SetBotPulling(false); + SetBotPrecombat(false); #endif AI_Init(); diff --git a/zone/client.h b/zone/client.h index 3ade2e6fe..ffba61520 100644 --- a/zone/client.h +++ b/zone/client.h @@ -1646,9 +1646,13 @@ public: bool GetBotPulling() { return m_bot_pulling; } void SetBotPulling(bool flag = true) { m_bot_pulling = flag; } + bool GetBotPrecombat() { return m_bot_precombat; } + void SetBotPrecombat(bool flag = true) { m_bot_precombat = flag; } + private: bool bot_owner_options[_booCount]; bool m_bot_pulling; + bool m_bot_precombat; #endif }; diff --git a/zone/mob.cpp b/zone/mob.cpp index 68571b709..fa1103055 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -3203,6 +3203,10 @@ void Mob::SetTarget(Mob *mob) if (this->CastToClient()->admin > 200) { this->DisplayInfo(mob); } + +#ifdef BOTS + CastToClient()->SetBotPrecombat(false); // Any change in target will nullify this flag (target == mob checked above) +#endif } if (IsPet() && GetOwner() && GetOwner()->IsClient()) {