From e60876a1cb3b67688eaf9f340f40f5ae27b4396b Mon Sep 17 00:00:00 2001 From: crow Date: Fri, 12 Sep 2025 08:46:17 -0500 Subject: [PATCH] Update Aran, Netherspite, Prince --- .../karazhan/RaidKarazhanActionContext.h | 16 +- .../raids/karazhan/RaidKarazhanActions.cpp | 345 ++++++++++++------ .../raids/karazhan/RaidKarazhanActions.h | 97 ++--- .../raids/karazhan/RaidKarazhanHelpers.cpp | 94 ++++- .../raids/karazhan/RaidKarazhanHelpers.h | 7 +- .../karazhan/RaidKarazhanMultipliers.cpp | 183 ++++++++++ .../raids/karazhan/RaidKarazhanMultipliers.h | 34 ++ .../raids/karazhan/RaidKarazhanStrategy.cpp | 14 +- .../raids/karazhan/RaidKarazhanStrategy.h | 5 +- .../karazhan/RaidKarazhanTriggerContext.h | 2 +- .../raids/karazhan/RaidKarazhanTriggers.cpp | 2 +- 11 files changed, 607 insertions(+), 192 deletions(-) create mode 100644 src/strategy/raids/karazhan/RaidKarazhanMultipliers.cpp create mode 100644 src/strategy/raids/karazhan/RaidKarazhanMultipliers.h diff --git a/src/strategy/raids/karazhan/RaidKarazhanActionContext.h b/src/strategy/raids/karazhan/RaidKarazhanActionContext.h index f58fe4b5..ac338cba 100644 --- a/src/strategy/raids/karazhan/RaidKarazhanActionContext.h +++ b/src/strategy/raids/karazhan/RaidKarazhanActionContext.h @@ -1,10 +1,8 @@ #ifndef _PLAYERBOT_RAIDKARAZHANACTIONS_CONTEXT_H #define _PLAYERBOT_RAIDKARAZHANACTIONS_CONTEXT_H -#include "Action.h" -#include "NamedObjectContext.h" #include "RaidKarazhanActions.h" - +#include "NamedObjectContext.h" class RaidKarazhanActionContext : public NamedObjectContext { @@ -32,7 +30,7 @@ public: creators["karazhan terestian illhoof mark target"] = &RaidKarazhanActionContext::karazhan_terestian_illhoof_mark_target; creators["karazhan shade of aran arcane explosion run away"] = &RaidKarazhanActionContext::karazhan_shade_of_aran_arcane_explosion_run_away; - creators["karazhan shade of aran flame wreath stop bot"] = &RaidKarazhanActionContext::karazhan_shade_of_aran_flame_wreath_stop_bot; + creators["karazhan shade of aran flame wreath stop movement"] = &RaidKarazhanActionContext::karazhan_shade_of_aran_flame_wreath_stop_movement; creators["karazhan shade of aran mark conjured elemental"] = &RaidKarazhanActionContext::karazhan_shade_of_aran_mark_conjured_elemental; creators["karazhan shade of aran spread ranged"] = &RaidKarazhanActionContext::karazhan_shade_of_aran_spread_ranged; @@ -42,8 +40,8 @@ public: creators["karazhan netherspite avoid beam and void zone"] = &RaidKarazhanActionContext::karazhan_netherspite_avoid_beam_and_void_zone; creators["karazhan netherspite banish phase avoid void zone"] = &RaidKarazhanActionContext::karazhan_netherspite_banish_phase_avoid_void_zone; - creators["karazhan prince malchezaar avoid infernal"] = &RaidKarazhanActionContext::karazhan_prince_malchezaar_avoid_infernal; - creators["karazhan prince malchezaar run away from shadow nova"] = &RaidKarazhanActionContext::karazhan_prince_malchezaar_run_away_from_shadow_nova; + creators["karazhan prince malchezaar non tank avoid hazard"] = &RaidKarazhanActionContext::karazhan_prince_malchezaar_non_tank_avoid_hazard; + creators["karazhan prince malchezaar tank avoid hazard"] = &RaidKarazhanActionContext::karazhan_prince_malchezaar_tank_avoid_hazard; } private: @@ -68,7 +66,7 @@ private: static Action* karazhan_terestian_illhoof_mark_target(PlayerbotAI* botAI) { return new KarazhanTerestianIllhoofMarkTargetAction(botAI); } static Action* karazhan_shade_of_aran_arcane_explosion_run_away(PlayerbotAI* botAI) { return new KarazhanShadeOfAranArcaneExplosionRunAwayAction(botAI); } - static Action* karazhan_shade_of_aran_flame_wreath_stop_bot(PlayerbotAI* botAI) { return new KarazhanShadeOfAranFlameWreathStopBotAction(botAI); } + static Action* karazhan_shade_of_aran_flame_wreath_stop_movement(PlayerbotAI* botAI) { return new KarazhanShadeOfAranFlameWreathStopMovementAction(botAI); } static Action* karazhan_shade_of_aran_mark_conjured_elemental(PlayerbotAI* botAI) { return new KarazhanShadeOfAranMarkConjuredElementalAction(botAI); } static Action* karazhan_shade_of_aran_spread_ranged(PlayerbotAI* botAI) { return new KarazhanShadeOfAranSpreadRangedAction(botAI); } @@ -78,8 +76,8 @@ private: static Action* karazhan_netherspite_avoid_beam_and_void_zone(PlayerbotAI* botAI) { return new KarazhanNetherspiteAvoidBeamAndVoidZoneAction(botAI); } static Action* karazhan_netherspite_banish_phase_avoid_void_zone(PlayerbotAI* botAI) { return new KarazhanNetherspiteBanishPhaseAvoidVoidZoneAction(botAI); } - static Action* karazhan_prince_malchezaar_avoid_infernal(PlayerbotAI* botAI) { return new KarazhanPrinceMalchezaarAvoidInfernalAction(botAI); } - static Action* karazhan_prince_malchezaar_run_away_from_shadow_nova(PlayerbotAI* botAI) { return new KarazhanPrinceMalchezaarRunAwayFromShadowNovaAction(botAI); } + static Action* karazhan_prince_malchezaar_non_tank_avoid_hazard(PlayerbotAI* botAI) { return new KarazhanPrinceMalchezaarNonTankAvoidHazardAction(botAI); } + static Action* karazhan_prince_malchezaar_tank_avoid_hazard(PlayerbotAI* botAI) { return new KarazhanPrinceMalchezaarTankAvoidHazardAction(botAI); } }; #endif diff --git a/src/strategy/raids/karazhan/RaidKarazhanActions.cpp b/src/strategy/raids/karazhan/RaidKarazhanActions.cpp index 799e7476..5f0e6064 100644 --- a/src/strategy/raids/karazhan/RaidKarazhanActions.cpp +++ b/src/strategy/raids/karazhan/RaidKarazhanActions.cpp @@ -1,14 +1,9 @@ -#include "Playerbots.h" #include "RaidKarazhanActions.h" #include "RaidKarazhanHelpers.h" -#include "Timer.h" -#include "WarlockActions.h" #include "AiObjectContext.h" -#include "Pet.h" -#include "GenericActions.h" +#include "Playerbots.h" #include "PlayerbotMgr.h" #include "PlayerbotAI.h" -#include "MovementActions.h" namespace { @@ -344,8 +339,6 @@ bool KarazhanTerestianIllhoofMarkTargetAction::Execute(Event event) bool KarazhanShadeOfAranArcaneExplosionRunAwayAction::Execute(Event event) { Unit* boss = AI_VALUE2(Unit*, "find target", "shade of aran"); - static std::map arcaneExplosionEndTimes; - ObjectGuid botGuid = bot->GetGUID(); const float safeDistance = 20.0f; const float distance = bot->GetDistance2d(boss); @@ -356,64 +349,30 @@ bool KarazhanShadeOfAranArcaneExplosionRunAwayAction::Execute(Event event) { return MoveAway(boss, safeDistance - distance); } - - if (!botAI->HasStrategy("stay", BOT_STATE_COMBAT)) - botAI->ChangeStrategy("+stay", BOT_STATE_COMBAT); - + return false; } bool KarazhanShadeOfAranArcaneExplosionRunAwayAction::isUseful() { Unit* boss = AI_VALUE2(Unit*, "find target", "shade of aran"); - static std::map arcaneExplosionEndTimes; - ObjectGuid botGuid = bot->GetGUID(); if (!boss || !boss->IsAlive()) return false; - if (boss->HasUnitState(UNIT_STATE_CASTING) && boss->FindCurrentSpellBySpellId(SPELL_ARCANE_EXPLOSION)) - { - arcaneExplosionEndTimes[botGuid] = time(nullptr) + 1; - return true; - } - - if (arcaneExplosionEndTimes.count(botGuid) && arcaneExplosionEndTimes[botGuid] > time(nullptr)) - { - return true; - } - - if (arcaneExplosionEndTimes.count(botGuid)) - arcaneExplosionEndTimes.erase(botGuid); - - if (botAI->HasStrategy("stay", BOT_STATE_COMBAT)) - botAI->ChangeStrategy("-stay", BOT_STATE_COMBAT); - - return false; + return boss->HasUnitState(UNIT_STATE_CASTING) && boss->FindCurrentSpellBySpellId(SPELL_ARCANE_EXPLOSION); } -bool KarazhanShadeOfAranFlameWreathStopBotAction::Execute(Event event) +bool KarazhanShadeOfAranFlameWreathStopMovementAction::Execute(Event event) { RaidKarazhanHelpers karazhanHelper(botAI); - static std::map flameWreathPositions; - ObjectGuid botGuid = bot->GetGUID(); if (karazhanHelper.IsFlameWreathActive()) { - if (flameWreathPositions.find(botGuid) == flameWreathPositions.end()) - { - flameWreathPositions[botGuid] = Position(bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ()); - } - AI_VALUE(LastMovement&, "last movement").Set(nullptr); bot->GetMotionMaster()->Clear(); if (bot->isMoving()) bot->StopMoving(); - Position& pos = flameWreathPositions[botGuid]; - return MoveTo(bot->GetMapId(), pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), false, false, false, true, MovementPriority::MOVEMENT_FORCED); - } - else - { - flameWreathPositions.erase(botGuid); + return true; } return false; } @@ -422,11 +381,11 @@ bool KarazhanShadeOfAranMarkConjuredElementalAction::Execute(Event event) { RaidKarazhanHelpers karazhanHelper(botAI); Unit* boss = AI_VALUE2(Unit*, "find target", "shade of aran"); - if (!boss || !boss->IsAlive() || karazhanHelper.IsFlameWreathActive()) + if (!boss || !boss->IsAlive()) return false; Unit* target = karazhanHelper.GetFirstAliveUnitByEntry(NPC_CONJURED_ELEMENTAL); - if (!target || target->HasAura(SPELL_WARLOCK_BANISH) || !target->IsAlive()) + if (!target || !target->IsAlive() || target->HasAura(SPELL_WARLOCK_BANISH)) { return false; } @@ -474,7 +433,8 @@ bool KarazhanShadeOfAranSpreadRangedAction::isUseful() RaidKarazhanHelpers karazhanHelper(botAI); - return botAI->IsRanged(bot) && !karazhanHelper.IsFlameWreathActive() && !(boss->HasUnitState(UNIT_STATE_CASTING) && boss->FindCurrentSpellBySpellId(SPELL_ARCANE_EXPLOSION)); + return botAI->IsRanged(bot) && !karazhanHelper.IsFlameWreathActive() && !(boss->HasUnitState(UNIT_STATE_CASTING) + && boss->FindCurrentSpellBySpellId(SPELL_ARCANE_EXPLOSION)); } // One tank per phase will dance in and out of the red beam (5 seconds in, 5 seconds out) @@ -524,7 +484,8 @@ bool KarazhanNetherspiteBlockRedBeamAction::Execute(Event event) } if (!lastBeamMoveSideways[botGuid]) { - return MoveTo(bot->GetMapId(), beamPos.GetPositionX(), beamPos.GetPositionY(), beamPos.GetPositionZ(), false, false, false, true, MovementPriority::MOVEMENT_FORCED); + return MoveTo(bot->GetMapId(), beamPos.GetPositionX(), beamPos.GetPositionY(), beamPos.GetPositionZ(), + false, false, false, true, MovementPriority::MOVEMENT_FORCED); } else { @@ -654,7 +615,8 @@ bool KarazhanNetherspiteBlockBlueBeamAction::Execute(Event event) } if (found) { - return MoveTo(bot->GetMapId(), bestPos.GetPositionX(), bestPos.GetPositionY(), bestPos.GetPositionZ(), false, false, false, true, MovementPriority::MOVEMENT_FORCED); + return MoveTo(bot->GetMapId(), bestPos.GetPositionX(), bestPos.GetPositionY(), bestPos.GetPositionZ(), + false, false, false, true, MovementPriority::MOVEMENT_FORCED); } return false; } @@ -744,7 +706,8 @@ bool KarazhanNetherspiteBlockGreenBeamAction::Execute(Event event) } if (found) { - return MoveTo(bot->GetMapId(), bestPos.GetPositionX(), bestPos.GetPositionY(), bestPos.GetPositionZ(), false, false, false, true, MovementPriority::MOVEMENT_FORCED); + return MoveTo(bot->GetMapId(), bestPos.GetPositionX(), bestPos.GetPositionY(), bestPos.GetPositionZ(), + false, false, false, true, MovementPriority::MOVEMENT_FORCED); } return false; } @@ -881,10 +844,9 @@ bool KarazhanNetherspiteAvoidBeamAndVoidZoneAction::Execute(Event event) } if (found && karazhanHelper.IsSafePosition(bestCandidate.GetPositionX(), bestCandidate.GetPositionY(), bestCandidate.GetPositionZ(), voidZones, 4.0f)) - { + return MoveTo(bot->GetMapId(), bestCandidate.GetPositionX(), bestCandidate.GetPositionY(), bestCandidate.GetPositionZ(), false, false, false, true, MovementPriority::MOVEMENT_COMBAT); - } return false; } @@ -910,9 +872,7 @@ bool KarazhanNetherspiteBanishPhaseAvoidVoidZoneAction::Execute(Event event) for (Unit* vz : voidZones) { if (vz->GetEntry() == NPC_VOID_ZONE && bot->GetExactDist2d(vz) < 4.0f) - { return FleePosition(vz->GetPosition(), 4.0f); - } } return false; } @@ -928,95 +888,252 @@ bool KarazhanNetherspiteBanishPhaseAvoidVoidZoneAction::isUseful() for (Unit* vz : voidZones) { if (bot->GetExactDist2d(vz) < 4.0f) - { return true; - } } return false; } -bool KarazhanPrinceMalchezaarAvoidInfernalAction::Execute(Event event) -{ - Unit* boss = AI_VALUE2(Unit*, "find target", "prince malchezaar"); - if (!boss) - return false; - - RaidKarazhanHelpers karazhanHelper(botAI); - std::vector infernals = karazhanHelper.GetSpawnedInfernals(); - - const float safeInfernalDistance = 20.0f; - const float safeInfernalTankingDistance = 25.0f; - float safeDistance = botAI->IsTank(bot) && botAI->HasAggro(boss) && boss->GetVictim() == - bot ? safeInfernalTankingDistance : safeInfernalDistance; - - for (Unit* infernal : infernals) - { - float distance = bot->GetDistance2d(infernal); - if (distance < safeDistance) - { - bot->AttackStop(); - bot->InterruptNonMeleeSpells(false); - return MoveAway(infernal, safeDistance - distance); - } - } - return false; -} - -// For Enfeebled bots to avoid getting one-shot by Shadow Nova -bool KarazhanPrinceMalchezaarRunAwayFromShadowNovaAction::Execute(Event event) +// For Enfeebled bots to avoid Shadow Nova and all non-tank bots to avoid infernals +bool KarazhanPrinceMalchezaarNonTankAvoidHazardAction::Execute(Event event) { Unit* boss = AI_VALUE2(Unit*, "find target", "prince malchezaar"); RaidKarazhanHelpers karazhanHelper(botAI); std::vector infernals = karazhanHelper.GetSpawnedInfernals(); - const float safeBossDistance = 30.0f; - const float safeInfernalDistance = 20.0f; - float currentBossDistance = bot->GetDistance2d(boss); - if (currentBossDistance < safeBossDistance) + const float minSafeBossDistance = 35.0f; + const float maxSafeBossDistance = 40.0f; + const float safeInfernalDistance = 22.0f; + const float stepSize = 0.5f; + const int numAngles = 64; + float bx = bot->GetPositionX(); + float by = bot->GetPositionY(); + float bz = bot->GetPositionZ(); + float bossX = boss->GetPositionX(); + float bossY = boss->GetPositionY(); + float bossZ = boss->GetPositionZ(); + float bestMoveDist = std::numeric_limits::max(); + float bestDestX = 0.0f, bestDestY = 0.0f, bestDestZ = bz; + bool found = false; + + if (bot->HasAura(SPELL_ENFEEBLE)) { - const float stepSize = 0.5f; - const int numAngles = 64; for (int i = 0; i < numAngles; ++i) { float angle = (2 * M_PI * i) / numAngles; float dx = cos(angle); float dy = sin(angle); - - bool pathIsSafe = true; - for (float dist = stepSize; dist <= safeBossDistance; dist += stepSize) + for (float dist = minSafeBossDistance; dist <= maxSafeBossDistance; dist += stepSize) { - float x = bot->GetPositionX() + dx * dist; - float y = bot->GetPositionY() + dy * dist; - for (Unit* infernal : infernals) + float x = bossX + dx * dist; + float y = bossY + dy * dist; + float destZ = bossZ; + if (!bot->IsWithinLOS(x, y, destZ)) + continue; + bool pathSafe = karazhanHelper.IsStraightPathSafe(Position(bx, by, bz), Position(x, y, destZ), infernals, safeInfernalDistance, stepSize); + float moveDist = sqrt(pow(x - bx, 2) + pow(y - by, 2)); + if (pathSafe && moveDist < bestMoveDist) { - float infernalDist = sqrt(pow(x - infernal->GetPositionX(), 2) + pow(y - infernal->GetPositionY(), 2)); - if (infernalDist < safeInfernalDistance) + bestMoveDist = moveDist; + bestDestX = x; + bestDestY = y; + bestDestZ = destZ; + found = true; + } + } + } + if (found) + { + bot->AttackStop(); + bot->InterruptNonMeleeSpells(false); + + return MoveTo(bot->GetMapId(), bestDestX, bestDestY, bestDestZ, false, false, false, true, MovementPriority::MOVEMENT_FORCED); + } + return false; + } + + if (!bot->HasAura(SPELL_ENFEEBLE)) + { + bool nearInfernal = false; + for (Unit* infernal : infernals) + { + float infernalDist = sqrt(pow(bx - infernal->GetPositionX(), 2) + pow(by - infernal->GetPositionY(), 2)); + if (infernalDist < safeInfernalDistance) + { + nearInfernal = true; + break; + } + } + if (nearInfernal) + { + float bestMoveDist = std::numeric_limits::max(); + float bestDestX = bx, bestDestY = by, bestDestZ = bz; + bool found = false; + bool usedArc = false; + for (int i = 0; i < numAngles; ++i) + { + float angle = (2 * M_PI * i) / numAngles; + float dx = cos(angle); + float dy = sin(angle); + for (float dist = stepSize; dist <= 35.0f; dist += stepSize) + { + float x = bossX + dx * dist; + float y = bossY + dy * dist; + float destZ = bossZ; + if (!bot->IsWithinLOS(x, y, destZ)) + continue; + bool pathSafe = karazhanHelper.IsStraightPathSafe(Position(bx, by, bz), Position(x, y, destZ), infernals, safeInfernalDistance, stepSize); + float moveDist = sqrt(pow(x - bx, 2) + pow(y - by, 2)); + if (pathSafe && moveDist < bestMoveDist) { - pathIsSafe = false; - break; + bestMoveDist = moveDist; + bestDestX = x; + bestDestY = y; + bestDestZ = destZ; + found = true; + usedArc = false; + } + if (!pathSafe) + { + Position arcPoint = karazhanHelper.CalculateArcPoint(Position(bx, by, bz), Position(x, y, destZ), Position(bossX, bossY, bossZ)); + if (!bot->IsWithinLOS(arcPoint.GetPositionX(), arcPoint.GetPositionY(), arcPoint.GetPositionZ())) + continue; + bool arcSafe = true; + for (Unit* infernal : infernals) + { + float infernalDist = sqrt(pow(arcPoint.GetPositionX() - infernal->GetPositionX(), 2) + pow(arcPoint.GetPositionY() - infernal->GetPositionY(), 2)); + if (infernalDist < safeInfernalDistance) + { + arcSafe = false; + break; + } + } + float arcMoveDist = sqrt(pow(arcPoint.GetPositionX() - bx, 2) + pow(arcPoint.GetPositionY() - by, 2)); + if (arcSafe && arcMoveDist < bestMoveDist) + { + bestMoveDist = arcMoveDist; + bestDestX = arcPoint.GetPositionX(); + bestDestY = arcPoint.GetPositionY(); + bestDestZ = arcPoint.GetPositionZ(); + found = true; + usedArc = true; + } } } - if (!pathIsSafe) - break; } - if (pathIsSafe) + if (found) { - float destX = bot->GetPositionX() + dx * (safeBossDistance - currentBossDistance); - float destY = bot->GetPositionY() + dy * (safeBossDistance - currentBossDistance); - float destZ = bot->GetPositionZ(); bot->AttackStop(); bot->InterruptNonMeleeSpells(false); - if (karazhanHelper.IsSafePosition(destX, destY, destZ, infernals, 20.0f)) - return MoveTo(bot->GetMapId(), destX, destY, destZ, false, false, false, true, MovementPriority::MOVEMENT_FORCED); + + return MoveTo(bot->GetMapId(), bestDestX, bestDestY, bestDestZ, false, false, false, true, MovementPriority::MOVEMENT_COMBAT); } } } return false; } -bool KarazhanPrinceMalchezaarRunAwayFromShadowNovaAction::isUseful() +bool KarazhanPrinceMalchezaarNonTankAvoidHazardAction::isUseful() { Unit* boss = AI_VALUE2(Unit*, "find target", "prince malchezaar"); - - return boss && bot->HasAura(SPELL_ENFEEBLE); + + return boss && !(botAI->IsTank(bot) && botAI->HasAggro(boss) && boss->GetVictim() == bot); +} + +// For tank to avoid infernals (with buffer distance) +bool KarazhanPrinceMalchezaarTankAvoidHazardAction::Execute(Event event) +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "prince malchezaar"); + RaidKarazhanHelpers karazhanHelper(botAI); + std::vector infernals = karazhanHelper.GetSpawnedInfernals(); + + const float safeInfernalDistance = 30.0f; + const float stepSize = 0.5f; + const int numAngles = 64; + const float maxSampleDist = 60.0f; + float bx = bot->GetPositionX(); + float by = bot->GetPositionY(); + float bz = bot->GetPositionZ(); + float bestMoveDist = std::numeric_limits::max(); + float bestDestX = bx, bestDestY = by, bestDestZ = bz; + bool found = false; + bool usedArc = false; + + bool nearInfernal = false; + for (Unit* infernal : infernals) + { + float infernalDist = sqrt(pow(bx - infernal->GetPositionX(), 2) + pow(by - infernal->GetPositionY(), 2)); + if (infernalDist < safeInfernalDistance) + { + nearInfernal = true; + break; + } + } + if (nearInfernal) + { + for (int i = 0; i < numAngles; ++i) + { + float angle = (2 * M_PI * i) / numAngles; + float dx = cos(angle); + float dy = sin(angle); + for (float dist = stepSize; dist <= maxSampleDist; dist += stepSize) + { + float x = bx + dx * dist; + float y = by + dy * dist; + float z = bz; + if (!bot->IsWithinLOS(x, y, z)) + continue; + bool safe = karazhanHelper.IsStraightPathSafe(Position(bx, by, bz), Position(x, y, z), infernals, safeInfernalDistance, stepSize); + float moveDist = sqrt(pow(x - bx, 2) + pow(y - by, 2)); + if (safe && moveDist < bestMoveDist) + { + bestMoveDist = moveDist; + bestDestX = x; + bestDestY = y; + bestDestZ = z; + found = true; + usedArc = false; + } + if (!safe) + { + Position arcPoint = karazhanHelper.CalculateArcPoint(Position(bx, by, bz), Position(x, y, z), Position(bx, by, bz)); + if (!bot->IsWithinLOS(arcPoint.GetPositionX(), arcPoint.GetPositionY(), arcPoint.GetPositionZ())) + continue; + bool arcSafe = true; + for (Unit* infernal : infernals) + { + float infernalDist = sqrt(pow(arcPoint.GetPositionX() - infernal->GetPositionX(), 2) + pow(arcPoint.GetPositionY() - infernal->GetPositionY(), 2)); + if (infernalDist < safeInfernalDistance) + { + arcSafe = false; + break; + } + } + float arcMoveDist = sqrt(pow(arcPoint.GetPositionX() - bx, 2) + pow(arcPoint.GetPositionY() - by, 2)); + if (arcSafe && arcMoveDist < bestMoveDist) + { + bestMoveDist = arcMoveDist; + bestDestX = arcPoint.GetPositionX(); + bestDestY = arcPoint.GetPositionY(); + bestDestZ = arcPoint.GetPositionZ(); + found = true; + usedArc = true; + } + } + } + } + if (found) + { + bot->AttackStop(); + bot->InterruptNonMeleeSpells(false); + return MoveTo(bot->GetMapId(), bestDestX, bestDestY, bestDestZ, false, false, false, true, MovementPriority::MOVEMENT_COMBAT); + } + } + return false; +} + +bool KarazhanPrinceMalchezaarTankAvoidHazardAction::isUseful() +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "prince malchezaar"); + + return boss && botAI->IsTank(bot) && botAI->HasAggro(boss) && boss->GetVictim() == bot; } diff --git a/src/strategy/raids/karazhan/RaidKarazhanActions.h b/src/strategy/raids/karazhan/RaidKarazhanActions.h index 37d69b14..c9b34d03 100644 --- a/src/strategy/raids/karazhan/RaidKarazhanActions.h +++ b/src/strategy/raids/karazhan/RaidKarazhanActions.h @@ -1,48 +1,48 @@ #ifndef _PLAYERBOT_RAIDKARAZHANACTIONS_H #define _PLAYERBOT_RAIDKARAZHANACTIONS_H -#include "AttackAction.h" -#include "RaidKarazhanHelpers.h" +#include "Action.h" +#include "MovementActions.h" -class KarazhanAttumenTheHuntsmanStackBehindAction : public AttackAction +class KarazhanAttumenTheHuntsmanStackBehindAction : public MovementAction { public: - KarazhanAttumenTheHuntsmanStackBehindAction(PlayerbotAI* botAI, std::string const name = "karazhan attumen the huntsman stack behind") : AttackAction(botAI, name) {} + KarazhanAttumenTheHuntsmanStackBehindAction(PlayerbotAI* botAI, std::string const name = "karazhan attumen the huntsman stack behind") : MovementAction(botAI, name) {} bool Execute(Event event) override; bool isUseful() override; }; -class KarazhanMoroesMarkTargetAction : public AttackAction +class KarazhanMoroesMarkTargetAction : public Action { public: - KarazhanMoroesMarkTargetAction(PlayerbotAI* botAI, std::string const name = "karazhan moroes mark target") : AttackAction(botAI, name) {} + KarazhanMoroesMarkTargetAction(PlayerbotAI* botAI, std::string const name = "karazhan moroes mark target") : Action(botAI, name) {} bool Execute(Event event) override; }; -class KarazhanMaidenOfVirtuePositionBossAction : public AttackAction +class KarazhanMaidenOfVirtuePositionBossAction : public MovementAction { public: - KarazhanMaidenOfVirtuePositionBossAction(PlayerbotAI* botAI, std::string const name = "karazhan maiden of virtue position boss") : AttackAction(botAI, name) {} + KarazhanMaidenOfVirtuePositionBossAction(PlayerbotAI* botAI, std::string const name = "karazhan maiden of virtue position boss") : MovementAction(botAI, name) {} bool Execute(Event event) override; bool isUseful() override; }; -class KarazhanMaidenOfVirtuePositionRangedAction : public AttackAction +class KarazhanMaidenOfVirtuePositionRangedAction : public MovementAction { public: - KarazhanMaidenOfVirtuePositionRangedAction(PlayerbotAI* botAI, std::string const name = "karazhan maiden of virtue position ranged") : AttackAction(botAI, name) {} + KarazhanMaidenOfVirtuePositionRangedAction(PlayerbotAI* botAI, std::string const name = "karazhan maiden of virtue position ranged") : MovementAction(botAI, name) {} bool Execute(Event event) override; bool isUseful() override; }; -class KarazhanBigBadWolfRunAwayAction : public AttackAction +class KarazhanBigBadWolfRunAwayAction : public MovementAction { public: - KarazhanBigBadWolfRunAwayAction(PlayerbotAI* botAI, std::string const name = "karazhan big bad wolf run away") : AttackAction(botAI, name) {} + KarazhanBigBadWolfRunAwayAction(PlayerbotAI* botAI, std::string const name = "karazhan big bad wolf run away") : MovementAction(botAI, name) {} bool Execute(Event event) override; bool isUseful() override; @@ -51,155 +51,156 @@ private: size_t currentIndex = 0; }; -class KarazhanRomuloAndJulianneMarkTargetAction : public AttackAction +class KarazhanRomuloAndJulianneMarkTargetAction : public Action { public: - KarazhanRomuloAndJulianneMarkTargetAction(PlayerbotAI* botAI, std::string const name = "karazhan romulo and julianne mark target") : AttackAction(botAI, name) {} + KarazhanRomuloAndJulianneMarkTargetAction(PlayerbotAI* botAI, std::string const name = "karazhan romulo and julianne mark target") : Action(botAI, name) {} bool Execute(Event event) override; }; -class KarazhanWizardOfOzMarkTargetAction : public AttackAction +class KarazhanWizardOfOzMarkTargetAction : public Action { public: - KarazhanWizardOfOzMarkTargetAction(PlayerbotAI* botAI, std::string const name = "karazhan wizard of oz mark target") : AttackAction(botAI, name) {} + KarazhanWizardOfOzMarkTargetAction(PlayerbotAI* botAI, std::string const name = "karazhan wizard of oz mark target") : Action(botAI, name) {} bool Execute(Event event) override; }; -class KarazhanWizardOfOzScorchStrawmanAction : public AttackAction +class KarazhanWizardOfOzScorchStrawmanAction : public Action { public: - KarazhanWizardOfOzScorchStrawmanAction(PlayerbotAI* botAI, std::string const name = "karazhan wizard of oz scorch strawman") : AttackAction(botAI, name) {} + KarazhanWizardOfOzScorchStrawmanAction(PlayerbotAI* botAI, std::string const name = "karazhan wizard of oz scorch strawman") : Action(botAI, name) {} bool Execute(Event event) override; }; -class KarazhanTheCuratorMarkTargetAction : public AttackAction +class KarazhanTheCuratorMarkTargetAction : public Action { public: - KarazhanTheCuratorMarkTargetAction(PlayerbotAI* botAI, std::string const name = "karazhan the curator mark target") : AttackAction(botAI, name) {} + KarazhanTheCuratorMarkTargetAction(PlayerbotAI* botAI, std::string const name = "karazhan the curator mark target") : Action(botAI, name) {} bool Execute(Event event) override; }; -class KarazhanTheCuratorPositionBossAction : public AttackAction +class KarazhanTheCuratorPositionBossAction : public MovementAction { public: - KarazhanTheCuratorPositionBossAction(PlayerbotAI* botAI, std::string const name = "karazhan the curator position boss") : AttackAction(botAI, name) {} + KarazhanTheCuratorPositionBossAction(PlayerbotAI* botAI, std::string const name = "karazhan the curator position boss") : MovementAction(botAI, name) {} bool Execute(Event event) override; bool isUseful() override; }; -class KarazhanTheCuratorSpreadRangedAction : public AttackAction +class KarazhanTheCuratorSpreadRangedAction : public MovementAction { public: - KarazhanTheCuratorSpreadRangedAction(PlayerbotAI* botAI, std::string const name = "karazhan the curator spread ranged") : AttackAction(botAI, name) {} + KarazhanTheCuratorSpreadRangedAction(PlayerbotAI* botAI, std::string const name = "karazhan the curator spread ranged") : MovementAction(botAI, name) {} bool Execute(Event event) override; bool isUseful() override; }; -class KarazhanTerestianIllhoofMarkTargetAction : public AttackAction +class KarazhanTerestianIllhoofMarkTargetAction : public Action { public: - KarazhanTerestianIllhoofMarkTargetAction(PlayerbotAI* botAI, std::string const name = "karazhan terestian illhoof mark target") : AttackAction(botAI, name) {} + KarazhanTerestianIllhoofMarkTargetAction(PlayerbotAI* botAI, std::string const name = "karazhan terestian illhoof mark target") : Action(botAI, name) {} bool Execute(Event event) override; }; -class KarazhanShadeOfAranArcaneExplosionRunAwayAction : public AttackAction +class KarazhanShadeOfAranArcaneExplosionRunAwayAction : public MovementAction { public: - KarazhanShadeOfAranArcaneExplosionRunAwayAction(PlayerbotAI* botAI, std::string const name = "karazhan shade of aran arcane explosion run away") : AttackAction(botAI, name) {} + KarazhanShadeOfAranArcaneExplosionRunAwayAction(PlayerbotAI* botAI, std::string const name = "karazhan shade of aran arcane explosion run away") : MovementAction(botAI, name) {} bool Execute(Event event) override; bool isUseful() override; }; -class KarazhanShadeOfAranFlameWreathStopBotAction : public AttackAction +class KarazhanShadeOfAranFlameWreathStopMovementAction : public MovementAction { public: - KarazhanShadeOfAranFlameWreathStopBotAction(PlayerbotAI* botAI, std::string const name = "karazhan shade of aran flame wreath stop bot") : AttackAction(botAI, name) {} + KarazhanShadeOfAranFlameWreathStopMovementAction(PlayerbotAI* botAI, std::string const name = "karazhan shade of aran flame wreath stop bot") : MovementAction(botAI, name) {} bool Execute(Event event) override; }; -class KarazhanShadeOfAranMarkConjuredElementalAction : public AttackAction +class KarazhanShadeOfAranMarkConjuredElementalAction : public Action { public: - KarazhanShadeOfAranMarkConjuredElementalAction(PlayerbotAI* botAI, std::string const name = "karazhan shade of aran mark conjured elemental") : AttackAction(botAI, name) {} + KarazhanShadeOfAranMarkConjuredElementalAction(PlayerbotAI* botAI, std::string const name = "karazhan shade of aran mark conjured elemental") : Action(botAI, name) {} bool Execute(Event event) override; }; -class KarazhanShadeOfAranSpreadRangedAction : public AttackAction +class KarazhanShadeOfAranSpreadRangedAction : public MovementAction { public: - KarazhanShadeOfAranSpreadRangedAction(PlayerbotAI* botAI, std::string const name = "karazhan shade of aran spread ranged") : AttackAction(botAI, name) {} + KarazhanShadeOfAranSpreadRangedAction(PlayerbotAI* botAI, std::string const name = "karazhan shade of aran spread ranged") : MovementAction(botAI, name) {} bool Execute(Event event) override; bool isUseful() override; }; -class KarazhanNetherspiteBlockRedBeamAction : public AttackAction +class KarazhanNetherspiteBlockRedBeamAction : public MovementAction { public: - KarazhanNetherspiteBlockRedBeamAction(PlayerbotAI* botAI, std::string const name = "karazhan netherspite block red beam") : AttackAction(botAI, name) {} + KarazhanNetherspiteBlockRedBeamAction(PlayerbotAI* botAI, std::string const name = "karazhan netherspite block red beam") : MovementAction(botAI, name) {} bool Execute(Event event) override; bool isUseful() override; }; -class KarazhanNetherspiteBlockBlueBeamAction : public AttackAction +class KarazhanNetherspiteBlockBlueBeamAction : public MovementAction { public: - KarazhanNetherspiteBlockBlueBeamAction(PlayerbotAI* botAI, std::string const name = "karazhan netherspite block blue beam") : AttackAction(botAI, name) {} + KarazhanNetherspiteBlockBlueBeamAction(PlayerbotAI* botAI, std::string const name = "karazhan netherspite block blue beam") : MovementAction(botAI, name) {} bool Execute(Event event) override; bool isUseful() override; }; -class KarazhanNetherspiteBlockGreenBeamAction : public AttackAction +class KarazhanNetherspiteBlockGreenBeamAction : public MovementAction { public: - KarazhanNetherspiteBlockGreenBeamAction(PlayerbotAI* botAI, std::string const name = "karazhan netherspite block green beam") : AttackAction(botAI, name) {} + KarazhanNetherspiteBlockGreenBeamAction(PlayerbotAI* botAI, std::string const name = "karazhan netherspite block green beam") : MovementAction(botAI, name) {} bool Execute(Event event) override; bool isUseful() override; }; -class KarazhanNetherspiteAvoidBeamAndVoidZoneAction : public AttackAction +class KarazhanNetherspiteAvoidBeamAndVoidZoneAction : public MovementAction { public: - KarazhanNetherspiteAvoidBeamAndVoidZoneAction(PlayerbotAI* botAI, std::string const name = "karazhan netherspite avoid beam and void zone") : AttackAction(botAI, name) {} + KarazhanNetherspiteAvoidBeamAndVoidZoneAction(PlayerbotAI* botAI, std::string const name = "karazhan netherspite avoid beam and void zone") : MovementAction(botAI, name) {} bool Execute(Event event) override; bool isUseful() override; }; -class KarazhanNetherspiteBanishPhaseAvoidVoidZoneAction : public AttackAction +class KarazhanNetherspiteBanishPhaseAvoidVoidZoneAction : public MovementAction { public: - KarazhanNetherspiteBanishPhaseAvoidVoidZoneAction(PlayerbotAI* botAI, std::string const name = "karazhan netherspite banish phase avoid void zone") : AttackAction(botAI, name) {} + KarazhanNetherspiteBanishPhaseAvoidVoidZoneAction(PlayerbotAI* botAI, std::string const name = "karazhan netherspite banish phase avoid void zone") : MovementAction(botAI, name) {} bool Execute(Event event) override; bool isUseful() override; }; -class KarazhanPrinceMalchezaarAvoidInfernalAction : public AttackAction +class KarazhanPrinceMalchezaarNonTankAvoidHazardAction : public MovementAction { public: - KarazhanPrinceMalchezaarAvoidInfernalAction(PlayerbotAI* botAI, std::string const name = "karazhan prince malchezaar avoid infernal") : AttackAction(botAI, name) {} + KarazhanPrinceMalchezaarNonTankAvoidHazardAction(PlayerbotAI* botAI, std::string const name = "karazhan prince malchezaar non-tank avoid hazard") : MovementAction(botAI, name) {} bool Execute(Event event) override; + bool isUseful() override; }; -class KarazhanPrinceMalchezaarRunAwayFromShadowNovaAction : public AttackAction +class KarazhanPrinceMalchezaarTankAvoidHazardAction : public MovementAction { public: - KarazhanPrinceMalchezaarRunAwayFromShadowNovaAction(PlayerbotAI* botAI, std::string const name = "karazhan prince malchezaar run away from shadow nova") : AttackAction(botAI, name) {} + KarazhanPrinceMalchezaarTankAvoidHazardAction(PlayerbotAI* botAI, std::string const name = "karazhan prince malchezaar tank avoid hazard") : MovementAction(botAI, name) {} bool Execute(Event event) override; bool isUseful() override; diff --git a/src/strategy/raids/karazhan/RaidKarazhanHelpers.cpp b/src/strategy/raids/karazhan/RaidKarazhanHelpers.cpp index 3a1360cc..21b08e47 100644 --- a/src/strategy/raids/karazhan/RaidKarazhanHelpers.cpp +++ b/src/strategy/raids/karazhan/RaidKarazhanHelpers.cpp @@ -1,13 +1,13 @@ -#include "RaidKarazhanActions.h" -#include "RaidKarazhanHelpers.h" -#include "PlayerbotMgr.h" -#include "AiObjectContext.h" -#include "Position.h" -#include "Spell.h" - #include #include +#include "RaidKarazhanHelpers.h" +#include "RaidKarazhanActions.h" +#include "AiObjectContext.h" +#include "PlayerbotMgr.h" +#include "Position.h" +#include "Spell.h" + void RaidKarazhanHelpers::MarkTargetWithSkull(Unit* target) { if (!target) @@ -71,7 +71,7 @@ bool RaidKarazhanHelpers::IsFlameWreathActive() return false; Spell* currentSpell = boss->GetCurrentSpell(CURRENT_GENERIC_SPELL); - if (currentSpell && currentSpell->m_spellInfo && currentSpell->m_spellInfo->Id == SPELL_FLAME_WREATH_CAST) + if (currentSpell && currentSpell->m_spellInfo && currentSpell->m_spellInfo->Id == SPELL_FLAME_WREATH) { bot->Yell("I will not move when Flame Wreath is cast or the raid blows up.", LANG_UNIVERSAL); return true; @@ -84,7 +84,7 @@ bool RaidKarazhanHelpers::IsFlameWreathActive() Player* member = itr->GetSource(); if (!member || !member->IsAlive()) continue; - if (member->HasAura(SPELL_FLAME_WREATH_AURA)) + if (member->HasAura(SPELL_AURA_FLAME_WREATH)) return true; } } @@ -260,3 +260,79 @@ std::vector RaidKarazhanHelpers::GetSpawnedInfernals() const } return infernals; } + +bool RaidKarazhanHelpers::IsStraightPathSafe(const Position& start, const Position& target, const std::vector& hazards, float hazardRadius, float stepSize) +{ + float sx = start.GetPositionX(); + float sy = start.GetPositionY(); + float sz = start.GetPositionZ(); + float tx = target.GetPositionX(); + float ty = target.GetPositionY(); + float tz = target.GetPositionZ(); + float totalDist = std::sqrt(std::pow(tx - sx, 2) + std::pow(ty - sy, 2)); + if (totalDist == 0.0f) + return true; + for (float checkDist = 0.0f; checkDist <= totalDist; checkDist += stepSize) + { + float t = checkDist / totalDist; + float checkX = sx + (tx - sx) * t; + float checkY = sy + (ty - sy) * t; + float checkZ = sz + (tz - sz) * t; + for (Unit* hazard : hazards) + { + float hazardDist = std::sqrt(std::pow(checkX - hazard->GetPositionX(), 2) + std::pow(checkY - hazard->GetPositionY(), 2)); + if (hazardDist < hazardRadius) + return false; + } + } + return true; +} + +Position RaidKarazhanHelpers::CalculateArcPoint(const Position& current, const Position& target, const Position& center) +{ + float arcFraction = 0.25f; + // Calculate vectors from center to current position and target + float currentX = current.GetPositionX() - center.GetPositionX(); + float currentY = current.GetPositionY() - center.GetPositionY(); + float targetX = target.GetPositionX() - center.GetPositionX(); + float targetY = target.GetPositionY() - center.GetPositionY(); + + // Calculate distances + float currentDist = std::sqrt(currentX * currentX + currentY * currentY); + float targetDist = std::sqrt(targetX * targetX + targetY * targetY); + if (currentDist == 0.0f || targetDist == 0.0f) + return current; + + // Normalize vectors + currentX /= currentDist; + currentY /= currentDist; + targetX /= targetDist; + targetY /= targetDist; + + // Calculate dot product to find the angle between vectors + float dotProduct = currentX * targetX + currentY * targetY; + dotProduct = std::max(-1.0f, std::min(1.0f, dotProduct)); // Clamp to [-1, 1] + float angle = std::acos(dotProduct); + + // Determine rotation direction (clockwise or counterclockwise) + float crossProduct = currentX * targetY - currentY * targetX; + float stepAngle = angle * arcFraction; // Move arcFraction along the arc + if (crossProduct < 0) + stepAngle = -stepAngle; // Clockwise + + // Calculate rotation matrix components + float cos_a = std::cos(stepAngle); + float sin_a = std::sin(stepAngle); + + // Rotate current vector + float rotatedX = currentX * cos_a - currentY * sin_a; + float rotatedY = currentX * sin_a + currentY * cos_a; + + // Smoothing: blend current and target radius + float desiredDist = currentDist * 0.9f + targetDist * 0.1f; + + // Calculate the new position + return Position(center.GetPositionX() + rotatedX * desiredDist, + center.GetPositionY() + rotatedY * desiredDist, + current.GetPositionZ()); +} diff --git a/src/strategy/raids/karazhan/RaidKarazhanHelpers.h b/src/strategy/raids/karazhan/RaidKarazhanHelpers.h index bb218f45..39335de6 100644 --- a/src/strategy/raids/karazhan/RaidKarazhanHelpers.h +++ b/src/strategy/raids/karazhan/RaidKarazhanHelpers.h @@ -3,7 +3,6 @@ #include "AiObject.h" #include "Playerbots.h" -#include "MovementActions.h" enum KarazhanSpells { @@ -15,8 +14,8 @@ enum KarazhanSpells SPELL_FEAR = 6215, // Rank 3 // Shade of Aran - SPELL_FLAME_WREATH_CAST = 30004, - SPELL_FLAME_WREATH_AURA = 29946, + SPELL_FLAME_WREATH = 30004, + SPELL_AURA_FLAME_WREATH = 29946, SPELL_ARCANE_EXPLOSION = 29973, SPELL_WARLOCK_BANISH = 18647, // Rank 2 @@ -100,6 +99,8 @@ public: bool IsSafePosition (float x, float y, float z, const std::vector& hazards, float hazardRadius); std::vector GetSpawnedInfernals() const; + bool IsStraightPathSafe(const Position& start, const Position& target, const std::vector& hazards, float hazardRadius, float stepSize); + Position CalculateArcPoint(const Position& current, const Position& target, const Position& center); }; #endif diff --git a/src/strategy/raids/karazhan/RaidKarazhanMultipliers.cpp b/src/strategy/raids/karazhan/RaidKarazhanMultipliers.cpp new file mode 100644 index 00000000..4843e27b --- /dev/null +++ b/src/strategy/raids/karazhan/RaidKarazhanMultipliers.cpp @@ -0,0 +1,183 @@ +#include "RaidKarazhanMultipliers.h" +#include "RaidKarazhanActions.h" +#include "RaidKarazhanHelpers.h" +#include "AiObjectContext.h" +#include "DruidBearActions.h" +#include "DruidCatActions.h" +#include "WarriorActions.h" + +static bool IsChargeAction(Action* action) +{ + return dynamic_cast(action) || + dynamic_cast(action) || + dynamic_cast(action) || + dynamic_cast(action); +} + +float KarazhanShadeOfAranMultiplier::GetValue(Action* action) +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "shade of aran"); + if (!boss) + return 1.0f; + + if (boss && boss->HasUnitState(UNIT_STATE_CASTING) && boss->FindCurrentSpellBySpellId(SPELL_ARCANE_EXPLOSION)) + { + if (IsChargeAction(action)) + return 0.0f; + + if (dynamic_cast(action) || IsChargeAction(action)) + { + const float safeDistance = 20.0f; + if (bot->GetDistance2d(boss) >= safeDistance) + return 0.0f; + } + } + + bool flameWreathActive = boss->HasAura(SPELL_FLAME_WREATH); + + if (!flameWreathActive && bot->GetGroup()) + { + for (GroupReference* itr = bot->GetGroup()->GetFirstMember(); itr != nullptr; itr = itr->next()) + { + Player* member = itr->GetSource(); + if (member && member->HasAura(SPELL_AURA_FLAME_WREATH)) + { + flameWreathActive = true; + break; + } + } + } + + if (flameWreathActive) + { + if (dynamic_cast(action) || IsChargeAction(action)) + return 0.0f; + } + return 1.0f; +} + +float KarazhanNetherspiteBlueAndGreenBeamMultiplier::GetValue(Action* action) +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "netherspite"); + if (!boss || !boss->IsAlive()) + return 1.0f; + + RaidKarazhanHelpers karazhanHelper(botAI); + auto [redBlocker /*unused*/, greenBlocker, blueBlocker] = karazhanHelper.GetCurrentBeamBlockers(); + bool isBlocker = (bot == greenBlocker || bot == blueBlocker); + if (isBlocker) + { + Unit* bluePortal = bot->FindNearestCreature(NPC_BLUE_PORTAL, 150.0f); + Unit* greenPortal = bot->FindNearestCreature(NPC_GREEN_PORTAL, 150.0f); + + bool inBeam = false; + for (Unit* portal : {bluePortal, greenPortal}) { + if (!portal) continue; + float bx = boss->GetPositionX(), by = boss->GetPositionY(); + float px = portal->GetPositionX(), py = portal->GetPositionY(); + float dx = px - bx, dy = py - by; + float length = sqrt(dx*dx + dy*dy); + if (length == 0.0f) continue; + dx /= length; dy /= length; + float botdx = bot->GetPositionX() - bx, botdy = bot->GetPositionY() - by; + float t = (botdx * dx + botdy * dy); + float beamX = bx + dx * t, beamY = by + dy * t; + float distToBeam = sqrt(pow(bot->GetPositionX() - beamX, 2) + pow(bot->GetPositionY() - beamY, 2)); + if (distToBeam < 5.0f && t > 0.0f && t < length) { + inBeam = true; + break; + } + } + if (inBeam) + { + std::vector voidZones = karazhanHelper.GetAllVoidZones(); + bool inVoidZone = false; + for (Unit* vz : voidZones) { + if (bot->GetExactDist2d(vz) < 4.0f) + { + inVoidZone = true; + break; + } + } + if (!inVoidZone) + { + if (dynamic_cast(action) || IsChargeAction(action)) + return 0.0f; + } + } + } + return 1.0f; +} + +float KarazhanNetherspiteRedBeamMultiplier::GetValue(Action* action) +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "netherspite"); + if (!boss || !boss->IsAlive()) + return 1.0f; + + RaidKarazhanHelpers karazhanHelper(botAI); + auto [redBlocker, greenBlocker /*unused*/, blueBlocker /*unused*/] = karazhanHelper.GetCurrentBeamBlockers(); + + static std::map beamMoveTimes; + static std::map lastBeamMoveSideways; + ObjectGuid botGuid = bot->GetGUID(); + Unit* redPortal = bot->FindNearestCreature(NPC_RED_PORTAL, 150.0f); + if (bot == redBlocker && boss && redPortal) + { + Position blockingPos = karazhanHelper.GetPositionOnBeam(boss, redPortal, 18.0f); + float bx = boss->GetPositionX(); + float by = boss->GetPositionY(); + float px = redPortal->GetPositionX(); + float py = redPortal->GetPositionY(); + float dx = px - bx; + float dy = py - by; + float length = sqrt(dx*dx + dy*dy); + if (length != 0.0f) + { + dx /= length; + dy /= length; + float perpDx = -dy; + float perpDy = dx; + Position sidewaysPos(blockingPos.GetPositionX() + perpDx * 3.0f, + blockingPos.GetPositionY() + perpDy * 3.0f, + blockingPos.GetPositionZ()); + + uint32 intervalSecs = 5; + if (beamMoveTimes[botGuid] == 0) + { + beamMoveTimes[botGuid] = time(nullptr); + lastBeamMoveSideways[botGuid] = false; + } + if (time(nullptr) - beamMoveTimes[botGuid] >= intervalSecs) + { + lastBeamMoveSideways[botGuid] = !lastBeamMoveSideways[botGuid]; + beamMoveTimes[botGuid] = time(nullptr); + } + + Position targetPos = lastBeamMoveSideways[botGuid] ? sidewaysPos : blockingPos; + float distToTarget = bot->GetExactDist2d(targetPos.GetPositionX(), targetPos.GetPositionY()); + const float positionTolerance = 1.5f; + + if (distToTarget < positionTolerance) + { + if (dynamic_cast(action) || IsChargeAction(action)) + return 0.0f; + } + } + } + return 1.0f; +} + +float KarazhanPrinceMalchezaarMultiplier::GetValue(Action* action) +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "prince malchezaar"); + if (!boss) + return 1.0f; + + if (boss && bot->HasAura(SPELL_ENFEEBLE)) + { + if (IsChargeAction(action)) + return 0.0f; + } + return 1.0f; +} diff --git a/src/strategy/raids/karazhan/RaidKarazhanMultipliers.h b/src/strategy/raids/karazhan/RaidKarazhanMultipliers.h new file mode 100644 index 00000000..e2066554 --- /dev/null +++ b/src/strategy/raids/karazhan/RaidKarazhanMultipliers.h @@ -0,0 +1,34 @@ +#ifndef _PLAYERBOT_RAIDKARAZHANMULTIPLIERS_H +#define _PLAYERBOT_RAIDKARAZHANMULTIPLIERS_H + +#include "Multiplier.h" + +class KarazhanShadeOfAranMultiplier : public Multiplier +{ +public: + KarazhanShadeOfAranMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "karazhan shade of aran multiplier") {} + virtual float GetValue(Action* action); +}; + +class KarazhanNetherspiteBlueAndGreenBeamMultiplier : public Multiplier +{ +public: + KarazhanNetherspiteBlueAndGreenBeamMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "karazhan netherspite blue and green beam multiplier") {} + virtual float GetValue(Action* action); +}; + +class KarazhanNetherspiteRedBeamMultiplier : public Multiplier +{ +public: + KarazhanNetherspiteRedBeamMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "karazhan netherspite red beam multiplier") {} + virtual float GetValue(Action* action); +}; + +class KarazhanPrinceMalchezaarMultiplier : public Multiplier +{ +public: + KarazhanPrinceMalchezaarMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "karazhan prince malchezaar multiplier") {} + virtual float GetValue(Action* action); +}; + +#endif diff --git a/src/strategy/raids/karazhan/RaidKarazhanStrategy.cpp b/src/strategy/raids/karazhan/RaidKarazhanStrategy.cpp index 79544687..8e39f254 100644 --- a/src/strategy/raids/karazhan/RaidKarazhanStrategy.cpp +++ b/src/strategy/raids/karazhan/RaidKarazhanStrategy.cpp @@ -1,4 +1,5 @@ #include "RaidKarazhanStrategy.h" +#include "RaidKarazhanMultipliers.h" void RaidKarazhanStrategy::InitTriggers(std::vector& triggers) { @@ -48,7 +49,7 @@ void RaidKarazhanStrategy::InitTriggers(std::vector& triggers) triggers.push_back(new TriggerNode( "karazhan shade of aran", NextAction::array(0, - new NextAction("karazhan shade of aran flame wreath stop bot", ACTION_EMERGENCY + 7), + new NextAction("karazhan shade of aran flame wreath stop movement", ACTION_EMERGENCY + 7), new NextAction("karazhan shade of aran arcane explosion run away", ACTION_EMERGENCY + 6), new NextAction("karazhan shade of aran spread ranged", ACTION_RAID + 2), new NextAction("karazhan shade of aran mark conjured elemental", ACTION_RAID + 1), @@ -65,12 +66,15 @@ void RaidKarazhanStrategy::InitTriggers(std::vector& triggers) triggers.push_back(new TriggerNode( "karazhan prince malchezaar", NextAction::array(0, - new NextAction("karazhan prince malchezaar run away from shadow nova", ACTION_EMERGENCY + 6), - new NextAction("karazhan prince malchezaar avoid infernal", ACTION_RAID + 1), + new NextAction("karazhan prince malchezaar non tank avoid hazard", ACTION_EMERGENCY + 6), + new NextAction("karazhan prince malchezaar tank avoid hazard", ACTION_EMERGENCY + 6), nullptr))); } -void RaidKarazhanStrategy::InitMultipliers(std::vector& /*multipliers*/) +void RaidKarazhanStrategy::InitMultipliers(std::vector& multipliers) { - // No multipliers for this strategy + multipliers.push_back(new KarazhanShadeOfAranMultiplier(botAI)); + multipliers.push_back(new KarazhanNetherspiteBlueAndGreenBeamMultiplier(botAI)); + multipliers.push_back(new KarazhanNetherspiteRedBeamMultiplier(botAI)); + multipliers.push_back(new KarazhanPrinceMalchezaarMultiplier(botAI)); } diff --git a/src/strategy/raids/karazhan/RaidKarazhanStrategy.h b/src/strategy/raids/karazhan/RaidKarazhanStrategy.h index 070259b4..c03e4285 100644 --- a/src/strategy/raids/karazhan/RaidKarazhanStrategy.h +++ b/src/strategy/raids/karazhan/RaidKarazhanStrategy.h @@ -2,6 +2,7 @@ #define _PLAYERBOT_RAIDKARAZHANSTRATEGY_H_ #include "Strategy.h" +#include "Multiplier.h" class RaidKarazhanStrategy : public Strategy { @@ -10,8 +11,8 @@ public: std::string const getName() override { return "karazhan"; } - void InitTriggers(std::vector& /*triggers*/) override; - void InitMultipliers(std::vector& /*multipliers*/) override; + void InitTriggers(std::vector& triggers) override; + void InitMultipliers(std::vector& multipliers) override; }; #endif diff --git a/src/strategy/raids/karazhan/RaidKarazhanTriggerContext.h b/src/strategy/raids/karazhan/RaidKarazhanTriggerContext.h index 4451212c..0b6a29e8 100644 --- a/src/strategy/raids/karazhan/RaidKarazhanTriggerContext.h +++ b/src/strategy/raids/karazhan/RaidKarazhanTriggerContext.h @@ -1,8 +1,8 @@ #ifndef _PLAYERBOT_RAIDKARAZHANTRIGGERCONTEXT_H #define _PLAYERBOT_RAIDKARAZHANTRIGGERCONTEXT_H -#include "AiObjectContext.h" #include "RaidKarazhanTriggers.h" +#include "AiObjectContext.h" class RaidKarazhanTriggerContext : public NamedObjectContext { diff --git a/src/strategy/raids/karazhan/RaidKarazhanTriggers.cpp b/src/strategy/raids/karazhan/RaidKarazhanTriggers.cpp index 206ae531..55aa175e 100644 --- a/src/strategy/raids/karazhan/RaidKarazhanTriggers.cpp +++ b/src/strategy/raids/karazhan/RaidKarazhanTriggers.cpp @@ -1,7 +1,7 @@ -#include "Playerbots.h" #include "RaidKarazhanTriggers.h" #include "RaidKarazhanHelpers.h" #include "RaidKarazhanActions.h" +#include "Playerbots.h" bool KarazhanAttumenTheHuntsmanTrigger::IsActive() {