From 500de1de10f4b3fd90b01e3231ba3da5dea6cb64 Mon Sep 17 00:00:00 2001 From: Fuzz Date: Wed, 10 Jul 2024 22:13:12 +1000 Subject: [PATCH 1/4] optionally disable bots using MotionMaster::MoveSplitPath() for BG/Arena or everywhere (so that stuns stun/snare/root/etc can work against bots) --- conf/playerbots.conf.dist | 7 +++++++ src/PlayerbotAIConfig.cpp | 1 + src/PlayerbotAIConfig.h | 4 ++-- src/strategy/actions/MovementActions.cpp | 4 +++- 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index 3a3c2736d..016e322ae 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -248,6 +248,13 @@ AiPlayerbot.GlobalCooldown = 500 # Max wait time when moving AiPlayerbot.MaxWaitForMove = 5000 +# Disables use of MoveSplinePath for bot movement, will result in more erratic bot movement but means stun/snare/root/etc +# will work on bots (they wont reliably work when MoveSplinePath is enabled, though slowing effects still work ok) +# Default: 0 - MoveSplinePath enabled +# 1 - MoveSplinePath disabled in BG/Arena only +# 2 - MoveSplinePath disabled everywhere +AiPlayerbot.DisableMoveSplinePath = 0 + # Max search time for movement (higher for better movement on slopes) # default: 3 AiPlayerbot.MaxMovementSearchTime = 3 diff --git a/src/PlayerbotAIConfig.cpp b/src/PlayerbotAIConfig.cpp index ed840e9c7..f09212240 100644 --- a/src/PlayerbotAIConfig.cpp +++ b/src/PlayerbotAIConfig.cpp @@ -53,6 +53,7 @@ bool PlayerbotAIConfig::Initialize() globalCoolDown = sConfigMgr->GetOption("AiPlayerbot.GlobalCooldown", 1500); maxWaitForMove = sConfigMgr->GetOption("AiPlayerbot.MaxWaitForMove", 5000); + disableMoveSplinePath = sConfigMgr->GetOption("AiPlayerbot.DisableMoveSplinePath", 0); maxMovementSearchTime = sConfigMgr->GetOption("AiPlayerbot.MaxMovementSearchTime", 3); expireActionTime = sConfigMgr->GetOption("AiPlayerbot.ExpireActionTime", 5000); dispelAuraDuration = sConfigMgr->GetOption("AiPlayerbot.DispelAuraDuration", 7000); diff --git a/src/PlayerbotAIConfig.h b/src/PlayerbotAIConfig.h index 40a660341..477f9c51f 100644 --- a/src/PlayerbotAIConfig.h +++ b/src/PlayerbotAIConfig.h @@ -54,8 +54,8 @@ class PlayerbotAIConfig bool enabled; bool allowGuildBots, allowPlayerBots; - uint32 globalCoolDown, reactDelay, maxWaitForMove, maxMovementSearchTime, expireActionTime, - dispelAuraDuration, passiveDelay, repeatDelay, + uint32 globalCoolDown, reactDelay, maxWaitForMove, disableMoveSplinePath, maxMovementSearchTime, + expireActionTime, dispelAuraDuration, passiveDelay, repeatDelay, errorDelay, rpgDelay, sitDelay, returnDelay, lootDelay; float sightDistance, spellDistance, reactDistance, grindDistance, lootDistance, shootDistance, fleeDistance, tooCloseDistance, meleeDistance, followDistance, whisperDistance, contactDistance, diff --git a/src/strategy/actions/MovementActions.cpp b/src/strategy/actions/MovementActions.cpp index f86d539e8..6a67e01b1 100644 --- a/src/strategy/actions/MovementActions.cpp +++ b/src/strategy/actions/MovementActions.cpp @@ -163,7 +163,9 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle, // } bool generatePath = !bot->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) && !bot->IsFlying() && !bot->HasUnitMovementFlag(MOVEMENTFLAG_SWIMMING) && !bot->IsInWater(); - if (!generatePath) { + bool disableMoveSplinePath = sPlayerbotAIConfig->disableMoveSplinePath >= 2 || + (sPlayerbotAIConfig->disableMoveSplinePath == 1 && bot->InBattleground()); + if (disableMoveSplinePath || !generatePath) { float distance = bot->GetExactDist(x, y, z); if (distance > sPlayerbotAIConfig->contactDistance) { From 06379b1ad028f432c5585acf3987252fa7b900d1 Mon Sep 17 00:00:00 2001 From: Fuzz Date: Wed, 10 Jul 2024 22:25:59 +1000 Subject: [PATCH 2/4] improved path selection for non-WSG BG's (improvements to pathing in AB and AV especially) --- src/strategy/actions/BattleGroundTactics.cpp | 123 ++++++++----------- 1 file changed, 54 insertions(+), 69 deletions(-) diff --git a/src/strategy/actions/BattleGroundTactics.cpp b/src/strategy/actions/BattleGroundTactics.cpp index 226cce6ff..919c5f71c 100644 --- a/src/strategy/actions/BattleGroundTactics.cpp +++ b/src/strategy/actions/BattleGroundTactics.cpp @@ -4162,99 +4162,84 @@ bool BGTactics::selectObjectiveWp(std::vector const& vPaths) if (bgType == BATTLEGROUND_WS /* && (bot->HasAura(BG_WS_SPELL_WARSONG_FLAG) || bot->HasAura(BG_WS_SPELL_SILVERWING_FLAG))*/) return wsgPaths(); - BattleBotPath* pClosestPath = nullptr; - uint32 closestPoint = 0; - float closestDistanceToTarget = FLT_MAX; - bool reverse = false; - float maxDistanceToPoint = 50.0f; + float chosenPathScore = FLT_MAX;//lower score is better + BattleBotPath* chosenPath = nullptr; + uint32 chosenPathPoint = 0; + bool chosenPathReverse = false; + + float botDistanceLimit = 50.0f; // limit for how far path can be from bot + float botDistanceScoreSubtract = 8.0f; // path score modifier - lower = less likely to chose a further path (it's basically the distance from bot that's ignored) + float botDistanceScoreMultiply = 3.0f; // path score modifier - higher = less likely to chose a further path (it's basically a multiplier on distance from bot - makes distance from bot more signifcant than distance from destination) + if (bgType == BATTLEGROUND_IC) - maxDistanceToPoint = 80.0f; + botDistanceLimit = 80.0f; + else if (bgType == BATTLEGROUND_AB) + { + botDistanceScoreSubtract = 2.0f; + botDistanceScoreMultiply = 4.0f; + } - for (auto const& pPath : vPaths) + for (auto const& path : vPaths) { // skip mine paths of own faction - if (bot->GetTeamId() == TEAM_ALLIANCE && std::find(vPaths_AllyMine.begin(), vPaths_AllyMine.end(), pPath) != vPaths_AllyMine.end()) + if (bot->GetTeamId() == TEAM_ALLIANCE && std::find(vPaths_AllyMine.begin(), vPaths_AllyMine.end(), path) != vPaths_AllyMine.end()) continue; - if (bot->GetTeamId() == TEAM_HORDE && std::find(vPaths_HordeMine.begin(), vPaths_HordeMine.end(), pPath) != vPaths_HordeMine.end()) + if (bot->GetTeamId() == TEAM_HORDE && std::find(vPaths_HordeMine.begin(), vPaths_HordeMine.end(), path) != vPaths_HordeMine.end()) continue; - BattleBotWaypoint& lastPoint = ((*pPath)[pPath->size() - 1]); - float const distanceFromPathEndToTarget = sqrt(Position(pos.x, pos.y, pos.z, 0.f).GetExactDist(lastPoint.x, lastPoint.y, lastPoint.z)); - if (closestDistanceToTarget > distanceFromPathEndToTarget) - { - float closestDistanceFromMeToPoint = FLT_MAX; + BattleBotWaypoint& startPoint = ((*path)[0]); + float const startPointDistToDestination = sqrt(Position(pos.x, pos.y, pos.z, 0.f).GetExactDist(startPoint.x, startPoint.y, startPoint.z)); + BattleBotWaypoint& endPoint = ((*path)[path->size() - 1]); + float const endPointDistToDestination = sqrt(Position(pos.x, pos.y, pos.z, 0.f).GetExactDist(endPoint.x, endPoint.y, endPoint.z)); + + bool reverse = startPointDistToDestination < endPointDistToDestination; + + // dont travel reverse if it's a reverse paths + if (reverse && std::find(vPaths_NoReverseAllowed.begin(), vPaths_NoReverseAllowed.end(), path) != vPaths_NoReverseAllowed.end()) + continue; - for (uint32 i = 0; i < pPath->size(); i++) + int closestPointIndex = -1; + float closestPointDistToBot = FLT_MAX; + for (uint32 i = 0; i < path->size(); i++) + { + BattleBotWaypoint& waypoint = ((*path)[i]); + float const distToBot = sqrt(bot->GetDistance(waypoint.x, waypoint.y, waypoint.z)); + if (closestPointDistToBot > distToBot) { - BattleBotWaypoint& waypoint = ((*pPath)[i]); - float const distanceFromMeToPoint = sqrt(bot->GetDistance(waypoint.x, waypoint.y, waypoint.z)); - if (distanceFromMeToPoint < maxDistanceToPoint && closestDistanceFromMeToPoint > distanceFromMeToPoint) - { - reverse = false; - pClosestPath = pPath; - closestPoint = i; - closestDistanceToTarget = distanceFromPathEndToTarget; - closestDistanceFromMeToPoint = distanceFromMeToPoint; - } + closestPointDistToBot = distToBot; + closestPointIndex = i; } } - // skip no reverse paths - if (std::find(vPaths_NoReverseAllowed.begin(), vPaths_NoReverseAllowed.end(), pPath) != vPaths_NoReverseAllowed.end()) + // don't pick path where bot is already closest to the paths closest point to target (it means path cant lead it anywhere) + // don't pick path where closest point is too far away + if (closestPointIndex == (reverse ? 0 : path->size() - 1) || closestPointDistToBot > botDistanceLimit) continue; - // skip mine paths of own faction - if (bot->GetTeamId() == TEAM_ALLIANCE && std::find(vPaths_AllyMine.begin(), vPaths_AllyMine.end(), pPath) != vPaths_AllyMine.end()) - continue; - if (bot->GetTeamId() == TEAM_HORDE && std::find(vPaths_HordeMine.begin(), vPaths_HordeMine.end(), pPath) != vPaths_HordeMine.end()) - continue; + // creates a score based on dist-to-bot and dist-to-destination, where lower is better, and dist-to-bot is more important (when its beyond a certain distance) + // dist-to-bot is more important because otherwise they cant reach it at all (or will fly through air with MM::MovePoint()), also bot may need to use multiple + // paths (one after another) anyway + float distToDestination = reverse ? startPointDistToDestination : endPointDistToDestination; + float pathScore = (closestPointDistToBot < botDistanceScoreSubtract ? 0.0f : ((closestPointDistToBot - botDistanceScoreSubtract) * botDistanceScoreMultiply)) + distToDestination; - { - BattleBotWaypoint& firstPoint = ((*pPath)[0]); - float const distanceFromPathBeginToTarget = sqrt(Position(pos.x, pos.y, pos.z, 0).GetExactDist(firstPoint.x, firstPoint.y, firstPoint.z)); - if (closestDistanceToTarget > distanceFromPathBeginToTarget) - { - float closestDistanceFromMeToPoint = FLT_MAX; + //LOG_INFO("playerbots", "bot={}\t{:6.1f}\t{:4.1f}\t{:4.1f}\t{}", bot->GetName(), pathScore, closestPointDistToBot, distToDestination, vPaths_AB_name[pathNum]); - for (uint32 i = 0; i < pPath->size(); i++) - { - BattleBotWaypoint& waypoint = ((*pPath)[i]); - float const distanceFromMeToPoint = sqrt(bot->GetDistance(waypoint.x, waypoint.y, waypoint.z)); - if (distanceFromMeToPoint < maxDistanceToPoint && closestDistanceFromMeToPoint > distanceFromMeToPoint) - { - reverse = true; - pClosestPath = pPath; - closestPoint = i; - closestDistanceToTarget = distanceFromPathBeginToTarget; - closestDistanceFromMeToPoint = distanceFromMeToPoint; - } - } - } + if (chosenPathScore > pathScore) { + chosenPathScore = pathScore; + chosenPath = path; + chosenPathPoint = closestPointIndex; + chosenPathReverse = reverse; } } - if (!pClosestPath) + if (!chosenPath) return false; - // Prevent picking last point of path. - // It means we are already there. - if (reverse) - { - if (closestPoint == 0) - return false; - } - else - { - if (closestPoint == pClosestPath->size() - 1) - return false; - } + //LOG_INFO("playerbots", "bot={} {}", bot->GetName(), vPaths_AB_name[chosenPathNum]); - BattleBotPath* currentPath = pClosestPath; - uint32 currentPoint = reverse ? closestPoint + 1 : closestPoint - 1; - - return moveToObjectiveWp(currentPath, currentPoint, reverse); + return moveToObjectiveWp(chosenPath, chosenPathPoint, chosenPathReverse); return false; } From 3316490f5dc6db63ac9a08186dab8bad02e5db05 Mon Sep 17 00:00:00 2001 From: Fuzz Date: Wed, 10 Jul 2024 22:36:22 +1000 Subject: [PATCH 3/4] many many fixes for AV - fixed main path from horde cave starting too far away (flying bots, or bots going nowhere), fixed wrong objects targetted for objective-nodes (bots hanging around already captured points), wrong creatures targetted for boss and captain (bot running toward and away from captain, bot capturing every point then running home), wrong flag state checked for certain points (bot waiting forever in burning tower), fixed bots not moving close enough to flags in towers (bots sitting in towers forever), and more --- src/strategy/actions/BattleGroundTactics.cpp | 168 +++++++++++-------- 1 file changed, 98 insertions(+), 70 deletions(-) diff --git a/src/strategy/actions/BattleGroundTactics.cpp b/src/strategy/actions/BattleGroundTactics.cpp index 919c5f71c..80eff17b6 100644 --- a/src/strategy/actions/BattleGroundTactics.cpp +++ b/src/strategy/actions/BattleGroundTactics.cpp @@ -40,12 +40,16 @@ Position const WS_FLAG_HIDE_ALLIANCE_2 = { 1540.286f, 1476.026f, 352.692f, 2.91f Position const WS_FLAG_HIDE_ALLIANCE_3 = { 1495.807f, 1466.774f, 352.350f, 1.50f }; std::vector const WS_FLAG_HIDE_HORDE = { WS_FLAG_HIDE_HORDE_1 , WS_FLAG_HIDE_HORDE_2, WS_FLAG_HIDE_HORDE_3 }; std::vector const WS_FLAG_HIDE_ALLIANCE = { WS_FLAG_HIDE_ALLIANCE_1 , WS_FLAG_HIDE_ALLIANCE_2, WS_FLAG_HIDE_ALLIANCE_3 }; + Position const AB_WAITING_POS_HORDE = { 702.884f, 703.045f, -16.115f, 0.77f }; Position const AB_WAITING_POS_ALLIANCE = { 1286.054f, 1282.500f, -15.697f, 3.95f }; + Position const AV_WAITING_POS_ALLIANCE = { 793.627f, -493.814f, 99.689f, 3.09f }; Position const AV_WAITING_POS_HORDE = { -1381.865f, -544.872f, 54.773f, 0.76f }; -Position const AV_ICEBLOOD_GARRISON_WAITING_ALLIANCE = { -492.17f, -187.077f, 57.1342f, 2.77f }; -Position const AV_STONEHEARTH_WAITING_HORDE = { 28.1264f, -302.593f, 15.076f, 2.96f }; +Position const AV_ICEBLOOD_GARRISON_WAITING_ALLIANCE = { -523.105f, -182.178f, 57.956f, 2.77f }; +Position const AV_ICEBLOOD_GARRISON_ATTACKING_ALLIANCE = { -545.288f, -167.932f, 57.012f, 2.77f }; +Position const AV_STONEHEARTH_WAITING_HORDE = { -36.399f, -306.403f, 15.565f, 2.96f }; +Position const AV_STONEHEARTH_ATTACKING_HORDE = { -55.210f, -288.546f, 15.578f, 2.96f }; Position const EY_WAITING_POS_HORDE = { 1809.102f, 1540.854f, 1267.142f, 6.18f }; Position const EY_WAITING_POS_ALLIANCE = { 2526.020f, 1596.787f, 1270.127f, 3.14f }; @@ -799,7 +803,16 @@ BattleBotPath vPath_AB_Farm_to_LumberMill = BattleBotPath vPath_AV_Horde_Cave_to_Tower_Point_Crossroad = { - { -885.928f, -536.612f, 55.1936f, nullptr }, + { -1362.395f, -529.615f, 52.636f, nullptr }, + { -1327.036f, -511.374f, 51.138f, nullptr }, + { -1277.047f, -516.327f, 50.667f, nullptr }, + { -1214.901f, -529.350f, 52.251f, nullptr }, + { -1151.129f, -545.598f, 51.990f, nullptr }, + { -1085.775f, -538.719f, 47.905f, nullptr }, + { -1038.552f, -517.946f, 43.876f, nullptr }, + { -981.371f, -494.593f, 41.127f, nullptr }, + { -930.598f, -463.751f, 43.060f, nullptr }, + { -887.138f, -475.816f, 44.374f, nullptr }, { -880.957f, -525.119f, 53.6791f, nullptr }, { -839.408f, -499.746f, 49.7505f, nullptr }, { -820.21f, -469.193f, 49.4085f, nullptr }, @@ -2262,48 +2275,48 @@ std::vector const vPaths_HordeMine = &vPath_AV_Coldtooth_Mine_Entrance_to_Coldtooth_Mine_Boss, }; -static uint32 AV_HordeAttackObjectives[] = +static std::pair AV_HordeAttackObjectives[] = { // Attack - { BG_AV_NODES_STONEHEART_BUNKER }, - { BG_AV_NODES_STONEHEART_GRAVE }, - { BG_AV_NODES_ICEWING_BUNKER }, - { BG_AV_NODES_STORMPIKE_GRAVE }, - { BG_AV_NODES_DUNBALDAR_SOUTH }, - { BG_AV_NODES_DUNBALDAR_NORTH }, - { BG_AV_NODES_FIRSTAID_STATION } + { BG_AV_NODES_STONEHEART_BUNKER, BG_AV_OBJECT_FLAG_A_STONEHEART_BUNKER }, + { BG_AV_NODES_STONEHEART_GRAVE, BG_AV_OBJECT_FLAG_A_STONEHEART_GRAVE }, + { BG_AV_NODES_ICEWING_BUNKER, BG_AV_OBJECT_FLAG_A_ICEWING_BUNKER }, + { BG_AV_NODES_STORMPIKE_GRAVE, BG_AV_OBJECT_FLAG_A_STORMPIKE_GRAVE }, + { BG_AV_NODES_DUNBALDAR_SOUTH, BG_AV_OBJECT_FLAG_A_DUNBALDAR_SOUTH }, + { BG_AV_NODES_DUNBALDAR_NORTH, BG_AV_OBJECT_FLAG_A_DUNBALDAR_NORTH }, + { BG_AV_NODES_FIRSTAID_STATION, BG_AV_OBJECT_FLAG_A_FIRSTAID_STATION } }; -static uint32 AV_HordeDefendObjectives[] = +static std::pair AV_HordeDefendObjectives[] = { // Defend - { BG_AV_NODES_FROSTWOLF_GRAVE }, - { BG_AV_NODES_FROSTWOLF_ETOWER }, - { BG_AV_NODES_FROSTWOLF_WTOWER }, - { BG_AV_NODES_TOWER_POINT }, - { BG_AV_NODES_ICEBLOOD_TOWER }, + { BG_AV_NODES_FROSTWOLF_GRAVE, BG_AV_OBJECT_FLAG_H_FROSTWOLF_GRAVE }, + { BG_AV_NODES_FROSTWOLF_ETOWER, BG_AV_OBJECT_FLAG_H_FROSTWOLF_ETOWER }, + { BG_AV_NODES_FROSTWOLF_WTOWER, BG_AV_OBJECT_FLAG_H_FROSTWOLF_WTOWER }, + { BG_AV_NODES_TOWER_POINT, BG_AV_OBJECT_FLAG_H_TOWER_POINT }, + { BG_AV_NODES_ICEBLOOD_TOWER, BG_AV_OBJECT_FLAG_H_ICEBLOOD_TOWER }, }; -static uint32 AV_AllianceAttackObjectives[] = +static std::pair AV_AllianceAttackObjectives[] = { // Attack - { BG_AV_NODES_ICEBLOOD_TOWER }, - { BG_AV_NODES_ICEBLOOD_GRAVE }, - { BG_AV_NODES_TOWER_POINT }, - { BG_AV_NODES_FROSTWOLF_GRAVE }, - { BG_AV_NODES_FROSTWOLF_ETOWER }, - { BG_AV_NODES_FROSTWOLF_WTOWER }, - { BG_AV_NODES_FROSTWOLF_HUT }, + { BG_AV_NODES_ICEBLOOD_TOWER, BG_AV_OBJECT_FLAG_H_ICEBLOOD_TOWER}, + { BG_AV_NODES_ICEBLOOD_GRAVE, BG_AV_OBJECT_FLAG_H_ICEBLOOD_GRAVE}, + { BG_AV_NODES_TOWER_POINT, BG_AV_OBJECT_FLAG_H_TOWER_POINT }, + { BG_AV_NODES_FROSTWOLF_GRAVE, BG_AV_OBJECT_FLAG_H_FROSTWOLF_GRAVE }, + { BG_AV_NODES_FROSTWOLF_ETOWER, BG_AV_OBJECT_FLAG_H_FROSTWOLF_ETOWER }, + { BG_AV_NODES_FROSTWOLF_WTOWER, BG_AV_OBJECT_FLAG_H_FROSTWOLF_WTOWER }, + { BG_AV_NODES_FROSTWOLF_HUT, BG_AV_OBJECT_FLAG_H_FROSTWOLF_HUT }, }; -static uint32 AV_AllianceDefendObjectives[] = +static std::pair AV_AllianceDefendObjectives[] = { // Defend - { BG_AV_NODES_STORMPIKE_GRAVE }, - { BG_AV_NODES_DUNBALDAR_SOUTH }, - { BG_AV_NODES_DUNBALDAR_NORTH }, - { BG_AV_NODES_ICEWING_BUNKER }, - { BG_AV_NODES_STONEHEART_BUNKER }, + { BG_AV_NODES_STORMPIKE_GRAVE, BG_AV_OBJECT_FLAG_A_STORMPIKE_GRAVE }, + { BG_AV_NODES_DUNBALDAR_SOUTH, BG_AV_OBJECT_FLAG_A_DUNBALDAR_SOUTH }, + { BG_AV_NODES_DUNBALDAR_NORTH, BG_AV_OBJECT_FLAG_A_DUNBALDAR_NORTH }, + { BG_AV_NODES_ICEWING_BUNKER, BG_AV_OBJECT_FLAG_A_ICEWING_BUNKER }, + { BG_AV_NODES_STONEHEART_BUNKER, BG_AV_OBJECT_FLAG_A_STONEHEART_BUNKER }, }; static uint32 AB_AttackObjectives[] = @@ -2937,7 +2950,7 @@ bool BGTactics::selectObjective(bool reset) alterValleyBG->GetAVNodeInfo(BG_AV_NODES_STONEHEART_BUNKER).TotalOwnerId != TEAM_ALLIANCE && alterValleyBG->GetAVNodeInfo(BG_AV_NODES_FIRSTAID_STATION).TotalOwnerId != TEAM_ALLIANCE) { - if (Creature* pVanndar = bg->GetBGCreature(AV_NPC_A_BOSS)) + if (Creature* pVanndar = bg->GetBGCreature(AV_CPLACE_TRIGGER17)) { BgObjective = pVanndar; endBoss = true; @@ -2952,8 +2965,9 @@ bool BGTactics::selectObjective(bool reset) // Only go to Snowfall Graveyard if already close to it. // Need to fix AV script - if (!BgObjective && supporter && (alterValleyBG->GetAVNodeInfo(BG_AV_NODES_SNOWFALL_GRAVE).OwnerId == TEAM_ALLIANCE || - alterValleyBG->GetAVNodeInfo(BG_AV_NODES_SNOWFALL_GRAVE).OwnerId == TEAM_HORDE || alterValleyBG->GetAVNodeInfo(BG_AV_NODES_SNOWFALL_GRAVE).OwnerId == TEAM_OTHER)) + if (!BgObjective && supporter && + (alterValleyBG->GetAVNodeInfo(BG_AV_NODES_SNOWFALL_GRAVE).OwnerId == TEAM_ALLIANCE || + alterValleyBG->GetAVNodeInfo(BG_AV_NODES_SNOWFALL_GRAVE).OwnerId == TEAM_OTHER)) { if (GameObject* pGO = bg->GetBGObject(BG_AV_NODES_SNOWFALL_GRAVE)) if (bot->IsWithinDist(pGO, 200.f)) @@ -2967,19 +2981,20 @@ bool BGTactics::selectObjective(bool reset) if (!BgObjective && alterValleyBG->IsCaptainAlive(0)) { - if (Creature* pBalinda = bg->GetBGCreature(AV_NPC_A_CAPTAIN)) + if (Creature* pBalinda = bg->GetBGCreature(AV_CPLACE_TRIGGER16)) { if (pBalinda->getDeathState() != DeathState::Dead) { - uint32 attackCount = 0; - attackCount += getDefendersCount(AV_STONEHEARTH_WAITING_HORDE, 10.0f, false); + uint32 attackCount = getDefendersCount(AV_STONEHEARTH_WAITING_HORDE, 10.0f, false) + getDefendersCount(AV_STONEHEARTH_ATTACKING_HORDE, 10.0f, false); // prepare to attack Captain if (attackCount < 10 && !pBalinda->IsInCombat()) { // get in position to attack Captain - pos.Set(AV_STONEHEARTH_WAITING_HORDE.GetPositionX(), AV_STONEHEARTH_WAITING_HORDE.GetPositionY(), - AV_STONEHEARTH_WAITING_HORDE.GetPositionZ(), bg->GetMapId()); + pos.Set(AV_STONEHEARTH_WAITING_HORDE.GetPositionX(), + AV_STONEHEARTH_WAITING_HORDE.GetPositionY(), + AV_STONEHEARTH_WAITING_HORDE.GetPositionZ(), + bg->GetMapId()); std::ostringstream out; out << "Taking position at Stonehearth!"; @@ -2987,6 +3002,12 @@ bool BGTactics::selectObjective(bool reset) } else { + // they need help getting there (or did before I fixed the target creature, will leave in anyway, as it probably makes it more robust) + pos.Set(AV_STONEHEARTH_ATTACKING_HORDE.GetPositionX(), + AV_STONEHEARTH_ATTACKING_HORDE.GetPositionY(), + AV_STONEHEARTH_ATTACKING_HORDE.GetPositionZ(), + bg->GetMapId()); + std::ostringstream out; out << "Attacking Balinda!"; //bot->Say(out.str(), LANG_UNIVERSAL); @@ -3007,9 +3028,9 @@ bool BGTactics::selectObjective(bool reset) { for (const auto& objective : AV_HordeDefendObjectives) { - if (!BgObjective && alterValleyBG->GetAVNodeInfo(objective).OwnerId == TEAM_ALLIANCE) + if (!BgObjective && alterValleyBG->GetAVNodeInfo(objective.first).OwnerId == TEAM_ALLIANCE) { - if (GameObject* pGO = bg->GetBGObject(objective)) + if (GameObject* pGO = bg->GetBGObject(objective.second)) if (bot->IsWithinDist(pGO, 400.0f)) { BgObjective = pGO; @@ -3022,7 +3043,8 @@ bool BGTactics::selectObjective(bool reset) } // Mine capture (need paths & script fix) - if (!BgObjective && supporter && !endBoss && (alterValleyBG->GetMineOwner(AV_NORTH_MINE) == TEAM_ALLIANCE || alterValleyBG->GetMineOwner(AV_NORTH_MINE) == TEAM_OTHER) && + if (!BgObjective && supporter && !endBoss && + (alterValleyBG->GetMineOwner(AV_NORTH_MINE) == TEAM_ALLIANCE || alterValleyBG->GetMineOwner(AV_NORTH_MINE) == TEAM_OTHER) && alterValleyBG->GetAVNodeInfo(BG_AV_NODES_STORMPIKE_GRAVE).OwnerId != TEAM_ALLIANCE) { if (Creature* mBossNeutral = bg->GetBGCreature(AV_CPLACE_MINE_N_3)) @@ -3055,10 +3077,9 @@ bool BGTactics::selectObjective(bool reset) for (const auto& objective : AV_HordeAttackObjectives) { if ((!BgObjective/* || (supporter && objective.first == BG_AV_NODES_STONEHEART_BUNKER && !bg->IsActiveEvent(BG_AV_NODE_CAPTAIN_DEAD_A, 0))*/) && - (alterValleyBG->GetAVNodeInfo(objective).OwnerId == TEAM_ALLIANCE || alterValleyBG->GetAVNodeInfo(objective).TotalOwnerId == TEAM_ALLIANCE || - alterValleyBG->GetAVNodeInfo(objective).OwnerId == TEAM_OTHER)) + alterValleyBG->GetAVNodeInfo(objective.first).TotalOwnerId == TEAM_ALLIANCE)//need to check TotalOwnerId for attack objectives { - if (GameObject* pGO = bg->GetBGObject(objective)) + if (GameObject* pGO = bg->GetBGObject(objective.second)) { BgObjective = pGO; //std::ostringstream out; @@ -3073,11 +3094,13 @@ bool BGTactics::selectObjective(bool reset) { bool endBoss = false; // End boss - if (alterValleyBG->GetAVNodeInfo(BG_AV_NODES_ICEBLOOD_TOWER).OwnerId != TEAM_HORDE && alterValleyBG->GetAVNodeInfo(BG_AV_NODES_TOWER_POINT).OwnerId != TEAM_HORDE && - alterValleyBG->GetAVNodeInfo(BG_AV_NODES_FROSTWOLF_ETOWER).OwnerId != TEAM_HORDE && alterValleyBG->GetAVNodeInfo(BG_AV_NODES_FROSTWOLF_WTOWER).OwnerId != TEAM_HORDE && - alterValleyBG->GetAVNodeInfo(BG_AV_NODES_FROSTWOLF_HUT).OwnerId != TEAM_HORDE) + if (alterValleyBG->GetAVNodeInfo(BG_AV_NODES_ICEBLOOD_TOWER).TotalOwnerId != TEAM_HORDE && + alterValleyBG->GetAVNodeInfo(BG_AV_NODES_TOWER_POINT).TotalOwnerId != TEAM_HORDE && + alterValleyBG->GetAVNodeInfo(BG_AV_NODES_FROSTWOLF_ETOWER).TotalOwnerId != TEAM_HORDE && + alterValleyBG->GetAVNodeInfo(BG_AV_NODES_FROSTWOLF_WTOWER).TotalOwnerId != TEAM_HORDE && + alterValleyBG->GetAVNodeInfo(BG_AV_NODES_FROSTWOLF_HUT).TotalOwnerId != TEAM_HORDE) { - if (Creature* pDrek = bg->GetBGCreature(AV_NPC_H_BOSS)) + if (Creature* pDrek = bg->GetBGCreature(AV_CPLACE_TRIGGER19)) { BgObjective = pDrek; endBoss = true; @@ -3091,9 +3114,9 @@ bool BGTactics::selectObjective(bool reset) bool supporter = role < 3; // Only go to Snowfall Graveyard if already close to it. - if (!BgObjective && supporter && (alterValleyBG->GetAVNodeInfo(BG_AV_NODES_SNOWFALL_GRAVE).OwnerId == TEAM_HORDE || - alterValleyBG->GetAVNodeInfo(BG_AV_NODES_SNOWFALL_GRAVE).TotalOwnerId == TEAM_HORDE || - alterValleyBG->GetAVNodeInfo(BG_AV_NODES_SNOWFALL_GRAVE).TotalOwnerId == TEAM_OTHER)) + if (!BgObjective && supporter && + (alterValleyBG->GetAVNodeInfo(BG_AV_NODES_SNOWFALL_GRAVE).OwnerId == TEAM_HORDE || + alterValleyBG->GetAVNodeInfo(BG_AV_NODES_SNOWFALL_GRAVE).OwnerId == TEAM_OTHER)) { if (GameObject* pGO = bg->GetBGObject(BG_AV_NODES_SNOWFALL_GRAVE)) if (bot->IsWithinDist(pGO, 200.f)) @@ -3110,9 +3133,9 @@ bool BGTactics::selectObjective(bool reset) { for (const auto& objective : AV_AllianceDefendObjectives) { - if (!BgObjective && alterValleyBG->GetAVNodeInfo(objective).OwnerId == TEAM_HORDE) + if (!BgObjective && alterValleyBG->GetAVNodeInfo(objective.first).OwnerId == TEAM_HORDE) { - if (GameObject* pGO = bg->GetBGObject(objective)) + if (GameObject* pGO = bg->GetBGObject(objective.second)) { BgObjective = pGO; //std::ostringstream out; out << "Defending Node #" << objective.first; @@ -3123,8 +3146,8 @@ bool BGTactics::selectObjective(bool reset) } // Mine capture (need paths & script fix) - if (!BgObjective && supporter && !endBoss && (alterValleyBG->GetMineOwner(AV_SOUTH_MINE) == TEAM_HORDE || - alterValleyBG->GetMineOwner(AV_SOUTH_MINE) == TEAM_OTHER) && + if (!BgObjective && supporter && !endBoss && + (alterValleyBG->GetMineOwner(AV_SOUTH_MINE) == TEAM_HORDE || alterValleyBG->GetMineOwner(AV_SOUTH_MINE) == TEAM_OTHER) && alterValleyBG->GetAVNodeInfo(BG_AV_NODES_FROSTWOLF_GRAVE).TotalOwnerId != TEAM_HORDE) { if (Creature* mBossNeutral = bg->GetBGCreature(AV_CPLACE_MINE_S_3)) @@ -3158,17 +3181,18 @@ bool BGTactics::selectObjective(bool reset) if (alterValleyBG->IsCaptainAlive(1)) { - if (Creature* pGalvangar = bg->GetBGCreature(AV_NPC_H_CAPTAIN)) + if (Creature* pGalvangar = bg->GetBGCreature(AV_CPLACE_TRIGGER18)) { - uint32 attackCount = 0; - attackCount += getDefendersCount(AV_ICEBLOOD_GARRISON_WAITING_ALLIANCE, 10.0f, false); + uint32 attackCount = getDefendersCount(AV_ICEBLOOD_GARRISON_WAITING_ALLIANCE, 10.0f, false) + getDefendersCount(AV_ICEBLOOD_GARRISON_ATTACKING_ALLIANCE, 10.0f, false); // prepare to attack Captain if (attackCount < 10 && !pGalvangar->IsInCombat()) { // get in position to attack Captain - pos.Set(AV_ICEBLOOD_GARRISON_WAITING_ALLIANCE.GetPositionX(), AV_ICEBLOOD_GARRISON_WAITING_ALLIANCE.GetPositionY(), - AV_ICEBLOOD_GARRISON_WAITING_ALLIANCE.GetPositionZ(), bg->GetMapId()); + pos.Set(AV_ICEBLOOD_GARRISON_WAITING_ALLIANCE.GetPositionX(), + AV_ICEBLOOD_GARRISON_WAITING_ALLIANCE.GetPositionY(), + AV_ICEBLOOD_GARRISON_WAITING_ALLIANCE.GetPositionZ(), + bg->GetMapId()); //std::ostringstream out; //out << "Taking position at Iceblood Outpost!"; @@ -3176,6 +3200,12 @@ bool BGTactics::selectObjective(bool reset) } else { + // they need help getting there (or did before I fixed the target creature, will leave in anyway, as it probably makes it more robust) + pos.Set(AV_ICEBLOOD_GARRISON_ATTACKING_ALLIANCE.GetPositionX(), + AV_ICEBLOOD_GARRISON_ATTACKING_ALLIANCE.GetPositionY(), + AV_ICEBLOOD_GARRISON_ATTACKING_ALLIANCE.GetPositionZ(), + bg->GetMapId()); + //std::ostringstream out; // out << "Attacking Galvangar!"; //bot->Say(out.str(), LANG_UNIVERSAL); @@ -3187,11 +3217,9 @@ bool BGTactics::selectObjective(bool reset) for (const auto& objective : AV_AllianceAttackObjectives) { - if (alterValleyBG->GetAVNodeInfo(objective).OwnerId == TEAM_HORDE || - alterValleyBG->GetAVNodeInfo(objective).TotalOwnerId == TEAM_HORDE || - alterValleyBG->GetAVNodeInfo(objective).TotalOwnerId == TEAM_OTHER) + if (alterValleyBG->GetAVNodeInfo(objective.first).TotalOwnerId == TEAM_HORDE)//need to check TotalOwnerId for attack objectives { - if (GameObject* pGO = bg->GetBGObject(objective)) + if (GameObject* pGO = bg->GetBGObject(objective.second)) { float const distance = sqrt(bot->GetDistance(pGO)); if (attackObjectiveDistance > distance) @@ -4124,7 +4152,7 @@ bool BGTactics::moveToObjective() } // don't try to move if already close - if (sqrt(bot->GetDistance(pos.x, pos.y, pos.z)) < 5.0f) + if (sqrt(bot->GetDistance(pos.x, pos.y, pos.z)) < 2.0f) { resetObjective(); @@ -4134,8 +4162,8 @@ bool BGTactics::moveToObjective() //std::ostringstream out; out << "Moving to objective " << pos.x << ", " << pos.y << ", Distance: " << sServerFacade->GetDistance2d(bot, pos.x, pos.y); //bot->Say(out.str(), LANG_UNIVERSAL); - // more precise position for wsg - if (bgType == BATTLEGROUND_WS) + // more precise position for wsg and AV (flags in AV towers require precision) + if (bgType == BATTLEGROUND_WS || bgType == BATTLEGROUND_AV) return MoveTo(bot->GetMapId(), pos.x, pos.y, pos.z); else return MoveNear(bot->GetMapId(), pos.x, pos.y, pos.z, 3.0f); @@ -4946,9 +4974,9 @@ bool ArenaTactics::moveToCenter(Battleground* bg) case BATTLEGROUND_DS: if (!MoveTo(bg->GetMapId(), 1291.58f + frand(-5, +5), 790.87f + frand(-5, +5), 7.8f, false, true)) { // they like to hang around at the tip of the pipes doing nothing, so we just teleport them down - if (bot->GetDistance(1333.07f, 817.18f, 13.35f) < 2) + if (bot->GetDistance(1333.07f, 817.18f, 13.35f) < 4) bot->TeleportTo(bg->GetMapId(), 1330.96f, 816.75f, 3.2f, bot->GetOrientation()); - if (bot->GetDistance(1250.13f, 764.79f, 13.34f) < 2) + if (bot->GetDistance(1250.13f, 764.79f, 13.34f) < 4) bot->TeleportTo(bg->GetMapId(), 1252.19f, 765.41f, 3.2f, bot->GetOrientation()); } break; From 72eb38af88d9146b446bf12792fa591620c39f5a Mon Sep 17 00:00:00 2001 From: Fuzz Date: Thu, 11 Jul 2024 13:06:17 +1000 Subject: [PATCH 4/4] fixed bots of same faction not fighting in arena until player triggers it --- src/strategy/values/AttackersValue.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/strategy/values/AttackersValue.cpp b/src/strategy/values/AttackersValue.cpp index 527b8def6..cae2223ac 100644 --- a/src/strategy/values/AttackersValue.cpp +++ b/src/strategy/values/AttackersValue.cpp @@ -47,8 +47,21 @@ GuidVector AttackersValue::Calculate() if (bot->duel && bot->duel->Opponent) result.push_back(bot->duel->Opponent->GetGUID()); - - return result; + + // workaround for bots of same faction not fighting in arena + if (bot->InArena()) + { + GuidVector possibleTargets = AI_VALUE(GuidVector, "possible targets"); + for (ObjectGuid const guid : possibleTargets) + { + Unit* unit = botAI->GetUnit(guid); + if (unit && unit->IsPlayer() && IsValidTarget(unit, bot)) { + result.push_back(unit->GetGUID()); + } + } + } + + return result; } void AttackersValue::AddAttackersOf(Group* group, std::unordered_set& targets)