- Added Mimiron Strategy (#1358)

- Fixed nearest npc value
This commit is contained in:
kadeshar
2025-06-06 08:51:28 +02:00
committed by GitHub
parent 3c05e47cb2
commit db9bcb97ba
8 changed files with 1141 additions and 9 deletions

View File

@@ -54,6 +54,14 @@ public:
creators["thorim gauntlet positioning action"] = &RaidUlduarActionContext::thorim_gauntlet_positioning_action;
creators["thorim phase 2 positioning action"] = &RaidUlduarActionContext::thorim_phase2_positioning_action;
creators["mimiron fire resistance action"] = &RaidUlduarActionContext::mimiron_fire_resistance_action;
creators["mimiron shock blast action"] = &RaidUlduarActionContext::mimiron_shock_blast_action;
creators["mimiron phase 1 positioning action"] = &RaidUlduarActionContext::mimiron_phase_1_positioning_action;
creators["mimiron p3wx2 laser barrage action"] = &RaidUlduarActionContext::mimiron_p3wx2_laser_barrage_action;
creators["mimiron rapid burst action"] = &RaidUlduarActionContext::mimiron_rapid_burst_action;
creators["mimiron aerial command unit action"] = &RaidUlduarActionContext::mimiron_aerial_command_unit_action;
creators["mimiron rocket strike action"] = &RaidUlduarActionContext::mimiron_rocket_strike_action;
creators["mimiron phase 4 mark dps action"] = &RaidUlduarActionContext::mimiron_phase_4_mark_dps_action;
creators["mimiron cheat action"] = &RaidUlduarActionContext::mimiron_cheat_action;
}
private:
@@ -95,6 +103,14 @@ private:
static Action* thorim_gauntlet_positioning_action(PlayerbotAI* ai) { return new ThorimGauntletPositioningAction(ai); }
static Action* thorim_phase2_positioning_action(PlayerbotAI* ai) { return new ThorimPhase2PositioningAction(ai); }
static Action* mimiron_fire_resistance_action(PlayerbotAI* ai) { return new BossFireResistanceAction(ai, "mimiron"); }
static Action* mimiron_shock_blast_action(PlayerbotAI* ai) { return new MimironShockBlastAction(ai); }
static Action* mimiron_phase_1_positioning_action(PlayerbotAI* ai) { return new MimironPhase1PositioningAction(ai); }
static Action* mimiron_p3wx2_laser_barrage_action(PlayerbotAI* ai) { return new MimironP3Wx2LaserBarrageAction(ai); }
static Action* mimiron_rapid_burst_action(PlayerbotAI* ai) { return new MimironRapidBurstAction(ai); }
static Action* mimiron_aerial_command_unit_action(PlayerbotAI* ai) { return new MimironAerialCommandUnitAction(ai); }
static Action* mimiron_rocket_strike_action(PlayerbotAI* ai) { return new MimironRocketStrikeAction(ai); }
static Action* mimiron_phase_4_mark_dps_action(PlayerbotAI* ai) { return new MimironPhase4MarkDpsAction(ai); }
static Action* mimiron_cheat_action(PlayerbotAI* ai) { return new MimironCheatAction(ai); }
};
#endif

View File

