mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 21:01:29 +00:00
[Bots] Fix taunting bots positioning (#4754)
* [Bots] Fix taunting bots positioning - Fixes taunting bots liking to hug their target on certain models or chosen positions. - Makes bots have a more realistic combat range in comparison to players. - Removed unnecessary rules and checks for melee distance. * Update ruletypes.h
This commit is contained in:
parent
1d4ba082ad
commit
d6a21be25e
@ -850,17 +850,15 @@ 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_BOOL(Bots, UseFlatNormalMeleeRange, false, "False Default. If true, bots melee distance will be a flat distance set by Bots:NormalMeleeRangeDistance.")
|
||||
RULE_REAL(Bots, NormalMeleeRangeDistance, 0.75, "If UseFlatNormalMeleeRange is enabled, multiplier of the max melee range at which a bot will stand in melee combat. 0.75 Recommended, max melee for all abilities to land.")
|
||||
RULE_REAL(Bots, PercentMinMeleeDistance, 0.75, "Multiplier of the their melee range - Minimum distance from target a bot will stand while in melee combat before trying to adjust. 0.60 Recommended.")
|
||||
RULE_REAL(Bots, MaxDistanceForMelee, 20, "Maximum distance bots will stand for melee. Default 20 to allow all special attacks to land.")
|
||||
RULE_REAL(Bots, TauntNormalMeleeRangeDistance, 0.50, "Multiplier of the max melee range at which a taunting bot will stand in melee combat. 0.50 Recommended, closer than others .")
|
||||
RULE_REAL(Bots, PercentTauntMinMeleeDistance, 0.40, "Multiplier of their melee range - Minimum distance from target a taunting bot will stand while in melee combat before trying to adjust. 0.25 Recommended.")
|
||||
RULE_REAL(Bots, PercentMaxMeleeRangeDistance, 0.95, "Multiplier of the max melee range at which a bot will stand in melee combat. 0.95 Recommended, max melee while disabling special attacks/taunt.")
|
||||
RULE_REAL(Bots, PercentMinMaxMeleeRangeDistance, 0.75, "Multiplier of the closest max melee range at which a bot will stand in melee combat before trying to adjust. 0.75 Recommended, max melee while disabling special attacks/taunt.")
|
||||
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_BOOL(Bots, TauntingBotsFollowTopHate, true, "True Default. If true, bots that are taunting will attempt to stick with whoever currently is top hate.")
|
||||
RULE_INT(Bots, DistanceTauntingBotsStickMainHate, 10, "If TauntingBotsFollowTopHate is enabled, this is the distance bots will try to stick to whoever currently is Top Hate.")
|
||||
RULE_BOOL(Bots, DisableSpecialAbilitiesAtMaxMelee, true, "True Default. If true, when bots are at max melee distance, special abilities including taunt will be disabled.")
|
||||
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.")
|
||||
RULE_BOOL(Bots, PreventBotCampOnFD, true, "True Default. If true, players will not be able to camp bots while feign death.")
|
||||
|
||||
207
zone/bot.cpp
207
zone/bot.cpp
@ -2256,7 +2256,7 @@ void Bot::AI_Process()
|
||||
SetAttackingFlag(false);
|
||||
}
|
||||
|
||||
float tar_distance = DistanceSquared(m_Position, tar->GetPosition());
|
||||
float tar_distance = DistanceSquaredNoZ(m_Position, tar->GetPosition());
|
||||
|
||||
// TARGET VALIDATION
|
||||
if (!IsValidTarget(bot_owner, leash_owner, lo_distance, leash_distance, tar, tar_distance)) {
|
||||
@ -2296,7 +2296,6 @@ void Bot::AI_Process()
|
||||
CombatRangeInput input = {
|
||||
.target = tar,
|
||||
.target_distance = tar_distance,
|
||||
.behind_mob = behind_mob,
|
||||
.stop_melee_level = stop_melee_level,
|
||||
.p_item = p_item,
|
||||
.s_item = s_item
|
||||
@ -2368,6 +2367,16 @@ void Bot::AI_Process()
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
HasTargetReflection() &&
|
||||
!IsTaunting() &&
|
||||
!tar->IsFleeing() &&
|
||||
!tar->IsFeared() &&
|
||||
TryEvade(tar)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// ENGAGED AT COMBAT RANGE
|
||||
|
||||
// We can fight
|
||||
@ -2434,7 +2443,11 @@ void Bot::AI_Process()
|
||||
ranged_timer.Start();
|
||||
}
|
||||
else if (!IsBotRanged() && GetLevel() < stop_melee_level) {
|
||||
if (!GetMaxMeleeRange() || !RuleB(Bots, DisableSpecialAbilitiesAtMaxMelee)) {
|
||||
if (
|
||||
IsTaunting() ||
|
||||
!GetMaxMeleeRange() ||
|
||||
!RuleB(Bots, DisableSpecialAbilitiesAtMaxMelee)
|
||||
) {
|
||||
DoClassAttacks(tar);
|
||||
}
|
||||
|
||||
@ -3065,7 +3078,7 @@ CombatRangeOutput Bot::EvaluateCombatRange(const CombatRangeInput& input) {
|
||||
|
||||
// For races with a fixed size
|
||||
if (GetRace() == Race::LavaDragon || GetRace() == Race::Wurm || GetRace() == Race::GhostDragon) {
|
||||
// size_mod = 60.0f;
|
||||
size_mod = 60.0f;
|
||||
}
|
||||
else if (size_mod < 6.0f) {
|
||||
size_mod = 8.0f;
|
||||
@ -3110,91 +3123,39 @@ CombatRangeOutput Bot::EvaluateCombatRange(const CombatRangeInput& input) {
|
||||
size_mod = (size_mod / 7.0f);
|
||||
}
|
||||
|
||||
o.melee_distance_max = size_mod;
|
||||
o.melee_distance_max = sqrt(size_mod);
|
||||
|
||||
if (!RuleB(Bots, UseFlatNormalMeleeRange)) {
|
||||
bool is_two_hander = input.p_item && input.p_item->GetItem()->IsType2HWeapon();
|
||||
bool is_shield = input.s_item && input.s_item->GetItem()->IsTypeShield();
|
||||
bool is_backstab_weapon = input.p_item && input.p_item->GetItemBackstabDamage();
|
||||
bool is_stop_melee_level = GetLevel() >= input.stop_melee_level;
|
||||
|
||||
bool is_two_hander = input.p_item && input.p_item->GetItem()->IsType2HWeapon();
|
||||
bool is_shield = input.s_item && input.s_item->GetItem()->IsTypeShield();
|
||||
bool is_backstab_weapon = input.p_item && input.p_item->GetItemBackstabDamage();
|
||||
|
||||
switch (GetClass()) {
|
||||
case Class::Warrior:
|
||||
case Class::Paladin:
|
||||
case Class::ShadowKnight:
|
||||
o.melee_distance = (
|
||||
is_two_hander ? o.melee_distance_max * 0.45f
|
||||
: is_shield ? o.melee_distance_max * 0.35f
|
||||
: o.melee_distance_max * 0.40f
|
||||
);
|
||||
|
||||
break;
|
||||
case Class::Necromancer:
|
||||
case Class::Wizard:
|
||||
case Class::Magician:
|
||||
case Class::Enchanter:
|
||||
o.melee_distance = (
|
||||
is_two_hander ? o.melee_distance_max * 0.95f
|
||||
: o.melee_distance_max * 0.75f
|
||||
);
|
||||
|
||||
break;
|
||||
case Class::Rogue:
|
||||
o.melee_distance = (
|
||||
input.behind_mob && is_backstab_weapon
|
||||
? o.melee_distance_max * 0.35f
|
||||
: o.melee_distance_max * 0.50f
|
||||
);
|
||||
|
||||
break;
|
||||
default:
|
||||
o.melee_distance = (
|
||||
is_two_hander ? o.melee_distance_max * 0.70f
|
||||
: o.melee_distance_max * 0.50f
|
||||
);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
o.melee_distance = sqrt(o.melee_distance);
|
||||
o.melee_distance_max = sqrt(o.melee_distance_max);
|
||||
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);
|
||||
}
|
||||
else {
|
||||
o.melee_distance_max = sqrt(o.melee_distance_max);
|
||||
o.melee_distance = o.melee_distance_max * RuleR(Bots, NormalMeleeRangeDistance);
|
||||
else if (IsBotRanged()) { // Archers/Throwers
|
||||
float min_distance = RuleI(Combat, MinRangedAttackDist);
|
||||
float max_distance = GetBotRangedValue();
|
||||
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 = std::min(max_distance, desired_range);
|
||||
}
|
||||
else if (is_stop_melee_level) { // Casters
|
||||
float desired_range = GetBotDistanceRanged();
|
||||
|
||||
if (o.melee_distance > RuleR(Bots, MaxDistanceForMelee)) {
|
||||
o.melee_distance = RuleR(Bots, MaxDistanceForMelee);
|
||||
o.melee_distance_min = std::max(o.melee_distance_max, (desired_range / 2));
|
||||
o.melee_distance = std::max((o.melee_distance_max * 1.25f), desired_range);
|
||||
}
|
||||
|
||||
o.melee_distance_min = o.melee_distance * RuleR(Bots, PercentMinMeleeDistance);
|
||||
|
||||
if (IsTaunting()) {
|
||||
o.melee_distance_min = o.melee_distance * RuleR(Bots, PercentTauntMinMeleeDistance);
|
||||
o.melee_distance = o.melee_distance * RuleR(Bots, TauntNormalMeleeRangeDistance);
|
||||
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);
|
||||
}
|
||||
|
||||
bool is_stop_melee_level = GetLevel() >= input.stop_melee_level;
|
||||
|
||||
if (!IsTaunting() && !IsBotRanged() && !is_stop_melee_level && GetMaxMeleeRange()) {
|
||||
o.melee_distance_min = o.melee_distance_max * RuleR(Bots, PercentMinMaxMeleeRangeDistance);
|
||||
o.melee_distance = o.melee_distance_max * RuleR(Bots, PercentMaxMeleeRangeDistance);
|
||||
}
|
||||
|
||||
if (is_stop_melee_level && !IsBotRanged()) {
|
||||
float desired_range = GetBotDistanceRanged();
|
||||
o.melee_distance_min = std::max(o.melee_distance, (desired_range / 2));
|
||||
o.melee_distance = std::max((o.melee_distance + 1), desired_range);
|
||||
}
|
||||
|
||||
if (IsBotRanged()) {
|
||||
float min_distance = RuleI(Combat, MinRangedAttackDist);
|
||||
float max_distance = GetBotRangedValue();
|
||||
float desired_range = GetBotDistanceRanged();
|
||||
max_distance = (max_distance == 0 ? desired_range : max_distance); // stay ranged if set to ranged even if items/ammo aren't correct
|
||||
o.melee_distance_min = std::max(min_distance, (desired_range / 2));
|
||||
o.melee_distance = std::min(max_distance, desired_range);
|
||||
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.at_combat_range = (input.target_distance <= o.melee_distance);
|
||||
@ -11846,21 +11807,19 @@ void Bot::DoCombatPositioning(
|
||||
bool front_mob
|
||||
) {
|
||||
if (HasTargetReflection()) {
|
||||
if (!IsTaunting() && !tar->IsFeared() && !tar->IsStunned()) {
|
||||
if (TryEvade(tar)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (tar->IsRooted() && !IsTaunting()) { // Move non-taunters out of range - Above already checks if bot is targeted, otherwise they would stay
|
||||
if (tar->IsRooted() && !IsTaunting()) { // Move non-taunters out of range
|
||||
if (tar_distance <= melee_distance_max) {
|
||||
if (PlotBotPositionAroundTarget(tar, Goal.x, Goal.y, Goal.z, (melee_distance_max + 1), (melee_distance_max * 2), GetBehindMob(), false)) {
|
||||
if (PlotBotPositionAroundTarget(tar, Goal.x, Goal.y, Goal.z, (melee_distance_max + 1), (melee_distance_max * 1.25f), GetBehindMob(), false)) {
|
||||
RunToGoalWithJitter(Goal);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (tar_distance < melee_distance_min || (!front_mob && IsTaunting())) { // Back up any bots that are too close
|
||||
else if (
|
||||
tar_distance < melee_distance_min ||
|
||||
(!front_mob && IsTaunting())
|
||||
) { // Back up any bots that are too close or if they're taunting and not in front of the mob
|
||||
if (PlotBotPositionAroundTarget(tar, Goal.x, Goal.y, Goal.z, melee_distance_min, melee_distance, GetBehindMob(), (IsTaunting() || !GetBehindMob()))) {
|
||||
RunToGoalWithJitter(Goal);
|
||||
|
||||
@ -11870,46 +11829,58 @@ void Bot::DoCombatPositioning(
|
||||
}
|
||||
else {
|
||||
if (!tar->IsFeared()) {
|
||||
if (IsTaunting()) { // Taunting adjustments
|
||||
Mob* mob_tar = tar->GetTarget();
|
||||
|
||||
if (!mob_tar) {
|
||||
DoFaceCheckNoJitter(tar);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (RuleB(Bots, TauntingBotsFollowTopHate)) { // If enabled, taunting bots will stick to top hate
|
||||
if (Distance(m_Position, mob_tar->GetPosition()) > RuleI(Bots, DistanceTauntingBotsStickMainHate)) {
|
||||
Goal = mob_tar->GetPosition();
|
||||
RunToGoalWithJitter(Goal);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
else { // Otherwise, stick to any other bots that are taunting
|
||||
if (mob_tar->IsBot() && mob_tar->CastToBot()->IsTaunting() && (Distance(m_Position, mob_tar->GetPosition()) > RuleI(Bots, DistanceTauntingBotsStickMainHate))) {
|
||||
Goal = mob_tar->GetPosition();
|
||||
RunToGoalWithJitter(Goal);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (tar_distance < melee_distance_min || (GetBehindMob() && !behind_mob) || (IsTaunting() && !front_mob) || !HasRequiredLoSForPositioning(tar)) { // Regular adjustment
|
||||
if (
|
||||
tar_distance < melee_distance_min ||
|
||||
(GetBehindMob() && !behind_mob) ||
|
||||
(IsTaunting() && !front_mob) ||
|
||||
!HasRequiredLoSForPositioning(tar)
|
||||
) { // Regular adjustment
|
||||
if (PlotBotPositionAroundTarget(tar, Goal.x, Goal.y, Goal.z, melee_distance_min, melee_distance, GetBehindMob(), (IsTaunting() || !GetBehindMob()))) {
|
||||
RunToGoalWithJitter(Goal);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (tar->IsEnraged() && !IsTaunting() && !stop_melee_level && !behind_mob) { // Move non-taunting melee bots behind target during enrage
|
||||
else if (
|
||||
tar->IsEnraged() &&
|
||||
!IsTaunting() &&
|
||||
!stop_melee_level &&
|
||||
!behind_mob
|
||||
) { // Move non-taunting melee bots behind target during enrage
|
||||
if (PlotBotPositionAroundTarget(tar, Goal.x, Goal.y, Goal.z, melee_distance_min, melee_distance, true)) {
|
||||
RunToGoalWithJitter(Goal);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (IsTaunting()) { // Taunting adjustments
|
||||
Mob* mob_tar = tar->GetTarget();
|
||||
|
||||
if (mob_tar) {
|
||||
if (
|
||||
RuleB(Bots, TauntingBotsFollowTopHate) &&
|
||||
(Distance(m_Position, mob_tar->GetPosition()) > RuleI(Bots, DistanceTauntingBotsStickMainHate))
|
||||
) { // If enabled, taunting bots will stick to top hate
|
||||
Goal = mob_tar->GetPosition();
|
||||
RunToGoalWithJitter(Goal);
|
||||
|
||||
return;
|
||||
}
|
||||
else { // Otherwise, stick to any other bots that are taunting
|
||||
if (
|
||||
mob_tar->IsBot() &&
|
||||
mob_tar->CastToBot()->IsTaunting() &&
|
||||
(Distance(m_Position, mob_tar->GetPosition()) > RuleI(Bots, DistanceTauntingBotsStickMainHate))
|
||||
) {
|
||||
Goal = mob_tar->GetPosition();
|
||||
RunToGoalWithJitter(Goal);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -235,7 +235,6 @@ static std::map<uint16, std::string> botSubType_names = {
|
||||
struct CombatRangeInput {
|
||||
Mob* target;
|
||||
float target_distance;
|
||||
bool behind_mob;
|
||||
uint8 stop_melee_level;
|
||||
const EQ::ItemInstance* p_item;
|
||||
const EQ::ItemInstance* s_item;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user