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

View File

@ -4,12 +4,10 @@
*/
#include "BattleGroundTactics.h"
#include <algorithm>
#include "BattleGroundJoinAction.h"
#include "ArenaTeam.h"
#include "ArenaTeamMgr.h"
#include "BattleGroundJoinAction.h"
#include "Battleground.h"
#include "BattlegroundAB.h"
#include "BattlegroundAV.h"
@ -24,12 +22,11 @@
#include "BattlegroundSA.h"
#include "BattlegroundWS.h"
#include "Event.h"
#include "GameObject.h"
#include "IVMapMgr.h"
#include "PathGenerator.h"
#include "Playerbots.h"
#include "PositionValue.h"
#include "PvpTriggers.h"
#include "PathGenerator.h"
#include "ServerFacade.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.GetPositionZ());
}
else // BB_WSG_WAIT_SPOT_SPAWN
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),
@ -3368,12 +3365,12 @@ bool BGTactics::resetObjective()
return false;
// Adjust role-change chance based on battleground type
uint32 oddsToChangeRole = 1; // default low
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)
else if (bgType == BATTLEGROUND_EY || bgType == BATTLEGROUND_IC || bgType == BATTLEGROUND_AB)
oddsToChangeRole = 1;
else if (bgType == BATTLEGROUND_AV)
oddsToChangeRole = 0;
@ -3581,16 +3578,6 @@ bool BGTactics::atFlag(std::vector<BattleBotPath*> const& vPaths, std::vector<ui
GuidVector closePlayers;
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
switch (bgType)
{
@ -3620,82 +3607,27 @@ bool BGTactics::atFlag(std::vector<BattleBotPath*> const& vPaths, std::vector<ui
if (closeObjects.empty())
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
GameObject* targetFlag = nullptr;
for (ObjectGuid const guid : closeObjects)
{
GameObject* go = botAI->GetGameObject(guid);
if (!go)
{
continue;
}
bool const isEyCenterFlag = eyeBg && eyCenterFlag && eyCenterFlag->GetGUID() == go->GetGUID();
// Check if this object is a valid capture target
std::vector<uint32>::const_iterator f = std::find(vFlagIds.begin(), vFlagIds.end(), go->GetEntry());
if (f == vFlagIds.end() && !isEyCenterFlag)
{
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;
@ -3723,7 +3655,7 @@ bool BGTactics::atFlag(std::vector<BattleBotPath*> const& vPaths, std::vector<ui
}
// 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
uint32 numCapturing = 0;
@ -3732,17 +3664,14 @@ bool BGTactics::atFlag(std::vector<BattleBotPath*> const& vPaths, std::vector<ui
{
if (Unit* pFriend = botAI->GetUnit(guid))
{
// Check if they're casting or channeling the capture spell
Spell* spell = pFriend->GetCurrentSpell(CURRENT_GENERIC_SPELL);
if (!spell)
// Check if they're casting the capture spell
if (Spell* spell = pFriend->GetCurrentSpell(CURRENT_GENERIC_SPELL))
{
spell = pFriend->GetCurrentSpell(CURRENT_CHANNELED_SPELL);
}
if (spell && spell->m_spellInfo && spell->m_spellInfo->Id == SPELL_CAPTURE_BANNER)
{
numCapturing++;
capturingPlayer = pFriend;
if (spell->m_spellInfo->Id == SPELL_CAPTURE_BANNER)
{
numCapturing++;
capturingPlayer = pFriend;
}
}
}
}
@ -3775,11 +3704,9 @@ bool BGTactics::atFlag(std::vector<BattleBotPath*> const& vPaths, std::vector<ui
if (!go)
continue;
bool const isEyCenterFlag = eyeBg && eyCenterFlag && eyCenterFlag->GetGUID() == go->GetGUID();
// Validate this is a capture target
std::vector<uint32>::const_iterator f = std::find(vFlagIds.begin(), vFlagIds.end(), go->GetEntry());
if (f == vFlagIds.end() && !isEyCenterFlag)
std::vector<uint32>::const_iterator f = find(vFlagIds.begin(), vFlagIds.end(), go->GetEntry());
if (f == vFlagIds.end())
continue;
// Check object is active
@ -3795,40 +3722,12 @@ bool BGTactics::atFlag(std::vector<BattleBotPath*> const& vPaths, std::vector<ui
continue;
// Special handling for WSG and EY base flags
bool isWsBaseFlag = bgType == BATTLEGROUND_WS && go->GetEntry() == vFlagsWS[bot->GetTeamId()];
bool isEyBaseFlag = bgType == BATTLEGROUND_EY && go->GetEntry() == vFlagsEY[0];
// 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();
}
}
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 (isWsBaseFlag && bgType == BATTLEGROUND_WS &&
if (atBase && bgType == BATTLEGROUND_WS &&
!(bot->HasAura(BG_WS_SPELL_WARSONG_FLAG) || bot->HasAura(BG_WS_SPELL_SILVERWING_FLAG)))
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;
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
@ -3873,7 +3772,7 @@ bool BGTactics::atFlag(std::vector<BattleBotPath*> const& vPaths, std::vector<ui
if (dist < INTERACTION_DISTANCE)
{
// Handle flag capture at base
if (isWsBaseFlag)
if (atBase)
{
if (bot->GetTeamId() == TEAM_HORDE)
{
@ -3912,50 +3811,28 @@ bool BGTactics::atFlag(std::vector<BattleBotPath*> const& vPaths, std::vector<ui
}
}
case BATTLEGROUND_EY:
{ // Handle Netherstorm flag capture requiring a channel
{ // 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 (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);
if (!spellInfo)
return false;
Spell* spell = new Spell(bot, spellInfo, TRIGGERED_NONE);
spell->m_targets.SetGOTarget(go);
bot->StopMoving();
spell->prepare(&spell->m_targets);
botAI->WaitForSpellCast(spell);
resetObjective();
return true;
//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
@ -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());
}
}
default:
break;
default:
break;
}
}