@@ -1,6 +1,7 @@
#include "RaidUlduarActions.h"
#include <CombatStrategy.h>
#include <FollowMasterStrategy.h>
#include <cmath>
@@ -62,7 +63,7 @@ bool FlameLeviathanVehicleAction::Execute(Event event)
continue;
if (unit->GetEntry() == 33142) // Leviathan Defense Turret
continue;
if (unit->GetEntry() == 33113) // Flame Leviathan
if (unit->GetEntry() == 33113) // Flame Leviathan
{
flame = unit;
continue;
@@ -1851,7 +1852,7 @@ bool ThorimMarkDpsTargetAction::Execute(Event event)
(!currentSkullUnit || currentSkullUnit->GetEntry() != acolyte->GetEntry()))
targetToMark = acolyte;
else if (evoker && evoker->IsAlive() && bot->GetDistance(evoker) < 50.0f &&
(!currentSkullUnit || currentSkullUnit->GetEntry() != evoker->GetEntry()))
(!currentSkullUnit || currentSkullUnit->GetEntry() != evoker->GetEntry()))
targetToMark = evoker;
else
return false;
@@ -2095,8 +2096,8 @@ bool ThorimGauntletPositioningAction::Execute(Event event)
boss->GetPositionZ() < ULDUAR_THORIM_AXIS_Z_FLOOR_THRESHOLD)
{
MoveTo(bot->GetMapId(), ULDUAR_THORIM_JUMP_START_POINT.GetPositionX(),
ULDUAR_THORIM_JUMP_START_POINT.GetPositionY(), ULDUAR_THORIM_JUMP_START_POINT.GetPositionZ(), false,
false, false, true, MovementPriority::MOVEMENT_NORMAL, true);
ULDUAR_THORIM_JUMP_START_POINT.GetPositionY(), ULDUAR_THORIM_JUMP_START_POINT.GetPositionZ(), false,
false, false, true, MovementPriority::MOVEMENT_NORMAL, true);
if (bot->GetDistance(ULDUAR_THORIM_JUMP_START_POINT) > 0.5f)
return false;
@@ -2171,9 +2172,8 @@ bool ThorimPhase2PositioningAction::Execute(Event event)
targetPosition = ULDUAR_THORIM_PHASE2_RANGE3_SPOT;
}
MoveTo(bot->GetMapId(), targetPosition.GetPositionX(), targetPosition.GetPositionY(),
targetPosition.GetPositionZ(), false, false, false, true, MovementPriority::MOVEMENT_COMBAT, true,
backward);
MoveTo(bot->GetMapId(), targetPosition.GetPositionX(), targetPosition.GetPositionY(), targetPosition.GetPositionZ(),
false, false, false, true, MovementPriority::MOVEMENT_COMBAT, true, backward);
if (bot->GetDistance(targetPosition) > 1.0f)
return false;
@@ -2186,3 +2186,464 @@ bool ThorimPhase2PositioningAction::isUseful()
ThorimPhase2PositioningTrigger thorimPhase2PositioningTrigger(botAI);
return thorimPhase2PositioningTrigger.IsActive();
}
bool MimironShockBlastAction::Execute(Event event)
{
Unit* leviathanMkII = nullptr;
Unit* vx001 = nullptr;
Unit* aerialCommandUnit = nullptr;
float radius = 20.0f;
GuidVector targets = AI_VALUE(GuidVector, "possible targets");
Unit* target = nullptr;
for (auto i = targets.begin(); i != targets.end(); ++i)
{
target = botAI->GetUnit(*i);
if (!target || !target->IsAlive())
continue;
if (target->GetEntry() == NPC_LEVIATHAN_MKII)
{
leviathanMkII = target;
}
else if (target->GetEntry() == NPC_VX001)
{
vx001 = target;
}
else if (target->GetEntry() == NPC_AERIAL_COMMAND_UNIT)
{
aerialCommandUnit = target;
}
}
if (!leviathanMkII)
{
return false;
}
if (!vx001 && !aerialCommandUnit)
{
float currentDistance = bot->GetDistance2d(leviathanMkII);
MoveAway(leviathanMkII, radius - currentDistance);
if (botAI->IsMelee(bot))
{
botAI->SetNextCheckDelay(100);
}
return true;
}
else
{
float init_angle = leviathanMkII->GetAngle(bot);
float distance = radius - bot->GetDistance2d(leviathanMkII);
for (float delta = 0; delta <= M_PI / 2; delta += M_PI / 8)
{
float angle = init_angle + delta;
float dx = bot->GetPositionX() + cos(angle) * distance;
float dy = bot->GetPositionY() + sin(angle) * distance;
float dz = bot->GetPositionZ();
if (bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bot->GetPositionX(), bot->GetPositionY(),
bot->GetPositionZ(), dx, dy, dz))
{
bot->TeleportTo(target->GetMapId(), dx, dy, dz, target->GetOrientation());
return true;
}
}
return false;
}
}
bool MimironShockBlastAction::isUseful()
{
MimironShockBlastTrigger mimironShockBlastTrigger(botAI);
return mimironShockBlastTrigger.IsActive();
}
bool MimironPhase1PositioningAction::Execute(Event event)
{
SET_AI_VALUE(float, "disperse distance", 6.0f);
return true;
}
bool MimironPhase1PositioningAction::isUseful()
{
MimironPhase1PositioningTrigger mimironPhase1PositioningTrigger(botAI);
return mimironPhase1PositioningTrigger.IsActive();
}
bool MimironP3Wx2LaserBarrageAction::Execute(Event event)
{
auto master = botAI->GetMaster();
if (!master || !master->IsAlive())
{
return false;
}
if (bot->GetDistance2d(master) > 15.0f)
{
return bot->TeleportTo(master->GetMapId(), master->GetPositionX(), master->GetPositionY(),
master->GetPositionZ(), master->GetOrientation());
}
return MoveTo(master->GetMapId(), master->GetPositionX(), master->GetPositionY(), master->GetPositionZ(), false,
false, false, true, MovementPriority::MOVEMENT_COMBAT, true);
}
bool MimironRapidBurstAction::isUseful()
{
MimironRapidBurstTrigger mimironRapidBurstTrigger(botAI);
return mimironRapidBurstTrigger.IsActive();
}
bool MimironRapidBurstAction::Execute(Event event)
{
Unit* leviathanMkII = nullptr;
GuidVector targets = AI_VALUE(GuidVector, "possible targets");
Unit* target = nullptr;
for (auto i = targets.begin(); i != targets.end(); ++i)
{
target = botAI->GetUnit(*i);
if (!target || !target->IsAlive())
continue;
if (target->GetEntry() == NPC_LEVIATHAN_MKII)
{
leviathanMkII = target;
}
}
Position targetPosition;
Group* group = bot->GetGroup();
if (!group)
{
return false;
}
uint32 memberSpotNumber = 0;
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
{
Player* member = gref->GetSource();
if (!member)
continue;
if (bot->GetGUID() == member->GetGUID())
{
if (botAI->IsRanged(bot))
{
switch (memberSpotNumber)
{
case 0:
targetPosition = ULDUAR_MIMIRON_PHASE2_SIDE1RANGE_SPOT;
break;
case 1:
targetPosition = ULDUAR_MIMIRON_PHASE2_SIDE2RANGE_SPOT;
break;
case 2:
targetPosition = ULDUAR_MIMIRON_PHASE2_SIDE3RANGE_SPOT;
break;
default:
break;
}
}
else if (botAI->IsMainTank(bot) && leviathanMkII)
{
targetPosition = ULDUAR_MIMIRON_PHASE4_TANK_SPOT;
}
else
{
switch (memberSpotNumber)
{
case 0:
targetPosition = ULDUAR_MIMIRON_PHASE2_SIDE1MELEE_SPOT;
break;
case 1:
targetPosition = ULDUAR_MIMIRON_PHASE2_SIDE2MELEE_SPOT;
break;
case 2:
targetPosition = ULDUAR_MIMIRON_PHASE2_SIDE3MELEE_SPOT;
break;
default:
break;
}
}
}
memberSpotNumber++;
if (memberSpotNumber == 3)
{
memberSpotNumber = 0;
}
}
MoveTo(bot->GetMapId(), targetPosition.GetPositionX(), targetPosition.GetPositionY(), targetPosition.GetPositionZ(),
false, false, false, true, MovementPriority::MOVEMENT_FORCED, true, false);
if (AI_VALUE(float, "disperse distance") != 0.0f)
{
SET_AI_VALUE(float, "disperse distance", 0.0f);
}
TankFaceStrategy tankFaceStrategy(botAI);
if (botAI->HasStrategy(tankFaceStrategy.getName(), BotState::BOT_STATE_COMBAT))
{
botAI->ChangeStrategy(REMOVE_STRATEGY_CHAR + tankFaceStrategy.getName(), BotState::BOT_STATE_COMBAT);
}
if (botAI->HasStrategy(tankFaceStrategy.getName(), BotState::BOT_STATE_NON_COMBAT))
{
botAI->ChangeStrategy(REMOVE_STRATEGY_CHAR + tankFaceStrategy.getName(), BotState::BOT_STATE_NON_COMBAT);
}
if (bot->GetDistance(targetPosition) > 1.0f)
return false;
return true;
}
bool MimironAerialCommandUnitAction::Execute(Event event)
{
Unit* boss = nullptr;
Unit* bombBot = nullptr;
Unit* assaultBot = nullptr;
GuidVector targets = AI_VALUE(GuidVector, "possible targets");
Unit* target = nullptr;
for (auto i = targets.begin(); i != targets.end(); ++i)
{
target = botAI->GetUnit(*i);
if (!target || !target->IsAlive())
continue;
if (target->GetEntry() == NPC_AERIAL_COMMAND_UNIT)
{
boss = target;
}
else if (target->GetEntry() == NPC_BOMB_BOT)
{
bombBot = target;
}
else if (target->GetEntry() == NPC_ASSAULT_BOT)
{
assaultBot = target;
}
}
if (botAI->IsMainTank(bot) || botAI->IsAssistTankOfIndex(bot, 0))
{
Group* group = bot->GetGroup();
if (!group)
{
return false;
}
if (bombBot)
{
group->SetTargetIcon(crossIndex, bot->GetGUID(), bombBot->GetGUID());
}
else if (boss)
{
group->SetTargetIcon(crossIndex, bot->GetGUID(), boss->GetGUID());
}
if (assaultBot)
{
ObjectGuid skullTarget = group->GetTargetIcon(skullIndex);
Unit* skullUnit = botAI->GetUnit(skullTarget);
if (!skullTarget || !skullUnit || !skullUnit->IsAlive())
{
group->SetTargetIcon(skullIndex, bot->GetGUID(), assaultBot->GetGUID());
}
}
return true;
}
if (AI_VALUE(float, "disperse distance") != 5.0f)
{
SET_AI_VALUE(float, "disperse distance", 5.0f);
}
botAI->GetAiObjectContext()->GetValue<std::string>("rti")->Set("cross");
return true;
}
bool MimironRocketStrikeAction::isUseful()
{
MimironRocketStrikeTrigger mimironRocketStrikeTrigger(botAI);
return mimironRocketStrikeTrigger.IsActive();
}
bool MimironRocketStrikeAction::Execute(Event event)
{
Unit* leviathanMkII = nullptr;
Unit* vx001 = nullptr;
Unit* aerialCommandUnit = nullptr;
GuidVector targets = AI_VALUE(GuidVector, "possible targets");
Unit* target = nullptr;
for (auto i = targets.begin(); i != targets.end(); ++i)
{
target = botAI->GetUnit(*i);
if (!target || !target->IsAlive())
continue;
if (target->GetEntry() == NPC_LEVIATHAN_MKII)
{
leviathanMkII = target;
}
else if (target->GetEntry() == NPC_VX001)
{
vx001 = target;
}
else if (target->GetEntry() == NPC_AERIAL_COMMAND_UNIT)
{
aerialCommandUnit = target;
}
}
Creature* rocketStrikeN = bot->FindNearestCreature(NPC_ROCKET_STRIKE_N, 100.0f);
if (!rocketStrikeN)
{
return false;
}
if (!vx001 && !aerialCommandUnit)
{
MoveAway(rocketStrikeN, 10.0f);
return true;
}
else
{
float init_angle = rocketStrikeN->GetAngle(bot);
float distance = 10.0f - bot->GetDistance2d(rocketStrikeN);
for (float delta = 0; delta <= M_PI / 2; delta += M_PI / 8)
{
float angle = init_angle + delta;
float dx = bot->GetPositionX() + cos(angle) * distance;
float dy = bot->GetPositionY() + sin(angle) * distance;
float dz = bot->GetPositionZ();
if (bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bot->GetPositionX(), bot->GetPositionY(),
bot->GetPositionZ(), dx, dy, dz))
{
bot->TeleportTo(target->GetMapId(), dx, dy, dz, target->GetOrientation());
return true;
}
}
return false;
}
}
bool MimironPhase4MarkDpsAction::Execute(Event event)
{
Unit* leviathanMkII = nullptr;
Unit* vx001 = nullptr;
Unit* aerialCommandUnit = nullptr;
Group* group = bot->GetGroup();
if (!group)
{
return false;
}
GuidVector targets = AI_VALUE(GuidVector, "possible targets");
Unit* target = nullptr;
for (auto i = targets.begin(); i != targets.end(); ++i)
{
target = botAI->GetUnit(*i);
if (!target || !target->IsAlive())
continue;
if (target->GetEntry() == NPC_LEVIATHAN_MKII)
{
leviathanMkII = target;
}
else if (target->GetEntry() == NPC_VX001)
{
vx001 = target;
}
else if (target->GetEntry() == NPC_AERIAL_COMMAND_UNIT)
{
aerialCommandUnit = target;
}
}
if (!leviathanMkII || !vx001 || !aerialCommandUnit)
{
return false;
}
if (botAI->IsMainTank(bot))
{
Unit* highestHealthUnit = nullptr;
uint32 highestHealth = 0;
if (leviathanMkII && leviathanMkII->GetHealth() > highestHealth)
{
highestHealth = leviathanMkII->GetHealth();
highestHealthUnit = leviathanMkII;
}
if (vx001 && vx001->GetHealth() > highestHealth)
{
highestHealth = vx001->GetHealth();
highestHealthUnit = vx001;
}
if (aerialCommandUnit && aerialCommandUnit->GetHealth() > highestHealth)
{
highestHealthUnit = aerialCommandUnit;
}
group->SetTargetIcon(skullIndex, bot->GetGUID(), highestHealthUnit->GetGUID());
if (highestHealthUnit == leviathanMkII)
{
if (AI_VALUE(std::string, "rti") == "skull")
{
botAI->GetAiObjectContext()->GetValue<std::string>("rti")->Set("skull");
}
}
else
{
group->SetTargetIcon(crossIndex, bot->GetGUID(), leviathanMkII->GetGUID());
if (AI_VALUE(std::string, "rti") != "cross")
{
botAI->GetAiObjectContext()->GetValue<std::string>("rti")->Set("cross");
}
}
botAI->DoSpecificAction("attack rti target");
return true;
}
else
{
/*if (AI_VALUE(float, "disperse distance") != 0.0f)
{
SET_AI_VALUE(float, "disperse distance", 0.0f);
}*/
botAI->GetAiObjectContext()->GetValue<std::string>("rti")->Set("skull");
return true;
}
}
bool MimironCheatAction::Execute(Event event)
{
GuidVector targets = AI_VALUE(GuidVector, "nearest npcs");
for (const ObjectGuid& guid : targets)
{
Unit* unit = botAI->GetUnit(guid);
if (!unit || !unit->IsAlive())
continue;
if (unit->GetEntry() == NPC_PROXIMITY_MINE)
{
unit->Kill(bot, unit);
}
else if (unit->GetEntry() == NPC_BOMB_BOT)
{
unit->Kill(bot, unit);
}
}
return true;
}

