Merge branch 'master' into configured65-mod-playerbots-pr-branch

This commit is contained in:
conFIGured
2024-07-12 08:08:55 -04:00
committed by GitHub
8 changed files with 204 additions and 165 deletions

View File

@@ -341,6 +341,13 @@ AiPlayerbot.GlobalCooldown = 500
# Max wait time when moving # Max wait time when moving
AiPlayerbot.MaxWaitForMove = 5000 AiPlayerbot.MaxWaitForMove = 5000
# Disables use of MoveSplinePath for bot movement, will result in more erratic bot movement but means stun/snare/root/etc
# will work on bots (they wont reliably work when MoveSplinePath is enabled, though slowing effects still work ok)
# Default: 0 - MoveSplinePath enabled
# 1 - MoveSplinePath disabled in BG/Arena only
# 2 - MoveSplinePath disabled everywhere
AiPlayerbot.DisableMoveSplinePath = 0
# Max search time for movement (higher for better movement on slopes) # Max search time for movement (higher for better movement on slopes)
# default: 3 # default: 3
AiPlayerbot.MaxMovementSearchTime = 3 AiPlayerbot.MaxMovementSearchTime = 3

View File

@@ -53,6 +53,7 @@ bool PlayerbotAIConfig::Initialize()
globalCoolDown = sConfigMgr->GetOption<int32>("AiPlayerbot.GlobalCooldown", 1500); globalCoolDown = sConfigMgr->GetOption<int32>("AiPlayerbot.GlobalCooldown", 1500);
maxWaitForMove = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxWaitForMove", 5000); maxWaitForMove = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxWaitForMove", 5000);
disableMoveSplinePath = sConfigMgr->GetOption<int32>("AiPlayerbot.DisableMoveSplinePath", 0);
maxMovementSearchTime = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxMovementSearchTime", 3); maxMovementSearchTime = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxMovementSearchTime", 3);
expireActionTime = sConfigMgr->GetOption<int32>("AiPlayerbot.ExpireActionTime", 5000); expireActionTime = sConfigMgr->GetOption<int32>("AiPlayerbot.ExpireActionTime", 5000);
dispelAuraDuration = sConfigMgr->GetOption<int32>("AiPlayerbot.DispelAuraDuration", 7000); dispelAuraDuration = sConfigMgr->GetOption<int32>("AiPlayerbot.DispelAuraDuration", 7000);
@@ -272,6 +273,9 @@ bool PlayerbotAIConfig::Initialize()
equipmentPersistence = sConfigMgr->GetOption<bool>("AiPlayerbot.EquipmentPersistence", false); equipmentPersistence = sConfigMgr->GetOption<bool>("AiPlayerbot.EquipmentPersistence", false);
equipmentPersistenceLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.EquipmentPersistenceLevel", 80); equipmentPersistenceLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.EquipmentPersistenceLevel", 80);
groupInvitationPermission = sConfigMgr->GetOption<int32>("AiPlayerbot.GroupInvitationPermission", 1); groupInvitationPermission = sConfigMgr->GetOption<int32>("AiPlayerbot.GroupInvitationPermission", 1);
allowSummonInCombat = sConfigMgr->GetOption<bool>("AiPlayerbot.AllowSummonInCombat", true);
allowSummonWhenMasterIsDead = sConfigMgr->GetOption<bool>("AiPlayerbot.AllowSummonWhenMasterIsDead", true);
allowSummonWhenBotIsDead = sConfigMgr->GetOption<bool>("AiPlayerbot.AllowSummonWhenBotIsDead", true);
botReviveWhenSummon = sConfigMgr->GetOption<int>("AiPlayerbot.BotReviveWhenSummon", 1); botReviveWhenSummon = sConfigMgr->GetOption<int>("AiPlayerbot.BotReviveWhenSummon", 1);
botRepairWhenSummon = sConfigMgr->GetOption<bool>("AiPlayerbot.BotRepairWhenSummon", true); botRepairWhenSummon = sConfigMgr->GetOption<bool>("AiPlayerbot.BotRepairWhenSummon", true);
autoInitOnly = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoInitOnly", false); autoInitOnly = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoInitOnly", false);

View File

@@ -54,8 +54,8 @@ class PlayerbotAIConfig
bool enabled; bool enabled;
bool allowGuildBots, allowPlayerBots; bool allowGuildBots, allowPlayerBots;
uint32 globalCoolDown, reactDelay, maxWaitForMove, maxMovementSearchTime, expireActionTime, uint32 globalCoolDown, reactDelay, maxWaitForMove, disableMoveSplinePath, maxMovementSearchTime,
dispelAuraDuration, passiveDelay, repeatDelay, expireActionTime, dispelAuraDuration, passiveDelay, repeatDelay,
errorDelay, rpgDelay, sitDelay, returnDelay, lootDelay; errorDelay, rpgDelay, sitDelay, returnDelay, lootDelay;
float sightDistance, spellDistance, reactDistance, grindDistance, lootDistance, shootDistance, float sightDistance, spellDistance, reactDistance, grindDistance, lootDistance, shootDistance,
fleeDistance, tooCloseDistance, meleeDistance, followDistance, whisperDistance, contactDistance, fleeDistance, tooCloseDistance, meleeDistance, followDistance, whisperDistance, contactDistance,
@@ -214,6 +214,9 @@ class PlayerbotAIConfig
bool equipmentPersistence; bool equipmentPersistence;
int32 equipmentPersistenceLevel; int32 equipmentPersistenceLevel;
int32 groupInvitationPermission; int32 groupInvitationPermission;
bool allowSummonInCombat;
bool allowSummonWhenMasterIsDead;
bool allowSummonWhenBotIsDead;
int32 botReviveWhenSummon; int32 botReviveWhenSummon;
bool botRepairWhenSummon; bool botRepairWhenSummon;
bool autoInitOnly; bool autoInitOnly;

View File

