mirror of
https://github.com/mod-playerbots/mod-playerbots.git
synced 2026-01-13 00:58:33 +00:00
This update enhances bot behavior by adding a check for both line of sight (LoS) and significant vertical height differences between the bot and its target. If the bot cannot see its target or if the height difference exceeds 5.0f, it calculates a valid path and moves closer to regain visibility and combat effectiveness. This resolves cases where bots would previously stand still when enemies jumped from elevated terrain or were behind obstacles.
4297 lines
194 KiB
C++
4297 lines
194 KiB
C++
/*
|
|
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
|
|
* and/or modify it under version 2 of the License, or (at your option), any later version.
|
|
*/
|
|
|
|
#include "BattleGroundTactics.h"
|
|
#include "BattleGroundJoinAction.h"
|
|
|
|
#include "ArenaTeam.h"
|
|
#include "ArenaTeamMgr.h"
|
|
#include "Battleground.h"
|
|
#include "BattlegroundAB.h"
|
|
#include "BattlegroundAV.h"
|
|
#include "BattlegroundBE.h"
|
|
#include "BattlegroundDS.h"
|
|
#include "BattlegroundEY.h"
|
|
#include "BattlegroundIC.h"
|
|
#include "BattlegroundMgr.h"
|
|
#include "BattlegroundNA.h"
|
|
#include "BattlegroundRL.h"
|
|
#include "BattlegroundRV.h"
|
|
#include "BattlegroundSA.h"
|
|
#include "BattlegroundWS.h"
|
|
#include "Event.h"
|
|
#include "IVMapMgr.h"
|
|
#include "Playerbots.h"
|
|
#include "PositionValue.h"
|
|
#include "PvpTriggers.h"
|
|
#include "ServerFacade.h"
|
|
#include "Vehicle.h"
|
|
|
|
// common bg positions
|
|
Position const WS_WAITING_POS_HORDE_1 = {944.981f, 1423.478f, 345.434f, 6.18f};
|
|
Position const WS_WAITING_POS_HORDE_2 = {948.488f, 1459.834f, 343.066f, 6.27f};
|
|
Position const WS_WAITING_POS_HORDE_3 = {933.484f, 1433.726f, 345.535f, 0.08f};
|
|
Position const WS_WAITING_POS_ALLIANCE_1 = {1510.502f, 1493.385f, 351.995f, 3.1f};
|
|
Position const WS_WAITING_POS_ALLIANCE_2 = {1496.578f, 1457.900f, 344.442f, 3.1f};
|
|
Position const WS_WAITING_POS_ALLIANCE_3 = {1521.235f, 1480.951f, 352.007f, 3.2f};
|
|
Position const WS_FLAG_POS_HORDE = {915.958f, 1433.925f, 346.193f, 0.0f};
|
|
Position const WS_FLAG_POS_ALLIANCE = {1539.219f, 1481.747f, 352.458f, 0.0f};
|
|
Position const WS_FLAG_HIDE_HORDE_1 = {926.142f, 1460.641f, 346.116f, 4.84f};
|
|
Position const WS_FLAG_HIDE_HORDE_2 = {925.166f, 1458.084f, 355.966f, 0.00f};
|
|
Position const WS_FLAG_HIDE_HORDE_3 = {924.922f, 1423.672f, 345.524f, 0.82f};
|
|
Position const WS_FLAG_HIDE_ALLIANCE_1 = {1529.249f, 1456.470f, 353.04f, 1.25f};
|
|
Position const WS_FLAG_HIDE_ALLIANCE_2 = {1540.286f, 1476.026f, 352.692f, 2.91f};
|
|
Position const WS_FLAG_HIDE_ALLIANCE_3 = {1495.807f, 1466.774f, 352.350f, 1.50f};
|
|
Position const WS_ROAM_POS = {1227.446f, 1476.235f, 307.484f, 1.50f};
|
|
Position const WS_GY_CAMPING_HORDE = {1039.819, 1388.759f, 340.703f, 0.0f};
|
|
Position const WS_GY_CAMPING_ALLIANCE = {1422.320f, 1551.978f, 342.834f, 0.0f};
|
|
std::vector<Position> const WS_FLAG_HIDE_HORDE = {WS_FLAG_HIDE_HORDE_1, WS_FLAG_HIDE_HORDE_2, WS_FLAG_HIDE_HORDE_3};
|
|
std::vector<Position> const WS_FLAG_HIDE_ALLIANCE = {WS_FLAG_HIDE_ALLIANCE_1, WS_FLAG_HIDE_ALLIANCE_2,
|
|
WS_FLAG_HIDE_ALLIANCE_3};
|
|
|
|
Position const AB_WAITING_POS_HORDE = {702.884f, 703.045f, -16.115f, 0.77f};
|
|
Position const AB_WAITING_POS_ALLIANCE = {1286.054f, 1282.500f, -15.697f, 3.95f};
|
|
Position const AB_GY_CAMPING_HORDE = {723.513f, 725.924f, -28.265f, 3.99f};
|
|
Position const AB_GY_CAMPING_ALLIANCE = {1262.627f, 1256.341f, -27.289f, 0.64f};
|
|
|
|
// the captains aren't the actual creatures but invisible trigger creatures - they still have correct death state and
|
|
// location (unless they move)
|
|
uint32 const AV_CREATURE_A_CAPTAIN = AV_CPLACE_TRIGGER16;
|
|
uint32 const AV_CREATURE_A_BOSS = AV_CPLACE_A_BOSS;
|
|
uint32 const AV_CREATURE_H_CAPTAIN = AV_CPLACE_TRIGGER18;
|
|
uint32 const AV_CREATURE_H_BOSS = AV_CPLACE_H_BOSS;
|
|
|
|
Position const AV_CAVE_SPAWN_ALLIANCE = {872.460f, -491.571f, 96.546f, 0.0f};
|
|
Position const AV_CAVE_SPAWN_HORDE = {-1437.127f, -608.382f, 51.185f, 0.0f};
|
|
Position const AV_WAITING_POS_ALLIANCE = {793.627f, -493.814f, 99.689f, 3.09f};
|
|
Position const AV_WAITING_POS_HORDE = {-1381.865f, -544.872f, 54.773f, 0.76f};
|
|
Position const AV_ICEBLOOD_GARRISON_WAITING_ALLIANCE = {-523.105f, -182.178f, 57.956f, 0.0f};
|
|
Position const AV_ICEBLOOD_GARRISON_ATTACKING_ALLIANCE = {-545.288f, -167.932f, 57.012f, 0.0f};
|
|
Position const AV_STONEHEARTH_WAITING_HORDE = {-36.399f, -306.403f, 15.565f, 0.0f};
|
|
Position const AV_STONEHEARTH_ATTACKING_HORDE = {-55.210f, -288.546f, 15.578f, 0.0f};
|
|
Position const AV_BOSS_WAIT_H = {689.210f, -20.173f, 50.620f, 0.0f};
|
|
Position const AV_BOSS_WAIT_A = {-1361.773f, -248.977f, 99.369f, 0.0f};
|
|
Position const AV_MINE_SOUTH_1 = {-860.159f, -12.780f, 70.817f, 0.0f};
|
|
Position const AV_MINE_SOUTH_2 = {-827.639f, -147.314f, 62.565f, 0.0f};
|
|
Position const AV_MINE_SOUTH_3 = {-920.228f, -134.594f, 61.478f, 0.0f};
|
|
Position const AV_MINE_NORTH_1 = {822.477f, -456.782f, 48.569f, 0.0f};
|
|
Position const AV_MINE_NORTH_2 = {966.362f, -446.570f, 56.641f, 0.0f};
|
|
Position const AV_MINE_NORTH_3 = {952.081f, -335.073f, 63.579f, 0.0f};
|
|
Position const EY_WAITING_POS_HORDE = {1809.102f, 1540.854f, 1267.142f, 0.0f};
|
|
Position const EY_WAITING_POS_ALLIANCE = {2523.827f, 1596.915f, 1270.204f, 0.0f};
|
|
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 EY_GY_CAMPING_HORDE = {1874.854f, 1530.405f, 1207.432f, 0.0f};
|
|
Position const EY_GY_CAMPING_ALLIANCE = {2456.887f, 1599.025f, 1206.280f, 0.0f};
|
|
|
|
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_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,
|
|
BB_WSG_WAIT_SPOT_LEFT,
|
|
BB_WSG_WAIT_SPOT_RIGHT
|
|
};
|
|
|
|
std::unordered_map<uint32, BGStrategyData> bgStrategies;
|
|
|
|
std::vector<uint32> const vFlagsAV = {
|
|
BG_AV_OBJECTID_BANNER_H_B, BG_AV_OBJECTID_BANNER_H, BG_AV_OBJECTID_BANNER_A_B,
|
|
BG_AV_OBJECTID_BANNER_A, BG_AV_OBJECTID_BANNER_CONT_A, BG_AV_OBJECTID_BANNER_CONT_A_B,
|
|
BG_AV_OBJECTID_BANNER_CONT_H_B, BG_AV_OBJECTID_BANNER_CONT_H, BG_AV_OBJECTID_BANNER_SNOWFALL_N};
|
|
|
|
std::vector<uint32> const vFlagsAB = {
|
|
BG_AB_OBJECTID_BANNER_A,
|
|
BG_AB_OBJECTID_BANNER_CONT_A,
|
|
BG_AB_OBJECTID_BANNER_H,
|
|
BG_AB_OBJECTID_BANNER_CONT_H,
|
|
BG_AB_OBJECTID_NODE_BANNER_0,
|
|
BG_AB_OBJECTID_NODE_BANNER_1,
|
|
BG_AB_OBJECTID_NODE_BANNER_2,
|
|
BG_AB_OBJECTID_NODE_BANNER_3,
|
|
BG_AB_OBJECTID_NODE_BANNER_4
|
|
};
|
|
|
|
std::vector<uint32> const vFlagsWS = {BG_OBJECT_A_FLAG_WS_ENTRY, BG_OBJECT_H_FLAG_WS_ENTRY,
|
|
BG_OBJECT_A_FLAG_GROUND_WS_ENTRY, BG_OBJECT_H_FLAG_GROUND_WS_ENTRY};
|
|
|
|
std::vector<uint32> const vFlagsEY = {BG_OBJECT_FLAG2_EY_ENTRY, BG_OBJECT_FLAG3_EY_ENTRY};
|
|
|
|
std::vector<uint32> 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)
|
|
|
|
// Horde Flag Room to Horde Graveyard
|
|
BattleBotPath vPath_WSG_HordeFlagRoom_to_HordeGraveyard = {
|
|
{933.331f, 1433.72f, 345.536f, nullptr}, {944.859f, 1423.05f, 345.437f, nullptr},
|
|
{966.691f, 1422.53f, 345.223f, nullptr}, {979.588f, 1422.84f, 345.46f, nullptr},
|
|
{997.806f, 1422.52f, 344.623f, nullptr}, {1008.53f, 1417.02f, 343.206f, nullptr},
|
|
{1016.42f, 1402.33f, 341.352f, nullptr}, {1029.14f, 1387.49f, 340.836f, nullptr},
|
|
};
|
|
|
|
// Horde Graveyard to Horde Tunnel
|
|
BattleBotPath vPath_WSG_HordeGraveyard_to_HordeTunnel = {
|
|
{1029.14f, 1387.49f, 340.836f, nullptr}, {1034.95f, 1392.62f, 340.856f, nullptr},
|
|
{1038.21f, 1406.43f, 341.562f, nullptr}, {1043.87f, 1426.9f, 339.197f, nullptr},
|
|
{1054.53f, 1441.47f, 339.725f, nullptr}, {1056.33f, 1456.03f, 341.463f, nullptr},
|
|
{1057.39f, 1469.98f, 342.148f, nullptr}, {1057.67f, 1487.55f, 342.537f, nullptr},
|
|
{1048.7f, 1505.37f, 341.117f, nullptr}, {1042.19f, 1521.69f, 338.003f, nullptr},
|
|
{1050.01f, 1538.22f, 332.43f, nullptr}, {1068.15f, 1548.1f, 321.446f, nullptr},
|
|
{1088.14f, 1538.45f, 316.398f, nullptr}, {1101.26f, 1522.79f, 314.918f, nullptr},
|
|
{1114.67f, 1503.18f, 312.947f, nullptr}, {1126.45f, 1487.4f, 314.136f, nullptr},
|
|
{1124.37f, 1462.28f, 315.853f, nullptr},
|
|
};
|
|
|
|
// Horde Tunnel to Horde Flag Room
|
|
BattleBotPath vPath_WSG_HordeTunnel_to_HordeFlagRoom = {
|
|
{1124.37f, 1462.28f, 315.853f, nullptr}, {1106.87f, 1462.13f, 316.558f, nullptr},
|
|
{1089.44f, 1461.04f, 316.332f, nullptr}, {1072.07f, 1459.46f, 317.449f, nullptr},
|
|
{1051.09f, 1459.89f, 323.126f, nullptr}, {1030.1f, 1459.58f, 330.204f, nullptr},
|
|
{1010.76f, 1457.49f, 334.896f, nullptr}, {1005.47f, 1448.19f, 335.864f, nullptr},
|
|
{999.974f, 1458.49f, 335.632f, nullptr}, {982.632f, 1459.18f, 336.127f, nullptr},
|
|
{965.049f, 1459.15f, 338.076f, nullptr}, {944.526f, 1459.0f, 344.207f, nullptr},
|
|
{937.479f, 1451.12f, 345.553f, nullptr}, {933.331f, 1433.72f, 345.536f, nullptr},
|
|
};
|
|
|
|
// Alliance Flag Room to Alliance Graveyard
|
|
BattleBotPath vPath_WSG_AllianceFlagRoom_to_AllianceGraveyard = {
|
|
{1519.53f, 1481.87f, 352.024f, nullptr}, {1508.27f, 1493.17f, 352.005f, nullptr},
|
|
{1490.78f, 1493.51f, 352.141f, nullptr}, {1469.79f, 1494.13f, 351.774f, nullptr},
|
|
{1453.65f, 1494.39f, 350.614f, nullptr}, {1443.51f, 1501.75f, 348.317f, nullptr},
|
|
{1443.33f, 1517.78f, 345.534f, nullptr}, {1443.55f, 1533.4f, 343.148f, nullptr},
|
|
{1441.47f, 1548.12f, 342.752f, nullptr}, {1433.79f, 1552.67f, 342.763f, nullptr},
|
|
{1422.88f, 1552.37f, 342.751f, nullptr}, {1415.33f, 1554.79f, 343.156f, nullptr},
|
|
};
|
|
|
|
// Alliance Graveyard to Alliance Tunnel
|
|
BattleBotPath vPath_WSG_AllianceGraveyard_to_AllianceTunnel = {
|
|
{1415.33f, 1554.79f, 343.156f, nullptr}, {1428.29f, 1551.79f, 342.751f, nullptr},
|
|
{1441.51f, 1545.79f, 342.757f, nullptr}, {1441.15f, 1530.35f, 343.712f, nullptr},
|
|
{1435.53f, 1517.29f, 346.698f, nullptr}, {1424.81f, 1499.24f, 349.486f, nullptr},
|
|
{1416.31f, 1483.94f, 348.536f, nullptr}, {1408.83f, 1468.4f, 347.648f, nullptr},
|
|
{1404.64f, 1449.79f, 347.279f, nullptr}, {1405.34f, 1432.33f, 345.792f, nullptr},
|
|
{1406.38f, 1416.18f, 344.755f, nullptr}, {1400.22f, 1401.87f, 340.496f, nullptr},
|
|
{1385.96f, 1394.15f, 333.829f, nullptr}, {1372.38f, 1390.75f, 328.722f, nullptr},
|
|
{1362.93f, 1390.02f, 327.034f, nullptr}, {1357.91f, 1398.07f, 325.674f, nullptr},
|
|
{1354.17f, 1411.56f, 324.327f, nullptr}, {1351.44f, 1430.38f, 323.506f, nullptr},
|
|
{1350.36f, 1444.43f, 323.388f, nullptr}, {1348.02f, 1461.06f, 323.167f, nullptr},
|
|
};
|
|
|
|
// Alliance Tunnel to Alliance Flag Room
|
|
BattleBotPath vPath_WSG_AllianceTunnel_to_AllianceFlagRoom = {
|
|
{1348.02f, 1461.06f, 323.167f, nullptr}, {1359.8f, 1461.49f, 324.527f, nullptr},
|
|
{1372.47f, 1461.61f, 324.354f, nullptr}, {1389.08f, 1461.12f, 325.913f, nullptr},
|
|
{1406.57f, 1460.48f, 330.615f, nullptr}, {1424.04f, 1459.57f, 336.029f, nullptr},
|
|
{1442.5f, 1459.7f, 342.024f, nullptr}, {1449.59f, 1469.14f, 342.65f, nullptr},
|
|
{1458.03f, 1458.43f, 342.746f, nullptr}, {1469.4f, 1458.14f, 342.794f, nullptr},
|
|
{1489.06f, 1457.86f, 342.794f, nullptr}, {1502.27f, 1457.52f, 347.589f, nullptr},
|
|
{1512.87f, 1457.81f, 352.039f, nullptr}, {1517.53f, 1468.79f, 352.033f, nullptr},
|
|
{1519.53f, 1481.87f, 352.024f, nullptr},
|
|
};
|
|
|
|
// Horde Tunnel to Horde Base Roof
|
|
BattleBotPath vPath_WSG_HordeTunnel_to_HordeBaseRoof = {
|
|
{1124.37f, 1462.28f, 315.853f, nullptr}, {1106.87f, 1462.13f, 316.558f, nullptr},
|
|
{1089.44f, 1461.04f, 316.332f, nullptr}, {1072.07f, 1459.46f, 317.449f, nullptr},
|
|
{1051.09f, 1459.89f, 323.126f, nullptr}, {1030.1f, 1459.58f, 330.204f, nullptr},
|
|
{1010.76f, 1457.49f, 334.896f, nullptr}, {981.948f, 1459.07f, 336.154f, nullptr},
|
|
{981.768f, 1480.46f, 335.976f, nullptr}, {974.664f, 1495.9f, 340.837f, nullptr},
|
|
{964.661f, 1510.21f, 347.509f, nullptr}, {951.188f, 1520.99f, 356.377f, nullptr},
|
|
{937.37f, 1513.27f, 362.589f, nullptr}, {935.947f, 1499.58f, 364.199f, nullptr},
|
|
{935.9f, 1482.08f, 366.396f, nullptr}, {937.564f, 1462.81f, 367.287f, nullptr},
|
|
{945.871f, 1458.65f, 367.287f, nullptr}, {956.972f, 1459.48f, 367.291f, nullptr},
|
|
{968.317f, 1459.71f, 367.291f, nullptr}, {979.934f, 1454.58f, 367.078f, nullptr},
|
|
{979.99f, 1442.87f, 367.093f, nullptr}, {978.632f, 1430.71f, 367.125f, nullptr},
|
|
{970.395f, 1422.32f, 367.289f, nullptr}, {956.338f, 1425.09f, 367.293f, nullptr},
|
|
{952.778f, 1433.0f, 367.604f, nullptr}, {952.708f, 1445.01f, 367.604f, nullptr},
|
|
};
|
|
|
|
// Alliance Tunnel to Alliance Base Roof
|
|
BattleBotPath vPath_WSG_AllianceTunnel_to_AllianceBaseRoof = {
|
|
{1348.02f, 1461.06f, 323.167f, nullptr}, {1359.8f, 1461.49f, 324.527f, nullptr},
|
|
{1372.47f, 1461.61f, 324.354f, nullptr}, {1389.08f, 1461.12f, 325.913f, nullptr},
|
|
{1406.57f, 1460.48f, 330.615f, nullptr}, {1424.04f, 1459.57f, 336.029f, nullptr},
|
|
{1442.5f, 1459.7f, 342.024f, nullptr}, {1471.86f, 1456.65f, 342.794f, nullptr},
|
|
{1470.93f, 1440.5f, 342.794f, nullptr}, {1472.24f, 1427.49f, 342.06f, nullptr},
|
|
{1476.86f, 1412.46f, 341.426f, nullptr}, {1484.42f, 1396.69f, 346.117f, nullptr},
|
|
{1490.7f, 1387.59f, 351.861f, nullptr}, {1500.79f, 1382.98f, 357.784f, nullptr},
|
|
{1511.08f, 1391.29f, 364.444f, nullptr}, {1517.85f, 1403.18f, 370.336f, nullptr},
|
|
{1517.99f, 1417.59f, 371.636f, nullptr}, {1517.07f, 1431.56f, 372.106f, nullptr},
|
|
{1516.66f, 1445.55f, 372.939f, nullptr}, {1514.23f, 1457.37f, 373.689f, nullptr},
|
|
{1503.73f, 1457.67f, 373.684f, nullptr}, {1486.24f, 1457.8f, 373.718f, nullptr},
|
|
{1476.78f, 1460.35f, 373.711f, nullptr}, {1477.37f, 1470.83f, 373.709f, nullptr},
|
|
{1477.5f, 1484.83f, 373.715f, nullptr}, {1480.53f, 1495.26f, 373.721f, nullptr},
|
|
{1492.61f, 1494.72f, 373.721f, nullptr}, {1499.37f, 1489.02f, 373.718f, nullptr},
|
|
{1500.63f, 1472.89f, 373.707f, nullptr},
|
|
};
|
|
|
|
// Alliance Tunnel to Horde Tunnel
|
|
BattleBotPath vPath_WSG_AllianceTunnel_to_HordeTunnel = {
|
|
{1129.30f, 1461.03f, 315.206f, nullptr},
|
|
{1149.55f, 1466.57f, 311.031f, nullptr},
|
|
{1196.39f, 1477.25f, 305.697f, nullptr},
|
|
{1227.73f, 1478.38f, 307.418f, nullptr},
|
|
{1267.06f, 1463.40f, 312.227f, nullptr},
|
|
{1303.42f, 1460.18f, 317.257f, nullptr},
|
|
};
|
|
|
|
// Alliance Graveyard (lower) to Horde Flag room
|
|
BattleBotPath vPath_WSG_AllianceGraveyardLower_to_HordeFlagRoom = {
|
|
//{1370.71f, 1543.55f, 321.585f, nullptr},
|
|
//{1339.41f, 1533.42f, 313.336f, nullptr},
|
|
{1316.07f, 1533.53f, 315.700f, nullptr},
|
|
{1276.17f, 1533.72f, 311.722f, nullptr},
|
|
{1246.25f, 1533.86f, 307.072f, nullptr},
|
|
{1206.84f, 1528.22f, 307.677f, nullptr},
|
|
{1172.28f, 1523.28f, 301.958f, nullptr},
|
|
{1135.93f, 1505.27f, 308.085f, nullptr},
|
|
{1103.54f, 1521.89f, 314.583f, nullptr},
|
|
{1073.49f, 1551.19f, 319.418f, nullptr},
|
|
{1042.92f, 1530.49f, 336.667f, nullptr},
|
|
{1052.11f, 1493.52f, 342.176f, nullptr},
|
|
{1057.42f, 1452.75f, 341.131f, nullptr},
|
|
{1037.96f, 1422.27f, 339.919f, nullptr},
|
|
{966.01f, 1422.84f, 345.223f, nullptr},
|
|
{942.74f, 1423.10f, 345.467f, nullptr},
|
|
{929.39f, 1434.75f, 345.535f, nullptr},
|
|
};
|
|
|
|
// Horde Graveyard (lower) to Alliance Flag room
|
|
BattleBotPath vPath_WSG_HordeGraveyardLower_to_AllianceFlagRoom = {
|
|
//{1096.59f, 1395.07f, 317.016f, nullptr},
|
|
//{1134.38f, 1370.13f, 312.741f, nullptr},
|
|
{1164.96f, 1356.91f, 313.884f, nullptr},
|
|
{1208.32f, 1346.27f, 313.816f, nullptr},
|
|
{1245.06f, 1346.12f, 312.112f, nullptr},
|
|
{1291.43f, 1394.60f, 314.359f, nullptr},
|
|
{1329.33f, 1411.13f, 318.399f, nullptr},
|
|
{1361.57f, 1391.21f, 326.756f, nullptr},
|
|
{1382.19f, 1381.03f, 332.314f, nullptr},
|
|
{1408.06f, 1412.93f, 344.565f, nullptr},
|
|
{1407.88f, 1458.76f, 347.346f, nullptr},
|
|
{1430.40f, 1489.34f, 348.658f, nullptr},
|
|
{1466.64f, 1493.50f, 351.869f, nullptr},
|
|
{1511.51f, 1493.75f, 352.009f, nullptr},
|
|
{1531.44f, 1481.79f, 351.959f, nullptr},
|
|
};
|
|
|
|
// Alliance Graveyard Jump
|
|
BattleBotPath vPath_WSG_AllianceGraveyardJump = {
|
|
{1420.08f, 1552.84f, 342.878f, nullptr},
|
|
{1404.06f, 1551.37f, 342.850f, nullptr},
|
|
{1386.24f, 1543.37f, 321.944f, nullptr},
|
|
};
|
|
|
|
// Horde Graveyard Jump
|
|
BattleBotPath vPath_WSG_HordeGraveyardJump = {
|
|
{1045.70f, 1389.15f, 340.638f, nullptr},
|
|
{1057.43f, 1390.12f, 339.869f, nullptr},
|
|
{1074.59f, 1400.67f, 323.811f, nullptr},
|
|
{1092.85f, 1399.38f, 317.429f, nullptr},
|
|
};
|
|
|
|
// Alliance Base to Stables
|
|
BattleBotPath vPath_AB_AllianceBase_to_Stables = {
|
|
{1285.67f, 1282.14f, -15.8466f, nullptr}, {1272.52f, 1267.83f, -21.7811f, nullptr},
|
|
{1250.44f, 1248.09f, -33.3028f, nullptr}, {1232.56f, 1233.05f, -41.5241f, nullptr},
|
|
{1213.25f, 1224.93f, -47.5513f, nullptr}, {1189.29f, 1219.49f, -53.119f, nullptr},
|
|
{1177.17f, 1210.21f, -56.4593f, nullptr}, {1167.98f, 1202.9f, -56.4743f, nullptr},
|
|
};
|
|
|
|
// Blacksmith to Lumber Mill
|
|
BattleBotPath vPath_AB_Blacksmith_to_LumberMill = {
|
|
{967.04f, 1039.03f, -45.091f, nullptr}, {933.67f, 1016.49f, -50.5154f, nullptr},
|
|
{904.02f, 996.63f, -62.3461f, nullptr}, {841.74f, 985.23f, -58.8920f, nullptr},
|
|
{796.25f, 1009.93f, -44.3286f, nullptr}, {781.29f, 1034.49f, -32.887f, nullptr},
|
|
{793.17f, 1107.21f, 5.5663f, nullptr}, {848.98f, 1155.9f, 11.3453f, nullptr},
|
|
};
|
|
|
|
// Blacksmith to GoldMine
|
|
BattleBotPath vPath_AB_Blacksmith_to_GoldMine = {
|
|
{1035.98f, 1015.66f, -46.0278f, nullptr}, {1096.86f, 1002.05f, -60.8013f, nullptr},
|
|
{1159.93f, 1003.69f, -63.8378f, nullptr}, {1198.03f, 1064.09f, -65.8385f, nullptr},
|
|
{1218.58f, 1016.96f, -76.9848f, nullptr}, {1192.83f, 956.25f, -93.6974f, nullptr},
|
|
{1162.93f, 908.92f, -108.6703f, nullptr}, {1144.94f, 860.09f, -111.2100f, nullptr},
|
|
};
|
|
|
|
// Farm to Stables
|
|
BattleBotPath vPath_AB_Farm_to_Stable = {
|
|
{749.88f, 878.23f, -55.1523f, nullptr}, {819.77f, 931.13f, -57.5882f, nullptr},
|
|
{842.34f, 984.76f, -59.0333f, nullptr}, {863.03f, 1051.47f, -58.0495f, nullptr},
|
|
{899.28f, 1098.27f, -57.4149f, nullptr}, {949.22f, 1153.27f, -54.4464f, nullptr},
|
|
{999.07f, 1189.47f, -49.9125f, nullptr}, {1063.11f, 1211.55f, -53.4164f, nullptr},
|
|
{1098.45f, 1225.47f, -53.1301f, nullptr}, {1146.02f, 1226.34f, -53.8979f, nullptr},
|
|
{1167.10f, 1204.31f, -56.55f, nullptr},
|
|
};
|
|
|
|
// Alliance Base to Gold Mine
|
|
BattleBotPath vPath_AB_AllianceBase_to_GoldMine = {
|
|
{1285.67f, 1282.14f, -15.8466f, nullptr}, {1276.41f, 1267.11f, -20.775f, nullptr},
|
|
{1261.34f, 1241.52f, -31.2971f, nullptr}, {1244.91f, 1219.03f, -41.9658f, nullptr},
|
|
{1232.25f, 1184.41f, -50.3348f, nullptr}, {1226.89f, 1150.82f, -55.7935f, nullptr},
|
|
{1224.09f, 1120.38f, -57.0633f, nullptr}, {1220.03f, 1092.72f, -59.1744f, nullptr},
|
|
{1216.05f, 1060.86f, -67.2771f, nullptr}, {1213.77f, 1027.96f, -74.429f, nullptr},
|
|
{1208.56f, 998.394f, -81.9493f, nullptr}, {1197.42f, 969.73f, -89.9385f, nullptr},
|
|
{1185.23f, 944.531f, -97.2433f, nullptr}, {1166.29f, 913.945f, -107.214f, nullptr},
|
|
{1153.17f, 887.863f, -112.34f, nullptr}, {1148.89f, 871.391f, -111.96f, nullptr},
|
|
{1145.24f, 850.82f, -110.514f, nullptr},
|
|
};
|
|
|
|
// Alliance Base to Lumber Mill
|
|
BattleBotPath vPath_AB_AllianceBase_to_LumberMill = {
|
|
{1285.67f, 1282.14f, -15.8466f, nullptr}, {1269.13f, 1267.89f, -22.7764f, nullptr},
|
|
{1247.79f, 1249.77f, -33.2518f, nullptr}, {1226.29f, 1232.02f, -43.9193f, nullptr},
|
|
{1196.68f, 1230.15f, -50.4644f, nullptr}, {1168.72f, 1228.98f, -53.9329f, nullptr},
|
|
{1140.82f, 1226.7f, -53.6318f, nullptr}, {1126.85f, 1225.77f, -47.98f, nullptr},
|
|
{1096.5f, 1226.57f, -53.1769f, nullptr}, {1054.52f, 1226.14f, -49.2011f, nullptr},
|
|
{1033.52f, 1226.08f, -45.5968f, nullptr}, {1005.52f, 1226.08f, -43.2912f, nullptr},
|
|
{977.53f, 1226.68f, -40.16f, nullptr}, {957.242f, 1227.94f, -34.1487f, nullptr},
|
|
{930.689f, 1221.57f, -18.9588f, nullptr}, {918.202f, 1211.98f, -12.2494f, nullptr},
|
|
{880.329f, 1192.63f, 7.61168f, nullptr}, {869.965f, 1178.52f, 10.9678f, nullptr},
|
|
{864.74f, 1163.78f, 12.385f, nullptr}, {859.165f, 1148.84f, 11.5289f, nullptr},
|
|
};
|
|
|
|
// Stables to Blacksmith
|
|
BattleBotPath vPath_AB_Stables_to_Blacksmith = {
|
|
{1169.52f, 1198.71f, -56.2742f, nullptr}, {1166.93f, 1185.2f, -56.3634f, nullptr},
|
|
{1173.84f, 1170.6f, -56.4094f, nullptr}, {1186.7f, 1163.92f, -56.3961f, nullptr},
|
|
{1189.7f, 1150.68f, -55.8664f, nullptr}, {1185.18f, 1129.31f, -58.1044f, nullptr},
|
|
{1181.7f, 1108.6f, -62.1797f, nullptr}, {1177.92f, 1087.95f, -63.5768f, nullptr},
|
|
{1174.52f, 1067.23f, -64.402f, nullptr}, {1171.27f, 1051.09f, -65.0833f, nullptr},
|
|
{1163.22f, 1031.7f, -64.954f, nullptr}, {1154.25f, 1010.25f, -63.5299f, nullptr},
|
|
{1141.07f, 999.479f, -63.3713f, nullptr}, {1127.12f, 1000.37f, -60.628f, nullptr},
|
|
{1106.17f, 1001.66f, -61.7457f, nullptr}, {1085.64f, 1005.62f, -58.5932f, nullptr},
|
|
{1064.88f, 1008.65f, -52.3547f, nullptr}, {1044.16f, 1011.96f, -47.2647f, nullptr},
|
|
{1029.72f, 1014.88f, -45.3546f, nullptr}, {1013.94f, 1028.7f, -43.9786f, nullptr},
|
|
{990.89f, 1039.3f, -42.7659f, nullptr}, {978.269f, 1043.84f, -44.4588f, nullptr},
|
|
};
|
|
|
|
// Horde Base to Farm
|
|
BattleBotPath vPath_AB_HordeBase_to_Farm = {
|
|
{707.259f, 707.839f, -17.5318f, nullptr}, {712.063f, 712.928f, -20.1802f, nullptr},
|
|
{725.941f, 728.682f, -29.7536f, nullptr}, {734.715f, 739.591f, -35.2144f, nullptr},
|
|
{747.607f, 756.161f, -40.899f, nullptr}, {753.994f, 766.668f, -43.3049f, nullptr},
|
|
{758.715f, 787.106f, -46.7014f, nullptr}, {762.077f, 807.831f, -48.4721f, nullptr},
|
|
{764.132f, 821.68f, -49.656f, nullptr}, {767.947f, 839.274f, -50.8574f, nullptr},
|
|
{773.745f, 852.013f, -52.6226f, nullptr}, {785.123f, 869.103f, -54.2089f, nullptr},
|
|
{804.429f, 874.961f, -55.2691f, nullptr},
|
|
};
|
|
|
|
// Horde Base to Gold Mine
|
|
BattleBotPath vPath_AB_HordeBase_to_GoldMine = {
|
|
{707.259f, 707.839f, -17.5318f, nullptr}, {717.935f, 716.874f, -23.3941f, nullptr},
|
|
{739.195f, 732.483f, -34.5791f, nullptr}, {757.087f, 742.008f, -38.1123f, nullptr},
|
|
{776.946f, 748.775f, -42.7346f, nullptr}, {797.138f, 754.539f, -46.3237f, nullptr},
|
|
{817.37f, 760.167f, -48.9235f, nullptr}, {837.638f, 765.664f, -49.7374f, nullptr},
|
|
{865.092f, 774.738f, -51.9831f, nullptr}, {878.86f, 777.149f, -47.2361f, nullptr},
|
|
{903.911f, 780.212f, -53.1424f, nullptr}, {923.454f, 787.888f, -54.7937f, nullptr},
|
|
{946.218f, 798.93f, -59.0904f, nullptr}, {978.1f, 813.321f, -66.7268f, nullptr},
|
|
{1002.94f, 817.895f, -77.3119f, nullptr}, {1030.77f, 820.92f, -88.7717f, nullptr},
|
|
{1058.61f, 823.889f, -94.1623f, nullptr}, {1081.6f, 828.32f, -99.4137f, nullptr},
|
|
{1104.64f, 844.773f, -106.387f, nullptr}, {1117.56f, 853.686f, -110.716f, nullptr},
|
|
{1144.9f, 850.049f, -110.522f, nullptr},
|
|
};
|
|
|
|
// Horde Base to Lumber Mill
|
|
BattleBotPath vPath_AB_HordeBase_to_LumberMill = {
|
|
{707.259f, 707.839f, -17.5318f, nullptr}, {721.611f, 726.507f, -27.9646f, nullptr},
|
|
{733.846f, 743.573f, -35.8633f, nullptr}, {746.201f, 760.547f, -40.838f, nullptr},
|
|
{758.937f, 787.565f, -46.741f, nullptr}, {761.289f, 801.357f, -48.0037f, nullptr},
|
|
{764.341f, 822.128f, -49.6908f, nullptr}, {769.766f, 842.244f, -51.1239f, nullptr},
|
|
{775.322f, 855.093f, -53.1161f, nullptr}, {783.995f, 874.216f, -55.0822f, nullptr},
|
|
{789.917f, 886.902f, -56.2935f, nullptr}, {798.03f, 906.259f, -57.1162f, nullptr},
|
|
{803.183f, 919.266f, -57.6692f, nullptr}, {813.248f, 937.688f, -57.7106f, nullptr},
|
|
{820.412f, 958.712f, -56.1492f, nullptr}, {814.247f, 973.692f, -50.4602f, nullptr},
|
|
{807.697f, 985.502f, -47.2383f, nullptr}, {795.672f, 1002.69f, -44.9382f, nullptr},
|
|
{784.653f, 1020.77f, -38.6278f, nullptr}, {784.826f, 1037.34f, -31.5719f, nullptr},
|
|
{786.083f, 1051.28f, -24.0793f, nullptr}, {787.314f, 1065.23f, -16.8918f, nullptr},
|
|
{788.892f, 1086.17f, -6.42608f, nullptr}, {792.077f, 1106.53f, 4.81124f, nullptr},
|
|
{800.398f, 1119.48f, 8.5814f, nullptr}, {812.476f, 1131.1f, 10.439f, nullptr},
|
|
{829.704f, 1142.52f, 10.738f, nullptr}, {842.646f, 1143.51f, 11.9984f, nullptr},
|
|
{857.674f, 1146.16f, 11.529f, nullptr},
|
|
};
|
|
|
|
// Farm to Blacksmith
|
|
BattleBotPath vPath_AB_Farm_to_Blacksmith = {
|
|
{803.826f, 874.909f, -55.2547f, nullptr}, {808.763f, 887.991f, -57.4437f, nullptr},
|
|
{818.33f, 906.674f, -59.3554f, nullptr}, {828.634f, 924.972f, -60.5664f, nullptr},
|
|
{835.255f, 937.308f, -60.2915f, nullptr}, {845.244f, 955.78f, -60.4208f, nullptr},
|
|
{852.125f, 967.965f, -61.3135f, nullptr}, {863.232f, 983.109f, -62.6402f, nullptr},
|
|
{875.413f, 989.245f, -61.2916f, nullptr}, {895.765f, 994.41f, -63.6287f, nullptr},
|
|
{914.16f, 1001.09f, -58.37f, nullptr}, {932.418f, 1011.44f, -51.9225f, nullptr},
|
|
{944.244f, 1018.92f, -49.1438f, nullptr}, {961.55f, 1030.81f, -45.814f, nullptr},
|
|
{978.122f, 1043.87f, -44.4682f, nullptr},
|
|
};
|
|
|
|
// Stables to Gold Mine
|
|
BattleBotPath vPath_AB_Stables_to_GoldMine = {
|
|
{1169.52f, 1198.71f, -56.2742f, nullptr}, {1166.72f, 1183.58f, -56.3633f, nullptr},
|
|
{1172.14f, 1170.99f, -56.4735f, nullptr}, {1185.18f, 1164.02f, -56.4269f, nullptr},
|
|
{1193.98f, 1155.85f, -55.924f, nullptr}, {1201.51f, 1145.65f, -56.4733f, nullptr},
|
|
{1205.39f, 1134.81f, -56.2366f, nullptr}, {1207.57f, 1106.9f, -58.4748f, nullptr},
|
|
{1209.4f, 1085.98f, -63.4022f, nullptr}, {1212.68f, 1065.25f, -66.514f, nullptr},
|
|
{1216.42f, 1037.52f, -72.0457f, nullptr}, {1215.4f, 1011.56f, -78.3338f, nullptr},
|
|
{1209.8f, 992.293f, -83.2433f, nullptr}, {1201.23f, 973.121f, -88.5661f, nullptr},
|
|
{1192.16f, 954.183f, -94.2209f, nullptr}, {1181.88f, 935.894f, -99.5239f, nullptr},
|
|
{1169.86f, 918.68f, -105.588f, nullptr}, {1159.36f, 900.497f, -110.461f, nullptr},
|
|
{1149.32f, 874.429f, -112.142f, nullptr}, {1145.34f, 849.824f, -110.523f, nullptr},
|
|
};
|
|
|
|
// Stables to Lumber Mill
|
|
BattleBotPath vPath_AB_Stables_to_LumberMill = {
|
|
{1169.52f, 1198.71f, -56.2742f, nullptr}, {1169.33f, 1203.43f, -56.5457f, nullptr},
|
|
{1164.77f, 1208.73f, -56.1907f, nullptr}, {1141.52f, 1224.99f, -53.8204f, nullptr},
|
|
{1127.54f, 1224.82f, -48.2081f, nullptr}, {1106.56f, 1225.58f, -50.5154f, nullptr},
|
|
{1085.6f, 1226.54f, -53.1863f, nullptr}, {1064.6f, 1226.82f, -50.4381f, nullptr},
|
|
{1043.6f, 1227.27f, -46.5439f, nullptr}, {1022.61f, 1227.72f, -44.7157f, nullptr},
|
|
{1001.61f, 1227.62f, -42.6876f, nullptr}, {980.623f, 1226.93f, -40.4687f, nullptr},
|
|
{959.628f, 1227.1f, -35.3838f, nullptr}, {938.776f, 1226.34f, -23.5399f, nullptr},
|
|
{926.138f, 1217.21f, -16.2176f, nullptr}, {911.966f, 1205.99f, -9.69655f, nullptr},
|
|
{895.135f, 1198.85f, -0.546275f, nullptr}, {873.419f, 1189.27f, 9.3466f, nullptr},
|
|
{863.821f, 1181.72f, 9.76912f, nullptr}, {851.803f, 1166.3f, 10.4423f, nullptr},
|
|
{853.921f, 1150.92f, 11.543f, nullptr},
|
|
};
|
|
|
|
// Farm to Gold Mine
|
|
BattleBotPath vPath_AB_Farm_to_GoldMine = {
|
|
{803.826f, 874.909f, -55.2547f, nullptr}, {801.662f, 865.689f, -56.9445f, nullptr},
|
|
{806.433f, 860.776f, -57.5899f, nullptr}, {816.236f, 857.397f, -57.7029f, nullptr},
|
|
{826.717f, 855.846f, -57.9914f, nullptr}, {836.128f, 851.257f, -57.8321f, nullptr},
|
|
{847.933f, 843.837f, -58.1296f, nullptr}, {855.08f, 832.688f, -57.7373f, nullptr},
|
|
{864.513f, 813.663f, -57.574f, nullptr}, {864.229f, 797.762f, -54.2057f, nullptr},
|
|
{862.967f, 787.372f, -53.0276f, nullptr}, {864.163f, 776.33f, -52.0372f, nullptr},
|
|
{872.583f, 777.391f, -48.5342f, nullptr}, {893.575f, 777.922f, -49.1826f, nullptr},
|
|
{915.941f, 783.534f, -53.6598f, nullptr}, {928.105f, 789.929f, -55.4802f, nullptr},
|
|
{946.263f, 800.46f, -59.166f, nullptr}, {958.715f, 806.845f, -62.1494f, nullptr},
|
|
{975.79f, 811.913f, -65.9648f, nullptr}, {989.468f, 814.883f, -71.3089f, nullptr},
|
|
{1010.13f, 818.643f, -80.0817f, nullptr}, {1023.97f, 820.667f, -86.1114f, nullptr},
|
|
{1044.84f, 823.011f, -92.0583f, nullptr}, {1058.77f, 824.482f, -94.1937f, nullptr},
|
|
{1079.13f, 829.402f, -99.1207f, nullptr}, {1092.85f, 836.986f, -102.755f, nullptr},
|
|
{1114.75f, 851.21f, -109.782f, nullptr}, {1128.22f, 851.928f, -111.078f, nullptr},
|
|
{1145.14f, 849.895f, -110.523f, nullptr},
|
|
};
|
|
|
|
// Farm to Lumber Mill
|
|
BattleBotPath vPath_AB_Farm_to_LumberMill = {
|
|
{803.826f, 874.909f, -55.2547f, nullptr}, {802.874f, 894.28f, -56.4661f, nullptr},
|
|
{806.844f, 920.39f, -57.3157f, nullptr}, {814.003f, 934.161f, -57.6065f, nullptr},
|
|
{824.594f, 958.47f, -58.4916f, nullptr}, {820.434f, 971.184f, -53.201f, nullptr},
|
|
{808.339f, 987.79f, -47.5705f, nullptr}, {795.98f, 1004.76f, -44.9189f, nullptr},
|
|
{785.497f, 1019.18f, -39.2806f, nullptr}, {783.94f, 1032.46f, -33.5692f, nullptr},
|
|
{784.956f, 1053.41f, -22.8368f, nullptr}, {787.499f, 1074.25f, -12.4232f, nullptr},
|
|
{789.406f, 1088.11f, -5.28606f, nullptr}, {794.617f, 1109.17f, 6.1966f, nullptr},
|
|
{801.514f, 1120.77f, 8.81455f, nullptr}, {817.3f, 1134.59f, 10.6064f, nullptr},
|
|
{828.961f, 1142.98f, 10.7354f, nullptr}, {841.63f, 1147.75f, 11.6916f, nullptr},
|
|
{854.326f, 1150.55f, 11.537f, nullptr},
|
|
};
|
|
|
|
//* ALLIANCE SIDE WAYPOINTS *//
|
|
BattleBotPath vPath_AV_AllianceSpawn_To_AllianceCrossroad1 = {
|
|
{768.306f, -492.228f, 97.862f, nullptr}, {758.694f, -489.560f, 96.219f, nullptr},
|
|
{718.949f, -473.185f, 75.285f, nullptr}, {701.759f, -457.199f, 64.398f, nullptr},
|
|
{691.888f, -424.726f, 63.641f, nullptr}, {663.458f, -408.930f, 67.525f, nullptr},
|
|
{650.696f, -400.027f, 67.948f, nullptr}, {621.638f, -383.551f, 67.511f, nullptr},
|
|
{584.176f, -395.038f, 65.210f, nullptr}, {554.333f, -392.831f, 55.495f, nullptr},
|
|
{518.020f, -415.663f, 43.470f, nullptr}, {444.974f, -429.032f, 27.276f, nullptr},
|
|
{418.297f, -409.409f, 9.173f, nullptr}, {400.182f, -392.450f, -1.197f, nullptr}
|
|
};
|
|
|
|
BattleBotPath vPath_AV_AllianceFortress_To_AllianceCrossroad1 = {
|
|
{654.750f, -32.779f, 48.611f, nullptr}, {639.731f, -46.509f, 44.072f, nullptr},
|
|
{630.953f, -64.360f, 41.341f, nullptr}, {634.789f, -85.583f, 41.495f, nullptr},
|
|
{628.271f, -100.943f, 40.328f, nullptr}, {621.330f, -129.900f, 33.687f, nullptr},
|
|
{620.615f, -153.156f, 33.606f, nullptr}, {622.186f, -171.443f, 36.848f, nullptr},
|
|
{624.456f, -188.047f, 38.569f, nullptr}, {629.185f, -222.637f, 38.362f, nullptr},
|
|
{633.239f, -252.286f, 34.275f, nullptr}, {635.941f, -272.053f, 30.130f, nullptr},
|
|
{632.884f, -294.946f, 30.267f, nullptr}, {625.348f, -322.407f, 30.133f, nullptr},
|
|
{608.386f, -335.968f, 30.347f, nullptr}, {588.856f, -331.991f, 30.485f, nullptr},
|
|
{560.140f, -327.872f, 17.396f, nullptr}, {530.523f, -324.481f, 1.718f, nullptr},
|
|
{511.340f, -329.767f, -1.084f, nullptr}, {497.221f, -341.494f, -1.184f, nullptr},
|
|
{465.281f, -365.577f, -1.243f, nullptr}, {437.839f, -376.473f, -1.243f, nullptr},
|
|
{414.292f, -384.557f, -1.243f, nullptr}
|
|
};
|
|
|
|
BattleBotPath vPath_AV_AllianceCrossroad1_To_AllianceCrossroad2 = {
|
|
{391.160f, -391.667f, -1.244f, nullptr}, {369.595f, -388.874f, -0.153f, nullptr},
|
|
{334.986f, -384.282f, -0.726f, nullptr}, {308.373f, -383.026f, -0.336f, nullptr},
|
|
{287.175f, -386.773f, 5.531f, nullptr}, {276.595f, -394.487f, 12.126f, nullptr},
|
|
{264.248f, -405.109f, 23.509f, nullptr}, {253.142f, -412.069f, 31.665f, nullptr},
|
|
{237.243f, -416.570f, 37.103f, nullptr}, {216.805f, -416.987f, 40.497f, nullptr},
|
|
{195.369f, -407.750f, 42.876f, nullptr}, {179.619f, -402.642f, 42.793f, nullptr},
|
|
{157.154f, -391.535f, 43.616f, nullptr}, {137.928f, -380.956f, 43.018f, nullptr},
|
|
{117.990f, -380.243f, 43.571f, nullptr}
|
|
};
|
|
|
|
BattleBotPath vPath_AV_StoneheartGrave_To_AllianceCrossroad2 = {
|
|
{73.141f, -481.863f, 48.479f, nullptr}, {72.974f, -461.923f, 48.498f, nullptr},
|
|
{73.498f, -443.377f, 48.989f, nullptr}, {74.061f, -423.435f, 49.235f, nullptr},
|
|
{83.086f, -403.871f, 47.412f, nullptr}, {102.003f, -388.023f, 45.095f, nullptr}
|
|
};
|
|
|
|
BattleBotPath vPath_AV_AllianceCrossroad2_To_StoneheartBunker = {
|
|
{113.412f, -381.154f, 44.324f, nullptr}, {87.868f, -389.039f, 45.025f, nullptr},
|
|
{62.170f, -388.790f, 45.012f, nullptr}, {30.645f, -390.873f, 45.644f, nullptr},
|
|
{6.239f, -410.405f, 45.157f, nullptr}, {-11.185f, -423.994f, 45.222f, nullptr},
|
|
{-19.595f, -437.877f, 46.383f, nullptr}, {-31.747f, -451.316f, 45.500f, nullptr},
|
|
{-49.279f, -466.706f, 41.101f, nullptr}, {-78.427f, -459.899f, 27.648f, nullptr},
|
|
{-103.623f, -467.766f, 24.806f, nullptr}, {-113.718f, -476.527f, 25.802f, nullptr},
|
|
{-129.793f, -481.160f, 27.735f, nullptr}
|
|
};
|
|
|
|
BattleBotPath vPath_AV_AllianceCrossroad2_To_AllianceCaptain = {
|
|
{117.948f, -363.836f, 43.485f, nullptr}, {110.096f, -342.635f, 41.331f, nullptr},
|
|
{92.672f, -320.463f, 35.312f, nullptr}, {75.147f, -303.007f, 29.411f, nullptr},
|
|
{59.694f, -293.137f, 24.670f, nullptr}, {41.342f, -293.374f, 17.193f, nullptr},
|
|
{22.388f, -299.599f, 14.204f, nullptr}
|
|
};
|
|
|
|
BattleBotPath vPath_AV_AllianceCrossroads3_To_SnowfallGraveyard = {
|
|
{-141.090f, -248.599f, 6.746f, nullptr}, {-147.551f, -233.354f, 9.675f, nullptr},
|
|
{-153.353f, -219.665f, 17.267f, nullptr}, {-159.091f, -205.990f, 26.091f, nullptr},
|
|
{-164.041f, -188.716f, 35.813f, nullptr}, {-170.634f, -166.838f, 51.540f, nullptr},
|
|
{-183.338f, -154.159f, 64.252f, nullptr}, {-193.333f, -139.166f, 74.581f, nullptr},
|
|
{-199.853f, -124.194f, 78.247f, nullptr}
|
|
};
|
|
|
|
BattleBotPath vPath_AV_AllianceCaptain_To_AllianceCrossroad3 = {
|
|
{31.023f, -290.783f, 15.966f, nullptr}, {31.857f, -270.165f, 16.040f, nullptr},
|
|
{26.531f, -242.488f, 14.158f, nullptr}, {3.448f, -241.318f, 11.900f, nullptr},
|
|
{-24.158f, -233.744f, 9.802f, nullptr}, {-55.556f, -235.327f, 10.038f, nullptr},
|
|
{-93.670f, -255.273f, 6.264f, nullptr}, {-117.164f, -263.636f, 6.363f, nullptr}
|
|
};
|
|
|
|
BattleBotPath vPath_AV_AllianceCaptain_To_HordeCrossroad3 = {
|
|
{31.023f, -290.783f, 15.966f, nullptr}, {31.857f, -270.165f, 16.040f, nullptr},
|
|
{26.531f, -242.488f, 14.158f, nullptr}, {3.448f, -241.318f, 11.900f, nullptr},
|
|
{-24.158f, -233.744f, 9.802f, nullptr}, {-55.556f, -235.327f, 10.038f, nullptr},
|
|
{-93.670f, -255.273f, 6.264f, nullptr}, {-117.164f, -263.636f, 6.363f, nullptr},
|
|
{-154.433f, -272.428f, 8.016f, nullptr}, {-165.219f, -277.141f, 9.138f, nullptr},
|
|
{-174.154f, -281.561f, 7.062f, nullptr}, {-189.765f, -290.755f, 6.668f, nullptr},
|
|
{-213.121f, -303.227f, 6.668f, nullptr}, {-240.497f, -315.013f, 6.668f, nullptr},
|
|
{-260.829f, -329.400f, 6.677f, nullptr}, {-280.652f, -344.530f, 6.668f, nullptr},
|
|
{-305.708f, -363.655f, 6.668f, nullptr}, {-326.363f, -377.530f, 6.668f, nullptr},
|
|
{-347.706f, -377.546f, 11.493f, nullptr}, {-361.965f, -373.012f, 13.904f, nullptr},
|
|
{-379.646f, -367.389f, 16.907f, nullptr}, {-399.610f, -353.045f, 17.793f, nullptr},
|
|
{-411.324f, -335.019f, 17.564f, nullptr}, {-421.800f, -316.128f, 17.843f, nullptr},
|
|
{-435.855f, -293.863f, 19.553f, nullptr}, {-454.279f, -277.457f, 21.943f, nullptr},
|
|
{-473.868f, -280.536f, 24.837f, nullptr}, {-492.305f, -289.846f, 29.787f, nullptr},
|
|
{-504.724f, -313.745f, 31.938f, nullptr}, {-518.431f, -333.087f, 34.017f, nullptr}
|
|
};
|
|
|
|
BattleBotPath vPath_AV_StoneheartBunker_To_HordeCrossroad3 = {
|
|
{-507.656f, -342.031f, 33.079f, nullptr}, {-490.580f, -348.193f, 29.170f, nullptr},
|
|
{-458.194f, -343.101f, 31.685f, nullptr}, {-441.632f, -329.773f, 19.349f, nullptr},
|
|
{-429.951f, -333.153f, 18.078f, nullptr}, {-415.858f, -341.834f, 17.865f, nullptr},
|
|
{-406.698f, -361.322f, 17.764f, nullptr}, {-394.097f, -376.775f, 16.309f, nullptr},
|
|
{-380.107f, -393.161f, 10.662f, nullptr}, {-359.474f, -405.379f, 10.437f, nullptr},
|
|
{-343.166f, -415.036f, 10.177f, nullptr}, {-328.328f, -423.823f, 11.057f, nullptr},
|
|
{-315.454f, -431.447f, 17.709f, nullptr}, {-296.180f, -449.228f, 22.316f, nullptr},
|
|
{-272.700f, -459.303f, 28.764f, nullptr}, {-262.987f, -457.030f, 30.248f, nullptr},
|
|
{-244.145f, -452.620f, 25.754f, nullptr}, {-221.311f, -448.195f, 25.166f, nullptr},
|
|
{-201.762f, -457.441f, 27.413f, nullptr}, {-172.130f, -474.654f, 28.884f, nullptr},
|
|
{-153.135f, -480.692f, 30.459f, nullptr}, {-137.077f, -478.766f, 28.798f, nullptr}
|
|
};
|
|
|
|
BattleBotPath vPath_AV_AllianceCrossroad1_To_AllianceMine = {
|
|
{414.329f, -386.483f, -1.244f, nullptr}, {428.252f, -380.010f, -1.244f, nullptr},
|
|
{446.203f, -372.263f, -1.244f, nullptr}, {468.352f, -360.936f, -1.244f, nullptr},
|
|
{490.502f, -344.252f, -1.228f, nullptr}, {515.565f, -328.078f, -1.085f, nullptr},
|
|
{531.431f, -323.435f, 1.906f, nullptr}, {548.612f, -324.795f, 10.162f, nullptr},
|
|
{565.412f, -326.485f, 20.217f, nullptr}, {579.313f, -331.417f, 28.435f, nullptr},
|
|
{593.026f, -336.281f, 30.215f, nullptr}, {614.580f, -331.387f, 30.236f, nullptr},
|
|
{626.524f, -309.520f, 30.375f, nullptr}, {642.822f, -290.896f, 30.201f, nullptr},
|
|
{661.428f, -285.810f, 29.862f, nullptr}, {670.488f, -281.637f, 27.951f, nullptr},
|
|
{687.522f, -273.793f, 23.510f, nullptr}, {706.938f, -272.231f, 31.122f, nullptr},
|
|
{725.715f, -281.845f, 40.529f, nullptr}, {733.208f, -296.224f, 47.418f, nullptr},
|
|
{742.182f, -308.196f, 52.947f, nullptr}, {749.742f, -319.208f, 56.275f, nullptr},
|
|
{760.992f, -335.660f, 60.279f, nullptr}, {783.734f, -342.468f, 61.410f, nullptr},
|
|
{791.843f, -330.986f, 63.040f, nullptr}, {800.683f, -338.452f, 63.286f, nullptr},
|
|
{812.383f, -337.218f, 64.698f, nullptr}, {826.326f, -331.789f, 64.492f, nullptr},
|
|
{839.641f, -338.601f, 65.461f, nullptr}, {851.763f, -345.123f, 65.935f, nullptr},
|
|
{871.511f, -345.464f, 64.947f, nullptr}, {882.320f, -340.819f, 66.864f, nullptr},
|
|
{898.911f, -333.166f, 67.532f, nullptr}, {910.825f, -334.185f, 66.889f, nullptr},
|
|
{922.109f, -336.746f, 66.120f, nullptr}, {929.915f, -353.314f, 65.902f, nullptr},
|
|
{918.736f, -367.359f, 66.307f, nullptr}, {920.196f, -380.444f, 62.599f, nullptr},
|
|
{920.625f, -400.310f, 59.454f, nullptr}, {920.521f, -410.085f, 57.002f, nullptr},
|
|
{917.319f, -424.261f, 56.972f, nullptr}, {909.302f, -429.930f, 58.459f, nullptr},
|
|
{893.164f, -430.083f, 55.782f, nullptr}, {873.846f, -425.108f, 51.387f, nullptr},
|
|
{860.920f, -421.705f, 51.032f, nullptr}, {839.651f, -412.104f, 47.572f, nullptr},
|
|
{831.515f, -410.477f, 47.778f, nullptr}
|
|
};
|
|
//* ALLIANCE SIDE WAYPOINTS *//
|
|
|
|
//* HORDE SIDE WAYPOINTS *//
|
|
BattleBotPath vPath_AV_HordeSpawn_To_MainRoad = {
|
|
{-1366.182f, -532.170f, 53.354f, nullptr}, {-1325.007f, -516.055f, 51.554f, nullptr},
|
|
{-1273.492f, -514.574f, 50.360f, nullptr}, {-1232.875f, -515.097f, 51.085f, nullptr},
|
|
{-1201.299f, -500.807f, 51.665f, nullptr}, {-1161.199f, -476.367f, 54.956f, nullptr},
|
|
{-1135.679f, -469.551f, 56.934f, nullptr}, {-1113.439f, -458.271f, 52.196f, nullptr},
|
|
{-1086.750f, -444.735f, 52.903f, nullptr}, {-1061.950f, -434.380f, 51.396f, nullptr},
|
|
{-1031.777f, -424.596f, 51.262f, nullptr}, {-967.556f, -399.110f, 49.213f, nullptr}
|
|
};
|
|
|
|
BattleBotPath vPath_AV_SnowfallGraveyard_To_HordeCaptain = {
|
|
{-213.992f, -103.451f, 79.389f, nullptr}, {-222.690f, -95.820f, 77.588f, nullptr},
|
|
{-237.377f, -88.173f, 65.871f, nullptr}, {-253.605f, -85.059f, 56.342f, nullptr},
|
|
{-272.886f, -94.676f, 42.306f, nullptr}, {-289.627f, -108.123f, 26.978f, nullptr},
|
|
{-304.265f, -105.120f, 20.341f, nullptr}, {-316.857f, -92.162f, 22.999f, nullptr},
|
|
{-332.066f, -75.537f, 27.062f, nullptr}, {-358.184f, -76.459f, 27.212f, nullptr},
|
|
{-388.166f, -81.693f, 23.836f, nullptr}, {-407.733f, -90.216f, 23.385f, nullptr},
|
|
{-420.646f, -122.109f, 23.955f, nullptr}, {-418.916f, -143.640f, 24.135f, nullptr},
|
|
{-419.211f, -171.836f, 24.088f, nullptr}, {-425.798f, -195.843f, 26.290f, nullptr},
|
|
{-445.352f, -195.483f, 35.300f, nullptr}, {-464.614f, -194.387f, 49.409f, nullptr},
|
|
{-477.910f, -193.219f, 54.985f, nullptr}, {-488.230f, -187.985f, 56.729f, nullptr}
|
|
};
|
|
|
|
BattleBotPath vPath_AV_HordeCrossroad3_To_IcebloodTower = {
|
|
{-533.792f, -341.435f, 35.860f, nullptr}, {-551.527f, -332.298f, 38.432f, nullptr},
|
|
{-574.093f, -312.653f, 44.791f, nullptr}
|
|
};
|
|
|
|
BattleBotPath vPath_AV_IcebloodTower_To_HordeCaptain = {
|
|
{-569.690f, -295.928f, 49.096f, nullptr}, {-559.809f, -282.641f, 52.074f, nullptr},
|
|
{-546.890f, -261.488f, 53.194f, nullptr}, {-529.471f, -236.931f, 56.746f, nullptr},
|
|
{-518.182f, -222.736f, 56.922f, nullptr}, {-500.372f, -205.938f, 57.364f, nullptr},
|
|
{-494.455f, -190.473f, 57.190f, nullptr}
|
|
};
|
|
|
|
BattleBotPath vPath_AV_IcebloodTower_To_IcebloodGrave = {
|
|
{-584.305f, -313.025f, 47.651f, nullptr}, {-600.831f, -327.032f, 51.026f, nullptr},
|
|
{-613.276f, -343.187f, 54.958f, nullptr}, {-625.873f, -364.812f, 56.829f, nullptr},
|
|
{-625.494f, -390.816f, 58.781f, nullptr}
|
|
};
|
|
|
|
BattleBotPath vPath_AV_IcebloodGrave_To_TowerBottom = {
|
|
{-635.524f, -393.738f, 59.527f, nullptr}, {-659.484f, -386.214f, 63.131f, nullptr},
|
|
{-679.221f, -374.851f, 65.710f, nullptr}, {-694.579f, -368.145f, 66.017f, nullptr},
|
|
{-726.698f, -346.235f, 66.804f, nullptr}, {-743.446f, -345.899f, 66.566f, nullptr},
|
|
{-754.564f, -344.804f, 67.422f, nullptr}
|
|
};
|
|
|
|
BattleBotPath vPath_AV_TowerBottom_To_HordeCrossroad1 = {
|
|
{-764.722f, -339.262f, 67.669f, nullptr}, {-777.559f, -338.964f, 66.287f, nullptr},
|
|
{-796.674f, -341.982f, 61.848f, nullptr}, {-812.721f, -346.317f, 53.286f, nullptr},
|
|
{-826.586f, -350.765f, 50.140f, nullptr}, {-842.410f, -355.642f, 49.750f, nullptr},
|
|
{-861.475f, -361.517f, 50.514f, nullptr}, {-878.634f, -366.805f, 49.987f, nullptr},
|
|
{-897.097f, -374.362f, 48.931f, nullptr}, {-920.177f, -383.808f, 49.487f, nullptr},
|
|
{-947.087f, -392.660f, 48.533f, nullptr}, {-977.268f, -395.606f, 49.426f, nullptr},
|
|
{-993.685f, -394.251f, 50.180f, nullptr}, {-1016.760f, -390.774f, 50.955f, nullptr},
|
|
{-1042.994f, -383.854f, 50.904f, nullptr}, {-1066.925f, -377.541f, 52.535f, nullptr},
|
|
{-1103.309f, -365.939f, 51.502f, nullptr}, {-1127.469f, -354.968f, 51.502f, nullptr}
|
|
};
|
|
|
|
BattleBotPath vPath_AV_HordeCrossroad1_To_FrostwolfGrave = {
|
|
{-1127.565f, -340.254f, 51.753f, nullptr}, {-1112.843f, -337.645f, 53.368f, nullptr},
|
|
{-1089.873f, -334.993f, 54.580f, nullptr}
|
|
};
|
|
|
|
BattleBotPath vPath_AV_HordeCrossroad1_To_HordeFortress = {
|
|
{-1140.070f, -349.834f, 51.090f, nullptr}, {-1161.807f, -352.447f, 51.782f, nullptr},
|
|
{-1182.047f, -361.856f, 52.458f, nullptr}, {-1203.318f, -365.951f, 54.427f, nullptr},
|
|
{-1228.105f, -367.462f, 58.155f, nullptr}, {-1243.013f, -357.409f, 59.866f, nullptr},
|
|
{-1245.382f, -337.206f, 59.322f, nullptr}, {-1236.790f, -323.051f, 60.500f, nullptr},
|
|
{-1227.642f, -311.981f, 63.269f, nullptr}, {-1217.120f, -299.546f, 69.058f, nullptr},
|
|
{-1207.536f, -288.218f, 71.742f, nullptr}, {-1198.808f, -270.859f, 72.431f, nullptr},
|
|
{-1203.695f, -255.038f, 72.498f, nullptr}, {-1220.292f, -252.715f, 73.243f, nullptr},
|
|
{-1236.539f, -252.215f, 73.326f, nullptr}, {-1246.512f, -257.577f, 73.326f, nullptr},
|
|
{-1257.051f, -272.847f, 73.018f, nullptr}, {-1265.600f, -284.769f, 77.939f, nullptr},
|
|
{-1282.656f, -290.696f, 88.334f, nullptr}, {-1292.589f, -290.809f, 90.446f, nullptr},
|
|
{-1307.385f, -290.950f, 90.681f, nullptr}, {-1318.955f, -291.061f, 90.451f, nullptr},
|
|
{-1332.717f, -291.117f, 90.806f, nullptr}, {-1346.880f, -287.015f, 91.066f, nullptr}
|
|
};
|
|
|
|
BattleBotPath vPath_AV_FrostwolfGrave_To_HordeMine = {
|
|
{-1075.070f, -332.081f, 55.758f, nullptr}, {-1055.926f, -326.469f, 57.026f, nullptr},
|
|
{-1036.115f, -328.239f, 59.368f, nullptr}, {-1018.217f, -332.306f, 59.335f, nullptr},
|
|
{-990.396f, -337.397f, 58.342f, nullptr}, {-963.987f, -335.529f, 60.945f, nullptr},
|
|
{-954.477f, -321.258f, 63.429f, nullptr}, {-951.052f, -301.476f, 64.761f, nullptr},
|
|
{-955.257f, -282.794f, 63.683f, nullptr}, {-960.355f, -261.040f, 64.498f, nullptr},
|
|
{-967.410f, -230.933f, 67.408f, nullptr}, {-967.187f, -207.444f, 68.924f, nullptr},
|
|
};
|
|
//* HORDE SIDE WAYPOINTS *//
|
|
|
|
BattleBotPath vPath_EY_Horde_Spawn_to_Crossroad1Horde = {
|
|
{1809.102f, 1540.854f, 1267.142f, nullptr}, {1832.335f, 1539.495f, 1256.417f, nullptr},
|
|
{1846.995f, 1539.792f, 1243.077f, nullptr}, {1846.243f, 1530.716f, 1238.477f, nullptr},
|
|
{1883.154f, 1532.143f, 1202.143f, nullptr}, {1941.452f, 1549.086f, 1176.700f, nullptr}};
|
|
|
|
BattleBotPath vPath_EY_Horde_Crossroad1Horde_to_Crossroad2Horde = {{1951.647f, 1545.187f, 1174.831f, nullptr},
|
|
{1992.266f, 1546.962f, 1169.816f, nullptr},
|
|
{2045.865f, 1543.925f, 1163.759f, nullptr}};
|
|
|
|
BattleBotPath vPath_EY_Crossroad1Horde_to_Blood_Elf_Tower = {{1952.907f, 1539.857f, 1174.638f, nullptr},
|
|
{2000.130f, 1508.182f, 1169.778f, nullptr},
|
|
{2044.239f, 1483.860f, 1166.165f, nullptr},
|
|
{2048.773f, 1389.578f, 1193.903f, nullptr}};
|
|
|
|
BattleBotPath vPath_EY_Crossroad1Horde_to_Fel_Reaver_Ruins = {{1944.301f, 1557.170f, 1176.370f, nullptr},
|
|
{1992.953f, 1625.188f, 1173.616f, nullptr},
|
|
{2040.421f, 1676.989f, 1177.079f, nullptr},
|
|
{2045.527f, 1736.398f, 1189.661f, nullptr}};
|
|
|
|
BattleBotPath vPath_EY_Crossroad2Horde_to_Blood_Elf_Tower = {{2049.363f, 1532.337f, 1163.178f, nullptr},
|
|
{2050.149f, 1484.721f, 1165.099f, nullptr},
|
|
{2046.865f, 1423.937f, 1188.882f, nullptr},
|
|
{2048.478f, 1389.491f, 1193.878f, nullptr}};
|
|
|
|
BattleBotPath vPath_EY_Crossroad2Horde_to_Fel_Reaver_Ruins = {{2052.267f, 1555.692f, 1163.147f, nullptr},
|
|
{2047.684f, 1614.272f, 1165.397f, nullptr},
|
|
{2045.993f, 1668.937f, 1174.978f, nullptr},
|
|
{2044.286f, 1733.128f, 1189.739f, nullptr}};
|
|
|
|
BattleBotPath vPath_EY_Crossroad2Horde_to_Flag = {{2059.276f, 1546.143f, 1162.394f, nullptr},
|
|
{2115.978f, 1559.244f, 1156.362f, nullptr},
|
|
{2149.140f, 1556.570f, 1158.412f, nullptr},
|
|
{2170.601f, 1567.113f, 1159.456f, nullptr}};
|
|
|
|
BattleBotPath vPath_EY_Alliance_Spawn_to_Crossroad1Alliance = {
|
|
{2502.110f, 1604.330f, 1260.750f, nullptr}, {2497.077f, 1596.198f, 1257.302f, nullptr},
|
|
{2483.930f, 1597.062f, 1244.660f, nullptr}, {2486.549f, 1617.651f, 1225.837f, nullptr},
|
|
{2449.150f, 1601.792f, 1201.552f, nullptr}, {2395.737f, 1588.287f, 1176.570f, nullptr}};
|
|
|
|
BattleBotPath vPath_EY_Alliance_Crossroad1Alliance_to_Crossroad2Alliance = {
|
|
{2380.262f, 1586.757f, 1173.567f, nullptr},
|
|
{2333.956f, 1586.052f, 1169.873f, nullptr},
|
|
{2291.210f, 1591.435f, 1166.048f, nullptr},
|
|
};
|
|
|
|
BattleBotPath vPath_EY_Crossroad1Alliance_to_Mage_Tower = {{2380.973f, 1593.445f, 1173.189f, nullptr},
|
|
{2335.762f, 1621.922f, 1169.007f, nullptr},
|
|
{2293.526f, 1643.972f, 1166.501f, nullptr},
|
|
{2288.198f, 1688.568f, 1172.790f, nullptr},
|
|
{2284.286f, 1737.889f, 1189.708f, nullptr}};
|
|
|
|
BattleBotPath vPath_EY_Crossroad1Alliance_to_Draenei_Ruins = {{2388.687f, 1576.089f, 1175.975f, nullptr},
|
|
{2354.921f, 1522.763f, 1176.060f, nullptr},
|
|
{2300.056f, 1459.208f, 1184.181f, nullptr},
|
|
{2289.880f, 1415.640f, 1196.755f, nullptr},
|
|
{2279.870f, 1387.461f, 1195.003f, nullptr}};
|
|
|
|
BattleBotPath vPath_EY_Crossroad2Alliance_to_Mage_Tower = {{2282.525f, 1597.721f, 1164.553f, nullptr},
|
|
{2281.028f, 1651.310f, 1165.426f, nullptr},
|
|
{2284.633f, 1736.082f, 1189.708f, nullptr}};
|
|
|
|
BattleBotPath vPath_EY_Crossroad2Alliance_to_Draenei_Ruins = {{2282.487f, 1581.630f, 1165.318f, nullptr},
|
|
{2284.728f, 1525.618f, 1170.812f, nullptr},
|
|
{2287.697f, 1461.228f, 1183.450f, nullptr},
|
|
{2290.861f, 1413.606f, 1197.115f, nullptr}};
|
|
|
|
BattleBotPath vPath_EY_Crossroad2Alliance_to_Flag = {{2275.622f, 1586.123f, 1164.469f, nullptr},
|
|
{2221.334f, 1575.123f, 1158.277f, nullptr},
|
|
{2178.372f, 1572.144f, 1159.462f, nullptr}};
|
|
|
|
BattleBotPath vPath_EY_Draenei_Ruins_to_Blood_Elf_Tower = {
|
|
{2287.925f, 1406.976f, 1197.004f, nullptr}, {2283.283f, 1454.769f, 1184.243f, nullptr},
|
|
{2237.519f, 1398.161f, 1178.191f, nullptr}, {2173.150f, 1388.084f, 1170.185f, nullptr},
|
|
{2105.039f, 1381.507f, 1162.911f, nullptr}, {2074.315f, 1404.387f, 1178.141f, nullptr},
|
|
{2047.649f, 1411.681f, 1192.032f, nullptr}, {2049.197f, 1387.392f, 1193.799f, nullptr}};
|
|
|
|
BattleBotPath vPath_EY_Fel_Reaver_to_Mage_Tower = {
|
|
{2044.519f, 1726.113f, 1189.395f, nullptr}, {2045.408f, 1682.986f, 1177.574f, nullptr},
|
|
{2097.595f, 1736.117f, 1170.419f, nullptr}, {2158.866f, 1746.998f, 1161.184f, nullptr},
|
|
{2220.635f, 1757.837f, 1151.886f, nullptr}, {2249.922f, 1721.807f, 1161.550f, nullptr},
|
|
{2281.021f, 1694.735f, 1174.020f, nullptr}, {2284.522f, 1728.234f, 1189.015f, nullptr}};
|
|
|
|
BattleBotPath vPath_IC_Ally_Keep_to_Ally_Front_Crossroad = {
|
|
//{ 351.652f, -834.837f, 48.916f, nullptr },
|
|
{434.768f, -833.976f, 46.090f, nullptr},
|
|
{506.782f, -828.594f, 24.313f, nullptr},
|
|
{524.955f, -799.002f, 19.498f, nullptr}};
|
|
|
|
BattleBotPath vPath_IC_Ally_Front_Crossroad_to_Workshop = {
|
|
{524.955f, -799.002f, 19.498f, nullptr}, {573.557f, -804.838f, 9.6291f, nullptr},
|
|
{627.977f, -810.197f, 3.5154f, nullptr}, {681.501f, -805.208f, 3.1464f, nullptr},
|
|
{721.905f, -797.917f, 4.5112f, nullptr}, {774.466f, -801.058f, 6.3428f, nullptr}};
|
|
|
|
BattleBotPath vPath_IC_Ally_Keep_to_Ally_Dock_Crossroad = {{434.768f, -833.976f, 46.090f, nullptr},
|
|
{446.710f, -776.008f, 48.783f, nullptr},
|
|
{463.745f, -742.368f, 48.584f, nullptr},
|
|
{488.201f, -714.563f, 36.564f, nullptr},
|
|
{525.923f, -666.880f, 25.425f, nullptr}};
|
|
|
|
BattleBotPath vPath_IC_Ally_Front_Crossroad_to_Ally_Dock_Crossroad = {{524.955f, -799.002f, 19.498f, nullptr},
|
|
{542.225f, -745.142f, 18.348f, nullptr},
|
|
{545.309f, -712.497f, 22.005f, nullptr},
|
|
{538.678f, -748.361f, 18.261f, nullptr},
|
|
{525.923f, -666.880f, 25.425f, nullptr}};
|
|
|
|
BattleBotPath vPath_IC_Lower_Graveyard_to_Lower_Graveyard_Crossroad = {{443.095f, -310.797f, 51.749f, nullptr},
|
|
{462.733f, -323.587f, 48.706f, nullptr},
|
|
{471.540f, -343.914f, 40.706f, nullptr},
|
|
{475.622f, -360.728f, 34.384f, nullptr},
|
|
{484.458f, -379.796f, 33.122f, nullptr}};
|
|
|
|
BattleBotPath vPath_IC_Lower_Graveyard_Crossroad_to_Ally_Docks_Crossroad = {
|
|
{484.458f, -379.796f, 33.122f, nullptr}, {509.786f, -380.592f, 33.122f, nullptr},
|
|
{532.549f, -381.576f, 33.122f, nullptr}, {553.506f, -386.102f, 33.507f, nullptr},
|
|
{580.533f, -398.536f, 33.416f, nullptr}, {605.112f, -409.843f, 33.121f, nullptr},
|
|
{619.212f, -419.169f, 33.121f, nullptr}, {631.702f, -428.763f, 33.070f, nullptr},
|
|
{648.483f, -444.714f, 28.629f, nullptr}};
|
|
|
|
BattleBotPath vPath_IC_Lower_Graveyard_Crossroad_to_Ally_Docks_Second_Crossroad = {
|
|
{484.458f, -379.796f, 33.122f, nullptr}, {470.771f, -394.789f, 33.112f, nullptr},
|
|
{461.191f, -409.475f, 33.120f, nullptr}, {452.794f, -431.842f, 33.120f, nullptr},
|
|
{452.794f, -456.896f, 33.658f, nullptr}, {453.279f, -481.742f, 33.052f, nullptr},
|
|
{453.621f, -504.979f, 32.956f, nullptr}, {452.006f, -526.792f, 32.221f, nullptr},
|
|
{453.150f, -548.212f, 29.133f, nullptr}, {455.224f, -571.323f, 26.119f, nullptr},
|
|
{465.486f, -585.424f, 25.756f, nullptr}, {475.366f, -598.414f, 25.784f, nullptr},
|
|
{477.702f, -605.757f, 25.714f, nullptr}};
|
|
|
|
BattleBotPath vPath_IC_Ally_Dock_Crossroad_to_Ally_Docks_Second_Crossroad = {{525.923f, -666.880f, 25.425f, nullptr},
|
|
{497.190f, -630.709f, 25.626f, nullptr},
|
|
{477.702f, -605.757f, 25.714f, nullptr}};
|
|
|
|
BattleBotPath vPath_IC_Ally_Docks_Second_Crossroad_to_Ally_Docks_Crossroad = {{477.702f, -605.757f, 25.714f, nullptr},
|
|
{493.697f, -555.838f, 26.014f, nullptr},
|
|
{522.939f, -525.199f, 26.014f, nullptr},
|
|
{580.398f, -486.274f, 26.013f, nullptr},
|
|
{650.132f, -445.811f, 28.503f, nullptr}};
|
|
|
|
BattleBotPath vPath_IC_Ally_Docks_Crossroad_to_Docks_Flag = {{650.132f, -445.811f, 28.503f, nullptr},
|
|
{690.527f, -452.961f, 18.039f, nullptr},
|
|
{706.813f, -430.003f, 13.797f, nullptr},
|
|
{726.427f, -364.849f, 17.815f, nullptr}};
|
|
|
|
BattleBotPath vPath_IC_Docks_Graveyard_to_Docks_Flag = {
|
|
{638.142f, -283.782f, 11.512f, nullptr}, {655.760f, -284.433f, 13.220f, nullptr},
|
|
{661.656f, -299.912f, 12.756f, nullptr}, {675.068f, -317.192f, 12.627f, nullptr},
|
|
{692.712f, -323.866f, 12.686f, nullptr}, {712.968f, -341.285f, 13.350f, nullptr},
|
|
{726.427f, -364.849f, 17.815f, nullptr}};
|
|
|
|
BattleBotPath vPath_IC_Ally_Keep_to_Quarry_Crossroad = {
|
|
{320.547f, -919.896f, 48.481f, nullptr}, {335.384f, -922.371f, 49.518f, nullptr},
|
|
{353.471f, -920.316f, 48.660f, nullptr}, {353.305f, -958.823f, 47.665f, nullptr},
|
|
{369.196f, -989.960f, 37.719f, nullptr}, {380.671f, -1023.51f, 29.369f, nullptr}};
|
|
|
|
BattleBotPath vPath_IC_Quarry_Crossroad_to_Quarry_Flag = {
|
|
{380.671f, -1023.51f, 29.369f, nullptr}, {361.584f, -1052.89f, 27.445f, nullptr},
|
|
{341.853f, -1070.17f, 24.024f, nullptr}, {295.845f, -1075.22f, 16.164f, nullptr},
|
|
{253.030f, -1094.06f, 4.1517f, nullptr}, {211.391f, -1121.80f, 1.9591f, nullptr},
|
|
{187.836f, -1155.66f, 1.9749f, nullptr}, {221.193f, -1186.87f, 8.0247f, nullptr},
|
|
{249.181f, -1162.09f, 16.687f, nullptr}};
|
|
|
|
BattleBotPath vPath_IC_Ally_Front_Crossroad_to_Hangar_First_Crossroad = {{524.955f, -799.002f, 19.498f, nullptr},
|
|
{512.563f, -840.166f, 23.913f, nullptr},
|
|
{513.418f, -877.726f, 26.333f, nullptr},
|
|
{512.962f, -945.951f, 39.382f, nullptr}};
|
|
|
|
BattleBotPath vPath_IC_Ally_Keep_to_Hangar_First_Crossroad = {{434.768f, -833.976f, 46.090f, nullptr},
|
|
{486.355f, -909.736f, 26.112f, nullptr},
|
|
{512.962f, -945.951f, 39.382f, nullptr}};
|
|
|
|
BattleBotPath vPath_IC_Hangar_First_Crossroad_to_Hangar_Second_Crossroad = {{512.962f, -945.951f, 39.382f, nullptr},
|
|
{499.525f, -985.850f, 47.659f, nullptr},
|
|
{492.794f, -1016.36f, 49.834f, nullptr},
|
|
{481.738f, -1052.67f, 60.190f, nullptr}};
|
|
|
|
BattleBotPath vPath_IC_Quarry_Crossroad_to_Hangar_Second_Crossroad = {{380.671f, -1023.51f, 29.369f, nullptr},
|
|
{430.997f, -1021.72f, 31.021f, nullptr},
|
|
{439.528f, -1044.88f, 41.827f, nullptr},
|
|
{455.062f, -1060.67f, 67.209f, nullptr},
|
|
{481.738f, -1052.67f, 60.190f, nullptr}};
|
|
|
|
BattleBotPath vPath_IC_Hangar_Second_Crossroad_to_Hangar_Flag = {
|
|
{508.945f, -1103.30f, 79.054f, nullptr}, {536.397f, -1145.79f, 95.478f, nullptr},
|
|
{573.242f, -1138.19f, 109.26f, nullptr}, {609.051f, -1112.93f, 128.31f, nullptr},
|
|
{645.569f, -1094.58f, 132.13f, nullptr}, {689.621f, -1068.33f, 132.87f, nullptr},
|
|
{730.045f, -1042.67f, 133.03f, nullptr}, {755.322f, -1030.28f, 133.30f, nullptr},
|
|
{801.685f, -1005.46f, 132.39f, nullptr}, {806.404f, -1001.709f, 132.382f, nullptr}};
|
|
|
|
BattleBotPath vPath_IC_Horde_Keep_to_Horde_Front_Crossroad = {{1128.646f, -763.221f, 48.385f, nullptr},
|
|
{1091.273f, -763.619f, 42.352f, nullptr},
|
|
{1032.825f, -763.024f, 30.420f, nullptr},
|
|
{991.4235f, -807.672f, 21.788f, nullptr}};
|
|
|
|
BattleBotPath vPath_IC_Horde_Front_Crossroad_to_Horde_Hangar_Crossroad = {{991.4235f, -807.672f, 21.788f, nullptr},
|
|
{999.1844f, -855.182f, 21.484f, nullptr},
|
|
{1012.089f, -923.098f, 19.296f, nullptr}};
|
|
|
|
BattleBotPath vPath_IC_Horde_Keep_to_Horde_Hangar_Crossroad = {{1128.646f, -763.221f, 48.385f, nullptr},
|
|
{1121.090f, -816.666f, 49.008f, nullptr},
|
|
{1107.106f, -851.459f, 48.804f, nullptr},
|
|
{1072.313f, -888.355f, 30.853f, nullptr},
|
|
{1012.089f, -923.098f, 19.296f, nullptr}};
|
|
|
|
BattleBotPath vPath_IC_Horde_Hangar_Crossroad_to_Hangar_Flag = {
|
|
{1001.745f, -973.174f, 15.784f, nullptr}, {1015.437f, -1019.47f, 15.578f, nullptr},
|
|
{1009.622f, -1067.78f, 15.777f, nullptr}, {988.0692f, -1113.32f, 18.254f, nullptr},
|
|
{943.7221f, -1134.50f, 32.296f, nullptr}, {892.2205f, -1115.16f, 63.319f, nullptr},
|
|
{849.6576f, -1090.88f, 91.943f, nullptr}, {814.9168f, -1056.42f, 117.275f, nullptr},
|
|
{799.0856f, -1034.62f, 129.000f, nullptr}, {801.685f, -1005.46f, 132.39f, nullptr}};
|
|
|
|
BattleBotPath vPath_IC_Horde_Keep_to_Horde_Dock_Crossroad = {{1128.646f, -763.221f, 48.385f, nullptr},
|
|
{1116.203f, -723.328f, 48.655f, nullptr},
|
|
{1093.246f, -696.880f, 37.041f, nullptr},
|
|
{1034.226f, -653.581f, 24.432f, nullptr}};
|
|
|
|
BattleBotPath vPath_IC_Horde_Front_Crossroad_to_Horde_Dock_Crossroad = {{991.4235f, -807.672f, 21.788f, nullptr},
|
|
{1025.305f, -757.165f, 29.241f, nullptr},
|
|
{1029.308f, -710.366f, 26.366f, nullptr},
|
|
{1034.226f, -653.581f, 24.432f, nullptr}};
|
|
|
|
BattleBotPath vPath_IC_Horde_Dock_Crossroad_to_Refinery_Crossroad = {{1034.226f, -653.581f, 24.432f, nullptr},
|
|
{1102.358f, -617.505f, 5.4963f, nullptr},
|
|
{1116.255f, -580.956f, 18.184f, nullptr},
|
|
{1114.414f, -546.731f, 23.422f, nullptr},
|
|
{1148.358f, -503.947f, 23.423f, nullptr}};
|
|
|
|
BattleBotPath vPath_IC_Refinery_Crossroad_to_Refinery_Base = {{1148.358f, -503.947f, 23.423f, nullptr},
|
|
{1201.885f, -500.425f, 4.7262f, nullptr},
|
|
{1240.595f, -471.971f, 0.8933f, nullptr},
|
|
{1265.993f, -435.419f, 10.669f, nullptr}};
|
|
|
|
BattleBotPath vPath_IC_Horde_Side_Gate_to_Refinery_Base = {
|
|
{1218.676f, -660.487f, 47.870f, nullptr}, {1211.677f, -626.181f, 46.085f, nullptr},
|
|
{1212.720f, -562.300f, 19.514f, nullptr}, {1238.803f, -538.997f, 3.9892f, nullptr},
|
|
{1248.875f, -482.852f, 0.8933f, nullptr}, {1265.993f, -435.419f, 10.669f, nullptr}};
|
|
|
|
BattleBotPath vPath_IC_Refinery_Crossroad_to_Docks_Crossroad = {
|
|
{1148.358f, -503.947f, 23.423f, nullptr}, {1127.010f, -469.451f, 23.422f, nullptr},
|
|
{1100.976f, -431.146f, 21.312f, nullptr}, {1053.812f, -405.457f, 12.749f, nullptr},
|
|
{1005.570f, -375.439f, 12.695f, nullptr}, {963.4349f, -353.282f, 12.356f, nullptr},
|
|
{907.1394f, -380.470f, 11.912f, nullptr}};
|
|
|
|
BattleBotPath vPath_IC_Horde_Dock_Crossroad_to_Docks_Crossroad = {
|
|
{1034.226f, -653.581f, 24.432f, nullptr}, {1013.435f, -622.066f, 24.486f, nullptr},
|
|
{988.1990f, -547.937f, 24.424f, nullptr}, {982.4955f, -508.332f, 24.524f, nullptr},
|
|
{982.5065f, -462.920f, 16.833f, nullptr}, {948.8842f, -421.200f, 16.877f, nullptr},
|
|
{907.1394f, -380.470f, 11.912f, nullptr}};
|
|
|
|
BattleBotPath vPath_IC_Docks_Crossroad_to_Docks_Flag = {{907.1394f, -380.470f, 11.912f, nullptr},
|
|
{851.5726f, -382.503f, 11.906f, nullptr},
|
|
{808.1441f, -381.199f, 11.906f, nullptr},
|
|
{761.1740f, -381.854f, 14.504f, nullptr},
|
|
{726.427f, -364.849f, 17.815f, nullptr}};
|
|
|
|
BattleBotPath vPath_IC_Horde_Front_Crossroad_to_Workshop = {
|
|
{991.4235f, -807.672f, 21.788f, nullptr}, {944.5518f, -800.344f, 13.155f, nullptr},
|
|
{907.1300f, -798.892f, 8.3237f, nullptr}, {842.9721f, -795.224f, 5.2007f, nullptr},
|
|
{804.5959f, -794.269f, 5.9836f, nullptr}, {774.466f, -801.058f, 6.3428f, nullptr}};
|
|
|
|
BattleBotPath vPath_IC_Central_Graveyard_to_Workshop = {
|
|
{775.377f, -664.151f, 8.388f, nullptr}, {776.299f, -684.079f, 5.036f, nullptr},
|
|
{777.451f, -707.525f, 0.051f, nullptr}, {779.059f, -734.611f, 1.695f, nullptr},
|
|
{779.643f, -767.010f, 4.843f, nullptr}, {774.466f, -801.058f, 6.3428f, nullptr}};
|
|
|
|
BattleBotPath vPath_IC_Horde_East_Gate_to_Horde_Keep = {
|
|
{1216.1918f, -864.922f, 48.852f, nullptr}, {1197.3117f, -866.054f, 48.916f, nullptr},
|
|
{1174.195f, -867.931f, 48.621f, nullptr}, {1149.671f, -869.240f, 48.096f, nullptr},
|
|
{1128.257f, -860.087f, 49.562f, nullptr}, {1118.730f, -829.959f, 49.074f, nullptr},
|
|
{1123.201f, -806.498f, 48.896f, nullptr}, {1129.685f, -787.156f, 48.680f, nullptr},
|
|
{1128.646f, -763.221f, 48.385f, nullptr}};
|
|
|
|
BattleBotPath vPath_IC_Workshop_to_Workshop_Keep = {{773.792f, -825.637f, 8.127f, nullptr},
|
|
{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<BattleBotPath*> const vPaths_WS = {
|
|
&vPath_WSG_HordeFlagRoom_to_HordeGraveyard,
|
|
&vPath_WSG_HordeGraveyard_to_HordeTunnel,
|
|
&vPath_WSG_HordeTunnel_to_HordeFlagRoom,
|
|
&vPath_WSG_AllianceFlagRoom_to_AllianceGraveyard,
|
|
&vPath_WSG_AllianceGraveyard_to_AllianceTunnel,
|
|
&vPath_WSG_AllianceTunnel_to_AllianceFlagRoom,
|
|
&vPath_WSG_HordeTunnel_to_HordeBaseRoof,
|
|
&vPath_WSG_AllianceTunnel_to_AllianceBaseRoof,
|
|
&vPath_WSG_AllianceTunnel_to_HordeTunnel,
|
|
&vPath_WSG_AllianceGraveyardLower_to_HordeFlagRoom,
|
|
&vPath_WSG_HordeGraveyardLower_to_AllianceFlagRoom,
|
|
&vPath_WSG_AllianceGraveyardJump,
|
|
&vPath_WSG_HordeGraveyardJump
|
|
};
|
|
|
|
std::vector<BattleBotPath*> const vPaths_AB = {
|
|
&vPath_AB_AllianceBase_to_Stables, &vPath_AB_AllianceBase_to_GoldMine, &vPath_AB_AllianceBase_to_LumberMill,
|
|
&vPath_AB_Stables_to_Blacksmith, &vPath_AB_HordeBase_to_Farm, &vPath_AB_HordeBase_to_GoldMine,
|
|
&vPath_AB_HordeBase_to_LumberMill, &vPath_AB_Farm_to_Blacksmith, &vPath_AB_Stables_to_GoldMine,
|
|
&vPath_AB_Stables_to_LumberMill, &vPath_AB_Farm_to_GoldMine, &vPath_AB_Farm_to_LumberMill,
|
|
&vPath_AB_Blacksmith_to_LumberMill, &vPath_AB_Blacksmith_to_GoldMine, &vPath_AB_Farm_to_Stable,
|
|
};
|
|
|
|
std::vector<BattleBotPath*> const vPaths_AV = {
|
|
&vPath_AV_AllianceSpawn_To_AllianceCrossroad1,
|
|
&vPath_AV_AllianceFortress_To_AllianceCrossroad1,
|
|
&vPath_AV_AllianceCrossroad1_To_AllianceCrossroad2,
|
|
&vPath_AV_StoneheartGrave_To_AllianceCrossroad2,
|
|
&vPath_AV_AllianceCrossroad2_To_StoneheartBunker,
|
|
&vPath_AV_AllianceCrossroad2_To_AllianceCaptain,
|
|
&vPath_AV_AllianceCaptain_To_HordeCrossroad3,
|
|
&vPath_AV_AllianceCrossroads3_To_SnowfallGraveyard,
|
|
//&vPath_AV_AllianceCaptain_To_AllianceCrossroad3,
|
|
&vPath_AV_StoneheartBunker_To_HordeCrossroad3,
|
|
&vPath_AV_AllianceCrossroad1_To_AllianceMine,
|
|
&vPath_AV_HordeSpawn_To_MainRoad,
|
|
&vPath_AV_SnowfallGraveyard_To_HordeCaptain,
|
|
&vPath_AV_HordeCrossroad3_To_IcebloodTower,
|
|
&vPath_AV_IcebloodTower_To_HordeCaptain,
|
|
&vPath_AV_IcebloodTower_To_IcebloodGrave,
|
|
&vPath_AV_IcebloodGrave_To_TowerBottom,
|
|
&vPath_AV_TowerBottom_To_HordeCrossroad1,
|
|
&vPath_AV_HordeCrossroad1_To_FrostwolfGrave,
|
|
&vPath_AV_HordeCrossroad1_To_HordeFortress,
|
|
&vPath_AV_FrostwolfGrave_To_HordeMine
|
|
};
|
|
|
|
std::vector<BattleBotPath*> const vPaths_EY = {
|
|
&vPath_EY_Horde_Spawn_to_Crossroad1Horde,
|
|
&vPath_EY_Horde_Crossroad1Horde_to_Crossroad2Horde,
|
|
&vPath_EY_Crossroad1Horde_to_Blood_Elf_Tower,
|
|
&vPath_EY_Crossroad1Horde_to_Fel_Reaver_Ruins,
|
|
&vPath_EY_Crossroad2Horde_to_Blood_Elf_Tower,
|
|
&vPath_EY_Crossroad2Horde_to_Fel_Reaver_Ruins,
|
|
&vPath_EY_Crossroad2Horde_to_Flag,
|
|
&vPath_EY_Alliance_Spawn_to_Crossroad1Alliance,
|
|
&vPath_EY_Alliance_Crossroad1Alliance_to_Crossroad2Alliance,
|
|
&vPath_EY_Crossroad1Alliance_to_Mage_Tower,
|
|
&vPath_EY_Crossroad1Alliance_to_Draenei_Ruins,
|
|
&vPath_EY_Crossroad2Alliance_to_Mage_Tower,
|
|
&vPath_EY_Crossroad2Alliance_to_Draenei_Ruins,
|
|
&vPath_EY_Crossroad2Alliance_to_Flag,
|
|
&vPath_EY_Draenei_Ruins_to_Blood_Elf_Tower,
|
|
&vPath_EY_Fel_Reaver_to_Mage_Tower,
|
|
};
|
|
|
|
std::vector<BattleBotPath*> const vPaths_IC = {
|
|
&vPath_IC_Ally_Dock_Crossroad_to_Ally_Docks_Second_Crossroad,
|
|
&vPath_IC_Ally_Docks_Crossroad_to_Docks_Flag,
|
|
&vPath_IC_Ally_Docks_Second_Crossroad_to_Ally_Docks_Crossroad,
|
|
&vPath_IC_Lower_Graveyard_Crossroad_to_Ally_Docks_Crossroad,
|
|
&vPath_IC_Lower_Graveyard_Crossroad_to_Ally_Docks_Second_Crossroad,
|
|
&vPath_IC_Lower_Graveyard_to_Lower_Graveyard_Crossroad,
|
|
&vPath_IC_Ally_Front_Crossroad_to_Ally_Dock_Crossroad,
|
|
&vPath_IC_Ally_Front_Crossroad_to_Hangar_First_Crossroad,
|
|
&vPath_IC_Ally_Front_Crossroad_to_Workshop,
|
|
&vPath_IC_Ally_Keep_to_Ally_Dock_Crossroad,
|
|
&vPath_IC_Ally_Keep_to_Ally_Front_Crossroad,
|
|
&vPath_IC_Ally_Keep_to_Hangar_First_Crossroad,
|
|
&vPath_IC_Ally_Keep_to_Quarry_Crossroad,
|
|
&vPath_IC_Docks_Crossroad_to_Docks_Flag,
|
|
&vPath_IC_Docks_Graveyard_to_Docks_Flag,
|
|
&vPath_IC_Hangar_First_Crossroad_to_Hangar_Second_Crossroad,
|
|
&vPath_IC_Hangar_Second_Crossroad_to_Hangar_Flag,
|
|
&vPath_IC_Horde_Dock_Crossroad_to_Docks_Crossroad,
|
|
&vPath_IC_Horde_Dock_Crossroad_to_Refinery_Crossroad,
|
|
&vPath_IC_Horde_Front_Crossroad_to_Horde_Dock_Crossroad,
|
|
&vPath_IC_Horde_Front_Crossroad_to_Horde_Hangar_Crossroad,
|
|
&vPath_IC_Horde_Front_Crossroad_to_Workshop,
|
|
&vPath_IC_Horde_Hangar_Crossroad_to_Hangar_Flag,
|
|
&vPath_IC_Horde_Keep_to_Horde_Dock_Crossroad,
|
|
&vPath_IC_Horde_Keep_to_Horde_Front_Crossroad,
|
|
&vPath_IC_Horde_Keep_to_Horde_Hangar_Crossroad,
|
|
&vPath_IC_Horde_Side_Gate_to_Refinery_Base,
|
|
&vPath_IC_Quarry_Crossroad_to_Hangar_Second_Crossroad,
|
|
&vPath_IC_Quarry_Crossroad_to_Quarry_Flag,
|
|
&vPath_IC_Refinery_Crossroad_to_Docks_Crossroad,
|
|
&vPath_IC_Refinery_Crossroad_to_Refinery_Base,
|
|
&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<BattleBotPath*> const vPaths_NoReverseAllowed = {
|
|
&vPath_WSG_AllianceGraveyardJump,
|
|
&vPath_WSG_HordeGraveyardJump,
|
|
&vPath_IC_Central_Graveyard_to_Workshop,
|
|
&vPath_IC_Docks_Graveyard_to_Docks_Flag,
|
|
};
|
|
|
|
static std::vector<std::pair<uint8, uint32>> AV_AttackObjectives_Horde = {
|
|
// Attack - these are in order they should be attacked
|
|
{BG_AV_NODES_STONEHEART_GRAVE, BG_AV_OBJECT_FLAG_A_STONEHEART_GRAVE},
|
|
{BG_AV_NODES_STONEHEART_BUNKER, BG_AV_OBJECT_FLAG_A_STONEHEART_BUNKER},
|
|
{BG_AV_NODES_ICEWING_BUNKER, BG_AV_OBJECT_FLAG_A_ICEWING_BUNKER},
|
|
{BG_AV_NODES_STORMPIKE_GRAVE, BG_AV_OBJECT_FLAG_A_STORMPIKE_GRAVE},
|
|
{BG_AV_NODES_DUNBALDAR_SOUTH, BG_AV_OBJECT_FLAG_A_DUNBALDAR_SOUTH},
|
|
{BG_AV_NODES_DUNBALDAR_NORTH, BG_AV_OBJECT_FLAG_A_DUNBALDAR_NORTH},
|
|
{BG_AV_NODES_FIRSTAID_STATION, BG_AV_OBJECT_FLAG_A_FIRSTAID_STATION},
|
|
};
|
|
|
|
static std::vector<std::pair<uint8, uint32>> AV_AttackObjectives_Alliance = {
|
|
// Attack - these are in order they should be attacked
|
|
{BG_AV_NODES_ICEBLOOD_GRAVE, BG_AV_OBJECT_FLAG_H_ICEBLOOD_GRAVE},
|
|
{BG_AV_NODES_ICEBLOOD_TOWER, BG_AV_OBJECT_FLAG_H_ICEBLOOD_TOWER},
|
|
{BG_AV_NODES_TOWER_POINT, BG_AV_OBJECT_FLAG_H_TOWER_POINT},
|
|
{BG_AV_NODES_FROSTWOLF_GRAVE, BG_AV_OBJECT_FLAG_H_FROSTWOLF_GRAVE},
|
|
{BG_AV_NODES_FROSTWOLF_ETOWER, BG_AV_OBJECT_FLAG_H_FROSTWOLF_ETOWER},
|
|
{BG_AV_NODES_FROSTWOLF_WTOWER, BG_AV_OBJECT_FLAG_H_FROSTWOLF_WTOWER},
|
|
{BG_AV_NODES_FROSTWOLF_HUT, BG_AV_OBJECT_FLAG_H_FROSTWOLF_HUT},
|
|
};
|
|
|
|
static std::vector<std::pair<uint8, uint32>> AV_DefendObjectives_Horde = {
|
|
{BG_AV_NODES_FROSTWOLF_HUT, BG_AV_OBJECT_FLAG_H_FROSTWOLF_HUT},
|
|
{BG_AV_NODES_FROSTWOLF_WTOWER, BG_AV_OBJECT_FLAG_H_FROSTWOLF_WTOWER},
|
|
{BG_AV_NODES_FROSTWOLF_ETOWER, BG_AV_OBJECT_FLAG_H_FROSTWOLF_ETOWER},
|
|
{BG_AV_NODES_FROSTWOLF_GRAVE, BG_AV_OBJECT_FLAG_H_FROSTWOLF_GRAVE},
|
|
{BG_AV_NODES_TOWER_POINT, BG_AV_OBJECT_FLAG_H_TOWER_POINT},
|
|
{BG_AV_NODES_ICEBLOOD_TOWER, BG_AV_OBJECT_FLAG_H_ICEBLOOD_TOWER},
|
|
{BG_AV_NODES_ICEBLOOD_GRAVE, BG_AV_OBJECT_FLAG_H_ICEBLOOD_GRAVE},
|
|
};
|
|
|
|
static std::vector<std::pair<uint8, uint32>> AV_DefendObjectives_Alliance = {
|
|
{BG_AV_NODES_FIRSTAID_STATION, BG_AV_OBJECT_FLAG_A_FIRSTAID_STATION},
|
|
{BG_AV_NODES_DUNBALDAR_SOUTH, BG_AV_OBJECT_FLAG_A_DUNBALDAR_SOUTH},
|
|
{BG_AV_NODES_DUNBALDAR_NORTH, BG_AV_OBJECT_FLAG_A_DUNBALDAR_NORTH},
|
|
{BG_AV_NODES_STORMPIKE_GRAVE, BG_AV_OBJECT_FLAG_A_STORMPIKE_GRAVE},
|
|
{BG_AV_NODES_ICEWING_BUNKER, BG_AV_OBJECT_FLAG_A_ICEWING_BUNKER},
|
|
{BG_AV_NODES_STONEHEART_BUNKER, BG_AV_OBJECT_FLAG_A_STONEHEART_BUNKER},
|
|
{BG_AV_NODES_STONEHEART_GRAVE, BG_AV_OBJECT_FLAG_A_STONEHEART_GRAVE},
|
|
};
|
|
|
|
static uint32 AB_AttackObjectives[] = {
|
|
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<uint32, uint32, uint32> EY_AttackObjectives[] = {
|
|
{POINT_FEL_REAVER, BG_EY_OBJECT_FLAG_FEL_REAVER, AT_FEL_REAVER_POINT},
|
|
{POINT_BLOOD_ELF, BG_EY_OBJECT_FLAG_BLOOD_ELF, AT_BLOOD_ELF_POINT},
|
|
{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::unordered_map<uint32, Position> EY_NodePositions = {
|
|
{POINT_FEL_REAVER, Position(2044.173f, 1727.503f, 1189.505f)},
|
|
{POINT_BLOOD_ELF, Position(2048.277f, 1395.093f, 1194.255f)},
|
|
{POINT_DRAENEI_RUINS, Position(2286.245f, 1404.683f, 1196.991f)},
|
|
{POINT_MAGE_TOWER, Position(2284.720f, 1728.457f, 1189.153f)}
|
|
};
|
|
|
|
static std::pair<uint32, uint32> 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)
|
|
{
|
|
if (!sPlayerbotAIConfig->enabled)
|
|
{
|
|
handler->PSendSysMessage("|cffff0000Playerbot system is currently disabled!");
|
|
return true;
|
|
}
|
|
WorldSession* session = handler->GetSession();
|
|
if (!session)
|
|
{
|
|
handler->PSendSysMessage("Command can only be used from an active session");
|
|
return true;
|
|
}
|
|
std::string const commandOutput = HandleConsoleCommandPrivate(session, args);
|
|
if (!commandOutput.empty())
|
|
handler->PSendSysMessage(commandOutput.c_str());
|
|
return true;
|
|
}
|
|
|
|
// has different name to above as some compilers get confused
|
|
std::string const BGTactics::HandleConsoleCommandPrivate(WorldSession* session, char const* args)
|
|
{
|
|
Player* player = session->GetPlayer();
|
|
if (!player)
|
|
return "Error - session player not found";
|
|
if (player->GetSession()->GetSecurity() < SEC_GAMEMASTER)
|
|
return "Command can only be used by a GM";
|
|
Battleground* bg = player->GetBattleground();
|
|
if (!bg)
|
|
return "Command can only be used within a battleground";
|
|
BattlegroundTypeId bgType = bg->GetBgTypeID();
|
|
if (bgType == BATTLEGROUND_RB)
|
|
bgType = bg->GetBgTypeID(true);
|
|
char* cmd = strtok((char*)args, " ");
|
|
// char* charname = strtok(nullptr, " ");
|
|
|
|
if (!strncmp(cmd, "showpath", 8))
|
|
{
|
|
int num = -1;
|
|
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";
|
|
}
|
|
std::vector<BattleBotPath*> const* vPaths;
|
|
switch (bgType)
|
|
{
|
|
case BATTLEGROUND_AB:
|
|
vPaths = &vPaths_AB;
|
|
break;
|
|
case BATTLEGROUND_AV:
|
|
vPaths = &vPaths_AV;
|
|
break;
|
|
case BATTLEGROUND_WS:
|
|
vPaths = &vPaths_WS;
|
|
break;
|
|
case BATTLEGROUND_EY:
|
|
vPaths = &vPaths_EY;
|
|
break;
|
|
case BATTLEGROUND_IC:
|
|
vPaths = &vPaths_IC;
|
|
break;
|
|
default:
|
|
vPaths = nullptr;
|
|
break;
|
|
}
|
|
if (!vPaths)
|
|
return "This battleground has no paths and is unsupported";
|
|
if (num == -1)
|
|
{
|
|
float closestPoint = FLT_MAX;
|
|
for (uint32 j = 0; j < vPaths->size(); j++)
|
|
{
|
|
auto const& path = (*vPaths)[j];
|
|
for (uint32 i = 0; i < path->size(); i++)
|
|
{
|
|
BattleBotWaypoint& waypoint = ((*path)[i]);
|
|
float dist = player->GetDistance(waypoint.x, waypoint.y, waypoint.z);
|
|
if (closestPoint > dist)
|
|
{
|
|
closestPoint = dist;
|
|
num = j;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
uint32 min = 0u;
|
|
uint32 max = vPaths->size() - 1;
|
|
if (num >= 0) // num specified or found
|
|
{
|
|
if (num > max)
|
|
return fmt::format("Path {} of range of 0 - {}", num, max);
|
|
min = num;
|
|
max = 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))
|
|
{
|
|
uint32 num;
|
|
if (sscanf(cmd, "showcreature=%u", &num) == -1)
|
|
return "Bad showcreature parameter";
|
|
if (num >= bg->BgCreatures.size())
|
|
return fmt::format("Creature out of range of 0 - {}", bg->BgCreatures.size() - 1);
|
|
Creature* c = bg->GetBGCreature(num);
|
|
if (!c)
|
|
return "Creature not found";
|
|
Creature* wpCreature = player->SummonCreature(15631, c->GetPositionX(), c->GetPositionY(), c->GetPositionZ(), 0,
|
|
TEMPSUMMON_TIMED_DESPAWN, 15000u);
|
|
wpCreature->SetOwnerGUID(player->GetGUID());
|
|
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))
|
|
{
|
|
uint32 num;
|
|
if (sscanf(cmd, "showobject=%u", &num) == -1)
|
|
return "Bad showobject parameter";
|
|
if (num >= bg->BgObjects.size())
|
|
return fmt::format("Object out of range of 0 - {}", bg->BgObjects.size() - 1);
|
|
GameObject* o = bg->GetBGObject(num);
|
|
if (!o)
|
|
return "GameObject not found";
|
|
Creature* wpCreature = player->SummonCreature(15631, o->GetPositionX(), o->GetPositionY(), o->GetPositionZ(), 0,
|
|
TEMPSUMMON_TIMED_DESPAWN, 15000u);
|
|
wpCreature->SetOwnerGUID(player->GetGUID());
|
|
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]";
|
|
}
|
|
|
|
// Depends on OnBattlegroundStart in playerbots.cpp
|
|
uint8 BGTactics::GetBotStrategyForTeam(Battleground* bg, TeamId teamId)
|
|
{
|
|
auto itr = bgStrategies.find(bg->GetInstanceID());
|
|
if (itr == bgStrategies.end())
|
|
return 0;
|
|
|
|
return teamId == TEAM_ALLIANCE ? itr->second.allianceStrategy : itr->second.hordeStrategy;
|
|
}
|
|
|
|
bool BGTactics::wsJumpDown()
|
|
{
|
|
Battleground* bg = bot->GetBattleground();
|
|
if (!bg)
|
|
return false;
|
|
|
|
TeamId team = bot->GetTeamId();
|
|
uint32 mapId = bg->GetMapId();
|
|
|
|
if (team == TEAM_HORDE)
|
|
{
|
|
if (bot->GetDistance({1038.220f, 1420.197f, 340.099f}) < 4.0f)
|
|
{
|
|
MoveTo(mapId, 1029.242f, 1387.024f, 340.866f);
|
|
return true;
|
|
}
|
|
if (bot->GetDistance({1029.242f, 1387.024f, 340.866f}) < 4.0f)
|
|
{
|
|
MoveTo(mapId, 1045.764f, 1389.831f, 340.825f);
|
|
return true;
|
|
}
|
|
if (bot->GetDistance({1045.764f, 1389.831f, 340.825f}) < 4.0f)
|
|
{
|
|
MoveTo(mapId, 1057.076f, 1393.081f, 339.505f);
|
|
return true;
|
|
}
|
|
if (bot->GetDistance({1057.076f, 1393.081f, 339.505f}) < 4.0f)
|
|
{
|
|
JumpTo(mapId, 1075.233f, 1398.645f, 323.669f);
|
|
return true;
|
|
}
|
|
if (bot->GetDistance({1075.233f, 1398.645f, 323.669f}) < 4.0f)
|
|
{
|
|
MoveTo(mapId, 1096.590f, 1395.070f, 317.016f);
|
|
return true;
|
|
}
|
|
if (bot->GetDistance({1096.590f, 1395.070f, 317.016f}) < 4.0f)
|
|
{
|
|
MoveTo(mapId, 1134.380f, 1370.130f, 312.741f);
|
|
return true;
|
|
}
|
|
}
|
|
else if (team == TEAM_ALLIANCE)
|
|
{
|
|
if (bot->GetDistance({1415.548f, 1554.538f, 343.164f}) < 4.0f)
|
|
{
|
|
MoveTo(mapId, 1407.234f, 1551.658f, 343.432f);
|
|
return true;
|
|
}
|
|
if (bot->GetDistance({1407.234f, 1551.658f, 343.432f}) < 4.0f)
|
|
{
|
|
JumpTo(mapId, 1385.325f, 1544.592f, 322.047f);
|
|
return true;
|
|
}
|
|
if (bot->GetDistance({1385.325f, 1544.592f, 322.047f}) < 4.0f)
|
|
{
|
|
MoveTo(mapId, 1370.710f, 1543.550f, 321.585f);
|
|
return true;
|
|
}
|
|
if (bot->GetDistance({1370.710f, 1543.550f, 321.585f}) < 4.0f)
|
|
{
|
|
MoveTo(mapId, 1339.410f, 1533.420f, 313.336f);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool BGTactics::eyJumpDown()
|
|
{
|
|
Battleground* bg = bot->GetBattleground();
|
|
if (!bg)
|
|
return false;
|
|
Position const hordeJumpPositions[] = {
|
|
EY_WAITING_POS_HORDE,
|
|
{1838.007f, 1539.856f, 1253.383f},
|
|
{1846.264f, 1535.062f, 1240.796f},
|
|
{1849.813f, 1527.303f, 1237.262f},
|
|
{1849.041f, 1518.884f, 1223.624f},
|
|
};
|
|
Position const allianceJumpPositions[] = {
|
|
EY_WAITING_POS_ALLIANCE,
|
|
{2492.955f, 1597.769f, 1254.828f},
|
|
{2484.601f, 1598.209f, 1244.344f},
|
|
{2478.424f, 1609.539f, 1238.651f},
|
|
{2475.926f, 1619.658f, 1218.706f},
|
|
};
|
|
Position const* positons = bot->GetTeamId() == TEAM_HORDE ? hordeJumpPositions : allianceJumpPositions;
|
|
{
|
|
if (bot->GetDistance(positons[0]) < 16.0f)
|
|
{
|
|
MoveTo(bg->GetMapId(), positons[1].GetPositionX(), positons[1].GetPositionY(), positons[1].GetPositionZ());
|
|
return true;
|
|
}
|
|
if (bot->GetDistance(positons[1]) < 4.0f)
|
|
{
|
|
JumpTo(bg->GetMapId(), positons[2].GetPositionX(), positons[2].GetPositionY(), positons[2].GetPositionZ());
|
|
return true;
|
|
}
|
|
if (bot->GetDistance(positons[2]) < 4.0f)
|
|
{
|
|
MoveTo(bg->GetMapId(), positons[3].GetPositionX(), positons[3].GetPositionY(), positons[3].GetPositionZ());
|
|
return true;
|
|
}
|
|
if (bot->GetDistance(positons[3]) < 4.0f)
|
|
{
|
|
JumpTo(bg->GetMapId(), positons[4].GetPositionX(), positons[4].GetPositionY(), positons[4].GetPositionZ());
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// actual bg tactics below
|
|
//
|
|
bool BGTactics::Execute(Event event)
|
|
{
|
|
Battleground* bg = bot->GetBattleground();
|
|
if (!bg)
|
|
{
|
|
botAI->ResetStrategies();
|
|
return false;
|
|
}
|
|
|
|
if (bg->GetStatus() == STATUS_WAIT_LEAVE)
|
|
return BGStatusAction::LeaveBG(botAI);
|
|
|
|
if (bg->isArena())
|
|
{
|
|
// can't use this in arena - no vPaths/vFlagIds (will crash server)
|
|
botAI->ResetStrategies();
|
|
return false;
|
|
}
|
|
|
|
if (bg->GetStatus() == STATUS_IN_PROGRESS)
|
|
botAI->ChangeStrategy("-buff", BOT_STATE_NON_COMBAT);
|
|
|
|
std::vector<BattleBotPath*> const* vPaths;
|
|
std::vector<uint32> const* vFlagIds;
|
|
BattlegroundTypeId bgType = bg->GetBgTypeID();
|
|
if (bgType == BATTLEGROUND_RB)
|
|
bgType = bot->GetBattleground()->GetBgTypeID(true);
|
|
|
|
switch (bgType)
|
|
{
|
|
case BATTLEGROUND_AB:
|
|
{
|
|
vPaths = &vPaths_AB;
|
|
vFlagIds = &vFlagsAB;
|
|
break;
|
|
}
|
|
case BATTLEGROUND_AV:
|
|
{
|
|
vPaths = &vPaths_AV;
|
|
vFlagIds = &vFlagsAV;
|
|
break;
|
|
}
|
|
case BATTLEGROUND_WS:
|
|
{
|
|
vPaths = &vPaths_WS;
|
|
vFlagIds = &vFlagsWS;
|
|
break;
|
|
}
|
|
case BATTLEGROUND_EY:
|
|
{
|
|
vPaths = &vPaths_EY;
|
|
vFlagIds = &vFlagsEY;
|
|
break;
|
|
}
|
|
case BATTLEGROUND_IC:
|
|
{
|
|
vPaths = &vPaths_IC;
|
|
vFlagIds = &vFlagsIC;
|
|
break;
|
|
}
|
|
default:
|
|
// can't use this in this BG - no vPaths/vFlagIds (will crash server)
|
|
botAI->ResetStrategies();
|
|
return false;
|
|
}
|
|
|
|
if (getName() == "move to start")
|
|
return moveToStart();
|
|
|
|
if (getName() == "reset objective force")
|
|
{
|
|
bool isCarryingFlag =
|
|
bot->HasAura(BG_WS_SPELL_WARSONG_FLAG) ||
|
|
bot->HasAura(BG_WS_SPELL_SILVERWING_FLAG) ||
|
|
bot->HasAura(BG_EY_NETHERSTORM_FLAG_SPELL);
|
|
|
|
if (!isCarryingFlag)
|
|
{
|
|
bot->StopMoving();
|
|
bot->GetMotionMaster()->Clear();
|
|
return resetObjective(); // Reset objective to not use "old" data
|
|
}
|
|
}
|
|
|
|
if (getName() == "select objective")
|
|
return selectObjective();
|
|
|
|
if (getName() == "protect fc")
|
|
{
|
|
if (protectFC())
|
|
return true;
|
|
}
|
|
|
|
if (getName() == "move to objective")
|
|
{
|
|
if (bg->GetStatus() == STATUS_WAIT_JOIN)
|
|
return false;
|
|
|
|
if (bot->isMoving())
|
|
return false;
|
|
|
|
if (!bot->IsStopped())
|
|
return false;
|
|
|
|
switch (bot->GetMotionMaster()->GetCurrentMovementGeneratorType())
|
|
{
|
|
// TODO: should ESCORT_MOTION_TYPE be here seeing as bots use it by default?
|
|
case IDLE_MOTION_TYPE:
|
|
case CHASE_MOTION_TYPE:
|
|
case POINT_MOTION_TYPE:
|
|
break;
|
|
default:
|
|
return true;
|
|
}
|
|
|
|
if (vFlagIds && atFlag(*vPaths, *vFlagIds))
|
|
return true;
|
|
|
|
if (useBuff())
|
|
return true;
|
|
|
|
// 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 && !PlayerHasFlag::IsCapturingFlag(bot))
|
|
{
|
|
// bot->GetMotionMaster()->MovementExpired();
|
|
return false;
|
|
}
|
|
|
|
if (!moveToObjective(false))
|
|
if (!selectObjectiveWp(*vPaths))
|
|
return moveToObjective(true);
|
|
|
|
// bot with flag should only move to objective
|
|
if (bot->HasAura(BG_WS_SPELL_WARSONG_FLAG) || bot->HasAura(BG_WS_SPELL_SILVERWING_FLAG) ||
|
|
bot->HasAura(BG_EY_NETHERSTORM_FLAG_SPELL))
|
|
return false;
|
|
|
|
if (!startNewPathBegin(*vPaths))
|
|
return moveToObjective(true);
|
|
|
|
if (!startNewPathFree(*vPaths))
|
|
return moveToObjective(true);
|
|
}
|
|
|
|
if (getName() == "use buff")
|
|
return useBuff();
|
|
|
|
if (getName() == "check flag")
|
|
{
|
|
if (vFlagIds && atFlag(*vPaths, *vFlagIds))
|
|
return true;
|
|
}
|
|
|
|
if (getName() == "check objective")
|
|
return resetObjective();
|
|
|
|
return false;
|
|
}
|
|
|
|
bool BGTactics::moveToStart(bool force)
|
|
{
|
|
Battleground* bg = bot->GetBattleground();
|
|
if (!bg)
|
|
return false;
|
|
|
|
if (!force && bg->GetStatus() != STATUS_WAIT_JOIN)
|
|
return false;
|
|
|
|
BattlegroundTypeId bgType = bg->GetBgTypeID();
|
|
if (bgType == BATTLEGROUND_RB)
|
|
bgType = bg->GetBgTypeID(true);
|
|
|
|
if (bgType == BATTLEGROUND_WS)
|
|
{
|
|
uint32 role = context->GetValue<uint32>("bg role")->Get();
|
|
|
|
int startSpot = role < 4 ? BB_WSG_WAIT_SPOT_LEFT : role > 6 ? BB_WSG_WAIT_SPOT_RIGHT : BB_WSG_WAIT_SPOT_SPAWN;
|
|
if (startSpot == BB_WSG_WAIT_SPOT_RIGHT)
|
|
{
|
|
if (bot->GetTeamId() == TEAM_HORDE)
|
|
MoveTo(bg->GetMapId(), WS_WAITING_POS_HORDE_1.GetPositionX() + frand(-4.0f, 4.0f),
|
|
WS_WAITING_POS_HORDE_1.GetPositionY() + frand(-4.0f, 4.0f),
|
|
WS_WAITING_POS_HORDE_1.GetPositionZ());
|
|
else
|
|
MoveTo(bg->GetMapId(), WS_WAITING_POS_ALLIANCE_1.GetPositionX() + frand(-4.0f, 4.0f),
|
|
WS_WAITING_POS_ALLIANCE_1.GetPositionY() + frand(-4.0f, 4.0f),
|
|
WS_WAITING_POS_ALLIANCE_1.GetPositionZ());
|
|
}
|
|
else if (startSpot == BB_WSG_WAIT_SPOT_LEFT)
|
|
{
|
|
if (bot->GetTeamId() == TEAM_HORDE)
|
|
MoveTo(bg->GetMapId(), WS_WAITING_POS_HORDE_2.GetPositionX() + frand(-4.0f, 4.0f),
|
|
WS_WAITING_POS_HORDE_2.GetPositionY() + frand(-4.0f, 4.0f),
|
|
WS_WAITING_POS_HORDE_2.GetPositionZ());
|
|
else
|
|
MoveTo(bg->GetMapId(), WS_WAITING_POS_ALLIANCE_2.GetPositionX() + frand(-4.0f, 4.0f),
|
|
WS_WAITING_POS_ALLIANCE_2.GetPositionY() + frand(-4.0f, 4.0f),
|
|
WS_WAITING_POS_ALLIANCE_2.GetPositionZ());
|
|
}
|
|
else // BB_WSG_WAIT_SPOT_SPAWN
|
|
{
|
|
if (bot->GetTeamId() == TEAM_HORDE)
|
|
MoveTo(bg->GetMapId(), WS_WAITING_POS_HORDE_3.GetPositionX() + frand(-10.0f, 10.0f),
|
|
WS_WAITING_POS_HORDE_3.GetPositionY() + frand(-10.0f, 10.0f),
|
|
WS_WAITING_POS_HORDE_3.GetPositionZ());
|
|
else
|
|
MoveTo(bg->GetMapId(), WS_WAITING_POS_ALLIANCE_3.GetPositionX() + frand(-10.0f, 10.0f),
|
|
WS_WAITING_POS_ALLIANCE_3.GetPositionY() + frand(-10.0f, 10.0f),
|
|
WS_WAITING_POS_ALLIANCE_3.GetPositionZ());
|
|
}
|
|
}
|
|
else if (bgType == BATTLEGROUND_AB)
|
|
{
|
|
if (bot->GetTeamId() == TEAM_HORDE)
|
|
MoveTo(bg->GetMapId(), AB_WAITING_POS_HORDE.GetPositionX() + frand(-7.0f, 7.0f),
|
|
AB_WAITING_POS_HORDE.GetPositionY() + frand(-2.0f, 2.0f), AB_WAITING_POS_HORDE.GetPositionZ());
|
|
else
|
|
MoveTo(bg->GetMapId(), AB_WAITING_POS_ALLIANCE.GetPositionX() + frand(-7.0f, 7.0f),
|
|
AB_WAITING_POS_ALLIANCE.GetPositionY() + frand(-2.0f, 2.0f), AB_WAITING_POS_ALLIANCE.GetPositionZ());
|
|
}
|
|
else if (bgType == BATTLEGROUND_AV)
|
|
{
|
|
if (bot->GetTeamId() == TEAM_HORDE)
|
|
MoveTo(bg->GetMapId(), AV_WAITING_POS_HORDE.GetPositionX() + frand(-5.0f, 5.0f),
|
|
AV_WAITING_POS_HORDE.GetPositionY() + frand(-3.0f, 3.0f), AV_WAITING_POS_HORDE.GetPositionZ());
|
|
else
|
|
MoveTo(bg->GetMapId(), AV_WAITING_POS_ALLIANCE.GetPositionX() + frand(-5.0f, 5.0f),
|
|
AV_WAITING_POS_ALLIANCE.GetPositionY() + frand(-3.0f, 3.0f), AV_WAITING_POS_ALLIANCE.GetPositionZ());
|
|
}
|
|
else if (bgType == BATTLEGROUND_EY)
|
|
{
|
|
/* Disabled: Not needed here and sometimes the bots can go out of map (at least with my map files)
|
|
if (bot->GetTeamId() == TEAM_HORDE)
|
|
{
|
|
MoveTo(bg->GetMapId(), EY_WAITING_POS_HORDE.GetPositionX(), EY_WAITING_POS_HORDE.GetPositionY(), EY_WAITING_POS_HORDE.GetPositionZ());
|
|
}
|
|
else
|
|
{
|
|
MoveTo(bg->GetMapId(), EY_WAITING_POS_ALLIANCE.GetPositionX(), EY_WAITING_POS_ALLIANCE.GetPositionZ(), EY_WAITING_POS_ALLIANCE.GetPositionZ());
|
|
}
|
|
*/
|
|
}
|
|
else if (bgType == BATTLEGROUND_IC)
|
|
{
|
|
uint32 role = context->GetValue<uint32>("bg role")->Get();
|
|
|
|
if (bot->GetTeamId() == TEAM_HORDE)
|
|
{
|
|
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) // 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());
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool BGTactics::selectObjective(bool reset)
|
|
{
|
|
Battleground* bg = bot->GetBattleground();
|
|
if (!bg)
|
|
return false;
|
|
|
|
if (bg->GetStatus() != STATUS_IN_PROGRESS)
|
|
return false;
|
|
|
|
PositionMap& posMap = context->GetValue<PositionMap&>("position")->Get();
|
|
PositionInfo pos = context->GetValue<PositionMap&>("position")->Get()["bg objective"];
|
|
if (pos.isSet() && !reset)
|
|
return false;
|
|
|
|
WorldObject* BgObjective = nullptr;
|
|
|
|
BattlegroundTypeId bgType = bg->GetBgTypeID();
|
|
if (bgType == BATTLEGROUND_RB)
|
|
bgType = bg->GetBgTypeID(true);
|
|
switch (bgType)
|
|
{
|
|
case BATTLEGROUND_AV:
|
|
{
|
|
BattlegroundAV* av = static_cast<BattlegroundAV*>(bg);
|
|
TeamId team = bot->GetTeamId();
|
|
uint8 role = context->GetValue<uint32>("bg role")->Get();
|
|
AVBotStrategy strategyHorde = static_cast<AVBotStrategy>(GetBotStrategyForTeam(bg, TEAM_HORDE));
|
|
AVBotStrategy strategyAlliance = static_cast<AVBotStrategy>(GetBotStrategyForTeam(bg, TEAM_ALLIANCE));
|
|
AVBotStrategy strategy = (team == TEAM_ALLIANCE) ? strategyAlliance : strategyHorde;
|
|
AVBotStrategy enemyStrategy = (team == TEAM_ALLIANCE) ? strategyHorde : strategyAlliance;
|
|
|
|
uint8 defendersProhab = 4;
|
|
bool enableMineCapture = true;
|
|
bool enableSnowfall = true;
|
|
|
|
switch (strategy)
|
|
{
|
|
case AV_STRATEGY_BALANCED:
|
|
defendersProhab = 4;
|
|
break;
|
|
case AV_STRATEGY_OFFENSIVE:
|
|
defendersProhab = 1;
|
|
enableMineCapture = false;
|
|
break;
|
|
case AV_STRATEGY_DEFENSIVE:
|
|
defendersProhab = 9;
|
|
enableSnowfall = false;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (enemyStrategy == AV_STRATEGY_DEFENSIVE)
|
|
defendersProhab = 0;
|
|
|
|
bool isDefender = role < defendersProhab;
|
|
bool isAdvanced = !isDefender && role > 8;
|
|
|
|
const auto& attackObjectives =
|
|
(team == TEAM_HORDE) ? AV_AttackObjectives_Horde : AV_AttackObjectives_Alliance;
|
|
const auto& defendObjectives =
|
|
(team == TEAM_HORDE) ? AV_DefendObjectives_Horde : AV_DefendObjectives_Alliance;
|
|
|
|
uint32 destroyedNodes = 0;
|
|
for (const auto& [nodeId, _] : defendObjectives)
|
|
if (av->GetAVNodeInfo(nodeId).State == POINT_DESTROYED)
|
|
destroyedNodes++;
|
|
|
|
float botX = bot->GetPositionX();
|
|
if (isDefender)
|
|
{
|
|
if ((team == TEAM_HORDE && botX >= -62.0f) || (team == TEAM_ALLIANCE && botX <= -462.0f))
|
|
isDefender = false;
|
|
}
|
|
|
|
if (isDefender && destroyedNodes > 0)
|
|
{
|
|
uint32 switchChance = 20 + (destroyedNodes * 15);
|
|
if (urand(0, 99) < switchChance)
|
|
isDefender = false;
|
|
}
|
|
|
|
// --- Mine Capture (rarely works, needs some improvement) ---
|
|
if (!BgObjective && enableMineCapture && role == 0)
|
|
{
|
|
BG_AV_OTHER_VALUES mineType = (team == TEAM_HORDE) ? AV_SOUTH_MINE : AV_NORTH_MINE;
|
|
if (av->GetMineOwner(mineType) != team)
|
|
{
|
|
uint32 bossEntry = (team == TEAM_HORDE) ? AV_CPLACE_MINE_S_3 : AV_CPLACE_MINE_N_3;
|
|
Creature* mBossNeutral = bg->GetBGCreature(bossEntry);
|
|
const Position* minePositions[] = {(team == TEAM_HORDE) ? &AV_MINE_SOUTH_1 : &AV_MINE_NORTH_1,
|
|
(team == TEAM_HORDE) ? &AV_MINE_SOUTH_2 : &AV_MINE_NORTH_2,
|
|
(team == TEAM_HORDE) ? &AV_MINE_SOUTH_3 : &AV_MINE_NORTH_3};
|
|
|
|
const Position* chosen = minePositions[urand(0, 2)];
|
|
pos.Set(chosen->GetPositionX(), chosen->GetPositionY(), chosen->GetPositionZ(), bot->GetMapId());
|
|
posMap["bg objective"] = pos;
|
|
BgObjective = mBossNeutral;
|
|
}
|
|
}
|
|
|
|
// --- Nearby Enemy ---
|
|
if (!BgObjective && urand(0, 99) < 8)
|
|
{
|
|
if (Unit* enemy = AI_VALUE(Unit*, "enemy player target"))
|
|
{
|
|
if (bot->GetDistance(enemy) < 500.0f)
|
|
{
|
|
pos.Set(enemy->GetPositionX(), enemy->GetPositionY(), enemy->GetPositionZ(), bot->GetMapId());
|
|
posMap["bg objective"] = pos;
|
|
BgObjective = enemy;
|
|
}
|
|
}
|
|
}
|
|
|
|
// --- Snowfall ---
|
|
bool hasSnowfallRole = enableSnowfall && ((team == TEAM_ALLIANCE && role < 6) || (team == TEAM_HORDE && role < 5));
|
|
|
|
if (!BgObjective && hasSnowfallRole)
|
|
{
|
|
const BG_AV_NodeInfo& snowfallNode = av->GetAVNodeInfo(BG_AV_NODES_SNOWFALL_GRAVE);
|
|
if (snowfallNode.OwnerId == TEAM_NEUTRAL)
|
|
{
|
|
if (GameObject* go = bg->GetBGObject(BG_AV_OBJECT_FLAG_N_SNOWFALL_GRAVE))
|
|
{
|
|
Position objPos = go->GetPosition();
|
|
float rx, ry, rz;
|
|
bot->GetRandomPoint(objPos, frand(5.0f, 15.0f), rx, ry, rz);
|
|
if (Map* map = bot->GetMap())
|
|
{
|
|
float groundZ = map->GetHeight(rx, ry, rz);
|
|
if (groundZ == VMAP_INVALID_HEIGHT_VALUE)
|
|
rz = groundZ;
|
|
}
|
|
|
|
pos.Set(rx, ry, rz, go->GetMapId());
|
|
posMap["bg objective"] = pos;
|
|
BgObjective = go;
|
|
}
|
|
}
|
|
}
|
|
|
|
// --- Captain ---
|
|
if (!BgObjective && urand(0, 99) < 90)
|
|
{
|
|
if (av->IsCaptainAlive(team == TEAM_HORDE ? TEAM_ALLIANCE : TEAM_HORDE))
|
|
{
|
|
uint32 creatureId = (team == TEAM_HORDE) ? AV_CREATURE_A_CAPTAIN : AV_CREATURE_H_CAPTAIN;
|
|
if (Creature* captain = bg->GetBGCreature(creatureId))
|
|
{
|
|
if (captain->IsAlive())
|
|
{
|
|
BgObjective = captain;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// --- Defender Logic ---
|
|
if (!BgObjective && isDefender)
|
|
{
|
|
std::vector<GameObject*> contestedObjectives;
|
|
std::vector<GameObject*> availableObjectives;
|
|
|
|
for (const auto& [nodeId, goId] : defendObjectives)
|
|
{
|
|
const BG_AV_NodeInfo& node = av->GetAVNodeInfo(nodeId);
|
|
if (node.State == POINT_DESTROYED)
|
|
continue;
|
|
|
|
GameObject* go = bg->GetBGObject(goId);
|
|
if (!go)
|
|
continue;
|
|
|
|
if (node.State == POINT_ASSAULTED)
|
|
contestedObjectives.push_back(go);
|
|
else
|
|
availableObjectives.push_back(go);
|
|
}
|
|
|
|
if (!contestedObjectives.empty())
|
|
BgObjective = contestedObjectives[urand(0, contestedObjectives.size() - 1)];
|
|
else if (!availableObjectives.empty())
|
|
BgObjective = availableObjectives[urand(0, availableObjectives.size() - 1)];
|
|
}
|
|
|
|
// --- Enemy Boss ---
|
|
if (!BgObjective)
|
|
{
|
|
uint32 towersDown = 0;
|
|
for (const auto& [nodeId, _] : attackObjectives)
|
|
if (av->GetAVNodeInfo(nodeId).State == POINT_DESTROYED)
|
|
towersDown++;
|
|
|
|
if ((towersDown >= 2) || (strategy == AV_STRATEGY_OFFENSIVE))
|
|
{
|
|
uint8 lastGY = (team == TEAM_HORDE) ? BG_AV_NODES_FIRSTAID_STATION : BG_AV_NODES_FROSTWOLF_HUT;
|
|
bool ownsFinalGY = av->GetAVNodeInfo(lastGY).OwnerId == team;
|
|
|
|
uint32 bossId = (team == TEAM_HORDE) ? AV_CREATURE_A_BOSS : AV_CREATURE_H_BOSS;
|
|
if (Creature* boss = bg->GetBGCreature(bossId))
|
|
{
|
|
if (boss->IsAlive())
|
|
{
|
|
uint32 nearbyCount = getPlayersInArea(team, boss->GetPosition(), 200.0f, false);
|
|
if (ownsFinalGY || nearbyCount >= 20)
|
|
BgObjective = boss;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// --- Attacker Logic ---
|
|
if (!BgObjective)
|
|
{
|
|
std::vector<GameObject*> candidates;
|
|
|
|
for (const auto& [nodeId, goId] : attackObjectives)
|
|
{
|
|
const BG_AV_NodeInfo& node = av->GetAVNodeInfo(nodeId);
|
|
GameObject* go = bg->GetBGObject(goId);
|
|
if (!go || node.State == POINT_DESTROYED || node.TotalOwnerId == team)
|
|
continue;
|
|
|
|
if (node.State == POINT_ASSAULTED && urand(0, 99) >= 1)
|
|
continue;
|
|
|
|
candidates.push_back(go);
|
|
|
|
if (((strategy == AV_STRATEGY_BALANCED && candidates.size() >= 2) ||
|
|
(strategy == AV_STRATEGY_OFFENSIVE && candidates.size() >= 3) ||
|
|
(strategy == AV_STRATEGY_DEFENSIVE && candidates.size() >= 1)) ||
|
|
isAdvanced)
|
|
break;
|
|
}
|
|
|
|
if (!candidates.empty())
|
|
BgObjective = candidates[urand(0, candidates.size() - 1)];
|
|
else
|
|
{
|
|
// Fallback: move to boss wait position
|
|
const Position& waitPos = (team == TEAM_HORDE) ? AV_BOSS_WAIT_H : AV_BOSS_WAIT_A;
|
|
|
|
float rx, ry, rz;
|
|
bot->GetRandomPoint(waitPos, 5.0f, rx, ry, rz);
|
|
|
|
if (Map* map = bot->GetMap())
|
|
{
|
|
float groundZ = map->GetHeight(rx, ry, rz);
|
|
if (groundZ == VMAP_INVALID_HEIGHT_VALUE)
|
|
rz = groundZ;
|
|
}
|
|
|
|
pos.Set(rx, ry, rz, bot->GetMapId());
|
|
posMap["bg objective"] = pos;
|
|
|
|
uint32 bossId = (team == TEAM_HORDE) ? AV_CREATURE_A_BOSS : AV_CREATURE_H_BOSS;
|
|
if (Creature* boss = bg->GetBGCreature(bossId))
|
|
if (boss->IsAlive())
|
|
BgObjective = boss;
|
|
}
|
|
}
|
|
|
|
// --- Movement logic for any valid objective ---
|
|
if (BgObjective)
|
|
{
|
|
Position objPos = BgObjective->GetPosition();
|
|
|
|
Optional<uint8> linkedNodeId;
|
|
for (const auto& [nodeId, goId] : attackObjectives)
|
|
if (bg->GetBGObject(goId) == BgObjective)
|
|
linkedNodeId = nodeId;
|
|
|
|
if (!linkedNodeId)
|
|
{
|
|
for (const auto& [nodeId, goId] : defendObjectives)
|
|
if (bg->GetBGObject(goId) == BgObjective)
|
|
linkedNodeId = nodeId;
|
|
}
|
|
|
|
float rx, ry, rz;
|
|
if (linkedNodeId && AVNodeMovementTargets.count(*linkedNodeId))
|
|
{
|
|
const AVNodePositionData& data = AVNodeMovementTargets[*linkedNodeId];
|
|
bot->GetRandomPoint(data.pos, frand(-data.maxRadius, data.maxRadius), rx, ry, rz);
|
|
}
|
|
else
|
|
bot->GetRandomPoint(objPos, frand(-2.0f, 2.0f), rx, ry, rz);
|
|
|
|
if (Map* map = bot->GetMap())
|
|
{
|
|
float groundZ = map->GetHeight(rx, ry, rz);
|
|
if (groundZ == VMAP_INVALID_HEIGHT_VALUE)
|
|
rz = groundZ;
|
|
}
|
|
|
|
pos.Set(rx, ry, rz, BgObjective->GetMapId());
|
|
posMap["bg objective"] = pos;
|
|
return true;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case BATTLEGROUND_WS:
|
|
{
|
|
Position target;
|
|
TeamId team = bot->GetTeamId();
|
|
|
|
// Utility to safely relocate a position with optional random radius
|
|
auto SetSafePos = [&](Position const& origin, float radius = 0.0f) -> void
|
|
{
|
|
float rx, ry, rz;
|
|
if (radius > 0.0f)
|
|
{
|
|
bot->GetRandomPoint(origin, radius, rx, ry, rz);
|
|
if (rz == VMAP_INVALID_HEIGHT_VALUE)
|
|
target.Relocate(rx, ry, rz);
|
|
else
|
|
target.Relocate(origin);
|
|
}
|
|
else
|
|
{
|
|
target.Relocate(origin);
|
|
}
|
|
};
|
|
|
|
// Check if the bot is carrying the flag
|
|
bool hasFlag = bot->HasAura(BG_WS_SPELL_WARSONG_FLAG) || bot->HasAura(BG_WS_SPELL_SILVERWING_FLAG);
|
|
|
|
// Retrieve role
|
|
uint8 role = context->GetValue<uint32>("bg role")->Get();
|
|
WSBotStrategy strategyHorde = static_cast<WSBotStrategy>(GetBotStrategyForTeam(bg, TEAM_HORDE));
|
|
WSBotStrategy strategyAlliance = static_cast<WSBotStrategy>(GetBotStrategyForTeam(bg, TEAM_ALLIANCE));
|
|
WSBotStrategy strategy = (team == TEAM_ALLIANCE) ? strategyAlliance : strategyHorde;
|
|
WSBotStrategy enemyStrategy = (team == TEAM_ALLIANCE) ? strategyHorde : strategyAlliance;
|
|
|
|
uint8 defendersProhab = 3; // Default balanced
|
|
|
|
switch (strategy)
|
|
{
|
|
case 0:
|
|
case 1:
|
|
case 2:
|
|
case 3: // Balanced
|
|
defendersProhab = 3;
|
|
break;
|
|
case 4:
|
|
case 5:
|
|
case 6:
|
|
case 7: // Heavy Offense
|
|
defendersProhab = 1;
|
|
break;
|
|
case 8:
|
|
case 9: // Heavy Defense
|
|
defendersProhab = 6;
|
|
break;
|
|
}
|
|
|
|
if (enemyStrategy == WS_STRATEGY_DEFENSIVE)
|
|
defendersProhab = 2;
|
|
|
|
// Role check
|
|
bool isDefender = role < defendersProhab;
|
|
|
|
// Retrieve flag carriers
|
|
Unit* enemyFC = AI_VALUE(Unit*, "enemy flag carrier");
|
|
Unit* teamFC = AI_VALUE(Unit*, "team flag carrier");
|
|
|
|
// Retrieve current score
|
|
uint8 allianceScore = bg->GetTeamScore(TEAM_ALLIANCE);
|
|
uint8 hordeScore = bg->GetTeamScore(TEAM_HORDE);
|
|
|
|
// Check if both teams currently have the flag
|
|
bool bothFlagsTaken = enemyFC && teamFC;
|
|
if (!hasFlag && bothFlagsTaken)
|
|
{
|
|
// If both flags taken: Bots have 20% chance to support own flag carrier, otherwise attack enemy FC
|
|
if (urand(0, 99) < 20 && teamFC)
|
|
{
|
|
target.Relocate(teamFC->GetPositionX(), teamFC->GetPositionY(), teamFC->GetPositionZ());
|
|
if (sServerFacade->GetDistance2d(bot, teamFC) < 33.0f)
|
|
Follow(teamFC);
|
|
}
|
|
else
|
|
target.Relocate(enemyFC->GetPositionX(), enemyFC->GetPositionY(), enemyFC->GetPositionZ());
|
|
}
|
|
// Graveyard Camping if in lead
|
|
else if (!hasFlag && role < 8 &&
|
|
(team == TEAM_ALLIANCE && allianceScore == 2 && hordeScore == 0) ||
|
|
(team == TEAM_HORDE && hordeScore == 2 && allianceScore == 0))
|
|
{
|
|
if (team == TEAM_ALLIANCE)
|
|
SetSafePos(WS_GY_CAMPING_HORDE, 10.0f);
|
|
else
|
|
SetSafePos(WS_GY_CAMPING_ALLIANCE, 10.0f);
|
|
}
|
|
else if (hasFlag)
|
|
{
|
|
// If carrying the flag, either hide or return to base
|
|
if (team == TEAM_ALLIANCE)
|
|
SetSafePos(teamFlagTaken() ? WS_FLAG_HIDE_ALLIANCE[urand(0, 2)] : WS_FLAG_POS_ALLIANCE);
|
|
else
|
|
SetSafePos(teamFlagTaken() ? WS_FLAG_HIDE_HORDE[urand(0, 2)] : WS_FLAG_POS_HORDE);
|
|
}
|
|
else
|
|
{
|
|
if (isDefender)
|
|
{
|
|
if (enemyFC)
|
|
{
|
|
// Defenders attack enemy FC if found
|
|
target.Relocate(enemyFC->GetPositionX(), enemyFC->GetPositionY(), enemyFC->GetPositionZ());
|
|
}
|
|
else if (urand(0, 99) < 33)
|
|
{
|
|
// 33% chance to roam near own base
|
|
SetSafePos(team == TEAM_ALLIANCE ? WS_FLAG_HIDE_ALLIANCE[urand(0, 2)] : WS_FLAG_HIDE_HORDE[urand(0, 2)], 5.0f);
|
|
}
|
|
else if (teamFC)
|
|
{
|
|
// 70% chance to support own FC
|
|
if (urand(0, 99) < 70)
|
|
{
|
|
target.Relocate(teamFC->GetPositionX(), teamFC->GetPositionY(), teamFC->GetPositionZ());
|
|
if (sServerFacade->GetDistance2d(bot, teamFC) < 33.0f)
|
|
Follow(teamFC);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Roam around central area
|
|
SetSafePos(WS_ROAM_POS, 75.0f);
|
|
}
|
|
}
|
|
else // attacker logic
|
|
{
|
|
if (enemyFC && urand(0, 99) < 70)
|
|
{
|
|
// 70% chance to pursue enemy FC
|
|
target.Relocate(enemyFC->GetPositionX(), enemyFC->GetPositionY(), enemyFC->GetPositionZ());
|
|
}
|
|
else if (teamFC)
|
|
{
|
|
// Assist own FC if not pursuing enemy FC
|
|
target.Relocate(teamFC->GetPositionX(), teamFC->GetPositionY(), teamFC->GetPositionZ());
|
|
if (sServerFacade->GetDistance2d(bot, teamFC) < 33.0f)
|
|
Follow(teamFC);
|
|
}
|
|
else if (urand(0, 99) < 5)
|
|
{
|
|
// 5% chance to free roam
|
|
SetSafePos(WS_ROAM_POS, 75.0f);
|
|
}
|
|
else
|
|
{
|
|
// Push toward enemy flag base
|
|
SetSafePos(team == TEAM_ALLIANCE ? WS_FLAG_POS_HORDE : WS_FLAG_POS_ALLIANCE);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Save the final target position
|
|
if (target.IsPositionValid())
|
|
{
|
|
pos.Set(target.GetPositionX(), target.GetPositionY(), target.GetPositionZ(), bot->GetMapId());
|
|
posMap["bg objective"] = pos;
|
|
return true;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case BATTLEGROUND_AB:
|
|
{
|
|
if (!bg)
|
|
break;
|
|
|
|
BattlegroundAB* ab = static_cast<BattlegroundAB*>(bg);
|
|
TeamId team = bot->GetTeamId();
|
|
|
|
uint8 role = context->GetValue<uint32>("bg role")->Get();
|
|
ABBotStrategy strategyHorde = static_cast<ABBotStrategy>(GetBotStrategyForTeam(bg, TEAM_HORDE));
|
|
ABBotStrategy strategyAlliance = static_cast<ABBotStrategy>(GetBotStrategyForTeam(bg, TEAM_ALLIANCE));
|
|
ABBotStrategy strategy = (team == TEAM_ALLIANCE) ? strategyAlliance : strategyHorde;
|
|
ABBotStrategy enemyStrategy = (team == TEAM_ALLIANCE) ? strategyHorde : strategyAlliance;
|
|
|
|
uint8 defendersProhab = 3;
|
|
if (strategy == AB_STRATEGY_OFFENSIVE)
|
|
defendersProhab = 1;
|
|
else if (strategy == AB_STRATEGY_DEFENSIVE)
|
|
defendersProhab = 6;
|
|
|
|
if (enemyStrategy == AB_STRATEGY_DEFENSIVE)
|
|
defendersProhab = 2;
|
|
|
|
bool isDefender = role < defendersProhab;
|
|
bool isSilly = urand(0, 99) < 20;
|
|
|
|
BgObjective = nullptr;
|
|
|
|
// --- PRIORITY 1: Nearby enemy (rare aggressive impulse)
|
|
if (urand(0, 99) < 5)
|
|
{
|
|
if (Unit* enemy = AI_VALUE(Unit*, "enemy player target"))
|
|
{
|
|
if (bot->GetDistance(enemy) < 500.0f)
|
|
{
|
|
pos.Set(enemy->GetPositionX(), enemy->GetPositionY(), enemy->GetPositionZ(), bot->GetMapId());
|
|
posMap["bg objective"] = pos;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// --- PRIORITY 2: No valid nodes? Camp or attack visible enemy
|
|
bool hasValidTarget = false;
|
|
for (uint32 nodeId : AB_AttackObjectives)
|
|
{
|
|
uint8 state = ab->GetCapturePointInfo(nodeId)._state;
|
|
if (state == BG_AB_NODE_STATE_NEUTRAL ||
|
|
(team == TEAM_ALLIANCE &&
|
|
(state == BG_AB_NODE_STATE_HORDE_OCCUPIED || state == BG_AB_NODE_STATE_HORDE_CONTESTED)) ||
|
|
(team == TEAM_HORDE &&
|
|
(state == BG_AB_NODE_STATE_ALLY_OCCUPIED || state == BG_AB_NODE_STATE_ALLY_CONTESTED)))
|
|
{
|
|
hasValidTarget = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!hasValidTarget)
|
|
{
|
|
if (Unit* enemy = AI_VALUE(Unit*, "enemy player target"))
|
|
{
|
|
if (bot->GetDistance(enemy) < 500.0f)
|
|
{
|
|
pos.Set(enemy->GetPositionX(), enemy->GetPositionY(), enemy->GetPositionZ(), bot->GetMapId());
|
|
posMap["bg objective"] = pos;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Camp enemy GY fallback
|
|
Position camp = (team == TEAM_ALLIANCE) ? AB_GY_CAMPING_HORDE : AB_GY_CAMPING_ALLIANCE;
|
|
float rx, ry, rz;
|
|
bot->GetRandomPoint(camp, 10.0f, rx, ry, rz);
|
|
if (Map* map = bot->GetMap())
|
|
{
|
|
float groundZ = map->GetHeight(rx, ry, rz);
|
|
if (groundZ == VMAP_INVALID_HEIGHT_VALUE)
|
|
rz = groundZ;
|
|
}
|
|
pos.Set(rx, ry, rz, bot->GetMapId());
|
|
posMap["bg objective"] = pos;
|
|
break;
|
|
}
|
|
|
|
// --- PRIORITY 3: Defender logic ---
|
|
if (isDefender && urand(0, 99) < 85)
|
|
{
|
|
float closestDist = FLT_MAX;
|
|
for (uint32 nodeId : AB_AttackObjectives)
|
|
{
|
|
uint8 state = ab->GetCapturePointInfo(nodeId)._state;
|
|
|
|
bool isContested = (team == TEAM_ALLIANCE && state == BG_AB_NODE_STATE_HORDE_CONTESTED) ||
|
|
(team == TEAM_HORDE && state == BG_AB_NODE_STATE_ALLY_CONTESTED);
|
|
bool isOwned = (team == TEAM_ALLIANCE && state == BG_AB_NODE_STATE_ALLY_OCCUPIED) ||
|
|
(team == TEAM_HORDE && state == BG_AB_NODE_STATE_HORDE_OCCUPIED);
|
|
|
|
if (!isContested && !isOwned)
|
|
continue;
|
|
|
|
GameObject* go = bg->GetBGObject(nodeId * BG_AB_OBJECTS_PER_NODE);
|
|
if (!go)
|
|
continue;
|
|
|
|
float dist = bot->GetDistance(go);
|
|
if (dist < closestDist)
|
|
{
|
|
closestDist = dist;
|
|
BgObjective = go;
|
|
}
|
|
}
|
|
}
|
|
|
|
// --- PRIORITY 4: Attack objectives ---
|
|
if (!BgObjective)
|
|
{
|
|
std::vector<GameObject*> objectivePool;
|
|
|
|
for (uint8 i = 0; i < 3; ++i)
|
|
{
|
|
float bestDist = isSilly ? 0.0f : FLT_MAX;
|
|
GameObject* chosen = nullptr;
|
|
|
|
for (uint32 nodeId : AB_AttackObjectives)
|
|
{
|
|
uint8 state = ab->GetCapturePointInfo(nodeId)._state;
|
|
|
|
bool isNeutral = state == BG_AB_NODE_STATE_NEUTRAL;
|
|
bool isEnemyOccupied = (team == TEAM_ALLIANCE && state == BG_AB_NODE_STATE_HORDE_OCCUPIED) ||
|
|
(team == TEAM_HORDE && state == BG_AB_NODE_STATE_ALLY_OCCUPIED);
|
|
bool isFriendlyContested =
|
|
(team == TEAM_ALLIANCE && state == BG_AB_NODE_STATE_ALLY_CONTESTED) ||
|
|
(team == TEAM_HORDE && state == BG_AB_NODE_STATE_HORDE_CONTESTED);
|
|
|
|
if (!(isNeutral || isEnemyOccupied || isFriendlyContested))
|
|
continue;
|
|
|
|
GameObject* go = bg->GetBGObject(nodeId * BG_AB_OBJECTS_PER_NODE);
|
|
if (!go || std::find(objectivePool.begin(), objectivePool.end(), go) != objectivePool.end())
|
|
continue;
|
|
|
|
float dist = bot->GetDistance(go);
|
|
if ((isSilly && dist > bestDist) || (!isSilly && dist < bestDist))
|
|
{
|
|
bestDist = dist;
|
|
chosen = go;
|
|
}
|
|
}
|
|
|
|
if (chosen)
|
|
objectivePool.push_back(chosen);
|
|
}
|
|
|
|
if (!objectivePool.empty())
|
|
BgObjective = objectivePool[urand(0, objectivePool.size() - 1)];
|
|
}
|
|
|
|
// --- Final move ---
|
|
if (BgObjective)
|
|
{
|
|
float rx, ry, rz;
|
|
Position objPos = BgObjective->GetPosition();
|
|
bot->GetRandomPoint(objPos, frand(5.0f, 15.0f), rx, ry, rz);
|
|
|
|
if (Map* map = bot->GetMap())
|
|
{
|
|
float groundZ = map->GetHeight(rx, ry, rz);
|
|
if (groundZ == VMAP_INVALID_HEIGHT_VALUE)
|
|
rz = groundZ;
|
|
}
|
|
|
|
pos.Set(rx, ry, rz, BgObjective->GetMapId());
|
|
posMap["bg objective"] = pos;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
case BATTLEGROUND_EY:
|
|
{
|
|
BattlegroundEY* eyeOfTheStormBG = (BattlegroundEY*)bg;
|
|
TeamId team = bot->GetTeamId();
|
|
uint8 role = context->GetValue<uint32>("bg role")->Get();
|
|
|
|
EYBotStrategy strategyHorde = static_cast<EYBotStrategy>(GetBotStrategyForTeam(bg, TEAM_HORDE));
|
|
EYBotStrategy strategyAlliance = static_cast<EYBotStrategy>(GetBotStrategyForTeam(bg, TEAM_ALLIANCE));
|
|
EYBotStrategy strategy = (team == TEAM_ALLIANCE) ? strategyAlliance : strategyHorde;
|
|
EYBotStrategy enemyStrategy = (team == TEAM_ALLIANCE) ? strategyHorde : strategyAlliance;
|
|
|
|
auto IsOwned = [&](uint32 nodeId) -> bool
|
|
{ return eyeOfTheStormBG->GetCapturePointInfo(nodeId)._ownerTeamId == team; };
|
|
|
|
uint8 defendersProhab = 4;
|
|
switch (strategy)
|
|
{
|
|
case EY_STRATEGY_FLAG_FOCUS:
|
|
defendersProhab = 2;
|
|
break;
|
|
case EY_STRATEGY_FRONT_FOCUS:
|
|
case EY_STRATEGY_BACK_FOCUS:
|
|
defendersProhab = 3;
|
|
break;
|
|
default:
|
|
defendersProhab = 4;
|
|
break;
|
|
}
|
|
|
|
bool isDefender = role < defendersProhab;
|
|
|
|
std::tuple<uint32, uint32, uint32> front[2];
|
|
std::tuple<uint32, uint32, uint32> back[2];
|
|
|
|
if (team == TEAM_HORDE)
|
|
{
|
|
front[0] = EY_AttackObjectives[0];
|
|
front[1] = EY_AttackObjectives[1];
|
|
back[0] = EY_AttackObjectives[2];
|
|
back[1] = EY_AttackObjectives[3];
|
|
}
|
|
else
|
|
{
|
|
front[0] = EY_AttackObjectives[2];
|
|
front[1] = EY_AttackObjectives[3];
|
|
back[0] = EY_AttackObjectives[0];
|
|
back[1] = EY_AttackObjectives[1];
|
|
}
|
|
|
|
bool foundObjective = false;
|
|
|
|
// --- PRIORITY 1: FLAG CARRIER ---
|
|
if (bot->HasAura(BG_EY_NETHERSTORM_FLAG_SPELL))
|
|
{
|
|
uint32 bestNodeId = 0;
|
|
float bestDist = FLT_MAX;
|
|
uint32 bestTrigger = 0;
|
|
|
|
for (const auto& [nodeId, _, areaTrigger] : EY_AttackObjectives)
|
|
{
|
|
if (!IsOwned(nodeId))
|
|
continue;
|
|
|
|
auto it = EY_NodePositions.find(nodeId);
|
|
if (it == EY_NodePositions.end())
|
|
continue;
|
|
|
|
float dist = bot->GetDistance(it->second);
|
|
if (dist < bestDist)
|
|
{
|
|
bestDist = dist;
|
|
bestNodeId = nodeId;
|
|
bestTrigger = areaTrigger;
|
|
}
|
|
}
|
|
|
|
if (bestNodeId != 0 && EY_NodePositions.contains(bestNodeId))
|
|
{
|
|
const Position& targetPos = EY_NodePositions[bestNodeId];
|
|
float rx, ry, rz;
|
|
bot->GetRandomPoint(targetPos, 5.0f, rx, ry, rz);
|
|
|
|
if (Map* map = bot->GetMap())
|
|
{
|
|
float groundZ = map->GetHeight(rx, ry, rz);
|
|
if (groundZ == VMAP_INVALID_HEIGHT_VALUE)
|
|
rz = groundZ;
|
|
}
|
|
|
|
pos.Set(rx, ry, rz, bot->GetMapId());
|
|
|
|
// Check AreaTrigger activation range
|
|
if (bestTrigger && bot->IsWithinDist3d(pos.x, pos.y, pos.z, INTERACTION_DISTANCE))
|
|
{
|
|
WorldPacket data(CMSG_AREATRIGGER);
|
|
data << uint32(bestTrigger);
|
|
bot->GetSession()->HandleAreaTriggerOpcode(data);
|
|
pos.Reset();
|
|
}
|
|
|
|
foundObjective = true;
|
|
}
|
|
else
|
|
{
|
|
const Position& fallback = (team == TEAM_ALLIANCE) ? EY_FLAG_RETURN_POS_RETREAT_ALLIANCE
|
|
: EY_FLAG_RETURN_POS_RETREAT_HORDE;
|
|
|
|
float rx, ry, rz;
|
|
bot->GetRandomPoint(fallback, 5.0f, rx, ry, rz);
|
|
|
|
if (Map* map = bot->GetMap())
|
|
{
|
|
float groundZ = map->GetHeight(rx, ry, rz);
|
|
if (groundZ == VMAP_INVALID_HEIGHT_VALUE)
|
|
rz = groundZ;
|
|
}
|
|
|
|
pos.Set(rx, ry, rz, bot->GetMapId());
|
|
foundObjective = true;
|
|
}
|
|
}
|
|
|
|
// --- PRIORITY 2: Nearby unowned contested node ---
|
|
if (!foundObjective)
|
|
{
|
|
for (const auto& [nodeId, _, __] : EY_AttackObjectives)
|
|
{
|
|
if (IsOwned(nodeId))
|
|
continue;
|
|
|
|
auto it = EY_NodePositions.find(nodeId);
|
|
if (it == EY_NodePositions.end())
|
|
continue;
|
|
|
|
const Position& p = it->second;
|
|
if (bot->IsWithinDist2d(p.GetPositionX(), p.GetPositionY(), 125.0f))
|
|
{
|
|
float rx, ry, rz;
|
|
bot->GetRandomPoint(p, 5.0f, rx, ry, rz);
|
|
rz = bot->GetMap()->GetHeight(rx, ry, rz);
|
|
pos.Set(rx, ry, rz, bot->GetMapId());
|
|
foundObjective = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// --- PRIORITY 3: Random nearby enemy (20%) ---
|
|
if (!foundObjective && urand(0, 99) < 20)
|
|
{
|
|
if (Unit* enemy = AI_VALUE(Unit*, "enemy player target"))
|
|
{
|
|
if (bot->GetDistance(enemy) < 250.0f)
|
|
{
|
|
pos.Set(enemy->GetPositionX(), enemy->GetPositionY(), enemy->GetPositionZ(), bot->GetMapId());
|
|
foundObjective = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// --- PRIORITY 4: Defender Logic ---
|
|
if (!foundObjective && isDefender && urand(0, 99) <= 80)
|
|
{
|
|
// 1. Chase enemy flag carrier
|
|
if (Unit* enemyFC = AI_VALUE(Unit*, "enemy flag carrier"))
|
|
{
|
|
if (bot->CanSeeOrDetect(enemyFC, false, false, true) && enemyFC->IsAlive())
|
|
{
|
|
pos.Set(enemyFC->GetPositionX(), enemyFC->GetPositionY(), enemyFC->GetPositionZ(), bot->GetMapId());
|
|
foundObjective = true;
|
|
}
|
|
}
|
|
|
|
// 2. Support friendly flag carrier
|
|
if (!foundObjective)
|
|
{
|
|
if (Unit* friendlyFC = AI_VALUE(Unit*, "team flag carrier"))
|
|
{
|
|
if (friendlyFC->IsAlive())
|
|
{
|
|
pos.Set(friendlyFC->GetPositionX(), friendlyFC->GetPositionY(), friendlyFC->GetPositionZ(), bot->GetMapId());
|
|
foundObjective = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 3. Pick up the flag
|
|
if (!foundObjective)
|
|
{
|
|
if (GameObject* flag = bg->GetBGObject(BG_EY_OBJECT_FLAG_NETHERSTORM); flag && flag->isSpawned())
|
|
{
|
|
pos.Set(flag->GetPositionX(), flag->GetPositionY(), flag->GetPositionZ(), flag->GetMapId());
|
|
foundObjective = true;
|
|
}
|
|
}
|
|
|
|
// 4. Default: defend owned node
|
|
if (!foundObjective && urand(0, 99) < 50)
|
|
{
|
|
std::vector<uint32> owned;
|
|
for (auto const& obj : front)
|
|
{
|
|
uint32 nodeId = std::get<0>(obj);
|
|
if (IsOwned(nodeId))
|
|
owned.push_back(nodeId);
|
|
}
|
|
|
|
if (!owned.empty())
|
|
{
|
|
uint32 chosenId = owned[urand(0, owned.size() - 1)];
|
|
if (EY_NodePositions.contains(chosenId))
|
|
{
|
|
const Position& p = EY_NodePositions[chosenId];
|
|
float rx, ry, rz;
|
|
bot->GetRandomPoint(p, 5.0f, rx, ry, rz);
|
|
rz = bot->GetMap()->GetHeight(rx, ry, rz);
|
|
pos.Set(rx, ry, rz, bot->GetMapId());
|
|
foundObjective = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// --- PRIORITY 5: Flag Strategy ---
|
|
if (!foundObjective && strategy == EY_STRATEGY_FLAG_FOCUS)
|
|
{
|
|
bool ownsAny = false;
|
|
for (const auto& [nodeId, _, __] : EY_AttackObjectives)
|
|
{
|
|
if (IsOwned(nodeId))
|
|
{
|
|
ownsAny = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ownsAny)
|
|
{
|
|
if (Unit* fc = AI_VALUE(Unit*, "enemy flag carrier"))
|
|
{
|
|
pos.Set(fc->GetPositionX(), fc->GetPositionY(), fc->GetPositionZ(), bot->GetMapId());
|
|
foundObjective = true;
|
|
}
|
|
else if (GameObject* flag = bg->GetBGObject(BG_EY_OBJECT_FLAG_NETHERSTORM);
|
|
flag && flag->isSpawned())
|
|
{
|
|
pos.Set(flag->GetPositionX(), flag->GetPositionY(), flag->GetPositionZ(), flag->GetMapId());
|
|
foundObjective = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
float bestDist = FLT_MAX;
|
|
Optional<uint32> bestNode;
|
|
|
|
for (const auto& [nodeId, _, __] : EY_AttackObjectives)
|
|
{
|
|
if (IsOwned(nodeId))
|
|
continue;
|
|
|
|
auto it = EY_NodePositions.find(nodeId);
|
|
if (it == EY_NodePositions.end())
|
|
continue;
|
|
|
|
float dist = bot->GetDistance(it->second);
|
|
if (dist < bestDist)
|
|
{
|
|
bestDist = dist;
|
|
bestNode = nodeId;
|
|
}
|
|
}
|
|
|
|
if (bestNode && EY_NodePositions.contains(*bestNode))
|
|
{
|
|
const Position& p = EY_NodePositions[*bestNode];
|
|
float rx, ry, rz;
|
|
bot->GetRandomPoint(p, 5.0f, rx, ry, rz);
|
|
rz = bot->GetMap()->GetHeight(rx, ry, rz);
|
|
pos.Set(rx, ry, rz, bot->GetMapId());
|
|
foundObjective = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// --- PRIORITY 6: Strategy Objectives ---
|
|
if (!foundObjective)
|
|
{
|
|
std::vector<std::tuple<uint32, uint32, uint32>> priority, secondary;
|
|
|
|
switch (strategy)
|
|
{
|
|
case EY_STRATEGY_FRONT_FOCUS:
|
|
priority = {front[0], front[1]};
|
|
secondary = {back[0], back[1]};
|
|
break;
|
|
case EY_STRATEGY_BACK_FOCUS:
|
|
priority = {back[0], back[1]};
|
|
secondary = {front[0], front[1]};
|
|
break;
|
|
case EY_STRATEGY_BALANCED:
|
|
default:
|
|
priority = {front[0], front[1], back[0], back[1]};
|
|
break;
|
|
}
|
|
|
|
std::vector<uint32> candidates;
|
|
|
|
for (auto const& obj : priority)
|
|
{
|
|
uint32 nodeId = std::get<0>(obj);
|
|
if (!IsOwned(nodeId))
|
|
candidates.push_back(nodeId);
|
|
}
|
|
|
|
if (candidates.empty())
|
|
{
|
|
for (auto const& obj : secondary)
|
|
{
|
|
uint32 nodeId = std::get<0>(obj);
|
|
if (!IsOwned(nodeId))
|
|
candidates.push_back(nodeId);
|
|
}
|
|
}
|
|
|
|
if (!candidates.empty())
|
|
{
|
|
uint32 chosen = candidates[urand(0, candidates.size() - 1)];
|
|
if (EY_NodePositions.contains(chosen))
|
|
{
|
|
const Position& p = EY_NodePositions[chosen];
|
|
pos.Set(p.GetPositionX(), p.GetPositionY(), p.GetPositionZ(), bot->GetMapId());
|
|
foundObjective = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// --- PRIORITY 7: Camp GY if everything is owned ---
|
|
bool ownsAll = IsOwned(std::get<0>(front[0])) && IsOwned(std::get<0>(front[1])) &&
|
|
IsOwned(std::get<0>(back[0])) && IsOwned(std::get<0>(back[1]));
|
|
|
|
if (!foundObjective && ownsAll)
|
|
{
|
|
Position camp = (team == TEAM_HORDE) ? EY_GY_CAMPING_ALLIANCE : EY_GY_CAMPING_HORDE;
|
|
float rx, ry, rz;
|
|
bot->GetRandomPoint(camp, 10.0f, rx, ry, rz);
|
|
rz = bot->GetMap()->GetHeight(rx, ry, rz);
|
|
pos.Set(rx, ry, rz, bot->GetMapId());
|
|
foundObjective = true;
|
|
}
|
|
|
|
if (foundObjective)
|
|
posMap["bg objective"] = pos;
|
|
|
|
return true;
|
|
}
|
|
case BATTLEGROUND_IC:
|
|
{
|
|
BattlegroundIC* isleOfConquestBG = (BattlegroundIC*)bg;
|
|
|
|
uint32 role = context->GetValue<uint32>("bg role")->Get();
|
|
bool inVehicle = botAI->IsInVehicle();
|
|
bool controlsVehicle = botAI->IsInVehicle(true);
|
|
uint32 vehicleId = inVehicle ? bot->GetVehicleBase()->GetEntry() : 0;
|
|
|
|
// skip if not the driver
|
|
if (inVehicle && !controlsVehicle)
|
|
return false;
|
|
|
|
/* TACTICS */
|
|
if (bot->GetTeamId() == TEAM_HORDE) // HORDE
|
|
{
|
|
bool gateOpen = false;
|
|
if (GameObject* pGO = bg->GetBGObject(BG_IC_GO_DOODAD_PORTCULLISACTIVE02))
|
|
{
|
|
if (pGO->isSpawned() && pGO->getLootState() == GO_ACTIVATED)
|
|
{
|
|
gateOpen = true;
|
|
PositionInfo siegePos = context->GetValue<PositionMap&>("position")->Get()["bg siege"];
|
|
siegePos.Reset();
|
|
posMap["bg siege"] = siegePos;
|
|
}
|
|
}
|
|
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())
|
|
{
|
|
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
|
|
{
|
|
// just make bot stay where it is if already close
|
|
// (stops them shifting around between the random spots)
|
|
if (bot->GetDistance(IC_GATE_ATTACK_POS_HORDE) < 8.0f)
|
|
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<PositionMap&>("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;
|
|
// LOG_INFO("playerbots", "bot={} guard point while it captures", bot->GetName());
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!BgObjective) // guard vehicles as they seige
|
|
{
|
|
// just make bot stay where it is if already close
|
|
// (stops them shifting around between the random spots)
|
|
if (bot->GetDistance(IC_GATE_ATTACK_POS_HORDE) < 8.0f)
|
|
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
|
|
{
|
|
bool gateOpen = false;
|
|
if (GameObject* pGO = bg->GetBGObject(BG_IC_GO_HORDE_KEEP_PORTCULLIS))
|
|
{
|
|
if (pGO->isSpawned() && pGO->getLootState() == GO_ACTIVATED)
|
|
{
|
|
gateOpen = true;
|
|
PositionInfo siegePos = context->GetValue<PositionMap&>("position")->Get()["bg siege"];
|
|
siegePos.Reset();
|
|
posMap["bg siege"] = siegePos;
|
|
}
|
|
}
|
|
|
|
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())
|
|
{
|
|
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
|
|
{
|
|
// just make bot stay where it is if already close
|
|
// (stops them shifting around between the random spots)
|
|
if (bot->GetDistance(IC_GATE_ATTACK_POS_ALLIANCE) < 8.0f)
|
|
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<PositionMap&>("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;
|
|
// LOG_INFO("playerbots", "bot={} guard point while it captures", bot->GetName());
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!BgObjective) // guard vehicles as they seige
|
|
{
|
|
// just make bot stay where it is if already close
|
|
// (stops them shifting around between the random spots)
|
|
if (bot->GetDistance(IC_GATE_ATTACK_POS_ALLIANCE) < 8.0f)
|
|
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)
|
|
{
|
|
pos.Set(BgObjective->GetPositionX(), BgObjective->GetPositionY(), BgObjective->GetPositionZ(),
|
|
bot->GetMapId());
|
|
posMap["bg objective"] = pos;
|
|
return true;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool BGTactics::moveToObjective(bool ignoreDist)
|
|
{
|
|
Battleground* bg = bot->GetBattleground();
|
|
if (!bg)
|
|
return false;
|
|
|
|
BattlegroundTypeId bgType = bg->GetBgTypeID();
|
|
if (bgType == BATTLEGROUND_RB)
|
|
bgType = bg->GetBgTypeID(true);
|
|
|
|
PositionInfo pos = context->GetValue<PositionMap&>("position")->Get()["bg objective"];
|
|
if (!pos.isSet())
|
|
return selectObjective();
|
|
else
|
|
{
|
|
// Use portals in Isle of Conquest Base
|
|
if (bgType == BATTLEGROUND_IC)
|
|
{
|
|
if (IsLockedInsideKeep())
|
|
return true;
|
|
}
|
|
|
|
if (!ignoreDist && sServerFacade->IsDistanceGreaterThan(sServerFacade->GetDistance2d(bot, pos.x, pos.y), 100.0f))
|
|
{
|
|
// std::ostringstream out;
|
|
// out << "It is too far away! " << pos.x << ", " << pos.y << ", Distance: " <<
|
|
// sServerFacade->GetDistance2d(bot, pos.x, pos.y); bot->Say(out.str(), LANG_UNIVERSAL);
|
|
return false;
|
|
}
|
|
|
|
// don't try to move if already close
|
|
if (bot->GetDistance(pos.x, pos.y, pos.z) < 4.0f)
|
|
{
|
|
resetObjective();
|
|
return true;
|
|
}
|
|
|
|
// std::ostringstream out; out << "Moving to objective " << pos.x << ", " << pos.y << ", Distance: " <<
|
|
// sServerFacade->GetDistance2d(bot, pos.x, pos.y); bot->Say(out.str(), LANG_UNIVERSAL);
|
|
|
|
// dont increase from 1.5 will cause bugs with horde capping AV towers
|
|
return MoveNear(bot->GetMapId(), pos.x, pos.y, pos.z, 1.5f);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool BGTactics::selectObjectiveWp(std::vector<BattleBotPath*> const& vPaths)
|
|
{
|
|
Battleground* bg = bot->GetBattleground();
|
|
if (!bg)
|
|
return false;
|
|
|
|
BattlegroundTypeId bgType = bg->GetBgTypeID();
|
|
if (bgType == BATTLEGROUND_RB)
|
|
bgType = bg->GetBgTypeID(true);
|
|
|
|
PositionMap& posMap = context->GetValue<PositionMap&>("position")->Get();
|
|
PositionInfo pos = context->GetValue<PositionMap&>("position")->Get()["bg objective"];
|
|
if (!pos.isSet())
|
|
return false;
|
|
|
|
if (bgType == BATTLEGROUND_WS)
|
|
{
|
|
if (wsJumpDown())
|
|
return true;
|
|
}
|
|
else if (bgType == BATTLEGROUND_AV)
|
|
{
|
|
// get bots out of cave when they respawn there (otherwise path selection happens while they're deep within cave
|
|
// and the results arent good)
|
|
Position const caveSpawn = bot->GetTeamId() == TEAM_ALLIANCE ? AV_CAVE_SPAWN_ALLIANCE : AV_CAVE_SPAWN_HORDE;
|
|
if (bot->GetDistance(caveSpawn) < 16.0f)
|
|
{
|
|
return moveToStart(true);
|
|
}
|
|
}
|
|
else if (bgType == BATTLEGROUND_EY)
|
|
{
|
|
if (eyJumpDown())
|
|
return true;
|
|
}
|
|
|
|
float chosenPathScore = FLT_MAX; // lower score is better
|
|
BattleBotPath* chosenPath = nullptr;
|
|
uint32 chosenPathPoint = 0;
|
|
bool chosenPathReverse = false;
|
|
|
|
float botDistanceLimit = 50.0f; // limit for how far path can be from bot
|
|
float botDistanceScoreSubtract = 8.0f; // path score modifier - lower = less likely to chose a further path (it's
|
|
// basically the distance from bot that's ignored)
|
|
float botDistanceScoreMultiply =
|
|
3.0f; // path score modifier - higher = less likely to chose a further path (it's basically a multiplier on
|
|
// distance from bot - makes distance from bot more signifcant than distance from destination)
|
|
|
|
if (bgType == BATTLEGROUND_IC)
|
|
{
|
|
// botDistanceLimit = 80.0f;
|
|
botDistanceScoreMultiply = 8.0f;
|
|
botDistanceScoreSubtract = 2.0f;
|
|
}
|
|
else if (bgType == BATTLEGROUND_AV)
|
|
{
|
|
botDistanceLimit = 80.0f;
|
|
botDistanceScoreMultiply = 8.0f;
|
|
}
|
|
else if (bgType == BATTLEGROUND_AB || bgType == BATTLEGROUND_EY || bgType == BATTLEGROUND_WS)
|
|
{
|
|
botDistanceScoreSubtract = 2.0f;
|
|
botDistanceScoreMultiply = 4.0f;
|
|
}
|
|
|
|
// uint32 index = -1;
|
|
// uint32 chosenPathIndex = -1;
|
|
for (auto const& path : vPaths)
|
|
{
|
|
// index++;
|
|
// TODO need to remove sqrt from these two and distToBot but it totally throws path scoring out of
|
|
// whack if you do that without changing how its implemented (I'm amazed it works as well as it does
|
|
// using sqrt'ed distances)
|
|
// In a reworked version maybe compare the differences of path distances to point (ie: against best path)
|
|
// or maybe ratio's (where if a path end is twice the difference in distance from destination we basically
|
|
// use that to multiply the total score?
|
|
BattleBotWaypoint& startPoint = ((*path)[0]);
|
|
float const startPointDistToDestination =
|
|
sqrt(Position(pos.x, pos.y, pos.z, 0.f).GetExactDist(startPoint.x, startPoint.y, startPoint.z));
|
|
BattleBotWaypoint& endPoint = ((*path)[path->size() - 1]);
|
|
float const endPointDistToDestination =
|
|
sqrt(Position(pos.x, pos.y, pos.z, 0.f).GetExactDist(endPoint.x, endPoint.y, endPoint.z));
|
|
|
|
bool reverse = startPointDistToDestination < endPointDistToDestination;
|
|
|
|
// dont travel reverse if it's a reverse paths
|
|
if (reverse && std::find(vPaths_NoReverseAllowed.begin(), vPaths_NoReverseAllowed.end(), path) !=
|
|
vPaths_NoReverseAllowed.end())
|
|
continue;
|
|
|
|
int closestPointIndex = -1;
|
|
float closestPointDistToBot = FLT_MAX;
|
|
for (uint32 i = 0; i < path->size(); i++)
|
|
{
|
|
BattleBotWaypoint& waypoint = ((*path)[i]);
|
|
float const distToBot = sqrt(bot->GetDistance(waypoint.x, waypoint.y, waypoint.z));
|
|
if (closestPointDistToBot > distToBot)
|
|
{
|
|
closestPointDistToBot = distToBot;
|
|
closestPointIndex = i;
|
|
}
|
|
}
|
|
|
|
// don't pick path where bot is already closest to the paths closest point to target (it means path cant lead it
|
|
// anywhere) don't pick path where closest point is too far away
|
|
if (closestPointIndex == (reverse ? 0 : path->size() - 1) || closestPointDistToBot > botDistanceLimit)
|
|
continue;
|
|
|
|
// creates a score based on dist-to-bot and dist-to-destination, where lower is better, and dist-to-bot is more
|
|
// important (when its beyond a certain distance) dist-to-bot is more important because otherwise they cant
|
|
// reach it at all (or will fly through air with MM::MovePoint()), also bot may need to use multiple paths (one
|
|
// after another) anyway
|
|
float distToDestination = reverse ? startPointDistToDestination : endPointDistToDestination;
|
|
float pathScore = (closestPointDistToBot < botDistanceScoreSubtract
|
|
? 0.0f
|
|
: ((closestPointDistToBot - botDistanceScoreSubtract) * botDistanceScoreMultiply)) +
|
|
distToDestination;
|
|
|
|
// LOG_INFO("playerbots", "bot={}\t{:6.1f}\t{:4.1f}\t{:4.1f}\t{}", bot->GetName(), pathScore,
|
|
// closestPointDistToBot, distToDestination, vPaths_AB_name[pathNum]);
|
|
|
|
if (chosenPathScore > pathScore)
|
|
{
|
|
chosenPathScore = pathScore;
|
|
chosenPath = path;
|
|
chosenPathPoint = closestPointIndex;
|
|
chosenPathReverse = reverse;
|
|
// chosenPathIndex = index;
|
|
}
|
|
}
|
|
|
|
if (!chosenPath)
|
|
return false;
|
|
|
|
// LOG_INFO("playerbots", "{} bot={} path={}", (bot->GetTeamId() == TEAM_HORDE ? "HORDE" : "ALLIANCE"),
|
|
// bot->GetName(), chosenPathIndex);
|
|
|
|
return moveToObjectiveWp(chosenPath, chosenPathPoint, chosenPathReverse);
|
|
}
|
|
|
|
bool BGTactics::resetObjective()
|
|
{
|
|
Battleground* bg = bot->GetBattleground();
|
|
if (!bg)
|
|
return false;
|
|
|
|
// Adjust role-change chance based on battleground type
|
|
uint32 oddsToChangeRole = 1; // default low
|
|
BattlegroundTypeId bgType = bg->GetBgTypeID();
|
|
|
|
if (bgType == BATTLEGROUND_WS)
|
|
oddsToChangeRole = 2;
|
|
else if (bgType == BATTLEGROUND_EY || bgType == BATTLEGROUND_IC || bgType == BATTLEGROUND_AB)
|
|
oddsToChangeRole = 1;
|
|
else if (bgType == BATTLEGROUND_AV)
|
|
oddsToChangeRole = 0;
|
|
|
|
bool isCarryingFlag =
|
|
bot->HasAura(BG_WS_SPELL_WARSONG_FLAG) ||
|
|
bot->HasAura(BG_WS_SPELL_SILVERWING_FLAG) ||
|
|
bot->HasAura(BG_EY_NETHERSTORM_FLAG_SPELL);
|
|
|
|
// Change role if allowed by odds and not carrying flag
|
|
if (urand(0, 99) < oddsToChangeRole && !isCarryingFlag)
|
|
context->GetValue<uint32>("bg role")->Set(urand(0, 9));
|
|
|
|
// Reset objective position
|
|
PositionMap& posMap = context->GetValue<PositionMap&>("position")->Get();
|
|
PositionInfo pos = context->GetValue<PositionMap&>("position")->Get()["bg objective"];
|
|
pos.Reset();
|
|
posMap["bg objective"] = pos;
|
|
|
|
return selectObjective(true);
|
|
}
|
|
|
|
bool BGTactics::moveToObjectiveWp(BattleBotPath* const& currentPath, uint32 currentPoint, bool reverse)
|
|
{
|
|
if (!currentPath)
|
|
return false;
|
|
|
|
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 || (inCombat && !PlayerHasFlag::IsCapturingFlag(bot)) || !bot->IsAlive())
|
|
{
|
|
// Path is over.
|
|
// std::ostringstream out;
|
|
// out << "Reached path end!";
|
|
// bot->Say(out.str(), LANG_UNIVERSAL);
|
|
resetObjective();
|
|
return false;
|
|
}
|
|
|
|
uint32 currPoint = currentPoint;
|
|
|
|
if (reverse)
|
|
currPoint--;
|
|
else
|
|
currPoint++;
|
|
|
|
uint32 nPoint = reverse ? std::max((int)(currPoint - urand(1, 5)), 0)
|
|
: std::min((uint32)(currPoint + urand(1, 5)), lastPointInPath);
|
|
if (reverse && nPoint < 0)
|
|
nPoint = 0;
|
|
|
|
BattleBotWaypoint& nextPoint = currentPath->at(nPoint);
|
|
|
|
// std::ostringstream out;
|
|
// out << "WP: ";
|
|
// reverse ? out << currPoint << " <<< -> " << nPoint : out << currPoint << ">>> ->" << nPoint;
|
|
// out << ", " << nextPoint.x << ", " << nextPoint.y << " Path Size: " << currentPath->size() << ", Dist: " <<
|
|
// sServerFacade->GetDistance2d(bot, nextPoint.x, nextPoint.y); bot->Say(out.str(), LANG_UNIVERSAL);
|
|
|
|
return MoveTo(bot->GetMapId(), nextPoint.x + frand(-2, 2), nextPoint.y + frand(-2, 2), nextPoint.z);
|
|
}
|
|
|
|
bool BGTactics::startNewPathBegin(std::vector<BattleBotPath*> const& vPaths)
|
|
{
|
|
Battleground* bg = bot->GetBattleground();
|
|
if (!bg)
|
|
return false;
|
|
|
|
BattlegroundTypeId bgType = bg->GetBgTypeID();
|
|
if (bgType == BATTLEGROUND_RB)
|
|
bgType = bg->GetBgTypeID(true);
|
|
|
|
if (bgType == BATTLEGROUND_IC)
|
|
return false;
|
|
|
|
PositionInfo pos = context->GetValue<PositionMap&>("position")->Get()["bg objective"];
|
|
if (!pos.isSet())
|
|
return false;
|
|
|
|
// Important for eye of the storm bg, so that bots stay near bg objective (see selectObjective for more Info)
|
|
if (bot->GetDistance(pos.x, pos.y, pos.z) < 25.0f)
|
|
return false;
|
|
|
|
struct AvailablePath
|
|
{
|
|
AvailablePath(BattleBotPath* pPath_, bool reverse_) : pPath(pPath_), reverse(reverse_) {}
|
|
|
|
BattleBotPath* pPath = nullptr;
|
|
bool reverse = false;
|
|
};
|
|
|
|
std::vector<AvailablePath> availablePaths;
|
|
for (auto const& pPath : vPaths)
|
|
{
|
|
// TODO remove sqrt
|
|
BattleBotWaypoint* pStart = &((*pPath)[0]);
|
|
if (sqrt(bot->GetDistance(pStart->x, pStart->y, pStart->z)) < INTERACTION_DISTANCE)
|
|
availablePaths.emplace_back(AvailablePath(pPath, false));
|
|
|
|
// Some paths are not allowed backwards.
|
|
if (std::find(vPaths_NoReverseAllowed.begin(), vPaths_NoReverseAllowed.end(), pPath) !=
|
|
vPaths_NoReverseAllowed.end())
|
|
continue;
|
|
|
|
// TODO remove sqrt
|
|
BattleBotWaypoint* pEnd = &((*pPath)[(*pPath).size() - 1]);
|
|
if (sqrt(bot->GetDistance(pEnd->x, pEnd->y, pEnd->z)) < INTERACTION_DISTANCE)
|
|
availablePaths.emplace_back(AvailablePath(pPath, true));
|
|
}
|
|
|
|
if (availablePaths.empty())
|
|
return false;
|
|
|
|
uint32 randomPath = urand(0, availablePaths.size() - 1);
|
|
AvailablePath const* chosenPath = &availablePaths[randomPath];
|
|
|
|
BattleBotPath* currentPath = chosenPath->pPath;
|
|
bool reverse = chosenPath->reverse;
|
|
uint32 currentPoint = reverse ? currentPath->size() - 1 : 0;
|
|
|
|
return moveToObjectiveWp(currentPath, currentPoint, reverse);
|
|
}
|
|
|
|
bool BGTactics::startNewPathFree(std::vector<BattleBotPath*> const& vPaths)
|
|
{
|
|
Battleground* bg = bot->GetBattleground();
|
|
if (!bg)
|
|
return false;
|
|
|
|
BattlegroundTypeId bgType = bg->GetBgTypeID();
|
|
if (bgType == BATTLEGROUND_RB)
|
|
bgType = bg->GetBgTypeID(true);
|
|
|
|
if (bgType == BATTLEGROUND_IC)
|
|
return false;
|
|
|
|
PositionInfo pos = context->GetValue<PositionMap&>("position")->Get()["bg objective"];
|
|
if (!pos.isSet())
|
|
return false;
|
|
|
|
// Important for eye of the storm bg, so that bots stay near bg objective (see selectObjective for more Info)
|
|
if (bot->GetDistance(pos.x, pos.y, pos.z) < 25.0f)
|
|
return false;
|
|
|
|
BattleBotPath* pClosestPath = nullptr;
|
|
uint32 closestPoint = 0;
|
|
float closestDistance = FLT_MAX;
|
|
|
|
for (auto const& pPath : vPaths)
|
|
{
|
|
for (uint32 i = 0; i < pPath->size(); i++)
|
|
{
|
|
BattleBotWaypoint& waypoint = ((*pPath)[i]);
|
|
// TODO remove sqrt
|
|
float const distanceToPoint = sqrt(bot->GetDistance(waypoint.x, waypoint.y, waypoint.z));
|
|
if (distanceToPoint < closestDistance)
|
|
{
|
|
pClosestPath = pPath;
|
|
closestPoint = i;
|
|
closestDistance = distanceToPoint;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!pClosestPath)
|
|
return false;
|
|
|
|
BattleBotPath* currentPath = pClosestPath;
|
|
bool reverse = false;
|
|
uint32 currentPoint = closestPoint - 1;
|
|
|
|
return moveToObjectiveWp(currentPath, currentPoint, reverse);
|
|
}
|
|
|
|
/**
|
|
* @brief Handles flag/base capturing gameplay in battlegrounds
|
|
*
|
|
* This function manages the logic for capturing flags and bases in various battlegrounds.
|
|
* It handles:
|
|
* - Enemy detection and combat near objectives
|
|
* - Coordination with friendly players who are capturing
|
|
* - Different capture mechanics for each battleground type
|
|
* - Proper positioning and movement
|
|
*
|
|
* @param vPaths Vector of possible paths the bot can take
|
|
* @param vFlagIds Vector of flag/base GameObjects that can be captured
|
|
* @return true if handling a flag/base action, false otherwise
|
|
*/
|
|
bool BGTactics::atFlag(std::vector<BattleBotPath*> const& vPaths, std::vector<uint32> const& vFlagIds)
|
|
{
|
|
// Basic sanity checks
|
|
Battleground* bg = bot->GetBattleground();
|
|
if (!bg)
|
|
return false;
|
|
|
|
// Get the actual BG type (in case of random BG)
|
|
BattlegroundTypeId bgType = bg->GetBgTypeID();
|
|
if (bgType == BATTLEGROUND_RB)
|
|
bgType = bg->GetBgTypeID(true);
|
|
|
|
// Initialize vectors for nearby objects and players
|
|
GuidVector closeObjects;
|
|
GuidVector closePlayers;
|
|
float flagRange = 0.0f;
|
|
|
|
// Set up appropriate search ranges and object lists based on BG type
|
|
switch (bgType)
|
|
{
|
|
case BATTLEGROUND_AV:
|
|
case BATTLEGROUND_AB:
|
|
case BATTLEGROUND_IC:
|
|
{
|
|
// For territory control BGs, use standard interaction range
|
|
closeObjects = *context->GetValue<GuidVector>("closest game objects");
|
|
closePlayers = *context->GetValue<GuidVector>("closest friendly players");
|
|
flagRange = INTERACTION_DISTANCE;
|
|
break;
|
|
}
|
|
case BATTLEGROUND_WS:
|
|
case BATTLEGROUND_EY:
|
|
{
|
|
// For flag carrying BGs, use wider range and ignore LOS
|
|
closeObjects = *context->GetValue<GuidVector>("nearest game objects no los");
|
|
closePlayers = *context->GetValue<GuidVector>("closest friendly players");
|
|
flagRange = 25.0f;
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (closeObjects.empty())
|
|
return false;
|
|
|
|
// First identify which flag/base we're trying to interact with
|
|
GameObject* targetFlag = nullptr;
|
|
for (ObjectGuid const guid : closeObjects)
|
|
{
|
|
GameObject* go = botAI->GetGameObject(guid);
|
|
if (!go)
|
|
continue;
|
|
|
|
// Check if this object is a valid capture target
|
|
std::vector<uint32>::const_iterator f = find(vFlagIds.begin(), vFlagIds.end(), go->GetEntry());
|
|
if (f == vFlagIds.end())
|
|
continue;
|
|
|
|
// Verify the object is active and ready
|
|
if (!go->isSpawned() || go->GetGoState() != GO_STATE_READY)
|
|
continue;
|
|
|
|
// Check if we're in range (using double range for enemy detection)
|
|
float const dist = bot->GetDistance(go);
|
|
if (flagRange && dist > flagRange * 2.0f)
|
|
continue;
|
|
|
|
targetFlag = go;
|
|
break;
|
|
}
|
|
|
|
// If we found a valid flag/base to interact with
|
|
if (bgType != BATTLEGROUND_WS && bgType != BATTLEGROUND_AV)
|
|
{
|
|
if (targetFlag)
|
|
{
|
|
// Check for enemy players near the flag using bot's targeting system
|
|
Unit* enemyPlayer = AI_VALUE(Unit*, "enemy player target");
|
|
if (enemyPlayer && enemyPlayer->IsAlive())
|
|
{
|
|
// If enemy is near the flag, engage them before attempting capture
|
|
float enemyDist = enemyPlayer->GetDistance(targetFlag);
|
|
if (enemyDist < flagRange * 2.0f)
|
|
{
|
|
// Set enemy as current target and let combat AI handle it
|
|
context->GetValue<Unit*>("current target")->Set(enemyPlayer);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check if friendly players are already capturing
|
|
if (!closePlayers.empty())
|
|
{
|
|
// Track number of friendly players capturing and the closest one
|
|
uint32 numCapturing = 0;
|
|
Unit* capturingPlayer = nullptr;
|
|
for (auto& guid : closePlayers)
|
|
{
|
|
if (Unit* pFriend = botAI->GetUnit(guid))
|
|
{
|
|
// Check if they're casting the capture spell
|
|
if (Spell* spell = pFriend->GetCurrentSpell(CURRENT_GENERIC_SPELL))
|
|
{
|
|
if (spell->m_spellInfo->Id == SPELL_CAPTURE_BANNER)
|
|
{
|
|
numCapturing++;
|
|
capturingPlayer = pFriend;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// If friendlies are capturing, stay to defend but don't capture
|
|
if (numCapturing > 0 && capturingPlayer && bot->GetGUID() != capturingPlayer->GetGUID())
|
|
{
|
|
// Move away if too close to avoid crowding
|
|
if (bot->GetDistance2d(capturingPlayer) < 3.0f)
|
|
{
|
|
float angle = bot->GetAngle(capturingPlayer);
|
|
float x = bot->GetPositionX() + 5.0f * cos(angle);
|
|
float y = bot->GetPositionY() + 5.0f * sin(angle);
|
|
MoveTo(bot->GetMapId(), x, y, bot->GetPositionZ());
|
|
}
|
|
|
|
// Reset objective and take new path for defending
|
|
resetObjective();
|
|
if (!startNewPathBegin(vPaths))
|
|
moveToObjective(true);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Area is clear of enemies and no friendlies are capturing
|
|
// Proceed with capture mechanics
|
|
for (ObjectGuid const guid : closeObjects)
|
|
{
|
|
GameObject* go = botAI->GetGameObject(guid);
|
|
if (!go)
|
|
continue;
|
|
|
|
// Validate this is a capture target
|
|
std::vector<uint32>::const_iterator f = find(vFlagIds.begin(), vFlagIds.end(), go->GetEntry());
|
|
if (f == vFlagIds.end())
|
|
continue;
|
|
|
|
// Check object is active
|
|
if (!go->isSpawned() || go->GetGoState() != GO_STATE_READY)
|
|
continue;
|
|
|
|
// Verify we can interact with it
|
|
if (!bot->CanUseBattlegroundObject(go) && bgType != BATTLEGROUND_WS)
|
|
continue;
|
|
|
|
float const dist = bot->GetDistance(go);
|
|
if (flagRange && dist > flagRange)
|
|
continue;
|
|
|
|
// Special handling for WSG and EY base flags
|
|
bool atBase = bgType == BATTLEGROUND_WS ? go->GetEntry() == vFlagsWS[bot->GetTeamId()]
|
|
: bgType == BATTLEGROUND_EY ? go->GetEntry() == vFlagsEY[0]
|
|
: false;
|
|
|
|
// Don't capture own flag in WSG unless carrying enemy flag
|
|
if (atBase && bgType == BATTLEGROUND_WS &&
|
|
!(bot->HasAura(BG_WS_SPELL_WARSONG_FLAG) || bot->HasAura(BG_WS_SPELL_SILVERWING_FLAG)))
|
|
continue;
|
|
|
|
// Handle capture mechanics based on BG type
|
|
switch (bgType)
|
|
{
|
|
case BATTLEGROUND_AV:
|
|
case BATTLEGROUND_AB:
|
|
case BATTLEGROUND_IC:
|
|
{
|
|
// Prevent capturing from inside flag pole
|
|
if (dist == 0.0f)
|
|
{
|
|
float const moveDist = bot->GetObjectSize() + go->GetObjectSize() + 0.1f;
|
|
return MoveTo(bot->GetMapId(), go->GetPositionX() + (urand(0, 1) ? -moveDist : moveDist),
|
|
go->GetPositionY() + (urand(0, 1) ? -moveDist : moveDist), go->GetPositionZ());
|
|
}
|
|
|
|
// Dismount before capturing
|
|
if (bot->IsMounted())
|
|
bot->RemoveAurasByType(SPELL_AURA_MOUNTED);
|
|
|
|
if (bot->IsInDisallowedMountForm())
|
|
bot->RemoveAurasByType(SPELL_AURA_MOD_SHAPESHIFT);
|
|
|
|
// Cast the capture spell
|
|
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(SPELL_CAPTURE_BANNER);
|
|
if (!spellInfo)
|
|
return false;
|
|
|
|
Spell* spell = new Spell(bot, spellInfo, TRIGGERED_NONE);
|
|
spell->m_targets.SetGOTarget(go);
|
|
spell->prepare(&spell->m_targets);
|
|
|
|
botAI->WaitForSpellCast(spell);
|
|
|
|
resetObjective();
|
|
return true;
|
|
}
|
|
case BATTLEGROUND_WS:
|
|
{
|
|
if (dist < INTERACTION_DISTANCE)
|
|
{
|
|
// Handle flag capture at base
|
|
if (atBase)
|
|
{
|
|
if (bot->GetTeamId() == TEAM_HORDE)
|
|
{
|
|
WorldPacket data(CMSG_AREATRIGGER);
|
|
data << uint32(BG_WS_TRIGGER_HORDE_FLAG_SPAWN);
|
|
bot->GetSession()->HandleAreaTriggerOpcode(data);
|
|
}
|
|
else
|
|
{
|
|
WorldPacket data(CMSG_AREATRIGGER);
|
|
data << uint32(BG_WS_TRIGGER_ALLIANCE_FLAG_SPAWN);
|
|
bot->GetSession()->HandleAreaTriggerOpcode(data);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Dismount before picking up flag
|
|
if (bot->IsMounted())
|
|
bot->RemoveAurasByType(SPELL_AURA_MOUNTED);
|
|
|
|
if (bot->IsInDisallowedMountForm())
|
|
bot->RemoveAurasByType(SPELL_AURA_MOD_SHAPESHIFT);
|
|
|
|
// Pick up the flag
|
|
WorldPacket data(CMSG_GAMEOBJ_USE);
|
|
data << go->GetGUID();
|
|
bot->GetSession()->HandleGameObjectUseOpcode(data);
|
|
|
|
resetObjective();
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
// Move to flag if not in range
|
|
return MoveTo(bot->GetMapId(), go->GetPositionX(), go->GetPositionY(), go->GetPositionZ());
|
|
}
|
|
}
|
|
case BATTLEGROUND_EY:
|
|
{ // Issue: Currently bots in EY take flag instantly without casttime
|
|
if (dist < INTERACTION_DISTANCE)
|
|
{
|
|
// Dismount before interacting
|
|
if (bot->IsMounted())
|
|
bot->RemoveAurasByType(SPELL_AURA_MOUNTED);
|
|
|
|
if (bot->IsInDisallowedMountForm())
|
|
bot->RemoveAurasByType(SPELL_AURA_MOD_SHAPESHIFT);
|
|
|
|
// Handle center flag differently (requires spell cast)
|
|
if (atBase)
|
|
{
|
|
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(SPELL_CAPTURE_BANNER);
|
|
if (!spellInfo)
|
|
return false;
|
|
|
|
Spell* spell = new Spell(bot, spellInfo, TRIGGERED_NONE);
|
|
spell->m_targets.SetGOTarget(go);
|
|
spell->prepare(&spell->m_targets);
|
|
botAI->WaitForSpellCast(spell);
|
|
//return true; Intended to make a bot cast SPELL_CAPTURE_BANNER and wait for spell finish, but doesn't work and causes infinite loop
|
|
}
|
|
|
|
// Pick up dropped flag
|
|
WorldPacket data(CMSG_GAMEOBJ_USE);
|
|
data << go->GetGUID();
|
|
bot->GetSession()->HandleGameObjectUseOpcode(data);
|
|
|
|
resetObjective();
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
// Move to flag if not in range
|
|
return MoveTo(bot->GetMapId(), go->GetPositionX(), go->GetPositionY(), go->GetPositionZ());
|
|
}
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool BGTactics::flagTaken()
|
|
{
|
|
BattlegroundWS* bg = (BattlegroundWS*)bot->GetBattleground();
|
|
if (!bg)
|
|
return false;
|
|
|
|
return !bg->GetFlagPickerGUID(bg->GetOtherTeamId(bot->GetTeamId())).IsEmpty();
|
|
}
|
|
|
|
bool BGTactics::teamFlagTaken()
|
|
{
|
|
BattlegroundWS* bg = (BattlegroundWS*)bot->GetBattleground();
|
|
if (!bg)
|
|
return false;
|
|
|
|
return !bg->GetFlagPickerGUID(bot->GetTeamId()).IsEmpty();
|
|
}
|
|
|
|
bool BGTactics::protectFC()
|
|
{
|
|
Battleground* bg = bot->GetBattleground();
|
|
if (!bg)
|
|
return false;
|
|
|
|
Unit* teamFC = AI_VALUE(Unit*, "team flag carrier");
|
|
|
|
if (!teamFC || teamFC == bot)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!bot->IsInCombat() && !bot->IsWithinDistInMap(teamFC, 20.0f))
|
|
{
|
|
// Get the flag carrier's position
|
|
float fcX = teamFC->GetPositionX();
|
|
float fcY = teamFC->GetPositionY();
|
|
float fcZ = teamFC->GetPositionZ();
|
|
uint32 mapId = bot->GetMapId();
|
|
|
|
return MoveNear(mapId, fcX, fcY, fcZ, 5.0f, MovementPriority::MOVEMENT_NORMAL);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool BGTactics::useBuff()
|
|
{
|
|
Battleground* bg = bot->GetBattleground();
|
|
if (!bg)
|
|
return false;
|
|
|
|
BattlegroundTypeId bgType = bg->GetBgTypeID();
|
|
if (bgType == BATTLEGROUND_RB)
|
|
bgType = bg->GetBgTypeID(true);
|
|
|
|
GuidVector closeObjects = AI_VALUE(GuidVector, "nearest game objects no los");
|
|
if (closeObjects.empty())
|
|
return false;
|
|
|
|
bool needRegen = bot->GetHealthPct() < sPlayerbotAIConfig->mediumHealth ||
|
|
(AI_VALUE2(bool, "has mana", "self target") &&
|
|
AI_VALUE2(uint8, "mana", "self target") < sPlayerbotAIConfig->mediumMana);
|
|
bool needSpeed = (bgType != BATTLEGROUND_WS || bot->HasAura(BG_WS_SPELL_WARSONG_FLAG) ||
|
|
bot->HasAura(BG_WS_SPELL_SILVERWING_FLAG) || bot->HasAura(BG_EY_NETHERSTORM_FLAG_SPELL)) ||
|
|
!(teamFlagTaken() || flagTaken());
|
|
bool foundBuff = false;
|
|
|
|
for (ObjectGuid const guid : closeObjects)
|
|
{
|
|
GameObject* go = botAI->GetGameObject(guid);
|
|
if (!go)
|
|
continue;
|
|
|
|
if (!go->isSpawned())
|
|
continue;
|
|
|
|
// use speed buff only if close
|
|
if (sServerFacade->IsDistanceGreaterThan(sServerFacade->GetDistance2d(bot, go),
|
|
go->GetEntry() == Buff_Entries[0] ? 20.0f : 50.0f))
|
|
continue;
|
|
|
|
if (needSpeed && go->GetEntry() == Buff_Entries[0])
|
|
foundBuff = true;
|
|
|
|
if (needRegen && go->GetEntry() == Buff_Entries[1])
|
|
foundBuff = true;
|
|
|
|
// do not move to Berserk buff if bot is healer or has flag
|
|
if (!(bot->HasAura(BG_WS_SPELL_WARSONG_FLAG) || bot->HasAura(BG_WS_SPELL_SILVERWING_FLAG) ||
|
|
bot->HasAura(BG_EY_NETHERSTORM_FLAG_SPELL)) &&
|
|
!botAI->IsHeal(bot) && go->GetEntry() == Buff_Entries[2])
|
|
foundBuff = true;
|
|
|
|
if (foundBuff)
|
|
{
|
|
// std::ostringstream out;
|
|
// out << "Moving to buff...";
|
|
// bot->Say(out.str(), LANG_UNIVERSAL);
|
|
return MoveTo(go->GetMapId(), go->GetPositionX(), go->GetPositionY(), go->GetPositionZ());
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
uint32 BGTactics::getPlayersInArea(TeamId teamId, Position point, float range, bool combat)
|
|
{
|
|
uint32 defCount = 0;
|
|
|
|
if (!bot->InBattleground())
|
|
return false;
|
|
|
|
Battleground* bg = bot->GetBattleground();
|
|
if (!bg)
|
|
return 0;
|
|
|
|
for (auto& guid : bg->GetBgMap()->GetPlayers())
|
|
{
|
|
Player* player = guid.GetSource();
|
|
if (!player)
|
|
continue;
|
|
|
|
if (player->IsAlive() && (teamId == TEAM_NEUTRAL || teamId == player->GetTeamId()))
|
|
{
|
|
if (!combat && player->IsInCombat())
|
|
continue;
|
|
|
|
if (sServerFacade->GetDistance2d(player, point.GetPositionX(), point.GetPositionY()) < range)
|
|
++defCount;
|
|
}
|
|
}
|
|
|
|
return defCount;
|
|
}
|
|
|
|
// check Isle of Conquest Keep position
|
|
bool BGTactics::IsLockedInsideKeep()
|
|
{
|
|
Battleground* bg = bot->GetBattleground();
|
|
if (!bg)
|
|
return false;
|
|
|
|
BattlegroundTypeId bgType = bg->GetBgTypeID();
|
|
if (bgType == BATTLEGROUND_RB)
|
|
bgType = bg->GetBgTypeID(true);
|
|
|
|
if (bgType != BATTLEGROUND_IC)
|
|
return false;
|
|
|
|
bool isInside = false;
|
|
if (bot->GetTeamId() == TEAM_ALLIANCE && bot->GetPositionX() < 410.0f && bot->GetPositionY() > -900.0f &&
|
|
bot->GetPositionY() < -765.0f)
|
|
isInside = true;
|
|
if (bot->GetTeamId() == TEAM_HORDE && bot->GetPositionX() > 1153.0f && bot->GetPositionY() > -849.0f &&
|
|
bot->GetPositionY() < -679.0f)
|
|
isInside = true;
|
|
|
|
if (!isInside)
|
|
return false;
|
|
|
|
GuidVector closeObjects;
|
|
closeObjects = *context->GetValue<GuidVector>("nearest game objects no los");
|
|
if (closeObjects.empty())
|
|
return moveToStart(true);
|
|
|
|
GameObject* closestPortal = nullptr;
|
|
float closestDistance = 100.0f;
|
|
bool gateLock = false;
|
|
|
|
// check inner gates status
|
|
// ALLIANCE
|
|
if (bot->GetTeamId() == TEAM_ALLIANCE)
|
|
{
|
|
if (GameObject* go = bg->GetBGObject(BG_IC_GO_DOODAD_PORTCULLISACTIVE02))
|
|
{
|
|
if (go->isSpawned())
|
|
{
|
|
gateLock = go->getLootState() != GO_ACTIVATED;
|
|
}
|
|
else
|
|
{
|
|
gateLock = false;
|
|
}
|
|
}
|
|
}
|
|
// HORDE
|
|
if (bot->GetTeamId() == TEAM_HORDE)
|
|
{
|
|
if (GameObject* go = bg->GetBGObject(BG_IC_GO_HORDE_KEEP_PORTCULLIS))
|
|
{
|
|
if (go->isSpawned())
|
|
{
|
|
gateLock = go->getLootState() != GO_ACTIVATED;
|
|
}
|
|
else
|
|
{
|
|
gateLock = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (ObjectGuid const& guid : closeObjects)
|
|
{
|
|
GameObject* go = botAI->GetGameObject(guid);
|
|
if (!go)
|
|
continue;
|
|
|
|
// ALLIANCE
|
|
// get closest portal
|
|
if (bot->GetTeamId() == TEAM_ALLIANCE && go->GetEntry() == GO_TELEPORTER_4)
|
|
{
|
|
float tempDist = sServerFacade->GetDistance2d(bot, go->GetPositionX(), go->GetPositionY());
|
|
|
|
if (sServerFacade->IsDistanceLessThan(tempDist, closestDistance))
|
|
{
|
|
closestDistance = tempDist;
|
|
closestPortal = go;
|
|
}
|
|
}
|
|
|
|
// HORDE
|
|
// get closest portal
|
|
if (bot->GetTeamId() == TEAM_HORDE && go->GetEntry() == GO_TELEPORTER_2)
|
|
{
|
|
float tempDist = sServerFacade->GetDistance2d(bot, go->GetPositionX(), go->GetPositionY());
|
|
|
|
if (sServerFacade->IsDistanceLessThan(tempDist, closestDistance))
|
|
{
|
|
closestDistance = tempDist;
|
|
closestPortal = go;
|
|
}
|
|
}
|
|
}
|
|
|
|
// portal not found, move closer
|
|
if (gateLock && !closestPortal)
|
|
return moveToStart(true);
|
|
|
|
// portal not found, move closer
|
|
if (!gateLock && !closestPortal)
|
|
return moveToStart(true);
|
|
|
|
// nothing found, allow move through
|
|
if (!gateLock || !closestPortal)
|
|
return false;
|
|
|
|
// portal found
|
|
if (closestPortal)
|
|
{
|
|
// if close
|
|
if (bot->IsWithinDistInMap(closestPortal, INTERACTION_DISTANCE))
|
|
{
|
|
WorldPacket data(CMSG_GAMEOBJ_USE);
|
|
data << closestPortal->GetGUID();
|
|
bot->GetSession()->HandleGameObjectUseOpcode(data);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return MoveTo(bot->GetMapId(), closestPortal->GetPositionX(), closestPortal->GetPositionY(),
|
|
closestPortal->GetPositionZ());
|
|
}
|
|
}
|
|
|
|
return moveToStart(true);
|
|
|
|
return false;
|
|
}
|
|
|
|
bool ArenaTactics::Execute(Event event)
|
|
{
|
|
if (!bot->InBattleground())
|
|
{
|
|
bool IsRandomBot = sRandomPlayerbotMgr->IsRandomBot(bot->GetGUID().GetCounter());
|
|
botAI->ChangeStrategy("-arena", BOT_STATE_COMBAT);
|
|
botAI->ChangeStrategy("-arena", BOT_STATE_NON_COMBAT);
|
|
botAI->ResetStrategies(!IsRandomBot);
|
|
return false;
|
|
}
|
|
|
|
Battleground* bg = bot->GetBattleground();
|
|
if (!bg)
|
|
return false;
|
|
|
|
if (bg->GetStatus() == STATUS_WAIT_LEAVE)
|
|
return BGStatusAction::LeaveBG(botAI);
|
|
|
|
if (bg->GetStatus() != STATUS_IN_PROGRESS)
|
|
return false;
|
|
|
|
if (bot->isDead())
|
|
return false;
|
|
|
|
if (bot->isMoving())
|
|
return false;
|
|
|
|
// startup phase
|
|
if (bg->GetStartDelayTime() > 0)
|
|
return false;
|
|
|
|
if (botAI->HasStrategy("collision", BOT_STATE_NON_COMBAT))
|
|
botAI->ChangeStrategy("-collision", BOT_STATE_NON_COMBAT);
|
|
|
|
if (botAI->HasStrategy("buff", BOT_STATE_NON_COMBAT))
|
|
botAI->ChangeStrategy("-buff", BOT_STATE_NON_COMBAT);
|
|
|
|
// Repositioning if the target is out of line of sight
|
|
Unit* target = bot->GetVictim();
|
|
if (target && (!bot->IsWithinLOSInMap(target) || fabs(bot->GetPositionZ() - target->GetPositionZ()) > 5.0f))
|
|
{
|
|
PathFinder path(bot);
|
|
path.CalculatePath(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), false);
|
|
|
|
if (path.IsValid() && path.GetPathType() != PATHFIND_NOPATH)
|
|
{
|
|
float x, y, z;
|
|
target->GetPosition(x, y, z);
|
|
botAI->TellMasterNoFacing("Repositioning to exit LoS or Height");
|
|
return MoveTo(target->GetMapId(), x + frand(-1, +1), y + frand(-1, +1), z, false, true);
|
|
}
|
|
}
|
|
|
|
if (!bot->IsInCombat())
|
|
return moveToCenter(bg);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ArenaTactics::moveToCenter(Battleground* bg)
|
|
{
|
|
// Sanity check
|
|
if (!bg)
|
|
{
|
|
return true;
|
|
}
|
|
uint32 Preference = 6;
|
|
|
|
switch (bot->getClass())
|
|
{
|
|
case CLASS_PRIEST:
|
|
case CLASS_SHAMAN:
|
|
case CLASS_DRUID:
|
|
Preference = 3;
|
|
break;
|
|
case CLASS_WARRIOR:
|
|
case CLASS_PALADIN:
|
|
case CLASS_ROGUE:
|
|
case CLASS_DEATH_KNIGHT:
|
|
Preference = 6;
|
|
break;
|
|
case CLASS_HUNTER:
|
|
case CLASS_MAGE:
|
|
case CLASS_WARLOCK:
|
|
Preference = 9;
|
|
break;
|
|
}
|
|
|
|
switch (bg->GetBgTypeID())
|
|
{
|
|
case BATTLEGROUND_BE:
|
|
if (bg->GetTeamStartPosition(bot->GetBgTeamId())->GetPositionY() < 240)
|
|
{
|
|
if (Preference == 3)
|
|
MoveTo(bg->GetMapId(), 6226.65f + frand(-1, +1), 264.36f + frand(-1, +1), 1.31f, false, true);
|
|
else if (Preference == 6)
|
|
MoveTo(bg->GetMapId(), 6239.89f + frand(-1, +1), 261.11f + frand(-1, +1), 0.89f, false, true);
|
|
else
|
|
MoveTo(bg->GetMapId(), 6235.60f + frand(-1, +1), 258.27f + frand(-1, +1), 0.89f, false, true);
|
|
}
|
|
else
|
|
{
|
|
if (Preference == 3)
|
|
MoveTo(bg->GetMapId(), 6265.72f + frand(-1, +1), 271.92f + frand(-1, +1), 3.65f, false, true);
|
|
else if (Preference == 6)
|
|
MoveTo(bg->GetMapId(), 6239.89f + frand(-1, +1), 261.11f + frand(-1, +1), 0.89f, false, true);
|
|
else
|
|
MoveTo(bg->GetMapId(), 6250.50f + frand(-1, +1), 266.66f + frand(-1, +1), 2.63f, false, true);
|
|
}
|
|
break;
|
|
case BATTLEGROUND_RL:
|
|
if (bg->GetTeamStartPosition(bot->GetBgTeamId())->GetPositionY() < 1600)
|
|
{
|
|
if (Preference == 3)
|
|
MoveTo(bg->GetMapId(), 1262.14f + frand(-1, +1), 1657.63f + frand(-1, +1), 33.76f, false, true);
|
|
else if (Preference == 6)
|
|
MoveTo(bg->GetMapId(), 1266.85f + frand(-1, +1), 1663.52f + frand(-1, +1), 34.04f, false, true);
|
|
else
|
|
MoveTo(bg->GetMapId(), 1274.07f + frand(-1, +1), 1656.36f + frand(-1, +1), 34.58f, false, true);
|
|
}
|
|
else
|
|
{
|
|
if (Preference == 3)
|
|
MoveTo(bg->GetMapId(), 1261.93f + frand(-1, +1), 1669.27f + frand(-1, +1), 34.25f, false, true);
|
|
else if (Preference == 6)
|
|
MoveTo(bg->GetMapId(), 1266.85f + frand(-1, +1), 1663.52f + frand(-1, +1), 34.04f, false, true);
|
|
else
|
|
MoveTo(bg->GetMapId(), 1266.37f + frand(-1, +1), 1672.40f + frand(-1, +1), 34.21f, false, true);
|
|
}
|
|
break;
|
|
case BATTLEGROUND_NA:
|
|
if (bg->GetTeamStartPosition(bot->GetBgTeamId())->GetPositionY() < 2870)
|
|
{
|
|
if (Preference == 3)
|
|
MoveTo(bg->GetMapId(), 4068.85f + frand(-1, +1), 2911.98f + frand(-1, +1), 12.99f, false, true);
|
|
else if (Preference == 6)
|
|
MoveTo(bg->GetMapId(), 4056.99f + frand(-1, +1), 2919.75f + frand(-1, +1), 13.51f, false, true);
|
|
else
|
|
MoveTo(bg->GetMapId(), 4056.27f + frand(-1, +1), 2905.33f + frand(-1, +1), 12.90f, false, true);
|
|
}
|
|
else
|
|
{
|
|
if (Preference == 3)
|
|
MoveTo(bg->GetMapId(), 4043.66f + frand(-1, +1), 2927.93f + frand(-1, +1), 13.17f, false, true);
|
|
else if (Preference == 6)
|
|
MoveTo(bg->GetMapId(), 4056.99f + frand(-1, +1), 2919.75f + frand(-1, +1), 13.51f, false, true);
|
|
else
|
|
MoveTo(bg->GetMapId(), 4054.80f + frand(-1, +1), 2934.28f + frand(-1, +1), 13.72f, false, true);
|
|
}
|
|
break;
|
|
case BATTLEGROUND_DS:
|
|
if (!MoveTo(bg->GetMapId(), 1291.58f + frand(-5, +5), 790.87f + frand(-5, +5), 7.8f, false, true))
|
|
{
|
|
// they like to hang around at the tip of the pipes doing nothing, so we just teleport them down
|
|
if (bot->GetDistance(1333.07f, 817.18f, 13.35f) < 4)
|
|
bot->TeleportTo(bg->GetMapId(), 1330.96f, 816.75f, 3.2f, bot->GetOrientation());
|
|
if (bot->GetDistance(1250.13f, 764.79f, 13.34f) < 4)
|
|
bot->TeleportTo(bg->GetMapId(), 1252.19f, 765.41f, 3.2f, bot->GetOrientation());
|
|
}
|
|
break;
|
|
case BATTLEGROUND_RV:
|
|
MoveTo(bg->GetMapId(), 764.65f + frand(-2, +2), -283.85f + frand(-2, +2), 28.28f, false, true);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|