View File

@@ -278,4 +278,80 @@ public:
bool isUseful() override;
};
class MimironShockBlastAction : public MovementAction
{
public:
MimironShockBlastAction(PlayerbotAI* ai) : MovementAction(ai, "mimiron shock blast action") {}
bool Execute(Event event) override;
bool isUseful() override;
};
class MimironPhase1PositioningAction : public MovementAction
{
public:
MimironPhase1PositioningAction(PlayerbotAI* ai) : MovementAction(ai, "mimiron phase 1 positioning action") {}
bool Execute(Event event) override;
bool isUseful() override;
};
class MimironP3Wx2LaserBarrageAction : public MovementAction
{
public:
MimironP3Wx2LaserBarrageAction(PlayerbotAI* ai, float distance = 24.0f, float delta_angle = M_PI / 8)
: MovementAction(ai, "mimiron p3wx2 laser barrage action")
{
this->distance = distance;
this->delta_angle = delta_angle;
}
virtual bool Execute(Event event);
protected:
float distance, delta_angle;
};
class MimironRapidBurstAction : public MovementAction
{
public:
MimironRapidBurstAction(PlayerbotAI* ai) : MovementAction(ai, "mimiron rapid burst action") {}
bool Execute(Event event) override;
bool isUseful() override;
};
class MimironAerialCommandUnitAction : public Action
{
public:
MimironAerialCommandUnitAction(PlayerbotAI* ai) : Action(ai, "mimiron aerial command unit action") {}
bool Execute(Event event) override;
};
class MimironRocketStrikeAction : public MovementAction
{
public:
MimironRocketStrikeAction(PlayerbotAI* ai) : MovementAction(ai, "mimiron rocket strike action") {}
bool Execute(Event event) override;
bool isUseful() override;
};
class MimironPhase4MarkDpsAction : public Action
{
public:
MimironPhase4MarkDpsAction(PlayerbotAI* ai) : Action(ai, "mimiron phase 4 mark dps action") {}
bool Execute(Event event) override;
};
class MimironCheatAction : public Action
{
public:
MimironCheatAction(PlayerbotAI* ai) : Action(ai, "mimiron cheat action") {}
bool Execute(Event event) override;
};
#endif

