diff --git a/src/strategy/raids/ulduar/RaidUlduarActionContext.h b/src/strategy/raids/ulduar/RaidUlduarActionContext.h index 1dc10cc2..da16537a 100644 --- a/src/strategy/raids/ulduar/RaidUlduarActionContext.h +++ b/src/strategy/raids/ulduar/RaidUlduarActionContext.h @@ -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 diff --git a/src/strategy/raids/ulduar/RaidUlduarActions.cpp b/src/strategy/raids/ulduar/RaidUlduarActions.cpp index 443cd275..901713be 100644 --- a/src/strategy/raids/ulduar/RaidUlduarActions.cpp +++ b/src/strategy/raids/ulduar/RaidUlduarActions.cpp @@ -1,6 +1,7 @@ #include "RaidUlduarActions.h" +#include #include #include @@ -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("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("rti")->Set("skull"); + } + } + else + { + group->SetTargetIcon(crossIndex, bot->GetGUID(), leviathanMkII->GetGUID()); + if (AI_VALUE(std::string, "rti") != "cross") + { + botAI->GetAiObjectContext()->GetValue("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("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; +} diff --git a/src/strategy/raids/ulduar/RaidUlduarActions.h b/src/strategy/raids/ulduar/RaidUlduarActions.h index 01867806..d39c6a1b 100644 --- a/src/strategy/raids/ulduar/RaidUlduarActions.h +++ b/src/strategy/raids/ulduar/RaidUlduarActions.h @@ -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 diff --git a/src/strategy/raids/ulduar/RaidUlduarStrategy.cpp b/src/strategy/raids/ulduar/RaidUlduarStrategy.cpp index f18ee9d6..d7e805c0 100644 --- a/src/strategy/raids/ulduar/RaidUlduarStrategy.cpp +++ b/src/strategy/raids/ulduar/RaidUlduarStrategy.cpp @@ -190,9 +190,41 @@ void RaidUlduarStrategy::InitTriggers(std::vector& 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& multipliers) diff --git a/src/strategy/raids/ulduar/RaidUlduarTriggerContext.h b/src/strategy/raids/ulduar/RaidUlduarTriggerContext.h index 220730f0..84cd1104 100644 --- a/src/strategy/raids/ulduar/RaidUlduarTriggerContext.h +++ b/src/strategy/raids/ulduar/RaidUlduarTriggerContext.h @@ -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 diff --git a/src/strategy/raids/ulduar/RaidUlduarTriggers.cpp b/src/strategy/raids/ulduar/RaidUlduarTriggers.cpp index 30700c3c..6deb508c 100644 --- a/src/strategy/raids/ulduar/RaidUlduarTriggers.cpp +++ b/src/strategy/raids/ulduar/RaidUlduarTriggers.cpp @@ -11,6 +11,7 @@ #include "SharedDefines.h" #include "Trigger.h" #include "Vehicle.h" +#include const std::vector 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::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; +} diff --git a/src/strategy/raids/ulduar/RaidUlduarTriggers.h b/src/strategy/raids/ulduar/RaidUlduarTriggers.h index 39b0c64d..e5f42223 100644 --- a/src/strategy/raids/ulduar/RaidUlduarTriggers.h +++ b/src/strategy/raids/ulduar/RaidUlduarTriggers.h @@ -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 diff --git a/src/strategy/values/NearestNpcsValue.cpp b/src/strategy/values/NearestNpcsValue.cpp index 1152842a..3b9e553f 100644 --- a/src/strategy/values/NearestNpcsValue.cpp +++ b/src/strategy/values/NearestNpcsValue.cpp @@ -18,7 +18,7 @@ void NearestNpcsValue::FindUnits(std::list& 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& targets) { @@ -64,4 +64,4 @@ void NearestTotemsValue::FindUnits(std::list& targets) Cell::VisitAllObjects(bot, searcher, range); } -bool NearestTotemsValue::AcceptUnit(Unit* unit) { return unit->IsTotem(); } \ No newline at end of file +bool NearestTotemsValue::AcceptUnit(Unit* unit) { return unit->IsTotem(); }