mirror of
https://github.com/mod-playerbots/mod-playerbots.git
synced 2026-01-13 00:58:33 +00:00
Improve Molten Core Strategy (#1852)
This is my first attempt of implementing playerbot strategies. A team of 40 can steamroll Molten Core relatively easy, even with lower item levels. Regardless, this PR adds resistance triggers and actions to mitigate some damage. Additionally, improvements were made for the encounters with Garr, Baron Geddon, Shazzrah and Golemagg. A short summary per boss is listed below. All planned features are included, but feedback is of course appreciated. ### Lucifron - Shadow resistance: mitigate damage from [Impending Doom](https://www.wowhead.com/classic/spell=19702/impending-doom) and [Shadow Shock](https://www.wowhead.com/classic/spell=19460/shadow-shock). ### Magmadar - Fire resistance: mitigate damage from [Lava Bomb](https://www.wowhead.com/classic/spell=19411/lava-bomb) and [Magma Spit](https://www.wowhead.com/classic/spell=19450/magma-spit). - Like King Dred and the fraction commander (Nexus), this fight might profit from an anti-fear strategy in order to counter [Panic](https://www.wowhead.com/classic/spell=19408/panic). Not implemented here. ### Gehennas - Shadow resistance: mitigate damage from [Shadow Bolt](https://www.wowhead.com/classic/spell=19728/shadow-bolt) and increase the chance to resist [Gehennas' Curse](https://www.wowhead.com/classic/spell=19716/gehennas-curse). ### Garr - Fire resistance: mitigate damage from the Firesworn adds ([Immolate](https://www.wowhead.com/classic/spell=20294/immolate) and [Eruption](https://www.wowhead.com/classic/spell=19497/eruption)). - Disabled dps aoe abilities via multiplier. This one is important because multiple exploding adds at once might delete bots rather quick... ### Baron Geddon - Refactored the existing strategy. - Fire resistance: mitigate damage from [Ignite Mana](https://www.wowhead.com/classic/spell=19659/ignite-mana), [Inferno](https://www.wowhead.com/classic/spell=19695/inferno) and [Living Bomb](https://www.wowhead.com/classic/spell=20475/living-bomb). - Better Inferno handling: Before moving away, bots stop attacking and interrupt their spells. Additionally, the new multiplier prevents bots from running back to Geddon while Inferno is still active. ### Shazzrah - Ranged bots now position themselves in a sweet spot that prevents them from getting hit with [Arcane Explosion](https://www.wowhead.com/classic/spell=19712/arcane-explosion) but still close enough to dps and heal. ### Sulfuron Harbinger - Fire resistance: mitigate damage from [Hand of Ragnaros](https://www.wowhead.com/classic/spell=19780/hand-of-ragnaros) and [Immolate](https://www.wowhead.com/classic/spell=20294/immolate). To be fair, this one is quite negligible... ### Golemagg - Fire resistance: mitigate damage from [Magma Splash](https://www.wowhead.com/classic/spell=13880/magma-splash) and [Pyroblast](https://www.wowhead.com/classic/spell=20228/pyroblast). - Disabled dps aoe abilities via multiplier. Kind of a preference on my side. Otherwise, the Core Ragers spam emotes about not wanting to die. ### Majordomo Executus - Shadow resistance: mitigate damage from [Aegis of Ragnaros](https://www.wowhead.com/classic/spell=20620/aegis-of-ragnaros), [Shadow Shock](https://www.wowhead.com/classic/spell=20603/shadow-shock) and [Shadow Bolt](https://www.wowhead.com/classic/spell=21077/shadow-bolt). This one is also negligible, TBF. ### Ragnaros - Fire resistance: mitigate damage from [Wrath of Ragnaros](https://www.wowhead.com/classic/spell=20566/wrath-of-ragnaros) and [Lava Burst](https://www.wowhead.com/classic/spell=21158/lava-burst).
This commit is contained in:
@@ -1459,7 +1459,7 @@ void PlayerbotAI::ApplyInstanceStrategies(uint32 mapId, bool tellMaster)
|
|||||||
strategyName = "onyxia"; // Onyxia's Lair
|
strategyName = "onyxia"; // Onyxia's Lair
|
||||||
break;
|
break;
|
||||||
case 409:
|
case 409:
|
||||||
strategyName = "mc"; // Molten Core
|
strategyName = "moltencore"; // Molten Core
|
||||||
break;
|
break;
|
||||||
case 469:
|
case 469:
|
||||||
strategyName = "bwl"; // Blackwing Lair
|
strategyName = "bwl"; // Blackwing Lair
|
||||||
@@ -2247,7 +2247,7 @@ uint32 PlayerbotAI::GetGroupTankNum(Player* player)
|
|||||||
|
|
||||||
bool PlayerbotAI::IsAssistTank(Player* player) { return IsTank(player) && !IsMainTank(player); }
|
bool PlayerbotAI::IsAssistTank(Player* player) { return IsTank(player) && !IsMainTank(player); }
|
||||||
|
|
||||||
bool PlayerbotAI::IsAssistTankOfIndex(Player* player, int index)
|
bool PlayerbotAI::IsAssistTankOfIndex(Player* player, int index, bool ignoreDeadPlayers)
|
||||||
{
|
{
|
||||||
Group* group = player->GetGroup();
|
Group* group = player->GetGroup();
|
||||||
if (!group)
|
if (!group)
|
||||||
@@ -2264,6 +2264,9 @@ bool PlayerbotAI::IsAssistTankOfIndex(Player* player, int index)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ignoreDeadPlayers && !member->IsAlive())
|
||||||
|
continue;
|
||||||
|
|
||||||
if (group->IsAssistant(member->GetGUID()) && IsAssistTank(member))
|
if (group->IsAssistant(member->GetGUID()) && IsAssistTank(member))
|
||||||
{
|
{
|
||||||
if (index == counter)
|
if (index == counter)
|
||||||
@@ -2283,6 +2286,9 @@ bool PlayerbotAI::IsAssistTankOfIndex(Player* player, int index)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ignoreDeadPlayers && !member->IsAlive())
|
||||||
|
continue;
|
||||||
|
|
||||||
if (!group->IsAssistant(member->GetGUID()) && IsAssistTank(member))
|
if (!group->IsAssistant(member->GetGUID()) && IsAssistTank(member))
|
||||||
{
|
{
|
||||||
if (index == counter)
|
if (index == counter)
|
||||||
|
|||||||
@@ -428,7 +428,7 @@ public:
|
|||||||
static bool IsMainTank(Player* player);
|
static bool IsMainTank(Player* player);
|
||||||
static uint32 GetGroupTankNum(Player* player);
|
static uint32 GetGroupTankNum(Player* player);
|
||||||
static bool IsAssistTank(Player* player);
|
static bool IsAssistTank(Player* player);
|
||||||
static bool IsAssistTankOfIndex(Player* player, int index);
|
static bool IsAssistTankOfIndex(Player* player, int index, bool ignoreDeadPlayers = false);
|
||||||
static bool IsHealAssistantOfIndex(Player* player, int index);
|
static bool IsHealAssistantOfIndex(Player* player, int index);
|
||||||
static bool IsRangedDpsAssistantOfIndex(Player* player, int index);
|
static bool IsRangedDpsAssistantOfIndex(Player* player, int index);
|
||||||
bool HasAggro(Unit* unit);
|
bool HasAggro(Unit* unit);
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ public:
|
|||||||
RaidStrategyContext() : NamedObjectContext<Strategy>(false, true)
|
RaidStrategyContext() : NamedObjectContext<Strategy>(false, true)
|
||||||
{
|
{
|
||||||
creators["aq20"] = &RaidStrategyContext::aq20;
|
creators["aq20"] = &RaidStrategyContext::aq20;
|
||||||
creators["mc"] = &RaidStrategyContext::mc;
|
creators["moltencore"] = &RaidStrategyContext::moltencore;
|
||||||
creators["bwl"] = &RaidStrategyContext::bwl;
|
creators["bwl"] = &RaidStrategyContext::bwl;
|
||||||
creators["karazhan"] = &RaidStrategyContext::karazhan;
|
creators["karazhan"] = &RaidStrategyContext::karazhan;
|
||||||
creators["magtheridon"] = &RaidStrategyContext::magtheridon;
|
creators["magtheridon"] = &RaidStrategyContext::magtheridon;
|
||||||
@@ -38,7 +38,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
static Strategy* aq20(PlayerbotAI* botAI) { return new RaidAq20Strategy(botAI); }
|
static Strategy* aq20(PlayerbotAI* botAI) { return new RaidAq20Strategy(botAI); }
|
||||||
static Strategy* mc(PlayerbotAI* botAI) { return new RaidMcStrategy(botAI); }
|
static Strategy* moltencore(PlayerbotAI* botAI) { return new RaidMcStrategy(botAI); }
|
||||||
static Strategy* bwl(PlayerbotAI* botAI) { return new RaidBwlStrategy(botAI); }
|
static Strategy* bwl(PlayerbotAI* botAI) { return new RaidBwlStrategy(botAI); }
|
||||||
static Strategy* karazhan(PlayerbotAI* botAI) { return new RaidKarazhanStrategy(botAI); }
|
static Strategy* karazhan(PlayerbotAI* botAI) { return new RaidKarazhanStrategy(botAI); }
|
||||||
static Strategy* magtheridon(PlayerbotAI* botAI) { return new RaidMagtheridonStrategy(botAI); }
|
static Strategy* magtheridon(PlayerbotAI* botAI) { return new RaidMagtheridonStrategy(botAI); }
|
||||||
|
|||||||
@@ -10,13 +10,39 @@ class RaidMcActionContext : public NamedObjectContext<Action>
|
|||||||
public:
|
public:
|
||||||
RaidMcActionContext()
|
RaidMcActionContext()
|
||||||
{
|
{
|
||||||
creators["mc check should move from group"] = &RaidMcActionContext::check_should_move_from_group;
|
creators["mc lucifron shadow resistance"] = &RaidMcActionContext::lucifron_shadow_resistance;
|
||||||
|
creators["mc magmadar fire resistance"] = &RaidMcActionContext::magmadar_fire_resistance;
|
||||||
|
creators["mc gehennas shadow resistance"] = &RaidMcActionContext::gehennas_shadow_resistance;
|
||||||
|
creators["mc garr fire resistance"] = &RaidMcActionContext::garr_fire_resistance;
|
||||||
|
creators["mc baron geddon fire resistance"] = &RaidMcActionContext::baron_geddon_fire_resistance;
|
||||||
|
creators["mc move from group"] = &RaidMcActionContext::check_should_move_from_group;
|
||||||
creators["mc move from baron geddon"] = &RaidMcActionContext::move_from_baron_geddon;
|
creators["mc move from baron geddon"] = &RaidMcActionContext::move_from_baron_geddon;
|
||||||
|
creators["mc shazzrah move away"] = &RaidMcActionContext::shazzrah_move_away;
|
||||||
|
creators["mc sulfuron harbinger fire resistance"] = &RaidMcActionContext::sulfuron_harbinger_fire_resistance;
|
||||||
|
creators["mc golemagg fire resistance"] = &RaidMcActionContext::golemagg_fire_resistance;
|
||||||
|
creators["mc golemagg mark boss"] = &RaidMcActionContext::golemagg_mark_boss;
|
||||||
|
creators["mc golemagg main tank attack golemagg"] = &RaidMcActionContext::golemagg_main_tank_attack_golemagg;
|
||||||
|
creators["mc golemagg assist tank attack core rager"] = &RaidMcActionContext::golemagg_assist_tank_attack_core_rager;
|
||||||
|
creators["mc majordomo shadow resistance"] = &RaidMcActionContext::majordomo_shadow_resistance;
|
||||||
|
creators["mc ragnaros fire resistance"] = &RaidMcActionContext::ragnaros_fire_resistance;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static Action* check_should_move_from_group(PlayerbotAI* ai) { return new McCheckShouldMoveFromGroupAction(ai); }
|
static Action* lucifron_shadow_resistance(PlayerbotAI* botAI) { return new BossShadowResistanceAction(botAI, "lucifron"); }
|
||||||
static Action* move_from_baron_geddon(PlayerbotAI* ai) { return new McMoveFromBaronGeddonAction(ai); }
|
static Action* magmadar_fire_resistance(PlayerbotAI* botAI) { return new BossFireResistanceAction(botAI, "magmadar"); }
|
||||||
|
static Action* gehennas_shadow_resistance(PlayerbotAI* botAI) { return new BossShadowResistanceAction(botAI, "gehennas"); }
|
||||||
|
static Action* garr_fire_resistance(PlayerbotAI* botAI) { return new BossFireResistanceAction(botAI, "garr"); }
|
||||||
|
static Action* baron_geddon_fire_resistance(PlayerbotAI* botAI) { return new BossFireResistanceAction(botAI, "baron geddon"); }
|
||||||
|
static Action* check_should_move_from_group(PlayerbotAI* botAI) { return new McMoveFromGroupAction(botAI); }
|
||||||
|
static Action* move_from_baron_geddon(PlayerbotAI* botAI) { return new McMoveFromBaronGeddonAction(botAI); }
|
||||||
|
static Action* shazzrah_move_away(PlayerbotAI* botAI) { return new McShazzrahMoveAwayAction(botAI); }
|
||||||
|
static Action* sulfuron_harbinger_fire_resistance(PlayerbotAI* botAI) { return new BossFireResistanceAction(botAI, "sulfuron harbinger"); }
|
||||||
|
static Action* golemagg_fire_resistance(PlayerbotAI* botAI) { return new BossFireResistanceAction(botAI, "golemagg the incinerator"); }
|
||||||
|
static Action* golemagg_mark_boss(PlayerbotAI* botAI) { return new McGolemaggMarkBossAction(botAI); }
|
||||||
|
static Action* golemagg_main_tank_attack_golemagg(PlayerbotAI* botAI) { return new McGolemaggMainTankAttackGolemaggAction(botAI); }
|
||||||
|
static Action* golemagg_assist_tank_attack_core_rager(PlayerbotAI* botAI) { return new McGolemaggAssistTankAttackCoreRagerAction(botAI); }
|
||||||
|
static Action* majordomo_shadow_resistance(PlayerbotAI* botAI) { return new BossShadowResistanceAction(botAI, "majordomo executus"); }
|
||||||
|
static Action* ragnaros_fire_resistance(PlayerbotAI* botAI) { return new BossFireResistanceAction(botAI, "ragnaros"); }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,43 +1,215 @@
|
|||||||
#include "RaidMcActions.h"
|
#include "RaidMcActions.h"
|
||||||
|
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
|
#include "RtiTargetValue.h"
|
||||||
|
#include "RaidMcTriggers.h"
|
||||||
|
#include "RaidMcHelpers.h"
|
||||||
|
|
||||||
bool McCheckShouldMoveFromGroupAction::Execute(Event event)
|
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)
|
||||||
{
|
{
|
||||||
if (bot->HasAura(20475)) // barron geddon's living bomb
|
return MoveFromGroup(LIVING_BOMB_DISTANCE);
|
||||||
{
|
|
||||||
if (!botAI->HasStrategy("move from group", BotState::BOT_STATE_COMBAT))
|
|
||||||
{
|
|
||||||
// add/remove from both for now as it will make it more obvious to
|
|
||||||
// player if this strat remains on after fight somehow
|
|
||||||
botAI->ChangeStrategy("+move from group", BOT_STATE_NON_COMBAT);
|
|
||||||
botAI->ChangeStrategy("+move from group", BOT_STATE_COMBAT);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (botAI->HasStrategy("move from group", BotState::BOT_STATE_COMBAT))
|
|
||||||
{
|
|
||||||
// add/remove from both for now as it will make it more obvious to
|
|
||||||
// player if this strat remains on after fight somehow
|
|
||||||
botAI->ChangeStrategy("-move from group", BOT_STATE_NON_COMBAT);
|
|
||||||
botAI->ChangeStrategy("-move from group", BOT_STATE_COMBAT);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool McMoveFromBaronGeddonAction::Execute(Event event)
|
bool McMoveFromBaronGeddonAction::Execute(Event event)
|
||||||
{
|
{
|
||||||
const float radius = 25.0f; // more than should be needed but bots keep trying to run back in
|
|
||||||
if (Unit* boss = AI_VALUE2(Unit*, "find target", "baron geddon"))
|
if (Unit* boss = AI_VALUE2(Unit*, "find target", "baron geddon"))
|
||||||
{
|
{
|
||||||
long distToTravel = radius - bot->GetDistance(boss);
|
float distToTravel = INFERNO_DISTANCE - bot->GetDistance2d(boss);
|
||||||
if (distToTravel > 0)
|
if (distToTravel > 0)
|
||||||
{
|
{
|
||||||
// float angle = bot->GetAngle(boss) + M_PI;
|
// Stop current spell first
|
||||||
// return Move(angle, distToTravel);
|
bot->AttackStop();
|
||||||
|
bot->InterruptNonMeleeSpells(false);
|
||||||
|
|
||||||
return MoveAway(boss, distToTravel);
|
return MoveAway(boss, distToTravel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
#ifndef _PLAYERBOT_RAIDMCACTIONS_H
|
#ifndef _PLAYERBOT_RAIDMCACTIONS_H
|
||||||
#define _PLAYERBOT_RAIDMCACTIONS_H
|
#define _PLAYERBOT_RAIDMCACTIONS_H
|
||||||
|
|
||||||
|
#include "AttackAction.h"
|
||||||
#include "MovementActions.h"
|
#include "MovementActions.h"
|
||||||
#include "PlayerbotAI.h"
|
#include "PlayerbotAI.h"
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
|
|
||||||
class McCheckShouldMoveFromGroupAction : public Action
|
class McMoveFromGroupAction : public MovementAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
McCheckShouldMoveFromGroupAction(PlayerbotAI* botAI, std::string const name = "mc check should move from group")
|
McMoveFromGroupAction(PlayerbotAI* botAI, std::string const name = "mc move from group")
|
||||||
: Action(botAI, name) {}
|
: MovementAction(botAI, name) {}
|
||||||
bool Execute(Event event) override;
|
bool Execute(Event event) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -21,4 +22,46 @@ public:
|
|||||||
bool Execute(Event event) override;
|
bool Execute(Event event) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class McShazzrahMoveAwayAction : public MovementAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
McShazzrahMoveAwayAction(PlayerbotAI* botAI, std::string const name = "mc shazzrah move away")
|
||||||
|
: MovementAction(botAI, name) {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class McGolemaggMarkBossAction : public Action
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
McGolemaggMarkBossAction(PlayerbotAI* botAI, std::string const name = "mc golemagg mark boss")
|
||||||
|
: Action(botAI, name) {};
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class McGolemaggTankAction : public AttackAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
McGolemaggTankAction(PlayerbotAI* botAI, std::string const name)
|
||||||
|
: AttackAction(botAI, name) {}
|
||||||
|
protected:
|
||||||
|
bool MoveUnitToPosition(Unit* target, const Position& tankPosition, float maxDistance, float stepDistance = 3.0f);
|
||||||
|
bool FindCoreRagers(Unit*& coreRager1, Unit*& coreRager2) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class McGolemaggMainTankAttackGolemaggAction : public McGolemaggTankAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
McGolemaggMainTankAttackGolemaggAction(PlayerbotAI* botAI, std::string const name = "mc golemagg main tank attack golemagg")
|
||||||
|
: McGolemaggTankAction(botAI, name) {};
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class McGolemaggAssistTankAttackCoreRagerAction : public McGolemaggTankAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
McGolemaggAssistTankAttackCoreRagerAction(PlayerbotAI* botAI, std::string const name = "mc golemagg assist tank attack core rager")
|
||||||
|
: McGolemaggTankAction(botAI, name) {};
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
22
src/strategy/raids/moltencore/RaidMcHelpers.h
Normal file
22
src/strategy/raids/moltencore/RaidMcHelpers.h
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
#ifndef _PLAYERBOT_RAIDMCHELPERS_H
|
||||||
|
#define _PLAYERBOT_RAIDMCHELPERS_H
|
||||||
|
|
||||||
|
namespace MoltenCoreHelpers
|
||||||
|
{
|
||||||
|
enum MoltenCoreNPCs
|
||||||
|
{
|
||||||
|
// Golemagg
|
||||||
|
NPC_CORE_RAGER = 11672,
|
||||||
|
};
|
||||||
|
enum MoltenCoreSpells
|
||||||
|
{
|
||||||
|
// Baron Geddon
|
||||||
|
SPELL_INFERNO = 19695,
|
||||||
|
SPELL_LIVING_BOMB = 20475,
|
||||||
|
|
||||||
|
// Golemagg
|
||||||
|
SPELL_GOLEMAGGS_TRUST = 20553,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
117
src/strategy/raids/moltencore/RaidMcMultipliers.cpp
Normal file
117
src/strategy/raids/moltencore/RaidMcMultipliers.cpp
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
#include "RaidMcMultipliers.h"
|
||||||
|
|
||||||
|
#include "Playerbots.h"
|
||||||
|
#include "ChooseTargetActions.h"
|
||||||
|
#include "GenericSpellActions.h"
|
||||||
|
#include "DruidActions.h"
|
||||||
|
#include "HunterActions.h"
|
||||||
|
#include "PaladinActions.h"
|
||||||
|
#include "ShamanActions.h"
|
||||||
|
#include "WarriorActions.h"
|
||||||
|
#include "DKActions.h"
|
||||||
|
#include "RaidMcActions.h"
|
||||||
|
#include "RaidMcHelpers.h"
|
||||||
|
|
||||||
|
using namespace MoltenCoreHelpers;
|
||||||
|
|
||||||
|
static bool IsDpsBotWithAoeAction(Player* bot, Action* action)
|
||||||
|
{
|
||||||
|
if (PlayerbotAI::IsDps(bot))
|
||||||
|
{
|
||||||
|
if (dynamic_cast<DpsAoeAction*>(action) || dynamic_cast<CastConsecrationAction*>(action) ||
|
||||||
|
dynamic_cast<CastStarfallAction*>(action) || dynamic_cast<CastWhirlwindAction*>(action) ||
|
||||||
|
dynamic_cast<CastMagmaTotemAction*>(action) || dynamic_cast<CastExplosiveTrapAction*>(action) ||
|
||||||
|
dynamic_cast<CastDeathAndDecayAction*>(action))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (auto castSpellAction = dynamic_cast<CastSpellAction*>(action))
|
||||||
|
{
|
||||||
|
if (castSpellAction->getThreatType() == Action::ActionThreatType::Aoe)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
float GarrDisableDpsAoeMultiplier::GetValue(Action* action)
|
||||||
|
{
|
||||||
|
if (AI_VALUE2(Unit*, "find target", "garr"))
|
||||||
|
{
|
||||||
|
if (IsDpsBotWithAoeAction(bot, action))
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool IsAllowedGeddonMovementAction(Action* action)
|
||||||
|
{
|
||||||
|
if (dynamic_cast<MovementAction*>(action) &&
|
||||||
|
!dynamic_cast<McMoveFromGroupAction*>(action) &&
|
||||||
|
!dynamic_cast<McMoveFromBaronGeddonAction*>(action))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (dynamic_cast<CastReachTargetSpellAction*>(action))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
float BaronGeddonAbilityMultiplier::GetValue(Action* action)
|
||||||
|
{
|
||||||
|
if (Unit* boss = AI_VALUE2(Unit*, "find target", "baron geddon"))
|
||||||
|
{
|
||||||
|
if (boss->HasAura(SPELL_INFERNO))
|
||||||
|
{
|
||||||
|
if (!IsAllowedGeddonMovementAction(action))
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No check for Baron Geddon, because bots may have the bomb even after Geddon died.
|
||||||
|
if (bot->HasAura(SPELL_LIVING_BOMB))
|
||||||
|
{
|
||||||
|
if (!IsAllowedGeddonMovementAction(action))
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool IsSingleLivingTankInGroup(Player* bot)
|
||||||
|
{
|
||||||
|
if (Group* group = bot->GetGroup())
|
||||||
|
{
|
||||||
|
for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
|
||||||
|
{
|
||||||
|
Player* member = itr->GetSource();
|
||||||
|
if (!member || !member->IsAlive() || member == bot)
|
||||||
|
continue;
|
||||||
|
if (PlayerbotAI::IsTank(member))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
float GolemaggMultiplier::GetValue(Action* action)
|
||||||
|
{
|
||||||
|
if (AI_VALUE2(Unit*, "find target", "golemagg the incinerator"))
|
||||||
|
{
|
||||||
|
if (PlayerbotAI::IsTank(bot) && IsSingleLivingTankInGroup(bot))
|
||||||
|
{
|
||||||
|
// Only one tank => Pick up Golemagg and the two Core Ragers
|
||||||
|
if (dynamic_cast<McGolemaggMainTankAttackGolemaggAction*>(action) ||
|
||||||
|
dynamic_cast<McGolemaggAssistTankAttackCoreRagerAction*>(action))
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
if (PlayerbotAI::IsAssistTank(bot))
|
||||||
|
{
|
||||||
|
// The first two assist tanks manage the Core Ragers. The remaining assist tanks attack the boss.
|
||||||
|
if (dynamic_cast<TankAssistAction*>(action))
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
if (IsDpsBotWithAoeAction(bot, action))
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
27
src/strategy/raids/moltencore/RaidMcMultipliers.h
Normal file
27
src/strategy/raids/moltencore/RaidMcMultipliers.h
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
#ifndef _PLAYERBOT_RAIDMCMULTIPLIERS_H
|
||||||
|
#define _PLAYERBOT_RAIDMCMULTIPLIERS_H
|
||||||
|
|
||||||
|
#include "Multiplier.h"
|
||||||
|
|
||||||
|
class GarrDisableDpsAoeMultiplier : public Multiplier
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GarrDisableDpsAoeMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "garr disable dps aoe multiplier") {}
|
||||||
|
float GetValue(Action* action) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class BaronGeddonAbilityMultiplier : public Multiplier
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BaronGeddonAbilityMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "baron geddon ability multiplier") {}
|
||||||
|
float GetValue(Action* action) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class GolemaggMultiplier : public Multiplier
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GolemaggMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "golemagg multiplier") {}
|
||||||
|
float GetValue(Action* action) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,13 +1,81 @@
|
|||||||
#include "RaidMcStrategy.h"
|
#include "RaidMcStrategy.h"
|
||||||
|
|
||||||
|
#include "RaidMcMultipliers.h"
|
||||||
#include "Strategy.h"
|
#include "Strategy.h"
|
||||||
|
|
||||||
void RaidMcStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
void RaidMcStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||||
{
|
{
|
||||||
|
// Lucifron
|
||||||
|
triggers.push_back(
|
||||||
|
new TriggerNode("mc lucifron shadow resistance",
|
||||||
|
NextAction::array(0, new NextAction("mc lucifron shadow resistance", ACTION_RAID), nullptr)));
|
||||||
|
|
||||||
|
// Magmadar
|
||||||
|
// TODO: Fear ward / tremor totem, or general anti-fear strat development. Same as King Dred (Drak'Tharon) and faction commander (Nexus).
|
||||||
|
triggers.push_back(
|
||||||
|
new TriggerNode("mc magmadar fire resistance",
|
||||||
|
NextAction::array(0, new NextAction("mc magmadar fire resistance", ACTION_RAID), nullptr)));
|
||||||
|
|
||||||
|
// Gehennas
|
||||||
|
triggers.push_back(
|
||||||
|
new TriggerNode("mc gehennas shadow resistance",
|
||||||
|
NextAction::array(0, new NextAction("mc gehennas shadow resistance", ACTION_RAID), nullptr)));
|
||||||
|
|
||||||
|
// Garr
|
||||||
|
triggers.push_back(
|
||||||
|
new TriggerNode("mc garr fire resistance",
|
||||||
|
NextAction::array(0, new NextAction("mc garr fire resistance", ACTION_RAID), nullptr)));
|
||||||
|
|
||||||
|
// Baron Geddon
|
||||||
|
triggers.push_back(
|
||||||
|
new TriggerNode("mc baron geddon fire resistance",
|
||||||
|
NextAction::array(0, new NextAction("mc baron geddon fire resistance", ACTION_RAID), nullptr)));
|
||||||
triggers.push_back(
|
triggers.push_back(
|
||||||
new TriggerNode("mc living bomb debuff",
|
new TriggerNode("mc living bomb debuff",
|
||||||
NextAction::array(0, new NextAction("mc check should move from group", ACTION_RAID), nullptr)));
|
NextAction::array(0, new NextAction("mc move from group", ACTION_RAID), nullptr)));
|
||||||
triggers.push_back(
|
triggers.push_back(
|
||||||
new TriggerNode("mc baron geddon inferno",
|
new TriggerNode("mc baron geddon inferno",
|
||||||
NextAction::array(0, new NextAction("mc move from baron geddon", ACTION_RAID), nullptr)));
|
NextAction::array(0, new NextAction("mc move from baron geddon", ACTION_RAID), nullptr)));
|
||||||
|
|
||||||
|
// Shazzrah
|
||||||
|
triggers.push_back(
|
||||||
|
new TriggerNode("mc shazzrah ranged",
|
||||||
|
NextAction::array(0, new NextAction("mc shazzrah move away", ACTION_RAID), nullptr)));
|
||||||
|
|
||||||
|
// Sulfuron Harbinger
|
||||||
|
// Alternatively, shadow resistance is also possible.
|
||||||
|
triggers.push_back(
|
||||||
|
new TriggerNode("mc sulfuron harbinger fire resistance",
|
||||||
|
NextAction::array(0, new NextAction("mc sulfuron harbinger fire resistance", ACTION_RAID), nullptr)));
|
||||||
|
|
||||||
|
// Golemagg the Incinerator
|
||||||
|
triggers.push_back(
|
||||||
|
new TriggerNode("mc golemagg fire resistance",
|
||||||
|
NextAction::array(0, new NextAction("mc golemagg fire resistance", ACTION_RAID), nullptr)));
|
||||||
|
triggers.push_back(
|
||||||
|
new TriggerNode("mc golemagg mark boss",
|
||||||
|
NextAction::array(0, new NextAction("mc golemagg mark boss", ACTION_RAID), nullptr)));
|
||||||
|
triggers.push_back(
|
||||||
|
new TriggerNode("mc golemagg is main tank",
|
||||||
|
NextAction::array(0, new NextAction("mc golemagg main tank attack golemagg", ACTION_RAID), nullptr)));
|
||||||
|
triggers.push_back(
|
||||||
|
new TriggerNode("mc golemagg is assist tank",
|
||||||
|
NextAction::array(0, new NextAction("mc golemagg assist tank attack core rager", ACTION_RAID), nullptr)));
|
||||||
|
|
||||||
|
// Majordomo Executus
|
||||||
|
triggers.push_back(
|
||||||
|
new TriggerNode("mc majordomo shadow resistance",
|
||||||
|
NextAction::array(0, new NextAction("mc majordomo shadow resistance", ACTION_RAID), nullptr)));
|
||||||
|
|
||||||
|
// Ragnaros
|
||||||
|
triggers.push_back(
|
||||||
|
new TriggerNode("mc ragnaros fire resistance",
|
||||||
|
NextAction::array(0, new NextAction("mc ragnaros fire resistance", ACTION_RAID), nullptr)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void RaidMcStrategy::InitMultipliers(std::vector<Multiplier*>& multipliers)
|
||||||
|
{
|
||||||
|
multipliers.push_back(new GarrDisableDpsAoeMultiplier(botAI));
|
||||||
|
multipliers.push_back(new BaronGeddonAbilityMultiplier(botAI));
|
||||||
|
multipliers.push_back(new GolemaggMultiplier(botAI));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,10 +8,10 @@
|
|||||||
class RaidMcStrategy : public Strategy
|
class RaidMcStrategy : public Strategy
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
RaidMcStrategy(PlayerbotAI* ai) : Strategy(ai) {}
|
RaidMcStrategy(PlayerbotAI* botAI) : Strategy(botAI) {}
|
||||||
virtual std::string const getName() override { return "mc"; }
|
std::string const getName() override { return "moltencore"; }
|
||||||
virtual void InitTriggers(std::vector<TriggerNode*>& triggers) override;
|
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
|
||||||
// virtual void InitMultipliers(std::vector<Multiplier*> &multipliers) override;
|
void InitMultipliers(std::vector<Multiplier*> &multipliers) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -10,13 +10,39 @@ class RaidMcTriggerContext : public NamedObjectContext<Trigger>
|
|||||||
public:
|
public:
|
||||||
RaidMcTriggerContext()
|
RaidMcTriggerContext()
|
||||||
{
|
{
|
||||||
|
creators["mc lucifron shadow resistance"] = &RaidMcTriggerContext::lucifron_shadow_resistance;
|
||||||
|
creators["mc magmadar fire resistance"] = &RaidMcTriggerContext::magmadar_fire_resistance;
|
||||||
|
creators["mc gehennas shadow resistance"] = &RaidMcTriggerContext::gehennas_shadow_resistance;
|
||||||
|
creators["mc garr fire resistance"] = &RaidMcTriggerContext::garr_fire_resistance;
|
||||||
|
creators["mc baron geddon fire resistance"] = &RaidMcTriggerContext::baron_geddon_fire_resistance;
|
||||||
creators["mc living bomb debuff"] = &RaidMcTriggerContext::living_bomb_debuff;
|
creators["mc living bomb debuff"] = &RaidMcTriggerContext::living_bomb_debuff;
|
||||||
creators["mc baron geddon inferno"] = &RaidMcTriggerContext::baron_geddon_inferno;
|
creators["mc baron geddon inferno"] = &RaidMcTriggerContext::baron_geddon_inferno;
|
||||||
|
creators["mc shazzrah ranged"] = &RaidMcTriggerContext::shazzrah_ranged;
|
||||||
|
creators["mc sulfuron harbinger fire resistance"] = &RaidMcTriggerContext::sulfuron_harbinger_fire_resistance;
|
||||||
|
creators["mc golemagg fire resistance"] = &RaidMcTriggerContext::golemagg_fire_resistance;
|
||||||
|
creators["mc golemagg mark boss"] = &RaidMcTriggerContext::golemagg_mark_boss;
|
||||||
|
creators["mc golemagg is main tank"] = &RaidMcTriggerContext::golemagg_is_main_tank;
|
||||||
|
creators["mc golemagg is assist tank"] = &RaidMcTriggerContext::golemagg_is_assist_tank;
|
||||||
|
creators["mc majordomo shadow resistance"] = &RaidMcTriggerContext::majordomo_shadow_resistance;
|
||||||
|
creators["mc ragnaros fire resistance"] = &RaidMcTriggerContext::ragnaros_fire_resistance;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static Trigger* living_bomb_debuff(PlayerbotAI* ai) { return new McLivingBombDebuffTrigger(ai); }
|
static Trigger* lucifron_shadow_resistance(PlayerbotAI* botAI) { return new BossShadowResistanceTrigger(botAI, "lucifron"); }
|
||||||
static Trigger* baron_geddon_inferno(PlayerbotAI* ai) { return new McBaronGeddonInfernoTrigger(ai); }
|
static Trigger* magmadar_fire_resistance(PlayerbotAI* botAI) { return new BossFireResistanceTrigger(botAI, "magmadar"); }
|
||||||
|
static Trigger* gehennas_shadow_resistance(PlayerbotAI* botAI) { return new BossShadowResistanceTrigger(botAI, "gehennas"); }
|
||||||
|
static Trigger* garr_fire_resistance(PlayerbotAI* botAI) { return new BossFireResistanceTrigger(botAI, "garr"); }
|
||||||
|
static Trigger* baron_geddon_fire_resistance(PlayerbotAI* botAI) { return new BossFireResistanceTrigger(botAI, "baron geddon"); }
|
||||||
|
static Trigger* living_bomb_debuff(PlayerbotAI* botAI) { return new McLivingBombDebuffTrigger(botAI); }
|
||||||
|
static Trigger* baron_geddon_inferno(PlayerbotAI* botAI) { return new McBaronGeddonInfernoTrigger(botAI); }
|
||||||
|
static Trigger* shazzrah_ranged(PlayerbotAI* botAI) { return new McShazzrahRangedTrigger(botAI); }
|
||||||
|
static Trigger* sulfuron_harbinger_fire_resistance(PlayerbotAI* botAI) { return new BossFireResistanceTrigger(botAI, "sulfuron harbinger"); }
|
||||||
|
static Trigger* golemagg_fire_resistance(PlayerbotAI* botAI) { return new BossFireResistanceTrigger(botAI, "golemagg the incinerator"); }
|
||||||
|
static Trigger* golemagg_mark_boss(PlayerbotAI* botAI) { return new McGolemaggMarkBossTrigger(botAI); }
|
||||||
|
static Trigger* golemagg_is_main_tank(PlayerbotAI* botAI) { return new McGolemaggIsMainTankTrigger(botAI); }
|
||||||
|
static Trigger* golemagg_is_assist_tank(PlayerbotAI* botAI) { return new McGolemaggIsAssistTankTrigger(botAI); }
|
||||||
|
static Trigger* majordomo_shadow_resistance(PlayerbotAI* botAI) { return new BossShadowResistanceTrigger(botAI, "majordomo executus"); }
|
||||||
|
static Trigger* ragnaros_fire_resistance(PlayerbotAI* botAI) { return new BossFireResistanceTrigger(botAI, "ragnaros"); }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,22 +1,40 @@
|
|||||||
#include "RaidMcTriggers.h"
|
#include "RaidMcTriggers.h"
|
||||||
|
|
||||||
#include "SharedDefines.h"
|
#include "SharedDefines.h"
|
||||||
|
#include "RaidMcHelpers.h"
|
||||||
|
|
||||||
|
using namespace MoltenCoreHelpers;
|
||||||
|
|
||||||
bool McLivingBombDebuffTrigger::IsActive()
|
bool McLivingBombDebuffTrigger::IsActive()
|
||||||
{
|
{
|
||||||
// if bot has barron geddon's living bomb, we need to add strat, otherwise we need to remove
|
// No check for Baron Geddon, because bots may have the bomb even after Geddon died.
|
||||||
// only do when fighting baron geddon (to avoid modifying strat set by player outside this fight)
|
return bot->HasAura(SPELL_LIVING_BOMB);
|
||||||
if (Unit* boss = AI_VALUE2(Unit*, "find target", "baron geddon"))
|
|
||||||
{
|
|
||||||
if (boss->IsInCombat())
|
|
||||||
return bot->HasAura(20475) != botAI->HasStrategy("move from group", BotState::BOT_STATE_COMBAT);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool McBaronGeddonInfernoTrigger::IsActive()
|
bool McBaronGeddonInfernoTrigger::IsActive()
|
||||||
{
|
{
|
||||||
if (Unit* boss = AI_VALUE2(Unit*, "find target", "baron geddon"))
|
if (Unit* boss = AI_VALUE2(Unit*, "find target", "baron geddon"))
|
||||||
return boss->HasAura(19695);
|
return boss->HasAura(SPELL_INFERNO);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool McShazzrahRangedTrigger::IsActive()
|
||||||
|
{
|
||||||
|
return AI_VALUE2(Unit*, "find target", "shazzrah") && PlayerbotAI::IsRanged(bot);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool McGolemaggMarkBossTrigger::IsActive()
|
||||||
|
{
|
||||||
|
// any tank may mark the boss
|
||||||
|
return AI_VALUE2(Unit*, "find target", "golemagg the incinerator") && PlayerbotAI::IsTank(bot);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool McGolemaggIsMainTankTrigger::IsActive()
|
||||||
|
{
|
||||||
|
return AI_VALUE2(Unit*, "find target", "golemagg the incinerator") && PlayerbotAI::IsMainTank(bot);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool McGolemaggIsAssistTankTrigger::IsActive()
|
||||||
|
{
|
||||||
|
return AI_VALUE2(Unit*, "find target", "golemagg the incinerator") && PlayerbotAI::IsAssistTank(bot);
|
||||||
|
}
|
||||||
|
|||||||
@@ -19,4 +19,32 @@ public:
|
|||||||
bool IsActive() override;
|
bool IsActive() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class McShazzrahRangedTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
McShazzrahRangedTrigger(PlayerbotAI* botAI) : Trigger(botAI, "mc shazzrah ranged") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class McGolemaggMarkBossTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
McGolemaggMarkBossTrigger(PlayerbotAI* botAI) : Trigger(botAI, "mc golemagg mark boss") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class McGolemaggIsMainTankTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
McGolemaggIsMainTankTrigger(PlayerbotAI* botAI) : Trigger(botAI, "mc golemagg is main tank") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class McGolemaggIsAssistTankTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
McGolemaggIsAssistTankTrigger(PlayerbotAI* botAI) : Trigger(botAI, "mc golemagg is assist tank") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user