From ee0821f5c471494f7e80efe767f13bedd992c2a1 Mon Sep 17 00:00:00 2001 From: Your Name <50133316+NoxMax@users.noreply.github.com> Date: Thu, 6 Nov 2025 16:04:58 -0700 Subject: [PATCH 1/3] Allow PVP prohibition near flight masters and inbkeepers. Fix some pet PVP prohibition --- conf/playerbots.conf.dist | 10 +- src/PlayerbotAIConfig.cpp | 52 ++++++- src/PlayerbotAIConfig.h | 5 +- src/RandomPlayerbotMgr.cpp | 7 +- src/RandomPlayerbotMgr.h | 2 + src/strategy/actions/AttackAction.cpp | 33 ++++- src/strategy/actions/ChooseTargetActions.cpp | 6 +- src/strategy/actions/GenericActions.cpp | 4 +- src/strategy/actions/PetsAction.cpp | 6 + src/strategy/values/AttackersValue.cpp | 137 +++++++++++++------ src/strategy/values/EnemyPlayerValue.cpp | 2 +- 11 files changed, 206 insertions(+), 58 deletions(-) diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index c38df8f09e..f0779f7d30 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -630,7 +630,7 @@ AiPlayerbot.RandomBotHordeRatio = 50 AiPlayerbot.DisableDeathKnightLogin = 0 # Enable simulated expansion limitation for talents and glyphs -# If enabled, limits talent trees to 5 rows plus the middle talent of the 6th row for bots until level 61 +# If enabled, limits talent trees to 5 rows plus the middle talent of the 6th row for bots until level 61 # and 7 rows plus the middle talent of the 8th row for bots from level 61 until level 71 # Default: 0 (disabled) AiPlayerbot.LimitTalentsExpansion = 0 @@ -1187,6 +1187,14 @@ AiPlayerbot.PvpProhibitedZoneIds = "2255,656,2361,2362,2363,976,35,2268,3425,392 # PvP Restricted Areas (bots don't pvp) AiPlayerbot.PvpProhibitedAreaIds = "976,35,392,2268,4161,4010,4317,4312,3649,3887,3958,3724,4080,3938,3754" +# PvP restricted distance from innkeepers (in yards) +# Default: 0 (disabled) +AiPlayerbot.PvpProhibitedInnkeeperDistance = 0 + +# PvP restricted distance from flight masters (in yards) +# Default: 0 (disabled) +AiPlayerbot.PvpProhibitedFlightMasterDistance = 0 + # Improve reaction speeds in battlegrounds and arenas (may cause lag) AiPlayerbot.FastReactInBG = 1 diff --git a/src/PlayerbotAIConfig.cpp b/src/PlayerbotAIConfig.cpp index 42ab801fb5..e6bc1baf7d 100644 --- a/src/PlayerbotAIConfig.cpp +++ b/src/PlayerbotAIConfig.cpp @@ -167,6 +167,8 @@ bool PlayerbotAIConfig::Initialize() sConfigMgr->GetOption("AiPlayerbot.PvpProhibitedAreaIds", "976,35,392,2268,4161,4010,4317,4312,3649,3887,3958,3724,4080,3938,3754"), pvpProhibitedAreaIds); + pvpProhibitedFlightMasterDistance = sConfigMgr->GetOption("AiPlayerbot.PvpProhibitedFlightMasterDistance", 0.0f); + pvpProhibitedInnkeeperDistance = sConfigMgr->GetOption("AiPlayerbot.PvpProhibitedInnkeeperDistance", 0.0f); fastReactInBG = sConfigMgr->GetOption("AiPlayerbot.FastReactInBG", true); LoadList>( sConfigMgr->GetOption("AiPlayerbot.RandomBotQuestIds", "3802,5505,6502,7761,7848,10277,10285,11492,13188,13189,24499,24511,24710,24712"), @@ -694,9 +696,15 @@ bool PlayerbotAIConfig::IsInRandomQuestItemList(uint32 id) return find(randomBotQuestItems.begin(), randomBotQuestItems.end(), id) != randomBotQuestItems.end(); } -bool PlayerbotAIConfig::IsPvpProhibited(uint32 zoneId, uint32 areaId) +bool PlayerbotAIConfig::IsPvpProhibited(uint32 zoneId, uint32 areaId, Player* player) { - return IsInPvpProhibitedZone(zoneId) || IsInPvpProhibitedArea(areaId) || IsInPvpProhibitedZone(areaId); + if (IsInPvpProhibitedZone(zoneId) || IsInPvpProhibitedArea(areaId) || IsInPvpProhibitedZone(areaId)) + return true; + + if (player && IsNearProtectedNPC(player)) + return true; + + return false; } bool PlayerbotAIConfig::IsInPvpProhibitedZone(uint32 id) @@ -709,6 +717,46 @@ bool PlayerbotAIConfig::IsInPvpProhibitedArea(uint32 id) return find(pvpProhibitedAreaIds.begin(), pvpProhibitedAreaIds.end(), id) != pvpProhibitedAreaIds.end(); } +bool PlayerbotAIConfig::IsNearProtectedNPC(Player* player) +{ + if (!player) + return false; + + if (pvpProhibitedInnkeeperDistance <= 0.0f && pvpProhibitedFlightMasterDistance <= 0.0f) + return false; + + WorldPosition botPos(player); + uint32 mapId = player->GetMapId(); + + if (pvpProhibitedFlightMasterDistance > 0.0f) + { + auto it = sRandomPlayerbotMgr->flightMastersByMap.find(mapId); + if (it != sRandomPlayerbotMgr->flightMastersByMap.end()) + { + for (const WorldPosition& fmPos : it->second) + { + if (botPos.distance(fmPos) <= pvpProhibitedFlightMasterDistance) + return true; + } + } + } + + if (pvpProhibitedInnkeeperDistance > 0.0f) + { + auto it = sRandomPlayerbotMgr->innkeepersByMap.find(mapId); + if (it != sRandomPlayerbotMgr->innkeepersByMap.end()) + { + for (const WorldPosition& innkeeperPos : it->second) + { + if (botPos.distance(innkeeperPos) <= pvpProhibitedInnkeeperDistance) + return true; + } + } + } + + return false; +} + bool PlayerbotAIConfig::IsRestrictedHealerDPSMap(uint32 mapId) const { return restrictHealerDPS && diff --git a/src/PlayerbotAIConfig.h b/src/PlayerbotAIConfig.h index 391b991a21..01ad4b48e1 100644 --- a/src/PlayerbotAIConfig.h +++ b/src/PlayerbotAIConfig.h @@ -72,9 +72,10 @@ class PlayerbotAIConfig bool Initialize(); bool IsInRandomAccountList(uint32 id); bool IsInRandomQuestItemList(uint32 id); - bool IsPvpProhibited(uint32 zoneId, uint32 areaId); + bool IsPvpProhibited(uint32 zoneId, uint32 areaId, Player* player = nullptr); bool IsInPvpProhibitedZone(uint32 id); bool IsInPvpProhibitedArea(uint32 id); + bool IsNearProtectedNPC(Player* player); bool enabled; bool disabledWithoutRealPlayer; @@ -272,6 +273,8 @@ class PlayerbotAIConfig std::vector randomBotGuilds; std::vector pvpProhibitedZoneIds; std::vector pvpProhibitedAreaIds; + float pvpProhibitedFlightMasterDistance; + float pvpProhibitedInnkeeperDistance; bool fastReactInBG; bool randombotsWalkingRPG; diff --git a/src/RandomPlayerbotMgr.cpp b/src/RandomPlayerbotMgr.cpp index 12713cbb34..05f4c8eff8 100644 --- a/src/RandomPlayerbotMgr.cpp +++ b/src/RandomPlayerbotMgr.cpp @@ -1576,7 +1576,7 @@ bool RandomPlayerbotMgr::ProcessBot(Player* bot) { idleBot = true; } - + if (idleBot) { // randomize @@ -2008,6 +2008,11 @@ void RandomPlayerbotMgr::PrepareTeleportCache() { allianceFlightMasterCache.push_back(guid); } + flightMastersByMap[mapId].push_back(WorldPosition(mapId, x, y, z)); + } + if (tNpcflag & UNIT_NPC_FLAG_INNKEEPER) + { + innkeepersByMap[mapId].push_back(WorldPosition(mapId, x, y, z)); } const AreaTableEntry* area = sAreaTableStore.LookupEntry(map->GetAreaId(PHASEMASK_NORMAL, x, y, z)); uint32 zoneId = area->zone ? area->zone : area->ID; diff --git a/src/RandomPlayerbotMgr.h b/src/RandomPlayerbotMgr.h index be624328d6..352e3acda7 100644 --- a/src/RandomPlayerbotMgr.h +++ b/src/RandomPlayerbotMgr.h @@ -177,6 +177,8 @@ class RandomPlayerbotMgr : public PlayerbotHolder std::map> hordeStarterPerLevelCache; std::vector allianceFlightMasterCache; std::vector hordeFlightMasterCache; + std::unordered_map> flightMastersByMap; + std::unordered_map> innkeepersByMap; struct LevelBracket { uint32 low; uint32 high; diff --git a/src/strategy/actions/AttackAction.cpp b/src/strategy/actions/AttackAction.cpp index 94c9541830..6e8ed60712 100644 --- a/src/strategy/actions/AttackAction.cpp +++ b/src/strategy/actions/AttackAction.cpp @@ -84,16 +84,43 @@ bool AttackAction::Attack(Unit* target, bool with_pet /*true*/) return false; } - if ((sPlayerbotAIConfig->IsInPvpProhibitedZone(bot->GetZoneId()) || - sPlayerbotAIConfig->IsInPvpProhibitedArea(bot->GetAreaId())) + // Check if bot is in prohibited area + if (sPlayerbotAIConfig->IsPvpProhibited(bot->GetZoneId(), bot->GetAreaId(), bot) && (target->IsPlayer() || target->IsPet())) { if (verbose) botAI->TellError("I cannot attack other players in PvP prohibited areas."); - return false; } + // Check if target is in prohibited area + if (target->IsPlayer() || target->IsPet()) + { + Player* targetPlayer = nullptr; + + if (target->IsPlayer()) + { + targetPlayer = target->ToPlayer(); + } + else if (target->IsPet()) + { + Pet* pet = target->ToPet(); + if (pet) + { + Unit* owner = pet->GetOwner(); + if (owner && owner->IsPlayer()) + targetPlayer = owner->ToPlayer(); + } + } + + if (targetPlayer && sPlayerbotAIConfig->IsPvpProhibited(target->GetZoneId(), target->GetAreaId(), targetPlayer)) + { + if (verbose) + botAI->TellError("I cannot attack players who are in PvP prohibited areas."); + return false; + } + } + if (bot->IsFriendlyTo(target)) { if (verbose) diff --git a/src/strategy/actions/ChooseTargetActions.cpp b/src/strategy/actions/ChooseTargetActions.cpp index f98360ff7d..dbf4badf58 100644 --- a/src/strategy/actions/ChooseTargetActions.cpp +++ b/src/strategy/actions/ChooseTargetActions.cpp @@ -19,7 +19,7 @@ bool AttackEnemyPlayerAction::isUseful() if (PlayerHasFlag::IsCapturingFlag(bot)) return false; - return !sPlayerbotAIConfig->IsPvpProhibited(bot->GetZoneId(), bot->GetAreaId()); + return !sPlayerbotAIConfig->IsPvpProhibited(bot->GetZoneId(), bot->GetAreaId(), bot); } bool AttackEnemyFlagCarrierAction::isUseful() @@ -60,7 +60,7 @@ bool AttackAnythingAction::isUseful() return true; } -bool DropTargetAction::Execute(Event event) +bool DropTargetAction::Execute(Event /*event*/) { Unit* target = context->GetValue("current target")->Get(); if (target && target->isDead()) @@ -138,7 +138,7 @@ bool DpsAssistAction::isUseful() return true; } -bool AttackRtiTargetAction::Execute(Event event) +bool AttackRtiTargetAction::Execute(Event /*event*/) { Unit* rtiTarget = AI_VALUE(Unit*, "rti target"); diff --git a/src/strategy/actions/GenericActions.cpp b/src/strategy/actions/GenericActions.cpp index 184b17715d..20aa2f3c30 100644 --- a/src/strategy/actions/GenericActions.cpp +++ b/src/strategy/actions/GenericActions.cpp @@ -54,7 +54,7 @@ bool MeleeAction::isUseful() return true; } -bool TogglePetSpellAutoCastAction::Execute(Event event) +bool TogglePetSpellAutoCastAction::Execute(Event /*event*/) { Pet* pet = bot->GetPet(); if (!pet) @@ -119,7 +119,7 @@ bool TogglePetSpellAutoCastAction::Execute(Event event) return toggled; } -bool PetAttackAction::Execute(Event event) +bool PetAttackAction::Execute(Event /*event*/) { Guardian* pet = bot->GetGuardianPet(); if (!pet) diff --git a/src/strategy/actions/PetsAction.cpp b/src/strategy/actions/PetsAction.cpp index 945a883672..8d78ba85ed 100644 --- a/src/strategy/actions/PetsAction.cpp +++ b/src/strategy/actions/PetsAction.cpp @@ -134,6 +134,12 @@ bool PetsAction::Execute(Event event) botAI->TellError("Target is not a valid attack target for the bot."); return false; } + if (sPlayerbotAIConfig->IsPvpProhibited(bot->GetZoneId(), bot->GetAreaId(), bot) + && (targetUnit->IsPlayer() || targetUnit->IsPet())) + { + botAI->TellError("I cannot command my pet to attack players in PvP prohibited areas."); + return false; + } bool didAttack = false; // For each controlled pet/guardian, command them to attack the selected target. diff --git a/src/strategy/values/AttackersValue.cpp b/src/strategy/values/AttackersValue.cpp index 745369a3b5..729aae6904 100644 --- a/src/strategy/values/AttackersValue.cpp +++ b/src/strategy/values/AttackersValue.cpp @@ -107,7 +107,6 @@ void AttackersValue::AddAttackersOf(Player* player, std::unordered_set& t { ThreatMgr* threatMgr = ref->GetSource(); Unit* attacker = threatMgr->GetOwner(); - Unit* victim = attacker->GetVictim(); if (player->IsValidAttackTarget(attacker) && player->GetDistance2d(attacker) < sPlayerbotAIConfig->sightDistance) @@ -142,57 +141,107 @@ bool AttackersValue::hasRealThreat(Unit* attacker) (attacker->GetThreatMgr().getCurrentVictim() || dynamic_cast(attacker)); } -bool AttackersValue::IsPossibleTarget(Unit* attacker, Player* bot, float range) +bool AttackersValue::IsPossibleTarget(Unit* attacker, Player* bot, float /*range*/) { - Creature* c = attacker->ToCreature(); - bool rti = false; - if (attacker && bot->GetGroup()) - rti = bot->GetGroup()->GetTargetIcon(7) == attacker->GetGUID(); - PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot); + if (!botAI) + return false; + + // Basic check + if (!attacker) + return false; + + // bool inCannon = botAI->IsInVehicle(false, true); + // bool enemy = botAI->GetAiObjectContext()->GetValue("enemy player target")->Get(); + + // Validity checks + if (!attacker->IsVisible() || !attacker->IsInWorld() || attacker->GetMapId() != bot->GetMapId()) + return false; - bool leaderHasThreat = false; - if (attacker && bot->GetGroup() && botAI->GetMaster()) - leaderHasThreat = attacker->GetThreatMgr().GetThreat(botAI->GetMaster()); + if (attacker->isDead() || attacker->HasSpiritOfRedemptionAura()) + return false; - bool isMemberBotGroup = false; - if (bot->GetGroup() && botAI->GetMaster()) + // Flag checks + if (attacker->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NON_ATTACKABLE_2)) + return false; + + if (attacker->HasUnitFlag(UNIT_FLAG_IMMUNE_TO_PC) || attacker->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE)) + return false; + + // Relationship checks + if (attacker->IsFriendlyTo(bot)) + return false; + + // Critter exception + if (attacker->GetCreatureType() == CREATURE_TYPE_CRITTER && !attacker->IsInCombat()) + return false; + + // Visibility check + if (!bot->CanSeeOrDetect(attacker)) + return false; + + // PvP prohibition checks + if ((attacker->GetGUID().IsPlayer() || attacker->GetGUID().IsPet()) && + (sPlayerbotAIConfig->IsPvpProhibited(attacker->GetZoneId(), attacker->GetAreaId(), bot) || + sPlayerbotAIConfig->IsPvpProhibited(bot->GetZoneId(), bot->GetAreaId(), bot))) { - PlayerbotAI* masterBotAI = GET_PLAYERBOT_AI(botAI->GetMaster()); - if (masterBotAI && !masterBotAI->IsRealPlayer()) - isMemberBotGroup = true; + // This will stop aggresive pets from starting an attack. + // This will stop currently attacking pets from continuing their attack. + // This will first require the bot to change from a combat strat. It will + // not be reached if the bot only switches targets, including NPC targets. + for (Unit::ControlSet::const_iterator itr = bot->m_Controlled.begin(); + itr != bot->m_Controlled.end(); ++itr) + { + Creature* creature = dynamic_cast(*itr); + if (creature && creature->GetVictim() == attacker) + { + creature->AttackStop(); + if (CharmInfo* charmInfo = creature->GetCharmInfo()) + charmInfo->SetIsCommandAttack(false); + } + } + + return false; } - // bool inCannon = botAI->IsInVehicle(false, true); - // bool enemy = botAI->GetAiObjectContext()->GetValue("enemy player target")->Get(); + // Unflagged player check + if (attacker->IsPlayer() && !attacker->IsPvP() && !attacker->IsFFAPvP() && + (!bot->duel || bot->duel->Opponent != attacker)) + return false; + + // Creature-specific checks + Creature* c = attacker->ToCreature(); + if (c) + { + if (c->IsInEvadeMode()) + return false; + + bool leaderHasThreat = false; + if (bot->GetGroup() && botAI->GetMaster()) + leaderHasThreat = attacker->GetThreatMgr().GetThreat(botAI->GetMaster()); + + bool isMemberBotGroup = false; + if (bot->GetGroup() && botAI->GetMaster()) + { + PlayerbotAI* masterBotAI = GET_PLAYERBOT_AI(botAI->GetMaster()); + if (masterBotAI && !masterBotAI->IsRealPlayer()) + isMemberBotGroup = true; + } + + bool canAttack = (!isMemberBotGroup && botAI->HasStrategy("attack tagged", BOT_STATE_NON_COMBAT)) || + leaderHasThreat || + (!c->hasLootRecipient() && + (!c->GetVictim() || + (c->GetVictim() && + ((!c->GetVictim()->IsPlayer() || bot->IsInSameGroupWith(c->GetVictim()->ToPlayer())) || + (botAI->GetMaster() && c->GetVictim() == botAI->GetMaster()))))) || + c->isTappedBy(bot); + + if (!canAttack) + return false; + } - return attacker && attacker->IsVisible() && attacker->IsInWorld() && attacker->GetMapId() == bot->GetMapId() && - !attacker->isDead() && - !attacker->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NON_ATTACKABLE_2) && - // (inCannon || !attacker->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE)) && - // attacker->CanSeeOrDetect(bot) && - // !(attacker->HasUnitState(UNIT_STATE_STUNNED) && botAI->HasAura("shackle undead", attacker)) && - // !((attacker->IsPolymorphed() || botAI->HasAura("sap", attacker) || /*attacker->IsCharmed() ||*/ - // attacker->isFeared()) && !rti) && - /*!sServerFacade->IsInRoots(attacker) &&*/ - !attacker->IsFriendlyTo(bot) && !attacker->HasSpiritOfRedemptionAura() && - // !(attacker->GetGUID().IsPet() && enemy) && - !(attacker->GetCreatureType() == CREATURE_TYPE_CRITTER && !attacker->IsInCombat()) && - !attacker->HasUnitFlag(UNIT_FLAG_IMMUNE_TO_PC) && !attacker->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE) && - bot->CanSeeOrDetect(attacker) && - !(sPlayerbotAIConfig->IsPvpProhibited(attacker->GetZoneId(), attacker->GetAreaId()) && - (attacker->GetGUID().IsPlayer() || attacker->GetGUID().IsPet())) && - !(attacker->IsPlayer() && !attacker->IsPvP() && !attacker->IsFFAPvP() && - (!bot->duel || bot->duel->Opponent != attacker)) && - (!c || - (!c->IsInEvadeMode() && - ((!isMemberBotGroup && botAI->HasStrategy("attack tagged", BOT_STATE_NON_COMBAT)) || leaderHasThreat || - (!c->hasLootRecipient() && - (!c->GetVictim() || - (c->GetVictim() && - ((!c->GetVictim()->IsPlayer() || bot->IsInSameGroupWith(c->GetVictim()->ToPlayer())) || - (botAI->GetMaster() && c->GetVictim() == botAI->GetMaster()))))) || - c->isTappedBy(bot)))); + return true; } bool AttackersValue::IsValidTarget(Unit* attacker, Player* bot) diff --git a/src/strategy/values/EnemyPlayerValue.cpp b/src/strategy/values/EnemyPlayerValue.cpp index 9c2a413042..e3db79ba32 100644 --- a/src/strategy/values/EnemyPlayerValue.cpp +++ b/src/strategy/values/EnemyPlayerValue.cpp @@ -14,7 +14,7 @@ bool NearestEnemyPlayersValue::AcceptUnit(Unit* unit) bool inCannon = botAI->IsInVehicle(false, true); Player* enemy = dynamic_cast(unit); if (enemy && botAI->IsOpposing(enemy) && enemy->IsPvP() && - !sPlayerbotAIConfig->IsPvpProhibited(enemy->GetZoneId(), enemy->GetAreaId()) && + !sPlayerbotAIConfig->IsPvpProhibited(enemy->GetZoneId(), enemy->GetAreaId(), enemy) && !enemy->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NON_ATTACKABLE_2) && ((inCannon || !enemy->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE))) && /*!enemy->HasStealthAura() && !enemy->HasInvisibilityAura()*/ enemy->CanSeeOrDetect(bot) && From 85768119b6408e26d337b472617eb4ba77f58318 Mon Sep 17 00:00:00 2001 From: NoxMax <50133316+NoxMax@users.noreply.github.com> Date: Tue, 9 Dec 2025 21:54:19 -0700 Subject: [PATCH 2/3] Merger cleanup for PVP prohibition near flight masters and inbkeepers --- src/RandomPlayerbotMgr.cpp | 3 +-- src/strategy/actions/AttackAction.cpp | 8 ++++---- src/strategy/actions/ChooseTargetActions.cpp | 4 ++-- src/strategy/actions/GenericActions.cpp | 4 ++-- src/strategy/actions/PetsAction.cpp | 10 ++-------- 5 files changed, 11 insertions(+), 18 deletions(-) diff --git a/src/RandomPlayerbotMgr.cpp b/src/RandomPlayerbotMgr.cpp index 222990ca20..d95a2b01ae 100644 --- a/src/RandomPlayerbotMgr.cpp +++ b/src/RandomPlayerbotMgr.cpp @@ -2010,9 +2010,8 @@ void RandomPlayerbotMgr::PrepareTeleportCache() flightMastersByMap[mapId].push_back(WorldPosition(mapId, x, y, z)); } if (tNpcflag & UNIT_NPC_FLAG_INNKEEPER) - { innkeepersByMap[mapId].push_back(WorldPosition(mapId, x, y, z)); - } + const AreaTableEntry* area = sAreaTableStore.LookupEntry(map->GetAreaId(PHASEMASK_NORMAL, x, y, z)); uint32 zoneId = area->zone ? area->zone : area->ID; if (zone2LevelBracket.find(zoneId) == zone2LevelBracket.end()) diff --git a/src/strategy/actions/AttackAction.cpp b/src/strategy/actions/AttackAction.cpp index df7a06ec4f..544f7da169 100644 --- a/src/strategy/actions/AttackAction.cpp +++ b/src/strategy/actions/AttackAction.cpp @@ -85,11 +85,12 @@ bool AttackAction::Attack(Unit* target, bool with_pet /*true*/) } // Check if bot is in prohibited area - if (sPlayerbotAIConfig->IsPvpProhibited(bot->GetZoneId(), bot->GetAreaId(), bot) - && (target->IsPlayer() || target->IsPet())) + if ((target->IsPlayer() || target->IsPet()) && + sPlayerbotAIConfig->IsPvpProhibited(bot->GetZoneId(), bot->GetAreaId(), bot)) { if (verbose) botAI->TellError("I cannot attack other players in PvP prohibited areas."); + return false; } @@ -99,9 +100,8 @@ bool AttackAction::Attack(Unit* target, bool with_pet /*true*/) Player* targetPlayer = nullptr; if (target->IsPlayer()) - { targetPlayer = target->ToPlayer(); - } + else if (target->IsPet()) { Pet* pet = target->ToPet(); diff --git a/src/strategy/actions/ChooseTargetActions.cpp b/src/strategy/actions/ChooseTargetActions.cpp index dbf4badf58..7206ef3e8a 100644 --- a/src/strategy/actions/ChooseTargetActions.cpp +++ b/src/strategy/actions/ChooseTargetActions.cpp @@ -60,7 +60,7 @@ bool AttackAnythingAction::isUseful() return true; } -bool DropTargetAction::Execute(Event /*event*/) +bool DropTargetAction::Execute(Event event) { Unit* target = context->GetValue("current target")->Get(); if (target && target->isDead()) @@ -138,7 +138,7 @@ bool DpsAssistAction::isUseful() return true; } -bool AttackRtiTargetAction::Execute(Event /*event*/) +bool AttackRtiTargetAction::Execute(Event event) { Unit* rtiTarget = AI_VALUE(Unit*, "rti target"); diff --git a/src/strategy/actions/GenericActions.cpp b/src/strategy/actions/GenericActions.cpp index 20aa2f3c30..184b17715d 100644 --- a/src/strategy/actions/GenericActions.cpp +++ b/src/strategy/actions/GenericActions.cpp @@ -54,7 +54,7 @@ bool MeleeAction::isUseful() return true; } -bool TogglePetSpellAutoCastAction::Execute(Event /*event*/) +bool TogglePetSpellAutoCastAction::Execute(Event event) { Pet* pet = bot->GetPet(); if (!pet) @@ -119,7 +119,7 @@ bool TogglePetSpellAutoCastAction::Execute(Event /*event*/) return toggled; } -bool PetAttackAction::Execute(Event /*event*/) +bool PetAttackAction::Execute(Event event) { Guardian* pet = bot->GetGuardianPet(); if (!pet) diff --git a/src/strategy/actions/PetsAction.cpp b/src/strategy/actions/PetsAction.cpp index 0785b5eabe..8af46fbf6b 100644 --- a/src/strategy/actions/PetsAction.cpp +++ b/src/strategy/actions/PetsAction.cpp @@ -156,20 +156,14 @@ 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(), bot) && + (targetUnit->IsPlayer() || targetUnit->IsPet())) { std::string text = sPlayerbotTextMgr->GetBotTextOrDefault( "pet_pvp_prohibited_error", "I cannot command my pet to attack players in PvP prohibited areas.", {}); botAI->TellError(text); return false; } - if (sPlayerbotAIConfig->IsPvpProhibited(bot->GetZoneId(), bot->GetAreaId(), bot) - && (targetUnit->IsPlayer() || targetUnit->IsPet())) - { - botAI->TellError("I cannot command my pet to attack players in PvP prohibited areas."); - return false; - } bool didAttack = false; // For each controlled pet/guardian, command them to attack the selected target. From 2b17253be26d6aa899707e96edbba01b34a95d06 Mon Sep 17 00:00:00 2001 From: NoxMax <50133316+NoxMax@users.noreply.github.com> Date: Tue, 16 Dec 2025 21:18:07 -0700 Subject: [PATCH 3/3] Duel check in prohibited areas cleanup --- src/strategy/actions/AttackAction.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/strategy/actions/AttackAction.cpp b/src/strategy/actions/AttackAction.cpp index 26943b3acd..e963d9bb61 100644 --- a/src/strategy/actions/AttackAction.cpp +++ b/src/strategy/actions/AttackAction.cpp @@ -84,8 +84,9 @@ bool AttackAction::Attack(Unit* target, bool /*with_pet*/ /*true*/) return false; } - // Check if bot is in prohibited area + // Check if bot 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(), bot)) { if (verbose) @@ -94,7 +95,7 @@ bool AttackAction::Attack(Unit* target, bool /*with_pet*/ /*true*/) return false; } - // Check if target is in prohibited area + // Check if target is in prohibited zone/area (skip for duels) if (target->IsPlayer() || target->IsPet()) { Player* targetPlayer = nullptr; @@ -113,7 +114,8 @@ bool AttackAction::Attack(Unit* target, bool /*with_pet*/ /*true*/) } } - if (targetPlayer && sPlayerbotAIConfig->IsPvpProhibited(target->GetZoneId(), target->GetAreaId(), targetPlayer)) + if (targetPlayer && (!bot->duel || bot->duel->Opponent != target) && + sPlayerbotAIConfig->IsPvpProhibited(target->GetZoneId(), target->GetAreaId(), targetPlayer)) { if (verbose) botAI->TellError("I cannot attack players who are in PvP prohibited areas.");