From af6eb61d336f6ab72a2837baf55f6be3b97f6ad1 Mon Sep 17 00:00:00 2001 From: Bobblybook Date: Sun, 15 Dec 2024 23:37:56 +1100 Subject: [PATCH] Prelim EoE completion --- .../wotlk/oculus/OculusActionContext.h | 4 +- .../dungeons/wotlk/oculus/OculusActions.cpp | 12 +- .../dungeons/wotlk/oculus/OculusActions.h | 9 +- .../wotlk/oculus/OculusMultipliers.cpp | 6 +- .../dungeons/wotlk/oculus/OculusMultipliers.h | 4 +- .../dungeons/wotlk/oculus/OculusStrategy.cpp | 2 +- src/strategy/raids/RaidStrategyContext.h | 3 + .../eyeofeternity/RaidEoEActionContext.h | 24 +- .../raids/eyeofeternity/RaidEoEActions.cpp | 564 +++++++++++------- .../raids/eyeofeternity/RaidEoEActions.h | 101 ++-- .../eyeofeternity/RaidEoEMultipliers.cpp | 65 ++ .../raids/eyeofeternity/RaidEoEMultipliers.h | 14 +- .../raids/eyeofeternity/RaidEoEStrategy.cpp | 35 +- .../eyeofeternity/RaidEoETriggerContext.h | 18 +- .../raids/eyeofeternity/RaidEoETriggers.cpp | 171 ++---- .../raids/eyeofeternity/RaidEoETriggers.h | 140 ++--- 16 files changed, 617 insertions(+), 555 deletions(-) diff --git a/src/strategy/dungeons/wotlk/oculus/OculusActionContext.h b/src/strategy/dungeons/wotlk/oculus/OculusActionContext.h index 38cd640b..fc22fdbb 100644 --- a/src/strategy/dungeons/wotlk/oculus/OculusActionContext.h +++ b/src/strategy/dungeons/wotlk/oculus/OculusActionContext.h @@ -21,8 +21,8 @@ class WotlkDungeonOccActionContext : public NamedObjectContext static Action* avoid_unstable_sphere(PlayerbotAI* ai) { return new AvoidUnstableSphereAction(ai); } static Action* mount_drake(PlayerbotAI* ai) { return new MountDrakeAction(ai); } static Action* dismount_drake(PlayerbotAI* ai) { return new DismountDrakeAction(ai); } - static Action* fly_drake(PlayerbotAI* ai) { return new FlyDrakeAction(ai); } - static Action* drake_attack(PlayerbotAI* ai) { return new DrakeAttackAction(ai); } + static Action* fly_drake(PlayerbotAI* ai) { return new OccFlyDrakeAction(ai); } + static Action* drake_attack(PlayerbotAI* ai) { return new OccDrakeAttackAction(ai); } static Action* avoid_arcane_explosion(PlayerbotAI* ai) { return new AvoidArcaneExplosionAction(ai); } static Action* time_bomb_spread(PlayerbotAI* ai) { return new TimeBombSpreadAction(ai); } }; diff --git a/src/strategy/dungeons/wotlk/oculus/OculusActions.cpp b/src/strategy/dungeons/wotlk/oculus/OculusActions.cpp index 115181e2..608ff618 100644 --- a/src/strategy/dungeons/wotlk/oculus/OculusActions.cpp +++ b/src/strategy/dungeons/wotlk/oculus/OculusActions.cpp @@ -111,7 +111,7 @@ bool DismountDrakeAction::Execute(Event event) return false; } -bool FlyDrakeAction::Execute(Event event) +bool OccFlyDrakeAction::Execute(Event event) { Player* master = botAI->GetMaster(); if (!master) { return false; } @@ -152,7 +152,7 @@ bool FlyDrakeAction::Execute(Event event) return false; } -bool DrakeAttackAction::Execute(Event event) +bool OccDrakeAttackAction::Execute(Event event) { vehicleBase = bot->GetVehicleBase(); if (!vehicleBase) { return false; } @@ -188,7 +188,7 @@ bool DrakeAttackAction::Execute(Event event) return false; } -bool DrakeAttackAction::CastDrakeSpellAction(Unit* target, uint32 spellId, uint32 cooldown) +bool OccDrakeAttackAction::CastDrakeSpellAction(Unit* target, uint32 spellId, uint32 cooldown) { if (botAI->CanCastVehicleSpell(spellId, target)) if (botAI->CastVehicleSpell(spellId, target)) @@ -199,7 +199,7 @@ bool DrakeAttackAction::CastDrakeSpellAction(Unit* target, uint32 spellId, uint3 return false; } -bool DrakeAttackAction::AmberDrakeAction(Unit* target) +bool OccDrakeAttackAction::AmberDrakeAction(Unit* target) { Aura* shockCharges = target->GetAura(SPELL_SHOCK_CHARGE, vehicleBase->GetGUID()); if (shockCharges && shockCharges->GetStackAmount() > 8) @@ -225,7 +225,7 @@ bool DrakeAttackAction::AmberDrakeAction(Unit* target) return false; } -bool DrakeAttackAction::EmeraldDrakeAction(Unit* target) +bool OccDrakeAttackAction::EmeraldDrakeAction(Unit* target) { Aura* poisonStacks = target->GetAura(SPELL_LEECHING_POISON, vehicleBase->GetGUID()); if (!poisonStacks || (poisonStacks->GetStackAmount() < 3 || @@ -286,7 +286,7 @@ bool DrakeAttackAction::EmeraldDrakeAction(Unit* target) return false; } -bool DrakeAttackAction::RubyDrakeAction(Unit* target) +bool OccDrakeAttackAction::RubyDrakeAction(Unit* target) { Aura* evasiveCharges = vehicleBase->GetAura(SPELL_EVASIVE_CHARGES); Aura* evasiveManeuvers = vehicleBase->GetAura(SPELL_EVASIVE_MANEUVERS); diff --git a/src/strategy/dungeons/wotlk/oculus/OculusActions.h b/src/strategy/dungeons/wotlk/oculus/OculusActions.h index 2111461a..6b26b9dd 100644 --- a/src/strategy/dungeons/wotlk/oculus/OculusActions.h +++ b/src/strategy/dungeons/wotlk/oculus/OculusActions.h @@ -38,17 +38,17 @@ public: bool Execute(Event event) override; }; -class FlyDrakeAction : public MovementAction +class OccFlyDrakeAction : public MovementAction { public: - FlyDrakeAction(PlayerbotAI* ai) : MovementAction(ai, "fly drake") {} + OccFlyDrakeAction(PlayerbotAI* ai) : MovementAction(ai, "occ fly drake") {} bool Execute(Event event) override; }; -class DrakeAttackAction : public Action +class OccDrakeAttackAction : public Action { public: - DrakeAttackAction(PlayerbotAI* botAI) : Action(botAI, "drake attack") {} + OccDrakeAttackAction(PlayerbotAI* botAI) : Action(botAI, "occ drake attack") {} bool Execute(Event event) override; protected: @@ -57,7 +57,6 @@ protected: bool AmberDrakeAction(Unit* target); bool EmeraldDrakeAction(Unit* target); bool RubyDrakeAction(Unit* target); - }; class AvoidArcaneExplosionAction : public MovementAction diff --git a/src/strategy/dungeons/wotlk/oculus/OculusMultipliers.cpp b/src/strategy/dungeons/wotlk/oculus/OculusMultipliers.cpp index 023d5256..b30c4db1 100644 --- a/src/strategy/dungeons/wotlk/oculus/OculusMultipliers.cpp +++ b/src/strategy/dungeons/wotlk/oculus/OculusMultipliers.cpp @@ -26,12 +26,12 @@ float MountingDrakeMultiplier::GetValue(Action* action) return 1.0f; } -float FlyingMultiplier::GetValue(Action* action) +float OccFlyingMultiplier::GetValue(Action* action) { if (bot->GetMapId() != OCULUS_MAP_ID || !bot->GetVehicleBase()) { return 1.0f; } // Suppresses FollowAction as well as some attack-based movements - if (dynamic_cast(action) && !dynamic_cast(action)) + if (dynamic_cast(action) && !dynamic_cast(action)) { return 0.0f; } @@ -103,7 +103,7 @@ float EregosMultiplier::GetValue(Action* action) Unit* boss = AI_VALUE2(Unit*, "find target", "ley-guardian eregos"); if (!boss) { return 1.0f; } - if (boss->HasAura(SPELL_PLANAR_SHIFT && dynamic_cast(action))) + if (boss->HasAura(SPELL_PLANAR_SHIFT && dynamic_cast(action))) { return 0.0f; } diff --git a/src/strategy/dungeons/wotlk/oculus/OculusMultipliers.h b/src/strategy/dungeons/wotlk/oculus/OculusMultipliers.h index f2f86f79..423364b0 100644 --- a/src/strategy/dungeons/wotlk/oculus/OculusMultipliers.h +++ b/src/strategy/dungeons/wotlk/oculus/OculusMultipliers.h @@ -21,10 +21,10 @@ class MountingDrakeMultiplier : public Multiplier virtual float GetValue(Action* action); }; -class FlyingMultiplier : public Multiplier +class OccFlyingMultiplier : public Multiplier { public: - FlyingMultiplier(PlayerbotAI* ai) : Multiplier(ai, "flying drake") {} + OccFlyingMultiplier(PlayerbotAI* ai) : Multiplier(ai, "occ flying drake") {} public: virtual float GetValue(Action* action); diff --git a/src/strategy/dungeons/wotlk/oculus/OculusStrategy.cpp b/src/strategy/dungeons/wotlk/oculus/OculusStrategy.cpp index 2b98e7da..9c1786b5 100644 --- a/src/strategy/dungeons/wotlk/oculus/OculusStrategy.cpp +++ b/src/strategy/dungeons/wotlk/oculus/OculusStrategy.cpp @@ -36,7 +36,7 @@ void WotlkDungeonOccStrategy::InitTriggers(std::vector &triggers) void WotlkDungeonOccStrategy::InitMultipliers(std::vector &multipliers) { multipliers.push_back(new MountingDrakeMultiplier(botAI)); - multipliers.push_back(new FlyingMultiplier(botAI)); + multipliers.push_back(new OccFlyingMultiplier(botAI)); multipliers.push_back(new UromMultiplier(botAI)); multipliers.push_back(new EregosMultiplier(botAI)); } diff --git a/src/strategy/raids/RaidStrategyContext.h b/src/strategy/raids/RaidStrategyContext.h index 31675f7f..d863aa0a 100644 --- a/src/strategy/raids/RaidStrategyContext.h +++ b/src/strategy/raids/RaidStrategyContext.h @@ -6,6 +6,7 @@ #include "RaidBwlStrategy.h" #include "RaidNaxxStrategy.h" #include "RaidOsStrategy.h" +#include "RaidEoEStrategy.h" #include "RaidMcStrategy.h" #include "RaidAq20Strategy.h" #include "RaidIccStrategy.h" @@ -23,6 +24,7 @@ public: creators["aq20"] = &RaidStrategyContext::aq20; creators["naxx"] = &RaidStrategyContext::naxx; creators["wotlk-os"] = &RaidStrategyContext::wotlk_os; + creators["wotlk-eoe"] = &RaidStrategyContext::wotlk_eoe; creators["uld"] = &RaidStrategyContext::uld; creators["icc"] = &RaidStrategyContext::icc; } @@ -33,6 +35,7 @@ private: static Strategy* aq20(PlayerbotAI* botAI) { return new RaidAq20Strategy(botAI); } static Strategy* naxx(PlayerbotAI* botAI) { return new RaidNaxxStrategy(botAI); } static Strategy* wotlk_os(PlayerbotAI* botAI) { return new RaidOsStrategy(botAI); } + static Strategy* wotlk_eoe(PlayerbotAI* botAI) { return new RaidEoEStrategy(botAI); } static Strategy* uld(PlayerbotAI* botAI) { return new RaidUlduarStrategy(botAI); } static Strategy* icc(PlayerbotAI* botAI) { return new RaidIccStrategy(botAI); } }; diff --git a/src/strategy/raids/eyeofeternity/RaidEoEActionContext.h b/src/strategy/raids/eyeofeternity/RaidEoEActionContext.h index 1250b26b..ba4d841d 100644 --- a/src/strategy/raids/eyeofeternity/RaidEoEActionContext.h +++ b/src/strategy/raids/eyeofeternity/RaidEoEActionContext.h @@ -10,21 +10,21 @@ class RaidEoEActionContext : public NamedObjectContext public: RaidEoEActionContext() { - // creators["sartharion tank position"] = &RaidOsActionContext::tank_position; - // creators["avoid twilight fissure"] = &RaidOsActionContext::avoid_twilight_fissure; - // creators["avoid flame tsunami"] = &RaidOsActionContext::avoid_flame_tsunami; - // creators["sartharion attack priority"] = &RaidOsActionContext::attack_priority; - // creators["enter twilight portal"] = &RaidOsActionContext::enter_twilight_portal; - // creators["exit twilight portal"] = &RaidOsActionContext::exit_twilight_portal; + creators["malygos position"] = &RaidEoEActionContext::position; + creators["malygos target"] = &RaidEoEActionContext::target; + // creators["pull power spark"] = &RaidEoEActionContext::pull_power_spark; + // creators["kill power spark"] = &RaidEoEActionContext::kill_power_spark; + creators["fly drake"] = &RaidEoEActionContext::fly_drake; + creators["drake attack"] = &RaidEoEActionContext::drake_attack; } private: - // static Action* tank_position(PlayerbotAI* ai) { return new SartharionTankPositionAction(ai); } - // static Action* avoid_twilight_fissure(PlayerbotAI* ai) { return new AvoidTwilightFissureAction(ai); } - // static Action* avoid_flame_tsunami(PlayerbotAI* ai) { return new AvoidFlameTsunamiAction(ai); } - // static Action* attack_priority(PlayerbotAI* ai) { return new SartharionAttackPriorityAction(ai); } - // static Action* enter_twilight_portal(PlayerbotAI* ai) { return new EnterTwilightPortalAction(ai); } - // static Action* exit_twilight_portal(PlayerbotAI* ai) { return new ExitTwilightPortalAction(ai); } + static Action* position(PlayerbotAI* ai) { return new MalygosPositionAction(ai); } + static Action* target(PlayerbotAI* ai) { return new MalygosTargetAction(ai); } + // static Action* pull_power_spark(PlayerbotAI* ai) { return new PullPowerSparkAction(ai); } + // static Action* kill_power_spark(PlayerbotAI* ai) { return new KillPowerSparkAction(ai); } + static Action* fly_drake(PlayerbotAI* ai) { return new EoEFlyDrakeAction(ai); } + static Action* drake_attack(PlayerbotAI* ai) { return new EoEDrakeAttackAction(ai); } }; #endif diff --git a/src/strategy/raids/eyeofeternity/RaidEoEActions.cpp b/src/strategy/raids/eyeofeternity/RaidEoEActions.cpp index 0166d92e..4bacf89e 100644 --- a/src/strategy/raids/eyeofeternity/RaidEoEActions.cpp +++ b/src/strategy/raids/eyeofeternity/RaidEoEActions.cpp @@ -3,244 +3,388 @@ #include "Playerbots.h" -// bool SartharionTankPositionAction::Execute(Event event) + +bool MalygosPositionAction::Execute(Event event) +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "malygos"); + if (!boss) { return false; } + + uint8 phase = MalygosTrigger::getPhase(bot, boss); + + float distance = 5.0f; + + if (phase == 1) + { + Unit* spark = nullptr; + + GuidVector targets = AI_VALUE(GuidVector, "possible targets no los"); + for (auto& target : targets) + { + Unit* unit = botAI->GetUnit(target); + if (unit && unit->GetEntry() == NPC_POWER_SPARK) + { + spark = unit; + break; + } + } + + // Position tank + if (botAI->IsMainTank(bot)) + { + if (bot->GetDistance2d(MALYGOS_MAINTANK_POSITION.first, MALYGOS_MAINTANK_POSITION.second) > distance) + { + return MoveTo(EOE_MAP_ID, MALYGOS_MAINTANK_POSITION.first, MALYGOS_MAINTANK_POSITION.second, bot->GetPositionZ(), + false, false, false, false, MovementPriority::MOVEMENT_COMBAT); + } + return false; + } + // Position DK for spark pull + // else if (spark && bot->IsClass(CLASS_DEATH_KNIGHT)) + // { + // if (bot->GetDistance2d(MALYGOS_STACK_POSITION.first, MALYGOS_STACK_POSITION.second) > distance) + // { + // bot->Yell("SPARK SPAWNED, MOVING TO STACK", LANG_UNIVERSAL); + // return MoveTo(EOE_MAP_ID, MALYGOS_STACK_POSITION.first, MALYGOS_STACK_POSITION.second, bot->GetPositionZ(), + // false, false, false, false, MovementPriority::MOVEMENT_COMBAT); + // } + // return false; + // } + else if (spark) + { + return false; + } + else if (!bot->IsClass(CLASS_HUNTER)) + { + if (bot->GetDistance2d(MALYGOS_STACK_POSITION.first, MALYGOS_STACK_POSITION.second) > (distance * 3.0f)) + { + return MoveTo(EOE_MAP_ID, MALYGOS_STACK_POSITION.first, MALYGOS_STACK_POSITION.second, bot->GetPositionZ(), + false, false, false, false, MovementPriority::MOVEMENT_COMBAT); + } + return false; + } + } + + return false; +} + +bool MalygosTargetAction::Execute(Event event) +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "malygos"); + if (!boss) { return false; } + + uint8 phase = MalygosTrigger::getPhase(bot, boss); + + if (phase == 1) + { + if (botAI->IsHeal(bot)) { return false; } + + Unit* newTarget = boss; + Unit* spark = nullptr; + + // GuidVector targets = AI_VALUE(GuidVector, "possible targets no los"); + // for (auto& target : targets) + // { + // Unit* unit = botAI->GetUnit(target); + // if (unit && unit->GetEntry() == NPC_POWER_SPARK) + // { + // spark = unit; + // break; + // } + // } + + // if (spark && botAI->IsRangedDps(bot)) + // { + // newTarget = spark; + // } + + Unit* currentTarget = AI_VALUE(Unit*, "current target"); + + if (!currentTarget || currentTarget->GetEntry() != newTarget->GetEntry()) + { + return Attack(newTarget); + } + } + else if (phase == 2) + { + if (botAI->IsHeal(bot)) { return false; } + + Unit* newTarget = nullptr; + Unit* nexusLord = nullptr; + Unit* scionOfEternity = nullptr; + + GuidVector targets = AI_VALUE(GuidVector, "possible targets no los"); + for (auto& target : targets) + { + Unit* unit = botAI->GetUnit(target); + if (!unit) { continue; } + + if (unit->GetEntry() == NPC_NEXUS_LORD) + { + nexusLord = unit; + } + else if (unit->GetEntry() == NPC_SCION_OF_ETERNITY) + { + scionOfEternity = unit; + } + } + + if (botAI->IsRangedDps(bot) && scionOfEternity) + { + newTarget = scionOfEternity; + } + else + { + newTarget = nexusLord; + } + + if (!newTarget) { return false; } + + Unit* currentTarget = AI_VALUE(Unit*, "current target"); + if (!currentTarget || currentTarget->GetEntry() != newTarget->GetEntry()) + { + return Attack(newTarget); + } + } + + // else if (phase == 3) + // {} + + return false; +} + +// bool PullPowerSparkAction::Execute(Event event) // { -// Unit* boss = AI_VALUE2(Unit*, "find target", "sartharion"); -// if (!boss) { return false; } +// Unit* spark = nullptr; -// // Unit* shadron = AI_VALUE2(Unit*, "find target", "shadron"); -// // Unit* tenebron = AI_VALUE2(Unit*, "find target", "tenebron"); -// // Unit* vesperon = AI_VALUE2(Unit*, "find target", "vesperon"); -// Unit* shadron = nullptr; -// Unit* tenebron = nullptr; -// Unit* vesperon = nullptr; - -// // Detect incoming drakes before they are on aggro table // GuidVector targets = AI_VALUE(GuidVector, "possible targets no los"); // for (auto& target : targets) // { // Unit* unit = botAI->GetUnit(target); -// if (!unit) { continue; } - -// switch (unit->GetEntry()) +// if (unit && unit->GetEntry() == NPC_POWER_SPARK) // { -// case NPC_SHADRON: -// shadron = unit; -// continue; -// case NPC_TENEBRON: -// tenebron = unit; -// continue; -// case NPC_VESPERON: -// vesperon = unit; -// continue; -// default: -// continue; +// spark = unit; +// break; // } // } -// Position currentPos = bot->GetPosition(); -// // Adjustable, this is the acceptable distance to stack point that will be accepted as "safe" -// float looseDistance = 12.0f; +// if (!spark) { return false; } -// if (botAI->IsMainTank(bot)) +// if (spark->GetDistance2d(MALYGOS_STACK_POSITION.first, MALYGOS_STACK_POSITION.second) > 3.0f) // { -// if (bot->GetExactDist2d(SARTHARION_MAINTANK_POSITION.first, SARTHARION_MAINTANK_POSITION.second) > looseDistance) -// { -// return MoveTo(OS_MAP_ID, SARTHARION_MAINTANK_POSITION.first, SARTHARION_MAINTANK_POSITION.second, currentPos.GetPositionZ(), -// false, false, false, false, MovementPriority::MOVEMENT_COMBAT); -// } -// } -// // Offtank grab drakes -// else if (shadron || tenebron || vesperon) -// { -// float triggerDistance = 100.0f; -// // Prioritise threat before positioning -// if (tenebron && bot->GetExactDist2d(tenebron) < triggerDistance && -// tenebron->GetTarget() != bot->GetGUID() && AI_VALUE(Unit*, "current target") != tenebron) -// { -// return Attack(tenebron); -// } -// if (shadron && bot->GetExactDist2d(shadron) < triggerDistance && -// shadron->GetTarget() != bot->GetGUID() && AI_VALUE(Unit*, "current target") != shadron) -// { -// return Attack(shadron); -// } -// if (vesperon && bot->GetExactDist2d(vesperon) < triggerDistance && -// vesperon->GetTarget() != bot->GetGUID() && AI_VALUE(Unit*, "current target") != vesperon) -// { -// return Attack(vesperon); -// } - -// bool drakeInCombat = (tenebron && bot->GetExactDist2d(tenebron) < triggerDistance) || -// (shadron && bot->GetExactDist2d(shadron) < triggerDistance) || -// (vesperon && bot->GetExactDist2d(vesperon) < triggerDistance); -// // Offtank has threat on drakes, check positioning -// if (drakeInCombat && bot->GetExactDist2d(SARTHARION_OFFTANK_POSITION.first, SARTHARION_OFFTANK_POSITION.second) > looseDistance) -// { -// return MoveTo(OS_MAP_ID, SARTHARION_OFFTANK_POSITION.first, SARTHARION_OFFTANK_POSITION.second, currentPos.GetPositionZ(), -// false, false, false, false, MovementPriority::MOVEMENT_COMBAT); -// } -// } -// return false; -// } - -// bool AvoidTwilightFissureAction::Execute(Event event) -// { -// const float radius = 5.0f; - -// GuidVector npcs = AI_VALUE(GuidVector, "nearest hostile npcs"); -// for (auto& npc : npcs) -// { -// Unit* unit = botAI->GetUnit(npc); -// if (unit && unit->GetEntry() == NPC_TWILIGHT_FISSURE) -// { -// float currentDistance = bot->GetDistance2d(unit); -// if (currentDistance < radius) -// { -// return MoveAway(unit, radius - currentDistance); -// } -// } -// } -// return false; -// } - -// bool AvoidFlameTsunamiAction::Execute(Event event) -// { -// // Adjustable, this is the acceptable distance to stack point that will be accepted as "safe" -// float looseDistance = 4.0f; - -// GuidVector npcs = AI_VALUE(GuidVector, "nearest hostile npcs"); -// for (auto& npc : npcs) -// { -// Unit* unit = botAI->GetUnit(npc); -// if (unit && unit->GetEntry() == NPC_FLAME_TSUNAMI) -// { -// Position currentPos = bot->GetPosition(); - -// // I think these are centrepoints for the wave segments. Either way they uniquely identify the wave -// // direction as they have different coords for the left and right waves -// // int casting is not a mistake, need to avoid FP errors somehow. -// // I always saw these accurate to around 6 decimal places, but if there are issues, -// // can switch this to abs comparison of floats which would technically be more robust. -// int posY = (int) unit->GetPositionY(); -// if (posY == 505 || posY == 555) // RIGHT WAVE -// { -// bool wavePassed = currentPos.GetPositionX() > unit->GetPositionX(); -// if (wavePassed) -// { -// return false; -// } - -// if (bot->GetExactDist2d(currentPos.GetPositionX(), TSUNAMI_RIGHT_SAFE_ALL) > looseDistance) -// { -// return MoveTo(OS_MAP_ID, currentPos.GetPositionX(), TSUNAMI_RIGHT_SAFE_ALL, currentPos.GetPositionZ(), -// false, false, false, false, MovementPriority::MOVEMENT_COMBAT); -// } -// } -// else // LEFT WAVE -// { -// bool wavePassed = currentPos.GetPositionX() < unit->GetPositionX(); -// if (wavePassed) -// { -// return false; -// } - -// if (botAI->IsMelee(bot)) -// { -// if (bot->GetExactDist2d(currentPos.GetPositionX(), TSUNAMI_LEFT_SAFE_MELEE) > looseDistance) -// { -// return MoveTo(OS_MAP_ID, currentPos.GetPositionX(), TSUNAMI_LEFT_SAFE_MELEE, currentPos.GetPositionZ(), -// false, false, false, false, MovementPriority::MOVEMENT_COMBAT); -// } -// } -// else // Ranged/healers -// { -// if (bot->GetExactDist2d(currentPos.GetPositionX(), TSUNAMI_LEFT_SAFE_RANGED) > looseDistance) -// { -// return MoveTo(OS_MAP_ID, currentPos.GetPositionX(), TSUNAMI_LEFT_SAFE_RANGED, currentPos.GetPositionZ(), -// false, false, false, false, MovementPriority::MOVEMENT_COMBAT); -// } -// } -// } -// } -// } -// return false; -// } - -// bool SartharionAttackPriorityAction::Execute(Event event) -// { -// Unit* sartharion = AI_VALUE2(Unit*, "find target", "sartharion"); -// Unit* shadron = AI_VALUE2(Unit*, "find target", "shadron"); -// Unit* tenebron = AI_VALUE2(Unit*, "find target", "tenebron"); -// Unit* vesperon = AI_VALUE2(Unit*, "find target", "vesperon"); -// Unit* acolyte = AI_VALUE2(Unit*, "find target", "acolyte of shadron"); - -// Unit* target = nullptr; - -// if (acolyte) -// { -// target = acolyte; -// } -// else if (vesperon) -// { -// target = vesperon; -// } -// else if (tenebron) -// { -// target = tenebron; -// } -// else if (shadron) -// { -// target = shadron; -// } -// else if (sartharion) -// { -// target = sartharion; -// } - -// if (target && AI_VALUE(Unit*, "current target") != target) -// { -// return Attack(target); +// bot->Yell("GRIPPING SPARK", LANG_UNIVERSAL); +// return botAI->CastSpell("death grip", spark); // } // return false; // } -// bool EnterTwilightPortalAction::Execute(Event event) +// bool PullPowerSparkAction::isPossible() // { -// Unit* boss = AI_VALUE2(Unit*, "find target", "sartharion"); -// if (!boss || !boss->HasAura(SPELL_GIFT_OF_TWILIGHT_FIRE)) { return false; } +// Unit* spark = nullptr; -// GameObject* portal = bot->FindNearestGameObject(GO_TWILIGHT_PORTAL, 100.0f); -// if (!portal) { return false; } - -// if (!portal->IsAtInteractDistance(bot)) +// GuidVector targets = AI_VALUE(GuidVector, "possible targets no los"); +// for (auto& target : targets) // { -// return MoveTo(portal, fmaxf(portal->GetInteractionDistance() - 1.0f, 0.0f)); +// Unit* unit = botAI->GetUnit(target); +// if (unit && unit->GetEntry() == NPC_POWER_SPARK) +// { +// spark = unit; +// break; +// } // } -// // Go through portal -// WorldPacket data1(CMSG_GAMEOBJ_USE); -// data1 << portal->GetGUID(); -// bot->GetSession()->HandleGameObjectUseOpcode(data1); - -// return true; +// return botAI->CanCastSpell(spell, spark); // } -// bool ExitTwilightPortalAction::Execute(Event event) +// bool PullPowerSparkAction::isUseful() // { -// GameObject* portal = bot->FindNearestGameObject(GO_NORMAL_PORTAL, 100.0f); -// if (!portal) { return false; } +// Unit* spark = nullptr; -// if (!portal->IsAtInteractDistance(bot)) +// GuidVector targets = AI_VALUE(GuidVector, "possible targets no los"); +// for (auto& target : targets) // { -// return MoveTo(portal, fmaxf(portal->GetInteractionDistance() - 1.0f, 0.0f)); +// Unit* unit = botAI->GetUnit(target); +// if (unit && unit->GetEntry() == NPC_POWER_SPARK) +// { +// spark = unit; +// break; +// } // } -// // Go through portal -// WorldPacket data1(CMSG_GAMEOBJ_USE); -// data1 << portal->GetGUID(); -// bot->GetSession()->HandleGameObjectUseOpcode(data1); +// if (!spark) +// return false; -// return true; +// if (!spark->IsInWorld() || spark->GetMapId() != bot->GetMapId()) +// return false; + +// return bot->GetDistance2d(MALYGOS_STACK_POSITION.first, MALYGOS_STACK_POSITION.second) < 3.0f; // } + +// bool KillPowerSparkAction::Execute(Event event) +// { +// return false; +// } + +bool EoEFlyDrakeAction::isPossible() +{ + Unit* vehicleBase = bot->GetVehicleBase(); + return (vehicleBase && vehicleBase->GetEntry() == NPC_WYRMREST_SKYTALON); +} +bool EoEFlyDrakeAction::Execute(Event event) +{ + Player* master = botAI->GetMaster(); + if (!master) { return false; } + Unit* masterVehicle = master->GetVehicleBase(); + Unit* vehicleBase = bot->GetVehicleBase(); + if (!vehicleBase || !masterVehicle) { return false; } + + MotionMaster* mm = vehicleBase->GetMotionMaster(); + Unit* boss = AI_VALUE2(Unit*, "find target", "malygos"); + if (boss && false) + { + // Handle as boss encounter instead of formation flight + mm->Clear(false); + float distance = vehicleBase->GetExactDist(boss); + float range = 55.0f; // Drake range is 60yd + if (distance > range) + { + mm->MoveForwards(boss, range - distance); + vehicleBase->SendMovementFlagUpdate(); + return true; + } + + vehicleBase->SetFacingToObject(boss); + mm->MoveIdle(); + vehicleBase->SendMovementFlagUpdate(); + return false; + } + + if (vehicleBase->GetExactDist(masterVehicle) > 5.0f) + { + uint8 numPlayers; + bot->GetRaidDifficulty() == RAID_DIFFICULTY_25MAN_NORMAL ? numPlayers = 25 : numPlayers = 10; + // 3/4 of a circle, with frontal cone 90 deg unobstructed + float angle = botAI->GetGroupSlotIndex(bot) * (2*M_PI - M_PI_2)/numPlayers + M_PI_2; + // float angle = M_PI; + vehicleBase->SetCanFly(true); + mm->MoveFollow(masterVehicle, 3.0f, angle); + vehicleBase->SendMovementFlagUpdate(); + return true; + } + return false; +} + +bool EoEDrakeAttackAction::isPossible() +{ + Unit* vehicleBase = bot->GetVehicleBase(); + return (vehicleBase && vehicleBase->GetEntry() == NPC_WYRMREST_SKYTALON); +} +bool EoEDrakeAttackAction::Execute(Event event) +{ + vehicleBase = bot->GetVehicleBase(); + if (!vehicleBase) { return false; } + + // Unit* target = AI_VALUE(Unit*, "current target"); + Unit* boss = AI_VALUE2(Unit*, "find target", "malygos"); + // if (!boss) { return false; } + + if (!boss) + { + GuidVector npcs = AI_VALUE(GuidVector, "possible targets"); + for (auto& npc : npcs) + { + Unit* unit = botAI->GetUnit(npc); + if (!unit || unit->GetEntry() != NPC_MALYGOS) { continue; } + + boss = unit; + break; + } + } + // Check this again to see if a target was assigned + if (!boss) { return false; } + + if (botAI->IsHeal(bot)) + { + return DrakeHealAction(); + } + else + { + return DrakeDpsAction(boss); + } + + return false; +} + +bool EoEDrakeAttackAction::CastDrakeSpellAction(Unit* target, uint32 spellId, uint32 cooldown) +{ + if (botAI->CanCastVehicleSpell(spellId, target)) + if (botAI->CastVehicleSpell(spellId, target)) + { + vehicleBase->AddSpellCooldown(spellId, 0, cooldown); + return true; + } + return false; +} + +bool EoEDrakeAttackAction::DrakeDpsAction(Unit* target) +{ + Unit* vehicleBase = bot->GetVehicleBase(); + if (!vehicleBase) { return false; } + + Vehicle* veh = bot->GetVehicle(); + + uint8 comboPoints = vehicleBase->GetComboPoints(target); + if (comboPoints >= 2) + { + return CastDrakeSpellAction(target, SPELL_ENGULF_IN_FLAMES, 0); + } + else + { + return CastDrakeSpellAction(target, SPELL_FLAME_SPIKE, 0); + } +} + +bool EoEDrakeAttackAction::DrakeHealAction() +{ + Unit* vehicleBase = bot->GetVehicleBase(); + if (!vehicleBase) { return false; } + + Unit* target = vehicleBase->GetComboTarget(); + if (!target) + { + // Unit* newTarget = nullptr; + Unit* newTarget = vehicleBase; + GuidVector members = AI_VALUE(GuidVector, "group members"); + for (auto& member : members) + { + Unit* unit = botAI->GetUnit(member); + if (!unit) + { + continue; + } + + Unit* drake = unit->GetVehicleBase(); + if (!drake || drake->IsFullHealth()) { continue; } + + if (!newTarget || drake->GetHealthPct() < newTarget->GetHealthPct() - 5.0f) + { + newTarget = drake; + } + } + target = newTarget; + } + + uint8 comboPoints = vehicleBase->GetComboPoints(target); + if (comboPoints >= 5) + { + return CastDrakeSpellAction(target, SPELL_LIFE_BURST, 0); + } + else + { + // "Revivify" may be bugged server-side: + // "botAI->CanCastVehicleSpell()" returns SPELL_FAILED_BAD_TARGETS when targeting drakes. + // Forcing the cast attempt seems to succeed, not sure what's going on here. + // return CastDrakeSpellAction(target, SPELL_REVIVIFY, 0); + return botAI->CastVehicleSpell(SPELL_REVIVIFY, target); + } +} diff --git a/src/strategy/raids/eyeofeternity/RaidEoEActions.h b/src/strategy/raids/eyeofeternity/RaidEoEActions.h index b5173f71..d2d158c7 100644 --- a/src/strategy/raids/eyeofeternity/RaidEoEActions.h +++ b/src/strategy/raids/eyeofeternity/RaidEoEActions.h @@ -3,62 +3,67 @@ #include "MovementActions.h" #include "AttackAction.h" +#include "GenericSpellActions.h" #include "PlayerbotAI.h" #include "Playerbots.h" -// const float TSUNAMI_LEFT_SAFE_MELEE = 552.0f; -// const float TSUNAMI_LEFT_SAFE_RANGED = 504.0f; -// const float TSUNAMI_RIGHT_SAFE_ALL = 529.0f; -// const std::pair SARTHARION_MAINTANK_POSITION = {3258.5f, 532.5f}; -// const std::pair SARTHARION_OFFTANK_POSITION = {3230.0f, 526.0f}; -// const std::pair SARTHARION_RANGED_POSITION = {3248.0f, 507.0f}; +const std::pair MALYGOS_MAINTANK_POSITION = {757.0f, 1337.0f}; +const std::pair MALYGOS_STACK_POSITION = {755.0f, 1301.0f}; -// class SartharionTankPositionAction : public AttackAction -// { -// public: -// SartharionTankPositionAction(PlayerbotAI* botAI, std::string const name = "sartharion tank position") -// : AttackAction(botAI, name) {} -// bool Execute(Event event) override; -// }; +class MalygosPositionAction : public MovementAction +{ +public: + MalygosPositionAction(PlayerbotAI* botAI, std::string const name = "malygos position") + : MovementAction(botAI, name) {} + bool Execute(Event event) override; +}; -// class AvoidTwilightFissureAction : public MovementAction -// { -// public: -// AvoidTwilightFissureAction(PlayerbotAI* botAI, std::string const name = "avoid twilight fissure") -// : MovementAction(botAI, name) {} -// bool Execute(Event event) override; -// }; +class MalygosTargetAction : public AttackAction +{ +public: + MalygosTargetAction(PlayerbotAI* botAI, std::string const name = "malygos target") + : AttackAction(botAI, name) {} + bool Execute(Event event) override; +}; -// class AvoidFlameTsunamiAction : public MovementAction -// { -// public: -// AvoidFlameTsunamiAction(PlayerbotAI* botAI, std::string const name = "avoid flame tsunami") -// : MovementAction(botAI, name) {} -// bool Execute(Event event) override; -// }; +class PullPowerSparkAction : public CastSpellAction +{ +public: + PullPowerSparkAction(PlayerbotAI* botAI, std::string const name = "pull power spark") + : CastSpellAction(botAI, "death grip") {} + bool Execute(Event event) override; + bool isPossible() override; + bool isUseful() override; +}; -// class SartharionAttackPriorityAction : public AttackAction -// { -// public: -// SartharionAttackPriorityAction(PlayerbotAI* botAI, std::string const name = "sartharion attack priority") -// : AttackAction(botAI, name) {} -// bool Execute(Event event) override; -// }; +class KillPowerSparkAction : public AttackAction +{ +public: + KillPowerSparkAction(PlayerbotAI* botAI, std::string const name = "kill power spark") + : AttackAction(botAI, name) {} + bool Execute(Event event) override; +}; -// class EnterTwilightPortalAction : public MovementAction -// { -// public: -// EnterTwilightPortalAction(PlayerbotAI* botAI, std::string const name = "enter twilight portal") -// : MovementAction(botAI, name) {} -// bool Execute(Event event) override; -// }; +class EoEFlyDrakeAction : public MovementAction +{ +public: + EoEFlyDrakeAction(PlayerbotAI* ai) : MovementAction(ai, "eoe fly drake") {} + bool Execute(Event event) override; + bool isPossible() override; +}; -// class ExitTwilightPortalAction : public MovementAction -// { -// public: -// ExitTwilightPortalAction(PlayerbotAI* botAI, std::string const name = "exit twilight portal") -// : MovementAction(botAI, name) {} -// bool Execute(Event event) override; -// }; +class EoEDrakeAttackAction : public Action +{ +public: + EoEDrakeAttackAction(PlayerbotAI* botAI) : Action(botAI, "eoe drake attack") {} + bool Execute(Event event) override; + bool isPossible() override; + +protected: + Unit* vehicleBase; + bool CastDrakeSpellAction(Unit* target, uint32 spellId, uint32 cooldown); + bool DrakeDpsAction(Unit* target); + bool DrakeHealAction(); +}; #endif diff --git a/src/strategy/raids/eyeofeternity/RaidEoEMultipliers.cpp b/src/strategy/raids/eyeofeternity/RaidEoEMultipliers.cpp index 9d077802..0866bfb1 100644 --- a/src/strategy/raids/eyeofeternity/RaidEoEMultipliers.cpp +++ b/src/strategy/raids/eyeofeternity/RaidEoEMultipliers.cpp @@ -47,3 +47,68 @@ // } // return 1.0f; // } + +float MalygosMultiplier::GetValue(Action* action) +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "malygos"); + + uint8 phase = MalygosTrigger::getPhase(bot, boss); + if (phase == 0) { return 1.0f; } + + if (phase == 1) + { + if (dynamic_cast(action)) + { + return 0.0f; + } + + if (botAI->IsDps(bot) && dynamic_cast(action)) + { + return 0.0f; + } + + if (botAI->IsRangedDps(bot) && dynamic_cast(action)) + { + return 0.0f; + } + + if (!botAI->IsMainTank(bot) && dynamic_cast(action)) + { + return 0.0f; + } + + // if (dynamic_cast(action) && !dynamic_cast(action)) + // { + // return 0.0f; + // } + } + else if (phase == 2) + { + if (botAI->IsDps(bot) && dynamic_cast(action)) + { + return 0.0f; + } + + if (dynamic_cast(action)) + { + return 0.0f; + } + + if (dynamic_cast(action)) + { + Unit* target = action->GetTarget(); + if (target && target->GetEntry() == NPC_SCION_OF_ETERNITY) + return 0.0f; + } + } + else if (phase == 3) + { + // Suppresses FollowAction as well as some attack-based movements + if (dynamic_cast(action) && !dynamic_cast(action)) + { + return 0.0f; + } + } + + return 1.0f; +} diff --git a/src/strategy/raids/eyeofeternity/RaidEoEMultipliers.h b/src/strategy/raids/eyeofeternity/RaidEoEMultipliers.h index 0a710601..05db5ee9 100644 --- a/src/strategy/raids/eyeofeternity/RaidEoEMultipliers.h +++ b/src/strategy/raids/eyeofeternity/RaidEoEMultipliers.h @@ -4,13 +4,13 @@ #include "Multiplier.h" -// class SartharionMultiplier : public Multiplier -// { -// public: -// SartharionMultiplier(PlayerbotAI* ai) : Multiplier(ai, "sartharion") {} +class MalygosMultiplier : public Multiplier +{ +public: + MalygosMultiplier(PlayerbotAI* ai) : Multiplier(ai, "malygos") {} -// public: -// virtual float GetValue(Action* action); -// }; +public: + virtual float GetValue(Action* action); +}; #endif diff --git a/src/strategy/raids/eyeofeternity/RaidEoEStrategy.cpp b/src/strategy/raids/eyeofeternity/RaidEoEStrategy.cpp index 630ca7f3..f30cf30a 100644 --- a/src/strategy/raids/eyeofeternity/RaidEoEStrategy.cpp +++ b/src/strategy/raids/eyeofeternity/RaidEoEStrategy.cpp @@ -4,29 +4,22 @@ void RaidEoEStrategy::InitTriggers(std::vector& triggers) { - // triggers.push_back( - // new TriggerNode("sartharion tank", - // NextAction::array(0, new NextAction("sartharion tank position", ACTION_MOVE), nullptr))); - // triggers.push_back( - // new TriggerNode("twilight fissure", - // NextAction::array(0, new NextAction("avoid twilight fissure", ACTION_RAID + 2), nullptr))); - // triggers.push_back( - // new TriggerNode("flame tsunami", - // NextAction::array(0, new NextAction("avoid flame tsunami", ACTION_RAID + 1), nullptr))); - // triggers.push_back( - // new TriggerNode("sartharion dps", - // NextAction::array(0, new NextAction("sartharion attack priority", ACTION_RAID), nullptr))); - // // Flank dragon positioning - // triggers.push_back(new TriggerNode("sartharion melee positioning", - // NextAction::array(0, new NextAction("rear flank", ACTION_MOVE + 4), nullptr))); - - // triggers.push_back(new TriggerNode("twilight portal enter", - // NextAction::array(0, new NextAction("enter twilight portal", ACTION_RAID + 1), nullptr))); - // triggers.push_back(new TriggerNode("twilight portal exit", - // NextAction::array(0, new NextAction("exit twilight portal", ACTION_RAID + 1), nullptr))); + triggers.push_back(new TriggerNode("malygos", + NextAction::array(0, new NextAction("malygos position", ACTION_MOVE), nullptr))); + triggers.push_back(new TriggerNode("malygos", + NextAction::array(0, new NextAction("malygos target", ACTION_RAID + 1), nullptr))); + // triggers.push_back(new TriggerNode("power spark", + // NextAction::array(0, new NextAction("pull power spark", ACTION_RAID + 2), nullptr))); + // triggers.push_back(new TriggerNode("power spark", + // NextAction::array(0, new NextAction("kill power spark", ACTION_RAID + 3), nullptr))); + + triggers.push_back(new TriggerNode("group flying", + NextAction::array(0, new NextAction("fly drake", ACTION_NORMAL + 1), nullptr))); + triggers.push_back(new TriggerNode("drake combat", + NextAction::array(0, new NextAction("drake attack", ACTION_NORMAL + 5), nullptr))); } void RaidEoEStrategy::InitMultipliers(std::vector &multipliers) { - // multipliers.push_back(new SartharionMultiplier(botAI)); + multipliers.push_back(new MalygosMultiplier(botAI)); } diff --git a/src/strategy/raids/eyeofeternity/RaidEoETriggerContext.h b/src/strategy/raids/eyeofeternity/RaidEoETriggerContext.h index 438d0ef7..0c58f6cb 100644 --- a/src/strategy/raids/eyeofeternity/RaidEoETriggerContext.h +++ b/src/strategy/raids/eyeofeternity/RaidEoETriggerContext.h @@ -10,23 +10,13 @@ class RaidEoETriggerContext : public NamedObjectContext public: RaidEoETriggerContext() { - // creators["sartharion tank"] = &RaidOsTriggerContext::sartharion_tank; - // creators["flame tsunami"] = &RaidOsTriggerContext::flame_tsunami; - // creators["twilight fissure"] = &RaidOsTriggerContext::twilight_fissure; - // creators["sartharion dps"] = &RaidOsTriggerContext::sartharion_dps; - // creators["sartharion melee positioning"] = &RaidOsTriggerContext::sartharion_melee; - // creators["twilight portal enter"] = &RaidOsTriggerContext::twilight_portal_enter; - // creators["twilight portal exit"] = &RaidOsTriggerContext::twilight_portal_exit; + creators["malygos"] = &RaidEoETriggerContext::malygos; + creators["power spark"] = &RaidEoETriggerContext::power_spark; } private: - // static Trigger* sartharion_tank(PlayerbotAI* ai) { return new SartharionTankTrigger(ai); } - // static Trigger* flame_tsunami(PlayerbotAI* ai) { return new FlameTsunamiTrigger(ai); } - // static Trigger* twilight_fissure(PlayerbotAI* ai) { return new TwilightFissureTrigger(ai); } - // static Trigger* sartharion_dps(PlayerbotAI* ai) { return new SartharionDpsTrigger(ai); } - // static Trigger* sartharion_melee(PlayerbotAI* ai) { return new SartharionMeleePositioningTrigger(ai); } - // static Trigger* twilight_portal_enter(PlayerbotAI* ai) { return new TwilightPortalEnterTrigger(ai); } - // static Trigger* twilight_portal_exit(PlayerbotAI* ai) { return new TwilightPortalExitTrigger(ai); } + static Trigger* power_spark(PlayerbotAI* ai) { return new PowerSparkTrigger(ai); } + static Trigger* malygos(PlayerbotAI* ai) { return new MalygosTrigger(ai); } }; #endif diff --git a/src/strategy/raids/eyeofeternity/RaidEoETriggers.cpp b/src/strategy/raids/eyeofeternity/RaidEoETriggers.cpp index 8427ab8f..2506ea1f 100644 --- a/src/strategy/raids/eyeofeternity/RaidEoETriggers.cpp +++ b/src/strategy/raids/eyeofeternity/RaidEoETriggers.cpp @@ -2,127 +2,52 @@ #include "SharedDefines.h" -// bool SartharionTankTrigger::IsActive() -// { -// Unit* boss = AI_VALUE2(Unit*, "find target", "sartharion"); -// if (!boss) { return false; } +uint8 MalygosTrigger::getPhase(Player* bot, Unit* boss) +{ + uint8 phase = 0; + Unit* vehicle = bot->GetVehicleBase(); + if (bot->GetMapId() != EOE_MAP_ID) { return phase; } + + if (vehicle && vehicle->GetEntry() == NPC_WYRMREST_SKYTALON) + { + phase = 3; + } + else if (boss && boss->HealthAbovePct(50)) + { + phase = 1; + } + else if (boss) + { + phase = 2; + } + + return phase; +} + +bool MalygosTrigger::IsActive() +{ + return bool(AI_VALUE2(Unit*, "find target", "malygos")); +} + +bool PowerSparkTrigger::IsActive() +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "malygos"); + if (!boss) { return false; } + + if (bot->getClass() != CLASS_DEATH_KNIGHT) + { + return false; + } + + GuidVector targets = AI_VALUE(GuidVector, "possible targets no los"); + for (auto& target : targets) + { + Unit* unit = botAI->GetUnit(target); + if (unit && unit->GetEntry() == NPC_POWER_SPARK) + { + return true; + } + } -// return botAI->IsTank(bot); -// } - -// bool FlameTsunamiTrigger::IsActive() -// { -// if (botAI->IsTank(bot)) { return false; } - -// Unit* boss = AI_VALUE2(Unit*, "find target", "sartharion"); -// if (!boss) { return false; } - - -// GuidVector npcs = AI_VALUE(GuidVector, "nearest hostile npcs"); -// for (auto& npc : npcs) -// { -// Unit* unit = botAI->GetUnit(npc); -// if (unit) -// { -// if (unit->GetEntry() == NPC_FLAME_TSUNAMI) -// { -// return true; -// } -// } -// } - -// return false; -// } - -// bool TwilightFissureTrigger::IsActive() -// { -// Unit* boss = AI_VALUE2(Unit*, "find target", "sartharion"); -// if (!boss) { return false; } - - -// GuidVector npcs = AI_VALUE(GuidVector, "nearest hostile npcs"); -// for (auto& npc : npcs) -// { -// Unit* unit = botAI->GetUnit(npc); -// if (unit) -// { -// if (unit->GetEntry() == NPC_TWILIGHT_FISSURE) -// { -// return true; -// } -// } -// } - -// return false; -// } - -// bool SartharionDpsTrigger::IsActive() -// { -// Unit* boss = AI_VALUE2(Unit*, "find target", "sartharion"); -// if (!boss) { return false; } - -// return botAI->IsDps(bot); -// } - -// bool SartharionMeleePositioningTrigger::IsActive() -// { -// if (!botAI->IsMelee(bot) || !botAI->IsDps(bot)) { return false; } - -// Unit* boss = AI_VALUE2(Unit*, "find target", "sartharion"); -// if (!boss) { return false; } - -// Unit* shadron = AI_VALUE2(Unit*, "find target", "shadron"); -// Unit* tenebron = AI_VALUE2(Unit*, "find target", "tenebron"); -// Unit* vesperon = AI_VALUE2(Unit*, "find target", "vesperon"); - -// return !(shadron || tenebron || vesperon); -// } - -// bool TwilightPortalEnterTrigger::IsActive() -// { -// if (botAI->IsMainTank(bot) || botAI->IsHealAssistantOfIndex(bot, 0)) { return false; } - -// // In 25-man, take two healers in. Otherwise just take one -// // if (bot->GetRaidDifficulty() == RAID_DIFFICULTY_25MAN_NORMAL) -// // { -// // if (botAI->IsHealAssistantOfIndex(bot, 0) || botAI->IsHealAssistantOfIndex(bot, 1)) -// // { -// // return false; -// // } -// // } -// // else -// // { -// // if (botAI->IsHealAssistantOfIndex(bot, 0)) -// // { -// // return false; -// // } -// // } - - -// // Don't enter portal until drakes are dead -// if (bot->HasAura(SPELL_POWER_OF_SHADRON) || -// bot->HasAura(SPELL_POWER_OF_TENEBRON) || -// bot->HasAura(SPELL_POWER_OF_VESPERON)) -// { -// return false; -// } - -// Unit* boss = AI_VALUE2(Unit*, "find target", "sartharion"); -// if (!boss) { return false; } - -// // GuidVector objects = AI_VALUE(GuidVector, "nearest game objects no los"); -// // for (auto& object : objects) -// // { -// // GameObject* go = botAI->GetGameObject(object); -// // if (go && go->GetEntry() == GO_TWILIGHT_PORTAL) -// // { -// // return true; -// // } -// // } -// return bool(bot->FindNearestGameObject(GO_TWILIGHT_PORTAL, 100.0f)); -// } - -// bool TwilightPortalExitTrigger::IsActive() -// { -// return bot->HasAura(SPELL_TWILIGHT_SHIFT) && !AI_VALUE2(Unit*, "find target", "acolyte of shadron"); -// } \ No newline at end of file + return false; +} diff --git a/src/strategy/raids/eyeofeternity/RaidEoETriggers.h b/src/strategy/raids/eyeofeternity/RaidEoETriggers.h index 798e5a49..9262c114 100644 --- a/src/strategy/raids/eyeofeternity/RaidEoETriggers.h +++ b/src/strategy/raids/eyeofeternity/RaidEoETriggers.h @@ -7,114 +7,52 @@ enum EyeOfEternityIDs { - // // Bosses - // NPC_SARTHARION = 28860, - // NPC_SHADRON = 30451, - // NPC_TENEBRON = 30452, - // NPC_VESPERON = 30449, + NPC_MALYGOS = 28859, + NPC_POWER_SPARK = 30084, + NPC_NEXUS_LORD = 30245, + NPC_SCION_OF_ETERNITY = 30249, + NPC_WYRMREST_SKYTALON = 30161, + + SPELL_POWER_SPARK_VISUAL = 55845, + SPELL_POWER_SPARK_GROUND_BUFF = 55852, + SPELL_POWER_SPARK_MALYGOS_BUFF = 56152, - // // Mini-boss shared - // SPELL_SHADOW_BREATH = 57570, - // SPELL_SHADOW_FISSURE = 57579, - // SPELL_SUMMON_TWILIGHT_WHELP = 58035, - // SPELL_GIFT_OF_TWILIGHT_SHADOW = 57835, - // SPELL_TWILIGHT_TORMENT_VESPERON = 57935, + SPELL_TELEPORT_VISUAL = 52096, - // // Sartharion - // SPELL_SARTHARION_CLEAVE = 56909, - // SPELL_SARTHARION_FLAME_BREATH = 56908, - // SPELL_SARTHARION_TAIL_LASH = 56910, - // SPELL_CYCLONE_AURA_PERIODIC = 57598, - // SPELL_LAVA_STRIKE_DUMMY = 57578, - // SPELL_LAVA_STRIKE_DUMMY_TRIGGER = 57697, - // SPELL_LAVA_STRIKE_SUMMON = 57572, - // SPELL_SARTHARION_PYROBUFFET = 56916, - // SPELL_SARTHARION_BERSERK = 61632, - // SPELL_SARTHARION_TWILIGHT_REVENGE = 60639, + SPELL_SCION_ARCANE_BARRAGE = 56397, + SPELL_ARCANE_SHOCK_N = 57058, + SPELL_ARCANE_SHOCK_H = 60073, + SPELL_HASTE = 57060, - // // Sartharion with drakes - // SPELL_WILL_OF_SARTHARION = 61254, - // SPELL_POWER_OF_TENEBRON = 61248, - // SPELL_POWER_OF_VESPERON = 61251, - // SPELL_POWER_OF_SHADRON = 58105, - // SPELL_GIFT_OF_TWILIGHT_FIRE = 58766, + SPELL_ALEXSTRASZA_GIFT = 61028, - // // Visuals - // SPELL_EGG_MARKER_VISUAL = 58547, - // SPELL_FLAME_TSUNAMI_VISUAL = 57494, - - // // Misc - // SPELL_FADE_ARMOR = 60708, - // SPELL_FLAME_TSUNAMI_DAMAGE_AURA = 57492, - // SPELL_FLAME_TSUNAMI_LEAP = 60241, - // SPELL_SARTHARION_PYROBUFFET_TRIGGER = 57557, - - // NPC_TWILIGHT_EGG = 30882, - // NPC_TWILIGHT_WHELP = 30890, - // NPC_DISCIPLE_OF_SHADRON = 30688, - // NPC_DISCIPLE_OF_VESPERON = 30858, - // NPC_ACOLYTE_OF_SHADRON = 31218, - // NPC_ACOLYTE_OF_VESPERON = 31219, - - // // Sartharion fight - // NPC_LAVA_BLAZE = 30643, - // NPC_FLAME_TSUNAMI = 30616, - // NPC_SAFE_AREA_TRIGGER = 30494, - // NPC_TWILIGHT_FISSURE = 30641, - // GO_TWILIGHT_PORTAL = 193988, - // GO_NORMAL_PORTAL = 193989, - // SPELL_TWILIGHT_SHIFT = 57874, + // Drake Abilities: + // DPS + SPELL_FLAME_SPIKE = 56091, + SPELL_ENGULF_IN_FLAMES = 56092, + // Healing + SPELL_REVIVIFY = 57090, + SPELL_LIFE_BURST = 57143, + // Utility + SPELL_FLAME_SHIELD = 57108, + SPELL_BLAZING_SPEED = 57092, }; -const uint32 EOE_MAP_ID = 615; +const uint32 EOE_MAP_ID = 616; -// class SartharionTankTrigger : public Trigger -// { -// public: -// SartharionTankTrigger(PlayerbotAI* botAI) : Trigger(botAI, "sartharion tank") {} -// bool IsActive() override; -// }; +class MalygosTrigger : public Trigger +{ +public: + MalygosTrigger(PlayerbotAI* botAI) : Trigger(botAI, "malygos") {} + bool IsActive() override; + uint8 static getPhase(Player* bot, Unit* boss); +}; -// class FlameTsunamiTrigger : public Trigger -// { -// public: -// FlameTsunamiTrigger(PlayerbotAI* botAI) : Trigger(botAI, "flame tsunami") {} -// bool IsActive() override; -// }; - -// class TwilightFissureTrigger : public Trigger -// { -// public: -// TwilightFissureTrigger(PlayerbotAI* botAI) : Trigger(botAI, "twilight fissure") {} -// bool IsActive() override; -// }; - -// class SartharionDpsTrigger : public Trigger -// { -// public: -// SartharionDpsTrigger(PlayerbotAI* botAI) : Trigger(botAI, "sartharion dps") {} -// bool IsActive() override; -// }; - -// class SartharionMeleePositioningTrigger : public Trigger -// { -// public: -// SartharionMeleePositioningTrigger(PlayerbotAI* botAI) : Trigger(botAI, "sartharion melee positioning") {} -// bool IsActive() override; -// }; - -// class TwilightPortalEnterTrigger : public Trigger -// { -// public: -// TwilightPortalEnterTrigger(PlayerbotAI* botAI) : Trigger(botAI, "twilight portal enter") {} -// bool IsActive() override; -// }; - -// class TwilightPortalExitTrigger : public Trigger -// { -// public: -// TwilightPortalExitTrigger(PlayerbotAI* botAI) : Trigger(botAI, "twilight portal exit") {} -// bool IsActive() override; -// }; +class PowerSparkTrigger : public Trigger +{ +public: + PowerSparkTrigger(PlayerbotAI* botAI) : Trigger(botAI, "power spark") {} + bool IsActive() override; +}; #endif