diff --git a/common/ruletypes.h b/common/ruletypes.h index 1a4a7ea67..cb4b41405 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -595,6 +595,8 @@ RULE_INT(Bots, CasterStopMeleeLevel, 13, "Level at which caster bots stop melee RULE_INT(Bots, AllowedClasses, 0xFFFFFFFF, "Bitmask of allowed bot classes") RULE_INT(Bots, AllowedRaces, 0xFFFFFFFF, "Bitmask of allowed bot races") RULE_INT(Bots, AllowedGenders, 0x3, "Bitmask of allowed bot genders") +RULE_BOOL(Bots, AllowOwnerAutoDefend, false, "When active, bots will defend their owner on enemy aggro") +RULE_REAL(Bots, LeashDistance, 562500.0f, "Distance a bot is allowed to travel from leash owner before being pulled back (squared value)") RULE_CATEGORY_END() #endif diff --git a/zone/bot.cpp b/zone/bot.cpp index bba29fb38..428472fac 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -2397,6 +2397,7 @@ void Bot::AI_Process() float fm_distance = DistanceSquared(m_Position, follow_mob->GetPosition()); float lo_distance = DistanceSquared(m_Position, leash_owner->GetPosition()); + float leash_distance = RuleR(Bots, LeashDistance); //#pragma region CURRENTLY CASTING CHECKS @@ -2551,8 +2552,8 @@ void Bot::AI_Process() lo_target->IsNPC() && !lo_target->IsMezzed() && ((bot_owner->GetBotOption(Client::booAutoDefend) && lo_target->GetHateAmount(leash_owner)) || leash_owner->AutoAttackEnabled()) && - lo_distance <= BOT_LEASH_DISTANCE && - DistanceSquared(m_Position, lo_target->GetPosition()) <= BOT_LEASH_DISTANCE && + lo_distance <= leash_distance && + DistanceSquared(m_Position, lo_target->GetPosition()) <= leash_distance && (CheckLosFN(lo_target) || leash_owner->CheckLosFN(lo_target)) && IsAttackAllowed(lo_target)) { @@ -2579,8 +2580,8 @@ void Bot::AI_Process() if (!bgm_target->IsMezzed() && ((bot_owner->GetBotOption(Client::booAutoDefend) && bgm_target->GetHateAmount(bg_member)) || leash_owner->AutoAttackEnabled()) && - lo_distance <= BOT_LEASH_DISTANCE && - DistanceSquared(m_Position, bgm_target->GetPosition()) <= BOT_LEASH_DISTANCE && + lo_distance <= leash_distance && + DistanceSquared(m_Position, bgm_target->GetPosition()) <= leash_distance && (CheckLosFN(bgm_target) || leash_owner->CheckLosFN(bgm_target)) && IsAttackAllowed(bgm_target)) { @@ -2715,7 +2716,7 @@ void Bot::AI_Process() else { // This will keep bots on target for now..but, future updates will allow for rooting/stunning - SetTarget(hate_list.GetEscapingEntOnHateList(leash_owner, BOT_LEASH_DISTANCE)); + SetTarget(hate_list.GetEscapingEntOnHateList(leash_owner, leash_distance)); if (!GetTarget()) { SetTarget(hate_list.GetEntWithMostHateOnList(this)); } @@ -2783,8 +2784,8 @@ void Bot::AI_Process() if (HOLDING || !tar->IsNPC() || tar->IsMezzed() || - lo_distance > BOT_LEASH_DISTANCE || - tar_distance > BOT_LEASH_DISTANCE || + lo_distance > leash_distance || + tar_distance > leash_distance || (!GetAttackingFlag() && !CheckLosFN(tar) && !leash_owner->CheckLosFN(tar)) || // This is suppose to keep bots from attacking things behind walls !IsAttackAllowed(tar) || (bo_alt_combat && @@ -3333,7 +3334,7 @@ void Bot::AI_Process() LogAI("Pursuing [{}] while engaged", GetTarget()->GetCleanName()); Goal = GetTarget()->GetPosition(); - if (DistanceSquared(m_Position, Goal) <= BOT_LEASH_DISTANCE) { + if (DistanceSquared(m_Position, Goal) <= leash_distance) { RunTo(Goal.x, Goal.y, Goal.z); } else { @@ -3401,35 +3402,38 @@ void Bot::AI_Process() // 'class Client' doesn't make use of hate_list... if (bot_owner->GetAggroCount() && bot_owner->GetBotOption(Client::booAutoDefend)) { - if (NOT_HOLDING && NOT_PASSIVE) { + if (RuleB(Bots, AllowOwnerAutoDefend)) { - auto xhaters = bot_owner->GetXTargetAutoMgr(); - if (xhaters && !xhaters->empty()) { + if (NOT_HOLDING && NOT_PASSIVE) { - for (auto hater_iter : xhaters->get_list()) { + auto xhaters = bot_owner->GetXTargetAutoMgr(); + if (xhaters && !xhaters->empty()) { - if (!hater_iter.spawn_id) { - continue; - } + for (auto hater_iter : xhaters->get_list()) { - if (bot_owner->GetBotPulling() && bot_owner->GetTarget() && hater_iter.spawn_id == bot_owner->GetTarget()->GetID()) { - continue; - } - - auto hater = entity_list.GetMob(hater_iter.spawn_id); - if (hater && DistanceSquared(hater->GetPosition(), bot_owner->GetPosition()) <= BOT_LEASH_DISTANCE) { - - // This is roughly equivilent to npc attacking a client pet owner - AddToHateList(hater, 1); - SetTarget(hater); - SetAttackingFlag(); - if (HasPet() && (GetClass() != ENCHANTER || GetPet()->GetPetType() != petAnimation || GetAA(aaAnimationEmpathy) >= 2)) { - - GetPet()->AddToHateList(hater, 1); - GetPet()->SetTarget(hater); + if (!hater_iter.spawn_id) { + continue; } - return; + if (bot_owner->GetBotPulling() && bot_owner->GetTarget() && hater_iter.spawn_id == bot_owner->GetTarget()->GetID()) { + continue; + } + + auto hater = entity_list.GetMob(hater_iter.spawn_id); + if (hater && 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 (HasPet() && (GetClass() != ENCHANTER || GetPet()->GetPetType() != petAnimation || GetAA(aaAnimationEmpathy) >= 2)) { + + GetPet()->AddToHateList(hater, 1); + GetPet()->SetTarget(hater); + } + + return; + } } } } diff --git a/zone/bot.h b/zone/bot.h index abc3e1dae..63195e23b 100644 --- a/zone/bot.h +++ b/zone/bot.h @@ -41,8 +41,6 @@ constexpr float BOT_FOLLOW_DISTANCE_DEFAULT = 184.0f; // as DSq value (~13.565 u constexpr float BOT_FOLLOW_DISTANCE_DEFAULT_MAX = 2500.0f; // as DSq value (50 units) constexpr float BOT_FOLLOW_DISTANCE_WALK = 1000.0f; // as DSq value (~31.623 units) -constexpr float BOT_LEASH_DISTANCE = 250000.0f; // as DSq value (500 units) - constexpr uint32 BOT_KEEP_ALIVE_INTERVAL = 5000; // 5 seconds //constexpr uint32 BOT_COMBAT_JITTER_INTERVAL_MIN = 5000; // 5 seconds diff --git a/zone/bot_command.cpp b/zone/bot_command.cpp index 7a1a7cac4..8ca5878ce 100644 --- a/zone/bot_command.cpp +++ b/zone/bot_command.cpp @@ -3769,19 +3769,25 @@ void bot_command_owner_option(Client *c, const Seperator *sep) } else if (!owner_option.compare("autodefend")) { - if (!argument.compare("enable")) { - c->SetBotOption(Client::booAutoDefend, true); - } - else if (!argument.compare("disable")) { - c->SetBotOption(Client::booAutoDefend, false); + if (RuleB(Bots, AllowOwnerAutoDefend)) { + + if (!argument.compare("enable")) { + c->SetBotOption(Client::booAutoDefend, true); + } + else if (!argument.compare("disable")) { + c->SetBotOption(Client::booAutoDefend, false); + } + else { + c->SetBotOption(Client::booAutoDefend, !c->GetBotOption(Client::booAutoDefend)); + } + + database.botdb.SaveOwnerOption(c->CharacterID(), Client::booAutoDefend, c->GetBotOption(Client::booAutoDefend)); + + c->Message(m_action, "Bot 'auto defend' is now %s.", (c->GetBotOption(Client::booAutoDefend) == true ? "enabled" : "disabled")); } else { - c->SetBotOption(Client::booAutoDefend, !c->GetBotOption(Client::booAutoDefend)); + c->Message(m_fail, "Bot owner option 'autodefend' is not allowed on this server."); } - - database.botdb.SaveOwnerOption(c->CharacterID(), Client::booAutoDefend, c->GetBotOption(Client::booAutoDefend)); - - c->Message(m_action, "Bot 'auto defend' is now %s.", (c->GetBotOption(Client::booAutoDefend) == true ? "enabled" : "disabled")); } else if (!owner_option.compare("current")) { diff --git a/zone/client.cpp b/zone/client.cpp index 251b23ad1..3c16b8a9b 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -353,7 +353,7 @@ Client::Client(EQStreamInterface* ieqs) bot_owner_options[booSpawnMessageTell] = true; bot_owner_options[booSpawnMessageClassSpecific] = true; bot_owner_options[booAltCombat] = false; - bot_owner_options[booAutoDefend] = true; + bot_owner_options[booAutoDefend] = RuleB(Bots, AllowOwnerAutoDefend); SetBotPulling(false); #endif