From 3881940f338a11a380b24b25e224ce99916a895b Mon Sep 17 00:00:00 2001 From: Noscopezz Date: Sun, 11 May 2025 00:24:09 +0200 Subject: [PATCH] PoS Strategies (#1283) PoS Strategies --- src/strategy/AiObjectContext.cpp | 4 +- .../dungeons/DungeonStrategyContext.h | 4 +- .../wotlk/WotlkDungeonActionContext.h | 2 +- .../wotlk/WotlkDungeonTriggerContext.h | 3 +- .../forgeofsouls/ForgeOfSoulsTriggerContext.h | 12 +- .../pitofsaron/PitOfSaronActionContext.h | 21 ++ .../wotlk/pitofsaron/PitOfSaronActions.cpp | 315 ++++++++++++++++++ .../wotlk/pitofsaron/PitOfSaronActions.h | 32 ++ .../pitofsaron/PitOfSaronMultipliers.cpp | 39 +++ .../wotlk/pitofsaron/PitOfSaronMultipliers.h | 24 ++ .../wotlk/pitofsaron/PitOfSaronStrategy.cpp | 17 + .../wotlk/pitofsaron/PitOfSaronStrategy.h | 16 + .../pitofsaron/PitOfSaronTriggerContext.h | 22 ++ .../wotlk/pitofsaron/PitOfSaronTriggers.cpp | 22 ++ .../wotlk/pitofsaron/PitOfSaronTriggers.h | 48 +++ src/strategy/dungeons/wotlk/pitofsaron/TODO | 0 16 files changed, 571 insertions(+), 10 deletions(-) create mode 100644 src/strategy/dungeons/wotlk/pitofsaron/PitOfSaronActionContext.h create mode 100644 src/strategy/dungeons/wotlk/pitofsaron/PitOfSaronActions.cpp create mode 100644 src/strategy/dungeons/wotlk/pitofsaron/PitOfSaronActions.h create mode 100644 src/strategy/dungeons/wotlk/pitofsaron/PitOfSaronMultipliers.cpp create mode 100644 src/strategy/dungeons/wotlk/pitofsaron/PitOfSaronMultipliers.h create mode 100644 src/strategy/dungeons/wotlk/pitofsaron/PitOfSaronStrategy.cpp create mode 100644 src/strategy/dungeons/wotlk/pitofsaron/PitOfSaronStrategy.h create mode 100644 src/strategy/dungeons/wotlk/pitofsaron/PitOfSaronTriggerContext.h create mode 100644 src/strategy/dungeons/wotlk/pitofsaron/PitOfSaronTriggers.cpp create mode 100644 src/strategy/dungeons/wotlk/pitofsaron/PitOfSaronTriggers.h delete mode 100644 src/strategy/dungeons/wotlk/pitofsaron/TODO diff --git a/src/strategy/AiObjectContext.cpp b/src/strategy/AiObjectContext.cpp index 9ef20498..c308a7cd 100644 --- a/src/strategy/AiObjectContext.cpp +++ b/src/strategy/AiObjectContext.cpp @@ -75,6 +75,7 @@ AiObjectContext::AiObjectContext(PlayerbotAI* botAI) : PlayerbotAIAware(botAI) actionContexts.Add(new WotlkDungeonUPActionContext()); actionContexts.Add(new WotlkDungeonCoSActionContext()); actionContexts.Add(new WotlkDungeonFoSActionContext()); + actionContexts.Add(new WotlkDungeonPoSActionContext()); actionContexts.Add(new WotlkDungeonToCActionContext()); triggerContexts.Add(new TriggerContext()); @@ -102,7 +103,8 @@ AiObjectContext::AiObjectContext(PlayerbotAI* botAI) : PlayerbotAIAware(botAI) triggerContexts.Add(new WotlkDungeonOccTriggerContext()); triggerContexts.Add(new WotlkDungeonUPTriggerContext()); triggerContexts.Add(new WotlkDungeonCoSTriggerContext()); - triggerContexts.Add(new WotlkDungeonFosTriggerContext()); + triggerContexts.Add(new WotlkDungeonFoSTriggerContext()); + triggerContexts.Add(new WotlkDungeonPoSTriggerContext()); triggerContexts.Add(new WotlkDungeonToCTriggerContext()); valueContexts.Add(new ValueContext()); diff --git a/src/strategy/dungeons/DungeonStrategyContext.h b/src/strategy/dungeons/DungeonStrategyContext.h index 0a6bae84..33efaffe 100644 --- a/src/strategy/dungeons/DungeonStrategyContext.h +++ b/src/strategy/dungeons/DungeonStrategyContext.h @@ -15,6 +15,7 @@ #include "wotlk/utgardepinnacle/UtgardePinnacleStrategy.h" #include "wotlk/cullingofstratholme/CullingOfStratholmeStrategy.h" #include "wotlk/forgeofsouls/ForgeOfSoulsStrategy.h" +#include "wotlk/pitofsaron/PitOfSaronStrategy.h" #include "wotlk/trialofthechampion/TrialOfTheChampionStrategy.h" /* @@ -79,10 +80,11 @@ class DungeonStrategyContext : public NamedObjectContext static Strategy* wotlk_up(PlayerbotAI* botAI) { return new WotlkDungeonUPStrategy(botAI); } static Strategy* wotlk_cos(PlayerbotAI* botAI) { return new WotlkDungeonCoSStrategy(botAI); } static Strategy* wotlk_fos(PlayerbotAI* botAI) { return new WotlkDungeonFoSStrategy(botAI); } + static Strategy* wotlk_pos(PlayerbotAI* botAI) { return new WotlkDungeonPoSStrategy(botAI); } static Strategy* wotlk_toc(PlayerbotAI* botAI) { return new WotlkDungeonToCStrategy(botAI); } // NYI from here down static Strategy* wotlk_hor(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); } - static Strategy* wotlk_pos(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); } + }; diff --git a/src/strategy/dungeons/wotlk/WotlkDungeonActionContext.h b/src/strategy/dungeons/wotlk/WotlkDungeonActionContext.h index 54cb995c..a53f9515 100644 --- a/src/strategy/dungeons/wotlk/WotlkDungeonActionContext.h +++ b/src/strategy/dungeons/wotlk/WotlkDungeonActionContext.h @@ -14,8 +14,8 @@ #include "utgardepinnacle/UtgardePinnacleActionContext.h" #include "cullingofstratholme/CullingOfStratholmeActionContext.h" #include "forgeofsouls/ForgeOfSoulsActionContext.h" +#include "pitofsaron/PitOfSaronActionContext.h" #include "trialofthechampion/TrialOfTheChampionActionContext.h" // #include "hallsofreflection/HallsOfReflectionActionContext.h" -// #include "pitofsaron/PitOfSaronActionContext.h" #endif diff --git a/src/strategy/dungeons/wotlk/WotlkDungeonTriggerContext.h b/src/strategy/dungeons/wotlk/WotlkDungeonTriggerContext.h index 913dd941..057d25e0 100644 --- a/src/strategy/dungeons/wotlk/WotlkDungeonTriggerContext.h +++ b/src/strategy/dungeons/wotlk/WotlkDungeonTriggerContext.h @@ -14,8 +14,9 @@ #include "utgardepinnacle/UtgardePinnacleTriggerContext.h" #include "cullingofstratholme/CullingOfStratholmeTriggerContext.h" #include "forgeofsouls/ForgeOfSoulsTriggerContext.h" +#include "pitofsaron/PitOfSaronTriggerContext.h" #include "trialofthechampion/TrialOfTheChampionTriggerContext.h" // #include "hallsofreflection/HallsOfReflectionTriggerContext.h" -// #include "pitofsaron/PitOfSaronTriggerContext.h" + #endif diff --git a/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsTriggerContext.h b/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsTriggerContext.h index 6a85ef67..12912412 100644 --- a/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsTriggerContext.h +++ b/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsTriggerContext.h @@ -5,15 +5,15 @@ #include "AiObjectContext.h" #include "ForgeOfSoulsTriggers.h" -class WotlkDungeonFosTriggerContext : public NamedObjectContext +class WotlkDungeonFoSTriggerContext : public NamedObjectContext { public: - WotlkDungeonFosTriggerContext() + WotlkDungeonFoSTriggerContext() { - creators["bronjahm position"] = &WotlkDungeonFosTriggerContext::bronjahm_position; - creators["move from bronjahm"] = &WotlkDungeonFosTriggerContext::move_from_bronjahm; - creators["switch to soul fragment"] = &WotlkDungeonFosTriggerContext::switch_to_soul_fragment; - creators["devourer of souls"] = &WotlkDungeonFosTriggerContext::devourer_of_souls; + creators["bronjahm position"] = &WotlkDungeonFoSTriggerContext::bronjahm_position; + creators["move from bronjahm"] = &WotlkDungeonFoSTriggerContext::move_from_bronjahm; + creators["switch to soul fragment"] = &WotlkDungeonFoSTriggerContext::switch_to_soul_fragment; + creators["devourer of souls"] = &WotlkDungeonFoSTriggerContext::devourer_of_souls; } private: diff --git a/src/strategy/dungeons/wotlk/pitofsaron/PitOfSaronActionContext.h b/src/strategy/dungeons/wotlk/pitofsaron/PitOfSaronActionContext.h new file mode 100644 index 00000000..816202a8 --- /dev/null +++ b/src/strategy/dungeons/wotlk/pitofsaron/PitOfSaronActionContext.h @@ -0,0 +1,21 @@ +#ifndef _PLAYERBOT_WOTLKDUNGEONPOSACTIONCONTEXT_H +#define _PLAYERBOT_WOTLKDUNGEONPOSACTIONCONTEXT_H + +#include "Action.h" +#include "NamedObjectContext.h" +#include "PitOfSaronActions.h" + +class WotlkDungeonPoSActionContext : public NamedObjectContext +{ + public: + WotlkDungeonPoSActionContext() + { + creators["ick and krick"] = &WotlkDungeonPoSActionContext::ick_and_krick; + creators["tyrannus"] = &WotlkDungeonPoSActionContext::tyrannus; + } + private: + static Action* ick_and_krick(PlayerbotAI* ai) { return new IckAndKrickAction(ai); } + static Action* tyrannus(PlayerbotAI* ai) { return new TyrannusAction(ai); } +}; + +#endif diff --git a/src/strategy/dungeons/wotlk/pitofsaron/PitOfSaronActions.cpp b/src/strategy/dungeons/wotlk/pitofsaron/PitOfSaronActions.cpp new file mode 100644 index 00000000..046c766d --- /dev/null +++ b/src/strategy/dungeons/wotlk/pitofsaron/PitOfSaronActions.cpp @@ -0,0 +1,315 @@ +#include "Playerbots.h" +#include "PitOfSaronActions.h" +#include "PitOfSaronStrategy.h" +#include "SharedDefines.h" + +bool IckAndKrickAction::Execute(Event event) +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "Ick"); + if (!boss) + return false; + + std::vector orbs; + bool orb = false; + + // First gather all orbs + GuidVector npcs1 = AI_VALUE(GuidVector, "nearest hostile npcs"); + for (auto& npc : npcs1) + { + Unit* unit = botAI->GetUnit(npc); + if (unit && unit->IsAlive() && unit->HasAura(SPELL_EXPLODING_ORB_VISUAL)) + { + orb = true; + break; + } + } + + bool pursuit = bot->HasAura(SPELL_PURSUIT) || (!botAI->IsTank(bot) && boss->HasUnitState(UNIT_STATE_CASTING) && boss->FindCurrentSpellBySpellId(SPELL_PURSUIT)); + bool poisonNova = boss->HasUnitState(UNIT_STATE_CASTING) && (boss->FindCurrentSpellBySpellId(SPELL_POISON_NOVA_POS) || boss->FindCurrentSpellBySpellId(SPELL_POISON_NOVA_POS_HC)); + bool explosiveBarrage = orb || boss->HasUnitState(UNIT_STATE_CASTING) && (boss->FindCurrentSpellBySpellId(SPELL_EXPLOSIVE_BARRAGE_ICK) || boss->FindCurrentSpellBySpellId(SPELL_EXPLOSIVE_BARRAGE_KRICK)); + bool isTank = botAI->IsTank(bot); + + if (pursuit && Pursuit(pursuit, boss)) + return true; + + if (poisonNova && PoisonNova(poisonNova, boss)) + return true; + + if (explosiveBarrage && ExplosiveBarrage(explosiveBarrage, boss)) + return true; + + if (isTank && !pursuit && !poisonNova && !explosiveBarrage) + { + if (TankPosition(boss)) + return true; + } + + return false; +} + +bool IckAndKrickAction::TankPosition(Unit* boss) +{ + if (botAI->HasAggro(boss)) + { + float distance = bot->GetExactDist2d(ICKANDKRICK_TANK_POSITION.GetPositionX(), ICKANDKRICK_TANK_POSITION.GetPositionY()); + if (distance > 7.0f) + { + // Calculate direction vector + float dirX = ICKANDKRICK_TANK_POSITION.GetPositionX() - bot->GetPositionX(); + float dirY = ICKANDKRICK_TANK_POSITION.GetPositionY() - bot->GetPositionY(); + float length = sqrt(dirX * dirX + dirY * dirY); + dirX /= length; + dirY /= length; + + // Move in increments of 3.0f + float moveX = bot->GetPositionX() + dirX * 3.0f; + float moveY = bot->GetPositionY() + dirY * 3.0f; + + return MoveTo(bot->GetMapId(), moveX, moveY, bot->GetPositionZ(), false, false, false, false, MovementPriority::MOVEMENT_COMBAT); + } + } + + return false; +} + +bool IckAndKrickAction::Pursuit(bool pursuit, Unit* boss) +{ + // Only execute this action when pursuit is active and for non-tank players + if (!pursuit || botAI->IsTank(bot)) + return false; + + // Get the tank position as a reference point + Position tankPosition = ICKANDKRICK_TANK_POSITION; + + // Calculate distance from boss + float distanceToBoss = bot->GetExactDist2d(boss); + + // If boss is close, move in a circular pattern + if (distanceToBoss < 20.0f) + { + // Current bot position + float x = bot->GetPositionX(); + float y = bot->GetPositionY(); + + // Calculate vector from tank to bot + float dx = x - tankPosition.GetPositionX(); + float dy = y - tankPosition.GetPositionY(); + + // Normalize the vector + float distance = std::sqrt(dx * dx + dy * dy); + if (distance > 0) + { + dx /= distance; + dy /= distance; + } + + // Rotate the vector by 90 degrees to create circular movement + // (x,y) rotated 90 degrees becomes (-y,x) + float rotatedX = -dy; + float rotatedY = dx; + + // Create a target position along the circular path + // We want to maintain a specific radius from the tank + float targetRadius = 20.0f; // 20 feet radius circle around tank + + Position targetPos; + targetPos.Relocate(tankPosition.GetPositionX() + rotatedX * targetRadius, + tankPosition.GetPositionY() + rotatedY * targetRadius, bot->GetPositionZ()); + + // Move to the calculated circular position + botAI->Reset(); + return MoveTo(bot->GetMapId(), targetPos.GetPositionX(), targetPos.GetPositionY(), bot->GetPositionZ(), + false, false, false, false, MovementPriority::MOVEMENT_COMBAT); + + } + + return false; +} + +bool IckAndKrickAction::PoisonNova(bool poisonNova, Unit* boss) +{ + if (bot->GetExactDist2d(boss) < 20.0f && poisonNova) + return MoveAway(boss, 11.0f); + else if (poisonNova) + return true; + + return false; +} + + +bool IckAndKrickAction::ExplosiveBarrage(bool explosiveBarrage, Unit* boss) +{ + std::vector orbs; + Unit* closestOrb = nullptr; + float closestDistance = std::numeric_limits::max(); + + // First gather all orbs + GuidVector npcs1 = AI_VALUE(GuidVector, "nearest hostile npcs"); + for (auto& npc : npcs1) + { + Unit* unit = botAI->GetUnit(npc); + if (unit && unit->IsAlive() && unit->HasAura(SPELL_EXPLODING_ORB_VISUAL)) + { + orbs.push_back(unit); + float dist = bot->GetDistance(unit); + if (dist < closestDistance) + { + closestDistance = dist; + closestOrb = unit; + } + } + } + + if (!orbs.empty() && closestOrb && bot->GetExactDist2d(closestOrb) < 7.0f) + { + // Get player positions to avoid moving toward them + std::vector playerPositions; + Group* group = bot->GetGroup(); + if (group) + { + for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) + { + if (Player* member = ref->GetSource()) + { + if (member != bot && member->IsAlive() && bot->GetMap() == member->GetMap() && + bot->GetExactDist2d(member) < 20.0f) + { + playerPositions.push_back(member->GetPosition()); + } + } + } + } + + // Calculate several potential escape positions + const int NUM_ANGLES = 16; // Check 16 different directions + const float SAFE_DISTANCE = 7.0f; + const float MAX_BOSS_DISTANCE = 30.0f; // Maximum allowed distance from boss + const float ANGLE_INCREMENT = 2 * M_PI / NUM_ANGLES; + + Position bestPos; + bool foundValidPos = false; + float bestScore = -1.0f; + + for (int i = 0; i < NUM_ANGLES; i++) + { + float angle = i * ANGLE_INCREMENT; + Position potentialPos; + potentialPos.m_positionX = bot->GetPositionX() + SAFE_DISTANCE * cos(angle); + potentialPos.m_positionY = bot->GetPositionY() + SAFE_DISTANCE * sin(angle); + potentialPos.m_positionZ = bot->GetPositionZ(); + + // Check if position is valid (not in a wall) + if (!bot->IsWithinLOS(potentialPos.m_positionX, potentialPos.m_positionY, potentialPos.m_positionZ)) + continue; + + // Check if position is within maximum allowed distance from boss + if (boss && sqrt(pow(potentialPos.m_positionX - boss->GetPositionX(), 2) + + pow(potentialPos.m_positionY - boss->GetPositionY(), 2)) > MAX_BOSS_DISTANCE) + continue; + + // Score this position based on: + // 1. Distance from all orbs (farther is better) + // 2. Distance from other players (farther is better) + // 3. Distance from boss (closer is better, but still safe) + float score = 0.0f; + + // Check distance from all orbs + float minOrbDist = std::numeric_limits::max(); + for (Unit* orb : orbs) + { + float orbDist = sqrt(pow(potentialPos.m_positionX - orb->GetPositionX(), 2) + + pow(potentialPos.m_positionY - orb->GetPositionY(), 2)); + minOrbDist = std::min(minOrbDist, orbDist); + } + score += minOrbDist * 2.0f; // Weight orb distance more heavily + + // Check distance from other players + for (const Position& playerPos : playerPositions) + { + float playerDist = sqrt(pow(potentialPos.m_positionX - playerPos.m_positionX, 2) + + pow(potentialPos.m_positionY - playerPos.m_positionY, 2)); + score += std::min(playerDist, 10.0f); // Cap player distance contribution + } + + // Factor in proximity to boss (closer is better, as long as we're safe from orbs) + if (boss) + { + float bossDist = sqrt(pow(potentialPos.m_positionX - boss->GetPositionX(), 2) + + pow(potentialPos.m_positionY - boss->GetPositionY(), 2)); + // Add points for being closer to boss (inverse relationship) + // but only if we're safely away from orbs + if (minOrbDist > SAFE_DISTANCE) + { + score += (MAX_BOSS_DISTANCE - bossDist) * 0.5f; + } + } + + // If this is the best position so far, remember it + if (score > bestScore) + { + bestScore = score; + bestPos = potentialPos; + foundValidPos = true; + } + } + + // If we found a valid position, move there + if (foundValidPos) + { + botAI->Reset(); + // Use MoveTo instead of FleePosition since we already calculated the exact position + return MoveTo(bot->GetMapId(), bestPos.m_positionX, bestPos.m_positionY, bot->GetPositionZ(), false, false, + false, true, MovementPriority::MOVEMENT_COMBAT); + } + else + { + return FleePosition(closestOrb->GetPosition(), 7.0f, 250U); + } + } + + return false; +} + +bool TyrannusAction::Execute(Event event) +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "scourgelord tyrannus"); + if (!boss) + return false; + + bool rangedSpread = false; + + if (botAI->IsRanged(bot) && boss->HealthBelowPct(99)) + rangedSpread = true; + + if (rangedSpread && RangedSpread(rangedSpread)) + return true; + + return false; +} + +bool TyrannusAction::RangedSpread(bool rangedSpread) +{ + float radius = 10.0f; + float moveIncrement = 3.0f; + + GuidVector members = AI_VALUE(GuidVector, "group members"); + if (botAI->IsRanged(bot) && rangedSpread) + { + // Ranged: spread from other members + for (auto& member : members) + { + Unit* unit = botAI->GetUnit(member); + if (!unit || !unit->IsAlive() || unit == bot) + continue; + + float dist = bot->GetExactDist2d(unit); + if (dist < radius) + { + float moveDistance = std::min(moveIncrement, radius - dist + 1.0f); + return FleePosition(unit->GetPosition(), moveDistance, 250U); + } + } + } + + return false; +} diff --git a/src/strategy/dungeons/wotlk/pitofsaron/PitOfSaronActions.h b/src/strategy/dungeons/wotlk/pitofsaron/PitOfSaronActions.h new file mode 100644 index 00000000..a467766f --- /dev/null +++ b/src/strategy/dungeons/wotlk/pitofsaron/PitOfSaronActions.h @@ -0,0 +1,32 @@ +#ifndef _PLAYERBOT_WOTLKDUNGEONPOSACTIONS_H +#define _PLAYERBOT_WOTLKDUNGEONPOSACTIONS_H + +#include "Action.h" +#include "AttackAction.h" +#include "PlayerbotAI.h" +#include "Playerbots.h" +#include "PitOfSaronTriggers.h" + +const Position ICKANDKRICK_TANK_POSITION = Position(816.8508f, 102.331505f, 509.1586f); + +class IckAndKrickAction : public AttackAction +{ +public: + IckAndKrickAction(PlayerbotAI* ai) : AttackAction(ai, "ick and krick") {} + bool Execute(Event event) override; + + bool TankPosition(Unit* boss); + bool Pursuit(bool pursuit, Unit* boss); + bool PoisonNova(bool poisonNova, Unit* boss); + bool ExplosiveBarrage(bool explosiveBarrage, Unit* boss); +}; + +class TyrannusAction : public AttackAction +{ +public: + TyrannusAction(PlayerbotAI* ai) : AttackAction(ai, "tyrannus") {} + bool Execute(Event event) override; + + bool RangedSpread(bool rangedSpread); +}; +#endif diff --git a/src/strategy/dungeons/wotlk/pitofsaron/PitOfSaronMultipliers.cpp b/src/strategy/dungeons/wotlk/pitofsaron/PitOfSaronMultipliers.cpp new file mode 100644 index 00000000..cbe18778 --- /dev/null +++ b/src/strategy/dungeons/wotlk/pitofsaron/PitOfSaronMultipliers.cpp @@ -0,0 +1,39 @@ +#include "PitOfSaronMultipliers.h" +#include "PitOfSaronActions.h" +#include "GenericSpellActions.h" +#include "ChooseTargetActions.h" +#include "MovementActions.h" +#include "PitOfSaronTriggers.h" + + + +float IckAndKrickMultiplier::GetValue(Action* action) +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "ick"); + if (!boss) + return 1.0f; + + // Allow the IckAndKrickAction to run + if (dynamic_cast(action)) + return 1.0f; + + if (boss->HasUnitState(UNIT_STATE_CASTING) && (boss->FindCurrentSpellBySpellId(SPELL_POISON_NOVA_POS) || boss->FindCurrentSpellBySpellId(SPELL_POISON_NOVA_POS_HC)) && bot->GetExactDist2d(boss) < 20.0f) + return 0.0f; // Cancel all other actions when we need to handle Poison Nova + + if (bot->GetExactDist2d(boss) < 15.0f && bot->HasAura(SPELL_PURSUIT) && !botAI->IsTank(bot)) + return 0.0f; // Cancel all other actions when we need to handle Pursuit + + if (!botAI->IsHeal(bot) && boss->HasUnitState(UNIT_STATE_CASTING) && (boss->FindCurrentSpellBySpellId(SPELL_EXPLOSIVE_BARRAGE_ICK) || boss->FindCurrentSpellBySpellId(SPELL_EXPLOSIVE_BARRAGE_KRICK))) + return 0.0f; // Cancel all other actions when we need to handle Explosive Barrage + + return 1.0f; +} + +float GarfrostMultiplier::GetValue(Action* action) +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "garfrost"); + if (!boss) + return 1.0f; + + return 1.0f; +} diff --git a/src/strategy/dungeons/wotlk/pitofsaron/PitOfSaronMultipliers.h b/src/strategy/dungeons/wotlk/pitofsaron/PitOfSaronMultipliers.h new file mode 100644 index 00000000..fabf6319 --- /dev/null +++ b/src/strategy/dungeons/wotlk/pitofsaron/PitOfSaronMultipliers.h @@ -0,0 +1,24 @@ +#ifndef _PLAYERBOT_WOTLKDUNGEONPOSMULTIPLIERS_H +#define _PLAYERBOT_WOTLKDUNGEONPOSMULTIPLIERS_H + +#include "Multiplier.h" + +class IckAndKrickMultiplier : public Multiplier +{ + public: + IckAndKrickMultiplier(PlayerbotAI* ai) : Multiplier(ai, "ick and krick") {} + + public: + virtual float GetValue(Action* action); +}; + +class GarfrostMultiplier : public Multiplier +{ +public: + GarfrostMultiplier(PlayerbotAI* ai) : Multiplier(ai, "garfrost") { } + + float GetValue(Action* action) override; +}; + + +#endif diff --git a/src/strategy/dungeons/wotlk/pitofsaron/PitOfSaronStrategy.cpp b/src/strategy/dungeons/wotlk/pitofsaron/PitOfSaronStrategy.cpp new file mode 100644 index 00000000..2539457b --- /dev/null +++ b/src/strategy/dungeons/wotlk/pitofsaron/PitOfSaronStrategy.cpp @@ -0,0 +1,17 @@ +#include "PitOfSaronStrategy.h" +#include "PitOfSaronMultipliers.h" + +void WotlkDungeonPoSStrategy::InitTriggers(std::vector& triggers) +{ + triggers.push_back(new TriggerNode("ick and krick", + NextAction::array(0, new NextAction("ick and krick", ACTION_RAID + 5), nullptr))); + + triggers.push_back(new TriggerNode("tyrannus", + NextAction::array(0, new NextAction("tyrannus", ACTION_RAID + 5), nullptr))); +} + +void WotlkDungeonPoSStrategy::InitMultipliers(std::vector& multipliers) +{ + multipliers.push_back(new IckAndKrickMultiplier(botAI)); + //multipliers.push_back(new AttackFragmentMultiplier(botAI)); +} diff --git a/src/strategy/dungeons/wotlk/pitofsaron/PitOfSaronStrategy.h b/src/strategy/dungeons/wotlk/pitofsaron/PitOfSaronStrategy.h new file mode 100644 index 00000000..4098378d --- /dev/null +++ b/src/strategy/dungeons/wotlk/pitofsaron/PitOfSaronStrategy.h @@ -0,0 +1,16 @@ +#ifndef _PLAYERBOT_WOTLKDUNGEONPOSSTRATEGY_H +#define _PLAYERBOT_WOTLKDUNGEONPOSSTRATEGY_H +#include "Multiplier.h" +#include "Strategy.h" + +class WotlkDungeonPoSStrategy : public Strategy +{ +public: + WotlkDungeonPoSStrategy(PlayerbotAI* ai) : Strategy(ai) {} + std::string const getName() override { return "pit of saron"; } + void InitTriggers(std::vector &triggers) override; + void InitMultipliers(std::vector &multipliers) override; + +}; + +#endif // !_PLAYERBOT_WOTLKDUNGEONFOSSTRATEGY_H diff --git a/src/strategy/dungeons/wotlk/pitofsaron/PitOfSaronTriggerContext.h b/src/strategy/dungeons/wotlk/pitofsaron/PitOfSaronTriggerContext.h new file mode 100644 index 00000000..a31bff94 --- /dev/null +++ b/src/strategy/dungeons/wotlk/pitofsaron/PitOfSaronTriggerContext.h @@ -0,0 +1,22 @@ +#ifndef _PLAYERBOT_WOTLKDUNGEONPOSTRIGGERCONTEXT_H +#define _PLAYERBOT_WOTLKDUNGEONPOSTRIGGERCONTEXT_H + +#include "NamedObjectContext.h" +#include "AiObjectContext.h" +#include "PitOfSaronTriggers.h" + +class WotlkDungeonPoSTriggerContext : public NamedObjectContext +{ +public: + WotlkDungeonPoSTriggerContext() + { + creators["ick and krick"] = &WotlkDungeonPoSTriggerContext::ick_and_krick; + creators["tyrannus"] = &WotlkDungeonPoSTriggerContext::tyrannus; + } + +private: + static Trigger* ick_and_krick(PlayerbotAI* ai) { return new IckAndKrickTrigger(ai); } + static Trigger* tyrannus(PlayerbotAI* ai) { return new TyrannusTrigger(ai); } +}; + +#endif diff --git a/src/strategy/dungeons/wotlk/pitofsaron/PitOfSaronTriggers.cpp b/src/strategy/dungeons/wotlk/pitofsaron/PitOfSaronTriggers.cpp new file mode 100644 index 00000000..f744302c --- /dev/null +++ b/src/strategy/dungeons/wotlk/pitofsaron/PitOfSaronTriggers.cpp @@ -0,0 +1,22 @@ +#include "Playerbots.h" +#include "PitOfSaronTriggers.h" +#include "AiObject.h" +#include "AiObjectContext.h" + +bool IckAndKrickTrigger::IsActive() +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "Ick"); + if (!boss) + return false; + + return true; +} + +bool TyrannusTrigger::IsActive() +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "scourgelord tyrannus"); + if (!boss) + return false; + + return true; +} diff --git a/src/strategy/dungeons/wotlk/pitofsaron/PitOfSaronTriggers.h b/src/strategy/dungeons/wotlk/pitofsaron/PitOfSaronTriggers.h new file mode 100644 index 00000000..9205026f --- /dev/null +++ b/src/strategy/dungeons/wotlk/pitofsaron/PitOfSaronTriggers.h @@ -0,0 +1,48 @@ +#ifndef _PLAYERBOT_WOTLKDUNGEONPOSTRIGGERS_H +#define _PLAYERBOT_WOTLKDUNGEONPOSTRIGGERS_H + +#include "Trigger.h" +#include "PlayerbotAIConfig.h" +#include "GenericTriggers.h" +#include "DungeonStrategyUtils.h" + +enum PitOfSaronIDs +{ + //NPCs + NPC_GARFROST = 36494, + NPC_KRICK = 36477, + NPC_ICK = 36476, + NPC_TYRANNUS = 36658, + NPC_RIMEFANG = 36661, + + //Spells + SPELL_PURSUIT = 68987, + SPELL_POISON_NOVA_POS = 68989, + SPELL_POISON_NOVA_POS_HC = 70434, + SPELL_EXPLOSIVE_BARRAGE_KRICK = 69012, + SPELL_EXPLOSIVE_BARRAGE_ICK = 69263, + SPELL_EXPLOSIVE_BARRAGE_SUMMON = 69015, + SPELL_EXPLODING_ORB_VISUAL = 69017, + SPELL_MARK_OF_RIMEFANG = 69275, + RIMEFANG_SPELL_HOARFROST = 69246, + RIMEFANG_SPELL_HOARFROST_HC = 69245, + RIMEFANG_SPELL_HOARFROST_HC2 = 69645, +}; + +class IckAndKrickTrigger : public Trigger +{ +public: + IckAndKrickTrigger(PlayerbotAI* ai) : Trigger(ai, "ick and krick") {} + + bool IsActive() override; +}; + +class TyrannusTrigger : public Trigger +{ +public: + TyrannusTrigger(PlayerbotAI* ai) : Trigger(ai, "tyrannus") {} + + bool IsActive() override; +}; + +#endif diff --git a/src/strategy/dungeons/wotlk/pitofsaron/TODO b/src/strategy/dungeons/wotlk/pitofsaron/TODO deleted file mode 100644 index e69de29b..00000000