View File

@@ -190,9 +190,41 @@ void RaidUlduarStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
//
// Mimiron
//
triggers.push_back(new TriggerNode(
"mimiron p3wx2 laser barrage trigger",
NextAction::array(0, new NextAction("mimiron p3wx2 laser barrage action", ACTION_RAID + 2), nullptr)));
triggers.push_back(new TriggerNode(
"mimiron shock blast trigger",
NextAction::array(0, new NextAction("mimiron shock blast action", ACTION_RAID + 1), nullptr)));
triggers.push_back(new TriggerNode(
"mimiron fire resistance trigger",
NextAction::array(0, new NextAction("mimiron fire resistance action", ACTION_RAID), nullptr)));
triggers.push_back(new TriggerNode(
"mimiron phase 1 positioning trigger",
NextAction::array(0, new NextAction("mimiron phase 1 positioning action", ACTION_RAID), nullptr)));
triggers.push_back(new TriggerNode(
"mimiron rapid burst trigger",
NextAction::array(0, new NextAction("mimiron rapid burst action", ACTION_RAID), nullptr)));
triggers.push_back(new TriggerNode(
"mimiron aerial command unit trigger",
NextAction::array(0, new NextAction("mimiron aerial command unit action", ACTION_RAID), nullptr)));
triggers.push_back(new TriggerNode(
"mimiron rocket strike trigger",
NextAction::array(0, new NextAction("mimiron rocket strike action", ACTION_RAID), nullptr)));
triggers.push_back(new TriggerNode(
"mimiron phase 4 mark dps trigger",
NextAction::array(0, new NextAction("mimiron phase 4 mark dps action", ACTION_RAID), nullptr)));
triggers.push_back(new TriggerNode(
"mimiron cheat trigger",
NextAction::array(0, new NextAction("mimiron cheat action", ACTION_RAID), nullptr)));
}
void RaidUlduarStrategy::InitMultipliers(std::vector<Multiplier*>& multipliers)

