mirror of
https://github.com/EQEmu/Server.git
synced 2026-06-03 03:50:40 +00:00
[Bots] Correct ^pull logic and add checks for Enchanter pets (#4827)
* [Bots] Fix bots getting stuck on ^pull - Removed initial LoS check from bots and rely only on owner when told to ^pull. This prevents bots from getting stuck in a loop if they don't have LoS when trying to initiate the pull. * [Bots] Add valid state checks to ^clickitem - Bots previously weren't checking if they were in a valid state or not before trying to click an item when told (in a death state, held, feared, silenced, in group/raid, etc.) * [Bots] Add valid state checks to ^clickitem - Bots previously weren't checking if they were in a valid state or not before trying to click an item when told (in a death state, held, feared, silenced, in group/raid, etc.) Miscommit * undo * Cleanup and Fixes - Cleanup - Fixed Animation Empathy checks and consolidates - Enchanter pets will honor Animation Empathy rules all around - Pets will properly guard if allowed when pulling
This commit is contained in:
+110
-84
@@ -2102,10 +2102,6 @@ void Bot::SetGuardMode() {
|
||||
StopMoving();
|
||||
m_GuardPoint = GetPosition();
|
||||
SetGuardFlag();
|
||||
|
||||
if (HasPet() && (GetClass() != Class::Enchanter || GetPet()->GetPetType() != petAnimation || GetAA(aaAnimationEmpathy) >= 2)) {
|
||||
GetPet()->StopMoving();
|
||||
}
|
||||
}
|
||||
|
||||
void Bot::SetHoldMode() {
|
||||
@@ -2270,7 +2266,7 @@ void Bot::AI_Process()
|
||||
}
|
||||
|
||||
// This causes conflicts with default pet handler (bounces between targets)
|
||||
if (NOT_PULLING_BOT && NOT_RETURNING_BOT && HasPet() && (GetClass() != Class::Enchanter || GetPet()->GetPetType() != petAnimation || GetAA(aaAnimationEmpathy) >= 2)) {
|
||||
if (NOT_PULLING_BOT && NOT_RETURNING_BOT && HasControllablePet(BotAnimEmpathy::Attack)) {
|
||||
// We don't add to hate list here because it's assumed to already be on the list
|
||||
GetPet()->SetTarget(tar);
|
||||
}
|
||||
@@ -2284,11 +2280,11 @@ void Bot::AI_Process()
|
||||
}
|
||||
|
||||
// COMBAT RANGE CALCS
|
||||
bool front_mob = InFrontMob(tar, GetX(), GetY());
|
||||
bool behind_mob = BehindMob(tar, GetX(), GetY());
|
||||
bool stop_melee_level = GetLevel() >= GetStopMeleeLevel();
|
||||
bool front_mob = InFrontMob(tar, GetX(), GetY());
|
||||
bool behind_mob = BehindMob(tar, GetX(), GetY());
|
||||
bool stop_melee_level = GetLevel() >= GetStopMeleeLevel();
|
||||
|
||||
tar_distance = sqrt(tar_distance); // sqrt this for future calculations
|
||||
// Item variables
|
||||
const EQ::ItemInstance* p_item = GetBotItem(EQ::invslot::slotPrimary);
|
||||
const EQ::ItemInstance* s_item = GetBotItem(EQ::invslot::slotSecondary);
|
||||
|
||||
@@ -2310,20 +2306,36 @@ void Bot::AI_Process()
|
||||
|
||||
// PULLING FLAG (ACTIONABLE RANGE)
|
||||
|
||||
if (PULLING_BOT || RETURNING_BOT) {
|
||||
if (!TargetValidation(tar)) { return; }
|
||||
if (PULLING_BOT) {
|
||||
if (!TargetValidation(tar)) {
|
||||
SetPullFlag(false);
|
||||
SetPullingFlag(false);
|
||||
bot_owner->SetBotPulling(false);
|
||||
|
||||
if (GetPet()) {
|
||||
GetPet()->SetPetOrder(SPO_Follow);
|
||||
GetPet()->CastToNPC()->SaveGuardSpot(true);
|
||||
}
|
||||
|
||||
if (RuleB(Bots, BotsRequireLoS) && !HasLoS()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (at_combat_range) {
|
||||
if (
|
||||
!tar->GetSpecialAbility(SpecialAbility::RangedAttackImmunity) &&
|
||||
if (!at_combat_range && RuleB(Bots, UseSpellPulling)) {
|
||||
uint16 pull_spell_id = RuleI(Bots, PullSpellID);
|
||||
|
||||
if (IsValidSpell(pull_spell_id) && tar_distance <= spells[pull_spell_id].range) {
|
||||
at_combat_range = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (at_combat_range && DoLosChecks(tar)) {
|
||||
bool ai_cast_successful = false;
|
||||
bool can_range_attack = !tar->GetSpecialAbility(SpecialAbility::RangedAttackImmunity) &&
|
||||
RuleB(Bots, AllowRangedPulling) &&
|
||||
IsBotRanged() &&
|
||||
ranged_timer.Check(false)
|
||||
) {
|
||||
ranged_timer.Check(false);
|
||||
|
||||
if (can_range_attack) {
|
||||
StopMoving(CalculateHeadingToTarget(tar->GetX(), tar->GetY()));
|
||||
|
||||
if (BotRangedAttack(tar) && CheckDoubleRangedAttack()) {
|
||||
@@ -2335,30 +2347,33 @@ void Bot::AI_Process()
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
RuleB(Bots, AllowAISpellPulling) &&
|
||||
bool can_ai_spell_pull = RuleB(Bots, AllowAISpellPulling) &&
|
||||
!IsBotNonSpellFighter() &&
|
||||
AI_HasSpells()
|
||||
) {
|
||||
AI_HasSpells();
|
||||
|
||||
if (can_ai_spell_pull) {
|
||||
StopMoving(CalculateHeadingToTarget(tar->GetX(), tar->GetY()));
|
||||
SetPullingSpell(true);
|
||||
AI_EngagedCastCheck();
|
||||
ai_cast_successful = AI_EngagedCastCheck();
|
||||
SetPullingSpell(false);
|
||||
|
||||
return;
|
||||
if (ai_cast_successful) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (RuleB(Bots, UseSpellPulling)) {
|
||||
uint16 spell_id = RuleI(Bots, PullSpellID);
|
||||
if (RuleB(Bots, UseSpellPulling)) {
|
||||
uint16 pull_spell_id = RuleI(Bots, PullSpellID);
|
||||
|
||||
if (tar_distance <= spells[spell_id].range) {
|
||||
StopMoving();
|
||||
SetPullingSpell(true);
|
||||
CastSpell(spell_id, tar->GetID());
|
||||
SetPullingSpell(false);
|
||||
|
||||
return;
|
||||
if (IsValidSpell(pull_spell_id) && tar_distance <= spells[pull_spell_id].range) {
|
||||
StopMoving(CalculateHeadingToTarget(tar->GetX(), tar->GetY()));
|
||||
SetPullingSpell(true);
|
||||
CastSpell(pull_spell_id, tar->GetID());
|
||||
SetPullingSpell(false);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
TryPursueTarget(leash_distance);
|
||||
@@ -2551,6 +2566,12 @@ void Bot::DoOutOfCombatChecks(Client* bot_owner, Mob* follow_mob, float leash_di
|
||||
if (PULLING_BOT || RETURNING_BOT || !bot_owner->GetBotPulling()) {
|
||||
SetPullingFlag(false);
|
||||
SetReturningFlag(false);
|
||||
bot_owner->SetBotPulling(false);
|
||||
|
||||
if (GetPet()) {
|
||||
GetPet()->SetPetOrder(SPO_Follow);
|
||||
GetPet()->CastToNPC()->SaveGuardSpot(true);
|
||||
}
|
||||
}
|
||||
|
||||
if (TryAutoDefend(bot_owner, leash_distance) ) {
|
||||
@@ -2559,14 +2580,7 @@ void Bot::DoOutOfCombatChecks(Client* bot_owner, Mob* follow_mob, float leash_di
|
||||
|
||||
SetTarget(nullptr);
|
||||
|
||||
if (
|
||||
HasPet() &&
|
||||
(
|
||||
GetClass() != Class::Enchanter ||
|
||||
GetPet()->GetPetType() != petAnimation ||
|
||||
GetAA(aaAnimationEmpathy) >= 1
|
||||
)
|
||||
) {
|
||||
if (HasControllablePet(BotAnimEmpathy::BackOff)) {
|
||||
GetPet()->WipeHateList();
|
||||
GetPet()->SetTarget(nullptr);
|
||||
}
|
||||
@@ -2729,7 +2743,7 @@ bool Bot::TryAutoDefend(Client* bot_owner, float leash_distance) {
|
||||
SetTarget(hater);
|
||||
SetAttackingFlag();
|
||||
|
||||
if (HasPet() && (GetClass() != Class::Enchanter || GetPet()->GetPetType() != petAnimation || GetAA(aaAnimationEmpathy) >= 2)) {
|
||||
if (HasControllablePet(BotAnimEmpathy::Attack)) {
|
||||
GetPet()->AddToHateList(hater, 1);
|
||||
GetPet()->SetTarget(hater);
|
||||
}
|
||||
@@ -2799,14 +2813,7 @@ bool Bot::TryPursueTarget(float leash_distance) {
|
||||
WipeHateList();
|
||||
SetTarget(nullptr);
|
||||
|
||||
if (
|
||||
HasPet() &&
|
||||
(
|
||||
GetClass() != Class::Enchanter ||
|
||||
GetPet()->GetPetType() != petAnimation ||
|
||||
GetAA(aaAnimationEmpathy) >= 2
|
||||
)
|
||||
) {
|
||||
if (HasControllablePet(BotAnimEmpathy::BackOff)) {
|
||||
GetPet()->WipeHateList();
|
||||
GetPet()->SetTarget(nullptr);
|
||||
}
|
||||
@@ -3191,7 +3198,8 @@ bool Bot::IsValidTarget(
|
||||
bot_owner->SetBotPulling(false);
|
||||
|
||||
if (GetPet()) {
|
||||
GetPet()->SetPetOrder(m_previous_pet_order);
|
||||
GetPet()->SetPetOrder(SPO_Follow);
|
||||
GetPet()->CastToNPC()->SaveGuardSpot(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3225,7 +3233,8 @@ Mob* Bot::GetBotTarget(Client* bot_owner)
|
||||
bot_owner->SetBotPulling(false);
|
||||
|
||||
if (GetPet()) {
|
||||
GetPet()->SetPetOrder(m_previous_pet_order);
|
||||
GetPet()->SetPetOrder(SPO_Follow);
|
||||
GetPet()->CastToNPC()->SaveGuardSpot(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3248,15 +3257,11 @@ bool Bot::TargetValidation(Mob* other) {
|
||||
}
|
||||
|
||||
bool Bot::ReturningFlagChecks(Client* bot_owner, Mob* leash_owner, float fm_distance) {
|
||||
auto engage_range = (GetBotDistanceRanged() < 30 ? 30 : GetBotDistanceRanged());
|
||||
bool target_check = !GetTarget() || Distance(GetPosition(), GetTarget()->GetPosition()) <= 75.0f;
|
||||
bool returned_check = (NOT_GUARDING && fm_distance <= GetFollowDistance()) ||
|
||||
(GUARDING && DistanceSquared(GetPosition(), GetGuardPoint()) <= GetFollowDistance());
|
||||
|
||||
if (
|
||||
(GetTarget() && Distance(GetPosition(), GetTarget()->GetPosition()) <= engage_range) &&
|
||||
(
|
||||
(NOT_GUARDING && fm_distance <= GetFollowDistance()) ||
|
||||
(GUARDING && DistanceSquared(GetPosition(), GetGuardPoint()) <= GetFollowDistance())
|
||||
)
|
||||
) { // Once we're back, clear blocking flags so everyone else can join in
|
||||
if (target_check && returned_check) { // Once we're back, clear blocking flags so everyone else can join in
|
||||
WipeHateList();
|
||||
SetTarget(nullptr);
|
||||
SetPullingFlag(false);
|
||||
@@ -3264,9 +3269,10 @@ bool Bot::ReturningFlagChecks(Client* bot_owner, Mob* leash_owner, float fm_dist
|
||||
bot_owner->SetBotPulling(false);
|
||||
|
||||
if (GetPet()) {
|
||||
GetPet()->SetPetOrder(m_previous_pet_order);
|
||||
GetPet()->SetPetOrder(SPO_Follow);
|
||||
GetPet()->CastToNPC()->SaveGuardSpot(true);
|
||||
|
||||
if (GetClass() != Class::Enchanter || GetPet()->GetPetType() != petAnimation || GetAA(aaAnimationEmpathy) >= 1) {
|
||||
if (HasControllablePet(BotAnimEmpathy::BackOff)) {
|
||||
GetPet()->WipeHateList();
|
||||
GetPet()->SetTarget(nullptr);
|
||||
}
|
||||
@@ -3307,7 +3313,8 @@ bool Bot::PullingFlagChecks(Client* bot_owner) {
|
||||
bot_owner->SetBotPulling(false);
|
||||
|
||||
if (GetPet()) {
|
||||
GetPet()->SetPetOrder(m_previous_pet_order);
|
||||
GetPet()->SetPetOrder(SPO_Follow);
|
||||
GetPet()->CastToNPC()->SaveGuardSpot(true);
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -3316,11 +3323,16 @@ bool Bot::PullingFlagChecks(Client* bot_owner) {
|
||||
SetPullingFlag(false);
|
||||
SetReturningFlag();
|
||||
|
||||
if (HasPet() &&
|
||||
(GetClass() != Class::Enchanter || GetPet()->GetPetType() != petAnimation || GetAA(aaAnimationEmpathy) >= 1)) {
|
||||
Mob* my_pet = GetPet();
|
||||
|
||||
GetPet()->WipeHateList();
|
||||
GetPet()->SetTarget(nullptr);
|
||||
if (my_pet) {
|
||||
if (HasControllablePet(BotAnimEmpathy::BackOff)) {
|
||||
my_pet->WipeHateList();
|
||||
my_pet->SetTarget(nullptr);
|
||||
} else {
|
||||
my_pet->AddToHateList(GetTarget(), 1);
|
||||
my_pet->SetTarget(GetTarget());
|
||||
}
|
||||
}
|
||||
|
||||
if (GetPlayerState() & static_cast<uint32>(PlayerState::Aggressive)) {
|
||||
@@ -3482,7 +3494,7 @@ Client* Bot::SetLeashOwner(Client* bot_owner, Group* bot_group, Raid* raid, uint
|
||||
|
||||
void Bot::SetOwnerTarget(Client* bot_owner) {
|
||||
if (GetPet() && (PULLING_BOT || RETURNING_BOT)) {
|
||||
GetPet()->SetPetOrder(m_previous_pet_order);
|
||||
GetPet()->SetPetOrder(SPO_Follow);
|
||||
}
|
||||
|
||||
SetAttackFlag(false);
|
||||
@@ -3502,7 +3514,7 @@ void Bot::SetOwnerTarget(Client* bot_owner) {
|
||||
SetTarget(attack_target);
|
||||
SetAttackingFlag();
|
||||
|
||||
if (GetPet() && (GetClass() != Class::Enchanter || GetPet()->GetPetType() != petAnimation || GetAA(aaAnimationEmpathy) >= 2)) {
|
||||
if (HasControllablePet(BotAnimEmpathy::Attack)) {
|
||||
GetPet()->WipeHateList();
|
||||
GetPet()->AddToHateList(attack_target, 1);
|
||||
GetPet()->SetTarget(attack_target);
|
||||
@@ -3520,20 +3532,21 @@ void Bot::BotPullerProcess(Client* bot_owner, Raid* raid) {
|
||||
SetReturningFlag(false);
|
||||
bot_owner->SetBotPulling(false);
|
||||
|
||||
if (GetPet()) {
|
||||
GetPet()->SetPetOrder(SPO_Follow);
|
||||
GetPet()->CastToNPC()->SaveGuardSpot(true);
|
||||
}
|
||||
|
||||
if (NOT_HOLDING && NOT_PASSIVE) {
|
||||
auto pull_target = bot_owner->GetTarget();
|
||||
|
||||
if (pull_target) {
|
||||
if (raid) {
|
||||
const auto msg = fmt::format("Pulling {}.", pull_target->GetCleanName());
|
||||
raid->RaidSay(msg.c_str(), GetCleanName(), 0, 100);
|
||||
} else {
|
||||
RaidGroupSay(
|
||||
fmt::format(
|
||||
"Pulling {}.",
|
||||
pull_target->GetCleanName()
|
||||
).c_str()
|
||||
);
|
||||
}
|
||||
RaidGroupSay(
|
||||
fmt::format(
|
||||
"Pulling {}.",
|
||||
pull_target->GetCleanName()
|
||||
).c_str()
|
||||
);
|
||||
|
||||
InterruptSpell();
|
||||
WipeHateList();
|
||||
@@ -3542,12 +3555,15 @@ void Bot::BotPullerProcess(Client* bot_owner, Raid* raid) {
|
||||
SetPullingFlag();
|
||||
bot_owner->SetBotPulling();
|
||||
|
||||
if (HasPet() && (GetClass() != Class::Enchanter || GetPet()->GetPetType() != petAnimation || GetAA(aaAnimationEmpathy) >= 1)) {
|
||||
if (GetPet()) {
|
||||
GetPet()->WipeHateList();
|
||||
GetPet()->SetTarget(nullptr);
|
||||
m_previous_pet_order = GetPet()->GetPetOrder();
|
||||
GetPet()->CastToNPC()->SaveGuardSpot(GetPosition());
|
||||
GetPet()->SetPetOrder(SPO_Guard);
|
||||
|
||||
if (HasControllablePet(BotAnimEmpathy::Guard)) {
|
||||
m_previous_pet_order = GetPet()->GetPetOrder();
|
||||
GetPet()->CastToNPC()->SaveGuardSpot(GetPosition());
|
||||
GetPet()->SetPetOrder(SPO_Guard);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13438,3 +13454,13 @@ bool Bot::IsValidBotStance(uint8 stance) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Bot::HasControllablePet(uint8 ranks_required) {
|
||||
if (!GetPet()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return GetClass() != Class::Enchanter ||
|
||||
GetPet()->GetPetType() != petAnimation ||
|
||||
GetAA(aaAnimationEmpathy) >= ranks_required;
|
||||
}
|
||||
Reference in New Issue
Block a user