diff --git a/common/ruletypes.h b/common/ruletypes.h index f1925f421..7a2a2fe50 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -858,12 +858,6 @@ RULE_BOOL(Bots, BotArcheryConsumesAmmo, true, "Set to false to disable Archery A RULE_BOOL(Bots, BotThrowingConsumesAmmo, true, "Set to false to disable Throwing Ammo Consumption") RULE_INT(Bots, StackSizeMin, 20, "20 Default. -1 to disable and use default max stack size. Minimum stack size to give a bot (Arrows/Throwing).") RULE_INT(Bots, HasOrMayGetAggroThreshold, 90, "90 Default. Percent threshold of total hate where bots will stop casting spells that generate hate if they are set to try to not pull aggro via spells.") -RULE_REAL(Bots, LowerMeleeDistanceMultiplier, 0.35, "Closest % of the hit box a melee bot will get to the target. Default 0.35") -RULE_REAL(Bots, LowerTauntingMeleeDistanceMultiplier, 0.25, "Closest % of the hit box a taunting melee bot will get to the target. Default 0.25") -RULE_REAL(Bots, LowerMaxMeleeRangeDistanceMultiplier, 0.80, "Closest % of the hit box a max melee range melee bot will get to the target. Default 0.80") -RULE_REAL(Bots, UpperMeleeDistanceMultiplier, 0.55, "Furthest % of the hit box a melee bot will get from the target. Default 0.55") -RULE_REAL(Bots, UpperTauntingMeleeDistanceMultiplier, 0.45, "Furthest % of the hit box a taunting melee bot will get from the target. Default 0.45") -RULE_REAL(Bots, UpperMaxMeleeRangeDistanceMultiplier, 0.95, "Furthest % of the hit box a max melee range melee bot will get from the target. Default 0.95") RULE_BOOL(Bots, DisableSpecialAbilitiesAtMaxMelee, true, "If true, when bots are at max melee distance, special abilities including taunt will be disabled. Default True.") RULE_INT(Bots, MinJitterTimer, 500, "Minimum ms between bot movement jitter checks.") RULE_INT(Bots, MaxJitterTimer, 2500, "Maximum ms between bot movement jitter checks. Set to 0 to disable timer checks.") diff --git a/zone/bot.cpp b/zone/bot.cpp index 42e09cb43..af6723181 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -245,6 +245,8 @@ Bot::Bot( EquipBot(); + m_combat_jitter_timer.Start(); + if (GetClass() == Class::Rogue) { m_rogue_evade_timer.Start(); } @@ -2186,8 +2188,7 @@ void Bot::AI_Process() } if (HOLDING || (raid && r_group == RAID_GROUPLESS)) { - glm::vec3 Goal(0, 0, 0); - TryNonCombatMovementChecks(bot_owner, follow_mob, Goal); + TryNonCombatMovementChecks(bot_owner, follow_mob); return; } @@ -2217,8 +2218,6 @@ void Bot::AI_Process() } //ALT COMBAT (ACQUIRE HATE) - glm::vec3 Goal(0, 0, 0); - // We have aggro to choose from if (IsEngaged()) { if (rest_timer.Enabled()) { @@ -2293,15 +2292,15 @@ void Bot::AI_Process() const EQ::ItemInstance* p_item = GetBotItem(EQ::invslot::slotPrimary); const EQ::ItemInstance* s_item = GetBotItem(EQ::invslot::slotSecondary); - CombatRangeInput input = { - .target = tar, - .target_distance = tar_distance, - .stop_melee_level = stop_melee_level, - .p_item = p_item, - .s_item = s_item + CombatRangeInput i = { + .target = tar, + .target_distance = tar_distance, + .stop_melee_level = stop_melee_level, + .p_item = p_item, + .s_item = s_item }; - CombatRangeOutput o = EvaluateCombatRange(input); + CombatRangeOutput o = EvaluateCombatRange(i); // Combat range variables bool at_combat_range = o.at_combat_range; @@ -2362,7 +2361,7 @@ void Bot::AI_Process() } } - TryPursueTarget(leash_distance, Goal); + TryPursueTarget(leash_distance); return; } @@ -2385,52 +2384,30 @@ void Bot::AI_Process() (bot_owner->GetBotPulling() && NOT_RETURNING_BOT); if (!other_bot_pulling && at_combat_range) { - bool jitter_cooldown = false; - - if (m_combat_jitter_timer.GetRemainingTime() > 1 && m_combat_jitter_timer.Enabled()) { - jitter_cooldown = true; - } - - if ( - IsMoving() || - GetCombatJitterFlag() || - GetCombatOutOfRangeJitterFlag() - ) { - if ( - !GetCombatJitterFlag() || - !IsMoving() || - GetCombatOutOfRangeJitterFlag() - ) { - StopMoving(CalculateHeadingToTarget(tar->GetX(), tar->GetY())); - } + CombatPositioningInput cpi { + .tar = tar, + .stop_melee_level = stop_melee_level, + .tar_distance = tar_distance, + .melee_distance_min = melee_distance_min, + .melee_distance = melee_distance, + .melee_distance_max = melee_distance_max, + .behind_mob = behind_mob, + .front_mob = front_mob + }; + if (DoCombatPositioning(cpi) && IsMoving()) { return; } - if ( - !jitter_cooldown && - AI_movement_timer->Check() && - (!spellend_timer.Enabled() || GetClass() == Class::Bard) - ) { - DoCombatPositioning(tar, Goal, stop_melee_level, tar_distance, melee_distance_min, melee_distance, melee_distance_max, behind_mob, front_mob); + if (!IsSitting() && !IsFacingMob(tar)) { + FaceTarget(tar); return; } - else { - if (!IsSitting() && !IsFacingMob(tar)) { - FaceTarget(tar); - return; - } - } if (!IsBotNonSpellFighter() && AI_HasSpells() && AI_EngagedCastCheck()) { return; } - if (IsMoving()) { - StopMoving(CalculateHeadingToTarget(tar->GetX(), tar->GetY())); - return; - } - if ( !tar->GetSpecialAbility(SpecialAbility::RangedAttackImmunity) && IsBotRanged() && @@ -2479,7 +2456,7 @@ void Bot::AI_Process() // ENGAGED NOT AT COMBAT RANGE - else if (!other_bot_pulling && !TryPursueTarget(leash_distance, Goal)) { + else if (!other_bot_pulling && !TryPursueTarget(leash_distance)) { return; } @@ -2492,7 +2469,7 @@ void Bot::AI_Process() TryMeditate(); } else { // Out-of-combat behavior - DoOutOfCombatChecks(bot_owner, follow_mob, Goal, leash_distance, fm_distance); + DoOutOfCombatChecks(bot_owner, follow_mob, leash_distance, fm_distance); } } @@ -2509,8 +2486,10 @@ bool Bot::TryBardMovementCasts() {// Basically, bard bots get a chance to cast i return false; } -bool Bot::TryNonCombatMovementChecks(Client* bot_owner, const Mob* follow_mob, glm::vec3& Goal) {// Non-engaged movement checks +bool Bot::TryNonCombatMovementChecks(Client* bot_owner, const Mob* follow_mob) {// Non-engaged movement checks if (AI_movement_timer->Check() && (!IsCasting() || GetClass() == Class::Bard)) { + glm::vec3 Goal(0, 0, 0); + if (GUARDING) { Goal = GetGuardPoint(); } @@ -2564,7 +2543,7 @@ bool Bot::TryIdleChecks(float fm_distance) { return false; } -void Bot::DoOutOfCombatChecks(Client* bot_owner, Mob* follow_mob, glm::vec3& Goal, float leash_distance, float fm_distance) { +void Bot::DoOutOfCombatChecks(Client* bot_owner, Mob* follow_mob, float leash_distance, float fm_distance) { SetAttackFlag(false); SetCombatRoundForAlerts(false); SetAttackingFlag(false); @@ -2597,7 +2576,7 @@ void Bot::DoOutOfCombatChecks(Client* bot_owner, Mob* follow_mob, glm::vec3& Goa } // Ok to idle - if (TryNonCombatMovementChecks(bot_owner, follow_mob, Goal)) { + if (TryNonCombatMovementChecks(bot_owner, follow_mob)) { return; } @@ -2808,15 +2787,14 @@ bool Bot::TryMeditate() { } // This code actually gets processed when we are too far away from target and have not engaged yet -bool Bot::TryPursueTarget(float leash_distance, glm::vec3& Goal) { +bool Bot::TryPursueTarget(float leash_distance) { if (AI_movement_timer->Check() && (!spellend_timer.Enabled() || GetClass() == Class::Bard)) { if (GetTarget() && !IsRooted()) { LogAIDetail("Pursuing [{}] while engaged", GetTarget()->GetCleanName()); - Goal = GetTarget()->GetPosition(); + glm::vec3 Goal = GetTarget()->GetPosition(); if (DistanceSquared(m_Position, Goal) <= leash_distance) { RunTo(Goal.x, Goal.y, Goal.z); - SetCombatOutOfRangeJitter(); } else { WipeHateList(); SetTarget(nullptr); @@ -3130,8 +3108,8 @@ CombatRangeOutput Bot::EvaluateCombatRange(const CombatRangeInput& input) { bool is_backstab_weapon = input.p_item && input.p_item->GetItemBackstabDamage(); if (IsTaunting()) { // Taunting bots - o.melee_distance_min = o.melee_distance_max * RuleR(Bots, LowerTauntingMeleeDistanceMultiplier); - o.melee_distance = o.melee_distance_max * RuleR(Bots, UpperTauntingMeleeDistanceMultiplier); + o.melee_distance_min = o.melee_distance_max * 0.25f; + o.melee_distance = o.melee_distance_max * 0.45f; } else if (IsBotRanged()) { // Archers/Throwers float min_distance = RuleI(Combat, MinRangedAttackDist); @@ -3139,22 +3117,22 @@ CombatRangeOutput Bot::EvaluateCombatRange(const CombatRangeInput& input) { float desired_range = GetBotDistanceRanged(); max_distance = (max_distance == 0 ? desired_range : max_distance); // stay ranged even if items/ammo aren't correct - o.melee_distance_min = std::max(min_distance, (desired_range / 2)); + o.melee_distance_min = std::max(min_distance, (desired_range * 0.75f)); o.melee_distance = std::min(max_distance, desired_range); } else if (input.stop_melee_level) { // Casters float desired_range = GetBotDistanceRanged(); - o.melee_distance_min = std::max(o.melee_distance_max, (desired_range / 2)); + o.melee_distance_min = std::max(o.melee_distance_max, (desired_range * 0.75f)); o.melee_distance = std::max((o.melee_distance_max * 1.25f), desired_range); } else if (GetMaxMeleeRange()) { // Melee bots set to max melee range - o.melee_distance_min = o.melee_distance_max * RuleR(Bots, LowerMaxMeleeRangeDistanceMultiplier); - o.melee_distance = o.melee_distance_max * RuleR(Bots, UpperMaxMeleeRangeDistanceMultiplier); + o.melee_distance_min = o.melee_distance_max * 0.80f; + o.melee_distance = o.melee_distance_max * 0.95f; } else { // Regular melee - o.melee_distance_min = o.melee_distance_max * RuleR(Bots, LowerMeleeDistanceMultiplier); - o.melee_distance = o.melee_distance_max * RuleR(Bots, UpperMeleeDistanceMultiplier); + o.melee_distance_min = o.melee_distance_max * 0.30f; + o.melee_distance = o.melee_distance_max * 0.65f; } o.at_combat_range = (input.target_distance <= o.melee_distance); @@ -11966,193 +11944,171 @@ void Bot::SetCastedSpellType(uint16 spell_type) { _castedSpellType = spell_type; } -void Bot::DoFaceCheckWithJitter(Mob* tar) { - if (!tar) { - return; - } - - if (IsMoving()) { - return; - } - - SetCombatJitter(); - if (!IsFacingMob(tar)) { - FaceTarget(tar); - return; - } - return; -} - -void Bot::DoFaceCheckNoJitter(Mob* tar) { - if (!tar) { - return; - } - - if (IsMoving()) { - return; - } - - if (!IsFacingMob(tar)) { - FaceTarget(tar); - return; - } - return; -} - void Bot::RunToGoalWithJitter(glm::vec3 Goal) { RunTo(Goal.x, Goal.y, Goal.z); SetCombatJitter(); } -void Bot::SetCombatOutOfRangeJitter() { - SetCombatOutOfRangeJitterFlag(); - - if (RuleI(Bots, MaxJitterTimer) > 0) { - m_combat_jitter_timer.Start(zone->random.Int(RuleI(Bots, MinJitterTimer), RuleI(Bots, MaxJitterTimer)), true); - } -} - void Bot::SetCombatJitter() { - SetCombatJitterFlag(); - if (RuleI(Bots, MaxJitterTimer) > 0) { m_combat_jitter_timer.Start(zone->random.Int(RuleI(Bots, MinJitterTimer), RuleI(Bots, MaxJitterTimer)), true); } } -void Bot::DoCombatPositioning( - Mob* tar, - glm::vec3 Goal, - bool stop_melee_level, - float tar_distance, - float melee_distance_min, - float melee_distance, - float melee_distance_max, - bool behind_mob, - bool front_mob -) { - if (!tar->IsFeared()) { - bool is_too_close = tar_distance < melee_distance_min; - bool los_adjust = !HasRequiredLoSForPositioning(tar); +bool Bot::DoCombatPositioning(const CombatPositioningInput& input) +{ + bool adjustment_needed = false; + bool is_too_close = input.tar_distance < input.melee_distance_min; + bool los_adjust = !HasRequiredLoSForPositioning(input.tar); + bool behind_mob_set = !input.stop_melee_level && + !IsBotRanged() && + GetBehindMob(); // Don't want casters or ranged to find positions behind the target. + bool adjustment_allowed = !IsMoving() && + m_combat_jitter_timer.Check() && + (!spellend_timer.Enabled() || GetClass() == Class::Bard); - if (tar->IsRooted() && !IsTaunting()) { // Move non-taunting melee out of range - bool rooted_adjust = tar_distance <= melee_distance_max && HasTargetReflection(); - if (rooted_adjust) { - if (PlotBotPositionAroundTarget(tar, Goal.x, Goal.y, Goal.z, (melee_distance_max + 1), (melee_distance_max * 1.25f), GetBehindMob(), !GetBehindMob())) { - RunToGoalWithJitter(Goal); - return; - } + if (!IsMoving() && !IsSitting() && !IsFacingMob(input.tar)) { + FaceTarget(input.tar); + } + + FindPositionInput find_position_input = { + .tar = input.tar, + .distance_min = input.melee_distance_min, + .distance_max = input.melee_distance_max, + .behind_only = behind_mob_set, + .front_only = IsTaunting(), + .bypass_los = false, + }; + + bool is_melee = (!input.stop_melee_level && !IsBotRanged()); + + if (input.tar->IsRooted() && !IsTaunting()) { // Move non-taunting melee out of range + adjustment_needed = + (input.tar_distance <= input.melee_distance_max) && + HasTargetReflection(); + + if (adjustment_needed && adjustment_allowed) { + find_position_input.distance_min = input.melee_distance_max + 1; + find_position_input.distance_max = input.melee_distance_max * 1.25f; + + PlotBotPositionAroundTarget(find_position_input); + } + } else { + if (input.tar->IsFeared()) { + adjustment_needed = los_adjust; + + if (adjustment_needed && adjustment_allowed) { + find_position_input.distance_min = input.melee_distance_min; + find_position_input.distance_max = input.melee_distance; + find_position_input.behind_only = false; + find_position_input.front_only = false; + + PlotBotPositionAroundTarget(find_position_input); } } - else { - if (IsTaunting()) { // Taunting adjustments - bool taunting_adjust = (!front_mob || is_too_close || los_adjust); + else if (IsTaunting() || HasTargetReflection()) { // Taunting/Aggro adjustments + adjustment_needed = + is_too_close || + los_adjust || + (is_melee && !input.front_mob); - if (taunting_adjust) { - if (PlotBotPositionAroundTarget(tar, Goal.x, Goal.y, Goal.z, melee_distance_min, melee_distance, false, true)) { - RunToGoalWithJitter(Goal); + if (adjustment_needed && adjustment_allowed) { + find_position_input.distance_min = input.melee_distance_min; + find_position_input.distance_max = input.melee_distance; + find_position_input.behind_only = false; + find_position_input.front_only = true; - return; - } - } + PlotBotPositionAroundTarget(find_position_input); } - else { - if (tar->IsEnraged() && !stop_melee_level && !IsBotRanged()) { // Move non-taunting melee bots behind target during enrage - bool enraged_adjust = !behind_mob || is_too_close || los_adjust; + } else { + if (input.tar->IsEnraged() && is_melee) { // Move non-taunting melee bots behind target during enrage + adjustment_needed = + !behind_mob_set || + is_too_close || + los_adjust; - if (enraged_adjust) { - if (PlotBotPositionAroundTarget(tar, Goal.x, Goal.y, Goal.z, melee_distance_min, melee_distance, true)) { - RunToGoalWithJitter(Goal); + if (adjustment_needed && adjustment_allowed) { + find_position_input.distance_min = input.melee_distance_min; + find_position_input.distance_max = input.melee_distance; + find_position_input.behind_only = true; + find_position_input.front_only = false; - return; - } - } + PlotBotPositionAroundTarget(find_position_input); } - else { // Regular adjustments - bool regular_adjust = - is_too_close || - los_adjust || - (!GetBehindMob() && !front_mob) || - (GetBehindMob() && !behind_mob); + } else { // Regular adjustments + adjustment_needed = + is_too_close || + los_adjust || + (behind_mob_set && !input.behind_mob); - if (regular_adjust) { - if (PlotBotPositionAroundTarget(tar, Goal.x, Goal.y, Goal.z, melee_distance_min, melee_distance, GetBehindMob(), !GetBehindMob())) { - RunToGoalWithJitter(Goal); + if (adjustment_needed && adjustment_allowed) { + find_position_input.distance_min = input.melee_distance_min; + find_position_input.distance_max = input.melee_distance; - return; - } - } + PlotBotPositionAroundTarget(find_position_input); } } } } - DoFaceCheckNoJitter(tar); + if (!adjustment_needed && IsMoving()) { + StopMoving(); + } + + return adjustment_needed; } -bool Bot::PlotBotPositionAroundTarget(Mob* target, float& x_dest, float& y_dest, float& z_dest, float min_distance, float max_distance, bool behind_only, bool front_only, bool bypass_los) { +bool Bot::PlotBotPositionAroundTarget(const FindPositionInput& input) { bool Result = false; - if (target) { - float look_heading = 0; - - min_distance = min_distance; - max_distance = max_distance; - float temp_x = 0; - float temp_y = 0; - float temp_z = target->GetZ(); - float best_z = 0; - auto offset = GetZOffset(); - const float tar_x = target->GetX(); - const float tar_y = target->GetY(); - float tar_distance = 0; - - glm::vec3 temp_z_Position; - glm::vec4 temp_m_Position; - - const uint16 max_iterations_allowed = 50; - uint16 counter = 0; + if (input.tar) { + glm::vec3 temp_goal(0, 0, input.tar->GetZ()); + glm::vec3 tar_position(input.tar->GetX(), input.tar->GetY(), input.tar->GetZ()); + float look_heading = 0; + float best_z = 0; + float tar_distance = 0; + float desired_angle = 0; + const float offset = GetZOffset(); + const uint16 max_iterations_allowed = 50; + uint16 counter = 0; while (counter < max_iterations_allowed) { - temp_x = tar_x + zone->random.Real(-max_distance, max_distance); - temp_y = tar_y + zone->random.Real(-max_distance, max_distance); - - temp_z_Position.x = temp_x; - temp_z_Position.y = temp_y; - temp_z_Position.z = temp_z; - best_z = GetFixedZ(temp_z_Position); + temp_goal.x = tar_position.x + zone->random.Real(-input.distance_max, input.distance_max); + temp_goal.y = tar_position.y + zone->random.Real(-input.distance_max, input.distance_max); + best_z = GetFixedZ(temp_goal); if (best_z != BEST_Z_INVALID) { - temp_z = best_z; + temp_goal.z = best_z; } else { counter++; + continue; } - temp_m_Position.x = temp_x; - temp_m_Position.y = temp_y; - temp_m_Position.z = temp_z; + tar_distance = Distance(input.tar->GetPosition(), temp_goal); - tar_distance = Distance(target->GetPosition(), temp_m_Position); - - if (tar_distance > max_distance || tar_distance < min_distance) { + if (tar_distance > input.distance_max || tar_distance < std::max(input.distance_min, (input.distance_max * 0.75f))) { counter++; + continue; } - if (front_only && !InFrontMob(target, temp_x, temp_y)) { + if (input.front_only && !InFrontMob(input.tar, temp_goal.x, temp_goal.y)) { counter++; + continue; } - else if (behind_only && !BehindMob(target, temp_x, temp_y)) { + else if (input.behind_only && !BehindMob(input.tar, temp_goal.x, temp_goal.y)) { counter++; + continue; } - if (!bypass_los && CastToBot()->RequiresLoSForPositioning() && !CheckPositioningLosFN(target, temp_x, temp_y, temp_z)) { + if (!input.bypass_los && CastToBot()->RequiresLoSForPositioning() && !CheckPositioningLosFN(input.tar, temp_goal.x, temp_goal.y, temp_goal.z)) { counter++; + continue; } @@ -12161,9 +12117,7 @@ bool Bot::PlotBotPositionAroundTarget(Mob* target, float& x_dest, float& y_dest, } if (Result) { - x_dest = temp_x; - y_dest = temp_y; - z_dest = temp_z; + RunToGoalWithJitter(temp_goal); } } diff --git a/zone/bot.h b/zone/bot.h index 2503006c0..5e9b8e193 100644 --- a/zone/bot.h +++ b/zone/bot.h @@ -39,9 +39,6 @@ constexpr uint32 BOT_KEEP_ALIVE_INTERVAL = 5000; // 5 seconds -constexpr uint32 BOT_COMBAT_JITTER_INTERVAL_MIN = 1500; // 1.5 seconds -constexpr uint32 BOT_COMBAT_JITTER_INTERVAL_MAX = 3000; // 3 seconds - constexpr uint32 MAG_EPIC_1_0 = 28034; extern WorldServer worldserver; @@ -232,21 +229,6 @@ static std::map botSubType_names = { { CommandedSubTypes::Selo, "Selo" } }; -struct CombatRangeInput { - Mob* target; - float target_distance; - bool stop_melee_level; - const EQ::ItemInstance* p_item; - const EQ::ItemInstance* s_item; -}; - -struct CombatRangeOutput { - bool at_combat_range = false; - float melee_distance_min = 0.0f; - float melee_distance = 0.0f; - float melee_distance_max = 0.0f; -}; - class Bot : public NPC { friend class Mob; public: @@ -577,7 +559,7 @@ public: uint16 GetPetBotSpellType(uint16 spell_type); // Movement checks - bool PlotBotPositionAroundTarget(Mob* target, float& x_dest, float& y_dest, float& z_dest, float min_distance, float max_distance, bool behind_only = false, bool front_only = false, bool bypass_los = false); + bool PlotBotPositionAroundTarget(const FindPositionInput& input); std::vector GetSpellTargetList(bool entire_raid = false); void SetSpellTargetList(std::vector spell_target_list) { _spell_target_list = spell_target_list; } std::vector GetGroupSpellTargetList() { return _group_spell_target_list; } @@ -1102,15 +1084,8 @@ public: bool CheckIfCasting(float fm_distance); void HealRotationChecks(); - bool GetCombatJitterFlag() { return m_combat_jitter_flag; } - void SetCombatJitterFlag(bool flag = true) { m_combat_jitter_flag = flag; } - bool GetCombatOutOfRangeJitterFlag() { return m_combat_out_of_range_jitter_flag; } - void SetCombatOutOfRangeJitterFlag(bool flag = true) { m_combat_out_of_range_jitter_flag = flag; } void SetCombatJitter(); - void SetCombatOutOfRangeJitter(); - void DoCombatPositioning(Mob* tar, glm::vec3 Goal, bool stop_melee_level, float tar_distance, float melee_distance_min, float melee_distance, float melee_distance_max, bool behind_mob, bool front_mob); - void DoFaceCheckWithJitter(Mob* tar); - void DoFaceCheckNoJitter(Mob* tar); + bool DoCombatPositioning(const CombatPositioningInput& input); void RunToGoalWithJitter(glm::vec3 Goal); bool RequiresLoSForPositioning(); bool HasRequiredLoSForPositioning(Mob* tar); @@ -1118,12 +1093,12 @@ public: // Try Combat Methods bool TryEvade(Mob* tar); bool TryFacingTarget(Mob* tar); - bool TryPursueTarget(float leash_distance, glm::vec3& Goal); + bool TryPursueTarget(float leash_distance); bool TryMeditate(); bool TryAutoDefend(Client* bot_owner, float leash_distance); bool TryIdleChecks(float fm_distance); - 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 TryNonCombatMovementChecks(Client* bot_owner, const Mob* follow_mob); + void DoOutOfCombatChecks(Client* bot_owner, Mob* follow_mob, float leash_distance, float fm_distance); bool TryBardMovementCasts(); bool BotRangedAttack(Mob* other, bool can_double_attack = false); bool CheckDoubleRangedAttack(); @@ -1189,8 +1164,6 @@ private: Timer m_auto_save_timer; Timer m_combat_jitter_timer; - bool m_combat_jitter_flag; - bool m_combat_out_of_range_jitter_flag; bool m_dirtyautohaters; bool m_guard_flag; diff --git a/zone/bot_structs.h b/zone/bot_structs.h index baa1aa73c..aaf226057 100644 --- a/zone/bot_structs.h +++ b/zone/bot_structs.h @@ -21,6 +21,7 @@ #include "../common/types.h" #include "../common/timer.h" +#include "mob.h" #include @@ -151,4 +152,39 @@ struct BotSpellTypesByClass { std::string description; }; +struct CombatRangeInput { + Mob* target; + float target_distance; + bool stop_melee_level; + const EQ::ItemInstance* p_item; + const EQ::ItemInstance* s_item; +}; + +struct CombatRangeOutput { + bool at_combat_range = false; + float melee_distance_min = 0.0f; + float melee_distance = 0.0f; + float melee_distance_max = 0.0f; +}; + +struct CombatPositioningInput { + Mob* tar; + bool stop_melee_level; + float tar_distance; + float melee_distance_min; + float melee_distance; + float melee_distance_max; + bool behind_mob; + bool front_mob; +}; + +struct FindPositionInput { + Mob* tar; + float distance_min; + float distance_max; + bool behind_only; + bool front_only; + bool bypass_los; +}; + #endif // BOT_STRUCTS diff --git a/zone/mob.cpp b/zone/mob.cpp index cb4171b38..b411197e6 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -1698,13 +1698,6 @@ void Mob::StopMoving() void Mob::StopMoving(float new_heading) { - if (IsBot()) { - auto bot = CastToBot(); - - bot->SetCombatJitterFlag(false); - bot->SetCombatOutOfRangeJitterFlag(false); - } - StopNavigation(); RotateTo(new_heading);