mirror of
https://github.com/mod-playerbots/mod-playerbots
synced 2025-11-29 15:58:20 +08:00
Update Aran, Netherspite, Prince
This commit is contained in:
@@ -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<Action>
|
||||
{
|
||||
@@ -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
|
||||
|
||||
@@ -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<ObjectGuid, time_t> 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<ObjectGuid, time_t> 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<ObjectGuid, Position> 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<Unit*> 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<Unit*> 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<float>::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<float>::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<Unit*> 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<float>::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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
#include "RaidKarazhanActions.h"
|
||||
#include "RaidKarazhanHelpers.h"
|
||||
#include "PlayerbotMgr.h"
|
||||
#include "AiObjectContext.h"
|
||||
#include "Position.h"
|
||||
#include "Spell.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
|
||||
#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<Unit*> RaidKarazhanHelpers::GetSpawnedInfernals() const
|
||||
}
|
||||
return infernals;
|
||||
}
|
||||
|
||||
bool RaidKarazhanHelpers::IsStraightPathSafe(const Position& start, const Position& target, const std::vector<Unit*>& 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());
|
||||
}
|
||||
|
||||
@@ -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<Unit*>& hazards, float hazardRadius);
|
||||
std::vector<Unit*> GetSpawnedInfernals() const;
|
||||
bool IsStraightPathSafe(const Position& start, const Position& target, const std::vector<Unit*>& hazards, float hazardRadius, float stepSize);
|
||||
Position CalculateArcPoint(const Position& current, const Position& target, const Position& center);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
183
src/strategy/raids/karazhan/RaidKarazhanMultipliers.cpp
Normal file
183
src/strategy/raids/karazhan/RaidKarazhanMultipliers.cpp
Normal file
@@ -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<CastChargeAction*>(action) ||
|
||||
dynamic_cast<CastInterceptAction*>(action) ||
|
||||
dynamic_cast<CastFeralChargeBearAction*>(action) ||
|
||||
dynamic_cast<CastFeralChargeCatAction*>(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<MovementAction*>(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<MovementAction*>(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<Unit*> voidZones = karazhanHelper.GetAllVoidZones();
|
||||
bool inVoidZone = false;
|
||||
for (Unit* vz : voidZones) {
|
||||
if (bot->GetExactDist2d(vz) < 4.0f)
|
||||
{
|
||||
inVoidZone = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!inVoidZone)
|
||||
{
|
||||
if (dynamic_cast<MovementAction*>(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<ObjectGuid, uint32> beamMoveTimes;
|
||||
static std::map<ObjectGuid, bool> 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<MovementAction*>(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;
|
||||
}
|
||||
34
src/strategy/raids/karazhan/RaidKarazhanMultipliers.h
Normal file
34
src/strategy/raids/karazhan/RaidKarazhanMultipliers.h
Normal file
@@ -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
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "RaidKarazhanStrategy.h"
|
||||
#include "RaidKarazhanMultipliers.h"
|
||||
|
||||
void RaidKarazhanStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
@@ -48,7 +49,7 @@ void RaidKarazhanStrategy::InitTriggers(std::vector<TriggerNode*>& 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<TriggerNode*>& 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<Multiplier*>& /*multipliers*/)
|
||||
void RaidKarazhanStrategy::InitMultipliers(std::vector<Multiplier*>& 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));
|
||||
}
|
||||
|
||||
@@ -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<TriggerNode*>& /*triggers*/) override;
|
||||
void InitMultipliers(std::vector<Multiplier*>& /*multipliers*/) override;
|
||||
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
|
||||
void InitMultipliers(std::vector<Multiplier*>& multipliers) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -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<Trigger>
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "Playerbots.h"
|
||||
#include "RaidKarazhanTriggers.h"
|
||||
#include "RaidKarazhanHelpers.h"
|
||||
#include "RaidKarazhanActions.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
bool KarazhanAttumenTheHuntsmanTrigger::IsActive()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user