View File

@@ -56,6 +56,14 @@ public:
creators["thorim fall from floor trigger"] = &RaidUlduarTriggerContext::thorim_fall_from_floor_trigger;
creators["thorim phase 2 positioning trigger"] = &RaidUlduarTriggerContext::thorim_phase2_positioning_trigger;
creators["mimiron fire resistance trigger"] = &RaidUlduarTriggerContext::mimiron_fire_resistance_trigger;
creators["mimiron shock blast trigger"] = &RaidUlduarTriggerContext::mimiron_shock_blast_trigger;
creators["mimiron phase 1 positioning trigger"] = &RaidUlduarTriggerContext::mimiron_phase_1_positioning_trigger;
creators["mimiron p3wx2 laser barrage trigger"] = &RaidUlduarTriggerContext::mimiron_p3wx2_laser_barrage_trigger;
creators["mimiron rapid burst trigger"] = &RaidUlduarTriggerContext::mimiron_rapid_burst_trigger;
creators["mimiron aerial command unit trigger"] = &RaidUlduarTriggerContext::mimiron_aerial_command_unit_trigger;
creators["mimiron rocket strike trigger"] = &RaidUlduarTriggerContext::mimiron_rocket_strike_trigger;
creators["mimiron phase 4 mark dps trigger"] = &RaidUlduarTriggerContext::mimiron_phase_4_mark_dps_trigger;
creators["mimiron cheat trigger"] = &RaidUlduarTriggerContext::mimiron_cheat_trigger;
}
private:
@@ -99,6 +107,14 @@ private:
static Trigger* thorim_fall_from_floor_trigger(PlayerbotAI* ai) { return new ThorimFallFromFloorTrigger(ai); }
static Trigger* thorim_phase2_positioning_trigger(PlayerbotAI* ai) { return new ThorimPhase2PositioningTrigger(ai); }
static Trigger* mimiron_fire_resistance_trigger(PlayerbotAI* ai) { return new BossFireResistanceTrigger(ai, "mimiron"); }
static Trigger* mimiron_shock_blast_trigger(PlayerbotAI* ai) { return new MimironShockBlastTrigger(ai); }
static Trigger* mimiron_phase_1_positioning_trigger(PlayerbotAI* ai) { return new MimironPhase1PositioningTrigger(ai); }
static Trigger* mimiron_p3wx2_laser_barrage_trigger(PlayerbotAI* ai) { return new MimironP3Wx2LaserBarrageTrigger(ai); }
static Trigger* mimiron_rapid_burst_trigger(PlayerbotAI* ai) { return new MimironRapidBurstTrigger(ai); }
static Trigger* mimiron_aerial_command_unit_trigger(PlayerbotAI* ai) { return new MimironAerialCommandUnitTrigger(ai); }
static Trigger* mimiron_rocket_strike_trigger(PlayerbotAI* ai) { return new MimironRocketStrikeTrigger(ai); }
static Trigger* mimiron_phase_4_mark_dps_trigger(PlayerbotAI* ai) { return new MimironPhase4MarkDpsTrigger(ai); }
static Trigger* mimiron_cheat_trigger(PlayerbotAI* ai) { return new MimironCheatTrigger(ai); }
};
#endif

View File