@@ -55,9 +55,9 @@ RandomPlayerbotFactory::RandomPlayerbotFactory(uint32 accountId) : accountId(acc
availableRaces[CLASS_PRIEST].push_back(RACE_NIGHTELF); availableRaces[CLASS_PRIEST].push_back(RACE_NIGHTELF);
availableRaces[CLASS_PRIEST].push_back(RACE_TROLL); availableRaces[CLASS_PRIEST].push_back(RACE_TROLL);
availableRaces[CLASS_PRIEST].push_back(RACE_UNDEAD_PLAYER); availableRaces[CLASS_PRIEST].push_back(RACE_UNDEAD_PLAYER);
availableRaces[CLASS_PRIEST].push_back(RACE_DRAENEI);
if(expansion >= EXPANSION_THE_BURNING_CRUSADE) if(expansion >= EXPANSION_THE_BURNING_CRUSADE)
{ {
availableRaces[CLASS_PRIEST].push_back(RACE_DRAENEI);
availableRaces[CLASS_PRIEST].push_back(RACE_BLOODELF); availableRaces[CLASS_PRIEST].push_back(RACE_BLOODELF);
} }

View File

@@ -40,12 +40,16 @@ Position const WS_FLAG_HIDE_ALLIANCE_2 = { 1540.286f, 1476.026f, 352.692f, 2.91f
Position const WS_FLAG_HIDE_ALLIANCE_3 = { 1495.807f, 1466.774f, 352.350f, 1.50f }; Position const WS_FLAG_HIDE_ALLIANCE_3 = { 1495.807f, 1466.774f, 352.350f, 1.50f };
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_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 }; 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_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_WAITING_POS_ALLIANCE = { 1286.054f, 1282.500f, -15.697f, 3.95f };
Position const AV_WAITING_POS_ALLIANCE = { 793.627f, -493.814f, 99.689f, 3.09f }; Position const AV_WAITING_POS_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_WAITING_POS_HORDE = { -1381.865f, -544.872f, 54.773f, 0.76f };
Position const AV_ICEBLOOD_GARRISON_WAITING_ALLIANCE = { -492.17f, -187.077f, 57.1342f, 2.77f }; Position const AV_ICEBLOOD_GARRISON_WAITING_ALLIANCE = { -523.105f, -182.178f, 57.956f, 2.77f };
Position const AV_STONEHEARTH_WAITING_HORDE = { 28.1264f, -302.593f, 15.076f, 2.96f }; Position const AV_ICEBLOOD_GARRISON_ATTACKING_ALLIANCE = { -545.288f, -167.932f, 57.012f, 2.77f };
Position const AV_STONEHEARTH_WAITING_HORDE = { -36.399f, -306.403f, 15.565f, 2.96f };
Position const AV_STONEHEARTH_ATTACKING_HORDE = { -55.210f, -288.546f, 15.578f, 2.96f };
Position const EY_WAITING_POS_HORDE = { 1809.102f, 1540.854f, 1267.142f, 6.18f }; Position const EY_WAITING_POS_HORDE = { 1809.102f, 1540.854f, 1267.142f, 6.18f };
Position const EY_WAITING_POS_ALLIANCE = { 2526.020f, 1596.787f, 1270.127f, 3.14f }; Position const EY_WAITING_POS_ALLIANCE = { 2526.020f, 1596.787f, 1270.127f, 3.14f };
@@ -799,7 +803,16 @@ BattleBotPath vPath_AB_Farm_to_LumberMill =
BattleBotPath vPath_AV_Horde_Cave_to_Tower_Point_Crossroad = BattleBotPath vPath_AV_Horde_Cave_to_Tower_Point_Crossroad =
{ {
{ -885.928f, -536.612f, 55.1936f, nullptr }, { -1362.395f, -529.615f, 52.636f, nullptr },
{ -1327.036f, -511.374f, 51.138f, nullptr },
{ -1277.047f, -516.327f, 50.667f, nullptr },
{ -1214.901f, -529.350f, 52.251f, nullptr },
{ -1151.129f, -545.598f, 51.990f, nullptr },
{ -1085.775f, -538.719f, 47.905f, nullptr },
{ -1038.552f, -517.946f, 43.876f, nullptr },
{ -981.371f, -494.593f, 41.127f, nullptr },
{ -930.598f, -463.751f, 43.060f, nullptr },
{ -887.138f, -475.816f, 44.374f, nullptr },
{ -880.957f, -525.119f, 53.6791f, nullptr }, { -880.957f, -525.119f, 53.6791f, nullptr },
{ -839.408f, -499.746f, 49.7505f, nullptr }, { -839.408f, -499.746f, 49.7505f, nullptr },
{ -820.21f, -469.193f, 49.4085f, nullptr }, { -820.21f, -469.193f, 49.4085f, nullptr },
@@ -2262,48 +2275,48 @@ std::vector<BattleBotPath*> const vPaths_HordeMine =
&vPath_AV_Coldtooth_Mine_Entrance_to_Coldtooth_Mine_Boss, &vPath_AV_Coldtooth_Mine_Entrance_to_Coldtooth_Mine_Boss,
}; };
static uint32 AV_HordeAttackObjectives[] = static std::pair<uint32, uint32> AV_HordeAttackObjectives[] =
{ {
// Attack // Attack
{ BG_AV_NODES_STONEHEART_BUNKER }, { BG_AV_NODES_STONEHEART_BUNKER, BG_AV_OBJECT_FLAG_A_STONEHEART_BUNKER },
{ BG_AV_NODES_STONEHEART_GRAVE }, { BG_AV_NODES_STONEHEART_GRAVE, BG_AV_OBJECT_FLAG_A_STONEHEART_GRAVE },
{ BG_AV_NODES_ICEWING_BUNKER }, { BG_AV_NODES_ICEWING_BUNKER, BG_AV_OBJECT_FLAG_A_ICEWING_BUNKER },
{ BG_AV_NODES_STORMPIKE_GRAVE }, { BG_AV_NODES_STORMPIKE_GRAVE, BG_AV_OBJECT_FLAG_A_STORMPIKE_GRAVE },
{ BG_AV_NODES_DUNBALDAR_SOUTH }, { BG_AV_NODES_DUNBALDAR_SOUTH, BG_AV_OBJECT_FLAG_A_DUNBALDAR_SOUTH },
{ BG_AV_NODES_DUNBALDAR_NORTH }, { BG_AV_NODES_DUNBALDAR_NORTH, BG_AV_OBJECT_FLAG_A_DUNBALDAR_NORTH },
{ BG_AV_NODES_FIRSTAID_STATION } { BG_AV_NODES_FIRSTAID_STATION, BG_AV_OBJECT_FLAG_A_FIRSTAID_STATION }
}; };
static uint32 AV_HordeDefendObjectives[] = static std::pair<uint32, uint32> AV_HordeDefendObjectives[] =
{ {
// Defend // Defend
{ BG_AV_NODES_FROSTWOLF_GRAVE }, { BG_AV_NODES_FROSTWOLF_GRAVE, BG_AV_OBJECT_FLAG_H_FROSTWOLF_GRAVE },
{ BG_AV_NODES_FROSTWOLF_ETOWER }, { BG_AV_NODES_FROSTWOLF_ETOWER, BG_AV_OBJECT_FLAG_H_FROSTWOLF_ETOWER },
{ BG_AV_NODES_FROSTWOLF_WTOWER }, { BG_AV_NODES_FROSTWOLF_WTOWER, BG_AV_OBJECT_FLAG_H_FROSTWOLF_WTOWER },
{ BG_AV_NODES_TOWER_POINT }, { BG_AV_NODES_TOWER_POINT, BG_AV_OBJECT_FLAG_H_TOWER_POINT },
{ BG_AV_NODES_ICEBLOOD_TOWER }, { BG_AV_NODES_ICEBLOOD_TOWER, BG_AV_OBJECT_FLAG_H_ICEBLOOD_TOWER },
}; };
static uint32 AV_AllianceAttackObjectives[] = static std::pair<uint32, uint32> AV_AllianceAttackObjectives[] =
{ {
// Attack // Attack
{ BG_AV_NODES_ICEBLOOD_TOWER }, { BG_AV_NODES_ICEBLOOD_TOWER, BG_AV_OBJECT_FLAG_H_ICEBLOOD_TOWER},
{ BG_AV_NODES_ICEBLOOD_GRAVE }, { BG_AV_NODES_ICEBLOOD_GRAVE, BG_AV_OBJECT_FLAG_H_ICEBLOOD_GRAVE},
{ BG_AV_NODES_TOWER_POINT }, { BG_AV_NODES_TOWER_POINT, BG_AV_OBJECT_FLAG_H_TOWER_POINT },
{ BG_AV_NODES_FROSTWOLF_GRAVE }, { BG_AV_NODES_FROSTWOLF_GRAVE, BG_AV_OBJECT_FLAG_H_FROSTWOLF_GRAVE },
{ BG_AV_NODES_FROSTWOLF_ETOWER }, { BG_AV_NODES_FROSTWOLF_ETOWER, BG_AV_OBJECT_FLAG_H_FROSTWOLF_ETOWER },
{ BG_AV_NODES_FROSTWOLF_WTOWER }, { BG_AV_NODES_FROSTWOLF_WTOWER, BG_AV_OBJECT_FLAG_H_FROSTWOLF_WTOWER },
{ BG_AV_NODES_FROSTWOLF_HUT }, { BG_AV_NODES_FROSTWOLF_HUT, BG_AV_OBJECT_FLAG_H_FROSTWOLF_HUT },
}; };
static uint32 AV_AllianceDefendObjectives[] = static std::pair<uint32, uint32> AV_AllianceDefendObjectives[] =
{ {
// Defend // Defend
{ BG_AV_NODES_STORMPIKE_GRAVE }, { BG_AV_NODES_STORMPIKE_GRAVE, BG_AV_OBJECT_FLAG_A_STORMPIKE_GRAVE },
{ BG_AV_NODES_DUNBALDAR_SOUTH }, { BG_AV_NODES_DUNBALDAR_SOUTH, BG_AV_OBJECT_FLAG_A_DUNBALDAR_SOUTH },
{ BG_AV_NODES_DUNBALDAR_NORTH }, { BG_AV_NODES_DUNBALDAR_NORTH, BG_AV_OBJECT_FLAG_A_DUNBALDAR_NORTH },
{ BG_AV_NODES_ICEWING_BUNKER }, { BG_AV_NODES_ICEWING_BUNKER, BG_AV_OBJECT_FLAG_A_ICEWING_BUNKER },
{ BG_AV_NODES_STONEHEART_BUNKER }, { BG_AV_NODES_STONEHEART_BUNKER, BG_AV_OBJECT_FLAG_A_STONEHEART_BUNKER },
}; };
static uint32 AB_AttackObjectives[] = static uint32 AB_AttackObjectives[] =
@@ -2937,7 +2950,7 @@ bool BGTactics::selectObjective(bool reset)
alterValleyBG->GetAVNodeInfo(BG_AV_NODES_STONEHEART_BUNKER).TotalOwnerId != TEAM_ALLIANCE && alterValleyBG->GetAVNodeInfo(BG_AV_NODES_STONEHEART_BUNKER).TotalOwnerId != TEAM_ALLIANCE &&
alterValleyBG->GetAVNodeInfo(BG_AV_NODES_FIRSTAID_STATION).TotalOwnerId != TEAM_ALLIANCE) alterValleyBG->GetAVNodeInfo(BG_AV_NODES_FIRSTAID_STATION).TotalOwnerId != TEAM_ALLIANCE)
{ {
if (Creature* pVanndar = bg->GetBGCreature(AV_NPC_A_BOSS)) if (Creature* pVanndar = bg->GetBGCreature(AV_CPLACE_TRIGGER17))
{ {
BgObjective = pVanndar; BgObjective = pVanndar;
endBoss = true; endBoss = true;
@@ -2952,8 +2965,9 @@ bool BGTactics::selectObjective(bool reset)
// Only go to Snowfall Graveyard if already close to it. // Only go to Snowfall Graveyard if already close to it.
// Need to fix AV script // Need to fix AV script
if (!BgObjective && supporter && (alterValleyBG->GetAVNodeInfo(BG_AV_NODES_SNOWFALL_GRAVE).OwnerId == TEAM_ALLIANCE || if (!BgObjective && supporter &&
alterValleyBG->GetAVNodeInfo(BG_AV_NODES_SNOWFALL_GRAVE).OwnerId == TEAM_HORDE || alterValleyBG->GetAVNodeInfo(BG_AV_NODES_SNOWFALL_GRAVE).OwnerId == TEAM_OTHER)) (alterValleyBG->GetAVNodeInfo(BG_AV_NODES_SNOWFALL_GRAVE).OwnerId == TEAM_ALLIANCE ||
alterValleyBG->GetAVNodeInfo(BG_AV_NODES_SNOWFALL_GRAVE).OwnerId == TEAM_OTHER))
{ {
if (GameObject* pGO = bg->GetBGObject(BG_AV_NODES_SNOWFALL_GRAVE)) if (GameObject* pGO = bg->GetBGObject(BG_AV_NODES_SNOWFALL_GRAVE))
if (bot->IsWithinDist(pGO, 200.f)) if (bot->IsWithinDist(pGO, 200.f))
@@ -2967,19 +2981,20 @@ bool BGTactics::selectObjective(bool reset)
if (!BgObjective && alterValleyBG->IsCaptainAlive(0)) if (!BgObjective && alterValleyBG->IsCaptainAlive(0))
{ {
if (Creature* pBalinda = bg->GetBGCreature(AV_NPC_A_CAPTAIN)) if (Creature* pBalinda = bg->GetBGCreature(AV_CPLACE_TRIGGER16))
{ {
if (pBalinda->getDeathState() != DeathState::Dead) if (pBalinda->getDeathState() != DeathState::Dead)
{ {
uint32 attackCount = 0; uint32 attackCount = getDefendersCount(AV_STONEHEARTH_WAITING_HORDE, 10.0f, false) + getDefendersCount(AV_STONEHEARTH_ATTACKING_HORDE, 10.0f, false);
attackCount += getDefendersCount(AV_STONEHEARTH_WAITING_HORDE, 10.0f, false);
// prepare to attack Captain // prepare to attack Captain
if (attackCount < 10 && !pBalinda->IsInCombat()) if (attackCount < 10 && !pBalinda->IsInCombat())
{ {
// get in position to attack Captain // get in position to attack Captain
pos.Set(AV_STONEHEARTH_WAITING_HORDE.GetPositionX(), AV_STONEHEARTH_WAITING_HORDE.GetPositionY(), pos.Set(AV_STONEHEARTH_WAITING_HORDE.GetPositionX(),
AV_STONEHEARTH_WAITING_HORDE.GetPositionZ(), bg->GetMapId()); AV_STONEHEARTH_WAITING_HORDE.GetPositionY(),
AV_STONEHEARTH_WAITING_HORDE.GetPositionZ(),
bg->GetMapId());
std::ostringstream out; std::ostringstream out;
out << "Taking position at Stonehearth!"; out << "Taking position at Stonehearth!";
@@ -2987,6 +3002,12 @@ bool BGTactics::selectObjective(bool reset)
} }
else else
{ {
// they need help getting there (or did before I fixed the target creature, will leave in anyway, as it probably makes it more robust)
pos.Set(AV_STONEHEARTH_ATTACKING_HORDE.GetPositionX(),
AV_STONEHEARTH_ATTACKING_HORDE.GetPositionY(),
AV_STONEHEARTH_ATTACKING_HORDE.GetPositionZ(),
bg->GetMapId());
std::ostringstream out; std::ostringstream out;
out << "Attacking Balinda!"; out << "Attacking Balinda!";
//bot->Say(out.str(), LANG_UNIVERSAL); //bot->Say(out.str(), LANG_UNIVERSAL);
@@ -3007,9 +3028,9 @@ bool BGTactics::selectObjective(bool reset)
{ {
for (const auto& objective : AV_HordeDefendObjectives) for (const auto& objective : AV_HordeDefendObjectives)
{ {
if (!BgObjective && alterValleyBG->GetAVNodeInfo(objective).OwnerId == TEAM_ALLIANCE) if (!BgObjective && alterValleyBG->GetAVNodeInfo(objective.first).OwnerId == TEAM_ALLIANCE)
{ {
if (GameObject* pGO = bg->GetBGObject(objective)) if (GameObject* pGO = bg->GetBGObject(objective.second))
if (bot->IsWithinDist(pGO, 400.0f)) if (bot->IsWithinDist(pGO, 400.0f))
{ {
BgObjective = pGO; BgObjective = pGO;
@@ -3022,7 +3043,8 @@ bool BGTactics::selectObjective(bool reset)
} }
// Mine capture (need paths & script fix) // Mine capture (need paths & script fix)
if (!BgObjective && supporter && !endBoss && (alterValleyBG->GetMineOwner(AV_NORTH_MINE) == TEAM_ALLIANCE || alterValleyBG->GetMineOwner(AV_NORTH_MINE) == TEAM_OTHER) && if (!BgObjective && supporter && !endBoss &&
(alterValleyBG->GetMineOwner(AV_NORTH_MINE) == TEAM_ALLIANCE || alterValleyBG->GetMineOwner(AV_NORTH_MINE) == TEAM_OTHER) &&
alterValleyBG->GetAVNodeInfo(BG_AV_NODES_STORMPIKE_GRAVE).OwnerId != TEAM_ALLIANCE) alterValleyBG->GetAVNodeInfo(BG_AV_NODES_STORMPIKE_GRAVE).OwnerId != TEAM_ALLIANCE)
{ {
if (Creature* mBossNeutral = bg->GetBGCreature(AV_CPLACE_MINE_N_3)) if (Creature* mBossNeutral = bg->GetBGCreature(AV_CPLACE_MINE_N_3))
@@ -3055,10 +3077,9 @@ bool BGTactics::selectObjective(bool reset)
for (const auto& objective : AV_HordeAttackObjectives) for (const auto& objective : AV_HordeAttackObjectives)
{ {
if ((!BgObjective/* || (supporter && objective.first == BG_AV_NODES_STONEHEART_BUNKER && !bg->IsActiveEvent(BG_AV_NODE_CAPTAIN_DEAD_A, 0))*/) && if ((!BgObjective/* || (supporter && objective.first == BG_AV_NODES_STONEHEART_BUNKER && !bg->IsActiveEvent(BG_AV_NODE_CAPTAIN_DEAD_A, 0))*/) &&
(alterValleyBG->GetAVNodeInfo(objective).OwnerId == TEAM_ALLIANCE || alterValleyBG->GetAVNodeInfo(objective).TotalOwnerId == TEAM_ALLIANCE || alterValleyBG->GetAVNodeInfo(objective.first).TotalOwnerId == TEAM_ALLIANCE)//need to check TotalOwnerId for attack objectives
alterValleyBG->GetAVNodeInfo(objective).OwnerId == TEAM_OTHER))
{ {
if (GameObject* pGO = bg->GetBGObject(objective)) if (GameObject* pGO = bg->GetBGObject(objective.second))
{ {
BgObjective = pGO; BgObjective = pGO;
//std::ostringstream out; //std::ostringstream out;
@@ -3073,11 +3094,13 @@ bool BGTactics::selectObjective(bool reset)
{ {
bool endBoss = false; bool endBoss = false;
// End boss // End boss
if (alterValleyBG->GetAVNodeInfo(BG_AV_NODES_ICEBLOOD_TOWER).OwnerId != TEAM_HORDE && alterValleyBG->GetAVNodeInfo(BG_AV_NODES_TOWER_POINT).OwnerId != TEAM_HORDE && if (alterValleyBG->GetAVNodeInfo(BG_AV_NODES_ICEBLOOD_TOWER).TotalOwnerId != TEAM_HORDE &&
alterValleyBG->GetAVNodeInfo(BG_AV_NODES_FROSTWOLF_ETOWER).OwnerId != TEAM_HORDE && alterValleyBG->GetAVNodeInfo(BG_AV_NODES_FROSTWOLF_WTOWER).OwnerId != TEAM_HORDE && alterValleyBG->GetAVNodeInfo(BG_AV_NODES_TOWER_POINT).TotalOwnerId != TEAM_HORDE &&
alterValleyBG->GetAVNodeInfo(BG_AV_NODES_FROSTWOLF_HUT).OwnerId != TEAM_HORDE) alterValleyBG->GetAVNodeInfo(BG_AV_NODES_FROSTWOLF_ETOWER).TotalOwnerId != TEAM_HORDE &&
alterValleyBG->GetAVNodeInfo(BG_AV_NODES_FROSTWOLF_WTOWER).TotalOwnerId != TEAM_HORDE &&
alterValleyBG->GetAVNodeInfo(BG_AV_NODES_FROSTWOLF_HUT).TotalOwnerId != TEAM_HORDE)
{ {
if (Creature* pDrek = bg->GetBGCreature(AV_NPC_H_BOSS)) if (Creature* pDrek = bg->GetBGCreature(AV_CPLACE_TRIGGER19))
{ {
BgObjective = pDrek; BgObjective = pDrek;
endBoss = true; endBoss = true;
@@ -3091,9 +3114,9 @@ bool BGTactics::selectObjective(bool reset)
bool supporter = role < 3; bool supporter = role < 3;
// Only go to Snowfall Graveyard if already close to it. // Only go to Snowfall Graveyard if already close to it.
if (!BgObjective && supporter && (alterValleyBG->GetAVNodeInfo(BG_AV_NODES_SNOWFALL_GRAVE).OwnerId == TEAM_HORDE || if (!BgObjective && supporter &&
alterValleyBG->GetAVNodeInfo(BG_AV_NODES_SNOWFALL_GRAVE).TotalOwnerId == TEAM_HORDE || (alterValleyBG->GetAVNodeInfo(BG_AV_NODES_SNOWFALL_GRAVE).OwnerId == TEAM_HORDE ||
alterValleyBG->GetAVNodeInfo(BG_AV_NODES_SNOWFALL_GRAVE).TotalOwnerId == TEAM_OTHER)) alterValleyBG->GetAVNodeInfo(BG_AV_NODES_SNOWFALL_GRAVE).OwnerId == TEAM_OTHER))
{ {
if (GameObject* pGO = bg->GetBGObject(BG_AV_NODES_SNOWFALL_GRAVE)) if (GameObject* pGO = bg->GetBGObject(BG_AV_NODES_SNOWFALL_GRAVE))
if (bot->IsWithinDist(pGO, 200.f)) if (bot->IsWithinDist(pGO, 200.f))
@@ -3110,9 +3133,9 @@ bool BGTactics::selectObjective(bool reset)
{ {
for (const auto& objective : AV_AllianceDefendObjectives) for (const auto& objective : AV_AllianceDefendObjectives)
{ {
if (!BgObjective && alterValleyBG->GetAVNodeInfo(objective).OwnerId == TEAM_HORDE) if (!BgObjective && alterValleyBG->GetAVNodeInfo(objective.first).OwnerId == TEAM_HORDE)
{ {
if (GameObject* pGO = bg->GetBGObject(objective)) if (GameObject* pGO = bg->GetBGObject(objective.second))
{ {
BgObjective = pGO; BgObjective = pGO;
//std::ostringstream out; out << "Defending Node #" << objective.first; //std::ostringstream out; out << "Defending Node #" << objective.first;
@@ -3123,8 +3146,8 @@ bool BGTactics::selectObjective(bool reset)
} }
// Mine capture (need paths & script fix) // Mine capture (need paths & script fix)
if (!BgObjective && supporter && !endBoss && (alterValleyBG->GetMineOwner(AV_SOUTH_MINE) == TEAM_HORDE || if (!BgObjective && supporter && !endBoss &&
alterValleyBG->GetMineOwner(AV_SOUTH_MINE) == TEAM_OTHER) && (alterValleyBG->GetMineOwner(AV_SOUTH_MINE) == TEAM_HORDE || alterValleyBG->GetMineOwner(AV_SOUTH_MINE) == TEAM_OTHER) &&
alterValleyBG->GetAVNodeInfo(BG_AV_NODES_FROSTWOLF_GRAVE).TotalOwnerId != TEAM_HORDE) alterValleyBG->GetAVNodeInfo(BG_AV_NODES_FROSTWOLF_GRAVE).TotalOwnerId != TEAM_HORDE)
{ {
if (Creature* mBossNeutral = bg->GetBGCreature(AV_CPLACE_MINE_S_3)) if (Creature* mBossNeutral = bg->GetBGCreature(AV_CPLACE_MINE_S_3))
@@ -3158,17 +3181,18 @@ bool BGTactics::selectObjective(bool reset)
if (alterValleyBG->IsCaptainAlive(1)) if (alterValleyBG->IsCaptainAlive(1))
{ {
if (Creature* pGalvangar = bg->GetBGCreature(AV_NPC_H_CAPTAIN)) if (Creature* pGalvangar = bg->GetBGCreature(AV_CPLACE_TRIGGER18))
{ {
uint32 attackCount = 0; uint32 attackCount = getDefendersCount(AV_ICEBLOOD_GARRISON_WAITING_ALLIANCE, 10.0f, false) + getDefendersCount(AV_ICEBLOOD_GARRISON_ATTACKING_ALLIANCE, 10.0f, false);
attackCount += getDefendersCount(AV_ICEBLOOD_GARRISON_WAITING_ALLIANCE, 10.0f, false);
// prepare to attack Captain // prepare to attack Captain
if (attackCount < 10 && !pGalvangar->IsInCombat()) if (attackCount < 10 && !pGalvangar->IsInCombat())
{ {
// get in position to attack Captain // get in position to attack Captain
pos.Set(AV_ICEBLOOD_GARRISON_WAITING_ALLIANCE.GetPositionX(), AV_ICEBLOOD_GARRISON_WAITING_ALLIANCE.GetPositionY(), pos.Set(AV_ICEBLOOD_GARRISON_WAITING_ALLIANCE.GetPositionX(),
AV_ICEBLOOD_GARRISON_WAITING_ALLIANCE.GetPositionZ(), bg->GetMapId()); AV_ICEBLOOD_GARRISON_WAITING_ALLIANCE.GetPositionY(),
AV_ICEBLOOD_GARRISON_WAITING_ALLIANCE.GetPositionZ(),
bg->GetMapId());
//std::ostringstream out; //std::ostringstream out;
//out << "Taking position at Iceblood Outpost!"; //out << "Taking position at Iceblood Outpost!";
@@ -3176,6 +3200,12 @@ bool BGTactics::selectObjective(bool reset)
} }
else else
{ {
// they need help getting there (or did before I fixed the target creature, will leave in anyway, as it probably makes it more robust)
pos.Set(AV_ICEBLOOD_GARRISON_ATTACKING_ALLIANCE.GetPositionX(),
AV_ICEBLOOD_GARRISON_ATTACKING_ALLIANCE.GetPositionY(),
AV_ICEBLOOD_GARRISON_ATTACKING_ALLIANCE.GetPositionZ(),
bg->GetMapId());
//std::ostringstream out; //std::ostringstream out;
// out << "Attacking Galvangar!"; // out << "Attacking Galvangar!";
//bot->Say(out.str(), LANG_UNIVERSAL); //bot->Say(out.str(), LANG_UNIVERSAL);
@@ -3187,11 +3217,9 @@ bool BGTactics::selectObjective(bool reset)
for (const auto& objective : AV_AllianceAttackObjectives) for (const auto& objective : AV_AllianceAttackObjectives)
{ {
if (alterValleyBG->GetAVNodeInfo(objective).OwnerId == TEAM_HORDE || if (alterValleyBG->GetAVNodeInfo(objective.first).TotalOwnerId == TEAM_HORDE)//need to check TotalOwnerId for attack objectives
alterValleyBG->GetAVNodeInfo(objective).TotalOwnerId == TEAM_HORDE ||
alterValleyBG->GetAVNodeInfo(objective).TotalOwnerId == TEAM_OTHER)
{ {
if (GameObject* pGO = bg->GetBGObject(objective)) if (GameObject* pGO = bg->GetBGObject(objective.second))
{ {
float const distance = sqrt(bot->GetDistance(pGO)); float const distance = sqrt(bot->GetDistance(pGO));
if (attackObjectiveDistance > distance) if (attackObjectiveDistance > distance)
@@ -4124,7 +4152,7 @@ bool BGTactics::moveToObjective()
} }
// don't try to move if already close // don't try to move if already close
if (sqrt(bot->GetDistance(pos.x, pos.y, pos.z)) < 5.0f) if (sqrt(bot->GetDistance(pos.x, pos.y, pos.z)) < 2.0f)
{ {
resetObjective(); resetObjective();
@@ -4134,8 +4162,8 @@ bool BGTactics::moveToObjective()
//std::ostringstream out; out << "Moving to objective " << pos.x << ", " << pos.y << ", Distance: " << sServerFacade->GetDistance2d(bot, pos.x, pos.y); //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); //bot->Say(out.str(), LANG_UNIVERSAL);
// more precise position for wsg // more precise position for wsg and AV (flags in AV towers require precision)
if (bgType == BATTLEGROUND_WS) if (bgType == BATTLEGROUND_WS || bgType == BATTLEGROUND_AV)
return MoveTo(bot->GetMapId(), pos.x, pos.y, pos.z); return MoveTo(bot->GetMapId(), pos.x, pos.y, pos.z);
else else
return MoveNear(bot->GetMapId(), pos.x, pos.y, pos.z, 3.0f); return MoveNear(bot->GetMapId(), pos.x, pos.y, pos.z, 3.0f);
@@ -4162,99 +4190,84 @@ bool BGTactics::selectObjectiveWp(std::vector<BattleBotPath*> const& vPaths)
if (bgType == BATTLEGROUND_WS /* && (bot->HasAura(BG_WS_SPELL_WARSONG_FLAG) || bot->HasAura(BG_WS_SPELL_SILVERWING_FLAG))*/) if (bgType == BATTLEGROUND_WS /* && (bot->HasAura(BG_WS_SPELL_WARSONG_FLAG) || bot->HasAura(BG_WS_SPELL_SILVERWING_FLAG))*/)
return wsgPaths(); return wsgPaths();
BattleBotPath* pClosestPath = nullptr; float chosenPathScore = FLT_MAX;//lower score is better
uint32 closestPoint = 0; BattleBotPath* chosenPath = nullptr;
float closestDistanceToTarget = FLT_MAX; uint32 chosenPathPoint = 0;
bool reverse = false; bool chosenPathReverse = false;
float maxDistanceToPoint = 50.0f;
if (bgType == BATTLEGROUND_IC)
maxDistanceToPoint = 80.0f;
for (auto const& pPath : vPaths) 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;
else if (bgType == BATTLEGROUND_AB)
{
botDistanceScoreSubtract = 2.0f;
botDistanceScoreMultiply = 4.0f;
}
for (auto const& path : vPaths)
{ {
// skip mine paths of own faction // skip mine paths of own faction
if (bot->GetTeamId() == TEAM_ALLIANCE && std::find(vPaths_AllyMine.begin(), vPaths_AllyMine.end(), pPath) != vPaths_AllyMine.end()) if (bot->GetTeamId() == TEAM_ALLIANCE && std::find(vPaths_AllyMine.begin(), vPaths_AllyMine.end(), path) != vPaths_AllyMine.end())
continue; continue;
if (bot->GetTeamId() == TEAM_HORDE && std::find(vPaths_HordeMine.begin(), vPaths_HordeMine.end(), pPath) != vPaths_HordeMine.end()) if (bot->GetTeamId() == TEAM_HORDE && std::find(vPaths_HordeMine.begin(), vPaths_HordeMine.end(), path) != vPaths_HordeMine.end())
continue; continue;
BattleBotWaypoint& lastPoint = ((*pPath)[pPath->size() - 1]); BattleBotWaypoint& startPoint = ((*path)[0]);
float const distanceFromPathEndToTarget = sqrt(Position(pos.x, pos.y, pos.z, 0.f).GetExactDist(lastPoint.x, lastPoint.y, lastPoint.z)); float const startPointDistToDestination = sqrt(Position(pos.x, pos.y, pos.z, 0.f).GetExactDist(startPoint.x, startPoint.y, startPoint.z));
if (closestDistanceToTarget > distanceFromPathEndToTarget) 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++)
{ {
float closestDistanceFromMeToPoint = FLT_MAX; BattleBotWaypoint& waypoint = ((*path)[i]);
float const distToBot = sqrt(bot->GetDistance(waypoint.x, waypoint.y, waypoint.z));
for (uint32 i = 0; i < pPath->size(); i++) if (closestPointDistToBot > distToBot)
{ {
BattleBotWaypoint& waypoint = ((*pPath)[i]); closestPointDistToBot = distToBot;
float const distanceFromMeToPoint = sqrt(bot->GetDistance(waypoint.x, waypoint.y, waypoint.z)); closestPointIndex = i;
if (distanceFromMeToPoint < maxDistanceToPoint && closestDistanceFromMeToPoint > distanceFromMeToPoint)
{
reverse = false;
pClosestPath = pPath;
closestPoint = i;
closestDistanceToTarget = distanceFromPathEndToTarget;
closestDistanceFromMeToPoint = distanceFromMeToPoint;
}
} }
} }
// skip no reverse paths // don't pick path where bot is already closest to the paths closest point to target (it means path cant lead it anywhere)
if (std::find(vPaths_NoReverseAllowed.begin(), vPaths_NoReverseAllowed.end(), pPath) != vPaths_NoReverseAllowed.end()) // don't pick path where closest point is too far away
if (closestPointIndex == (reverse ? 0 : path->size() - 1) || closestPointDistToBot > botDistanceLimit)
continue; continue;
// skip mine paths of own faction
if (bot->GetTeamId() == TEAM_ALLIANCE && std::find(vPaths_AllyMine.begin(), vPaths_AllyMine.end(), pPath) != vPaths_AllyMine.end())
continue;
if (bot->GetTeamId() == TEAM_HORDE && std::find(vPaths_HordeMine.begin(), vPaths_HordeMine.end(), pPath) != vPaths_HordeMine.end()) // 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)
continue; // 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]);
BattleBotWaypoint& firstPoint = ((*pPath)[0]);
float const distanceFromPathBeginToTarget = sqrt(Position(pos.x, pos.y, pos.z, 0).GetExactDist(firstPoint.x, firstPoint.y, firstPoint.z));
if (closestDistanceToTarget > distanceFromPathBeginToTarget)
{
float closestDistanceFromMeToPoint = FLT_MAX;
for (uint32 i = 0; i < pPath->size(); i++) if (chosenPathScore > pathScore) {
{ chosenPathScore = pathScore;
BattleBotWaypoint& waypoint = ((*pPath)[i]); chosenPath = path;
float const distanceFromMeToPoint = sqrt(bot->GetDistance(waypoint.x, waypoint.y, waypoint.z)); chosenPathPoint = closestPointIndex;
if (distanceFromMeToPoint < maxDistanceToPoint && closestDistanceFromMeToPoint > distanceFromMeToPoint) chosenPathReverse = reverse;
{
reverse = true;
pClosestPath = pPath;
closestPoint = i;
closestDistanceToTarget = distanceFromPathBeginToTarget;
closestDistanceFromMeToPoint = distanceFromMeToPoint;
}
}
}
} }
} }
if (!pClosestPath) if (!chosenPath)
return false; return false;
// Prevent picking last point of path. //LOG_INFO("playerbots", "bot={} {}", bot->GetName(), vPaths_AB_name[chosenPathNum]);
// It means we are already there.
if (reverse)
{
if (closestPoint == 0)
return false;
}
else
{
if (closestPoint == pClosestPath->size() - 1)
return false;
}
BattleBotPath* currentPath = pClosestPath; return moveToObjectiveWp(chosenPath, chosenPathPoint, chosenPathReverse);
uint32 currentPoint = reverse ? closestPoint + 1 : closestPoint - 1;
return moveToObjectiveWp(currentPath, currentPoint, reverse);
return false; return false;
} }
@@ -4961,9 +4974,9 @@ bool ArenaTactics::moveToCenter(Battleground* bg)
case BATTLEGROUND_DS: case BATTLEGROUND_DS:
if (!MoveTo(bg->GetMapId(), 1291.58f + frand(-5, +5), 790.87f + frand(-5, +5), 7.8f, false, true)) { 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 // they like to hang around at the tip of the pipes doing nothing, so we just teleport them down
if (bot->GetDistance(1333.07f, 817.18f, 13.35f) < 2) if (bot->GetDistance(1333.07f, 817.18f, 13.35f) < 4)
bot->TeleportTo(bg->GetMapId(), 1330.96f, 816.75f, 3.2f, bot->GetOrientation()); bot->TeleportTo(bg->GetMapId(), 1330.96f, 816.75f, 3.2f, bot->GetOrientation());
if (bot->GetDistance(1250.13f, 764.79f, 13.34f) < 2) if (bot->GetDistance(1250.13f, 764.79f, 13.34f) < 4)
bot->TeleportTo(bg->GetMapId(), 1252.19f, 765.41f, 3.2f, bot->GetOrientation()); bot->TeleportTo(bg->GetMapId(), 1252.19f, 765.41f, 3.2f, bot->GetOrientation());
} }
break; break;

View File

@@ -163,7 +163,9 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle,
// } // }
bool generatePath = !bot->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) && bool generatePath = !bot->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) &&
!bot->IsFlying() && !bot->HasUnitMovementFlag(MOVEMENTFLAG_SWIMMING) && !bot->IsInWater(); !bot->IsFlying() && !bot->HasUnitMovementFlag(MOVEMENTFLAG_SWIMMING) && !bot->IsInWater();
if (!generatePath) { bool disableMoveSplinePath = sPlayerbotAIConfig->disableMoveSplinePath >= 2 ||
(sPlayerbotAIConfig->disableMoveSplinePath == 1 && bot->InBattleground());
if (disableMoveSplinePath || !generatePath) {
float distance = bot->GetExactDist(x, y, z); float distance = bot->GetExactDist(x, y, z);
if (distance > sPlayerbotAIConfig->contactDistance) if (distance > sPlayerbotAIConfig->contactDistance)
{ {

View File

@@ -179,28 +179,25 @@ bool SummonAction::Teleport(Player* summoner, Player* player)
if (sPlayerbotAIConfig->botRepairWhenSummon) // .conf option to repair bot gear when summoned 0 = off, 1 = on if (sPlayerbotAIConfig->botRepairWhenSummon) // .conf option to repair bot gear when summoned 0 = off, 1 = on
bot->DurabilityRepairAll(false, 1.0f, false); bot->DurabilityRepairAll(false, 1.0f, false);
if (sPlayerbotAIConfig->botReviveWhenSummon < 2) if (master->IsInCombat() && !sPlayerbotAIConfig->allowSummonInCombat)
{ {
if (master->IsInCombat()) botAI->TellError("You cannot summon me while you're in combat");
{ return false;
botAI->TellError("You cannot summon me while you're in combat");
return false;
}
if (!master->IsAlive())
{
botAI->TellError("You cannot summon me while you're dead");
return false;
}
if (bot->isDead() && !bot->HasPlayerFlag(PLAYER_FLAGS_GHOST))
{
botAI->TellError("You cannot summon me while I'm dead, you need to release my spirit first");
return false;
}
} }
if (sPlayerbotAIConfig->botReviveWhenSummon > 0 && bot->isDead()) if (!master->IsAlive() && !sPlayerbotAIConfig->allowSummonWhenMasterIsDead)
{
botAI->TellError("You cannot summon me while you're dead");
return false;
}
if (bot->isDead() && !bot->HasPlayerFlag(PLAYER_FLAGS_GHOST) && !sPlayerbotAIConfig->allowSummonWhenBotIsDead)
{
botAI->TellError("You cannot summon me while I'm dead, you need to release my spirit first");
return false;
}
if (sPlayerbotAIConfig->botReviveWhenSummon == 2 || (sPlayerbotAIConfig->botReviveWhenSummon == 1 && !master->IsInCombat() && master->IsAlive()))
{ {
bot->ResurrectPlayer(1.0f, false); bot->ResurrectPlayer(1.0f, false);
botAI->TellMasterNoFacing("I live, again!"); botAI->TellMasterNoFacing("I live, again!");

View File

@@ -47,8 +47,21 @@ GuidVector AttackersValue::Calculate()
if (bot->duel && bot->duel->Opponent) if (bot->duel && bot->duel->Opponent)
result.push_back(bot->duel->Opponent->GetGUID()); result.push_back(bot->duel->Opponent->GetGUID());
return result; // workaround for bots of same faction not fighting in arena
if (bot->InArena())
{
GuidVector possibleTargets = AI_VALUE(GuidVector, "possible targets");
for (ObjectGuid const guid : possibleTargets)
{
Unit* unit = botAI->GetUnit(guid);
if (unit && unit->IsPlayer() && IsValidTarget(unit, bot)) {
result.push_back(unit->GetGUID());
}
}
}
return result;
} }
void AttackersValue::AddAttackersOf(Group* group, std::unordered_set<Unit*>& targets) void AttackersValue::AddAttackersOf(Group* group, std::unordered_set<Unit*>& targets)