From af674e9361cce8e8e8f5446142dd8a38e649a115 Mon Sep 17 00:00:00 2001 From: Fuzz Date: Tue, 6 Aug 2024 19:26:54 +1000 Subject: [PATCH] [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;