[Bots] Add checks to ensure bots and pets do not engage on ^pull (#4708)

This commit is contained in:
nytmyr 2025-02-21 23:13:54 -06:00 committed by GitHub
parent 63b1e6b4b4
commit 8b8b41dab3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 93 additions and 68 deletions

View File

@ -1856,6 +1856,7 @@ bool Bot::BotRangedAttack(Mob* other, bool can_double_attack) {
if ( if (
!GetPullingFlag() && !GetPullingFlag() &&
!GetReturningFlag() &&
( (
( (
GetBotStance() != Stance::Aggressive && GetBotStance() != Stance::Aggressive &&
@ -2115,8 +2116,10 @@ void Bot::SetHoldMode() {
void Bot::AI_Process() void Bot::AI_Process()
{ {
#define PULLING_BOT (GetPullingFlag() || GetReturningFlag()) #define PULLING_BOT (GetPullingFlag())
#define NOT_PULLING_BOT (!GetPullingFlag() && !GetReturningFlag()) #define NOT_PULLING_BOT (!GetPullingFlag())
#define RETURNING_BOT (GetReturningFlag())
#define NOT_RETURNING_BOT (!GetReturningFlag())
#define GUARDING (GetGuardFlag()) #define GUARDING (GetGuardFlag())
#define NOT_GUARDING (!GetGuardFlag()) #define NOT_GUARDING (!GetGuardFlag())
#define HOLDING (GetHoldFlag()) #define HOLDING (GetHoldFlag())
@ -2224,7 +2227,7 @@ void Bot::AI_Process()
// PULLING FLAG (TARGET VALIDATION) // PULLING FLAG (TARGET VALIDATION)
if (GetPullingFlag()) { if (PULLING_BOT) {
if (!PullingFlagChecks(bot_owner)) { if (!PullingFlagChecks(bot_owner)) {
return; return;
} }
@ -2232,10 +2235,10 @@ void Bot::AI_Process()
// RETURNING FLAG // RETURNING FLAG
if (GetReturningFlag()) { if (RETURNING_BOT) {
ReturningFlagChecks(bot_owner, leash_owner, fm_distance); if (ReturningFlagChecks(bot_owner, leash_owner, fm_distance)) {
return;
return; }
} }
// DEFAULT (ACQUIRE TARGET) // DEFAULT (ACQUIRE TARGET)
@ -2268,7 +2271,7 @@ void Bot::AI_Process()
} }
// This causes conflicts with default pet handler (bounces between targets) // This causes conflicts with default pet handler (bounces between targets)
if (NOT_PULLING_BOT && HasPet() && (GetClass() != Class::Enchanter || GetPet()->GetPetType() != petAnimation || GetAA(aaAnimationEmpathy) >= 2)) { if (NOT_PULLING_BOT && NOT_RETURNING_BOT && HasPet() && (GetClass() != Class::Enchanter || GetPet()->GetPetType() != petAnimation || GetAA(aaAnimationEmpathy) >= 2)) {
// We don't add to hate list here because it's assumed to already be on the list // We don't add to hate list here because it's assumed to already be on the list
GetPet()->SetTarget(tar); GetPet()->SetTarget(tar);
} }
@ -2309,7 +2312,7 @@ void Bot::AI_Process()
// PULLING FLAG (ACTIONABLE RANGE) // PULLING FLAG (ACTIONABLE RANGE)
if (GetPullingFlag()) { if (PULLING_BOT || RETURNING_BOT) {
if (!TargetValidation(tar)) { return; } if (!TargetValidation(tar)) { return; }
if (!DoLosChecks(tar)) { if (!DoLosChecks(tar)) {
@ -2368,7 +2371,11 @@ void Bot::AI_Process()
// ENGAGED AT COMBAT RANGE // ENGAGED AT COMBAT RANGE
// We can fight // We can fight
if (at_combat_range) { bool other_bot_pulling =
(bot_owner->GetBotPulling() && NOT_PULLING_BOT) &&
(bot_owner->GetBotPulling() && NOT_RETURNING_BOT);
if (!other_bot_pulling && at_combat_range) {
bool jitter_cooldown = false; bool jitter_cooldown = false;
if (m_combat_jitter_timer.GetRemainingTime() > 1 && m_combat_jitter_timer.Enabled()) { if (m_combat_jitter_timer.GetRemainingTime() > 1 && m_combat_jitter_timer.Enabled()) {
@ -2459,60 +2466,20 @@ void Bot::AI_Process()
// ENGAGED NOT AT COMBAT RANGE // ENGAGED NOT AT COMBAT RANGE
else if (!TryPursueTarget(leash_distance, Goal)) { else if (!other_bot_pulling && !TryPursueTarget(leash_distance, Goal)) {
return; return;
} }
// End not in combat range // End not in combat range
if (bot_owner->GetBotPulling() && HasPet()) {
TryMeditate();
}
else { // Out-of-combat behavior
SetAttackFlag(false);
SetCombatRoundForAlerts(false);
SetAttackingFlag(false);
if (!bot_owner->GetBotPulling()) {
SetPullingFlag(false);
SetReturningFlag(false);
}
// AUTO DEFEND
if (TryAutoDefend(bot_owner, leash_distance) ) {
return;
}
SetTarget(nullptr);
if (
HasPet() &&
(
GetClass() != Class::Enchanter ||
GetPet()->GetPetType() != petAnimation ||
GetAA(aaAnimationEmpathy) >= 1
)
) {
GetPet()->WipeHateList(); GetPet()->WipeHateList();
GetPet()->SetTarget(nullptr); GetPet()->SetTarget(nullptr);
} }
if (m_PlayerState & static_cast<uint32>(PlayerState::Aggressive)) { TryMeditate();
SendRemovePlayerState(PlayerState::Aggressive); }
} else { // Out-of-combat behavior
DoOutOfCombatChecks(bot_owner, follow_mob, Goal, leash_distance, fm_distance);
// OK TO IDLE
// Ok to idle
if (TryNonCombatMovementChecks(bot_owner, follow_mob, Goal)) {
return;
}
if (!IsBotNonSpellFighter() && AI_HasSpells() && TryIdleChecks(fm_distance)) {
return;
}
if (GetClass() == Class::Bard && AI_HasSpells() && TryBardMovementCasts()) {
return;
}
} }
} }
@ -2540,7 +2507,7 @@ bool Bot::TryNonCombatMovementChecks(Client* bot_owner, const Mob* follow_mob, g
float destination_distance = DistanceSquared(GetPosition(), Goal); float destination_distance = DistanceSquared(GetPosition(), Goal);
if ((!bot_owner->GetBotPulling() || PULLING_BOT) && (destination_distance > GetFollowDistance())) { if (destination_distance > GetFollowDistance()) {
if (!IsRooted()) { if (!IsRooted()) {
if (rest_timer.Enabled()) { if (rest_timer.Enabled()) {
rest_timer.Disable(); rest_timer.Disable();
@ -2580,9 +2547,56 @@ bool Bot::TryIdleChecks(float fm_distance) {
return true; return true;
} }
return false; return false;
} }
void Bot::DoOutOfCombatChecks(Client* bot_owner, Mob* follow_mob, glm::vec3& Goal, float leash_distance, float fm_distance) {
SetAttackFlag(false);
SetCombatRoundForAlerts(false);
SetAttackingFlag(false);
if (PULLING_BOT || RETURNING_BOT || !bot_owner->GetBotPulling()) {
SetPullingFlag(false);
SetReturningFlag(false);
}
if (TryAutoDefend(bot_owner, leash_distance) ) {
return;
}
SetTarget(nullptr);
if (
HasPet() &&
(
GetClass() != Class::Enchanter ||
GetPet()->GetPetType() != petAnimation ||
GetAA(aaAnimationEmpathy) >= 1
)
) {
GetPet()->WipeHateList();
GetPet()->SetTarget(nullptr);
}
if (m_PlayerState & static_cast<uint32>(PlayerState::Aggressive)) {
SendRemovePlayerState(PlayerState::Aggressive);
}
// Ok to idle
if (TryNonCombatMovementChecks(bot_owner, follow_mob, Goal)) {
return;
}
if (!IsBotNonSpellFighter() && AI_HasSpells() && TryIdleChecks(fm_distance)) {
return;
}
if (GetClass() == Class::Bard && AI_HasSpells() && TryBardMovementCasts()) {
return;
}
}
// This is as close as I could get without modifying the aggro mechanics and making it an expensive process... // This is as close as I could get without modifying the aggro mechanics and making it an expensive process...
// 'class Client' doesn't make use of hate_list // 'class Client' doesn't make use of hate_list
bool Bot::TryAutoDefend(Client* bot_owner, float leash_distance) { bool Bot::TryAutoDefend(Client* bot_owner, float leash_distance) {
@ -3230,7 +3244,7 @@ bool Bot::IsValidTarget(
SetCombatRoundForAlerts(false); SetCombatRoundForAlerts(false);
SetAttackingFlag(false); SetAttackingFlag(false);
if (PULLING_BOT) { if (PULLING_BOT || RETURNING_BOT) {
SetPullingFlag(false); SetPullingFlag(false);
SetReturningFlag(false); SetReturningFlag(false);
bot_owner->SetBotPulling(false); bot_owner->SetBotPulling(false);
@ -3263,7 +3277,7 @@ Mob* Bot::GetBotTarget(Client* bot_owner)
SetAttackFlag(false); SetAttackFlag(false);
SetAttackingFlag(false); SetAttackingFlag(false);
if (PULLING_BOT) { if (PULLING_BOT || RETURNING_BOT) {
// 'Flags' should only be set on the bot that is pulling // 'Flags' should only be set on the bot that is pulling
SetPullingFlag(false); SetPullingFlag(false);
SetReturningFlag(false); SetReturningFlag(false);
@ -3293,23 +3307,33 @@ bool Bot::TargetValidation(Mob* other) {
} }
bool Bot::ReturningFlagChecks(Client* bot_owner, Mob* leash_owner, float fm_distance) { bool Bot::ReturningFlagChecks(Client* bot_owner, Mob* leash_owner, float fm_distance) {
auto engage_range = (GetBotDistanceRanged() < 30 ? 30 : GetBotDistanceRanged());
if ( if (
(NOT_GUARDING && fm_distance <= GetFollowDistance()) || (GetTarget() && Distance(GetPosition(), GetTarget()->GetPosition()) <= engage_range) &&
(GUARDING && DistanceSquared(GetPosition(), GetGuardPoint()) <= GetFollowDistance()) (
(NOT_GUARDING && fm_distance <= GetFollowDistance()) ||
(GUARDING && DistanceSquared(GetPosition(), GetGuardPoint()) <= GetFollowDistance())
)
) { // Once we're back, clear blocking flags so everyone else can join in ) { // Once we're back, clear blocking flags so everyone else can join in
WipeHateList();
SetTarget(nullptr);
SetPullingFlag(false);
SetReturningFlag(false); SetReturningFlag(false);
bot_owner->SetBotPulling(false); bot_owner->SetBotPulling(false);
if (GetPet()) { if (GetPet()) {
GetPet()->SetPetOrder(m_previous_pet_order); GetPet()->SetPetOrder(m_previous_pet_order);
if (GetClass() != Class::Enchanter || GetPet()->GetPetType() != petAnimation || GetAA(aaAnimationEmpathy) >= 1) {
GetPet()->WipeHateList();
GetPet()->SetTarget(nullptr);
}
} }
return false; return false;
} }
// Need to keep puller out of combat until they reach their 'return to' destination
WipeHateList();
if (!IsMoving()) { if (!IsMoving()) {
glm::vec3 Goal(0, 0, 0); glm::vec3 Goal(0, 0, 0);
@ -3348,8 +3372,6 @@ bool Bot::PullingFlagChecks(Client* bot_owner) {
return false; return false;
} }
else if (GetTarget()->GetHateList().size()) { else if (GetTarget()->GetHateList().size()) {
WipeHateList();
SetTarget(nullptr);
SetPullingFlag(false); SetPullingFlag(false);
SetReturningFlag(); SetReturningFlag();
@ -3363,6 +3385,8 @@ bool Bot::PullingFlagChecks(Client* bot_owner) {
if (GetPlayerState() & static_cast<uint32>(PlayerState::Aggressive)) { if (GetPlayerState() & static_cast<uint32>(PlayerState::Aggressive)) {
SendRemovePlayerState(PlayerState::Aggressive); SendRemovePlayerState(PlayerState::Aggressive);
} }
return false;
} }
return true; return true;
@ -3516,7 +3540,7 @@ Client* Bot::SetLeashOwner(Client* bot_owner, Group* bot_group, Raid* raid, uint
} }
void Bot::SetOwnerTarget(Client* bot_owner) { void Bot::SetOwnerTarget(Client* bot_owner) {
if (GetPet() && PULLING_BOT) { if (GetPet() && (PULLING_BOT || RETURNING_BOT)) {
GetPet()->SetPetOrder(m_previous_pet_order); GetPet()->SetPetOrder(m_previous_pet_order);
} }
@ -4959,7 +4983,7 @@ bool Bot::Death(Mob *killer_mob, int64 damage, uint16 spell_id, EQ::skills::Skil
LeaveHealRotationMemberPool(); LeaveHealRotationMemberPool();
if ((GetPullingFlag() || GetReturningFlag()) && my_owner && my_owner->IsClient()) { if ((PULLING_BOT || RETURNING_BOT) && my_owner && my_owner->IsClient()) {
my_owner->CastToClient()->SetBotPulling(false); my_owner->CastToClient()->SetBotPulling(false);
} }

View File

@ -1127,6 +1127,7 @@ public:
bool TryAutoDefend(Client* bot_owner, float leash_distance); bool TryAutoDefend(Client* bot_owner, float leash_distance);
bool TryIdleChecks(float fm_distance); bool TryIdleChecks(float fm_distance);
bool TryNonCombatMovementChecks(Client* bot_owner, const Mob* follow_mob, glm::vec3& Goal); bool TryNonCombatMovementChecks(Client* bot_owner, const Mob* follow_mob, glm::vec3& Goal);
void DoOutOfCombatChecks(Client* bot_owner, Mob* follow_mob, glm::vec3& Goal, float leash_distance, float fm_distance);
bool TryBardMovementCasts(); bool TryBardMovementCasts();
bool BotRangedAttack(Mob* other, bool can_double_attack = false); bool BotRangedAttack(Mob* other, bool can_double_attack = false);
bool CheckDoubleRangedAttack(); bool CheckDoubleRangedAttack();