From 00cb177c86ecf375cff198e1f1f35f31cc8e2d4e Mon Sep 17 00:00:00 2001 From: NoxMax <50133316+NoxMax@users.noreply.github.com> Date: Tue, 16 Dec 2025 10:38:50 -0700 Subject: [PATCH] Fix: Allow bots to duel in PVP prohibited areas (#1906) Noticed that if you ask a bot to duel in a PVP prohibited area, it will accept, and do nothing. I thought about making the bot reject the request, but if you (the real player) want to duel with it, the duel should happen. This is just a minor fix to allow bots to duel if you ask them to in such areas. Tested with bots in party, random bots of the same faction, and random bots of the opposite faction. All behaved the same before and after fix. An example place to test is Zim'Torga in Zul'Drak which is by default is a PVP prohibited area. - Before fix, you challenge a bot, they accept and turn red, then they either just stay where they are or wander off. - After fix, bot attacks you within the PVP prohibited area when the duel starts. --- src/strategy/actions/AttackAction.cpp | 22 +++++++++++++--------- src/strategy/actions/PetsAction.cpp | 9 +++------ src/strategy/values/AttackersValue.cpp | 12 +++--------- 3 files changed, 19 insertions(+), 24 deletions(-) diff --git a/src/strategy/actions/AttackAction.cpp b/src/strategy/actions/AttackAction.cpp index 38cb9683..d72b18c5 100644 --- a/src/strategy/actions/AttackAction.cpp +++ b/src/strategy/actions/AttackAction.cpp @@ -15,20 +15,19 @@ #include "SharedDefines.h" #include "Unit.h" -bool AttackAction::Execute(Event event) +bool AttackAction::Execute(Event /*event*/) { Unit* target = GetTarget(); if (!target) return false; if (!target->IsInWorld()) - { return false; - } + return Attack(target); } -bool AttackMyTargetAction::Execute(Event event) +bool AttackMyTargetAction::Execute(Event /*event*/) { Player* master = GetMaster(); if (!master) @@ -51,7 +50,7 @@ bool AttackMyTargetAction::Execute(Event event) return result; } -bool AttackAction::Attack(Unit* target, bool with_pet /*true*/) +bool AttackAction::Attack(Unit* target, bool /*with_pet*/ /*true*/) { Unit* oldTarget = context->GetValue("current target")->Get(); bool shouldMelee = bot->IsWithinMeleeRange(target) || botAI->IsMelee(bot); @@ -81,11 +80,13 @@ bool AttackAction::Attack(Unit* target, bool with_pet /*true*/) { if (verbose) botAI->TellError(std::string(target->GetName()) + " is no longer in the world."); + return false; } - // Check if bot OR target is in prohibited zone/area + // Check if bot OR target is in prohibited zone/area (skip for duels) if ((target->IsPlayer() || target->IsPet()) && + (!bot->duel || bot->duel->Opponent != target) && (sPlayerbotAIConfig->IsPvpProhibited(bot->GetZoneId(), bot->GetAreaId()) || sPlayerbotAIConfig->IsPvpProhibited(target->GetZoneId(), target->GetAreaId()))) { @@ -99,6 +100,7 @@ bool AttackAction::Attack(Unit* target, bool with_pet /*true*/) { if (verbose) botAI->TellError(std::string(target->GetName()) + " is friendly to me."); + return false; } @@ -106,6 +108,7 @@ bool AttackAction::Attack(Unit* target, bool with_pet /*true*/) { if (verbose) botAI->TellError(std::string(target->GetName()) + " is dead."); + return false; } @@ -113,6 +116,7 @@ bool AttackAction::Attack(Unit* target, bool with_pet /*true*/) { if (verbose) botAI->TellError(std::string(target->GetName()) + " is not in my sight."); + return false; } @@ -120,6 +124,7 @@ bool AttackAction::Attack(Unit* target, bool with_pet /*true*/) { if (verbose) botAI->TellError("I am already attacking " + std::string(target->GetName()) + "."); + return false; } @@ -155,9 +160,8 @@ bool AttackAction::Attack(Unit* target, bool with_pet /*true*/) } if (IsMovingAllowed() && !bot->HasInArc(CAST_ANGLE_IN_FRONT, target)) - { sServerFacade->SetFacingTo(bot, target); - } + botAI->ChangeEngine(BOT_STATE_COMBAT); bot->Attack(target, shouldMelee); @@ -187,4 +191,4 @@ bool AttackAction::Attack(Unit* target, bool with_pet /*true*/) bool AttackDuelOpponentAction::isUseful() { return AI_VALUE(Unit*, "duel target"); } -bool AttackDuelOpponentAction::Execute(Event event) { return Attack(AI_VALUE(Unit*, "duel target")); } +bool AttackDuelOpponentAction::Execute(Event /*event*/) { return Attack(AI_VALUE(Unit*, "duel target")); } diff --git a/src/strategy/actions/PetsAction.cpp b/src/strategy/actions/PetsAction.cpp index 9e9e3172..cb9dc939 100644 --- a/src/strategy/actions/PetsAction.cpp +++ b/src/strategy/actions/PetsAction.cpp @@ -18,9 +18,7 @@ bool PetsAction::Execute(Event event) // Extract the command parameter from the event (e.g., "aggressive", "defensive", "attack", etc.) std::string param = event.getParam(); if (param.empty() && !defaultCmd.empty()) - { param = defaultCmd; - } if (param.empty()) { @@ -129,9 +127,7 @@ bool PetsAction::Execute(Event event) { ObjectGuid masterTargetGuid = master->GetTarget(); if (!masterTargetGuid.IsEmpty()) - { targetUnit = botAI->GetUnit(masterTargetGuid); - } } // If no valid target is selected, show an error and return. @@ -156,8 +152,9 @@ bool PetsAction::Execute(Event event) botAI->TellError(text); return false; } - if (sPlayerbotAIConfig->IsPvpProhibited(bot->GetZoneId(), bot->GetAreaId()) - && (targetUnit->IsPlayer() || targetUnit->IsPet())) + if (sPlayerbotAIConfig->IsPvpProhibited(bot->GetZoneId(), bot->GetAreaId()) && + (targetUnit->IsPlayer() || targetUnit->IsPet()) && + (!bot->duel || bot->duel->Opponent != targetUnit)) { std::string text = sPlayerbotTextMgr->GetBotTextOrDefault( "pet_pvp_prohibited_error", "I cannot command my pet to attack players in PvP prohibited areas.", {}); diff --git a/src/strategy/values/AttackersValue.cpp b/src/strategy/values/AttackersValue.cpp index d89f1f8d..3c968589 100644 --- a/src/strategy/values/AttackersValue.cpp +++ b/src/strategy/values/AttackersValue.cpp @@ -33,18 +33,14 @@ GuidVector AttackersValue::Calculate() { Unit* unit = botAI->GetUnit(target); if (unit && IsValidTarget(unit, bot)) - { targets.insert(unit); - } } if (Group* group = bot->GetGroup()) { ObjectGuid skullGuid = group->GetTargetIcon(7); Unit* skullTarget = botAI->GetUnit(skullGuid); if (skullTarget && IsValidTarget(skullTarget, bot)) - { targets.insert(skullTarget); - } } for (Unit* unit : targets) @@ -61,9 +57,7 @@ GuidVector AttackersValue::Calculate() { Unit* unit = botAI->GetUnit(guid); if (unit && unit->IsPlayer() && IsValidTarget(unit, bot)) - { result.push_back(unit->GetGUID()); - } } } @@ -110,9 +104,8 @@ void AttackersValue::AddAttackersOf(Player* player, std::unordered_set& t if (player->IsValidAttackTarget(attacker) && player->GetDistance2d(attacker) < sPlayerbotAIConfig->sightDistance) - { targets.insert(attacker); - } + ref = ref->next(); } } @@ -180,8 +173,9 @@ bool AttackersValue::IsPossibleTarget(Unit* attacker, Player* bot, float /*range if (!bot->CanSeeOrDetect(attacker)) return false; - // PvP prohibition checks + // PvP prohibition checks (skip for duels) if ((attacker->GetGUID().IsPlayer() || attacker->GetGUID().IsPet()) && + (!bot->duel || bot->duel->Opponent != attacker) && (sPlayerbotAIConfig->IsPvpProhibited(attacker->GetZoneId(), attacker->GetAreaId()) || sPlayerbotAIConfig->IsPvpProhibited(bot->GetZoneId(), bot->GetAreaId()))) {