mirror of
https://github.com/mod-playerbots/mod-playerbots.git
synced 2026-02-08 05:01:09 +00:00
216 lines
8.0 KiB
C++
216 lines
8.0 KiB
C++
#include "RaidMcActions.h"
|
|
|
|
#include "Playerbots.h"
|
|
#include "RtiTargetValue.h"
|
|
#include "RaidMcTriggers.h"
|
|
#include "RaidMcHelpers.h"
|
|
|
|
static constexpr float LIVING_BOMB_DISTANCE = 20.0f;
|
|
static constexpr float INFERNO_DISTANCE = 20.0f;
|
|
|
|
// don't get hit by Arcane Explosion but still be in casting range
|
|
static constexpr float ARCANE_EXPLOSION_DISTANCE = 26.0f;
|
|
|
|
// dedicated tank positions; prevents assist tanks from positioning Core Ragers on steep walls on pull
|
|
static const Position GOLEMAGG_TANK_POSITION{795.7308, -994.8848, -207.18661};
|
|
static const Position CORE_RAGER_TANK_POSITION{846.6453, -1019.0639, -198.9819};
|
|
|
|
static constexpr float GOLEMAGGS_TRUST_DISTANCE = 30.0f;
|
|
static constexpr float CORE_RAGER_STEP_DISTANCE = 5.0f;
|
|
|
|
using namespace MoltenCoreHelpers;
|
|
|
|
bool McMoveFromGroupAction::Execute(Event event)
|
|
{
|
|
return MoveFromGroup(LIVING_BOMB_DISTANCE);
|
|
}
|
|
|
|
bool McMoveFromBaronGeddonAction::Execute(Event event)
|
|
{
|
|
if (Unit* boss = AI_VALUE2(Unit*, "find target", "baron geddon"))
|
|
{
|
|
float distToTravel = INFERNO_DISTANCE - bot->GetDistance2d(boss);
|
|
if (distToTravel > 0)
|
|
{
|
|
// Stop current spell first
|
|
bot->AttackStop();
|
|
bot->InterruptNonMeleeSpells(false);
|
|
|
|
return MoveAway(boss, distToTravel);
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool McShazzrahMoveAwayAction::Execute(Event event)
|
|
{
|
|
if (Unit* boss = AI_VALUE2(Unit*, "find target", "shazzrah"))
|
|
{
|
|
float distToTravel = ARCANE_EXPLOSION_DISTANCE - bot->GetDistance2d(boss);
|
|
if (distToTravel > 0)
|
|
return MoveAway(boss, distToTravel);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool McGolemaggMarkBossAction::Execute(Event event)
|
|
{
|
|
if (Unit* boss = AI_VALUE2(Unit*, "find target", "golemagg the incinerator"))
|
|
{
|
|
if (Group* group = bot->GetGroup())
|
|
{
|
|
ObjectGuid currentSkullGuid = group->GetTargetIcon(RtiTargetValue::skullIndex);
|
|
if (currentSkullGuid.IsEmpty() || currentSkullGuid != boss->GetGUID())
|
|
{
|
|
group->SetTargetIcon(RtiTargetValue::skullIndex, bot->GetGUID(), boss->GetGUID());
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool McGolemaggTankAction::MoveUnitToPosition(Unit* target, const Position& tankPosition, float maxDistance,
|
|
float stepDistance)
|
|
{
|
|
if (bot->GetVictim() != target)
|
|
return Attack(target);
|
|
if (target->GetVictim() == bot)
|
|
{
|
|
float distanceToTankPosition = bot->GetExactDist2d(tankPosition.GetPositionX(), tankPosition.GetPositionY());
|
|
if (distanceToTankPosition > maxDistance)
|
|
{
|
|
float dX = tankPosition.GetPositionX() - bot->GetPositionX();
|
|
float dY = tankPosition.GetPositionY() - bot->GetPositionY();
|
|
float dist = sqrt(dX * dX + dY * dY);
|
|
float moveX = bot->GetPositionX() + (dX / dist) * stepDistance;
|
|
float moveY = bot->GetPositionY() + (dY / dist) * stepDistance;
|
|
return MoveTo(bot->GetMapId(), moveX, moveY, bot->GetPositionZ(), false, false,
|
|
false, false, MovementPriority::MOVEMENT_COMBAT, true,
|
|
true);
|
|
}
|
|
}
|
|
else if (botAI->DoSpecificAction("taunt spell", Event(), true))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
bool McGolemaggTankAction::FindCoreRagers(Unit*& coreRager1, Unit*& coreRager2) const
|
|
{
|
|
coreRager1 = coreRager2 = nullptr;
|
|
for (auto const& target : AI_VALUE(GuidVector, "possible targets no los"))
|
|
{
|
|
Unit* unit = botAI->GetUnit(target);
|
|
if (unit && unit->IsAlive() && unit->GetEntry() == NPC_CORE_RAGER)
|
|
{
|
|
if (coreRager1 == nullptr)
|
|
coreRager1 = unit;
|
|
else if (coreRager2 == nullptr)
|
|
{
|
|
coreRager2 = unit;
|
|
break; // There should be no third Core Rager.
|
|
}
|
|
}
|
|
}
|
|
return coreRager1 != nullptr && coreRager2 != nullptr;
|
|
}
|
|
|
|
bool McGolemaggMainTankAttackGolemaggAction::Execute(Event event)
|
|
{
|
|
// At this point, we know we are not the last living tank in the group.
|
|
if (Unit* boss = AI_VALUE2(Unit*, "find target", "golemagg the incinerator"))
|
|
{
|
|
Unit* coreRager1;
|
|
Unit* coreRager2;
|
|
if (!FindCoreRagers(coreRager1, coreRager2))
|
|
return false; // safety check
|
|
|
|
// We only need to move if the Core Ragers still have Golemagg's Trust
|
|
if (coreRager1->HasAura(SPELL_GOLEMAGGS_TRUST) || coreRager2->HasAura(SPELL_GOLEMAGGS_TRUST))
|
|
return MoveUnitToPosition(boss, GOLEMAGG_TANK_POSITION, boss->GetCombatReach());
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool McGolemaggAssistTankAttackCoreRagerAction::Execute(Event event)
|
|
{
|
|
Unit* boss = AI_VALUE2(Unit*, "find target", "golemagg the incinerator");
|
|
if (!boss)
|
|
return false;
|
|
|
|
// Step 0: Filter additional assist tanks. We only need 2.
|
|
bool isFirstAssistTank = PlayerbotAI::IsAssistTankOfIndex(bot, 0, true);
|
|
bool isSecondAssistTank = PlayerbotAI::IsAssistTankOfIndex(bot, 1, true);
|
|
if (!isFirstAssistTank && !isSecondAssistTank)
|
|
return Attack(boss);
|
|
|
|
// Step 1: Find both Core Ragers
|
|
Unit* coreRager1;
|
|
Unit* coreRager2;
|
|
if (!FindCoreRagers(coreRager1, coreRager2))
|
|
return false; // safety check
|
|
|
|
// Step 2: Assign Core Rager to bot
|
|
Unit* myCoreRager = nullptr;
|
|
Unit* otherCoreRager = nullptr;
|
|
if (isFirstAssistTank)
|
|
{
|
|
myCoreRager = coreRager1;
|
|
otherCoreRager = coreRager2;
|
|
}
|
|
else // isSecondAssistTank is always true here
|
|
{
|
|
myCoreRager = coreRager2;
|
|
otherCoreRager = coreRager1;
|
|
}
|
|
|
|
// Step 3: Select the right target
|
|
if (myCoreRager->GetVictim() != bot)
|
|
{
|
|
// Step 3.1: My Core Rager isn't attacking me. Attack until it does.
|
|
if (bot->GetVictim() != myCoreRager)
|
|
return Attack(myCoreRager);
|
|
return botAI->DoSpecificAction("taunt spell", event, true);
|
|
}
|
|
|
|
Unit* otherCoreRagerVictim = otherCoreRager->GetVictim();
|
|
if (otherCoreRagerVictim) // Core Rager victim can be NULL
|
|
{
|
|
// Step 3.2: Check if the other Core Rager isn't attacking its assist tank.
|
|
Player* otherCoreRagerPlayerVictim = otherCoreRagerVictim->ToPlayer();
|
|
if (otherCoreRagerPlayerVictim &&
|
|
!PlayerbotAI::IsAssistTankOfIndex(otherCoreRagerPlayerVictim, 0, true) &&
|
|
!PlayerbotAI::IsAssistTankOfIndex(otherCoreRagerPlayerVictim, 1, true))
|
|
{
|
|
// Assume we are the only assist tank or the other assist tank is dead => pick up other Core Rager!
|
|
if (bot->GetVictim() != otherCoreRager)
|
|
return Attack(otherCoreRager);
|
|
return botAI->DoSpecificAction("taunt spell", event, true);
|
|
}
|
|
}
|
|
|
|
if (bot->GetVictim() != myCoreRager)
|
|
return Attack(myCoreRager); // Step 3.3: Attack our Core Rager in case we previously switched in 3.2.
|
|
|
|
// Step 4: Prevent Golemagg's Trust on Core Ragers
|
|
if (myCoreRager->HasAura(SPELL_GOLEMAGGS_TRUST) ||
|
|
(otherCoreRagerVictim == bot && otherCoreRager->HasAura(SPELL_GOLEMAGGS_TRUST)))
|
|
{
|
|
// Step 4.1: Move Core Ragers to dedicated tank position (only if Golemagg is far enough away from said position)
|
|
float bossDistanceToCoreRagerTankPosition = boss->GetExactDist2d(
|
|
CORE_RAGER_TANK_POSITION.GetPositionX(), CORE_RAGER_TANK_POSITION.GetPositionY());
|
|
if (bossDistanceToCoreRagerTankPosition > GOLEMAGGS_TRUST_DISTANCE)
|
|
{
|
|
float distanceToTankPosition = bot->GetExactDist2d(CORE_RAGER_TANK_POSITION.GetPositionX(),
|
|
CORE_RAGER_TANK_POSITION.GetPositionY());
|
|
if (distanceToTankPosition > CORE_RAGER_STEP_DISTANCE)
|
|
return MoveUnitToPosition(myCoreRager, CORE_RAGER_TANK_POSITION, CORE_RAGER_STEP_DISTANCE);
|
|
}
|
|
|
|
// Step 4.2: if boss is too close to tank position, or we are already there, move away from Golemagg to try to out-range Golemagg's Trust
|
|
return MoveAway(boss, CORE_RAGER_STEP_DISTANCE, true);
|
|
}
|
|
|
|
return false;
|
|
}
|