From af674e9361cce8e8e8f5446142dd8a38e649a115 Mon Sep 17 00:00:00 2001 From: Fuzz Date: Tue, 6 Aug 2024 19:26:54 +1000 Subject: [PATCH 1/6] [Battlegrounds] many IOC fixes: fixed bots not being able to revive in their own base GY, fixed bots not able to use flags in IOC at all (couldnt cap anything), added path so bots could reach boss and several other paths too, fixed horde bots not being able to tell that alliance gate is down (stayed outside forever), fixed bots not able to get in vehicles, fixed bots not able to drive vehicles, fixed bots in vehicles becoming unresponsive after a fight (in-combat status seems to never clear in vehicle which may be AC bug), reduced bot 'agro distance' when in vehicle so they can get to their objective, redid selectObject strat completely, prevented bots using cannons (bots are useless in them) and catapults (they dont know how to use them), prevented bots using Glaive Thrower's Blade Salvo as it's bugged (and stops them using any attacks after they use it), many other fixes --- src/strategy/actions/BattleGroundTactics.cpp | 904 +++++++++--------- src/strategy/actions/MovementActions.cpp | 22 + src/strategy/actions/ReleaseSpiritAction.cpp | 6 +- src/strategy/actions/VehicleActions.cpp | 31 +- src/strategy/generic/BattlegroundStrategy.cpp | 5 +- src/strategy/values/EnemyPlayerValue.cpp | 22 +- src/strategy/values/NearestNpcsValue.cpp | 2 +- 7 files changed, 518 insertions(+), 474 deletions(-) diff --git a/src/strategy/actions/BattleGroundTactics.cpp b/src/strategy/actions/BattleGroundTactics.cpp index 03b838d5..7b28a19d 100644 --- a/src/strategy/actions/BattleGroundTactics.cpp +++ b/src/strategy/actions/BattleGroundTactics.cpp @@ -66,18 +66,22 @@ Position const EY_WAITING_POS_ALLIANCE = {2526.020f, 1596.787f, 1270.127f, 3.14f Position const EY_FLAG_RETURN_POS_RETREAT_HORDE = {1885.529f, 1532.157f, 1200.635f, 0.0f}; Position const EY_FLAG_RETURN_POS_RETREAT_ALLIANCE = {2452.253f, 1602.356f, 1203.617f, 0.0f}; -Position const IC_WAITING_POS_HORDE = {1166.322f, -762.402f, 48.628f, 3.14f}; -Position const IC_WAITING_POS_ALLIANCE = {387.893f, -833.384f, 48.714f, 6.28f}; +Position const IC_WAITING_POS_HORDE = {1166.322f, -762.402f, 48.628f}; +Position const IC_WEST_WAITING_POS_HORDE = {1217.666f, -685.449f, 48.915f}; +Position const IC_EAST_WAITING_POS_HORDE = {1219.068f, -838.791f, 48.916f}; -Position const IC_WEST_WAITING_POS_HORDE = {1217.666f, -685.449f, 48.915f, 1.54f}; -Position const IC_EAST_WAITING_POS_HORDE = {1219.068f, -838.791f, 48.916f, 4.72f}; -Position const IC_SIDE_WAITING_POS_ALLIANCE = {351.517f, -882.477f, 48.916f, 4.68f}; +Position const IC_WAITING_POS_ALLIANCE = {387.893f, -833.384f, 48.714f}; +Position const IC_WEST_WAITING_POS_ALLIANCE = {352.129f, -788.029f, 48.916f}; +Position const IC_EAST_WAITING_POS_ALLIANCE = {351.517f, -882.477f, 48.916f}; Position const IC_CANNON_POS_HORDE1 = {1140.938f, -838.685f, 88.124f, 2.30f}; Position const IC_CANNON_POS_HORDE2 = {1139.695f, -686.574f, 88.173f, 3.95f}; Position const IC_CANNON_POS_ALLIANCE1 = {424.860f, -855.795f, 87.96f, 0.44f}; Position const IC_CANNON_POS_ALLIANCE2 = {425.525f, -779.538f, 87.717f, 5.88f}; +Position const IC_GATE_ATTACK_POS_HORDE = {506.782f, -828.594f, 24.313f, 0.0f}; +Position const IC_GATE_ATTACK_POS_ALLIANCE = {1091.273f, -763.619f, 42.352f, 0.0f}; + enum BattleBotWsgWaitSpot { BB_WSG_WAIT_SPOT_SPAWN, @@ -100,9 +104,41 @@ std::vector const vFlagsWS = {BG_OBJECT_A_FLAG_WS_ENTRY, BG_OBJECT_H_FLA std::vector const vFlagsEY = {BG_OBJECT_FLAG2_EY_ENTRY, BG_OBJECT_FLAG3_EY_ENTRY}; -std::vector const vFlagsIC = {BG_IC_GO_HORDE_BANNER, BG_IC_GO_ALLIANCE_BANNER, BG_IC_GO_WORKSHOP_BANNER, - BG_IC_GO_DOCKS_BANNER, BG_IC_GO_HANGAR_BANNER, BG_IC_GO_QUARRY_BANNER, - BG_IC_GO_REFINERY_BANNER}; +std::vector const vFlagsIC = {GO_HORDE_BANNER, + GO_ALLIANCE_BANNER, + GO_WORKSHOP_BANNER, + GO_DOCKS_BANNER, + GO_HANGAR_BANNER, + GO_QUARRY_BANNER, + GO_REFINERY_BANNER, + GO_ALLIANCE_BANNER_DOCK, + GO_ALLIANCE_BANNER_DOCK_CONT, + GO_HORDE_BANNER_DOCK, + GO_HORDE_BANNER_DOCK_CONT, + GO_HORDE_BANNER_HANGAR, + GO_HORDE_BANNER_HANGAR_CONT, + GO_ALLIANCE_BANNER_HANGAR, + GO_ALLIANCE_BANNER_HANGAR_CONT, + GO_ALLIANCE_BANNER_QUARRY, + GO_ALLIANCE_BANNER_QUARRY_CONT, + GO_HORDE_BANNER_QUARRY, + GO_HORDE_BANNER_QUARRY_CONT, + GO_ALLIANCE_BANNER_REFINERY, + GO_ALLIANCE_BANNER_REFINERY_CONT, + GO_HORDE_BANNER_REFINERY, + GO_HORDE_BANNER_REFINERY_CONT, + GO_ALLIANCE_BANNER_WORKSHOP, + GO_ALLIANCE_BANNER_WORKSHOP_CONT, + GO_HORDE_BANNER_WORKSHOP, + GO_HORDE_BANNER_WORKSHOP_CONT, + GO_ALLIANCE_BANNER_GRAVEYARD_A, + GO_ALLIANCE_BANNER_GRAVEYARD_A_CONT, + GO_HORDE_BANNER_GRAVEYARD_A, + GO_HORDE_BANNER_GRAVEYARD_A_CONT, + GO_ALLIANCE_BANNER_GRAVEYARD_H, + GO_ALLIANCE_BANNER_GRAVEYARD_H_CONT, + GO_HORDE_BANNER_GRAVEYARD_H, + GO_HORDE_BANNER_GRAVEYARD_H_CONT}; // BG Waypoints (vmangos) @@ -1024,8 +1060,9 @@ BattleBotPath vPath_AV_Frostdagger_Pass_Lower_to_Iceblood_Garrison = { // path that allows alliance to bypass the mid on way to horde captain BattleBotPath vPath_AV_Icewing_Bunker_Crossroad_to_Frostdagger_Pass_Lower = { - // these are to cause bot to pick this when resurrecting at stonehearth (not really needed anymore as they get - // captain down in first wave since uneeded dismounting was fixed) + // the first 3 are to cause bot to pick this when resurrecting at stonehearth - seems to be key thing to + // stopping alliance getting bogged down in mid fighting, away from their objective (enemy captain) but close to + // horde objectives (advantaging horde significantly) {68.793f, -396.742f, 45.299f, nullptr}, {99.042f, -389.310f, 45.101f, nullptr}, {123.787f, -373.551f, 42.893f, nullptr}, {119.693f, -351.311f, 42.728f, nullptr}, {107.710f, -321.162f, 37.168f, nullptr}, {84.953f, -273.434f, 23.944f, nullptr}, @@ -1328,6 +1365,57 @@ BattleBotPath vPath_IC_Workshop_to_Workshop_Keep = {{773.792f, -825.637f, 8.127f {772.706f, -841.881f, 11.622f, nullptr}, {773.057f, -859.936f, 12.418f, nullptr}}; +BattleBotPath vPath_IC_Alliance_Base = { + {402.020f, -832.289f, 48.627f, nullptr}, {384.784f, -832.551f, 48.830f, nullptr}, + {369.413f, -832.480f, 48.916f, nullptr}, {346.677f, -832.355f, 48.916f, nullptr}, + {326.296f, -832.189f, 48.916f, nullptr}, {311.174f, -832.204f, 48.916f, nullptr}, +}; + +BattleBotPath vPath_IC_Horde_Base = { + {1158.652f, -762.680f, 48.628f, nullptr}, {1171.598f, -762.628f, 48.649f, nullptr}, + {1189.102f, -763.484f, 48.915f, nullptr}, {1208.599f, -764.332f, 48.915f, nullptr}, + {1227.592f, -764.782f, 48.915f, nullptr}, {1253.676f, -765.441f, 48.915f, nullptr}, +}; + +BattleBotPath vPath_IC_Workshop_to_North_West = { + {786.051f, -801.798f, 5.968f, nullptr}, {801.767f, -800.845f, 6.201f, nullptr}, + {830.190f, -800.059f, 5.163f, nullptr}, {858.827f, -797.691f, 5.602f, nullptr}, + {881.579f, -795.190f, 6.441f, nullptr}, {905.796f, -792.252f, 8.008f, nullptr}, + {929.874f, -788.912f, 10.674f, nullptr}, {960.001f, -784.233f, 15.521f, nullptr}, + {991.890f, -780.605f, 22.402f, nullptr}, {1014.062f, -761.863f, 28.672f, nullptr}, + {1019.925f, -730.822f, 27.421f, nullptr}, {1022.320f, -698.581f, 25.993f, nullptr}, + {1022.539f, -665.405f, 24.574f, nullptr}, {1016.279f, -632.780f, 24.487f, nullptr}, + {1004.839f, -602.680f, 24.501f, nullptr}, {992.826f, -567.833f, 24.558f, nullptr}, + {984.998f, -535.303f, 24.485f, nullptr}, +}; + +BattleBotPath vPath_IC_South_West_Crossroads = { + {528.932f, -667.953f, 25.413f, nullptr}, {514.800f, -650.381f, 26.171f, nullptr}, + {488.367f, -621.869f, 25.820f, nullptr}, {479.491f, -594.284f, 26.095f, nullptr}, + {498.094f, -557.031f, 26.015f, nullptr}, {528.272f, -528.761f, 26.015f, nullptr}, + {595.746f, -480.009f, 26.007f, nullptr}, {632.156f, -458.182f, 27.416f, nullptr}, + {656.013f, -446.685f, 28.003f, nullptr}, +}; + +BattleBotPath vPath_IC_Hanger_to_Workshop = { + {808.923f, -1003.441f, 132.380f, nullptr}, {804.031f, -1002.785f, 132.382f, nullptr}, + {798.466f, -1021.472f, 132.292f, nullptr}, {795.472f, -1031.693f, 130.232f, nullptr}, + {804.631f, -1042.672f, 125.310f, nullptr}, {827.549f, -1061.778f, 111.276f, nullptr}, + {847.424f, -1077.930f, 98.061f, nullptr}, {868.225f, -1091.563f, 83.794f, nullptr}, + {894.100f, -1104.828f, 66.570f, nullptr}, {923.615f, -1117.689f, 47.391f, nullptr}, + {954.614f, -1119.716f, 27.880f, nullptr}, {970.397f, -1116.281f, 22.124f, nullptr}, + {985.906f, -1105.714f, 18.572f, nullptr}, {996.308f, -1090.605f, 17.669f, nullptr}, + {1003.693f, -1072.916f, 16.583f, nullptr}, {1008.660f, -1051.310f, 15.970f, nullptr}, + {1008.437f, -1026.678f, 15.623f, nullptr}, {1000.103f, -999.047f, 16.487f, nullptr}, + {988.412f, -971.096f, 17.796f, nullptr}, {971.503f, -945.742f, 14.438f, nullptr}, + {947.420f, -931.306f, 13.209f, nullptr}, {922.920f, -916.960f, 10.859f, nullptr}, + {901.607f, -902.203f, 9.854f, nullptr}, {881.932f, -882.226f, 7.848f, nullptr}, + {861.795f, -862.477f, 6.731f, nullptr}, {844.186f, -845.952f, 6.192f, nullptr}, + {826.565f, -826.551f, 5.171f, nullptr}, {809.497f, -815.351f, 6.179f, nullptr}, + {790.787f, -809.678f, 6.450f, nullptr}, +}; + + std::vector const vPaths_WS = { &vPath_WSG_HordeFlagRoom_to_HordeGraveyard, &vPath_WSG_HordeGraveyard_to_HordeTunnel, &vPath_WSG_HordeTunnel_to_HordeFlagRoom, &vPath_WSG_HordeTunnel_to_AllianceTunnel_1, @@ -1463,6 +1551,11 @@ std::vector const vPaths_IC = { &vPath_IC_Central_Graveyard_to_Workshop, &vPath_IC_Horde_East_Gate_to_Horde_Keep, &vPath_IC_Workshop_to_Workshop_Keep, + &vPath_IC_Alliance_Base, + &vPath_IC_Horde_Base, + &vPath_IC_Workshop_to_North_West, + &vPath_IC_South_West_Crossroads, + &vPath_IC_Hanger_to_Workshop, }; std::vector const vPaths_NoReverseAllowed = { @@ -1535,7 +1628,6 @@ static std::pair AV_AllianceDefendObjectives[] = { }; static uint32 AB_AttackObjectives[] = { - // Attack BG_AB_NODE_STABLES, BG_AB_NODE_BLACKSMITH, BG_AB_NODE_FARM, BG_AB_NODE_LUMBER_MILL, BG_AB_NODE_GOLD_MINE}; static std::tuple EY_AttackObjectives[] = { @@ -1544,6 +1636,12 @@ static std::tuple EY_AttackObjectives[] = { {POINT_DRAENEI_RUINS, BG_EY_OBJECT_FLAG_DRAENEI_RUINS, AT_DRAENEI_RUINS_POINT}, {POINT_MAGE_TOWER, BG_EY_OBJECT_FLAG_MAGE_TOWER, AT_MAGE_TOWER_POINT}}; +static std::pair IC_AttackObjectives[] = { + {NODE_TYPE_WORKSHOP, BG_IC_GO_WORKSHOP_BANNER}, + {NODE_TYPE_DOCKS, BG_IC_GO_DOCKS_BANNER}, + {NODE_TYPE_HANGAR, BG_IC_GO_HANGAR_BANNER}, +}; + // useful commands for fixing BG bugs and checking waypoints/paths bool BGTactics::HandleConsoleCommand(ChatHandler* handler, char const* args) { @@ -1584,7 +1682,11 @@ std::string const BGTactics::HandleConsoleCommandPrivate(WorldSession* session, if (!strncmp(cmd, "showpath", 8)) { int num = -1; - if (!strncmp(cmd, "showpath=", 9)) + if (!strncmp(cmd, "showpath=all", 12)) + { + num = -2; + } + else if (!strncmp(cmd, "showpath=", 9)) { if (sscanf(cmd, "showpath=%d", &num) == -1 || num < 0) return "Bad showpath parameter"; @@ -1631,17 +1733,29 @@ std::string const BGTactics::HandleConsoleCommandPrivate(WorldSession* session, } } } - if (num >= vPaths->size()) - return fmt::format("Path out of range of 0 - {}", vPaths->size() - 1); - auto const& path = (*vPaths)[num]; - for (uint32 i = 0; i < path->size(); i++) + uint32 min = 0u; + uint32 max = vPaths->size() - 1; + if (num >= 0) // num specified or found { - BattleBotWaypoint& waypoint = ((*path)[i]); - Creature* wpCreature = - player->SummonCreature(15631, waypoint.x, waypoint.y, waypoint.z, 0, TEMPSUMMON_TIMED_DESPAWN, 15000u); - wpCreature->SetOwnerGUID(player->GetGUID()); + if (num > max) + return fmt::format("Path {} of range of 0 - {}", num, max); + min = num; + max = num; } - return fmt::format("Showing path {}", num); + for (uint32 j = min; j <= max; j++) + { + auto const& path = (*vPaths)[j]; + for (uint32 i = 0; i < path->size(); i++) + { + BattleBotWaypoint& waypoint = ((*path)[i]); + Creature* wpCreature = player->SummonCreature(15631, waypoint.x, waypoint.y, waypoint.z, 0, + TEMPSUMMON_TIMED_DESPAWN, 15000u); + wpCreature->SetOwnerGUID(player->GetGUID()); + } + } + if (num >= 0) + return fmt::format("Showing path {}", num); + return fmt::format("Showing paths 0 - {}", max); } if (!strncmp(cmd, "showcreature=", 13)) @@ -2150,9 +2264,10 @@ bool BGTactics::Execute(Event event) if (useBuff()) return true; - if (bot->IsInCombat() && - !(bot->HasAura(BG_WS_SPELL_WARSONG_FLAG) || bot->HasAura(BG_WS_SPELL_SILVERWING_FLAG) || - bot->HasAura(BG_EY_NETHERSTORM_FLAG_SPELL))) + // NOTE: can't use IsInCombat() when in vehicle as player is stuck in combat forever while in vehicle (ac bug?) + bool inCombat = bot->GetVehicle() ? (bool)AI_VALUE(Unit*, "enemy player target") : bot->IsInCombat(); + if (inCombat && !(bot->HasAura(BG_WS_SPELL_WARSONG_FLAG) || bot->HasAura(BG_WS_SPELL_SILVERWING_FLAG) || + bot->HasAura(BG_EY_NETHERSTORM_FLAG_SPELL))) { // bot->GetMotionMaster()->MovementExpired(); return false; @@ -2274,53 +2389,33 @@ bool BGTactics::moveToStart(bool force) if (bot->GetTeamId() == TEAM_HORDE) { - if (role < 3) - { - if (urand(0, 1)) - MoveTo(bg->GetMapId(), IC_WEST_WAITING_POS_HORDE.GetPositionX() + frand(-5.0f, 5.0f), - IC_WEST_WAITING_POS_HORDE.GetPositionY() + frand(-5.0f, 5.0f), - IC_WEST_WAITING_POS_HORDE.GetPositionZ()); - else - MoveTo(bg->GetMapId(), IC_WAITING_POS_HORDE.GetPositionX() + frand(-5.0f, 5.0f), - IC_WAITING_POS_HORDE.GetPositionY() + frand(-5.0f, 5.0f), - IC_WAITING_POS_HORDE.GetPositionZ()); - } - else - { - if (urand(0, 1)) - MoveTo(bg->GetMapId(), IC_EAST_WAITING_POS_HORDE.GetPositionX() + frand(-5.0f, 5.0f), - IC_EAST_WAITING_POS_HORDE.GetPositionY() + frand(-5.0f, 5.0f), - IC_EAST_WAITING_POS_HORDE.GetPositionZ()); - else - MoveTo(bg->GetMapId(), IC_WAITING_POS_HORDE.GetPositionX() + frand(-5.0f, 5.0f), - IC_WAITING_POS_HORDE.GetPositionY() + frand(-5.0f, 5.0f), - IC_WAITING_POS_HORDE.GetPositionZ()); - } + if (role == 9) // refinery + MoveTo(bg->GetMapId(), IC_WEST_WAITING_POS_HORDE.GetPositionX() + frand(-5.0f, 5.0f), + IC_WEST_WAITING_POS_HORDE.GetPositionY() + frand(-5.0f, 5.0f), + IC_WEST_WAITING_POS_HORDE.GetPositionZ()); + else if (role >= 3 && role < 6) // hanger + MoveTo(bg->GetMapId(), IC_EAST_WAITING_POS_HORDE.GetPositionX() + frand(-5.0f, 5.0f), + IC_EAST_WAITING_POS_HORDE.GetPositionY() + frand(-5.0f, 5.0f), + IC_EAST_WAITING_POS_HORDE.GetPositionZ()); + else // everything else + MoveTo(bg->GetMapId(), IC_WAITING_POS_HORDE.GetPositionX() + frand(-5.0f, 5.0f), + IC_WAITING_POS_HORDE.GetPositionY() + frand(-5.0f, 5.0f), IC_WAITING_POS_HORDE.GetPositionZ()); } else { - if (role < 3) - { - if (urand(0, 1)) - MoveTo(bg->GetMapId(), IC_SIDE_WAITING_POS_ALLIANCE.GetPositionX() + frand(-5.0f, 5.0f), - IC_SIDE_WAITING_POS_ALLIANCE.GetPositionY() + frand(-5.0f, 5.0f), - IC_SIDE_WAITING_POS_ALLIANCE.GetPositionZ()); - else - MoveTo(bg->GetMapId(), IC_WAITING_POS_ALLIANCE.GetPositionX() + frand(-5.0f, 5.0f), - IC_WAITING_POS_ALLIANCE.GetPositionY() + frand(-5.0f, 5.0f), - IC_WAITING_POS_ALLIANCE.GetPositionZ()); - } - else - { - if (urand(0, 1)) - MoveTo(bg->GetMapId(), IC_SIDE_WAITING_POS_ALLIANCE.GetPositionX() + frand(-5.0f, 5.0f), - IC_SIDE_WAITING_POS_ALLIANCE.GetPositionY() + frand(-5.0f, 5.0f), - IC_SIDE_WAITING_POS_ALLIANCE.GetPositionZ()); - else - MoveTo(bg->GetMapId(), IC_WAITING_POS_ALLIANCE.GetPositionX() + frand(-5.0f, 5.0f), - IC_WAITING_POS_ALLIANCE.GetPositionY() + frand(-5.0f, 5.0f), - IC_WAITING_POS_ALLIANCE.GetPositionZ()); - } + if (role < 3) // docks + MoveTo( + bg->GetMapId(), IC_WAITING_POS_ALLIANCE.GetPositionX() + frand(-5.0f, 5.0f), + IC_WAITING_POS_ALLIANCE.GetPositionY() + frand(-5.0f, 5.0f), + IC_WAITING_POS_ALLIANCE.GetPositionZ()); // dont bother using west, there's no paths to use anyway + else if (role == 9 || (role >= 3 && role < 6)) // quarry and hanger + MoveTo(bg->GetMapId(), IC_EAST_WAITING_POS_ALLIANCE.GetPositionX() + frand(-5.0f, 5.0f), + IC_EAST_WAITING_POS_ALLIANCE.GetPositionY() + frand(-5.0f, 5.0f), + IC_EAST_WAITING_POS_ALLIANCE.GetPositionZ()); + else // everything else + MoveTo(bg->GetMapId(), IC_WAITING_POS_ALLIANCE.GetPositionX() + frand(-5.0f, 5.0f), + IC_WAITING_POS_ALLIANCE.GetPositionY() + frand(-5.0f, 5.0f), + IC_WAITING_POS_ALLIANCE.GetPositionZ()); } } @@ -3238,7 +3333,6 @@ bool BGTactics::selectObjective(bool reset) { BattlegroundIC* isleOfConquestBG = (BattlegroundIC*)bg; - uint32 currentObjective = MAX_NODE_TYPES; uint32 role = context->GetValue("bg role")->Get(); bool inVehicle = botAI->IsInVehicle(); bool controlsVehicle = botAI->IsInVehicle(true); @@ -3251,421 +3345,306 @@ bool BGTactics::selectObjective(bool reset) /* TACTICS */ if (bot->GetTeamId() == TEAM_HORDE) // HORDE { - // If all bases are captured, go to enemy boss - bool allCaptured = true; - for (uint8 i = 0; i < MAX_NODE_TYPES; ++i) + bool gateOpen = false; + if (GameObject* pGO = bg->GetBGObject(BG_IC_GO_DOODAD_PORTCULLISACTIVE02)) { - // skip refinery and keep - if (i == NODE_TYPE_REFINERY || i == NODE_TYPE_GRAVEYARD_H) - continue; - - ICNodePoint const& nodePoint = isleOfConquestBG->GetICNodePoint(i); - if (nodePoint.nodeState != NODE_STATE_CONFLICT_H && nodePoint.nodeState != NODE_STATE_CONTROLLED_H) + if (pGO->isSpawned() && pGO->getLootState() == GO_ACTIVATED) { - allCaptured = false; - break; - } - } - - if (allCaptured) // target enemy boss - { - if (Creature* allyboss = bg->GetBGCreature(BG_IC_NPC_HIGH_COMMANDER_HALFORD_WYRMBANE)) - { - if (allyboss->IsVisible()) - { - BgObjective = allyboss; - // ostringstream out; - // out << "Attackign BOSS! BG objective set to " << BgObjective->GetName(); - // bot->Say(out.str(), LANG_UNIVERSAL); - } - } - } - - // If main bases are not captured, split tasks - if (!BgObjective) - { - bool foundTask = false; - // mount defensive cannons - if (role > 10) // disabled - { - uint32 firstTower = getPlayersInArea(bot->GetTeamId(), IC_CANNON_POS_HORDE1, 10.0f); - uint32 secondTower = getPlayersInArea(bot->GetTeamId(), IC_CANNON_POS_HORDE2, 10.0f); - - if (firstTower < 2) - { - pos.Set(IC_CANNON_POS_HORDE1.GetPositionX(), IC_CANNON_POS_HORDE1.GetPositionY(), - IC_CANNON_POS_HORDE1.GetPositionZ(), bg->GetMapId()); - posMap["bg objective"] = pos; - return true; - } - if (secondTower < 2) - { - pos.Set(IC_CANNON_POS_HORDE2.GetPositionX(), IC_CANNON_POS_HORDE2.GetPositionY(), - IC_CANNON_POS_HORDE2.GetPositionZ(), bg->GetMapId()); - posMap["bg objective"] = pos; - return true; - } - } - if (role < 3) // Capture Side base or Docks - { - // Capture Refinery - ICNodePoint const& nodePoint = isleOfConquestBG->GetICNodePoint(NODE_TYPE_REFINERY); - if (nodePoint.nodeState != NODE_STATE_CONFLICT_H && - nodePoint.nodeState != NODE_STATE_CONTROLLED_H) - { - BgObjective = bg->GetBGObject(BG_IC_GO_REFINERY_BANNER); - currentObjective = BG_IC_GO_REFINERY_BANNER; - foundTask = true; - } - } - - if (!BgObjective && role < 6 && urand(0, 1)) // Capture Docks - { - // Capture Docks - ICNodePoint const& nodePoint = isleOfConquestBG->GetICNodePoint(NODE_TYPE_DOCKS); - if (nodePoint.nodeState != NODE_STATE_CONFLICT_H && - nodePoint.nodeState != NODE_STATE_CONTROLLED_H) - { - if (GameObject* pGO = bg->GetBGObject(BG_IC_GO_DOCKS_BANNER)) - { - BgObjective = pGO; - currentObjective = BG_IC_GO_DOCKS_BANNER; - foundTask = true; - - // ostringstream out; - // out << "DOCKS! BG objective set to " << BgObjective->GetName(); - // bot->Say(out.str(), LANG_UNIVERSAL); - } - } - } - // If docks/side capped, help capture workshop - if (!BgObjective && role < 3) - { - ICNodePoint const& nodePoint = isleOfConquestBG->GetICNodePoint(NODE_TYPE_WORKSHOP); - if (nodePoint.nodeState != NODE_STATE_CONFLICT_H && - nodePoint.nodeState != NODE_STATE_CONTROLLED_H) - { - if (GameObject* pGO = bg->GetBGObject(BG_IC_GO_WORKSHOP_BANNER)) - { - BgObjective = pGO; - currentObjective = BG_IC_GO_WORKSHOP_BANNER; - foundTask = true; - - // ostringstream out; - // out << "WORKSHOP! BG objective set to " << BgObjective->GetName(); - // bot->Say(out.str(), LANG_UNIVERSAL); - } - } - } - if (!BgObjective && role < 6) // Capture Hangar - { - ICNodePoint const& nodePoint = isleOfConquestBG->GetICNodePoint(NODE_TYPE_HANGAR); - if (nodePoint.nodeState != NODE_STATE_CONFLICT_H && - nodePoint.nodeState != NODE_STATE_CONTROLLED_H) - { - if (GameObject* pGO = bg->GetBGObject(BG_IC_GO_HANGAR_BANNER)) - { - BgObjective = pGO; - currentObjective = BG_IC_GO_HANGAR_BANNER; - foundTask = true; - // ostringstream out; - // out << "HANGAR! BG objective set to " << BgObjective->GetName(); - // bot->Say(out.str(), LANG_UNIVERSAL); - } - } - } - bool gateOpen = false; - if (!BgObjective || controlsVehicle) // Check gates - { - // Keep Gates open if any wall is destroyed, check it - if (GameObject* pGO = bg->GetBGObject(BG_IC_GO_DOODAD_PORTCULLISACTIVE01)) - { - if (pGO->isSpawned() && pGO->getLootState() == GO_ACTIVATED) - { - gateOpen = true; - } - else - { - if (GameObject* gate = bg->GetBGObject(BG_IC_GO_ALLIANCE_GATE_3)) - { - if (controlsVehicle) - { - // come close to gate if siege engine - if (vehicleId == NPC_SIEGE_ENGINE_H) - { - BgObjective = gate; - } - else - { - // take a siege position - pos.Set(506.782f + frand(-5, +5), -828.594f + frand(-5, +5), 24.313f, - bot->GetMapId()); - posMap["bg objective"] = pos; - - // set siege position - PositionInfo siegePos = - context->GetValue("position")->Get()["bg siege"]; - siegePos.Set(gate->GetPositionX(), gate->GetPositionY(), - gate->GetPositionZ(), bot->GetMapId()); - posMap["bg siege"] = siegePos; - return true; - } - } - else - { - pos.Set(506.782f + frand(-5, +5), -828.594f + frand(-5, +5), 24.313f, - bot->GetMapId()); - posMap["bg objective"] = pos; - return true; - // BgObjective = gate; - } - } - } - } - } - if (!BgObjective && gateOpen) // Capture Keep - { - // reset siege position + gateOpen = true; PositionInfo siegePos = context->GetValue("position")->Get()["bg siege"]; siegePos.Reset(); posMap["bg siege"] = siegePos; - - ICNodePoint const& nodePoint = isleOfConquestBG->GetICNodePoint(NODE_TYPE_GRAVEYARD_A); - if (nodePoint.nodeState != NODE_STATE_CONFLICT_H && - nodePoint.nodeState != NODE_STATE_CONTROLLED_H) + } + } + if (gateOpen && !controlsVehicle && + isleOfConquestBG->GetICNodePoint(NODE_TYPE_GRAVEYARD_A).nodeState == + NODE_STATE_CONTROLLED_H) // target enemy boss + { + if (Creature* enemyBoss = bg->GetBGCreature(BG_IC_NPC_HIGH_COMMANDER_HALFORD_WYRMBANE)) + { + if (enemyBoss->IsVisible()) { - if (GameObject* pGO = bg->GetBGObject(BG_IC_GO_ALLIANCE_BANNER)) + BgObjective = enemyBoss; + // LOG_INFO("playerbots", "bot={} attack boss", bot->GetName()); + } + } + } + + if (!BgObjective && gateOpen && !controlsVehicle) + { + if (GameObject* pGO = bg->GetBGObject(BG_IC_GO_ALLIANCE_BANNER)) // capture flag within keep + { + BgObjective = pGO; + // LOG_INFO("playerbots", "bot={} attack keep", bot->GetName()); + } + } + + if (!BgObjective && !gateOpen && controlsVehicle) // attack gates + { + // TODO: check for free vehicles + if (GameObject* gate = bg->GetBGObject(BG_IC_GO_ALLIANCE_GATE_3)) + { + if (vehicleId == NPC_SIEGE_ENGINE_H) // target gate directly if siege engine + { + BgObjective = gate; + // LOG_INFO("playerbots", "bot={} (in siege-engine) attack gate", bot->GetName()); + } + else // target gate directly at range if other vehicle + { + // take a siege position + if (sqrt(bot->GetDistance(IC_GATE_ATTACK_POS_HORDE)) < + 5.0f) // just make bot stay where it is (stops them shifting around to the random + // spots) + pos.Set(bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(), bot->GetMapId()); + else + pos.Set(IC_GATE_ATTACK_POS_HORDE.GetPositionX() + frand(-5.0f, +5.0f), + IC_GATE_ATTACK_POS_HORDE.GetPositionY() + frand(-5.0f, +5.0f), + IC_GATE_ATTACK_POS_HORDE.GetPositionZ(), bot->GetMapId()); + posMap["bg objective"] = pos; + // set siege position + PositionInfo siegePos = context->GetValue("position")->Get()["bg siege"]; + siegePos.Set(gate->GetPositionX(), gate->GetPositionY(), gate->GetPositionZ(), + bot->GetMapId()); + posMap["bg siege"] = siegePos; + // LOG_INFO("playerbots", "bot={} (in vehicle={}) attack gate", bot->GetName(), vehicleId); + return true; + } + } + } + + // If gates arent down and not in vehicle, split tasks + if (!BgObjective && !controlsVehicle && role == 9) // Capture Side base + { + // Capture Refinery + ICNodePoint const& nodePoint = isleOfConquestBG->GetICNodePoint(NODE_TYPE_REFINERY); + if (nodePoint.nodeState != NODE_STATE_CONFLICT_H && nodePoint.nodeState != NODE_STATE_CONTROLLED_H) + { + BgObjective = bg->GetBGObject(BG_IC_GO_REFINERY_BANNER); + // LOG_INFO("playerbots", "bot={} attack refinery", bot->GetName()); + } + } + + if (!BgObjective && !controlsVehicle && role < 3) // Capture Docks + { + ICNodePoint const& nodePoint = isleOfConquestBG->GetICNodePoint(NODE_TYPE_DOCKS); + if (nodePoint.nodeState != NODE_STATE_CONFLICT_H && nodePoint.nodeState != NODE_STATE_CONTROLLED_H) + { + if (GameObject* pGO = bg->GetBGObject(BG_IC_GO_DOCKS_BANNER)) + { + BgObjective = pGO; + // LOG_INFO("playerbots", "bot={} attack docks", bot->GetName()); + } + } + } + if (!BgObjective && !controlsVehicle && role < 6) // Capture Hangar + { + ICNodePoint const& nodePoint = isleOfConquestBG->GetICNodePoint(NODE_TYPE_HANGAR); + if (nodePoint.nodeState != NODE_STATE_CONFLICT_H && nodePoint.nodeState != NODE_STATE_CONTROLLED_H) + { + if (GameObject* pGO = bg->GetBGObject(BG_IC_GO_HANGAR_BANNER)) + { + BgObjective = pGO; + // LOG_INFO("playerbots", "bot={} attack hangar", bot->GetName()); + } + } + } + if (!BgObjective && !controlsVehicle) // Capture Workshop + { + ICNodePoint const& nodePoint = isleOfConquestBG->GetICNodePoint(NODE_TYPE_WORKSHOP); + if (nodePoint.nodeState != NODE_STATE_CONFLICT_H && nodePoint.nodeState != NODE_STATE_CONTROLLED_H) + { + if (GameObject* pGO = bg->GetBGObject(BG_IC_GO_WORKSHOP_BANNER)) + { + BgObjective = pGO; + // LOG_INFO("playerbots", "bot={} attack workshop", bot->GetName()); + } + } + } + if (!BgObjective) // Guard point that's not fully capped (also gets them in place to board vehicle) + { + uint32 len = end(IC_AttackObjectives) - begin(IC_AttackObjectives); + for (uint32 i = 0; i < len; i++) + { + const auto& objective = + IC_AttackObjectives[(i + role) % + len]; // use role to determine which objective checked first + if (isleOfConquestBG->GetICNodePoint(objective.first).nodeState != NODE_STATE_CONTROLLED_H) + { + if (GameObject* pGO = bg->GetBGObject(objective.second)) { BgObjective = pGO; - currentObjective = BG_IC_GO_ALLIANCE_BANNER; - foundTask = true; - - // ostringstream out; - // out << "ALLY KEEP! BG objective set to " << BgObjective->GetName(); - // bot->Say(out.str(), LANG_UNIVERSAL); + // LOG_INFO("playerbots", "bot={} guard point while it captures", bot->GetName()); + break; } } } } + if (!BgObjective) // guard vehicles as they seige + + { + if (sqrt(bot->GetDistance(IC_GATE_ATTACK_POS_HORDE)) < + 5.0f) // just make bot stay where it is (stops them shifting around to the random spots) + pos.Set(bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(), bot->GetMapId()); + else + pos.Set(IC_GATE_ATTACK_POS_HORDE.GetPositionX() + frand(-5.0f, +5.0f), + IC_GATE_ATTACK_POS_HORDE.GetPositionY() + frand(-5.0f, +5.0f), + IC_GATE_ATTACK_POS_HORDE.GetPositionZ(), bot->GetMapId()); + posMap["bg objective"] = pos; + // LOG_INFO("playerbots", "bot={} guard vehicles as they attack gate", bot->GetName()); + return true; + } } if (bot->GetTeamId() == TEAM_ALLIANCE) // ALLIANCE { - // If all bases are captured, go to enemy boss - bool allCaptured = true; - for (uint8 i = 0; i < MAX_NODE_TYPES; ++i) + bool gateOpen = false; + if (GameObject* pGO = bg->GetBGObject(BG_IC_GO_HORDE_KEEP_PORTCULLIS)) { - // skip quarry and keep - if (i == NODE_TYPE_QUARRY || i == NODE_TYPE_GRAVEYARD_A) - continue; - - ICNodePoint const& nodePoint = isleOfConquestBG->GetICNodePoint(i); - if (nodePoint.nodeState != NODE_STATE_CONFLICT_A && nodePoint.nodeState != NODE_STATE_CONTROLLED_A) + if (pGO->isSpawned() && pGO->getLootState() == GO_ACTIVATED) { - allCaptured = false; - break; - } - } - - if (allCaptured) // target enemy boss - { - if (Creature* hordeboss = bg->GetBGCreature(BG_IC_NPC_OVERLORD_AGMAR)) - { - if (!hordeboss->IsVisible()) - { - BgObjective = hordeboss; - // ostringstream out; - // out << "HORDE BOSS! BG objective set to " << BgObjective->GetName(); - // bot->Say(out.str(), LANG_UNIVERSAL); - } - } - } - - // If main bases are not captured, split tasks - if (!BgObjective) - { - bool foundTask = false; - // mount defensive cannons - if (role > 10) // disabled - { - uint32 firstTower = getPlayersInArea(bot->GetTeamId(), IC_CANNON_POS_ALLIANCE1, 10.0f); - uint32 secondTower = getPlayersInArea(bot->GetTeamId(), IC_CANNON_POS_ALLIANCE2, 10.0f); - - if (firstTower < 3) - { - pos.Set(IC_CANNON_POS_ALLIANCE1.GetPositionX(), IC_CANNON_POS_ALLIANCE1.GetPositionY(), - IC_CANNON_POS_ALLIANCE1.GetPositionZ(), bg->GetMapId()); - posMap["bg objective"] = pos; - return true; - } - if (secondTower < 3) - { - pos.Set(IC_CANNON_POS_ALLIANCE2.GetPositionX(), IC_CANNON_POS_ALLIANCE2.GetPositionY(), - IC_CANNON_POS_ALLIANCE2.GetPositionZ(), bg->GetMapId()); - posMap["bg objective"] = pos; - return true; - } - } - - if (role < 3) // Capture Side base or Docks - { - // Capture Quarry - ICNodePoint const& nodePoint = isleOfConquestBG->GetICNodePoint(NODE_TYPE_QUARRY); - if (nodePoint.nodeState != NODE_STATE_CONFLICT_A && - nodePoint.nodeState != NODE_STATE_CONTROLLED_A) - { - if (GameObject* pGO = bg->GetBGObject(BG_IC_GO_QUARRY_BANNER)) - { - BgObjective = pGO; - currentObjective = BG_IC_GO_QUARRY_BANNER; - foundTask = true; - - // ostringstream out; - // out << "QUARRY! BG objective set to " << BgObjective->GetName(); - // bot->Say(out.str(), LANG_UNIVERSAL); - } - } - } - // take position at cannon - /*if (!BgObjective) - { - if (GameObject* pGO = bg->interactwith(BG_IC_VEHICLE_KEEP_CANNON)) - { - if (sServerFacade->isSpawned(pGO) && pGO->GetLootState() == GO_READY) - isCapping = true; - } - }*/ - if (!BgObjective && role < 6 && urand(0, 1)) - { - // Capture Docks - ICNodePoint const& nodePoint = isleOfConquestBG->GetICNodePoint(NODE_TYPE_DOCKS); - if (nodePoint.nodeState != NODE_STATE_CONFLICT_A && - nodePoint.nodeState != NODE_STATE_CONTROLLED_A) - { - if (GameObject* pGO = bg->GetBGObject(BG_IC_GO_DOCKS_BANNER)) - { - BgObjective = pGO; - currentObjective = BG_IC_GO_DOCKS_BANNER; - foundTask = true; - - // ostringstream out; - // out << "DOCKS! BG objective set to " << BgObjective->GetName(); - // bot->Say(out.str(), LANG_UNIVERSAL); - } - } - } - // If docks/side capped, help capture workshop - if (!BgObjective && role < 3) - { - ICNodePoint const& nodePoint = isleOfConquestBG->GetICNodePoint(NODE_TYPE_WORKSHOP); - if (nodePoint.nodeState != NODE_STATE_CONFLICT_A && - nodePoint.nodeState != NODE_STATE_CONTROLLED_A) - { - if (GameObject* pGO = bg->GetBGObject(BG_IC_GO_WORKSHOP_BANNER)) - { - BgObjective = pGO; - currentObjective = BG_IC_GO_WORKSHOP_BANNER; - foundTask = true; - - // ostringstream out; - // out << "WORKSHOP! BG objective set to " << BgObjective->GetName(); - // bot->Say(out.str(), LANG_UNIVERSAL); - } - } - } - if (!BgObjective && role < 6) // Capture Hangar - { - ICNodePoint const& nodePoint = isleOfConquestBG->GetICNodePoint(NODE_TYPE_HANGAR); - if (nodePoint.nodeState != NODE_STATE_CONFLICT_A && - nodePoint.nodeState != NODE_STATE_CONTROLLED_A) - { - if (GameObject* pGO = bg->GetBGObject(BG_IC_GO_HANGAR_BANNER)) - { - BgObjective = pGO; - currentObjective = BG_IC_GO_HANGAR_BANNER; - foundTask = true; - - // ostringstream out; - // out << "HANGAR! BG objective set to " << BgObjective->GetName(); - // bot->Say(out.str(), LANG_UNIVERSAL); - } - } - } - - bool gateOpen = false; - if (!BgObjective || controlsVehicle) // Check gates - { - // Keep Gates open if any wall is destroyed, check it - if (GameObject* pGO = bg->GetBGObject(BG_IC_GO_HORDE_KEEP_PORTCULLIS)) - { - if (pGO->isSpawned() && pGO->getLootState() == GO_ACTIVATED) - { - gateOpen = true; - } - else - { - if (GameObject* gate = bg->GetBGObject(BG_IC_GO_HORDE_GATE_3)) - { - if (controlsVehicle) - { - // come close to gate if siege engine - if (vehicleId == NPC_SIEGE_ENGINE_A) - { - BgObjective = gate; - } - else - { - // take a siege position - pos.Set(1091.273f + frand(-5, +5), -763.619f + frand(-5, +5), 42.352f, - bot->GetMapId()); - posMap["bg objective"] = pos; - - // set siege position - PositionInfo siegePos = - context->GetValue("position")->Get()["bg siege"]; - siegePos.Set(gate->GetPositionX(), gate->GetPositionY(), - gate->GetPositionZ(), bot->GetMapId()); - posMap["bg siege"] = siegePos; - return true; - } - } - else - { - pos.Set(1091.273f + frand(-5, +5), -763.619f + frand(-5, +5), 42.352f, - bot->GetMapId()); - posMap["bg objective"] = pos; - return true; - // take a siege position - // BgObjective = gate; - } - } - } - } - } - if (!BgObjective && gateOpen) // Capture Keep - { - // reset siege position + gateOpen = true; PositionInfo siegePos = context->GetValue("position")->Get()["bg siege"]; siegePos.Reset(); posMap["bg siege"] = siegePos; + } + } - ICNodePoint const& nodePoint = isleOfConquestBG->GetICNodePoint(NODE_TYPE_GRAVEYARD_H); - if (nodePoint.nodeState != NODE_STATE_CONFLICT_A && - nodePoint.nodeState != NODE_STATE_CONTROLLED_A) + if (gateOpen && !controlsVehicle && + isleOfConquestBG->GetICNodePoint(NODE_TYPE_GRAVEYARD_H).nodeState == + NODE_STATE_CONTROLLED_A) // target enemy boss + { + if (Creature* enemyBoss = bg->GetBGCreature(BG_IC_NPC_OVERLORD_AGMAR)) + { + if (enemyBoss->IsVisible()) { - if (GameObject* pGO = bg->GetBGObject(BG_IC_GO_HORDE_BANNER)) + BgObjective = enemyBoss; + // LOG_INFO("playerbots", "bot={} attack boss", bot->GetName()); + } + } + } + + if (!BgObjective && gateOpen && !controlsVehicle) + { + if (GameObject* pGO = bg->GetBGObject(BG_IC_GO_HORDE_BANNER)) // capture flag within keep + { + BgObjective = pGO; + // LOG_INFO("playerbots", "bot={} attack keep", bot->GetName()); + } + } + + if (!BgObjective && !gateOpen && controlsVehicle) // attack gates + { + // TODO: check for free vehicles + if (GameObject* gate = bg->GetBGObject(BG_IC_GO_HORDE_GATE_1)) + { + if (vehicleId == NPC_SIEGE_ENGINE_A) // target gate directly if siege engine + { + BgObjective = gate; + // LOG_INFO("playerbots", "bot={} (in siege-engine) attack gate", bot->GetName()); + } + else // target gate directly at range if other vehicle + { + // take a siege position + if (sqrt(bot->GetDistance(IC_GATE_ATTACK_POS_ALLIANCE)) < + 5.0f) // just make bot stay where it is (stops them shifting around to the random + // spots) + pos.Set(bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(), bot->GetMapId()); + else + pos.Set(IC_GATE_ATTACK_POS_ALLIANCE.GetPositionX() + frand(-5.0f, +5.0f), + IC_GATE_ATTACK_POS_ALLIANCE.GetPositionY() + frand(-5.0f, +5.0f), + IC_GATE_ATTACK_POS_ALLIANCE.GetPositionZ(), bot->GetMapId()); + posMap["bg objective"] = pos; + // set siege position + PositionInfo siegePos = context->GetValue("position")->Get()["bg siege"]; + siegePos.Set(gate->GetPositionX(), gate->GetPositionY(), gate->GetPositionZ(), + bot->GetMapId()); + posMap["bg siege"] = siegePos; + // LOG_INFO("playerbots", "bot={} (in vehicle={}) attack gate", bot->GetName(), vehicleId); + return true; + } + } + } + + // If gates arent down and not in vehicle, split tasks + if (!BgObjective && !controlsVehicle && role == 9) // Capture Side base + { + // Capture Refinery + ICNodePoint const& nodePoint = isleOfConquestBG->GetICNodePoint(NODE_TYPE_QUARRY); + if (nodePoint.nodeState != NODE_STATE_CONFLICT_A && nodePoint.nodeState != NODE_STATE_CONTROLLED_A) + { + BgObjective = bg->GetBGObject(BG_IC_GO_QUARRY_BANNER); + // LOG_INFO("playerbots", "bot={} attack quarry", bot->GetName()); + } + } + + if (!BgObjective && !controlsVehicle && role < 3) // Capture Docks + { + ICNodePoint const& nodePoint = isleOfConquestBG->GetICNodePoint(NODE_TYPE_DOCKS); + if (nodePoint.nodeState != NODE_STATE_CONFLICT_A && nodePoint.nodeState != NODE_STATE_CONTROLLED_A) + { + if (GameObject* pGO = bg->GetBGObject(BG_IC_GO_DOCKS_BANNER)) + { + BgObjective = pGO; + // LOG_INFO("playerbots", "bot={} attack docks", bot->GetName()); + } + } + } + if (!BgObjective && !controlsVehicle && role < 6) // Capture Hangar + { + ICNodePoint const& nodePoint = isleOfConquestBG->GetICNodePoint(NODE_TYPE_HANGAR); + if (nodePoint.nodeState != NODE_STATE_CONFLICT_A && nodePoint.nodeState != NODE_STATE_CONTROLLED_A) + { + if (GameObject* pGO = bg->GetBGObject(BG_IC_GO_HANGAR_BANNER)) + { + BgObjective = pGO; + // LOG_INFO("playerbots", "bot={} attack hangar", bot->GetName()); + } + } + } + if (!BgObjective && !controlsVehicle) // Capture Workshop + { + ICNodePoint const& nodePoint = isleOfConquestBG->GetICNodePoint(NODE_TYPE_WORKSHOP); + if (nodePoint.nodeState != NODE_STATE_CONFLICT_A && nodePoint.nodeState != NODE_STATE_CONTROLLED_A) + { + if (GameObject* pGO = bg->GetBGObject(BG_IC_GO_WORKSHOP_BANNER)) + { + BgObjective = pGO; + // LOG_INFO("playerbots", "bot={} attack workshop", bot->GetName()); + } + } + } + if (!BgObjective) // Guard point that's not fully capped (also gets them in place to board vehicle) + { + uint32 len = end(IC_AttackObjectives) - begin(IC_AttackObjectives); + for (uint32 i = 0; i < len; i++) + { + const auto& objective = + IC_AttackObjectives[(i + role) % + len]; // use role to determine which objective checked first + if (isleOfConquestBG->GetICNodePoint(objective.first).nodeState != NODE_STATE_CONTROLLED_H) + { + if (GameObject* pGO = bg->GetBGObject(objective.second)) { BgObjective = pGO; - currentObjective = BG_IC_GO_HORDE_BANNER; - foundTask = true; - - // ostringstream out; - // out << "HORDE KEEP! BG objective set to " << BgObjective->GetName(); - // bot->Say(out.str(), LANG_UNIVERSAL); + // LOG_INFO("playerbots", "bot={} guard point while it captures", bot->GetName()); + break; } } } } + if (!BgObjective) // guard vehicles as they seige + { + if (sqrt(bot->GetDistance(IC_GATE_ATTACK_POS_ALLIANCE)) < + 5.0f) // just make bot stay where it is (stops them shifting around to the random spots) + pos.Set(bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(), bot->GetMapId()); + else + pos.Set(IC_GATE_ATTACK_POS_ALLIANCE.GetPositionX() + frand(-5.0f, +5.0f), + IC_GATE_ATTACK_POS_ALLIANCE.GetPositionY() + frand(-5.0f, +5.0f), + IC_GATE_ATTACK_POS_ALLIANCE.GetPositionZ(), bot->GetMapId()); + posMap["bg objective"] = pos; + // LOG_INFO("playerbots", "bot={} guard vehicles as they attack gate", bot->GetName()); + return true; + } } if (BgObjective) @@ -3784,7 +3763,10 @@ bool BGTactics::selectObjectiveWp(std::vector const& vPaths) // distance from bot - makes distance from bot more signifcant than distance from destination) if (bgType == BATTLEGROUND_IC) - botDistanceLimit = 80.0f; + { + // botDistanceLimit = 80.0f; + botDistanceScoreMultiply = 8.0f; + } else if (bgType == BATTLEGROUND_AB || bgType == BATTLEGROUND_EY) { botDistanceScoreSubtract = 2.0f; @@ -3879,7 +3861,9 @@ bool BGTactics::resetObjective() // sometimes change role - should do so less often on larger BG's otherwise bots will spend too much time running // around map instead of doing something useful - uint32 rollChangeOdds = BATTLEGROUND_AV == bg->GetBgTypeID() ? 63 : BATTLEGROUND_EY == bg->GetBgTypeID() ? 31 : 5; + uint32 rollChangeOdds = BATTLEGROUND_AV == bg->GetBgTypeID() ? 63 + : BATTLEGROUND_EY == bg->GetBgTypeID() || BATTLEGROUND_IC == bg->GetBgTypeID() ? 31 + : 5; if (!urand(0, rollChangeOdds) && !(bot->HasAura(BG_WS_SPELL_WARSONG_FLAG) || bot->HasAura(BG_WS_SPELL_SILVERWING_FLAG) || bot->HasAura(BG_EY_NETHERSTORM_FLAG_SPELL))) @@ -3900,9 +3884,11 @@ bool BGTactics::moveToObjectiveWp(BattleBotPath* const& currentPath, uint32 curr uint32 const lastPointInPath = reverse ? 0 : ((*currentPath).size() - 1); + // NOTE: can't use IsInCombat() when in vehicle as player is stuck in combat forever while in vehicle (ac bug?) + bool inCombat = bot->GetVehicle() ? (bool)AI_VALUE(Unit*, "enemy player target") : bot->IsInCombat(); if ((currentPoint == lastPointInPath) || - (bot->IsInCombat() && !(bot->HasAura(BG_WS_SPELL_WARSONG_FLAG) || bot->HasAura(BG_WS_SPELL_SILVERWING_FLAG) || - bot->HasAura(BG_EY_NETHERSTORM_FLAG_SPELL))) || + (inCombat && !(bot->HasAura(BG_WS_SPELL_WARSONG_FLAG) || bot->HasAura(BG_WS_SPELL_SILVERWING_FLAG) || + bot->HasAura(BG_EY_NETHERSTORM_FLAG_SPELL))) || !bot->IsAlive()) { // Path is over. diff --git a/src/strategy/actions/MovementActions.cpp b/src/strategy/actions/MovementActions.cpp index 52310f76..c9b825f6 100644 --- a/src/strategy/actions/MovementActions.cpp +++ b/src/strategy/actions/MovementActions.cpp @@ -177,6 +177,28 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle, { return false; } + + if (Vehicle* vehicle = bot->GetVehicle()) + { + VehicleSeatEntry const* seat = vehicle->GetSeatForPassenger(bot); + Unit* vehicleBase = vehicle->GetBase(); + if (!vehicleBase || !seat || !seat->CanControl()) // is passenger and cant move anyway + return false; + + float distance = vehicleBase->GetExactDist(x, y, z); + if (distance <= sPlayerbotAIConfig->contactDistance) + return false; + + MotionMaster& mm = *vehicleBase->GetMotionMaster(); // need to move vehicle, not bot + mm.Clear(); + mm.MovePoint(mapId, x, y, z, generatePath); + + float delay = 1000.0f * (distance / vehicleBase->GetSpeed(MOVE_RUN)) - sPlayerbotAIConfig->reactDelay; + delay = std::max(.0f, delay); + delay = std::min((float)sPlayerbotAIConfig->maxWaitForMove, delay); + AI_VALUE(LastMovement&, "last movement").Set(mapId, x, y, z, bot->GetOrientation(), delay); + return true; + } // if (bot->Unit::IsFalling()) { // bot->Say("I'm falling!, flag:" + std::to_string(bot->m_movementInfo.GetMovementFlags()), LANG_UNIVERSAL); // return false; diff --git a/src/strategy/actions/ReleaseSpiritAction.cpp b/src/strategy/actions/ReleaseSpiritAction.cpp index 64521c4e..0d1ad8b6 100644 --- a/src/strategy/actions/ReleaseSpiritAction.cpp +++ b/src/strategy/actions/ReleaseSpiritAction.cpp @@ -119,7 +119,11 @@ bool AutoReleaseSpiritAction::Execute(Event event) } if (bot->GetDistance(unit) >= INTERACTION_DISTANCE) { - bot->GetMotionMaster()->MoveChase(unit); + // bot needs to actually click spirit-healer in BG to get res timer going + // and in IOC it's not within clicking range when they res in own base + MotionMaster& mm = *bot->GetMotionMaster(); + mm.Clear(); + mm.MovePoint(bot->GetMapId(), unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZ(), true); } else { diff --git a/src/strategy/actions/VehicleActions.cpp b/src/strategy/actions/VehicleActions.cpp index b036a036..2fc09cb3 100644 --- a/src/strategy/actions/VehicleActions.cpp +++ b/src/strategy/actions/VehicleActions.cpp @@ -5,11 +5,16 @@ #include "VehicleActions.h" +#include "BattlegroundIC.h" #include "ItemVisitors.h" #include "Playerbots.h" #include "ServerFacade.h" #include "Vehicle.h" +// TODO methods to enter/exit vehicle should be added to BGTactics or MovementAction (so that we can better control +// whether bot is in vehicle, eg: get out of vehicle to cap flag, if we're down to final boss, etc), +// right now they will enter vehicle based only what's available here, then they're stuck in vehicle until they die +// (LeaveVehicleAction doesnt do much seeing as they, or another bot, will get in immediately after exit) bool EnterVehicleAction::Execute(Event event) { // do not switch vehicles yet @@ -21,21 +26,31 @@ bool EnterVehicleAction::Execute(Event event) { Unit* vehicleBase = botAI->GetUnit(*i); if (!vehicleBase) - return false; + continue; + + // dont let them get in the cannons as they'll stay forever and do nothing useful + // dont let them in catapult they cant use them at all + if (NPC_KEEP_CANNON == vehicleBase->GetEntry() || NPC_CATAPULT == vehicleBase->GetEntry()) + continue; if (!vehicleBase->IsFriendlyTo(bot)) - return false; + continue; if (!vehicleBase->GetVehicleKit()->GetAvailableSeatCount()) - return false; + continue; - if (fabs(bot->GetPositionZ() - vehicleBase->GetPositionZ()) < 20.0f) + // this will avoid adding passengers (which dont really do much for the IOC vehicles which is the only place + // this code is used) + if (vehicleBase->GetVehicleKit()->IsVehicleInUse()) + continue; - // if (sServerFacade->GetDistance2d(bot, vehicle) > 100.0f) - // continue; + // if (fabs(bot->GetPositionZ() - vehicleBase->GetPositionZ()) < 20.0f) - if (sServerFacade->GetDistance2d(bot, vehicleBase) > 10.0f) - return MoveTo(vehicleBase, INTERACTION_DISTANCE); + // if (sServerFacade->GetDistance2d(bot, vehicle) > 100.0f) + // continue; + + if (sServerFacade->GetDistance2d(bot, vehicleBase) > INTERACTION_DISTANCE) + return MoveTo(vehicleBase, INTERACTION_DISTANCE - 1.0f); bot->EnterVehicle(vehicleBase); diff --git a/src/strategy/generic/BattlegroundStrategy.cpp b/src/strategy/generic/BattlegroundStrategy.cpp index 2a74b2f0..5a99cedd 100644 --- a/src/strategy/generic/BattlegroundStrategy.cpp +++ b/src/strategy/generic/BattlegroundStrategy.cpp @@ -99,8 +99,9 @@ void IsleStrategy::InitTriggers(std::vector& triggers) new TriggerNode("in vehicle", NextAction::array(0, new NextAction("incendiary rocket", 70.0f), nullptr))); triggers.push_back( new TriggerNode("in vehicle", NextAction::array(0, new NextAction("rocket blast", 70.0f), nullptr))); - triggers.push_back( - new TriggerNode("in vehicle", NextAction::array(0, new NextAction("blade salvo", 71.0f), nullptr))); + // this is bugged: it doesn't work, and stops glaive throw working (which is needed to take down gate) + // triggers.push_back( + // new TriggerNode("in vehicle", NextAction::array(0, new NextAction("blade salvo", 71.0f), nullptr))); triggers.push_back( new TriggerNode("in vehicle", NextAction::array(0, new NextAction("glaive throw", 70.0f), nullptr))); } diff --git a/src/strategy/values/EnemyPlayerValue.cpp b/src/strategy/values/EnemyPlayerValue.cpp index ba346a47..5302bde2 100644 --- a/src/strategy/values/EnemyPlayerValue.cpp +++ b/src/strategy/values/EnemyPlayerValue.cpp @@ -7,6 +7,7 @@ #include "Playerbots.h" #include "ServerFacade.h" +#include "Vehicle.h" bool NearestEnemyPlayersValue::AcceptUnit(Unit* unit) { @@ -25,7 +26,19 @@ bool NearestEnemyPlayersValue::AcceptUnit(Unit* unit) Unit* EnemyPlayerValue::Calculate() { - bool inCannon = botAI->IsInVehicle(false, true); + bool controllingCannon = false; + bool controllingVehicle = false; + if (Vehicle* vehicle = bot->GetVehicle()) + { + VehicleSeatEntry const* seat = vehicle->GetSeatForPassenger(bot); + if (!seat || !seat->CanControl()) // not in control of vehicle so cant attack anyone + return nullptr; + VehicleEntry const* vi = vehicle->GetVehicleInfo(); + if (vi && vi->m_flags & VEHICLE_FLAG_FIXED_POSITION) + controllingCannon = true; + else + controllingVehicle = true; + } // 1. Check units we are currently in combat with. std::vector targets; @@ -95,12 +108,15 @@ Unit* EnemyPlayerValue::Calculate() } // Aggro weak enemies from further away. - uint32 const aggroDistance = (inCannon || bot->GetHealth() > pTarget->GetHealth()) ? maxAggroDistance : 20.0f; + // If controlling mobile vehicle only agro close enemies (otherwise will never reach objective) + uint32 const aggroDistance = controllingVehicle ? 5.0f + : (controllingCannon || bot->GetHealth() > pTarget->GetHealth()) ? maxAggroDistance + : 20.0f; if (!bot->IsWithinDist(pTarget, aggroDistance)) continue; if (bot->IsWithinLOSInMap(pTarget) && - (inCannon || (fabs(bot->GetPositionZ() - pTarget->GetPositionZ()) < 30.0f))) + (controllingCannon || (fabs(bot->GetPositionZ() - pTarget->GetPositionZ()) < 30.0f))) return pTarget; } diff --git a/src/strategy/values/NearestNpcsValue.cpp b/src/strategy/values/NearestNpcsValue.cpp index c0c21509..cbbc8894 100644 --- a/src/strategy/values/NearestNpcsValue.cpp +++ b/src/strategy/values/NearestNpcsValue.cpp @@ -32,7 +32,7 @@ bool NearestVehiclesValue::AcceptUnit(Unit* unit) if (!unit || !unit->IsVehicle() || !unit->IsAlive()) return false; - Vehicle* veh = unit->GetVehicle(); + Vehicle* veh = unit->GetVehicleKit(); if (!veh || !veh->GetAvailableSeatCount()) return false; From 5ce49299c463fc2aabc4ed24c963f52d97a1cbbe Mon Sep 17 00:00:00 2001 From: Fuzz Date: Tue, 6 Aug 2024 19:56:20 +1000 Subject: [PATCH 2/6] cleaned up movement code (and left comment for liyunfan) --- src/strategy/actions/MovementActions.cpp | 44 ++++++++++++------------ 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/strategy/actions/MovementActions.cpp b/src/strategy/actions/MovementActions.cpp index c9b825f6..98018f6d 100644 --- a/src/strategy/actions/MovementActions.cpp +++ b/src/strategy/actions/MovementActions.cpp @@ -178,27 +178,6 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle, return false; } - if (Vehicle* vehicle = bot->GetVehicle()) - { - VehicleSeatEntry const* seat = vehicle->GetSeatForPassenger(bot); - Unit* vehicleBase = vehicle->GetBase(); - if (!vehicleBase || !seat || !seat->CanControl()) // is passenger and cant move anyway - return false; - - float distance = vehicleBase->GetExactDist(x, y, z); - if (distance <= sPlayerbotAIConfig->contactDistance) - return false; - - MotionMaster& mm = *vehicleBase->GetMotionMaster(); // need to move vehicle, not bot - mm.Clear(); - mm.MovePoint(mapId, x, y, z, generatePath); - - float delay = 1000.0f * (distance / vehicleBase->GetSpeed(MOVE_RUN)) - sPlayerbotAIConfig->reactDelay; - delay = std::max(.0f, delay); - delay = std::min((float)sPlayerbotAIConfig->maxWaitForMove, delay); - AI_VALUE(LastMovement&, "last movement").Set(mapId, x, y, z, bot->GetOrientation(), delay); - return true; - } // if (bot->Unit::IsFalling()) { // bot->Say("I'm falling!, flag:" + std::to_string(bot->m_movementInfo.GetMovementFlags()), LANG_UNIVERSAL); // return false; @@ -212,7 +191,28 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle, bool generatePath = !bot->IsFlying() && !bot->isSwimming(); bool disableMoveSplinePath = sPlayerbotAIConfig->disableMoveSplinePath >= 2 || (sPlayerbotAIConfig->disableMoveSplinePath == 1 && bot->InBattleground()); - if (exact_waypoint || disableMoveSplinePath || !generatePath) + if (Vehicle* vehicle = bot->GetVehicle()) + { + VehicleSeatEntry const* seat = vehicle->GetSeatForPassenger(bot); + Unit* vehicleBase = vehicle->GetBase(); + if (!vehicleBase || !seat || !seat->CanControl()) // is passenger and cant move anyway + return false; + + float distance = vehicleBase->GetExactDist(x, y, z); // use vehicle distance, not bot + if (distance > sPlayerbotAIConfig->contactDistance) + { + MotionMaster& mm = *vehicleBase->GetMotionMaster(); // need to move vehicle, not bot + mm.Clear(); + mm.MovePoint(mapId, x, y, z, generatePath); + float delay = 1000.0f * (distance / vehicleBase->GetSpeed(MOVE_RUN)) - sPlayerbotAIConfig->reactDelay; + delay = std::max(.0f, delay); + delay = std::min((float)sPlayerbotAIConfig->maxWaitForMove, delay); + AI_VALUE(LastMovement&, "last movement").Set(mapId, x, y, z, bot->GetOrientation(), delay); + // TODO: is botAI->SetNextCheckDelay() meant to go here or is setting "last movement" value enough? (same question goes for below) + return true; + } + } + else if (exact_waypoint || disableMoveSplinePath || !generatePath) { float distance = bot->GetExactDist(x, y, z); if (distance > sPlayerbotAIConfig->contactDistance) From 45ebef049ffce852a71a74e35ca1ce7a4a80dc32 Mon Sep 17 00:00:00 2001 From: Fuzz Date: Tue, 6 Aug 2024 22:21:55 +1000 Subject: [PATCH 3/6] [Battlegrounds] wsg pathing fix for #442 --- src/strategy/actions/BattleGroundTactics.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/strategy/actions/BattleGroundTactics.cpp b/src/strategy/actions/BattleGroundTactics.cpp index 7b28a19d..4b15eeee 100644 --- a/src/strategy/actions/BattleGroundTactics.cpp +++ b/src/strategy/actions/BattleGroundTactics.cpp @@ -2053,13 +2053,13 @@ bool BGTactics::wsgPaths() return true; } - if (bot->GetPositionX() > 1071.f) // move the ramp up a piece + if (bot->GetPositionX() > 1059.f) // move the ramp up a piece { - MoveTo(bg->GetMapId(), 1070.089478f, 1538.054443f, 332.460388f); + MoveTo(bg->GetMapId(), 1057.551f, 1546.271f, 326.864f); return true; } - if (bot->GetPositionX() > 1050.2f) // move the ramp up a piece + if (bot->GetPositionX() > 1051.2f) // move the ramp up a piece { MoveTo(bg->GetMapId(), 1050.089478f, 1538.054443f, 332.460388f); return true; From 901ae2305c5d107417976d0344d5751074c2d32e Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Wed, 7 Aug 2024 15:47:29 +0800 Subject: [PATCH 4/6] Fix gear quality issue for random bots --- src/RandomPlayerbotMgr.cpp | 3 +-- src/strategy/actions/AutoLearnSpellAction.cpp | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/RandomPlayerbotMgr.cpp b/src/RandomPlayerbotMgr.cpp index e6704884..2655052c 100644 --- a/src/RandomPlayerbotMgr.cpp +++ b/src/RandomPlayerbotMgr.cpp @@ -1815,8 +1815,7 @@ void RandomPlayerbotMgr::Refresh(Player* bot) bot->DurabilityRepairAll(false, 1.0f, false); bot->SetFullHealth(); bot->SetPvP(true); - - PlayerbotFactory factory(bot, bot->GetLevel(), ITEM_QUALITY_RARE); + PlayerbotFactory factory(bot, bot->GetLevel()); factory.Refresh(); if (bot->GetMaxPower(POWER_MANA) > 0) diff --git a/src/strategy/actions/AutoLearnSpellAction.cpp b/src/strategy/actions/AutoLearnSpellAction.cpp index e75945f6..4415eb5d 100644 --- a/src/strategy/actions/AutoLearnSpellAction.cpp +++ b/src/strategy/actions/AutoLearnSpellAction.cpp @@ -210,7 +210,7 @@ bool AutoUpgradeEquipAction::Execute(Event event) { return false; } - PlayerbotFactory factory(bot, bot->GetLevel(), ITEM_QUALITY_RARE); + PlayerbotFactory factory(bot, bot->GetLevel()); if (!sPlayerbotAIConfig->equipmentPersistence || bot->GetLevel() < sPlayerbotAIConfig->equipmentPersistenceLevel) { factory.InitEquipment(true); From 27c5d6b19cb187d5e2f7bf568aaaf8a702a41378 Mon Sep 17 00:00:00 2001 From: Fuzz Date: Wed, 7 Aug 2024 23:40:19 +1000 Subject: [PATCH 5/6] [Battlegrounds] fix for #424 - flag carrier not fighting back when enemy has flag too and bot is hiding --- src/strategy/actions/BattleGroundTactics.cpp | 19 +++++---- src/strategy/actions/ChooseTargetActions.cpp | 9 ++--- src/strategy/actions/VehicleActions.cpp | 11 +++--- src/strategy/triggers/PvpTriggers.cpp | 41 +++++++++++++++++--- src/strategy/triggers/PvpTriggers.h | 3 ++ 5 files changed, 59 insertions(+), 24 deletions(-) diff --git a/src/strategy/actions/BattleGroundTactics.cpp b/src/strategy/actions/BattleGroundTactics.cpp index 4b15eeee..e7f90ea9 100644 --- a/src/strategy/actions/BattleGroundTactics.cpp +++ b/src/strategy/actions/BattleGroundTactics.cpp @@ -22,6 +22,7 @@ #include "Event.h" #include "Playerbots.h" #include "PositionValue.h" +#include "PvpTriggers.h" #include "ServerFacade.h" #include "Vehicle.h" @@ -1771,7 +1772,10 @@ std::string const BGTactics::HandleConsoleCommandPrivate(WorldSession* session, Creature* wpCreature = player->SummonCreature(15631, c->GetPositionX(), c->GetPositionY(), c->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 15000u); wpCreature->SetOwnerGUID(player->GetGUID()); - return fmt::format("Showing location of Creature {}", num); + float distance = player->GetDistance(c); + float exactDistance = player->GetExactDist(c); + return fmt::format("Showing Creature {} location={:.3f},{:.3f},{:.3f} distance={} exactDistance={}", + num, c->GetPositionX(), c->GetPositionY(), c->GetPositionZ(), distance, exactDistance); } if (!strncmp(cmd, "showobject=", 11)) @@ -1787,7 +1791,10 @@ std::string const BGTactics::HandleConsoleCommandPrivate(WorldSession* session, Creature* wpCreature = player->SummonCreature(15631, o->GetPositionX(), o->GetPositionY(), o->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 15000u); wpCreature->SetOwnerGUID(player->GetGUID()); - return fmt::format("Showing location of GameObject {}", num); + float distance = player->GetDistance(o); + float exactDistance = player->GetExactDist(o); + return fmt::format("Showing GameObject {} location={:.3f},{:.3f},{:.3f} distance={} exactDistance={}", + num, o->GetPositionX(), o->GetPositionY(), o->GetPositionZ(), distance, exactDistance); } return "usage: showpath(=[num]) / showcreature=[num] / showobject=[num]"; @@ -2266,8 +2273,7 @@ bool BGTactics::Execute(Event event) // NOTE: can't use IsInCombat() when in vehicle as player is stuck in combat forever while in vehicle (ac bug?) bool inCombat = bot->GetVehicle() ? (bool)AI_VALUE(Unit*, "enemy player target") : bot->IsInCombat(); - if (inCombat && !(bot->HasAura(BG_WS_SPELL_WARSONG_FLAG) || bot->HasAura(BG_WS_SPELL_SILVERWING_FLAG) || - bot->HasAura(BG_EY_NETHERSTORM_FLAG_SPELL))) + if (inCombat && !PlayerHasFlag::IsCapturingFlag(bot)) { // bot->GetMotionMaster()->MovementExpired(); return false; @@ -3886,10 +3892,7 @@ bool BGTactics::moveToObjectiveWp(BattleBotPath* const& currentPath, uint32 curr // NOTE: can't use IsInCombat() when in vehicle as player is stuck in combat forever while in vehicle (ac bug?) bool inCombat = bot->GetVehicle() ? (bool)AI_VALUE(Unit*, "enemy player target") : bot->IsInCombat(); - if ((currentPoint == lastPointInPath) || - (inCombat && !(bot->HasAura(BG_WS_SPELL_WARSONG_FLAG) || bot->HasAura(BG_WS_SPELL_SILVERWING_FLAG) || - bot->HasAura(BG_EY_NETHERSTORM_FLAG_SPELL))) || - !bot->IsAlive()) + if (currentPoint == lastPointInPath || (inCombat && !PlayerHasFlag::IsCapturingFlag(bot)) || !bot->IsAlive()) { // Path is over. // std::ostringstream out; diff --git a/src/strategy/actions/ChooseTargetActions.cpp b/src/strategy/actions/ChooseTargetActions.cpp index 54bf0b1c..dddb3627 100644 --- a/src/strategy/actions/ChooseTargetActions.cpp +++ b/src/strategy/actions/ChooseTargetActions.cpp @@ -11,11 +11,11 @@ #include "Playerbots.h" #include "PossibleRpgTargetsValue.h" #include "ServerFacade.h" +#include "PvpTriggers.h" bool AttackEnemyPlayerAction::isUseful() { - // if carry flag, do not start fight - if (bot->HasAura(23333) || bot->HasAura(23335) || bot->HasAura(34976)) + if (PlayerHasFlag::IsCapturingFlag(bot)) return false; return !sPlayerbotAIConfig->IsPvpProhibited(bot->GetZoneId(), bot->GetAreaId()); @@ -25,7 +25,7 @@ bool AttackEnemyFlagCarrierAction::isUseful() { Unit* target = context->GetValue("enemy flag carrier")->Get(); return target && sServerFacade->IsDistanceLessOrEqualThan(sServerFacade->GetDistance2d(bot, target), 75.0f) && - (bot->HasAura(23333) || bot->HasAura(23335) || bot->HasAura(34976)); + PlayerHasFlag::IsCapturingFlag(bot); } bool AttackAnythingAction::isUseful() @@ -124,8 +124,7 @@ bool AttackAnythingAction::isPossible() { return AttackAction::isPossible() && G bool DpsAssistAction::isUseful() { - // if carry flag, do not start fight - if (bot->HasAura(23333) || bot->HasAura(23335) || bot->HasAura(34976)) + if (PlayerHasFlag::IsCapturingFlag(bot)) return false; return true; diff --git a/src/strategy/actions/VehicleActions.cpp b/src/strategy/actions/VehicleActions.cpp index 2fc09cb3..4683ba7a 100644 --- a/src/strategy/actions/VehicleActions.cpp +++ b/src/strategy/actions/VehicleActions.cpp @@ -44,13 +44,12 @@ bool EnterVehicleAction::Execute(Event event) if (vehicleBase->GetVehicleKit()->IsVehicleInUse()) continue; - // if (fabs(bot->GetPositionZ() - vehicleBase->GetPositionZ()) < 20.0f) + float dist = sServerFacade->GetDistance2d(bot, vehicleBase); + if (dist > 40.0f) + continue; - // if (sServerFacade->GetDistance2d(bot, vehicle) > 100.0f) - // continue; - - if (sServerFacade->GetDistance2d(bot, vehicleBase) > INTERACTION_DISTANCE) - return MoveTo(vehicleBase, INTERACTION_DISTANCE - 1.0f); + if (dist > INTERACTION_DISTANCE) + return MoveTo(vehicleBase); bot->EnterVehicle(vehicleBase); diff --git a/src/strategy/triggers/PvpTriggers.cpp b/src/strategy/triggers/PvpTriggers.cpp index 30d47404..b4a3edfb 100644 --- a/src/strategy/triggers/PvpTriggers.cpp +++ b/src/strategy/triggers/PvpTriggers.cpp @@ -117,22 +117,53 @@ bool PlayerIsInBattlegroundWithoutFlag::IsActive() } bool PlayerHasFlag::IsActive() +{ + return IsCapturingFlag(bot); +} + +bool PlayerHasFlag::IsCapturingFlag(Player* bot) { if (bot->InBattleground()) { if (bot->GetBattlegroundTypeId() == BATTLEGROUND_WS) { - BattlegroundWS* bg = (BattlegroundWS*)botAI->GetBot()->GetBattleground(); - if (bot->GetGUID() == bg->GetFlagPickerGUID(TEAM_ALLIANCE) || - bot->GetGUID() == bg->GetFlagPickerGUID(TEAM_HORDE)) + BattlegroundWS* bg = (BattlegroundWS*)bot->GetBattleground(); + // bot is horde and has ally flag + if (bot->GetGUID() == bg->GetFlagPickerGUID(TEAM_ALLIANCE)) { - return true; + if (bg->GetFlagPickerGUID(TEAM_HORDE)) // enemy has flag too + { + if (GameObject* go = bg->GetBGObject(BG_WS_OBJECT_H_FLAG)) + { + // only indicate capturing if signicant distance from own flag + // (otherwise allow bot to defend itself) + return bot->GetDistance(go) > 36.0f; + } + } + return true; // enemy doesnt have flag so we can cap immediately } + // bot is ally and has horde flag + if (bot->GetGUID() == bg->GetFlagPickerGUID(TEAM_HORDE)) + { + if (bg->GetFlagPickerGUID(TEAM_ALLIANCE)) // enemy has flag too + { + if (GameObject* go = bg->GetBGObject(BG_WS_OBJECT_A_FLAG)) + { + // only indicate capturing if signicant distance from own flag + // (otherwise allow bot to defend itself) + return bot->GetDistance(go) > 36.0f; + } + } + return true; // enemy doesnt have flag so we can cap immediately + } + return false; // bot doesn't have flag } if (bot->GetBattlegroundTypeId() == BATTLEGROUND_EY) { - BattlegroundEY* bg = (BattlegroundEY*)botAI->GetBot()->GetBattleground(); + // TODO we should probably add similiar logic as WSG to allow combat + // when bot has flag but no bases are available to take it to + BattlegroundEY* bg = (BattlegroundEY*)bot->GetBattleground(); return bot->GetGUID() == bg->GetFlagPickerGUID(); } diff --git a/src/strategy/triggers/PvpTriggers.h b/src/strategy/triggers/PvpTriggers.h index 7633c654..34019a67 100644 --- a/src/strategy/triggers/PvpTriggers.h +++ b/src/strategy/triggers/PvpTriggers.h @@ -26,12 +26,15 @@ public: bool IsActive() override; }; +// NOTE this trigger is only active when bot is actively returning flag +// (not when hiding in base because enemy has flag too) class PlayerHasFlag : public Trigger { public: PlayerHasFlag(PlayerbotAI* botAI) : Trigger(botAI, "player has flag") {} bool IsActive() override; + static bool IsCapturingFlag(Player* bot); }; class EnemyFlagCarrierNear : public Trigger From 84e6f6ef9df808fc96bf75acd80f146acd0f6bcb Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Thu, 8 Aug 2024 11:59:01 +0800 Subject: [PATCH 6/6] Fix itemQuality for random bots --- src/PlayerbotFactory.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/PlayerbotFactory.cpp b/src/PlayerbotFactory.cpp index 4591471b..84812822 100644 --- a/src/PlayerbotFactory.cpp +++ b/src/PlayerbotFactory.cpp @@ -55,6 +55,15 @@ PlayerbotFactory::PlayerbotFactory(Player* bot, uint32 level, uint32 itemQuality : level(level), itemQuality(itemQuality), gearScoreLimit(gearScoreLimit), bot(bot) { botAI = GET_PLAYERBOT_AI(bot); + if (!this->itemQuality) + { + uint32 gs = sPlayerbotAIConfig->randomGearScoreLimit == 0 + ? 0 + : PlayerbotFactory::CalcMixedGearScore(sPlayerbotAIConfig->randomGearScoreLimit, + sPlayerbotAIConfig->randomGearQualityLimit); + this->itemQuality = sPlayerbotAIConfig->randomGearQualityLimit; + this->gearScoreLimit = gs; + } } void PlayerbotFactory::Init() @@ -149,16 +158,6 @@ void PlayerbotFactory::Init() void PlayerbotFactory::Prepare() { - if (!itemQuality) - { - uint32 gs = sPlayerbotAIConfig->randomGearScoreLimit == 0 - ? 0 - : PlayerbotFactory::CalcMixedGearScore(sPlayerbotAIConfig->randomGearScoreLimit, - sPlayerbotAIConfig->randomGearQualityLimit); - itemQuality = sPlayerbotAIConfig->randomGearQualityLimit; - gearScoreLimit = gs; - } - if (bot->isDead()) bot->ResurrectPlayer(1.0f, false);