@@ -11,6 +11,7 @@
#include "SharedDefines.h"
#include "Trigger.h"
#include "Vehicle.h"
#include <MovementActions.h>
const std::vector<uint32> availableVehicles = {NPC_VEHICLE_CHOPPER, NPC_SALVAGED_DEMOLISHER,
NPC_SALVAGED_DEMOLISHER_TURRET, NPC_SALVAGED_SIEGE_ENGINE,
@@ -1108,3 +1109,451 @@ bool ThorimPhase2PositioningTrigger::IsActive()
return false;
}
bool MimironShockBlastTrigger::IsActive()
{
Unit* boss = AI_VALUE2(Unit*, "find target", "leviathan mk ii");
// Check boss and it is alive
if (!boss || !boss->IsAlive())
{
return false;
}
if (!boss->HasUnitState(UNIT_STATE_CASTING) || !boss->FindCurrentSpellBySpellId(SPELL_SHOCK_BLAST))
{
return false;
}
if (botAI->IsMelee(bot))
{
return true;
}
else
{
return bot->GetDistance2d(boss) < 15.0f;
}
}
bool MimironPhase1PositioningTrigger::IsActive()
{
if (!botAI->IsRanged(bot))
{
return false;
}
Unit* leviathanMkII = nullptr;
Unit* vx001 = nullptr;
Unit* aerialCommandUnit = nullptr;
GuidVector targets = AI_VALUE(GuidVector, "possible targets");
Unit* target = nullptr;
for (auto i = targets.begin(); i != targets.end(); ++i)
{
target = botAI->GetUnit(*i);
if (!target || !target->IsAlive())
continue;
if (target->GetEntry() == NPC_LEVIATHAN_MKII)
{
leviathanMkII = target;
}
else if (target->GetEntry() == NPC_VX001)
{
return false;
}
else if (target->GetEntry() == NPC_AERIAL_COMMAND_UNIT)
{
return false;
}
}
if (!leviathanMkII || !leviathanMkII->IsAlive())
{
return false;
}
return AI_VALUE(float, "disperse distance") != 6.0f;
}
bool MimironP3Wx2LaserBarrageTrigger::IsActive()
{
Unit* boss = AI_VALUE2(Unit*, "find target", "vx-001");
// Check boss and it is alive
if (!boss || !boss->IsAlive())
{
return false;
}
bool isCasting = boss->HasUnitState(UNIT_STATE_CASTING);
bool isP3WX2LaserBarrage = boss->FindCurrentSpellBySpellId(SPELL_SPINNING_UP) ||
boss->FindCurrentSpellBySpellId(SPELL_P3WX2_LASER_BARRAGE_1) ||
boss->FindCurrentSpellBySpellId(SPELL_P3WX2_LASER_BARRAGE_2) ||
boss->FindCurrentSpellBySpellId(SPELL_P3WX2_LASER_BARRAGE_AURA_1) ||
boss->FindCurrentSpellBySpellId(SPELL_P3WX2_LASER_BARRAGE_AURA_2) ||
boss->FindCurrentSpellBySpellId(SPELL_P3WX2_LASER_BARRAGE_3);
bool hasP3WX2LaserBarrageAura =
boss->HasAura(SPELL_P3WX2_LASER_BARRAGE_AURA_1) || boss->HasAura(SPELL_P3WX2_LASER_BARRAGE_AURA_2);
if ((!isCasting && !hasP3WX2LaserBarrageAura) || !isP3WX2LaserBarrage)
{
return false;
}
return true;
}
bool MimironRapidBurstTrigger::IsActive()
{
Unit* leviathanMkII = nullptr;
Unit* vx001 = nullptr;
Unit* aerialCommandUnit = nullptr;
GuidVector targets = AI_VALUE(GuidVector, "possible targets");
Unit* target = nullptr;
for (auto i = targets.begin(); i != targets.end(); ++i)
{
target = botAI->GetUnit(*i);
if (!target || !target->IsAlive())
continue;
if (target->GetEntry() == NPC_LEVIATHAN_MKII)
{
leviathanMkII = target;
}
else if (target->GetEntry() == NPC_VX001)
{
vx001 = target;
}
else if (target->GetEntry() == NPC_AERIAL_COMMAND_UNIT)
{
aerialCommandUnit = target;
}
}
if (!vx001 || !vx001->IsAlive())
{
return false;
}
if (leviathanMkII && leviathanMkII->HasUnitState(UNIT_STATE_CASTING) &&
leviathanMkII->FindCurrentSpellBySpellId(SPELL_SHOCK_BLAST))
{
return false;
}
if (botAI->IsMainTank(bot) && leviathanMkII && leviathanMkII->IsAlive() && leviathanMkII->GetVictim() != bot)
{
return false;
}
if (botAI->IsMelee(bot) && !botAI->IsMainTank(bot) && leviathanMkII && aerialCommandUnit)
{
return false;
}
MimironP3Wx2LaserBarrageTrigger mimironP3Wx2LaserBarrageTrigger(botAI);
if (mimironP3Wx2LaserBarrageTrigger.IsActive())
{
return false;
}
Group* group = bot->GetGroup();
if (!group)
{
return false;
}
uint32 memberSpotNumber = 0;
Position memberPosition;
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
{
Player* member = gref->GetSource();
if (!member)
continue;
if (bot->GetGUID() == member->GetGUID())
{
if (botAI->IsRanged(bot))
{
switch (memberSpotNumber)
{
case 0:
memberPosition = ULDUAR_MIMIRON_PHASE2_SIDE1RANGE_SPOT;
break;
case 1:
memberPosition = ULDUAR_MIMIRON_PHASE2_SIDE2RANGE_SPOT;
break;
case 2:
memberPosition = ULDUAR_MIMIRON_PHASE2_SIDE3RANGE_SPOT;
break;
default:
break;
}
}
else
{
if (botAI->IsMainTank(bot) && leviathanMkII)
{
memberPosition = ULDUAR_MIMIRON_PHASE4_TANK_SPOT;
}
else
{
switch (memberSpotNumber)
{
case 0:
memberPosition = ULDUAR_MIMIRON_PHASE2_SIDE1MELEE_SPOT;
break;
case 1:
memberPosition = ULDUAR_MIMIRON_PHASE2_SIDE2MELEE_SPOT;
break;
case 2:
memberPosition = ULDUAR_MIMIRON_PHASE2_SIDE3MELEE_SPOT;
break;
default:
break;
}
}
}
break;
}
memberSpotNumber++;
if (memberSpotNumber == 3)
{
memberSpotNumber = 0;
}
}
GuidVector npcs = AI_VALUE(GuidVector, "nearest npcs");
float nearestRocketStrikeDistance = std::numeric_limits<float>::max();
bool rocketStrikeDetected = false;
for (const ObjectGuid& guid : npcs)
{
Unit* unit = botAI->GetUnit(guid);
if (!unit)
continue;
if (unit->GetEntry() == NPC_ROCKET_STRIKE_N)
{
rocketStrikeDetected = true;
float distance = bot->GetDistance2d(memberPosition.GetPositionX(), memberPosition.GetPositionY());
if (distance < nearestRocketStrikeDistance)
{
nearestRocketStrikeDistance = distance;
}
}
}
return (bot->GetDistance(memberPosition) > 7.0f && !rocketStrikeDetected) ||
bot->GetDistance(memberPosition) > 20.0f;
}
bool MimironAerialCommandUnitTrigger::IsActive()
{
Unit* leviathanMkII = nullptr;
Unit* vx001 = nullptr;
Unit* aerialCommandUnit = nullptr;
//Unit* bombBot = nullptr;
Unit* assaultBot = nullptr;
GuidVector targets = AI_VALUE(GuidVector, "possible targets");
Unit* target = nullptr;
for (auto i = targets.begin(); i != targets.end(); ++i)
{
target = botAI->GetUnit(*i);
if (!target || !target->IsAlive())
continue;
if (target->GetEntry() == NPC_LEVIATHAN_MKII)
{
leviathanMkII = target;
}
else if (target->GetEntry() == NPC_VX001)
{
vx001 = target;
}
else if (target->GetEntry() == NPC_AERIAL_COMMAND_UNIT)
{
aerialCommandUnit = target;
}
//else if (target->GetEntry() == NPC_BOMB_BOT)
//{
// bombBot = target;
//}
else if (target->GetEntry() == NPC_ASSAULT_BOT)
{
assaultBot = target;
}
}
if (!aerialCommandUnit || !aerialCommandUnit->IsAlive() || leviathanMkII || vx001)
{
return false;
}
if (!botAI->IsRanged(bot) && !botAI->IsMainTank(bot) && !botAI->IsAssistTankOfIndex(bot, 0))
{
return false;
}
if (botAI->IsMainTank(bot) || botAI->IsAssistTankOfIndex(bot, 0))
{
Group* group = bot->GetGroup();
if (!group)
{
return false;
}
ObjectGuid skullTarget = group->GetTargetIcon(skullIndex);
ObjectGuid crossTarget = group->GetTargetIcon(crossIndex);
//if (bombBot && bombBot->GetGUID() != crossTarget)
//{
// return true;
//}
if (!crossTarget || aerialCommandUnit->GetGUID() != crossTarget)
{
return true;
}
else if (assaultBot && (!skullTarget || assaultBot->GetGUID() != skullTarget))
{
return true;
}
return false;
}
std::string rtiMark = AI_VALUE(std::string, "rti");
if (rtiMark != "cross")
{
return true;
}
return false;
}
bool MimironRocketStrikeTrigger::IsActive()
{
Unit* boss = AI_VALUE2(Unit*, "find target", "vx-001");
// Check boss and it is alive
if (!boss || !boss->IsAlive())
{
return false;
}
Creature* rocketStrikeN = bot->FindNearestCreature(NPC_ROCKET_STRIKE_N, 100.0f);
if (!rocketStrikeN)
{
return false;
}
return bot->GetDistance2d(rocketStrikeN->GetPositionX(), rocketStrikeN->GetPositionY()) <= 10.0f;
}
bool MimironPhase4MarkDpsTrigger::IsActive()
{
Unit* leviathanMkII = nullptr;
Unit* vx001 = nullptr;
Unit* aerialCommandUnit = nullptr;
Group* group = bot->GetGroup();
if (!group)
{
return false;
}
GuidVector targets = AI_VALUE(GuidVector, "possible targets");
Unit* target = nullptr;
for (auto i = targets.begin(); i != targets.end(); ++i)
{
target = botAI->GetUnit(*i);
if (!target || !target->IsAlive())
continue;
if (target->GetEntry() == NPC_LEVIATHAN_MKII)
{
leviathanMkII = target;
}
else if (target->GetEntry() == NPC_VX001)
{
vx001 = target;
}
else if (target->GetEntry() == NPC_AERIAL_COMMAND_UNIT)
{
aerialCommandUnit = target;
}
}
if (!leviathanMkII || !vx001 || !aerialCommandUnit)
{
return false;
}
if (botAI->IsMainTank(bot))
{
Unit* highestHealthUnit = nullptr;
uint32 highestHealth = 0;
if (leviathanMkII && leviathanMkII->GetHealth() > highestHealth)
{
highestHealth = leviathanMkII->GetHealth();
highestHealthUnit = leviathanMkII;
}
if (vx001 && vx001->GetHealth() > highestHealth)
{
highestHealth = vx001->GetHealth();
highestHealthUnit = vx001;
}
if (aerialCommandUnit && aerialCommandUnit->GetHealth() > highestHealth)
{
highestHealthUnit = aerialCommandUnit;
}
ObjectGuid skullTarget = group->GetTargetIcon(skullIndex);
if (!skullTarget)
{
return true;
}
return highestHealthUnit->GetGUID() != skullTarget;
}
else
{
return AI_VALUE(std::string, "rti") != "skull";
}
return false;
}
bool MimironCheatTrigger::IsActive()
{
if (!botAI->IsMainTank(bot))
{
return false;
}
GuidVector targets = AI_VALUE(GuidVector, "nearest npcs");
for (const ObjectGuid& guid : targets)
{
Unit* unit = botAI->GetUnit(guid);
if (!unit || !unit->IsAlive())
continue;
if (unit->GetEntry() == NPC_PROXIMITY_MINE)
{
return true;
}
else if (unit->GetEntry() == NPC_BOMB_BOT)
{
return true;
}
}
return false;
}

