Compare commits

..

No commits in common. "6effabfa42a2f793c417dfdfff948736430adae2" and "08c739f9185a88d9118ef9f282f845a89b37acd0" have entirely different histories.

2 changed files with 28 additions and 161 deletions

View File

@ -14,7 +14,6 @@
#include "BudgetValues.h" #include "BudgetValues.h"
#include "ChannelMgr.h" #include "ChannelMgr.h"
#include "CharacterPackets.h" #include "CharacterPackets.h"
#include "ChatHelper.h"
#include "Common.h" #include "Common.h"
#include "CreatureAIImpl.h" #include "CreatureAIImpl.h"
#include "CreatureData.h" #include "CreatureData.h"
@ -284,15 +283,6 @@ void PlayerbotAI::UpdateAI(uint32 elapsed, bool minimal)
return; return;
} }
GameObject* goSpellTarget = currentSpell->m_targets.GetGOTarget();
if (goSpellTarget && !goSpellTarget->isSpawned())
{
InterruptSpell();
YieldThread(GetReactDelay());
return;
}
bool isHeal = false; bool isHeal = false;
bool isSingleTarget = true; bool isSingleTarget = true;

View File

@ -4,12 +4,10 @@
*/ */
#include "BattleGroundTactics.h" #include "BattleGroundTactics.h"
#include "BattleGroundJoinAction.h"
#include <algorithm>
#include "ArenaTeam.h" #include "ArenaTeam.h"
#include "ArenaTeamMgr.h" #include "ArenaTeamMgr.h"
#include "BattleGroundJoinAction.h"
#include "Battleground.h" #include "Battleground.h"
#include "BattlegroundAB.h" #include "BattlegroundAB.h"
#include "BattlegroundAV.h" #include "BattlegroundAV.h"
@ -24,12 +22,11 @@
#include "BattlegroundSA.h" #include "BattlegroundSA.h"
#include "BattlegroundWS.h" #include "BattlegroundWS.h"
#include "Event.h" #include "Event.h"
#include "GameObject.h"
#include "IVMapMgr.h" #include "IVMapMgr.h"
#include "PathGenerator.h"
#include "Playerbots.h" #include "Playerbots.h"
#include "PositionValue.h" #include "PositionValue.h"
#include "PvpTriggers.h" #include "PvpTriggers.h"
#include "PathGenerator.h"
#include "ServerFacade.h" #include "ServerFacade.h"
#include "Vehicle.h" #include "Vehicle.h"
@ -1757,7 +1754,7 @@ bool BGTactics::moveToStart(bool force)
WS_WAITING_POS_ALLIANCE_2.GetPositionY() + frand(-4.0f, 4.0f), WS_WAITING_POS_ALLIANCE_2.GetPositionY() + frand(-4.0f, 4.0f),
WS_WAITING_POS_ALLIANCE_2.GetPositionZ()); WS_WAITING_POS_ALLIANCE_2.GetPositionZ());
} }
else // BB_WSG_WAIT_SPOT_SPAWN else // BB_WSG_WAIT_SPOT_SPAWN
{ {
if (bot->GetTeamId() == TEAM_HORDE) if (bot->GetTeamId() == TEAM_HORDE)
MoveTo(bg->GetMapId(), WS_WAITING_POS_HORDE_3.GetPositionX() + frand(-10.0f, 10.0f), MoveTo(bg->GetMapId(), WS_WAITING_POS_HORDE_3.GetPositionX() + frand(-10.0f, 10.0f),
@ -3368,12 +3365,12 @@ bool BGTactics::resetObjective()
return false; return false;
// Adjust role-change chance based on battleground type // Adjust role-change chance based on battleground type
uint32 oddsToChangeRole = 1; // default low uint32 oddsToChangeRole = 1; // default low
BattlegroundTypeId bgType = bg->GetBgTypeID(); BattlegroundTypeId bgType = bg->GetBgTypeID();
if (bgType == BATTLEGROUND_WS) if (bgType == BATTLEGROUND_WS)
oddsToChangeRole = 2; oddsToChangeRole = 2;
else if (bgType == BATTLEGROUND_EY || bgType == BATTLEGROUND_IC || bgType == BATTLEGROUND_AB) else if (bgType == BATTLEGROUND_EY || bgType == BATTLEGROUND_IC || bgType == BATTLEGROUND_AB)
oddsToChangeRole = 1; oddsToChangeRole = 1;
else if (bgType == BATTLEGROUND_AV) else if (bgType == BATTLEGROUND_AV)
oddsToChangeRole = 0; oddsToChangeRole = 0;
@ -3581,16 +3578,6 @@ bool BGTactics::atFlag(std::vector<BattleBotPath*> const& vPaths, std::vector<ui
GuidVector closePlayers; GuidVector closePlayers;
float flagRange = 0.0f; float flagRange = 0.0f;
// Eye of the Storm helpers used later when handling capture positioning
BattlegroundEY* eyeBg = nullptr;
GameObject* eyCenterFlag = nullptr;
if (bgType == BATTLEGROUND_EY)
{
eyeBg = static_cast<BattlegroundEY*>(bg);
if (eyeBg)
eyCenterFlag = eyeBg->GetBGObject(BG_EY_OBJECT_FLAG_NETHERSTORM);
}
// Set up appropriate search ranges and object lists based on BG type // Set up appropriate search ranges and object lists based on BG type
switch (bgType) switch (bgType)
{ {
@ -3620,82 +3607,27 @@ bool BGTactics::atFlag(std::vector<BattleBotPath*> const& vPaths, std::vector<ui
if (closeObjects.empty()) if (closeObjects.empty())
return false; return false;
auto keepStationaryWhileCapturing = [&](CurrentSpellTypes spellType)
{
Spell* currentSpell = bot->GetCurrentSpell(spellType);
if (!currentSpell || !currentSpell->m_spellInfo || currentSpell->m_spellInfo->Id != SPELL_CAPTURE_BANNER)
return false;
// If the capture target is no longer available (another bot already captured it), stop channeling
if (GameObject* targetFlag = currentSpell->m_targets.GetGOTarget())
{
if (!targetFlag->isSpawned() || targetFlag->GetGoState() != GO_STATE_READY)
{
bot->InterruptNonMeleeSpells(true);
resetObjective();
return false;
}
}
else
{
bot->InterruptNonMeleeSpells(true);
resetObjective();
return false;
}
if (bot->IsMounted())
{
bot->RemoveAurasByType(SPELL_AURA_MOUNTED);
}
if (bot->IsInDisallowedMountForm())
{
bot->RemoveAurasByType(SPELL_AURA_MOD_SHAPESHIFT);
}
if (bot->isMoving())
{
bot->StopMoving();
}
return true;
};
// If we are already channeling the capture spell, keep the bot stationary and dismounted
if (keepStationaryWhileCapturing(CURRENT_CHANNELED_SPELL) || keepStationaryWhileCapturing(CURRENT_GENERIC_SPELL))
return true;
// First identify which flag/base we're trying to interact with // First identify which flag/base we're trying to interact with
GameObject* targetFlag = nullptr; GameObject* targetFlag = nullptr;
for (ObjectGuid const guid : closeObjects) for (ObjectGuid const guid : closeObjects)
{ {
GameObject* go = botAI->GetGameObject(guid); GameObject* go = botAI->GetGameObject(guid);
if (!go) if (!go)
{
continue; continue;
}
bool const isEyCenterFlag = eyeBg && eyCenterFlag && eyCenterFlag->GetGUID() == go->GetGUID();
// Check if this object is a valid capture target // Check if this object is a valid capture target
std::vector<uint32>::const_iterator f = std::find(vFlagIds.begin(), vFlagIds.end(), go->GetEntry()); std::vector<uint32>::const_iterator f = find(vFlagIds.begin(), vFlagIds.end(), go->GetEntry());
if (f == vFlagIds.end() && !isEyCenterFlag) if (f == vFlagIds.end())
{
continue; continue;
}
// Verify the object is active and ready // Verify the object is active and ready
if (!go->isSpawned() || go->GetGoState() != GO_STATE_READY) if (!go->isSpawned() || go->GetGoState() != GO_STATE_READY)
{
continue; continue;
}
// Check if we're in range (using double range for enemy detection) // Check if we're in range (using double range for enemy detection)
float const dist = bot->GetDistance(go); float const dist = bot->GetDistance(go);
if (flagRange && dist > flagRange * 2.0f) if (flagRange && dist > flagRange * 2.0f)
{
continue; continue;
}
targetFlag = go; targetFlag = go;
break; break;
@ -3723,7 +3655,7 @@ bool BGTactics::atFlag(std::vector<BattleBotPath*> const& vPaths, std::vector<ui
} }
// Check if friendly players are already capturing // Check if friendly players are already capturing
if (!closePlayers.empty() && bgType != BATTLEGROUND_EY) if (!closePlayers.empty())
{ {
// Track number of friendly players capturing and the closest one // Track number of friendly players capturing and the closest one
uint32 numCapturing = 0; uint32 numCapturing = 0;
@ -3732,17 +3664,14 @@ bool BGTactics::atFlag(std::vector<BattleBotPath*> const& vPaths, std::vector<ui
{ {
if (Unit* pFriend = botAI->GetUnit(guid)) if (Unit* pFriend = botAI->GetUnit(guid))
{ {
// Check if they're casting or channeling the capture spell // Check if they're casting the capture spell
Spell* spell = pFriend->GetCurrentSpell(CURRENT_GENERIC_SPELL); if (Spell* spell = pFriend->GetCurrentSpell(CURRENT_GENERIC_SPELL))
if (!spell)
{ {
spell = pFriend->GetCurrentSpell(CURRENT_CHANNELED_SPELL); if (spell->m_spellInfo->Id == SPELL_CAPTURE_BANNER)
} {
numCapturing++;
if (spell && spell->m_spellInfo && spell->m_spellInfo->Id == SPELL_CAPTURE_BANNER) capturingPlayer = pFriend;
{ }
numCapturing++;
capturingPlayer = pFriend;
} }
} }
} }
@ -3775,11 +3704,9 @@ bool BGTactics::atFlag(std::vector<BattleBotPath*> const& vPaths, std::vector<ui
if (!go) if (!go)
continue; continue;
bool const isEyCenterFlag = eyeBg && eyCenterFlag && eyCenterFlag->GetGUID() == go->GetGUID();
// Validate this is a capture target // Validate this is a capture target
std::vector<uint32>::const_iterator f = std::find(vFlagIds.begin(), vFlagIds.end(), go->GetEntry()); std::vector<uint32>::const_iterator f = find(vFlagIds.begin(), vFlagIds.end(), go->GetEntry());
if (f == vFlagIds.end() && !isEyCenterFlag) if (f == vFlagIds.end())
continue; continue;
// Check object is active // Check object is active
@ -3795,40 +3722,12 @@ bool BGTactics::atFlag(std::vector<BattleBotPath*> const& vPaths, std::vector<ui
continue; continue;
// Special handling for WSG and EY base flags // Special handling for WSG and EY base flags
bool isWsBaseFlag = bgType == BATTLEGROUND_WS && go->GetEntry() == vFlagsWS[bot->GetTeamId()]; bool atBase = bgType == BATTLEGROUND_WS ? go->GetEntry() == vFlagsWS[bot->GetTeamId()]
bool isEyBaseFlag = bgType == BATTLEGROUND_EY && go->GetEntry() == vFlagsEY[0]; : bgType == BATTLEGROUND_EY ? go->GetEntry() == vFlagsEY[0]
: false;
// Ensure bots are inside the Eye of the Storm capture circle before casting
if (bgType == BATTLEGROUND_EY)
{
GameObject* captureFlag = (isEyBaseFlag && eyCenterFlag) ? eyCenterFlag : go;
float const requiredRange = 2.5f;
if (!bot->IsWithinDistInMap(captureFlag, requiredRange))
{
// Stay mounted while relocating to avoid mount/dismount loops
return MoveTo(bot->GetMapId(), captureFlag->GetPositionX(), captureFlag->GetPositionY(),
captureFlag->GetPositionZ());
}
// Once inside the circle, dismount and stop before starting the channel
if (bot->IsMounted())
{
bot->RemoveAurasByType(SPELL_AURA_MOUNTED);
}
if (bot->IsInDisallowedMountForm())
{
bot->RemoveAurasByType(SPELL_AURA_MOD_SHAPESHIFT);
}
if (bot->isMoving())
{
bot->StopMoving();
}
}
// Don't capture own flag in WSG unless carrying enemy flag // Don't capture own flag in WSG unless carrying enemy flag
if (isWsBaseFlag && bgType == BATTLEGROUND_WS && if (atBase && bgType == BATTLEGROUND_WS &&
!(bot->HasAura(BG_WS_SPELL_WARSONG_FLAG) || bot->HasAura(BG_WS_SPELL_SILVERWING_FLAG))) !(bot->HasAura(BG_WS_SPELL_WARSONG_FLAG) || bot->HasAura(BG_WS_SPELL_SILVERWING_FLAG)))
continue; continue;
@ -3844,7 +3743,7 @@ bool BGTactics::atFlag(std::vector<BattleBotPath*> const& vPaths, std::vector<ui
{ {
float const moveDist = bot->GetObjectSize() + go->GetObjectSize() + 0.1f; float const moveDist = bot->GetObjectSize() + go->GetObjectSize() + 0.1f;
return MoveTo(bot->GetMapId(), go->GetPositionX() + (urand(0, 1) ? -moveDist : moveDist), return MoveTo(bot->GetMapId(), go->GetPositionX() + (urand(0, 1) ? -moveDist : moveDist),
go->GetPositionY() + (urand(0, 1) ? -moveDist : moveDist), go->GetPositionZ()); go->GetPositionY() + (urand(0, 1) ? -moveDist : moveDist), go->GetPositionZ());
} }
// Dismount before capturing // Dismount before capturing
@ -3873,7 +3772,7 @@ bool BGTactics::atFlag(std::vector<BattleBotPath*> const& vPaths, std::vector<ui
if (dist < INTERACTION_DISTANCE) if (dist < INTERACTION_DISTANCE)
{ {
// Handle flag capture at base // Handle flag capture at base
if (isWsBaseFlag) if (atBase)
{ {
if (bot->GetTeamId() == TEAM_HORDE) if (bot->GetTeamId() == TEAM_HORDE)
{ {
@ -3912,50 +3811,28 @@ bool BGTactics::atFlag(std::vector<BattleBotPath*> const& vPaths, std::vector<ui
} }
} }
case BATTLEGROUND_EY: case BATTLEGROUND_EY:
{ // Handle Netherstorm flag capture requiring a channel { // Issue: Currently bots in EY take flag instantly without casttime
if (dist < INTERACTION_DISTANCE) if (dist < INTERACTION_DISTANCE)
{ {
// Dismount before interacting // Dismount before interacting
if (bot->IsMounted()) if (bot->IsMounted())
{
bot->RemoveAurasByType(SPELL_AURA_MOUNTED); bot->RemoveAurasByType(SPELL_AURA_MOUNTED);
}
if (bot->IsInDisallowedMountForm()) if (bot->IsInDisallowedMountForm())
{
bot->RemoveAurasByType(SPELL_AURA_MOD_SHAPESHIFT); bot->RemoveAurasByType(SPELL_AURA_MOD_SHAPESHIFT);
}
// Handle center flag differently (requires spell cast) // Handle center flag differently (requires spell cast)
if (isEyCenterFlag) if (atBase)
{ {
for (uint8 type = CURRENT_MELEE_SPELL; type <= CURRENT_CHANNELED_SPELL; ++type)
{
if (Spell* currentSpell = bot->GetCurrentSpell(static_cast<CurrentSpellTypes>(type)))
{
// m_spellInfo may be null in some states: protect access
if (currentSpell->m_spellInfo && currentSpell->m_spellInfo->Id == SPELL_CAPTURE_BANNER)
{
bot->StopMoving();
botAI->SetNextCheckDelay(500);
return true;
}
}
}
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(SPELL_CAPTURE_BANNER); SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(SPELL_CAPTURE_BANNER);
if (!spellInfo) if (!spellInfo)
return false; return false;
Spell* spell = new Spell(bot, spellInfo, TRIGGERED_NONE); Spell* spell = new Spell(bot, spellInfo, TRIGGERED_NONE);
spell->m_targets.SetGOTarget(go); spell->m_targets.SetGOTarget(go);
bot->StopMoving();
spell->prepare(&spell->m_targets); spell->prepare(&spell->m_targets);
botAI->WaitForSpellCast(spell); botAI->WaitForSpellCast(spell);
resetObjective(); //return true; Intended to make a bot cast SPELL_CAPTURE_BANNER and wait for spell finish, but doesn't work and causes infinite loop
return true;
} }
// Pick up dropped flag // Pick up dropped flag
@ -3972,8 +3849,8 @@ bool BGTactics::atFlag(std::vector<BattleBotPath*> const& vPaths, std::vector<ui
return MoveTo(bot->GetMapId(), go->GetPositionX(), go->GetPositionY(), go->GetPositionZ()); return MoveTo(bot->GetMapId(), go->GetPositionX(), go->GetPositionY(), go->GetPositionZ());
} }
} }
default: default:
break; break;
} }
} }