From 9207be96d334e2d467c6fcf0d8912f8ec81116ed Mon Sep 17 00:00:00 2001 From: nytmyr <53322305+nytmyr@users.noreply.github.com> Date: Thu, 5 Dec 2024 07:21:34 -0600 Subject: [PATCH] Rewrite ^pull logic and handling. **MORE** Add ^setassistee command to set who your bots will assist. Bots will always assist you first before anyone else. If the rule Bots, AllowCrossGroupRaidAssist is enabled bots will assist the group or raid main assists. Rewrites logic in handling of pull and returning to ensure bots make it back to their location. --- common/ruletypes.h | 1 + zone/bot.cpp | 158 ++++++++++++++++++++++++----- zone/bot_command.cpp | 2 + zone/bot_command.h | 1 + zone/bot_commands/set_assistee.cpp | 59 +++++++++++ zone/client.h | 3 + 6 files changed, 199 insertions(+), 25 deletions(-) create mode 100644 zone/bot_commands/set_assistee.cpp diff --git a/common/ruletypes.h b/common/ruletypes.h index 0d66fd1cf..08cac9b0e 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -886,6 +886,7 @@ RULE_BOOL(Bots, AllowCommandedResurrect, true, "If enabled bots can be commanded RULE_BOOL(Bots, AllowCommandedSummonCorpse, true, "If enabled bots can be commanded to summon other's corpses.") RULE_INT(Bots, CampTimer, 25, "Number of seconds after /camp has begun before bots camp out.") RULE_BOOL(Bots, SendClassRaceOnHelp, true, "If enabled a reminder of how to check class/race IDs will be sent when using compatible commands.") +RULE_BOOL(Bots, AllowCrossGroupRaidAssist, true, "If enabled bots will autodefend group or raid members set as main assist.") RULE_CATEGORY_END() RULE_CATEGORY(Chat) diff --git a/zone/bot.cpp b/zone/bot.cpp index ceeefb898..8fdf57d50 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -2041,6 +2041,7 @@ void Bot::AI_Process() auto raid = entity_list.GetRaidByBotName(GetName()); uint32 r_group = RAID_GROUPLESS; + if (raid) { raid->VerifyRaid(); r_group = raid->GetGroup(GetName()); @@ -2137,7 +2138,6 @@ void Bot::AI_Process() // RETURNING FLAG if (GetReturningFlag()) { - LogTestDebugDetail("#{}: {} has ReturningFlag", __LINE__, GetCleanName()); //deleteme ReturningFlagChecks(bot_owner, leash_owner, fm_distance); return; @@ -2210,6 +2210,7 @@ void Bot::AI_Process() if (!DoLosChecks(this, tar)) { return; } + if (atCombatRange) { if (RuleB(Bots, AllowRangedPulling) && IsBotRanged() && ranged_timer.Check(false)) { StopMoving(CalculateHeadingToTarget(tar->GetX(), tar->GetY())); @@ -2246,8 +2247,8 @@ void Bot::AI_Process() } TryPursueTarget(leash_distance, Goal); + return; - //TODO bot rewrite - need pulling checks below to prevent assist } // ENGAGED AT COMBAT RANGE @@ -2459,42 +2460,150 @@ bool Bot::TryAutoDefend(Client* bot_owner, float leash_distance) { if ( m_auto_defend_timer.Check() && - bot_owner->GetAggroCount() && NOT_HOLDING && NOT_PASSIVE ) { - auto xhaters = bot_owner->GetXTargetAutoMgr(); + XTargetAutoHaters* tempHaters; + std::vector assisteeHaters; + std::vector assisteeMembers; + bool found = false; - if (xhaters && !xhaters->empty()) { - for (auto hater_iter : xhaters->get_list()) { - if (!hater_iter.spawn_id) { - continue; - } + if (bot_owner->GetAggroCount()) { + tempHaters = bot_owner->GetXTargetAutoMgr(); - if (bot_owner->GetBotPulling() && bot_owner->GetTarget() && hater_iter.spawn_id == bot_owner->GetTarget()->GetID()) { - continue; - } + if (tempHaters && !tempHaters->empty()) { + assisteeHaters.emplace_back(tempHaters); + assisteeMembers.emplace_back(bot_owner); + } + } - auto hater = entity_list.GetMob(hater_iter.spawn_id); - if (hater && hater->CastToNPC()->IsOnHatelist(bot_owner) && !hater->IsMezzed() && DistanceSquared(hater->GetPosition(), bot_owner->GetPosition()) <= leash_distance) { - // This is roughly equivilent to npc attacking a client pet owner - AddToHateList(hater, 1); - SetTarget(hater); - SetAttackingFlag(); + if ( + (!bot_owner->GetAssistee() || !entity_list.GetClientByCharID(bot_owner->GetAssistee())) && + RuleB(Bots, AllowCrossGroupRaidAssist) + ) { + XTargetAutoHaters* temp_xhaters = bot_owner->GetXTargetAutoMgr(); + bool assisteeFound = false; - if (HasPet() && (GetClass() != Class::Enchanter || GetPet()->GetPetType() != petAnimation || GetAA(aaAnimationEmpathy) >= 2)) { - GetPet()->AddToHateList(hater, 1); - GetPet()->SetTarget(hater); + if (IsRaidGrouped()) { + Raid* r = entity_list.GetRaidByBotName(GetName()); + if (r) { + for (const auto& m : r->members) { + if ( + m.member && + m.member->IsClient() && + m.member->GetAggroCount() && + r->IsAssister(m.member_name) + ) { + temp_xhaters = m.member->GetXTargetAutoMgr(); + + if (!temp_xhaters || temp_xhaters->empty()) { + continue; + } + + assisteeHaters.emplace_back(temp_xhaters); + assisteeMembers.emplace_back(m.member); + } } + } + } + else if (HasGroup()) { + Group* g = GetGroup(); + if (g) { + for (auto& m : g->members) { + if ( + m && + m->IsClient() && + m->CastToClient()->GetAggroCount() && + g->AmIMainAssist(m->GetName()) + ) { + temp_xhaters = m->CastToClient()->GetXTargetAutoMgr(); - m_auto_defend_timer.Disable(); + if (!temp_xhaters || temp_xhaters->empty()) { + continue; + } - return true; + assisteeHaters.emplace_back(temp_xhaters); + assisteeMembers.emplace_back(m->CastToClient()); + } + } + } + } + else { + return false; + } + } + else { + if (bot_owner->GetAssistee()) { + Client* c = entity_list.GetClientByCharID(bot_owner->GetAssistee()); + + if (bot_owner->IsInGroupOrRaid(c) && c->GetAggroCount()) { + tempHaters = bot_owner->GetXTargetAutoMgr(); + + if (tempHaters && !tempHaters->empty()) { + assisteeHaters.emplace_back(tempHaters); + assisteeMembers.emplace_back(c); + } } } } + + if (!assisteeHaters.empty()) { + for (XTargetAutoHaters* xHaters : assisteeHaters) { + if (!xHaters->empty()) { + for (auto hater_iter : xHaters->get_list()) { + if (!hater_iter.spawn_id) { + continue; + } + + Mob* hater = nullptr; + + for (Client* xMember : assisteeMembers) { + if ( + xMember && + xMember->GetBotPulling() && + xMember->GetTarget() && + (hater_iter.spawn_id == xMember->GetTarget()->GetID()) + ) { + continue; + } + + hater = entity_list.GetMob(hater_iter.spawn_id); + + if ( + hater && + !hater->IsMezzed() && + (DistanceSquared(hater->GetPosition(), bot_owner->GetPosition()) <= leash_distance) && + hater->CastToNPC()->IsOnHatelist(xMember) + ) { + break; + } + + hater = nullptr; + } + + if (hater) { + AddToHateList(hater, 1); + SetTarget(hater); + SetAttackingFlag(); + + if (HasPet() && (GetClass() != Class::Enchanter || GetPet()->GetPetType() != petAnimation || GetAA(aaAnimationEmpathy) >= 2)) { + GetPet()->AddToHateList(hater, 1); + GetPet()->SetTarget(hater); + } + + m_auto_defend_timer.Disable(); + + return true; + } + } + } + } + } + + return false; } } + return false; } @@ -3054,6 +3163,7 @@ bool Bot::ReturningFlagChecks(Client* bot_owner, Mob* leash_owner, float fm_dist Goal = follow_mob->GetPosition(); } + RunTo(Goal.x, Goal.y, Goal.z); } @@ -11272,8 +11382,6 @@ void Bot::DoCombatPositioning( bool behindMob, bool frontMob ) { - //LogTestDebug("{} says, 'DoCombatPositioning. {} #{}", GetCleanName(), __FILE__, __LINE__); //deleteme - if (HasTargetReflection()) { if (!IsTaunting() && !tar->IsFeared() && !tar->IsStunned()) { if (TryEvade(tar)) { diff --git a/zone/bot_command.cpp b/zone/bot_command.cpp index 1b00d701a..a2a25a71f 100644 --- a/zone/bot_command.cpp +++ b/zone/bot_command.cpp @@ -1336,6 +1336,7 @@ int bot_command_init(void) bot_command_add("precombat", "Sets flag used to determine pre-combat behavior", AccountStatus::Player, bot_command_precombat) || bot_command_add("pull", "Orders a designated bot to 'pull' an enemy", AccountStatus::Player, bot_command_pull) || bot_command_add("release", "Releases a suspended bot's AI processing (with hate list wipe)", AccountStatus::Player, bot_command_release) || + bot_command_add("setassistee", "Sets your target to be the person your bots assist. Bots will always assist you before others", AccountStatus::Player, bot_command_set_assistee) || bot_command_add("sithppercent", "HP threshold for a bot to start sitting in combat if allowed", AccountStatus::Player, bot_command_sit_hp_percent) || bot_command_add("sitincombat", "Toggles whether or a not a bot will attempt to med or sit to heal in combat", AccountStatus::Player, bot_command_sit_in_combat) || bot_command_add("sitmanapercent", "Mana threshold for a bot to start sitting in combat if allowed", AccountStatus::Player, bot_command_sit_mana_percent) || @@ -2243,6 +2244,7 @@ void SendSpellTypeWindow(Client* c, const Seperator* sep) { #include "bot_commands/precombat.cpp" #include "bot_commands/pull.cpp" #include "bot_commands/release.cpp" +#include "bot_commands/set_assistee.cpp" #include "bot_commands/sit_hp_percent.cpp" #include "bot_commands/sit_in_combat.cpp" #include "bot_commands/sit_mana_percent.cpp" diff --git a/zone/bot_command.h b/zone/bot_command.h index ecce9485d..d6644bbf6 100644 --- a/zone/bot_command.h +++ b/zone/bot_command.h @@ -1747,6 +1747,7 @@ void bot_command_heritage(Client *c, const Seperator *sep); void bot_command_inspect_message(Client *c, const Seperator *sep); void bot_command_list_bots(Client *c, const Seperator *sep); void bot_command_report(Client *c, const Seperator *sep); +void bot_command_set_assistee(Client* c, const Seperator* sep); void bot_command_spawn(Client *c, const Seperator *sep); void bot_command_stance(Client *c, const Seperator *sep); void bot_command_stop_melee_level(Client *c, const Seperator *sep); diff --git a/zone/bot_commands/set_assistee.cpp b/zone/bot_commands/set_assistee.cpp new file mode 100644 index 000000000..d2be953e2 --- /dev/null +++ b/zone/bot_commands/set_assistee.cpp @@ -0,0 +1,59 @@ +#include "../bot_command.h" + +void bot_command_set_assistee(Client* c, const Seperator* sep) +{ + if (helper_is_help_or_usage(sep->arg[1])) { + std::vector description = + { + "Sets your bots to assist your target in addition to yourself" + }; + + std::vector notes = + { + "- Your target must be another player in your group or raid.", + "- This needs to be set on every zone/camp you do." + }; + + std::vector example_format = { }; + std::vector examples_one = { }; + std::vector examples_two = { }; + std::vector examples_three = { }; + + std::vector actionables = { }; + + std::vector options = { }; + std::vector options_one = { }; + std::vector options_two = { }; + std::vector options_three = { }; + + std::string popup_text = c->SendCommandHelpWindow( + c, + description, + notes, + example_format, + examples_one, examples_two, examples_three, + actionables, + options, + options_one, options_two, options_three + ); + + popup_text = DialogueWindow::Table(popup_text); + + c->SendPopupToClient(sep->arg[0], popup_text.c_str()); + + return; + } + + Mob* assistee = c->GetTarget(); + + if (assistee && assistee->IsClient() && c->IsInGroupOrRaid(assistee)) { + c->SetAssistee(assistee->CastToClient()->CharacterID()); + c->Message(Chat::Green, "Your bots will now assist %s.", assistee->GetCleanName()); + + return; + } + + c->Message(Chat::Yellow, "You can only set your bots to assist clients that are in your group or raid."); + + return; +} diff --git a/zone/client.h b/zone/client.h index 2a090eeac..c4ffd5460 100644 --- a/zone/client.h +++ b/zone/client.h @@ -2221,6 +2221,8 @@ public: bool GetBotPulling() { return m_bot_pulling; } void SetBotPulling(bool flag = true) { m_bot_pulling = flag; } + uint32 GetAssistee() { return _assistee; } + void SetAssistee(uint32 id = 0) { _assistee = id; } bool GetBotPrecombat() { return m_bot_precombat; } void SetBotPrecombat(bool flag = true) { m_bot_precombat = flag; } @@ -2257,6 +2259,7 @@ private: uint8 cure_min_threshold; uint8 cure_threshold; bool illusion_block; + uint32 _assistee; bool CanTradeFVNoDropItem(); void SendMobPositions();