View File

@@ -61,6 +61,22 @@ enum UlduarIDs
NPC_DARK_RUNE_ACOLYTE_G = 33110,
NPC_IRON_HONOR_GUARD = 32875,
SPELL_UNBALANCING_STRIKE = 62130,
//Mimiron
NPC_LEVIATHAN_MKII = 33432,
NPC_VX001 = 33651,
NPC_AERIAL_COMMAND_UNIT = 33670,
NPC_BOMB_BOT = 33836,
NPC_ROCKET_STRIKE_N = 34047,
NPC_ASSAULT_BOT = 34057,
NPC_PROXIMITY_MINE = 34362,
SPELL_P3WX2_LASER_BARRAGE_1 = 63293,
SPELL_P3WX2_LASER_BARRAGE_2 = 63297,
SPELL_SPINNING_UP = 63414,
SPELL_SHOCK_BLAST = 63631,
SPELL_P3WX2_LASER_BARRAGE_3 = 64042,
SPELL_P3WX2_LASER_BARRAGE_AURA_1 = 63274,
SPELL_P3WX2_LASER_BARRAGE_AURA_2 = 63300,
// Buffs
SPELL_FROST_TRAP = 13809
@@ -94,6 +110,13 @@ const Position ULDUAR_THORIM_PHASE2_TANK_SPOT = Position(2134.8572f, -287.0291f,
const Position ULDUAR_THORIM_PHASE2_RANGE1_SPOT = Position(2112.8752f, -267.69305f, 419.52814f);
const Position ULDUAR_THORIM_PHASE2_RANGE2_SPOT = Position(2129.09f, -277.142f, 419.67462f);
const Position ULDUAR_THORIM_PHASE2_RANGE3_SPOT = Position(2156.798f, -267.57434f, 419.52722f);
const Position ULDUAR_MIMIRON_PHASE2_SIDE1RANGE_SPOT = Position(2753.708f, 2583.9617f, 364.31357f);
const Position ULDUAR_MIMIRON_PHASE2_SIDE1MELEE_SPOT = Position(2746.9792f, 2573.6716f, 364.31357f);
const Position ULDUAR_MIMIRON_PHASE2_SIDE2RANGE_SPOT = Position(2727.7224f, 2569.527f, 364.31357f);
const Position ULDUAR_MIMIRON_PHASE2_SIDE2MELEE_SPOT = Position(2739.4746f, 2569.4106f, 364.31357f);
const Position ULDUAR_MIMIRON_PHASE2_SIDE3RANGE_SPOT = Position(2754.1294f, 2553.9954f, 364.31357f);
const Position ULDUAR_MIMIRON_PHASE2_SIDE3MELEE_SPOT = Position(2746.8513f, 2565.4263f, 364.31357f);
const Position ULDUAR_MIMIRON_PHASE4_TANK_SPOT = Position(2744.5754f, 2570.8657f, 364.3138f);
//
// Flame Levi
@@ -336,4 +359,63 @@ public:
bool IsActive() override;
};
//
// Mimiron
//
class MimironShockBlastTrigger : public Trigger
{
public:
MimironShockBlastTrigger(PlayerbotAI* ai) : Trigger(ai, "mimiron shock blast trigger") {}
bool IsActive() override;
};
class MimironPhase1PositioningTrigger : public Trigger
{
public:
MimironPhase1PositioningTrigger(PlayerbotAI* ai) : Trigger(ai, "mimiron phase 1 positioning trigger") {}
bool IsActive() override;
};
class MimironP3Wx2LaserBarrageTrigger : public Trigger
{
public:
MimironP3Wx2LaserBarrageTrigger(PlayerbotAI* ai) : Trigger(ai, "mimiron p3wx2 laser barrage trigger") {}
bool IsActive() override;
};
class MimironRapidBurstTrigger : public Trigger
{
public:
MimironRapidBurstTrigger(PlayerbotAI* ai) : Trigger(ai, "mimiron rapid burst trigger") {}
bool IsActive() override;
};
class MimironAerialCommandUnitTrigger : public Trigger
{
public:
MimironAerialCommandUnitTrigger(PlayerbotAI* ai) : Trigger(ai, "mimiron aerial command unit trigger") {}
bool IsActive() override;
};
class MimironRocketStrikeTrigger : public Trigger
{
public:
MimironRocketStrikeTrigger(PlayerbotAI* ai) : Trigger(ai, "mimiron rocket strike trigger") {}
bool IsActive() override;
};
class MimironPhase4MarkDpsTrigger : public Trigger
{
public:
MimironPhase4MarkDpsTrigger(PlayerbotAI* ai) : Trigger(ai, "mimiron phase 4 mark dps trigger") {}
bool IsActive() override;
};
class MimironCheatTrigger : public Trigger
{
public:
MimironCheatTrigger(PlayerbotAI* ai) : Trigger(ai, "mimiron cheat trigger") {}
bool IsActive() override;
};
#endif

View File

@@ -18,7 +18,7 @@ void NearestNpcsValue::FindUnits(std::list<Unit*>& targets)
Cell::VisitAllObjects(bot, searcher, range);
}
bool NearestNpcsValue::AcceptUnit(Unit* unit) { return !unit->IsHostileTo(bot) && !unit->IsPlayer(); }
bool NearestNpcsValue::AcceptUnit(Unit* unit) { return !unit->IsPlayer(); }
void NearestHostileNpcsValue::FindUnits(std::list<Unit*>& targets)
{
@@ -64,4 +64,4 @@ void NearestTotemsValue::FindUnits(std::list<Unit*>& targets)
Cell::VisitAllObjects(bot, searcher, range);
}
bool NearestTotemsValue::AcceptUnit(Unit* unit) { return unit->IsTotem(); }
bool NearestTotemsValue::AcceptUnit(Unit* unit) { return unit->IsTotem(); }