From 9be4b264248754a7722119e4fd55fe824ea9368b Mon Sep 17 00:00:00 2001 From: Jered <72664723+jl178@users.noreply.github.com> Date: Sun, 20 Apr 2025 00:23:14 -0600 Subject: [PATCH] Feat/onyxia raid strategy init (#1182) * feat: init onyxia raid strategy * feat: init onyxia raid strategy * feat: init onyxia raid strategy * feat: init onyxia raid strategy * feat: init onyxia raid strategy * feat: init onyxia raid strategy * feat: init onyxia raid strategy * feat: init onyxia raid strategy * feat: init onyxia raid strategy * feat: init onyxia raid strategy * feat: init onyxia raid strategy * feat: init onyxia raid strategy * feat: init onyxia raid strategy * feat: init onyxia raid strategy * feat: init onyxia raid strategy * feat: init onyxia raid strategy * feat: init onyxia raid strategy * Feat/onyxia raid strategy init fix (#1) * feat: init onyxia raid strategy * feat: ony raid strategy init fix * feat: ony raid strategy init fix * feat: ony raid strategy init fix * feat: ony raid strategy init fix * feat: ony raid strategy init fix * feat: ony raid strategy init fix * feat: ony raid strategy init fix * feat: ony raid strategy init fix * feat: ony raid strategy init fix * feat: ony raid strategy init fix * feat: ony raid strategy init fix * feat: ony raid strategy init fix * feat: ony raid strategy init fix * feat: ony raid strategy init fix * feat: ony raid strategy init fix * feat: ony raid strategy init fix * feat: ony raid strategy init fix * feat: ony raid strategy init fix * feat: ony raid strategy init fix * feat: ony raid strategy init fix * feat: ony raid strategy init fix * feat: ony raid strategy init fix * feat: ony raid strategy init fix * feat: ony raid strategy init fix * feat: ony raid strategy init fix * feat: ony raid strategy init fix * feat: ony raid strategy init fix --- src/PlayerbotAI.cpp | 3 + src/strategy/AiObjectContext.cpp | 4 + src/strategy/raids/RaidStrategyContext.h | 3 + .../raids/onyxia/RaidOnyxiaActionContext.h | 28 ++++ .../raids/onyxia/RaidOnyxiaActions.cpp | 147 ++++++++++++++++++ src/strategy/raids/onyxia/RaidOnyxiaActions.h | 107 +++++++++++++ .../raids/onyxia/RaidOnyxiaStrategy.cpp | 30 ++++ .../raids/onyxia/RaidOnyxiaStrategy.h | 19 +++ .../raids/onyxia/RaidOnyxiaTriggerContext.h | 28 ++++ .../raids/onyxia/RaidOnyxiaTriggers.cpp | 110 +++++++++++++ .../raids/onyxia/RaidOnyxiaTriggers.h | 44 ++++++ 11 files changed, 523 insertions(+) create mode 100644 src/strategy/raids/onyxia/RaidOnyxiaActionContext.h create mode 100644 src/strategy/raids/onyxia/RaidOnyxiaActions.cpp create mode 100644 src/strategy/raids/onyxia/RaidOnyxiaActions.h create mode 100644 src/strategy/raids/onyxia/RaidOnyxiaStrategy.cpp create mode 100644 src/strategy/raids/onyxia/RaidOnyxiaStrategy.h create mode 100644 src/strategy/raids/onyxia/RaidOnyxiaTriggerContext.h create mode 100644 src/strategy/raids/onyxia/RaidOnyxiaTriggers.cpp create mode 100644 src/strategy/raids/onyxia/RaidOnyxiaTriggers.h diff --git a/src/PlayerbotAI.cpp b/src/PlayerbotAI.cpp index 69973e65..43eb0446 100644 --- a/src/PlayerbotAI.cpp +++ b/src/PlayerbotAI.cpp @@ -1498,6 +1498,9 @@ void PlayerbotAI::ApplyInstanceStrategies(uint32 mapId, bool tellMaster) std::string strategyName; switch (mapId) { + case 249: + strategyName = "onyxia"; + break; case 409: strategyName = "mc"; break; diff --git a/src/strategy/AiObjectContext.cpp b/src/strategy/AiObjectContext.cpp index 52e7a247..35c2bed0 100644 --- a/src/strategy/AiObjectContext.cpp +++ b/src/strategy/AiObjectContext.cpp @@ -28,6 +28,8 @@ #include "raids/obsidiansanctum/RaidOsTriggerContext.h" #include "raids/eyeofeternity/RaidEoEActionContext.h" #include "raids/vaultofarchavon/RaidVoATriggerContext.h" +#include "raids/onyxia/RaidOnyxiaActionContext.h" +#include "raids/onyxia/RaidOnyxiaTriggerContext.h" #include "raids/vaultofarchavon/RaidVoAActionContext.h" #include "raids/eyeofeternity/RaidEoETriggerContext.h" #include "raids/moltencore/RaidMcActionContext.h" @@ -52,6 +54,7 @@ AiObjectContext::AiObjectContext(PlayerbotAI* botAI) : PlayerbotAIAware(botAI) actionContexts.Add(new WorldPacketActionContext()); actionContexts.Add(new RaidMcActionContext()); actionContexts.Add(new RaidBwlActionContext()); + actionContexts.Add(new RaidOnyxiaActionContext()); actionContexts.Add(new RaidAq20ActionContext()); actionContexts.Add(new RaidNaxxActionContext()); actionContexts.Add(new RaidOsActionContext()); @@ -78,6 +81,7 @@ AiObjectContext::AiObjectContext(PlayerbotAI* botAI) : PlayerbotAIAware(botAI) triggerContexts.Add(new WorldPacketTriggerContext()); triggerContexts.Add(new RaidMcTriggerContext()); triggerContexts.Add(new RaidBwlTriggerContext()); + triggerContexts.Add(new RaidOnyxiaTriggerContext()); triggerContexts.Add(new RaidAq20TriggerContext()); triggerContexts.Add(new RaidNaxxTriggerContext()); triggerContexts.Add(new RaidOsTriggerContext()); diff --git a/src/strategy/raids/RaidStrategyContext.h b/src/strategy/raids/RaidStrategyContext.h index 1b0cf49e..433abdc1 100644 --- a/src/strategy/raids/RaidStrategyContext.h +++ b/src/strategy/raids/RaidStrategyContext.h @@ -1,6 +1,7 @@ #ifndef _PLAYERBOT_RAIDSTRATEGYCONTEXT_H_ #define _PLAYERBOT_RAIDSTRATEGYCONTEXT_H_ +#include "RaidOnyxiaStrategy.h" #include "RaidUlduarStrategy.h" #include "Strategy.h" #include "RaidBwlStrategy.h" @@ -29,6 +30,7 @@ public: creators["voa"] = &RaidStrategyContext::voa; creators["uld"] = &RaidStrategyContext::uld; creators["icc"] = &RaidStrategyContext::icc; + creators["onyxia"] = &RaidStrategyContext::onyxia; } private: @@ -41,6 +43,7 @@ private: static Strategy* voa(PlayerbotAI* botAI) { return new RaidVoAStrategy(botAI); } static Strategy* uld(PlayerbotAI* botAI) { return new RaidUlduarStrategy(botAI); } static Strategy* icc(PlayerbotAI* botAI) { return new RaidIccStrategy(botAI); } + static Strategy* onyxia(PlayerbotAI* botAI) { return new RaidOnyxiaStrategy(botAI); } }; #endif diff --git a/src/strategy/raids/onyxia/RaidOnyxiaActionContext.h b/src/strategy/raids/onyxia/RaidOnyxiaActionContext.h new file mode 100644 index 00000000..b2923f96 --- /dev/null +++ b/src/strategy/raids/onyxia/RaidOnyxiaActionContext.h @@ -0,0 +1,28 @@ +#ifndef _PLAYERBOT_RAIDONYXIAACTIONS_CONTEXT_H +#define _PLAYERBOT_RAIDONYXIAACTIONS_CONTEXT_H + +#include "Action.h" +#include "NamedObjectContext.h" +#include "RaidOnyxiaActions.h" + +class RaidOnyxiaActionContext : public NamedObjectContext +{ +public: + RaidOnyxiaActionContext() + { + creators["ony move to side"] = &RaidOnyxiaActionContext::move_to_side; + creators["ony spread out"] = &RaidOnyxiaActionContext::spread_out; + creators["ony move to safe zone"] = &RaidOnyxiaActionContext::move_to_safe_zone; + creators["ony kill whelps"] = &RaidOnyxiaActionContext::kill_whelps; + creators["ony avoid eggs move"] = &RaidOnyxiaActionContext::avoid_eggs; + } + +private: + static Action* move_to_side(PlayerbotAI* ai) { return new RaidOnyxiaMoveToSideAction(ai); } + static Action* spread_out(PlayerbotAI* ai) { return new RaidOnyxiaSpreadOutAction(ai); } + static Action* move_to_safe_zone(PlayerbotAI* ai) { return new RaidOnyxiaMoveToSafeZoneAction(ai); } + static Action* kill_whelps(PlayerbotAI* ai) { return new RaidOnyxiaKillWhelpsAction(ai); } + static Action* avoid_eggs(PlayerbotAI* ai) { return new OnyxiaAvoidEggsAction(ai); } +}; + +#endif diff --git a/src/strategy/raids/onyxia/RaidOnyxiaActions.cpp b/src/strategy/raids/onyxia/RaidOnyxiaActions.cpp new file mode 100644 index 00000000..c0cd4beb --- /dev/null +++ b/src/strategy/raids/onyxia/RaidOnyxiaActions.cpp @@ -0,0 +1,147 @@ +// RaidOnyxiaActions.cpp +#include "RaidOnyxiaActions.h" + +#include "GenericSpellActions.h" +#include "LastMovementValue.h" +#include "MovementActions.h" +#include "Playerbots.h" +#include "PositionAction.h" + +bool RaidOnyxiaMoveToSideAction::Execute(Event event) +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "onyxia"); + if (!boss) + return false; + + float angleToBot = boss->GetAngle(bot); + float bossFacing = boss->GetOrientation(); + float diff = fabs(angleToBot - bossFacing); + if (diff > M_PI) + diff = 2 * M_PI - diff; + + float distance = bot->GetDistance(boss); + + // Too close (30 yards) and either in front or behind + if (distance <= 30.0f && (diff < M_PI / 4 || diff > 3 * M_PI / 4)) + { + float offsetAngle = bossFacing + M_PI_2; // 90° to the right + float offsetDist = 15.0f; + + float sideX = boss->GetPositionX() + offsetDist * cos(offsetAngle); + float sideY = boss->GetPositionY() + offsetDist * sin(offsetAngle); + + // bot->Yell("Too close to front or tail — moving to side of Onyxia!", LANG_UNIVERSAL); + return MoveTo(boss->GetMapId(), sideX, sideY, boss->GetPositionZ(), false, false, false, false, + MovementPriority::MOVEMENT_COMBAT); + } + + return false; +} + +bool RaidOnyxiaSpreadOutAction::Execute(Event event) +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "onyxia"); + + if (!boss) + return false; + + Player* target = boss->GetCurrentSpell(CURRENT_GENERIC_SPELL)->m_targets.GetUnitTarget()->ToPlayer(); + if (target != bot) + return false; + + // bot->Yell("Spreading out — I'm the Fireball target!", LANG_UNIVERSAL); + return MoveFromGroup(9.0f); // move 9 yards +} + +bool RaidOnyxiaMoveToSafeZoneAction::Execute(Event event) +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "onyxia"); + if (!boss) + return false; + + Spell* currentSpell = boss->GetCurrentSpell(CURRENT_GENERIC_SPELL); + if (!currentSpell) + return false; + + uint32 spellId = currentSpell->m_spellInfo->Id; + + std::vector safeZones = GetSafeZonesForBreath(spellId); + if (safeZones.empty()) + return false; + + // Find closest safe zone + SafeZone* bestZone = nullptr; + float bestDist = std::numeric_limits::max(); + + for (auto& zone : safeZones) + { + float dist = bot->GetExactDist2d(zone.pos.GetPositionX(), zone.pos.GetPositionY()); + if (dist < bestDist) + { + bestDist = dist; + bestZone = &zone; + } + } + + if (!bestZone) + return false; + + if (bot->IsWithinDist2d(bestZone->pos.GetPositionX(), bestZone->pos.GetPositionY(), bestZone->radius)) + return false; // Already safe + + // bot->Yell("Moving to Safe Zone!", LANG_UNIVERSAL); + return MoveTo(bot->GetMapId(), bestZone->pos.GetPositionX(), bestZone->pos.GetPositionY(), bot->GetPositionZ(), + false, false, false, false, MovementPriority::MOVEMENT_COMBAT); +} + +bool RaidOnyxiaKillWhelpsAction::Execute(Event event) +{ + Unit* currentTarget = AI_VALUE(Unit*, "current target"); + // If already attacking a whelp, don't swap targets + if (currentTarget && currentTarget->GetEntry() == 11262) + { + return false; + } + GuidVector targets = AI_VALUE(GuidVector, "possible targets"); + for (ObjectGuid guid : targets) + { + Creature* unit = botAI->GetCreature(guid); + if (!unit || !unit->IsAlive() || !unit->IsInWorld()) + continue; + + if (unit->GetEntry() == 11262) // Onyxia Whelp + { + // bot->Yell("Attacking Whelps!", LANG_UNIVERSAL); + return Attack(unit); + } + } + return false; +} + +bool OnyxiaAvoidEggsAction::Execute(Event event) +{ + Position botPos = Position(bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ()); + + float x, y; + + // get safe zone slightly away from eggs (Can this be dynamic?) + if (botPos.GetExactDist2d(-36.0f, -164.0f) <= 5.0f) + { + x = -10.0f; + y = -180.0f; + } + else if (botPos.GetExactDist2d(-34.0f, -262.0f) <= 5.0f) + { + x = -16.0f; + y = -250.0f; + } + else + { + return false; // Not in danger zone + } + + // bot->Yell("Too close to eggs — backing off!", LANG_UNIVERSAL); + + return MoveTo(bot->GetMapId(), x, y, bot->GetPositionZ(), false, false, false, false, + MovementPriority::MOVEMENT_COMBAT); +} diff --git a/src/strategy/raids/onyxia/RaidOnyxiaActions.h b/src/strategy/raids/onyxia/RaidOnyxiaActions.h new file mode 100644 index 00000000..3943aaf6 --- /dev/null +++ b/src/strategy/raids/onyxia/RaidOnyxiaActions.h @@ -0,0 +1,107 @@ +// RaidOnyxiaActions.h +#ifndef _PLAYERBOT_RAIDONYXIAACTIONS_H_ +#define _PLAYERBOT_RAIDONYXIAACTIONS_H_ + +#include "Action.h" +#include "AttackAction.h" +#include "GenericSpellActions.h" +#include "MovementActions.h" + +class PlayerbotAI; + +class RaidOnyxiaMoveToSideAction : public MovementAction +{ +public: + RaidOnyxiaMoveToSideAction(PlayerbotAI* botAI, std::string const name = "ony move to side") + : MovementAction(botAI, name) + { + } + bool Execute(Event event) override; +}; + +class RaidOnyxiaSpreadOutAction : public MovementAction +{ +public: + RaidOnyxiaSpreadOutAction(PlayerbotAI* botAI, std::string const name = "ony spread out") + : MovementAction(botAI, name) + { + } + bool Execute(Event event) override; +}; + +struct SafeZone +{ + Position pos; + float radius; +}; + +class RaidOnyxiaMoveToSafeZoneAction : public MovementAction +{ +public: + RaidOnyxiaMoveToSafeZoneAction(PlayerbotAI* botAI, std::string const name = "ony move to safe zone") + : MovementAction(botAI, name) + { + } + bool Execute(Event event) override; + +private: + std::vector GetSafeZonesForBreath(uint32 spellId) + { + // Define your safe zone coordinates based on the map + // Example assumes Onyxia's lair map coordinates + float z = bot->GetPositionZ(); // Stay at current height + + switch (spellId) + { + case 17086: // N to S + case 18351: // S to N + return {SafeZone{Position(-10.0f, -180.0f, z), 5.0f}, + SafeZone{Position(-20.0f, -250.0f, z), 5.0f}}; // Bottom Safe Zone + + case 18576: // E to W + case 18609: // W to E + return { + SafeZone{Position(20.0f, -210.0f, z), 5.0f}, + SafeZone{Position(-75.0f, -210.0f, z), 5.0f}, + }; // Left Safe Zone + + case 18564: // SE to NW + case 18584: // NW to SE + return { + SafeZone{Position(-60.0f, -195.0f, z), 5.0f}, + SafeZone{Position(10.0f, -240.0f, z), 5.0f}, + }; // NW Safe Zone + + case 18596: // SW to NE + case 18617: // NE to SW + return { + SafeZone{Position(7.0f, -185.0f, z), 5.0f}, + SafeZone{Position(-60.0f, -240.0f, z), 5.0f}, + }; // NE Safe Zone + + default: + return {SafeZone{Position(0.0f, 0.0f, z), 5.0f}}; // Fallback center - shouldn't ever happen + } + } +}; + +class RaidOnyxiaKillWhelpsAction : public AttackAction +{ +public: + RaidOnyxiaKillWhelpsAction(PlayerbotAI* botAI, std::string const name = "ony kill whelps") + : AttackAction(botAI, name) + { + } + + bool Execute(Event event) override; +}; + +class OnyxiaAvoidEggsAction : public MovementAction +{ +public: + OnyxiaAvoidEggsAction(PlayerbotAI* botAI) : MovementAction(botAI, "ony avoid eggs move") {} + + bool Execute(Event event) override; +}; + +#endif diff --git a/src/strategy/raids/onyxia/RaidOnyxiaStrategy.cpp b/src/strategy/raids/onyxia/RaidOnyxiaStrategy.cpp new file mode 100644 index 00000000..2e4d50d4 --- /dev/null +++ b/src/strategy/raids/onyxia/RaidOnyxiaStrategy.cpp @@ -0,0 +1,30 @@ +#include "RaidOnyxiaStrategy.h" + +void RaidOnyxiaStrategy::InitTriggers(std::vector& triggers) +{ + // ----------- Phase 1 (100% - 65%) ----------- + + triggers.push_back(new TriggerNode( + "ony near tail", NextAction::array(0, new NextAction("ony move to side", ACTION_RAID + 2), nullptr))); + + triggers.push_back(new TriggerNode( + "ony avoid eggs", NextAction::array(0, new NextAction("ony avoid eggs move", ACTION_EMERGENCY + 5), nullptr))); + + // ----------- Phase 2 (65% - 40%) ----------- + + triggers.push_back( + new TriggerNode("ony deep breath warning", + NextAction::array(0, new NextAction("ony move to safe zone", ACTION_EMERGENCY + 5), nullptr))); + + triggers.push_back( + new TriggerNode("ony fireball splash incoming", + NextAction::array(0, new NextAction("ony spread out", ACTION_EMERGENCY + 2), nullptr))); + + triggers.push_back(new TriggerNode( + "ony whelps spawn", NextAction::array(0, new NextAction("ony kill whelps", ACTION_RAID + 1), nullptr))); +} + +void RaidOnyxiaStrategy::InitMultipliers(std::vector& multipliers) +{ + // Empty for now +} diff --git a/src/strategy/raids/onyxia/RaidOnyxiaStrategy.h b/src/strategy/raids/onyxia/RaidOnyxiaStrategy.h new file mode 100644 index 00000000..189b2491 --- /dev/null +++ b/src/strategy/raids/onyxia/RaidOnyxiaStrategy.h @@ -0,0 +1,19 @@ + +// RaidOnyxiaStrategy.h +#ifndef _PLAYERBOT_RAIDONYXIASTRATEGY_H_ +#define _PLAYERBOT_RAIDONYXIASTRATEGY_H_ + +#include "Strategy.h" + +class RaidOnyxiaStrategy : public Strategy +{ +public: + RaidOnyxiaStrategy(PlayerbotAI* ai) : Strategy(ai) {} + + std::string const getName() override { return "onyxia"; } + + void InitTriggers(std::vector& triggers) override; + void InitMultipliers(std::vector& multipliers) override; +}; + +#endif diff --git a/src/strategy/raids/onyxia/RaidOnyxiaTriggerContext.h b/src/strategy/raids/onyxia/RaidOnyxiaTriggerContext.h new file mode 100644 index 00000000..dba18f56 --- /dev/null +++ b/src/strategy/raids/onyxia/RaidOnyxiaTriggerContext.h @@ -0,0 +1,28 @@ +#ifndef _PLAYERBOT_RAIDONYXIATRIGGERCONTEXT_H +#define _PLAYERBOT_RAIDONYXIATRIGGERCONTEXT_H + +#include "AiObjectContext.h" +#include "NamedObjectContext.h" +#include "RaidOnyxiaTriggers.h" + +class RaidOnyxiaTriggerContext : public NamedObjectContext +{ +public: + RaidOnyxiaTriggerContext() + { + creators["ony near tail"] = &RaidOnyxiaTriggerContext::near_tail; + creators["ony deep breath warning"] = &RaidOnyxiaTriggerContext::deep_breath; + creators["ony fireball splash incoming"] = &RaidOnyxiaTriggerContext::fireball_splash; + creators["ony whelps spawn"] = &RaidOnyxiaTriggerContext::whelps_spawn; + creators["ony avoid eggs"] = &RaidOnyxiaTriggerContext::avoid_eggs; + } + +private: + static Trigger* near_tail(PlayerbotAI* ai) { return new OnyxiaNearTailTrigger(ai); } + static Trigger* deep_breath(PlayerbotAI* ai) { return new OnyxiaDeepBreathTrigger(ai); } + static Trigger* fireball_splash(PlayerbotAI* ai) { return new RaidOnyxiaFireballSplashTrigger(ai); } + static Trigger* whelps_spawn(PlayerbotAI* ai) { return new RaidOnyxiaWhelpsSpawnTrigger(ai); } + static Trigger* avoid_eggs(PlayerbotAI* ai) { return new OnyxiaAvoidEggsTrigger(ai); } +}; + +#endif diff --git a/src/strategy/raids/onyxia/RaidOnyxiaTriggers.cpp b/src/strategy/raids/onyxia/RaidOnyxiaTriggers.cpp new file mode 100644 index 00000000..f74f34e3 --- /dev/null +++ b/src/strategy/raids/onyxia/RaidOnyxiaTriggers.cpp @@ -0,0 +1,110 @@ +#include "RaidOnyxiaTriggers.h" + +#include "GenericTriggers.h" +#include "ObjectAccessor.h" +#include "PlayerbotAI.h" +#include "Playerbots.h" +#include "strategy/values/NearestNpcsValue.h" + +OnyxiaDeepBreathTrigger::OnyxiaDeepBreathTrigger(PlayerbotAI* botAI) : Trigger(botAI, "ony deep breath warning") {} + +bool OnyxiaDeepBreathTrigger::IsActive() +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "onyxia"); + if (!boss || !boss->HasUnitState(UNIT_STATE_CASTING)) + return false; + + // Check if Onyxia is casting + Spell* currentSpell = boss->GetCurrentSpell(CURRENT_GENERIC_SPELL); + + if (!currentSpell) + return false; + + uint32 spellId = currentSpell->m_spellInfo->Id; + + if (spellId == 17086 || // North to South + spellId == 18351 || // South to North + spellId == 18576 || // East to West + spellId == 18609 || // West to East + spellId == 18564 || // Southeast to Northwest + spellId == 18584 || // Northwest to Southeast + spellId == 18596 || // Southwest to Northeast + spellId == 18617 // Northeast to Southwest + ) + { + return true; + } + + return false; +} + +OnyxiaNearTailTrigger::OnyxiaNearTailTrigger(PlayerbotAI* botAI) : Trigger(botAI, "ony near tail") {} + +bool OnyxiaNearTailTrigger::IsActive() +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "onyxia"); + if (!boss || botAI->IsTank(bot)) + return false; + + // Skip if Onyxia is in air or transitioning + if (!boss->IsInCombat() || boss->IsFlying() || !boss->GetVictim()) + return false; + + return true; +} +RaidOnyxiaFireballSplashTrigger::RaidOnyxiaFireballSplashTrigger(PlayerbotAI* botAI) + : Trigger(botAI, "ony fireball splash incoming") +{ +} + +bool RaidOnyxiaFireballSplashTrigger::IsActive() +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "onyxia"); + if (!boss || !boss->HasUnitState(UNIT_STATE_CASTING)) + return false; + + // Check if Onyxia is casting Fireball + Spell* currentSpell = boss->GetCurrentSpell(CURRENT_GENERIC_SPELL); + if (!currentSpell || currentSpell->m_spellInfo->Id != 18392) // 18392 is the classic Fireball ID + return false; + + GuidVector nearbyUnits = AI_VALUE(GuidVector, "nearest friendly players"); + + for (ObjectGuid guid : nearbyUnits) + { + Unit* unit = botAI->GetUnit(guid); + if (!unit || unit == bot || !unit->IsAlive()) + continue; + + if (bot->GetDistance(unit) < 8.0f) + return true; + } + + return false; +} + +RaidOnyxiaWhelpsSpawnTrigger::RaidOnyxiaWhelpsSpawnTrigger(PlayerbotAI* botAI) : Trigger(botAI, "ony whelps spawn") {} + +bool RaidOnyxiaWhelpsSpawnTrigger::IsActive() +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "onyxia"); + if (!boss) + return false; + + return !botAI->IsHeal(bot) && boss->IsFlying(); // DPS + Tanks only +} + +OnyxiaAvoidEggsTrigger::OnyxiaAvoidEggsTrigger(PlayerbotAI* botAI) : Trigger(botAI, "ony avoid eggs") {} + +bool OnyxiaAvoidEggsTrigger::IsActive() +{ + Position botPos = Position(bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ()); + + if (botPos.GetExactDist2d(-35.0f, -165.0f) <= 5.0f) + return true; + + if (botPos.GetExactDist2d(-35.0f, -260.0f) <= 5.0f) + return true; + + return false; +} diff --git a/src/strategy/raids/onyxia/RaidOnyxiaTriggers.h b/src/strategy/raids/onyxia/RaidOnyxiaTriggers.h new file mode 100644 index 00000000..d8205357 --- /dev/null +++ b/src/strategy/raids/onyxia/RaidOnyxiaTriggers.h @@ -0,0 +1,44 @@ +// OnyxiaTriggers.h +#ifndef _PLAYERBOT_ONYXIATRIGGERS_H_ +#define _PLAYERBOT_ONYXIATRIGGERS_H_ + +#include "PlayerbotAI.h" +#include "Trigger.h" + +// Mechanics +class OnyxiaDeepBreathTrigger : public Trigger +{ +public: + OnyxiaDeepBreathTrigger(PlayerbotAI* botAI); + bool IsActive() override; +}; + +class OnyxiaNearTailTrigger : public Trigger +{ +public: + OnyxiaNearTailTrigger(PlayerbotAI* botAI); + bool IsActive() override; +}; + +class RaidOnyxiaFireballSplashTrigger : public Trigger +{ +public: + RaidOnyxiaFireballSplashTrigger(PlayerbotAI* botAI); + bool IsActive() override; +}; + +class RaidOnyxiaWhelpsSpawnTrigger : public Trigger +{ +public: + RaidOnyxiaWhelpsSpawnTrigger(PlayerbotAI* botAI); + bool IsActive() override; +}; + +class OnyxiaAvoidEggsTrigger : public Trigger +{ +public: + OnyxiaAvoidEggsTrigger(PlayerbotAI* botAI); + bool IsActive() override; +}; + +#endif