mirror of
https://github.com/mod-playerbots/mod-playerbots.git
synced 2026-03-12 03:45:08 +00:00
Compare commits
4 Commits
hermensbas
...
026df0dabe
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
026df0dabe | ||
|
|
b31bda85ee | ||
|
|
bebac60c51 | ||
|
|
31765c77fa |
@@ -66,38 +66,35 @@ Please answer the following:
|
|||||||
|
|
||||||
## Complexity & Impact
|
## Complexity & Impact
|
||||||
|
|
||||||
- Does this change add new decision branches?
|
Does this change add new decision branches?
|
||||||
- [ ] No
|
- - [ ] No
|
||||||
- [ ] Yes (**explain below**)
|
- - [ ] Yes (**explain below**)
|
||||||
|
|
||||||
- Does this change increase per-bot or per-tick processing?
|
Does this change increase per-bot or per-tick processing?
|
||||||
- [ ] No
|
- - [ ] No
|
||||||
- [ ] Yes (**describe and justify impact**)
|
- - [ ] Yes (**describe and justify impact**)
|
||||||
|
|
||||||
- Could this logic scale poorly under load?
|
|
||||||
- [ ] No
|
|
||||||
- [ ] Yes (**explain why**)
|
|
||||||
|
|
||||||
|
Could this logic scale poorly under load?
|
||||||
|
- - [ ] No
|
||||||
|
- - [ ] Yes (**explain why**)
|
||||||
---
|
---
|
||||||
|
|
||||||
## Defaults & Configuration
|
## Defaults & Configuration
|
||||||
|
|
||||||
- Does this change modify default bot behavior?
|
Does this change modify default bot behavior?
|
||||||
- [ ] No
|
- - [ ] No
|
||||||
- [ ] Yes (**explain why**)
|
- - [ ] Yes (**explain why**)
|
||||||
|
|
||||||
If this introduces more advanced or AI-heavy logic:
|
If this introduces more advanced or AI-heavy logic:
|
||||||
|
- - [ ] Lightweight mode remains the default
|
||||||
- [ ] Lightweight mode remains the default
|
- - [ ] More complex behavior is optional and thereby configurable
|
||||||
- [ ] More complex behavior is optional and thereby configurable
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## AI Assistance
|
## AI Assistance
|
||||||
|
|
||||||
- Was AI assistance (e.g. ChatGPT or similar tools) used while working on this change?
|
Was AI assistance (e.g. ChatGPT or similar tools) used while working on this change?
|
||||||
- [ ] No
|
- - [ ] No
|
||||||
- [ ] Yes (**explain below**)
|
- - [ ] Yes (**explain below**)
|
||||||
|
|
||||||
If yes, please specify:
|
If yes, please specify:
|
||||||
|
|
||||||
@@ -114,10 +111,10 @@ about what they do and do not understand.
|
|||||||
|
|
||||||
## Final Checklist
|
## Final Checklist
|
||||||
|
|
||||||
- [ ] Stability is not compromised
|
- - [ ] Stability is not compromised
|
||||||
- [ ] Performance impact is understood, tested, and acceptable
|
- - [ ] Performance impact is understood, tested, and acceptable
|
||||||
- [ ] Added logic complexity is justified and explained
|
- - [ ] Added logic complexity is justified and explained
|
||||||
- [ ] Documentation updated if needed
|
- - [ ] Documentation updated if needed
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -990,7 +990,7 @@ AiPlayerbot.ZoneBracket.3433 = 10,22
|
|||||||
AiPlayerbot.ZoneBracket.3525 = 10,21
|
AiPlayerbot.ZoneBracket.3525 = 10,21
|
||||||
|
|
||||||
# Classic WoW - High-level zones:
|
# Classic WoW - High-level zones:
|
||||||
# Deadwind Pass (Zone ID: 10 Default Min,Max: 19,33)
|
# Duskwood (Zone ID: 10 Default Min,Max: 19,33)
|
||||||
# Wetlands (Zone ID: 11 Default Min,Max: 21,30)
|
# Wetlands (Zone ID: 11 Default Min,Max: 21,30)
|
||||||
# Redridge Mountains (Zone ID: 44 Default Min,Max: 16,28)
|
# Redridge Mountains (Zone ID: 44 Default Min,Max: 16,28)
|
||||||
# Hillsbrad Foothills (Zone ID: 267 Default Min,Max: 20,34)
|
# Hillsbrad Foothills (Zone ID: 267 Default Min,Max: 20,34)
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include "RaidGruulsLairHelpers.h"
|
#include "RaidGruulsLairHelpers.h"
|
||||||
#include "CreatureAI.h"
|
#include "CreatureAI.h"
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
|
#include "RaidBossHelpers.h"
|
||||||
#include "Unit.h"
|
#include "Unit.h"
|
||||||
|
|
||||||
using namespace GruulsLairHelpers;
|
using namespace GruulsLairHelpers;
|
||||||
@@ -12,6 +13,8 @@ using namespace GruulsLairHelpers;
|
|||||||
bool HighKingMaulgarMainTankAttackMaulgarAction::Execute(Event event)
|
bool HighKingMaulgarMainTankAttackMaulgarAction::Execute(Event event)
|
||||||
{
|
{
|
||||||
Unit* maulgar = AI_VALUE2(Unit*, "find target", "high king maulgar");
|
Unit* maulgar = AI_VALUE2(Unit*, "find target", "high king maulgar");
|
||||||
|
if (!maulgar)
|
||||||
|
return false;
|
||||||
|
|
||||||
MarkTargetWithSquare(bot, maulgar);
|
MarkTargetWithSquare(bot, maulgar);
|
||||||
SetRtiTarget(botAI, "square", maulgar);
|
SetRtiTarget(botAI, "square", maulgar);
|
||||||
@@ -21,31 +24,20 @@ bool HighKingMaulgarMainTankAttackMaulgarAction::Execute(Event event)
|
|||||||
|
|
||||||
if (maulgar->GetVictim() == bot)
|
if (maulgar->GetVictim() == bot)
|
||||||
{
|
{
|
||||||
const Location& tankPosition = GruulsLairLocations::MaulgarTankPosition;
|
const Position& position = MAULGAR_TANK_POSITION;
|
||||||
const float maxDistance = 3.0f;
|
const float maxDistance = 3.0f;
|
||||||
|
|
||||||
float distanceToTankPosition = bot->GetExactDist2d(tankPosition.x, tankPosition.y);
|
float distanceToPosition = bot->GetExactDist2d(position.GetPositionX(), position.GetPositionY());
|
||||||
|
|
||||||
if (distanceToTankPosition > maxDistance)
|
if (distanceToPosition > maxDistance)
|
||||||
{
|
{
|
||||||
float dX = tankPosition.x - bot->GetPositionX();
|
float dX = position.GetPositionX() - bot->GetPositionX();
|
||||||
float dY = tankPosition.y - bot->GetPositionY();
|
float dY = position.GetPositionY() - bot->GetPositionY();
|
||||||
float dist = sqrt(dX * dX + dY * dY);
|
float moveX = bot->GetPositionX() + (dX / distanceToPosition) * maxDistance;
|
||||||
float moveX = bot->GetPositionX() + (dX / dist) * maxDistance;
|
float moveY = bot->GetPositionY() + (dY / distanceToPosition) * maxDistance;
|
||||||
float moveY = bot->GetPositionY() + (dY / dist) * maxDistance;
|
return MoveTo(GRUULS_LAIR_MAP_ID, moveX, moveY, position.GetPositionZ(), false, false, false, false,
|
||||||
return MoveTo(bot->GetMapId(), moveX, moveY, tankPosition.z, false, false, false, false,
|
MovementPriority::MOVEMENT_COMBAT, true, true);
|
||||||
MovementPriority::MOVEMENT_COMBAT, true, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float orientation = atan2(maulgar->GetPositionY() - bot->GetPositionY(),
|
|
||||||
maulgar->GetPositionX() - bot->GetPositionX());
|
|
||||||
bot->SetFacingTo(orientation);
|
|
||||||
}
|
|
||||||
else if (!bot->IsWithinMeleeRange(maulgar))
|
|
||||||
{
|
|
||||||
return MoveTo(maulgar->GetMapId(), maulgar->GetPositionX(), maulgar->GetPositionY(),
|
|
||||||
maulgar->GetPositionZ(), false, false, false, false,
|
|
||||||
MovementPriority::MOVEMENT_COMBAT, true, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -55,6 +47,8 @@ bool HighKingMaulgarMainTankAttackMaulgarAction::Execute(Event event)
|
|||||||
bool HighKingMaulgarFirstAssistTankAttackOlmAction::Execute(Event event)
|
bool HighKingMaulgarFirstAssistTankAttackOlmAction::Execute(Event event)
|
||||||
{
|
{
|
||||||
Unit* olm = AI_VALUE2(Unit*, "find target", "olm the summoner");
|
Unit* olm = AI_VALUE2(Unit*, "find target", "olm the summoner");
|
||||||
|
if (!olm)
|
||||||
|
return false;
|
||||||
|
|
||||||
MarkTargetWithCircle(bot, olm);
|
MarkTargetWithCircle(bot, olm);
|
||||||
SetRtiTarget(botAI, "circle", olm);
|
SetRtiTarget(botAI, "circle", olm);
|
||||||
@@ -64,29 +58,22 @@ bool HighKingMaulgarFirstAssistTankAttackOlmAction::Execute(Event event)
|
|||||||
|
|
||||||
if (olm->GetVictim() == bot)
|
if (olm->GetVictim() == bot)
|
||||||
{
|
{
|
||||||
const Location& tankPosition = GruulsLairLocations::OlmTankPosition;
|
const Position& position = OLM_TANK_POSITION;
|
||||||
const float maxDistance = 3.0f;
|
const float maxDistance = 3.0f;
|
||||||
const float olmTankLeeway = 30.0f;
|
const float olmTankLeeway = 30.0f;
|
||||||
|
|
||||||
float distanceOlmToTankPosition = olm->GetExactDist2d(tankPosition.x, tankPosition.y);
|
float distanceOlmToPosition = olm->GetExactDist2d(position.GetPositionX(), position.GetPositionY());
|
||||||
|
|
||||||
if (distanceOlmToTankPosition > olmTankLeeway)
|
if (distanceOlmToPosition > olmTankLeeway)
|
||||||
{
|
{
|
||||||
float dX = tankPosition.x - bot->GetPositionX();
|
float dX = position.GetPositionX() - bot->GetPositionX();
|
||||||
float dY = tankPosition.y - bot->GetPositionY();
|
float dY = position.GetPositionY() - bot->GetPositionY();
|
||||||
float dist = sqrt(dX * dX + dY * dY);
|
float moveX = bot->GetPositionX() + (dX / distanceOlmToPosition) * maxDistance;
|
||||||
float moveX = bot->GetPositionX() + (dX / dist) * maxDistance;
|
float moveY = bot->GetPositionY() + (dY / distanceOlmToPosition) * maxDistance;
|
||||||
float moveY = bot->GetPositionY() + (dY / dist) * maxDistance;
|
return MoveTo(GRUULS_LAIR_MAP_ID, moveX, moveY, position.GetPositionZ(), false, false, false, false,
|
||||||
return MoveTo(bot->GetMapId(), moveX, moveY, tankPosition.z, false, false, false, false,
|
|
||||||
MovementPriority::MOVEMENT_COMBAT, true, false);
|
MovementPriority::MOVEMENT_COMBAT, true, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!bot->IsWithinMeleeRange(olm))
|
|
||||||
{
|
|
||||||
return MoveTo(olm->GetMapId(), olm->GetPositionX(), olm->GetPositionY(),
|
|
||||||
olm->GetPositionZ(), false, false, false, false,
|
|
||||||
MovementPriority::MOVEMENT_COMBAT, true, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -95,6 +82,8 @@ bool HighKingMaulgarFirstAssistTankAttackOlmAction::Execute(Event event)
|
|||||||
bool HighKingMaulgarSecondAssistTankAttackBlindeyeAction::Execute(Event event)
|
bool HighKingMaulgarSecondAssistTankAttackBlindeyeAction::Execute(Event event)
|
||||||
{
|
{
|
||||||
Unit* blindeye = AI_VALUE2(Unit*, "find target", "blindeye the seer");
|
Unit* blindeye = AI_VALUE2(Unit*, "find target", "blindeye the seer");
|
||||||
|
if (!blindeye)
|
||||||
|
return false;
|
||||||
|
|
||||||
MarkTargetWithStar(bot, blindeye);
|
MarkTargetWithStar(bot, blindeye);
|
||||||
SetRtiTarget(botAI, "star", blindeye);
|
SetRtiTarget(botAI, "star", blindeye);
|
||||||
@@ -104,31 +93,20 @@ bool HighKingMaulgarSecondAssistTankAttackBlindeyeAction::Execute(Event event)
|
|||||||
|
|
||||||
if (blindeye->GetVictim() == bot)
|
if (blindeye->GetVictim() == bot)
|
||||||
{
|
{
|
||||||
const Location& tankPosition = GruulsLairLocations::BlindeyeTankPosition;
|
const Position& position = BLINDEYE_TANK_POSITION;
|
||||||
const float maxDistance = 3.0f;
|
const float maxDistance = 3.0f;
|
||||||
|
|
||||||
float distanceToTankPosition = bot->GetExactDist2d(tankPosition.x, tankPosition.y);
|
float distanceToPosition = bot->GetExactDist2d(position.GetPositionX(), position.GetPositionY());
|
||||||
|
|
||||||
if (distanceToTankPosition > maxDistance)
|
if (distanceToPosition > maxDistance)
|
||||||
{
|
{
|
||||||
float dX = tankPosition.x - bot->GetPositionX();
|
float dX = position.GetPositionX() - bot->GetPositionX();
|
||||||
float dY = tankPosition.y - bot->GetPositionY();
|
float dY = position.GetPositionY() - bot->GetPositionY();
|
||||||
float dist = sqrt(dX * dX + dY * dY);
|
float moveX = bot->GetPositionX() + (dX / distanceToPosition) * maxDistance;
|
||||||
float moveX = bot->GetPositionX() + (dX / dist) * maxDistance;
|
float moveY = bot->GetPositionY() + (dY / distanceToPosition) * maxDistance;
|
||||||
float moveY = bot->GetPositionY() + (dY / dist) * maxDistance;
|
return MoveTo(GRUULS_LAIR_MAP_ID, moveX, moveY, position.GetPositionZ(), false, false, false, false,
|
||||||
return MoveTo(bot->GetMapId(), moveX, moveY, tankPosition.z, false, false, false, false,
|
|
||||||
MovementPriority::MOVEMENT_COMBAT, true, false);
|
MovementPriority::MOVEMENT_COMBAT, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
float orientation = atan2(blindeye->GetPositionY() - bot->GetPositionY(),
|
|
||||||
blindeye->GetPositionX() - bot->GetPositionX());
|
|
||||||
bot->SetFacingTo(orientation);
|
|
||||||
}
|
|
||||||
else if (!bot->IsWithinMeleeRange(blindeye))
|
|
||||||
{
|
|
||||||
return MoveTo(blindeye->GetMapId(), blindeye->GetPositionX(), blindeye->GetPositionY(),
|
|
||||||
blindeye->GetPositionZ(), false, false, false, false,
|
|
||||||
MovementPriority::MOVEMENT_COMBAT, true, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -138,6 +116,8 @@ bool HighKingMaulgarSecondAssistTankAttackBlindeyeAction::Execute(Event event)
|
|||||||
bool HighKingMaulgarMageTankAttackKroshAction::Execute(Event event)
|
bool HighKingMaulgarMageTankAttackKroshAction::Execute(Event event)
|
||||||
{
|
{
|
||||||
Unit* krosh = AI_VALUE2(Unit*, "find target", "krosh firehand");
|
Unit* krosh = AI_VALUE2(Unit*, "find target", "krosh firehand");
|
||||||
|
if (!krosh)
|
||||||
|
return false;
|
||||||
|
|
||||||
MarkTargetWithTriangle(bot, krosh);
|
MarkTargetWithTriangle(bot, krosh);
|
||||||
SetRtiTarget(botAI, "triangle", krosh);
|
SetRtiTarget(botAI, "triangle", krosh);
|
||||||
@@ -149,25 +129,22 @@ bool HighKingMaulgarMageTankAttackKroshAction::Execute(Event event)
|
|||||||
return botAI->CastSpell("fire ward", bot);
|
return botAI->CastSpell("fire ward", bot);
|
||||||
|
|
||||||
if (bot->GetTarget() != krosh->GetGUID())
|
if (bot->GetTarget() != krosh->GetGUID())
|
||||||
{
|
return Attack(krosh);
|
||||||
bot->SetSelection(krosh->GetGUID());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (krosh->GetVictim() == bot)
|
if (krosh->GetVictim() == bot)
|
||||||
{
|
{
|
||||||
const Location& tankPosition = GruulsLairLocations::KroshTankPosition;
|
const Position& position = KROSH_TANK_POSITION;
|
||||||
float distanceToKrosh = krosh->GetExactDist2d(tankPosition.x, tankPosition.y);
|
float distanceToKrosh = krosh->GetExactDist2d(position.GetPositionX(), position.GetPositionY());
|
||||||
const float minDistance = 16.0f;
|
const float minDistance = 16.0f;
|
||||||
const float maxDistance = 29.0f;
|
const float maxDistance = 29.0f;
|
||||||
const float tankPositionLeeway = 1.0f;
|
const float tankPositionLeeway = 1.0f;
|
||||||
|
|
||||||
if (distanceToKrosh > minDistance && distanceToKrosh < maxDistance)
|
if (distanceToKrosh > minDistance && distanceToKrosh < maxDistance)
|
||||||
{
|
{
|
||||||
if (!bot->IsWithinDist2d(tankPosition.x, tankPosition.y, tankPositionLeeway))
|
if (!bot->IsWithinDist2d(position.GetPositionX(), position.GetPositionY(), tankPositionLeeway))
|
||||||
{
|
{
|
||||||
return MoveTo(bot->GetMapId(), tankPosition.x, tankPosition.y, tankPosition.z, false,
|
return MoveTo(GRUULS_LAIR_MAP_ID, position.GetPositionX(), position.GetPositionY(), position.GetPositionZ(),
|
||||||
false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false);
|
false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
float orientation = atan2(krosh->GetPositionY() - bot->GetPositionY(),
|
float orientation = atan2(krosh->GetPositionY() - bot->GetPositionY(),
|
||||||
@@ -179,7 +156,7 @@ bool HighKingMaulgarMageTankAttackKroshAction::Execute(Event event)
|
|||||||
Position safePos;
|
Position safePos;
|
||||||
if (TryGetNewSafePosition(botAI, bot, safePos))
|
if (TryGetNewSafePosition(botAI, bot, safePos))
|
||||||
{
|
{
|
||||||
return MoveTo(krosh->GetMapId(), safePos.m_positionX, safePos.m_positionY, safePos.m_positionZ,
|
return MoveTo(GRUULS_LAIR_MAP_ID, safePos.GetPositionX(), safePos.GetPositionY(), safePos.GetPositionZ(),
|
||||||
false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false);
|
false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -192,20 +169,19 @@ bool HighKingMaulgarMageTankAttackKroshAction::Execute(Event event)
|
|||||||
bool HighKingMaulgarMoonkinTankAttackKigglerAction::Execute(Event event)
|
bool HighKingMaulgarMoonkinTankAttackKigglerAction::Execute(Event event)
|
||||||
{
|
{
|
||||||
Unit* kiggler = AI_VALUE2(Unit*, "find target", "kiggler the crazed");
|
Unit* kiggler = AI_VALUE2(Unit*, "find target", "kiggler the crazed");
|
||||||
|
if (!kiggler)
|
||||||
|
return false;
|
||||||
|
|
||||||
MarkTargetWithDiamond(bot, kiggler);
|
MarkTargetWithDiamond(bot, kiggler);
|
||||||
SetRtiTarget(botAI, "diamond", kiggler);
|
SetRtiTarget(botAI, "diamond", kiggler);
|
||||||
|
|
||||||
if (bot->GetTarget() != kiggler->GetGUID())
|
if (bot->GetTarget() != kiggler->GetGUID())
|
||||||
{
|
return Attack(kiggler);
|
||||||
bot->SetSelection(kiggler->GetGUID());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Position safePos;
|
Position safePos;
|
||||||
if (TryGetNewSafePosition(botAI, bot, safePos))
|
if (TryGetNewSafePosition(botAI, bot, safePos))
|
||||||
{
|
{
|
||||||
return MoveTo(kiggler->GetMapId(), safePos.m_positionX, safePos.m_positionY, safePos.m_positionZ,
|
return MoveTo(GRUULS_LAIR_MAP_ID, safePos.GetPositionX(), safePos.GetPositionY(), safePos.GetPositionZ(),
|
||||||
false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false);
|
false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,120 +192,105 @@ bool HighKingMaulgarAssignDPSPriorityAction::Execute(Event event)
|
|||||||
{
|
{
|
||||||
// Target priority 1: Blindeye
|
// Target priority 1: Blindeye
|
||||||
Unit* blindeye = AI_VALUE2(Unit*, "find target", "blindeye the seer");
|
Unit* blindeye = AI_VALUE2(Unit*, "find target", "blindeye the seer");
|
||||||
if (blindeye && blindeye->IsAlive())
|
if (blindeye)
|
||||||
{
|
{
|
||||||
Position safePos;
|
Position safePos;
|
||||||
if (TryGetNewSafePosition(botAI, bot, safePos))
|
if (TryGetNewSafePosition(botAI, bot, safePos))
|
||||||
{
|
{
|
||||||
bot->AttackStop();
|
bot->AttackStop();
|
||||||
bot->InterruptNonMeleeSpells(false);
|
bot->InterruptNonMeleeSpells(false);
|
||||||
return MoveTo(blindeye->GetMapId(), safePos.m_positionX, safePos.m_positionY, safePos.m_positionZ,
|
return MoveTo(GRUULS_LAIR_MAP_ID, safePos.GetPositionX(), safePos.GetPositionY(), safePos.GetPositionZ(),
|
||||||
false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false);
|
false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
SetRtiTarget(botAI, "star", blindeye);
|
SetRtiTarget(botAI, "star", blindeye);
|
||||||
|
|
||||||
if (bot->GetTarget() != blindeye->GetGUID())
|
if (bot->GetTarget() != blindeye->GetGUID())
|
||||||
{
|
|
||||||
bot->SetSelection(blindeye->GetGUID());
|
|
||||||
return Attack(blindeye);
|
return Attack(blindeye);
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Target priority 2: Olm
|
// Target priority 2: Olm
|
||||||
Unit* olm = AI_VALUE2(Unit*, "find target", "olm the summoner");
|
Unit* olm = AI_VALUE2(Unit*, "find target", "olm the summoner");
|
||||||
if (olm && olm->IsAlive())
|
if (olm)
|
||||||
{
|
{
|
||||||
Position safePos;
|
Position safePos;
|
||||||
if (TryGetNewSafePosition(botAI, bot, safePos))
|
if (TryGetNewSafePosition(botAI, bot, safePos))
|
||||||
{
|
{
|
||||||
bot->AttackStop();
|
bot->AttackStop();
|
||||||
bot->InterruptNonMeleeSpells(false);
|
bot->InterruptNonMeleeSpells(false);
|
||||||
return MoveTo(olm->GetMapId(), safePos.m_positionX, safePos.m_positionY, safePos.m_positionZ,
|
return MoveTo(GRUULS_LAIR_MAP_ID, safePos.GetPositionX(), safePos.GetPositionY(), safePos.GetPositionZ(),
|
||||||
false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false);
|
false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
SetRtiTarget(botAI, "circle", olm);
|
SetRtiTarget(botAI, "circle", olm);
|
||||||
|
|
||||||
if (bot->GetTarget() != olm->GetGUID())
|
if (bot->GetTarget() != olm->GetGUID())
|
||||||
{
|
|
||||||
bot->SetSelection(olm->GetGUID());
|
|
||||||
return Attack(olm);
|
return Attack(olm);
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Target priority 3a: Krosh (ranged only)
|
// Target priority 3a: Krosh (ranged only)
|
||||||
Unit* krosh = AI_VALUE2(Unit*, "find target", "krosh firehand");
|
Unit* krosh = AI_VALUE2(Unit*, "find target", "krosh firehand");
|
||||||
if (krosh && krosh->IsAlive() && botAI->IsRanged(bot))
|
if (krosh && botAI->IsRanged(bot))
|
||||||
{
|
{
|
||||||
Position safePos;
|
Position safePos;
|
||||||
if (TryGetNewSafePosition(botAI, bot, safePos))
|
if (TryGetNewSafePosition(botAI, bot, safePos))
|
||||||
{
|
{
|
||||||
bot->AttackStop();
|
bot->AttackStop();
|
||||||
bot->InterruptNonMeleeSpells(false);
|
bot->InterruptNonMeleeSpells(false);
|
||||||
return MoveTo(krosh->GetMapId(), safePos.m_positionX, safePos.m_positionY, safePos.m_positionZ,
|
return MoveTo(GRUULS_LAIR_MAP_ID, safePos.GetPositionX(), safePos.GetPositionY(), safePos.GetPositionZ(),
|
||||||
false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false);
|
false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
SetRtiTarget(botAI, "triangle", krosh);
|
SetRtiTarget(botAI, "triangle", krosh);
|
||||||
|
|
||||||
if (bot->GetTarget() != krosh->GetGUID())
|
if (bot->GetTarget() != krosh->GetGUID())
|
||||||
{
|
|
||||||
bot->SetSelection(krosh->GetGUID());
|
|
||||||
return Attack(krosh);
|
return Attack(krosh);
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Target priority 3b: Kiggler
|
// Target priority 3b: Kiggler
|
||||||
Unit* kiggler = AI_VALUE2(Unit*, "find target", "kiggler the crazed");
|
Unit* kiggler = AI_VALUE2(Unit*, "find target", "kiggler the crazed");
|
||||||
if (kiggler && kiggler->IsAlive())
|
if (kiggler)
|
||||||
{
|
{
|
||||||
Position safePos;
|
Position safePos;
|
||||||
if (TryGetNewSafePosition(botAI, bot, safePos))
|
if (TryGetNewSafePosition(botAI, bot, safePos))
|
||||||
{
|
{
|
||||||
bot->AttackStop();
|
bot->AttackStop();
|
||||||
bot->InterruptNonMeleeSpells(false);
|
bot->InterruptNonMeleeSpells(false);
|
||||||
return MoveTo(kiggler->GetMapId(), safePos.m_positionX, safePos.m_positionY, safePos.m_positionZ,
|
return MoveTo(GRUULS_LAIR_MAP_ID, safePos.GetPositionX(), safePos.GetPositionY(), safePos.GetPositionZ(),
|
||||||
false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false);
|
false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
SetRtiTarget(botAI, "diamond", kiggler);
|
SetRtiTarget(botAI, "diamond", kiggler);
|
||||||
|
|
||||||
if (bot->GetTarget() != kiggler->GetGUID())
|
if (bot->GetTarget() != kiggler->GetGUID())
|
||||||
{
|
|
||||||
bot->SetSelection(kiggler->GetGUID());
|
|
||||||
return Attack(kiggler);
|
return Attack(kiggler);
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Target priority 4: Maulgar
|
// Target priority 4: Maulgar
|
||||||
Unit* maulgar = AI_VALUE2(Unit*, "find target", "high king maulgar");
|
Unit* maulgar = AI_VALUE2(Unit*, "find target", "high king maulgar");
|
||||||
if (maulgar && maulgar->IsAlive())
|
if (maulgar)
|
||||||
{
|
{
|
||||||
Position safePos;
|
Position safePos;
|
||||||
if (TryGetNewSafePosition(botAI, bot, safePos))
|
if (TryGetNewSafePosition(botAI, bot, safePos))
|
||||||
{
|
{
|
||||||
bot->AttackStop();
|
bot->AttackStop();
|
||||||
bot->InterruptNonMeleeSpells(false);
|
bot->InterruptNonMeleeSpells(false);
|
||||||
return MoveTo(maulgar->GetMapId(), safePos.m_positionX, safePos.m_positionY, safePos.m_positionZ,
|
return MoveTo(GRUULS_LAIR_MAP_ID, safePos.GetPositionX(), safePos.GetPositionY(), safePos.GetPositionZ(),
|
||||||
false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false);
|
false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
SetRtiTarget(botAI, "square", maulgar);
|
SetRtiTarget(botAI, "square", maulgar);
|
||||||
|
|
||||||
if (bot->GetTarget() != maulgar->GetGUID())
|
if (bot->GetTarget() != maulgar->GetGUID())
|
||||||
{
|
|
||||||
bot->SetSelection(maulgar->GetGUID());
|
|
||||||
return Attack(maulgar);
|
return Attack(maulgar);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -338,22 +299,22 @@ bool HighKingMaulgarAssignDPSPriorityAction::Execute(Event event)
|
|||||||
// Avoid Whirlwind and Blast Wave and generally try to stay near the center of the room
|
// Avoid Whirlwind and Blast Wave and generally try to stay near the center of the room
|
||||||
bool HighKingMaulgarHealerFindSafePositionAction::Execute(Event event)
|
bool HighKingMaulgarHealerFindSafePositionAction::Execute(Event event)
|
||||||
{
|
{
|
||||||
const Location& fightCenter = GruulsLairLocations::MaulgarRoomCenter;
|
const Position& center = MAULGAR_ROOM_CENTER;
|
||||||
const float maxDistanceFromFight = 50.0f;
|
const float maxDistanceFromCenter = 50.0f;
|
||||||
float distToFight = bot->GetExactDist2d(fightCenter.x, fightCenter.y);
|
float distToCenter = bot->GetExactDist2d(center.GetPositionX(), center.GetPositionY());
|
||||||
|
|
||||||
if (distToFight > maxDistanceFromFight)
|
if (distToCenter > maxDistanceFromCenter)
|
||||||
{
|
{
|
||||||
float angle = atan2(bot->GetPositionY() - fightCenter.y, bot->GetPositionX() - fightCenter.x);
|
float angle = atan2(bot->GetPositionY() - center.GetPositionY(), bot->GetPositionX() - center.GetPositionX());
|
||||||
float destX = fightCenter.x + 40.0f * cos(angle);
|
float destX = center.GetPositionX() + 40.0f * cos(angle);
|
||||||
float destY = fightCenter.y + 40.0f * sin(angle);
|
float destY = center.GetPositionY() + 40.0f * sin(angle);
|
||||||
float destZ = fightCenter.z;
|
float destZ = center.GetPositionZ();
|
||||||
|
|
||||||
if (!bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bot->GetPositionX(), bot->GetPositionY(),
|
if (!bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bot->GetPositionX(), bot->GetPositionY(),
|
||||||
bot->GetPositionZ(), destX, destY, destZ))
|
bot->GetPositionZ(), destX, destY, destZ))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return MoveTo(bot->GetMapId(), destX, destY, destZ, false, false, false, false,
|
return MoveTo(GRUULS_LAIR_MAP_ID, destX, destY, destZ, false, false, false, false,
|
||||||
MovementPriority::MOVEMENT_COMBAT, true, false);
|
MovementPriority::MOVEMENT_COMBAT, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -362,7 +323,7 @@ bool HighKingMaulgarHealerFindSafePositionAction::Execute(Event event)
|
|||||||
{
|
{
|
||||||
bot->AttackStop();
|
bot->AttackStop();
|
||||||
bot->InterruptNonMeleeSpells(false);
|
bot->InterruptNonMeleeSpells(false);
|
||||||
return MoveTo(bot->GetMapId(), safePos.m_positionX, safePos.m_positionY, safePos.m_positionZ,
|
return MoveTo(GRUULS_LAIR_MAP_ID, safePos.GetPositionX(), safePos.GetPositionY(), safePos.GetPositionZ(),
|
||||||
false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false);
|
false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -373,6 +334,8 @@ bool HighKingMaulgarHealerFindSafePositionAction::Execute(Event event)
|
|||||||
bool HighKingMaulgarRunAwayFromWhirlwindAction::Execute(Event event)
|
bool HighKingMaulgarRunAwayFromWhirlwindAction::Execute(Event event)
|
||||||
{
|
{
|
||||||
Unit* maulgar = AI_VALUE2(Unit*, "find target", "high king maulgar");
|
Unit* maulgar = AI_VALUE2(Unit*, "find target", "high king maulgar");
|
||||||
|
if (!maulgar)
|
||||||
|
return false;
|
||||||
|
|
||||||
const float safeDistance = 10.0f;
|
const float safeDistance = 10.0f;
|
||||||
float distance = bot->GetExactDist2d(maulgar);
|
float distance = bot->GetExactDist2d(maulgar);
|
||||||
@@ -395,7 +358,7 @@ bool HighKingMaulgarRunAwayFromWhirlwindAction::Execute(Event event)
|
|||||||
{
|
{
|
||||||
bot->AttackStop();
|
bot->AttackStop();
|
||||||
bot->InterruptNonMeleeSpells(true);
|
bot->InterruptNonMeleeSpells(true);
|
||||||
return MoveTo(maulgar->GetMapId(), destX, destY, destZ, false, false, false, false,
|
return MoveTo(GRUULS_LAIR_MAP_ID, destX, destY, destZ, false, false, false, false,
|
||||||
MovementPriority::MOVEMENT_COMBAT, true, false);
|
MovementPriority::MOVEMENT_COMBAT, true, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -439,7 +402,7 @@ bool HighKingMaulgarBanishFelstalkerAction::Execute(Event event)
|
|||||||
if (warlockIndex >= 0 && warlockIndex < felStalkers.size())
|
if (warlockIndex >= 0 && warlockIndex < felStalkers.size())
|
||||||
{
|
{
|
||||||
Unit* assignedFelStalker = felStalkers[warlockIndex];
|
Unit* assignedFelStalker = felStalkers[warlockIndex];
|
||||||
if (!assignedFelStalker->HasAura(SPELL_BANISH) && botAI->CanCastSpell(SPELL_BANISH, assignedFelStalker, true))
|
if (!botAI->HasAura("banish", assignedFelStalker) && botAI->CanCastSpell("banish", assignedFelStalker))
|
||||||
return botAI->CastSpell("banish", assignedFelStalker);
|
return botAI->CastSpell("banish", assignedFelStalker);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -528,40 +491,33 @@ bool HighKingMaulgarMisdirectOlmAndBlindeyeAction::Execute(Event event)
|
|||||||
// Gruul the Dragonkiller Actions
|
// Gruul the Dragonkiller Actions
|
||||||
|
|
||||||
// Position in center of the room
|
// Position in center of the room
|
||||||
bool GruulTheDragonkillerMainTankPositionBossAction::Execute(Event event)
|
bool GruulTheDragonkillerTanksPositionBossAction::Execute(Event event)
|
||||||
{
|
{
|
||||||
Unit* gruul = AI_VALUE2(Unit*, "find target", "gruul the dragonkiller");
|
Unit* gruul = AI_VALUE2(Unit*, "find target", "gruul the dragonkiller");
|
||||||
|
if (!gruul)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (bot->GetVictim() != gruul)
|
if (bot->GetVictim() != gruul)
|
||||||
return Attack(gruul);
|
return Attack(gruul);
|
||||||
|
|
||||||
if (gruul->GetVictim() == bot)
|
if (gruul->GetVictim() == bot)
|
||||||
{
|
{
|
||||||
const Location& tankPosition = GruulsLairLocations::GruulTankPosition;
|
const Position& position = GRUUL_TANK_POSITION;
|
||||||
const float maxDistance = 3.0f;
|
const float maxDistance = 5.0f;
|
||||||
|
|
||||||
float dX = tankPosition.x - bot->GetPositionX();
|
float dX = position.GetPositionX() - bot->GetPositionX();
|
||||||
float dY = tankPosition.y - bot->GetPositionY();
|
float dY = position.GetPositionY() - bot->GetPositionY();
|
||||||
float distanceToTankPosition = bot->GetExactDist2d(tankPosition.x, tankPosition.y);
|
float distanceToTankPosition = bot->GetExactDist2d(position.GetPositionX(), position.GetPositionY());
|
||||||
|
|
||||||
if (distanceToTankPosition > maxDistance)
|
if (distanceToTankPosition > maxDistance)
|
||||||
{
|
{
|
||||||
float step = std::min(maxDistance, distanceToTankPosition);
|
float step = std::min(maxDistance, distanceToTankPosition);
|
||||||
float moveX = bot->GetPositionX() + (dX / distanceToTankPosition) * maxDistance;
|
float moveX = bot->GetPositionX() + (dX / distanceToTankPosition) * maxDistance;
|
||||||
float moveY = bot->GetPositionY() + (dY / distanceToTankPosition) * maxDistance;
|
float moveY = bot->GetPositionY() + (dY / distanceToTankPosition) * maxDistance;
|
||||||
const float moveZ = tankPosition.z;
|
const float moveZ = position.GetPositionZ();
|
||||||
return MoveTo(bot->GetMapId(), moveX, moveY, moveZ, false, false, false, false,
|
return MoveTo(GRUULS_LAIR_MAP_ID, moveX, moveY, moveZ, false, false, false, false,
|
||||||
MovementPriority::MOVEMENT_COMBAT, true, false);
|
MovementPriority::MOVEMENT_COMBAT, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
float orientation = atan2(gruul->GetPositionY() - bot->GetPositionY(),
|
|
||||||
gruul->GetPositionX() - bot->GetPositionX());
|
|
||||||
bot->SetFacingTo(orientation);
|
|
||||||
}
|
|
||||||
else if (!bot->IsWithinMeleeRange(gruul))
|
|
||||||
{
|
|
||||||
return MoveTo(gruul->GetMapId(), gruul->GetPositionX(), gruul->GetPositionY(), gruul->GetPositionZ(),
|
|
||||||
false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -579,16 +535,16 @@ bool GruulTheDragonkillerSpreadRangedAction::Execute(Event event)
|
|||||||
static std::unordered_map<ObjectGuid, bool> hasReachedInitialPosition;
|
static std::unordered_map<ObjectGuid, bool> hasReachedInitialPosition;
|
||||||
|
|
||||||
Unit* gruul = AI_VALUE2(Unit*, "find target", "gruul the dragonkiller");
|
Unit* gruul = AI_VALUE2(Unit*, "find target", "gruul the dragonkiller");
|
||||||
if (gruul && gruul->IsAlive() && gruul->GetHealth() == gruul->GetMaxHealth())
|
if (gruul && gruul->GetHealth() == gruul->GetMaxHealth())
|
||||||
{
|
{
|
||||||
initialPositions.clear();
|
initialPositions.erase(bot->GetGUID());
|
||||||
hasReachedInitialPosition.clear();
|
hasReachedInitialPosition.erase(bot->GetGUID());
|
||||||
}
|
}
|
||||||
|
|
||||||
const Location& tankPosition = GruulsLairLocations::GruulTankPosition;
|
const Position& position = GRUUL_TANK_POSITION;
|
||||||
const float centerX = tankPosition.x;
|
const float centerX = position.GetPositionX();
|
||||||
const float centerY = tankPosition.y;
|
const float centerY = position.GetPositionY();
|
||||||
float centerZ = bot->GetPositionZ();
|
const float centerZ = position.GetPositionZ();
|
||||||
const float minRadius = 25.0f;
|
const float minRadius = 25.0f;
|
||||||
const float maxRadius = 40.0f;
|
const float maxRadius = 40.0f;
|
||||||
|
|
||||||
@@ -642,7 +598,7 @@ bool GruulTheDragonkillerSpreadRangedAction::Execute(Event event)
|
|||||||
bot->GetPositionY(), bot->GetPositionZ(), destX, destY, destZ))
|
bot->GetPositionY(), bot->GetPositionZ(), destX, destY, destZ))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return MoveTo(bot->GetMapId(), destX, destY, destZ, false, false, false, false,
|
return MoveTo(GRUULS_LAIR_MAP_ID, destX, destY, destZ, false, false, false, false,
|
||||||
MovementPriority::MOVEMENT_COMBAT, true, false);
|
MovementPriority::MOVEMENT_COMBAT, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -85,10 +85,10 @@ public:
|
|||||||
bool Execute(Event event) override;
|
bool Execute(Event event) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class GruulTheDragonkillerMainTankPositionBossAction : public AttackAction
|
class GruulTheDragonkillerTanksPositionBossAction : public AttackAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
GruulTheDragonkillerMainTankPositionBossAction(PlayerbotAI* botAI, std::string const name = "gruul the dragonkiller main tank position boss") : AttackAction(botAI, name) {};
|
GruulTheDragonkillerTanksPositionBossAction(PlayerbotAI* botAI, std::string const name = "gruul the dragonkiller tanks position boss") : AttackAction(botAI, name) {};
|
||||||
|
|
||||||
bool Execute(Event event) override;
|
bool Execute(Event event) override;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -8,18 +8,11 @@
|
|||||||
#include "HunterActions.h"
|
#include "HunterActions.h"
|
||||||
#include "MageActions.h"
|
#include "MageActions.h"
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
|
#include "ReachTargetActions.h"
|
||||||
#include "WarriorActions.h"
|
#include "WarriorActions.h"
|
||||||
|
|
||||||
using namespace GruulsLairHelpers;
|
using namespace GruulsLairHelpers;
|
||||||
|
|
||||||
static bool IsChargeAction(Action* action)
|
|
||||||
{
|
|
||||||
return dynamic_cast<CastChargeAction*>(action) ||
|
|
||||||
dynamic_cast<CastInterceptAction*>(action) ||
|
|
||||||
dynamic_cast<CastFeralChargeBearAction*>(action) ||
|
|
||||||
dynamic_cast<CastFeralChargeCatAction*>(action);
|
|
||||||
}
|
|
||||||
|
|
||||||
float HighKingMaulgarDisableTankAssistMultiplier::GetValue(Action* action)
|
float HighKingMaulgarDisableTankAssistMultiplier::GetValue(Action* action)
|
||||||
{
|
{
|
||||||
if (IsAnyOgreBossAlive(botAI) && dynamic_cast<TankAssistAction*>(action))
|
if (IsAnyOgreBossAlive(botAI) && dynamic_cast<TankAssistAction*>(action))
|
||||||
@@ -38,12 +31,10 @@ float HighKingMaulgarAvoidWhirlwindMultiplier::GetValue(Action* action)
|
|||||||
Unit* blindeye = AI_VALUE2(Unit*, "find target", "blindeye the seer");
|
Unit* blindeye = AI_VALUE2(Unit*, "find target", "blindeye the seer");
|
||||||
|
|
||||||
if (maulgar && maulgar->HasAura(SPELL_WHIRLWIND) &&
|
if (maulgar && maulgar->HasAura(SPELL_WHIRLWIND) &&
|
||||||
(!kiggler || !kiggler->IsAlive()) &&
|
!kiggler && !krosh && !olm && !blindeye)
|
||||||
(!krosh || !krosh->IsAlive()) &&
|
|
||||||
(!olm || !olm->IsAlive()) &&
|
|
||||||
(!blindeye || !blindeye->IsAlive()))
|
|
||||||
{
|
{
|
||||||
if (IsChargeAction(action) || (dynamic_cast<MovementAction*>(action) &&
|
if (dynamic_cast<CastReachTargetSpellAction*>(action) ||
|
||||||
|
(dynamic_cast<MovementAction*>(action) &&
|
||||||
!dynamic_cast<HighKingMaulgarRunAwayFromWhirlwindAction*>(action)))
|
!dynamic_cast<HighKingMaulgarRunAwayFromWhirlwindAction*>(action)))
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
@@ -57,7 +48,8 @@ float HighKingMaulgarDisableArcaneShotOnKroshMultiplier::GetValue(Action* action
|
|||||||
Unit* krosh = AI_VALUE2(Unit*, "find target", "krosh firehand");
|
Unit* krosh = AI_VALUE2(Unit*, "find target", "krosh firehand");
|
||||||
Unit* target = AI_VALUE(Unit*, "current target");
|
Unit* target = AI_VALUE(Unit*, "current target");
|
||||||
|
|
||||||
if (krosh && target && target->GetGUID() == krosh->GetGUID() && dynamic_cast<CastArcaneShotAction*>(action))
|
if (krosh && target && target->GetGUID() == krosh->GetGUID() &&
|
||||||
|
dynamic_cast<CastArcaneShotAction*>(action))
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
|
|
||||||
return 1.0f;
|
return 1.0f;
|
||||||
@@ -101,8 +93,9 @@ float GruulTheDragonkillerGroundSlamMultiplier::GetValue(Action* action)
|
|||||||
if (bot->HasAura(SPELL_GROUND_SLAM_1) ||
|
if (bot->HasAura(SPELL_GROUND_SLAM_1) ||
|
||||||
bot->HasAura(SPELL_GROUND_SLAM_2))
|
bot->HasAura(SPELL_GROUND_SLAM_2))
|
||||||
{
|
{
|
||||||
if ((dynamic_cast<MovementAction*>(action) && !dynamic_cast<GruulTheDragonkillerShatterSpreadAction*>(action)) ||
|
if ((dynamic_cast<MovementAction*>(action) &&
|
||||||
IsChargeAction(action))
|
!dynamic_cast<GruulTheDragonkillerShatterSpreadAction*>(action)) ||
|
||||||
|
dynamic_cast<CastReachTargetSpellAction*>(action))
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ public:
|
|||||||
creators["high king maulgar misdirect olm and blindeye"] = &RaidGruulsLairActionContext::high_king_maulgar_misdirect_olm_and_blindeye;
|
creators["high king maulgar misdirect olm and blindeye"] = &RaidGruulsLairActionContext::high_king_maulgar_misdirect_olm_and_blindeye;
|
||||||
|
|
||||||
// Gruul the Dragonkiller
|
// Gruul the Dragonkiller
|
||||||
creators["gruul the dragonkiller main tank position boss"] = &RaidGruulsLairActionContext::gruul_the_dragonkiller_main_tank_position_boss;
|
creators["gruul the dragonkiller tanks position boss"] = &RaidGruulsLairActionContext::gruul_the_dragonkiller_tanks_position_boss;
|
||||||
creators["gruul the dragonkiller spread ranged"] = &RaidGruulsLairActionContext::gruul_the_dragonkiller_spread_ranged;
|
creators["gruul the dragonkiller spread ranged"] = &RaidGruulsLairActionContext::gruul_the_dragonkiller_spread_ranged;
|
||||||
creators["gruul the dragonkiller shatter spread"] = &RaidGruulsLairActionContext::gruul_the_dragonkiller_shatter_spread;
|
creators["gruul the dragonkiller shatter spread"] = &RaidGruulsLairActionContext::gruul_the_dragonkiller_shatter_spread;
|
||||||
}
|
}
|
||||||
@@ -41,7 +41,7 @@ private:
|
|||||||
static Action* high_king_maulgar_misdirect_olm_and_blindeye(PlayerbotAI* botAI) { return new HighKingMaulgarMisdirectOlmAndBlindeyeAction(botAI); }
|
static Action* high_king_maulgar_misdirect_olm_and_blindeye(PlayerbotAI* botAI) { return new HighKingMaulgarMisdirectOlmAndBlindeyeAction(botAI); }
|
||||||
|
|
||||||
// Gruul the Dragonkiller
|
// Gruul the Dragonkiller
|
||||||
static Action* gruul_the_dragonkiller_main_tank_position_boss(PlayerbotAI* botAI) { return new GruulTheDragonkillerMainTankPositionBossAction(botAI); }
|
static Action* gruul_the_dragonkiller_tanks_position_boss(PlayerbotAI* botAI) { return new GruulTheDragonkillerTanksPositionBossAction(botAI); }
|
||||||
static Action* gruul_the_dragonkiller_spread_ranged(PlayerbotAI* botAI) { return new GruulTheDragonkillerSpreadRangedAction(botAI); }
|
static Action* gruul_the_dragonkiller_spread_ranged(PlayerbotAI* botAI) { return new GruulTheDragonkillerSpreadRangedAction(botAI); }
|
||||||
static Action* gruul_the_dragonkiller_shatter_spread(PlayerbotAI* botAI) { return new GruulTheDragonkillerShatterSpreadAction(botAI); }
|
static Action* gruul_the_dragonkiller_shatter_spread(PlayerbotAI* botAI) { return new GruulTheDragonkillerShatterSpreadAction(botAI); }
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ public:
|
|||||||
creators["high king maulgar pulling olm and blindeye"] = &RaidGruulsLairTriggerContext::high_king_maulgar_pulling_olm_and_blindeye;
|
creators["high king maulgar pulling olm and blindeye"] = &RaidGruulsLairTriggerContext::high_king_maulgar_pulling_olm_and_blindeye;
|
||||||
|
|
||||||
// Gruul the Dragonkiller
|
// Gruul the Dragonkiller
|
||||||
creators["gruul the dragonkiller boss engaged by main tank"] = &RaidGruulsLairTriggerContext::gruul_the_dragonkiller_boss_engaged_by_main_tank;
|
creators["gruul the dragonkiller boss engaged by tanks"] = &RaidGruulsLairTriggerContext::gruul_the_dragonkiller_boss_engaged_by_tanks;
|
||||||
creators["gruul the dragonkiller boss engaged by range"] = &RaidGruulsLairTriggerContext::gruul_the_dragonkiller_boss_engaged_by_range;
|
creators["gruul the dragonkiller boss engaged by ranged"] = &RaidGruulsLairTriggerContext::gruul_the_dragonkiller_boss_engaged_by_ranged;
|
||||||
creators["gruul the dragonkiller incoming shatter"] = &RaidGruulsLairTriggerContext::gruul_the_dragonkiller_incoming_shatter;
|
creators["gruul the dragonkiller incoming shatter"] = &RaidGruulsLairTriggerContext::gruul_the_dragonkiller_incoming_shatter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,8 +41,8 @@ private:
|
|||||||
static Trigger* high_king_maulgar_pulling_olm_and_blindeye(PlayerbotAI* botAI) { return new HighKingMaulgarPullingOlmAndBlindeyeTrigger(botAI); }
|
static Trigger* high_king_maulgar_pulling_olm_and_blindeye(PlayerbotAI* botAI) { return new HighKingMaulgarPullingOlmAndBlindeyeTrigger(botAI); }
|
||||||
|
|
||||||
// Gruul the Dragonkiller
|
// Gruul the Dragonkiller
|
||||||
static Trigger* gruul_the_dragonkiller_boss_engaged_by_main_tank(PlayerbotAI* botAI) { return new GruulTheDragonkillerBossEngagedByMainTankTrigger(botAI); }
|
static Trigger* gruul_the_dragonkiller_boss_engaged_by_tanks(PlayerbotAI* botAI) { return new GruulTheDragonkillerBossEngagedByTanksTrigger(botAI); }
|
||||||
static Trigger* gruul_the_dragonkiller_boss_engaged_by_range(PlayerbotAI* botAI) { return new GruulTheDragonkillerBossEngagedByRangeTrigger(botAI); }
|
static Trigger* gruul_the_dragonkiller_boss_engaged_by_ranged(PlayerbotAI* botAI) { return new GruulTheDragonkillerBossEngagedByRangedTrigger(botAI); }
|
||||||
static Trigger* gruul_the_dragonkiller_incoming_shatter(PlayerbotAI* botAI) { return new GruulTheDragonkillerIncomingShatterTrigger(botAI); }
|
static Trigger* gruul_the_dragonkiller_incoming_shatter(PlayerbotAI* botAI) { return new GruulTheDragonkillerIncomingShatterTrigger(botAI); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -35,10 +35,10 @@ void RaidGruulsLairStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
NextAction("high king maulgar misdirect olm and blindeye", ACTION_RAID + 2) }));
|
NextAction("high king maulgar misdirect olm and blindeye", ACTION_RAID + 2) }));
|
||||||
|
|
||||||
// Gruul the Dragonkiller
|
// Gruul the Dragonkiller
|
||||||
triggers.push_back(new TriggerNode("gruul the dragonkiller boss engaged by main tank", {
|
triggers.push_back(new TriggerNode("gruul the dragonkiller boss engaged by tanks", {
|
||||||
NextAction("gruul the dragonkiller main tank position boss", ACTION_RAID + 1) }));
|
NextAction("gruul the dragonkiller tanks position boss", ACTION_RAID + 1) }));
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("gruul the dragonkiller boss engaged by range", {
|
triggers.push_back(new TriggerNode("gruul the dragonkiller boss engaged by ranged", {
|
||||||
NextAction("gruul the dragonkiller spread ranged", ACTION_RAID + 1) }));
|
NextAction("gruul the dragonkiller spread ranged", ACTION_RAID + 1) }));
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("gruul the dragonkiller incoming shatter", {
|
triggers.push_back(new TriggerNode("gruul the dragonkiller incoming shatter", {
|
||||||
|
|||||||
@@ -10,35 +10,35 @@ bool HighKingMaulgarIsMainTankTrigger::IsActive()
|
|||||||
{
|
{
|
||||||
Unit* maulgar = AI_VALUE2(Unit*, "find target", "high king maulgar");
|
Unit* maulgar = AI_VALUE2(Unit*, "find target", "high king maulgar");
|
||||||
|
|
||||||
return botAI->IsMainTank(bot) && maulgar && maulgar->IsAlive();
|
return botAI->IsMainTank(bot) && maulgar;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HighKingMaulgarIsFirstAssistTankTrigger::IsActive()
|
bool HighKingMaulgarIsFirstAssistTankTrigger::IsActive()
|
||||||
{
|
{
|
||||||
Unit* olm = AI_VALUE2(Unit*, "find target", "olm the summoner");
|
Unit* olm = AI_VALUE2(Unit*, "find target", "olm the summoner");
|
||||||
|
|
||||||
return botAI->IsAssistTankOfIndex(bot, 0) && olm && olm->IsAlive();
|
return botAI->IsAssistTankOfIndex(bot, 0, false) && olm;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HighKingMaulgarIsSecondAssistTankTrigger::IsActive()
|
bool HighKingMaulgarIsSecondAssistTankTrigger::IsActive()
|
||||||
{
|
{
|
||||||
Unit* blindeye = AI_VALUE2(Unit*, "find target", "blindeye the seer");
|
Unit* blindeye = AI_VALUE2(Unit*, "find target", "blindeye the seer");
|
||||||
|
|
||||||
return botAI->IsAssistTankOfIndex(bot, 1) && blindeye && blindeye->IsAlive();
|
return botAI->IsAssistTankOfIndex(bot, 1, false) && blindeye;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HighKingMaulgarIsMageTankTrigger::IsActive()
|
bool HighKingMaulgarIsMageTankTrigger::IsActive()
|
||||||
{
|
{
|
||||||
Unit* krosh = AI_VALUE2(Unit*, "find target", "krosh firehand");
|
Unit* krosh = AI_VALUE2(Unit*, "find target", "krosh firehand");
|
||||||
|
|
||||||
return IsKroshMageTank(botAI, bot) && krosh && krosh->IsAlive();
|
return IsKroshMageTank(botAI, bot) && krosh;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HighKingMaulgarIsMoonkinTankTrigger::IsActive()
|
bool HighKingMaulgarIsMoonkinTankTrigger::IsActive()
|
||||||
{
|
{
|
||||||
Unit* kiggler = AI_VALUE2(Unit*, "find target", "kiggler the crazed");
|
Unit* kiggler = AI_VALUE2(Unit*, "find target", "kiggler the crazed");
|
||||||
|
|
||||||
return IsKigglerMoonkinTank(botAI, bot) && kiggler && kiggler->IsAlive();
|
return IsKigglerMoonkinTank(botAI, bot) && kiggler;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HighKingMaulgarDeterminingKillOrderTrigger::IsActive()
|
bool HighKingMaulgarDeterminingKillOrderTrigger::IsActive()
|
||||||
@@ -50,11 +50,11 @@ bool HighKingMaulgarDeterminingKillOrderTrigger::IsActive()
|
|||||||
Unit* krosh = AI_VALUE2(Unit*, "find target", "krosh firehand");
|
Unit* krosh = AI_VALUE2(Unit*, "find target", "krosh firehand");
|
||||||
|
|
||||||
return (botAI->IsDps(bot) || botAI->IsTank(bot)) &&
|
return (botAI->IsDps(bot) || botAI->IsTank(bot)) &&
|
||||||
!(botAI->IsMainTank(bot) && maulgar && maulgar->IsAlive()) &&
|
!(botAI->IsMainTank(bot) && maulgar) &&
|
||||||
!(botAI->IsAssistTankOfIndex(bot, 0) && olm && olm->IsAlive()) &&
|
!(botAI->IsAssistTankOfIndex(bot, 0, false) && olm) &&
|
||||||
!(botAI->IsAssistTankOfIndex(bot, 1) && blindeye && blindeye->IsAlive()) &&
|
!(botAI->IsAssistTankOfIndex(bot, 1, false) && blindeye) &&
|
||||||
!(IsKroshMageTank(botAI, bot) && krosh && krosh->IsAlive()) &&
|
!(IsKroshMageTank(botAI, bot) && krosh) &&
|
||||||
!(IsKigglerMoonkinTank(botAI, bot) && kiggler && kiggler->IsAlive());
|
!(IsKigglerMoonkinTank(botAI, bot) && kiggler);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HighKingMaulgarHealerInDangerTrigger::IsActive()
|
bool HighKingMaulgarHealerInDangerTrigger::IsActive()
|
||||||
@@ -66,7 +66,7 @@ bool HighKingMaulgarBossChannelingWhirlwindTrigger::IsActive()
|
|||||||
{
|
{
|
||||||
Unit* maulgar = AI_VALUE2(Unit*, "find target", "high king maulgar");
|
Unit* maulgar = AI_VALUE2(Unit*, "find target", "high king maulgar");
|
||||||
|
|
||||||
return maulgar && maulgar->IsAlive() && maulgar->HasAura(SPELL_WHIRLWIND) &&
|
return maulgar && maulgar->HasAura(SPELL_WHIRLWIND) &&
|
||||||
!botAI->IsMainTank(bot);
|
!botAI->IsMainTank(bot);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,7 +74,7 @@ bool HighKingMaulgarWildFelstalkerSpawnedTrigger::IsActive()
|
|||||||
{
|
{
|
||||||
Unit* felStalker = AI_VALUE2(Unit*, "find target", "wild fel stalker");
|
Unit* felStalker = AI_VALUE2(Unit*, "find target", "wild fel stalker");
|
||||||
|
|
||||||
return felStalker && felStalker->IsAlive() && bot->getClass() == CLASS_WARLOCK;
|
return felStalker && bot->getClass() == CLASS_WARLOCK;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HighKingMaulgarPullingOlmAndBlindeyeTrigger::IsActive()
|
bool HighKingMaulgarPullingOlmAndBlindeyeTrigger::IsActive()
|
||||||
@@ -120,12 +120,12 @@ bool HighKingMaulgarPullingOlmAndBlindeyeTrigger::IsActive()
|
|||||||
switch (hunterIndex)
|
switch (hunterIndex)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
return olm && olm->IsAlive() && olm->GetHealthPct() > 98.0f &&
|
return olm && olm->GetHealthPct() > 98.0f &&
|
||||||
olmTank && olmTank->IsAlive() && botAI->CanCastSpell("misdirection", olmTank);
|
olmTank && botAI->CanCastSpell("misdirection", olmTank);
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
return blindeye && blindeye->IsAlive() && blindeye->GetHealthPct() > 90.0f &&
|
return blindeye && blindeye->GetHealthPct() > 90.0f &&
|
||||||
blindeyeTank && blindeyeTank->IsAlive() && botAI->CanCastSpell("misdirection", blindeyeTank);
|
blindeyeTank && botAI->CanCastSpell("misdirection", blindeyeTank);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -136,25 +136,24 @@ bool HighKingMaulgarPullingOlmAndBlindeyeTrigger::IsActive()
|
|||||||
|
|
||||||
// Gruul the Dragonkiller Triggers
|
// Gruul the Dragonkiller Triggers
|
||||||
|
|
||||||
bool GruulTheDragonkillerBossEngagedByMainTankTrigger::IsActive()
|
bool GruulTheDragonkillerBossEngagedByTanksTrigger::IsActive()
|
||||||
{
|
{
|
||||||
Unit* gruul = AI_VALUE2(Unit*, "find target", "gruul the dragonkiller");
|
Unit* gruul = AI_VALUE2(Unit*, "find target", "gruul the dragonkiller");
|
||||||
|
|
||||||
return gruul && gruul->IsAlive() && botAI->IsMainTank(bot);
|
return gruul && botAI->IsTank(bot);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GruulTheDragonkillerBossEngagedByRangeTrigger::IsActive()
|
bool GruulTheDragonkillerBossEngagedByRangedTrigger::IsActive()
|
||||||
{
|
{
|
||||||
Unit* gruul = AI_VALUE2(Unit*, "find target", "gruul the dragonkiller");
|
Unit* gruul = AI_VALUE2(Unit*, "find target", "gruul the dragonkiller");
|
||||||
|
|
||||||
return gruul && gruul->IsAlive() && botAI->IsRanged(bot);
|
return gruul && botAI->IsRanged(bot);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GruulTheDragonkillerIncomingShatterTrigger::IsActive()
|
bool GruulTheDragonkillerIncomingShatterTrigger::IsActive()
|
||||||
{
|
{
|
||||||
Unit* gruul = AI_VALUE2(Unit*, "find target", "gruul the dragonkiller");
|
Unit* gruul = AI_VALUE2(Unit*, "find target", "gruul the dragonkiller");
|
||||||
|
|
||||||
return gruul && gruul->IsAlive() &&
|
return gruul && (bot->HasAura(SPELL_GROUND_SLAM_1) ||
|
||||||
(bot->HasAura(SPELL_GROUND_SLAM_1) ||
|
bot->HasAura(SPELL_GROUND_SLAM_2));
|
||||||
bot->HasAura(SPELL_GROUND_SLAM_2));
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,17 +73,17 @@ public:
|
|||||||
bool IsActive() override;
|
bool IsActive() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class GruulTheDragonkillerBossEngagedByMainTankTrigger : public Trigger
|
class GruulTheDragonkillerBossEngagedByTanksTrigger : public Trigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
GruulTheDragonkillerBossEngagedByMainTankTrigger(PlayerbotAI* botAI) : Trigger(botAI, "gruul the dragonkiller boss engaged by main tank") {}
|
GruulTheDragonkillerBossEngagedByTanksTrigger(PlayerbotAI* botAI) : Trigger(botAI, "gruul the dragonkiller boss engaged by tanks") {}
|
||||||
bool IsActive() override;
|
bool IsActive() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class GruulTheDragonkillerBossEngagedByRangeTrigger : public Trigger
|
class GruulTheDragonkillerBossEngagedByRangedTrigger : public Trigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
GruulTheDragonkillerBossEngagedByRangeTrigger(PlayerbotAI* botAI) : Trigger(botAI, "gruul the dragonkiller boss engaged by range") {}
|
GruulTheDragonkillerBossEngagedByRangedTrigger(PlayerbotAI* botAI) : Trigger(botAI, "gruul the dragonkiller boss engaged by ranged") {}
|
||||||
bool IsActive() override;
|
bool IsActive() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -6,19 +6,16 @@
|
|||||||
|
|
||||||
namespace GruulsLairHelpers
|
namespace GruulsLairHelpers
|
||||||
{
|
{
|
||||||
namespace GruulsLairLocations
|
// Olm does not chase properly due to the Core's caster movement issues
|
||||||
{
|
// Thus, the below "OlmTankPosition" is beyond the actual desired tanking location
|
||||||
// Olm does not chase properly due to the Core's caster movement issues
|
// It is the spot to which the OlmTank runs to to pull Olm to a decent tanking location
|
||||||
// Thus, the below "OlmTankPosition" is beyond the actual desired tanking location
|
// "MaulgarRoomCenter" is to keep healers in a centralized location
|
||||||
// It is the spot to which the OlmTank runs to to pull Olm to a decent tanking location
|
const Position MAULGAR_TANK_POSITION = { 90.686f, 167.047f, -13.234f };
|
||||||
// "MaulgarRoomCenter" is to keep healers in a centralized location
|
const Position OLM_TANK_POSITION = { 87.485f, 234.942f, -3.635f };
|
||||||
const Location MaulgarTankPosition = { 90.686f, 167.047f, -13.234f };
|
const Position BLINDEYE_TANK_POSITION = { 99.681f, 213.989f, -10.345f };
|
||||||
const Location OlmTankPosition = { 87.485f, 234.942f, -3.635f };
|
const Position KROSH_TANK_POSITION = { 116.880f, 166.208f, -14.231f };
|
||||||
const Location BlindeyeTankPosition = { 99.681f, 213.989f, -10.345f };
|
const Position MAULGAR_ROOM_CENTER = { 88.754f, 150.759f, -11.569f };
|
||||||
const Location KroshTankPosition = { 116.880f, 166.208f, -14.231f };
|
const Position GRUUL_TANK_POSITION = { 241.238f, 365.025f, -4.220f };
|
||||||
const Location MaulgarRoomCenter = { 88.754f, 150.759f, -11.569f };
|
|
||||||
const Location GruulTankPosition = { 241.238f, 365.025f, -4.220f };
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsAnyOgreBossAlive(PlayerbotAI* botAI)
|
bool IsAnyOgreBossAlive(PlayerbotAI* botAI)
|
||||||
{
|
{
|
||||||
@@ -42,84 +39,43 @@ namespace GruulsLairHelpers
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MarkTargetWithIcon(Player* bot, Unit* target, uint8 iconId)
|
|
||||||
{
|
|
||||||
Group* group = bot->GetGroup();
|
|
||||||
if (!target || !group)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ObjectGuid currentGuid = group->GetTargetIcon(iconId);
|
|
||||||
if (currentGuid != target->GetGUID())
|
|
||||||
{
|
|
||||||
group->SetTargetIcon(iconId, bot->GetGUID(), target->GetGUID());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MarkTargetWithSquare(Player* bot, Unit* target)
|
|
||||||
{
|
|
||||||
MarkTargetWithIcon(bot, target, RtiTargetValue::squareIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MarkTargetWithStar(Player* bot, Unit* target)
|
|
||||||
{
|
|
||||||
MarkTargetWithIcon(bot, target, RtiTargetValue::starIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MarkTargetWithCircle(Player* bot, Unit* target)
|
|
||||||
{
|
|
||||||
MarkTargetWithIcon(bot, target, RtiTargetValue::circleIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MarkTargetWithDiamond(Player* bot, Unit* target)
|
|
||||||
{
|
|
||||||
MarkTargetWithIcon(bot, target, RtiTargetValue::diamondIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MarkTargetWithTriangle(Player* bot, Unit* target)
|
|
||||||
{
|
|
||||||
MarkTargetWithIcon(bot, target, RtiTargetValue::triangleIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetRtiTarget(PlayerbotAI* botAI, const std::string& rtiName, Unit* target)
|
|
||||||
{
|
|
||||||
if (!target)
|
|
||||||
return;
|
|
||||||
|
|
||||||
std::string currentRti = botAI->GetAiObjectContext()->GetValue<std::string>("rti")->Get();
|
|
||||||
Unit* currentTarget = botAI->GetAiObjectContext()->GetValue<Unit*>("rti target")->Get();
|
|
||||||
|
|
||||||
if (currentRti != rtiName || currentTarget != target)
|
|
||||||
{
|
|
||||||
botAI->GetAiObjectContext()->GetValue<std::string>("rti")->Set(rtiName);
|
|
||||||
botAI->GetAiObjectContext()->GetValue<Unit*>("rti target")->Set(target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsKroshMageTank(PlayerbotAI* botAI, Player* bot)
|
bool IsKroshMageTank(PlayerbotAI* botAI, Player* bot)
|
||||||
{
|
{
|
||||||
Group* group = bot->GetGroup();
|
Group* group = bot->GetGroup();
|
||||||
if (!group)
|
if (!group)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Player* highestHpMage = nullptr;
|
// (1) First loop: Return the first assistant Mage (real player or bot)
|
||||||
uint32 highestHp = 0;
|
|
||||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||||
{
|
{
|
||||||
Player* member = ref->GetSource();
|
Player* member = ref->GetSource();
|
||||||
if (!member || !member->IsAlive() || !GET_PLAYERBOT_AI(member))
|
if (!member || !member->IsAlive() || member->getClass() != CLASS_MAGE)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (member->getClass() == CLASS_MAGE)
|
if (group->IsAssistant(member->GetGUID()))
|
||||||
|
return member == bot;
|
||||||
|
}
|
||||||
|
|
||||||
|
// (2) Fall back to bot Mage with highest HP
|
||||||
|
Player* highestHpMage = nullptr;
|
||||||
|
uint32 highestHp = 0;
|
||||||
|
|
||||||
|
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||||
|
{
|
||||||
|
Player* member = ref->GetSource();
|
||||||
|
if (!member || !member->IsAlive() || !GET_PLAYERBOT_AI(member) ||
|
||||||
|
member->getClass() != CLASS_MAGE)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
uint32 hp = member->GetMaxHealth();
|
||||||
|
if (!highestHpMage || hp > highestHp)
|
||||||
{
|
{
|
||||||
uint32 hp = member->GetMaxHealth();
|
highestHpMage = member;
|
||||||
if (!highestHpMage || hp > highestHp)
|
highestHp = hp;
|
||||||
{
|
|
||||||
highestHpMage = member;
|
|
||||||
highestHp = hp;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// (3) Return the found Mage tank, or nullptr if none found
|
||||||
return highestHpMage == bot;
|
return highestHpMage == bot;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,30 +85,37 @@ namespace GruulsLairHelpers
|
|||||||
if (!group)
|
if (!group)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Player* highestHpMoonkin = nullptr;
|
// (1) First loop: Return the first assistant Moonkin (real player or bot)
|
||||||
uint32 highestHp = 0;
|
|
||||||
|
|
||||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||||
{
|
{
|
||||||
Player* member = ref->GetSource();
|
Player* member = ref->GetSource();
|
||||||
if (!member || !member->IsAlive() || !GET_PLAYERBOT_AI(member))
|
if (!member || !member->IsAlive() || member->getClass() != CLASS_DRUID)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (member->getClass() == CLASS_DRUID)
|
if (group->IsAssistant(member->GetGUID()) &&
|
||||||
|
AiFactory::GetPlayerSpecTab(member) == DRUID_TAB_BALANCE)
|
||||||
|
return member == bot;
|
||||||
|
}
|
||||||
|
|
||||||
|
// (2) Fall back to bot Moonkin with highest HP
|
||||||
|
Player* highestHpMoonkin = nullptr;
|
||||||
|
uint32 highestHp = 0;
|
||||||
|
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||||
|
{
|
||||||
|
Player* member = ref->GetSource();
|
||||||
|
if (!member || !member->IsAlive() || member->getClass() != CLASS_DRUID ||
|
||||||
|
!GET_PLAYERBOT_AI(member) || AiFactory::GetPlayerSpecTab(member) != DRUID_TAB_BALANCE)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
uint32 hp = member->GetMaxHealth();
|
||||||
|
if (!highestHpMoonkin || hp > highestHp)
|
||||||
{
|
{
|
||||||
int tab = AiFactory::GetPlayerSpecTab(member);
|
highestHpMoonkin = member;
|
||||||
if (tab == DRUID_TAB_BALANCE)
|
highestHp = hp;
|
||||||
{
|
|
||||||
uint32 hp = member->GetMaxHealth();
|
|
||||||
if (!highestHpMoonkin || hp > highestHp)
|
|
||||||
{
|
|
||||||
highestHpMoonkin = member;
|
|
||||||
highestHp = hp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// (3) Return the found Moonkin tank, or nullptr if none found
|
||||||
return highestHpMoonkin == bot;
|
return highestHpMoonkin == bot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,23 +2,19 @@
|
|||||||
#define RAID_GRUULSLAIRHELPERS_H
|
#define RAID_GRUULSLAIRHELPERS_H
|
||||||
|
|
||||||
#include "PlayerbotAI.h"
|
#include "PlayerbotAI.h"
|
||||||
#include "RtiTargetValue.h"
|
|
||||||
|
|
||||||
namespace GruulsLairHelpers
|
namespace GruulsLairHelpers
|
||||||
{
|
{
|
||||||
enum GruulsLairSpells
|
enum GruulsLairSpells
|
||||||
{
|
{
|
||||||
// High King Maulgar
|
// High King Maulgar
|
||||||
SPELL_WHIRLWIND = 33238,
|
SPELL_WHIRLWIND = 33238,
|
||||||
|
|
||||||
// Krosh Firehand
|
// Krosh Firehand
|
||||||
SPELL_SPELL_SHIELD = 33054,
|
SPELL_SPELL_SHIELD = 33054,
|
||||||
|
|
||||||
// Hunter
|
// Hunter
|
||||||
SPELL_MISDIRECTION = 35079,
|
SPELL_MISDIRECTION = 35079,
|
||||||
|
|
||||||
// Warlock
|
|
||||||
SPELL_BANISH = 18647, // Rank 2
|
|
||||||
|
|
||||||
// Gruul the Dragonkiller
|
// Gruul the Dragonkiller
|
||||||
SPELL_GROUND_SLAM_1 = 33525,
|
SPELL_GROUND_SLAM_1 = 33525,
|
||||||
@@ -30,33 +26,20 @@ namespace GruulsLairHelpers
|
|||||||
NPC_WILD_FEL_STALKER = 18847,
|
NPC_WILD_FEL_STALKER = 18847,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constexpr uint32 GRUULS_LAIR_MAP_ID = 565;
|
||||||
|
|
||||||
bool IsAnyOgreBossAlive(PlayerbotAI* botAI);
|
bool IsAnyOgreBossAlive(PlayerbotAI* botAI);
|
||||||
void MarkTargetWithIcon(Player* bot, Unit* target, uint8 iconId);
|
|
||||||
void MarkTargetWithSquare(Player* bot, Unit* target);
|
|
||||||
void MarkTargetWithStar(Player* bot, Unit* target);
|
|
||||||
void MarkTargetWithCircle(Player* bot, Unit* target);
|
|
||||||
void MarkTargetWithDiamond(Player* bot, Unit* target);
|
|
||||||
void MarkTargetWithTriangle(Player* bot, Unit* target);
|
|
||||||
void SetRtiTarget(PlayerbotAI* botAI, const std::string& rtiName, Unit* target);
|
|
||||||
bool IsKroshMageTank(PlayerbotAI* botAI, Player* bot);
|
bool IsKroshMageTank(PlayerbotAI* botAI, Player* bot);
|
||||||
bool IsKigglerMoonkinTank(PlayerbotAI* botAI, Player* bot);
|
bool IsKigglerMoonkinTank(PlayerbotAI* botAI, Player* bot);
|
||||||
bool IsPositionSafe(PlayerbotAI* botAI, Player* bot, Position pos);
|
bool IsPositionSafe(PlayerbotAI* botAI, Player* bot, Position pos);
|
||||||
bool TryGetNewSafePosition(PlayerbotAI* botAI, Player* bot, Position& outPos);
|
bool TryGetNewSafePosition(PlayerbotAI* botAI, Player* bot, Position& outPos);
|
||||||
|
|
||||||
struct Location
|
extern const Position MAULGAR_TANK_POSITION;
|
||||||
{
|
extern const Position OLM_TANK_POSITION;
|
||||||
float x, y, z;
|
extern const Position BLINDEYE_TANK_POSITION;
|
||||||
};
|
extern const Position KROSH_TANK_POSITION;
|
||||||
|
extern const Position MAULGAR_ROOM_CENTER;
|
||||||
namespace GruulsLairLocations
|
extern const Position GRUUL_TANK_POSITION;
|
||||||
{
|
|
||||||
extern const Location MaulgarTankPosition;
|
|
||||||
extern const Location OlmTankPosition;
|
|
||||||
extern const Location BlindeyeTankPosition;
|
|
||||||
extern const Location KroshTankPosition;
|
|
||||||
extern const Location MaulgarRoomCenter;
|
|
||||||
extern const Location GruulTankPosition;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include "RaidKarazhanHelpers.h"
|
#include "RaidKarazhanHelpers.h"
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
#include "PlayerbotTextMgr.h"
|
#include "PlayerbotTextMgr.h"
|
||||||
|
#include "RaidBossHelpers.h"
|
||||||
|
|
||||||
using namespace KarazhanHelpers;
|
using namespace KarazhanHelpers;
|
||||||
|
|
||||||
@@ -44,7 +45,7 @@ bool AttumenTheHuntsmanMarkTargetAction::Execute(Event event)
|
|||||||
Unit* attumenMounted = GetFirstAliveUnitByEntry(botAI, NPC_ATTUMEN_THE_HUNTSMAN_MOUNTED);
|
Unit* attumenMounted = GetFirstAliveUnitByEntry(botAI, NPC_ATTUMEN_THE_HUNTSMAN_MOUNTED);
|
||||||
if (attumenMounted)
|
if (attumenMounted)
|
||||||
{
|
{
|
||||||
if (IsInstanceTimerManager(botAI, bot))
|
if (IsMechanicTrackerBot(botAI, bot, KARAZHAN_MAP_ID, nullptr))
|
||||||
MarkTargetWithStar(bot, attumenMounted);
|
MarkTargetWithStar(bot, attumenMounted);
|
||||||
|
|
||||||
SetRtiTarget(botAI, "star", attumenMounted);
|
SetRtiTarget(botAI, "star", attumenMounted);
|
||||||
@@ -57,7 +58,7 @@ bool AttumenTheHuntsmanMarkTargetAction::Execute(Event event)
|
|||||||
}
|
}
|
||||||
else if (Unit* midnight = AI_VALUE2(Unit*, "find target", "midnight"))
|
else if (Unit* midnight = AI_VALUE2(Unit*, "find target", "midnight"))
|
||||||
{
|
{
|
||||||
if (IsInstanceTimerManager(botAI, bot))
|
if (IsMechanicTrackerBot(botAI, bot, KARAZHAN_MAP_ID, nullptr))
|
||||||
MarkTargetWithStar(bot, midnight);
|
MarkTargetWithStar(bot, midnight);
|
||||||
|
|
||||||
if (!botAI->IsAssistTankOfIndex(bot, 0))
|
if (!botAI->IsAssistTankOfIndex(bot, 0))
|
||||||
@@ -180,7 +181,7 @@ bool MoroesMarkTargetAction::Execute(Event event)
|
|||||||
|
|
||||||
if (target)
|
if (target)
|
||||||
{
|
{
|
||||||
if (IsInstanceTimerManager(botAI, bot))
|
if (IsMechanicTrackerBot(botAI, bot, KARAZHAN_MAP_ID, nullptr))
|
||||||
MarkTargetWithSkull(bot, target);
|
MarkTargetWithSkull(bot, target);
|
||||||
|
|
||||||
SetRtiTarget(botAI, "skull", target);
|
SetRtiTarget(botAI, "skull", target);
|
||||||
@@ -405,7 +406,7 @@ bool TheCuratorMarkAstralFlareAction::Execute(Event event)
|
|||||||
if (!flare)
|
if (!flare)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (IsInstanceTimerManager(botAI, bot))
|
if (IsMechanicTrackerBot(botAI, bot, KARAZHAN_MAP_ID, nullptr))
|
||||||
MarkTargetWithSkull(bot, flare);
|
MarkTargetWithSkull(bot, flare);
|
||||||
|
|
||||||
SetRtiTarget(botAI, "skull", flare);
|
SetRtiTarget(botAI, "skull", flare);
|
||||||
@@ -469,11 +470,11 @@ bool TheCuratorSpreadRangedAction::Execute(Event event)
|
|||||||
// Prioritize (1) Demon Chains, (2) Kil'rek, (3) Illhoof
|
// Prioritize (1) Demon Chains, (2) Kil'rek, (3) Illhoof
|
||||||
bool TerestianIllhoofMarkTargetAction::Execute(Event event)
|
bool TerestianIllhoofMarkTargetAction::Execute(Event event)
|
||||||
{
|
{
|
||||||
Unit* demonChains = AI_VALUE2(Unit*, "find target", "demon chains");
|
Unit* demonChains = GetFirstAliveUnitByEntry(botAI, NPC_DEMON_CHAINS);
|
||||||
Unit* kilrek = AI_VALUE2(Unit*, "find target", "kil'rek");
|
Unit* kilrek = GetFirstAliveUnitByEntry(botAI, NPC_KILREK);
|
||||||
Unit* illhoof = AI_VALUE2(Unit*, "find target", "terestian illhoof");
|
Unit* illhoof = AI_VALUE2(Unit*, "find target", "terestian illhoof");
|
||||||
Unit* target = GetFirstAliveUnit({demonChains, kilrek, illhoof});
|
|
||||||
|
|
||||||
|
Unit* target = GetFirstAliveUnit({demonChains, kilrek, illhoof});
|
||||||
if (target)
|
if (target)
|
||||||
MarkTargetWithSkull(bot, target);
|
MarkTargetWithSkull(bot, target);
|
||||||
|
|
||||||
@@ -1007,7 +1008,7 @@ bool NetherspiteManageTimersAndTrackersAction::Execute(Event event)
|
|||||||
if (netherspite->GetHealth() == netherspite->GetMaxHealth() &&
|
if (netherspite->GetHealth() == netherspite->GetMaxHealth() &&
|
||||||
!netherspite->HasAura(SPELL_GREEN_BEAM_HEAL))
|
!netherspite->HasAura(SPELL_GREEN_BEAM_HEAL))
|
||||||
{
|
{
|
||||||
if (IsInstanceTimerManager(botAI, bot))
|
if (IsMechanicTrackerBot(botAI, bot, KARAZHAN_MAP_ID, nullptr))
|
||||||
netherspiteDpsWaitTimer.insert_or_assign(instanceId, now);
|
netherspiteDpsWaitTimer.insert_or_assign(instanceId, now);
|
||||||
|
|
||||||
if (botAI->IsTank(bot) && !bot->HasAura(SPELL_RED_BEAM_DEBUFF))
|
if (botAI->IsTank(bot) && !bot->HasAura(SPELL_RED_BEAM_DEBUFF))
|
||||||
@@ -1018,7 +1019,7 @@ bool NetherspiteManageTimersAndTrackersAction::Execute(Event event)
|
|||||||
}
|
}
|
||||||
else if (netherspite->HasAura(SPELL_NETHERSPITE_BANISHED))
|
else if (netherspite->HasAura(SPELL_NETHERSPITE_BANISHED))
|
||||||
{
|
{
|
||||||
if (IsInstanceTimerManager(botAI, bot))
|
if (IsMechanicTrackerBot(botAI, bot, KARAZHAN_MAP_ID, nullptr))
|
||||||
netherspiteDpsWaitTimer.erase(instanceId);
|
netherspiteDpsWaitTimer.erase(instanceId);
|
||||||
|
|
||||||
if (botAI->IsTank(bot))
|
if (botAI->IsTank(bot))
|
||||||
@@ -1029,7 +1030,7 @@ bool NetherspiteManageTimersAndTrackersAction::Execute(Event event)
|
|||||||
}
|
}
|
||||||
else if (!netherspite->HasAura(SPELL_NETHERSPITE_BANISHED))
|
else if (!netherspite->HasAura(SPELL_NETHERSPITE_BANISHED))
|
||||||
{
|
{
|
||||||
if (IsInstanceTimerManager(botAI, bot))
|
if (IsMechanicTrackerBot(botAI, bot, KARAZHAN_MAP_ID, nullptr))
|
||||||
netherspiteDpsWaitTimer.try_emplace(instanceId, now);
|
netherspiteDpsWaitTimer.try_emplace(instanceId, now);
|
||||||
|
|
||||||
if (botAI->IsTank(bot) && bot->HasAura(SPELL_RED_BEAM_DEBUFF))
|
if (botAI->IsTank(bot) && bot->HasAura(SPELL_RED_BEAM_DEBUFF))
|
||||||
@@ -1458,7 +1459,7 @@ bool NightbaneManageTimersAndTrackersAction::Execute(Event event)
|
|||||||
if (botAI->IsRanged(bot))
|
if (botAI->IsRanged(bot))
|
||||||
nightbaneRangedStep.erase(botGuid);
|
nightbaneRangedStep.erase(botGuid);
|
||||||
|
|
||||||
if (IsInstanceTimerManager(botAI, bot))
|
if (IsMechanicTrackerBot(botAI, bot, KARAZHAN_MAP_ID, nullptr))
|
||||||
nightbaneDpsWaitTimer.erase(instanceId);
|
nightbaneDpsWaitTimer.erase(instanceId);
|
||||||
}
|
}
|
||||||
// Erase flight phase timer and Rain of Bones tracker on ground phase and start DPS wait timer
|
// Erase flight phase timer and Rain of Bones tracker on ground phase and start DPS wait timer
|
||||||
@@ -1466,7 +1467,7 @@ bool NightbaneManageTimersAndTrackersAction::Execute(Event event)
|
|||||||
{
|
{
|
||||||
nightbaneRainOfBonesHit.erase(botGuid);
|
nightbaneRainOfBonesHit.erase(botGuid);
|
||||||
|
|
||||||
if (IsInstanceTimerManager(botAI, bot))
|
if (IsMechanicTrackerBot(botAI, bot, KARAZHAN_MAP_ID, nullptr))
|
||||||
{
|
{
|
||||||
nightbaneFlightPhaseStartTimer.erase(instanceId);
|
nightbaneFlightPhaseStartTimer.erase(instanceId);
|
||||||
nightbaneDpsWaitTimer.try_emplace(instanceId, now);
|
nightbaneDpsWaitTimer.try_emplace(instanceId, now);
|
||||||
@@ -1482,7 +1483,7 @@ bool NightbaneManageTimersAndTrackersAction::Execute(Event event)
|
|||||||
if (botAI->IsRanged(bot))
|
if (botAI->IsRanged(bot))
|
||||||
nightbaneRangedStep.erase(botGuid);
|
nightbaneRangedStep.erase(botGuid);
|
||||||
|
|
||||||
if (IsInstanceTimerManager(botAI, bot))
|
if (IsMechanicTrackerBot(botAI, bot, KARAZHAN_MAP_ID, nullptr))
|
||||||
{
|
{
|
||||||
nightbaneDpsWaitTimer.erase(instanceId);
|
nightbaneDpsWaitTimer.erase(instanceId);
|
||||||
nightbaneFlightPhaseStartTimer.try_emplace(instanceId, now);
|
nightbaneFlightPhaseStartTimer.try_emplace(instanceId, now);
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include "MageActions.h"
|
#include "MageActions.h"
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
#include "PriestActions.h"
|
#include "PriestActions.h"
|
||||||
|
#include "RaidBossHelpers.h"
|
||||||
#include "ReachTargetActions.h"
|
#include "ReachTargetActions.h"
|
||||||
#include "RogueActions.h"
|
#include "RogueActions.h"
|
||||||
#include "ShamanActions.h"
|
#include "ShamanActions.h"
|
||||||
@@ -242,6 +243,9 @@ float PrinceMalchezaarEnfeebleKeepDistanceMultiplier::GetValue(Action* action)
|
|||||||
|
|
||||||
if (bot->HasAura(SPELL_ENFEEBLE))
|
if (bot->HasAura(SPELL_ENFEEBLE))
|
||||||
{
|
{
|
||||||
|
if (dynamic_cast<CastReachTargetSpellAction*>(action))
|
||||||
|
return 0.0f;
|
||||||
|
|
||||||
if (dynamic_cast<MovementAction*>(action) &&
|
if (dynamic_cast<MovementAction*>(action) &&
|
||||||
!dynamic_cast<PrinceMalchezaarEnfeebledAvoidHazardAction*>(action))
|
!dynamic_cast<PrinceMalchezaarEnfeebledAvoidHazardAction*>(action))
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include "RaidKarazhanHelpers.h"
|
#include "RaidKarazhanHelpers.h"
|
||||||
#include "RaidKarazhanActions.h"
|
#include "RaidKarazhanActions.h"
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
|
#include "RaidBossHelpers.h"
|
||||||
|
|
||||||
using namespace KarazhanHelpers;
|
using namespace KarazhanHelpers;
|
||||||
|
|
||||||
@@ -40,7 +41,7 @@ bool AttumenTheHuntsmanAttumenIsMountedTrigger::IsActive()
|
|||||||
|
|
||||||
bool AttumenTheHuntsmanBossWipesAggroWhenMountingTrigger::IsActive()
|
bool AttumenTheHuntsmanBossWipesAggroWhenMountingTrigger::IsActive()
|
||||||
{
|
{
|
||||||
if (!IsInstanceTimerManager(botAI, bot))
|
if (!IsMechanicTrackerBot(botAI, bot, KARAZHAN_MAP_ID, nullptr))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Unit* midnight = AI_VALUE2(Unit*, "find target", "midnight");
|
Unit* midnight = AI_VALUE2(Unit*, "find target", "midnight");
|
||||||
@@ -110,7 +111,7 @@ bool BigBadWolfBossIsChasingLittleRedRidingHoodTrigger::IsActive()
|
|||||||
|
|
||||||
bool RomuloAndJulianneBothBossesRevivedTrigger::IsActive()
|
bool RomuloAndJulianneBothBossesRevivedTrigger::IsActive()
|
||||||
{
|
{
|
||||||
if (!IsInstanceTimerManager(botAI, bot))
|
if (!IsMechanicTrackerBot(botAI, bot, KARAZHAN_MAP_ID, nullptr))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Unit* romulo = AI_VALUE2(Unit*, "find target", "romulo");
|
Unit* romulo = AI_VALUE2(Unit*, "find target", "romulo");
|
||||||
@@ -126,7 +127,7 @@ bool RomuloAndJulianneBothBossesRevivedTrigger::IsActive()
|
|||||||
|
|
||||||
bool WizardOfOzNeedTargetPriorityTrigger::IsActive()
|
bool WizardOfOzNeedTargetPriorityTrigger::IsActive()
|
||||||
{
|
{
|
||||||
if (!IsInstanceTimerManager(botAI, bot))
|
if (!IsMechanicTrackerBot(botAI, bot, KARAZHAN_MAP_ID, nullptr))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Unit* dorothee = AI_VALUE2(Unit*, "find target", "dorothee");
|
Unit* dorothee = AI_VALUE2(Unit*, "find target", "dorothee");
|
||||||
@@ -178,7 +179,7 @@ bool TheCuratorBossAstralFlaresCastArcingSearTrigger::IsActive()
|
|||||||
|
|
||||||
bool TerestianIllhoofNeedTargetPriorityTrigger::IsActive()
|
bool TerestianIllhoofNeedTargetPriorityTrigger::IsActive()
|
||||||
{
|
{
|
||||||
if (!IsInstanceTimerManager(botAI, bot))
|
if (!IsMechanicTrackerBot(botAI, bot, KARAZHAN_MAP_ID, nullptr))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Unit* illhoof = AI_VALUE2(Unit*, "find target", "terestian illhoof");
|
Unit* illhoof = AI_VALUE2(Unit*, "find target", "terestian illhoof");
|
||||||
@@ -202,7 +203,7 @@ bool ShadeOfAranFlameWreathIsActiveTrigger::IsActive()
|
|||||||
// Exclusion of Banish is so the player may Banish elementals if they wish
|
// Exclusion of Banish is so the player may Banish elementals if they wish
|
||||||
bool ShadeOfAranConjuredElementalsSummonedTrigger::IsActive()
|
bool ShadeOfAranConjuredElementalsSummonedTrigger::IsActive()
|
||||||
{
|
{
|
||||||
if (!IsInstanceTimerManager(botAI, bot))
|
if (!IsMechanicTrackerBot(botAI, bot, KARAZHAN_MAP_ID, nullptr))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Unit* elemental = AI_VALUE2(Unit*, "find target", "conjured elemental");
|
Unit* elemental = AI_VALUE2(Unit*, "find target", "conjured elemental");
|
||||||
@@ -279,7 +280,7 @@ bool NetherspiteBossIsBanishedTrigger::IsActive()
|
|||||||
|
|
||||||
bool NetherspiteNeedToManageTimersAndTrackersTrigger::IsActive()
|
bool NetherspiteNeedToManageTimersAndTrackersTrigger::IsActive()
|
||||||
{
|
{
|
||||||
if (!botAI->IsTank(bot) && !IsInstanceTimerManager(botAI, bot))
|
if (!botAI->IsTank(bot) && !IsMechanicTrackerBot(botAI, bot, KARAZHAN_MAP_ID, nullptr))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Unit* netherspite = AI_VALUE2(Unit*, "find target", "netherspite");
|
Unit* netherspite = AI_VALUE2(Unit*, "find target", "netherspite");
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
#include "RaidKarazhanHelpers.h"
|
#include "RaidKarazhanHelpers.h"
|
||||||
#include "RaidKarazhanActions.h"
|
#include "RaidKarazhanActions.h"
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
#include "RtiTargetValue.h"
|
|
||||||
|
|
||||||
namespace KarazhanHelpers
|
namespace KarazhanHelpers
|
||||||
{
|
{
|
||||||
@@ -52,75 +51,6 @@ namespace KarazhanHelpers
|
|||||||
const Position NIGHTBANE_FLIGHT_STACK_POSITION = { -11159.555f, -1893.526f, 91.473f }; // Broken Barrel
|
const Position NIGHTBANE_FLIGHT_STACK_POSITION = { -11159.555f, -1893.526f, 91.473f }; // Broken Barrel
|
||||||
const Position NIGHTBANE_RAIN_OF_BONES_POSITION = { -11165.233f, -1911.123f, 91.473f };
|
const Position NIGHTBANE_RAIN_OF_BONES_POSITION = { -11165.233f, -1911.123f, 91.473f };
|
||||||
|
|
||||||
void MarkTargetWithIcon(Player* bot, Unit* target, uint8 iconId)
|
|
||||||
{
|
|
||||||
if (!target)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (Group* group = bot->GetGroup())
|
|
||||||
{
|
|
||||||
ObjectGuid currentGuid = group->GetTargetIcon(iconId);
|
|
||||||
if (currentGuid != target->GetGUID())
|
|
||||||
group->SetTargetIcon(iconId, bot->GetGUID(), target->GetGUID());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MarkTargetWithSkull(Player* bot, Unit* target)
|
|
||||||
{
|
|
||||||
MarkTargetWithIcon(bot, target, RtiTargetValue::skullIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MarkTargetWithSquare(Player* bot, Unit* target)
|
|
||||||
{
|
|
||||||
MarkTargetWithIcon(bot, target, RtiTargetValue::squareIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MarkTargetWithStar(Player* bot, Unit* target)
|
|
||||||
{
|
|
||||||
MarkTargetWithIcon(bot, target, RtiTargetValue::starIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MarkTargetWithCircle(Player* bot, Unit* target)
|
|
||||||
{
|
|
||||||
MarkTargetWithIcon(bot, target, RtiTargetValue::circleIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MarkTargetWithMoon(Player* bot, Unit* target)
|
|
||||||
{
|
|
||||||
MarkTargetWithIcon(bot, target, RtiTargetValue::moonIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetRtiTarget(PlayerbotAI* botAI, const std::string& rtiName, Unit* target)
|
|
||||||
{
|
|
||||||
if (!target)
|
|
||||||
return;
|
|
||||||
|
|
||||||
std::string currentRti = botAI->GetAiObjectContext()->GetValue<std::string>("rti")->Get();
|
|
||||||
Unit* currentTarget = botAI->GetAiObjectContext()->GetValue<Unit*>("rti target")->Get();
|
|
||||||
|
|
||||||
if (currentRti != rtiName || currentTarget != target)
|
|
||||||
{
|
|
||||||
botAI->GetAiObjectContext()->GetValue<std::string>("rti")->Set(rtiName);
|
|
||||||
botAI->GetAiObjectContext()->GetValue<Unit*>("rti target")->Set(target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only one bot is needed to set/reset instance-wide timers
|
|
||||||
bool IsInstanceTimerManager(PlayerbotAI* botAI, Player* bot)
|
|
||||||
{
|
|
||||||
if (Group* group = bot->GetGroup())
|
|
||||||
{
|
|
||||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
|
||||||
{
|
|
||||||
Player* member = ref->GetSource();
|
|
||||||
if (member && member->IsAlive() && botAI->IsDps(member) && GET_PLAYERBOT_AI(member))
|
|
||||||
return member == bot;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Unit* GetFirstAliveUnit(const std::vector<Unit*>& units)
|
Unit* GetFirstAliveUnit(const std::vector<Unit*>& units)
|
||||||
{
|
{
|
||||||
for (Unit* unit : units)
|
for (Unit* unit : units)
|
||||||
@@ -132,44 +62,6 @@ namespace KarazhanHelpers
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Unit* GetFirstAliveUnitByEntry(PlayerbotAI* botAI, uint32 entry)
|
|
||||||
{
|
|
||||||
const GuidVector npcs = botAI->GetAiObjectContext()->GetValue<GuidVector>("nearest hostile npcs")->Get();
|
|
||||||
for (auto const& npcGuid : npcs)
|
|
||||||
{
|
|
||||||
Unit* unit = botAI->GetUnit(npcGuid);
|
|
||||||
if (unit && unit->IsAlive() && unit->GetEntry() == entry)
|
|
||||||
return unit;
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
Unit* GetNearestPlayerInRadius(Player* bot, float radius)
|
|
||||||
{
|
|
||||||
Unit* nearestPlayer = nullptr;
|
|
||||||
float nearestDistance = radius;
|
|
||||||
|
|
||||||
if (Group* group = bot->GetGroup())
|
|
||||||
{
|
|
||||||
for (GroupReference* ref = group->GetFirstMember(); ref != nullptr; ref = ref->next())
|
|
||||||
{
|
|
||||||
Player* member = ref->GetSource();
|
|
||||||
if (!member || !member->IsAlive() || member == bot)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
float distance = bot->GetExactDist2d(member);
|
|
||||||
if (distance < nearestDistance)
|
|
||||||
{
|
|
||||||
nearestDistance = distance;
|
|
||||||
nearestPlayer = member;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nearestPlayer;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsFlameWreathActive(PlayerbotAI* botAI, Player* bot)
|
bool IsFlameWreathActive(PlayerbotAI* botAI, Player* bot)
|
||||||
{
|
{
|
||||||
Unit* aran = botAI->GetAiObjectContext()->GetValue<Unit*>("find target", "shade of aran")->Get();
|
Unit* aran = botAI->GetAiObjectContext()->GetValue<Unit*>("find target", "shade of aran")->Get();
|
||||||
|
|||||||
@@ -61,6 +61,11 @@ namespace KarazhanHelpers
|
|||||||
NPC_ATTUMEN_THE_HUNTSMAN = 15550,
|
NPC_ATTUMEN_THE_HUNTSMAN = 15550,
|
||||||
NPC_ATTUMEN_THE_HUNTSMAN_MOUNTED = 16152,
|
NPC_ATTUMEN_THE_HUNTSMAN_MOUNTED = 16152,
|
||||||
|
|
||||||
|
// Terestian Illhoof
|
||||||
|
NPC_TERESTIAN_ILLHOOF = 15688,
|
||||||
|
NPC_DEMON_CHAINS = 17248,
|
||||||
|
NPC_KILREK = 17229,
|
||||||
|
|
||||||
// Shade of Aran
|
// Shade of Aran
|
||||||
NPC_CONJURED_ELEMENTAL = 17167,
|
NPC_CONJURED_ELEMENTAL = 17167,
|
||||||
|
|
||||||
@@ -74,8 +79,8 @@ namespace KarazhanHelpers
|
|||||||
NPC_NETHERSPITE_INFERNAL = 17646,
|
NPC_NETHERSPITE_INFERNAL = 17646,
|
||||||
};
|
};
|
||||||
|
|
||||||
const uint32 KARAZHAN_MAP_ID = 532;
|
constexpr uint32 KARAZHAN_MAP_ID = 532;
|
||||||
const float NIGHTBANE_FLIGHT_Z = 95.0f;
|
constexpr float NIGHTBANE_FLIGHT_Z = 95.0f;
|
||||||
|
|
||||||
// Attumen the Huntsman
|
// Attumen the Huntsman
|
||||||
extern std::unordered_map<uint32, time_t> attumenDpsWaitTimer;
|
extern std::unordered_map<uint32, time_t> attumenDpsWaitTimer;
|
||||||
@@ -105,17 +110,7 @@ namespace KarazhanHelpers
|
|||||||
extern const Position NIGHTBANE_FLIGHT_STACK_POSITION;
|
extern const Position NIGHTBANE_FLIGHT_STACK_POSITION;
|
||||||
extern const Position NIGHTBANE_RAIN_OF_BONES_POSITION;
|
extern const Position NIGHTBANE_RAIN_OF_BONES_POSITION;
|
||||||
|
|
||||||
void MarkTargetWithIcon(Player* bot, Unit* target, uint8 iconId);
|
|
||||||
void MarkTargetWithSkull(Player* bot, Unit* target);
|
|
||||||
void MarkTargetWithSquare(Player* bot, Unit* target);
|
|
||||||
void MarkTargetWithStar(Player* bot, Unit* target);
|
|
||||||
void MarkTargetWithCircle(Player* bot, Unit* target);
|
|
||||||
void MarkTargetWithMoon(Player* bot, Unit* target);
|
|
||||||
void SetRtiTarget(PlayerbotAI* botAI, const std::string& rtiName, Unit* target);
|
|
||||||
bool IsInstanceTimerManager(PlayerbotAI* botAI, Player* bot);
|
|
||||||
Unit* GetFirstAliveUnit(const std::vector<Unit*>& units);
|
Unit* GetFirstAliveUnit(const std::vector<Unit*>& units);
|
||||||
Unit* GetFirstAliveUnitByEntry(PlayerbotAI* botAI, uint32 entry);
|
|
||||||
Unit* GetNearestPlayerInRadius(Player* bot, float radius);
|
|
||||||
bool IsFlameWreathActive(PlayerbotAI* botAI, Player* bot);
|
bool IsFlameWreathActive(PlayerbotAI* botAI, Player* bot);
|
||||||
std::vector<Player*> GetRedBlockers(PlayerbotAI* botAI, Player* bot);
|
std::vector<Player*> GetRedBlockers(PlayerbotAI* botAI, Player* bot);
|
||||||
std::vector<Player*> GetBlueBlockers(PlayerbotAI* botAI, Player* bot);
|
std::vector<Player*> GetBlueBlockers(PlayerbotAI* botAI, Player* bot);
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "ObjectAccessor.h"
|
#include "ObjectAccessor.h"
|
||||||
#include "ObjectGuid.h"
|
#include "ObjectGuid.h"
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
|
#include "RaidBossHelpers.h"
|
||||||
|
|
||||||
using namespace MagtheridonHelpers;
|
using namespace MagtheridonHelpers;
|
||||||
|
|
||||||
@@ -14,46 +15,45 @@ bool MagtheridonMainTankAttackFirstThreeChannelersAction::Execute(Event event)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
Creature* channelerSquare = GetChanneler(bot, SOUTH_CHANNELER);
|
Creature* channelerSquare = GetChanneler(bot, SOUTH_CHANNELER);
|
||||||
if (channelerSquare && channelerSquare->IsAlive())
|
if (channelerSquare)
|
||||||
MarkTargetWithSquare(bot, channelerSquare);
|
MarkTargetWithSquare(bot, channelerSquare);
|
||||||
|
|
||||||
Creature* channelerStar = GetChanneler(bot, WEST_CHANNELER);
|
Creature* channelerStar = GetChanneler(bot, WEST_CHANNELER);
|
||||||
if (channelerStar && channelerStar->IsAlive())
|
if (channelerStar)
|
||||||
MarkTargetWithStar(bot, channelerStar);
|
MarkTargetWithStar(bot, channelerStar);
|
||||||
|
|
||||||
Creature* channelerCircle = GetChanneler(bot, EAST_CHANNELER);
|
Creature* channelerCircle = GetChanneler(bot, EAST_CHANNELER);
|
||||||
if (channelerCircle && channelerCircle->IsAlive())
|
if (channelerCircle)
|
||||||
MarkTargetWithCircle(bot, channelerCircle);
|
MarkTargetWithCircle(bot, channelerCircle);
|
||||||
|
|
||||||
// After first three channelers are dead, wait for Magtheridon to activate
|
// After first three channelers are dead, wait for Magtheridon to activate
|
||||||
if ((!channelerSquare || !channelerSquare->IsAlive()) &&
|
if (!channelerSquare && !channelerStar && !channelerCircle)
|
||||||
(!channelerStar || !channelerStar->IsAlive()) &&
|
|
||||||
(!channelerCircle || !channelerCircle->IsAlive()))
|
|
||||||
{
|
{
|
||||||
const Location& position = MagtheridonsLairLocations::WaitingForMagtheridonPosition;
|
const Position& position = WAITING_FOR_MAGTHERIDON_POSITION;
|
||||||
if (!bot->IsWithinDist2d(position.x, position.y, 2.0f))
|
if (!bot->IsWithinDist2d(position.GetPositionX(), position.GetPositionY(), 2.0f))
|
||||||
{
|
{
|
||||||
return MoveTo(bot->GetMapId(), position.x, position.y, position.z, false, false, false, false,
|
return MoveTo(MAGTHERIDON_MAP_ID, position.GetPositionX(), position.GetPositionY(),
|
||||||
|
position.GetPositionZ(), false, false, false, false,
|
||||||
MovementPriority::MOVEMENT_COMBAT, true, false);
|
MovementPriority::MOVEMENT_COMBAT, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
bot->SetFacingTo(position.orientation);
|
bot->SetFacingTo(position.GetOrientation());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Creature* currentTarget = nullptr;
|
Creature* currentTarget = nullptr;
|
||||||
std::string rtiName;
|
std::string rtiName;
|
||||||
if (channelerSquare && channelerSquare->IsAlive())
|
if (channelerSquare)
|
||||||
{
|
{
|
||||||
currentTarget = channelerSquare;
|
currentTarget = channelerSquare;
|
||||||
rtiName = "square";
|
rtiName = "square";
|
||||||
}
|
}
|
||||||
else if (channelerStar && channelerStar->IsAlive())
|
else if (channelerStar)
|
||||||
{
|
{
|
||||||
currentTarget = channelerStar;
|
currentTarget = channelerStar;
|
||||||
rtiName = "star";
|
rtiName = "star";
|
||||||
}
|
}
|
||||||
else if (channelerCircle && channelerCircle->IsAlive())
|
else if (channelerCircle)
|
||||||
{
|
{
|
||||||
currentTarget = channelerCircle;
|
currentTarget = channelerCircle;
|
||||||
rtiName = "circle";
|
rtiName = "circle";
|
||||||
@@ -70,7 +70,7 @@ bool MagtheridonMainTankAttackFirstThreeChannelersAction::Execute(Event event)
|
|||||||
bool MagtheridonFirstAssistTankAttackNWChannelerAction::Execute(Event event)
|
bool MagtheridonFirstAssistTankAttackNWChannelerAction::Execute(Event event)
|
||||||
{
|
{
|
||||||
Creature* channelerDiamond = GetChanneler(bot, NORTHWEST_CHANNELER);
|
Creature* channelerDiamond = GetChanneler(bot, NORTHWEST_CHANNELER);
|
||||||
if (!channelerDiamond || !channelerDiamond->IsAlive())
|
if (!channelerDiamond)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
MarkTargetWithDiamond(bot, channelerDiamond);
|
MarkTargetWithDiamond(bot, channelerDiamond);
|
||||||
@@ -81,18 +81,18 @@ bool MagtheridonFirstAssistTankAttackNWChannelerAction::Execute(Event event)
|
|||||||
|
|
||||||
if (channelerDiamond->GetVictim() == bot)
|
if (channelerDiamond->GetVictim() == bot)
|
||||||
{
|
{
|
||||||
const Location& position = MagtheridonsLairLocations::NWChannelerTankPosition;
|
const Position& position = NW_CHANNELER_TANK_POSITION;
|
||||||
const float maxDistance = 3.0f;
|
const float maxDistance = 3.0f;
|
||||||
|
float distanceToPosition = bot->GetExactDist2d(position.GetPositionX(), position.GetPositionY());
|
||||||
|
|
||||||
if (bot->GetExactDist2d(position.x, position.y) > maxDistance)
|
if (distanceToPosition > maxDistance)
|
||||||
{
|
{
|
||||||
float dX = position.x - bot->GetPositionX();
|
float dX = position.GetPositionX() - bot->GetPositionX();
|
||||||
float dY = position.y - bot->GetPositionY();
|
float dY = position.GetPositionY() - bot->GetPositionY();
|
||||||
float dist = sqrt(dX * dX + dY * dY);
|
float moveX = bot->GetPositionX() + (dX / distanceToPosition) * maxDistance;
|
||||||
float moveX = bot->GetPositionX() + (dX / dist) * maxDistance;
|
float moveY = bot->GetPositionY() + (dY / distanceToPosition) * maxDistance;
|
||||||
float moveY = bot->GetPositionY() + (dY / dist) * maxDistance;
|
|
||||||
|
|
||||||
return MoveTo(bot->GetMapId(), moveX, moveY, position.z, false, false, false, false,
|
return MoveTo(MAGTHERIDON_MAP_ID, moveX, moveY, position.GetPositionZ(), false, false, false, false,
|
||||||
MovementPriority::MOVEMENT_COMBAT, true, false);
|
MovementPriority::MOVEMENT_COMBAT, true, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -103,7 +103,7 @@ bool MagtheridonFirstAssistTankAttackNWChannelerAction::Execute(Event event)
|
|||||||
bool MagtheridonSecondAssistTankAttackNEChannelerAction::Execute(Event event)
|
bool MagtheridonSecondAssistTankAttackNEChannelerAction::Execute(Event event)
|
||||||
{
|
{
|
||||||
Creature* channelerTriangle = GetChanneler(bot, NORTHEAST_CHANNELER);
|
Creature* channelerTriangle = GetChanneler(bot, NORTHEAST_CHANNELER);
|
||||||
if (!channelerTriangle || !channelerTriangle->IsAlive())
|
if (!channelerTriangle)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
MarkTargetWithTriangle(bot, channelerTriangle);
|
MarkTargetWithTriangle(bot, channelerTriangle);
|
||||||
@@ -114,18 +114,18 @@ bool MagtheridonSecondAssistTankAttackNEChannelerAction::Execute(Event event)
|
|||||||
|
|
||||||
if (channelerTriangle->GetVictim() == bot)
|
if (channelerTriangle->GetVictim() == bot)
|
||||||
{
|
{
|
||||||
const Location& position = MagtheridonsLairLocations::NEChannelerTankPosition;
|
const Position& position = NE_CHANNELER_TANK_POSITION;
|
||||||
const float maxDistance = 3.0f;
|
const float maxDistance = 3.0f;
|
||||||
|
float distanceToPosition = bot->GetExactDist2d(position.GetPositionX(), position.GetPositionY());
|
||||||
|
|
||||||
if (bot->GetExactDist2d(position.x, position.y) > maxDistance)
|
if (distanceToPosition > maxDistance)
|
||||||
{
|
{
|
||||||
float dX = position.x - bot->GetPositionX();
|
float dX = position.GetPositionX() - bot->GetPositionX();
|
||||||
float dY = position.y - bot->GetPositionY();
|
float dY = position.GetPositionY() - bot->GetPositionY();
|
||||||
float dist = sqrt(dX * dX + dY * dY);
|
float moveX = bot->GetPositionX() + (dX / distanceToPosition) * maxDistance;
|
||||||
float moveX = bot->GetPositionX() + (dX / dist) * maxDistance;
|
float moveY = bot->GetPositionY() + (dY / distanceToPosition) * maxDistance;
|
||||||
float moveY = bot->GetPositionY() + (dY / dist) * maxDistance;
|
|
||||||
|
|
||||||
return MoveTo(bot->GetMapId(), moveX, moveY, position.z, false, false, false, false,
|
return MoveTo(MAGTHERIDON_MAP_ID, moveX, moveY, position.GetPositionZ(), false, false, false, false,
|
||||||
MovementPriority::MOVEMENT_COMBAT, true, false);
|
MovementPriority::MOVEMENT_COMBAT, true, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -175,7 +175,7 @@ bool MagtheridonMisdirectHellfireChannelers::Execute(Event event)
|
|||||||
switch (hunterIndex)
|
switch (hunterIndex)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
if (mainTank && channelerStar && channelerStar->IsAlive() &&
|
if (mainTank && channelerStar &&
|
||||||
channelerStar->GetVictim() != mainTank)
|
channelerStar->GetVictim() != mainTank)
|
||||||
{
|
{
|
||||||
if (botAI->CanCastSpell("misdirection", mainTank))
|
if (botAI->CanCastSpell("misdirection", mainTank))
|
||||||
@@ -190,7 +190,7 @@ bool MagtheridonMisdirectHellfireChannelers::Execute(Event event)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
if (mainTank && channelerCircle && channelerCircle->IsAlive() &&
|
if (mainTank && channelerCircle &&
|
||||||
channelerCircle->GetVictim() != mainTank)
|
channelerCircle->GetVictim() != mainTank)
|
||||||
{
|
{
|
||||||
if (botAI->CanCastSpell("misdirection", mainTank))
|
if (botAI->CanCastSpell("misdirection", mainTank))
|
||||||
@@ -215,90 +215,69 @@ bool MagtheridonAssignDPSPriorityAction::Execute(Event event)
|
|||||||
{
|
{
|
||||||
// Listed in order of priority
|
// Listed in order of priority
|
||||||
Creature* channelerSquare = GetChanneler(bot, SOUTH_CHANNELER);
|
Creature* channelerSquare = GetChanneler(bot, SOUTH_CHANNELER);
|
||||||
if (channelerSquare && channelerSquare->IsAlive())
|
if (channelerSquare)
|
||||||
{
|
{
|
||||||
SetRtiTarget(botAI, "square", channelerSquare);
|
SetRtiTarget(botAI, "square", channelerSquare);
|
||||||
|
|
||||||
if (bot->GetTarget() != channelerSquare->GetGUID())
|
if (bot->GetTarget() != channelerSquare->GetGUID())
|
||||||
{
|
|
||||||
bot->SetSelection(channelerSquare->GetGUID());
|
|
||||||
return Attack(channelerSquare);
|
return Attack(channelerSquare);
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Creature* channelerStar = GetChanneler(bot, WEST_CHANNELER);
|
Creature* channelerStar = GetChanneler(bot, WEST_CHANNELER);
|
||||||
if (channelerStar && channelerStar->IsAlive())
|
if (channelerStar)
|
||||||
{
|
{
|
||||||
SetRtiTarget(botAI, "star", channelerStar);
|
SetRtiTarget(botAI, "star", channelerStar);
|
||||||
|
|
||||||
if (bot->GetTarget() != channelerStar->GetGUID())
|
if (bot->GetTarget() != channelerStar->GetGUID())
|
||||||
{
|
|
||||||
bot->SetSelection(channelerStar->GetGUID());
|
|
||||||
return Attack(channelerStar);
|
return Attack(channelerStar);
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Creature* channelerCircle = GetChanneler(bot, EAST_CHANNELER);
|
Creature* channelerCircle = GetChanneler(bot, EAST_CHANNELER);
|
||||||
if (channelerCircle && channelerCircle->IsAlive())
|
if (channelerCircle)
|
||||||
{
|
{
|
||||||
SetRtiTarget(botAI, "circle", channelerCircle);
|
SetRtiTarget(botAI, "circle", channelerCircle);
|
||||||
|
|
||||||
if (bot->GetTarget() != channelerCircle->GetGUID())
|
if (bot->GetTarget() != channelerCircle->GetGUID())
|
||||||
{
|
|
||||||
bot->SetSelection(channelerCircle->GetGUID());
|
|
||||||
return Attack(channelerCircle);
|
return Attack(channelerCircle);
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Creature* channelerDiamond = GetChanneler(bot, NORTHWEST_CHANNELER);
|
Creature* channelerDiamond = GetChanneler(bot, NORTHWEST_CHANNELER);
|
||||||
if (channelerDiamond && channelerDiamond->IsAlive())
|
if (channelerDiamond)
|
||||||
{
|
{
|
||||||
SetRtiTarget(botAI, "diamond", channelerDiamond);
|
SetRtiTarget(botAI, "diamond", channelerDiamond);
|
||||||
|
|
||||||
if (bot->GetTarget() != channelerDiamond->GetGUID())
|
if (bot->GetTarget() != channelerDiamond->GetGUID())
|
||||||
{
|
|
||||||
bot->SetSelection(channelerDiamond->GetGUID());
|
|
||||||
return Attack(channelerDiamond);
|
return Attack(channelerDiamond);
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Creature* channelerTriangle = GetChanneler(bot, NORTHEAST_CHANNELER);
|
Creature* channelerTriangle = GetChanneler(bot, NORTHEAST_CHANNELER);
|
||||||
if (channelerTriangle && channelerTriangle->IsAlive())
|
if (channelerTriangle)
|
||||||
{
|
{
|
||||||
SetRtiTarget(botAI, "triangle", channelerTriangle);
|
SetRtiTarget(botAI, "triangle", channelerTriangle);
|
||||||
|
|
||||||
if (bot->GetTarget() != channelerTriangle->GetGUID())
|
if (bot->GetTarget() != channelerTriangle->GetGUID())
|
||||||
{
|
|
||||||
bot->SetSelection(channelerTriangle->GetGUID());
|
|
||||||
return Attack(channelerTriangle);
|
return Attack(channelerTriangle);
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Unit* magtheridon = AI_VALUE2(Unit*, "find target", "magtheridon");
|
Unit* magtheridon = AI_VALUE2(Unit*, "find target", "magtheridon");
|
||||||
if (magtheridon && !magtheridon->HasAura(SPELL_SHADOW_CAGE) &&
|
if (magtheridon && !magtheridon->HasAura(SPELL_SHADOW_CAGE) &&
|
||||||
(!channelerSquare || !channelerSquare->IsAlive()) &&
|
!channelerSquare && !channelerStar && !channelerCircle &&
|
||||||
(!channelerStar || !channelerStar->IsAlive()) &&
|
!channelerDiamond && !channelerTriangle)
|
||||||
(!channelerCircle || !channelerCircle->IsAlive()) &&
|
|
||||||
(!channelerDiamond || !channelerDiamond->IsAlive()) &&
|
|
||||||
(!channelerTriangle || !channelerTriangle->IsAlive()))
|
|
||||||
{
|
{
|
||||||
SetRtiTarget(botAI, "cross", magtheridon);
|
SetRtiTarget(botAI, "cross", magtheridon);
|
||||||
|
|
||||||
if (bot->GetTarget() != magtheridon->GetGUID())
|
if (bot->GetTarget() != magtheridon->GetGUID())
|
||||||
{
|
|
||||||
bot->SetSelection(magtheridon->GetGUID());
|
|
||||||
return Attack(magtheridon);
|
return Attack(magtheridon);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -343,15 +322,15 @@ bool MagtheridonWarlockCCBurningAbyssalAction::Execute(Event event)
|
|||||||
if (warlockIndex >= 0 && warlockIndex < abyssals.size())
|
if (warlockIndex >= 0 && warlockIndex < abyssals.size())
|
||||||
{
|
{
|
||||||
Unit* assignedAbyssal = abyssals[warlockIndex];
|
Unit* assignedAbyssal = abyssals[warlockIndex];
|
||||||
if (!assignedAbyssal->HasAura(SPELL_BANISH) && botAI->CanCastSpell(SPELL_BANISH, assignedAbyssal, true))
|
if (!botAI->HasAura("banish", assignedAbyssal) && botAI->CanCastSpell("banish", assignedAbyssal))
|
||||||
return botAI->CastSpell("banish", assignedAbyssal);
|
return botAI->CastSpell("banish", assignedAbyssal);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = warlocks.size(); i < abyssals.size(); ++i)
|
for (size_t i = warlocks.size(); i < abyssals.size(); ++i)
|
||||||
{
|
{
|
||||||
Unit* excessAbyssal = abyssals[i];
|
Unit* excessAbyssal = abyssals[i];
|
||||||
if (!excessAbyssal->HasAura(SPELL_BANISH) && !excessAbyssal->HasAura(SPELL_FEAR) &&
|
if (!botAI->HasAura("banish", excessAbyssal) && !botAI->HasAura("fear", excessAbyssal) &&
|
||||||
botAI->CanCastSpell(SPELL_FEAR, excessAbyssal, true))
|
botAI->CanCastSpell("fear", excessAbyssal))
|
||||||
return botAI->CastSpell("fear", excessAbyssal);
|
return botAI->CastSpell("fear", excessAbyssal);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -373,22 +352,20 @@ bool MagtheridonMainTankPositionBossAction::Execute(Event event)
|
|||||||
|
|
||||||
if (magtheridon->GetVictim() == bot)
|
if (magtheridon->GetVictim() == bot)
|
||||||
{
|
{
|
||||||
const Location& position = MagtheridonsLairLocations::MagtheridonTankPosition;
|
const Position& position = MAGTHERIDON_TANK_POSITION;
|
||||||
const float maxDistance = 2.0f;
|
const float maxDistance = 2.0f;
|
||||||
|
float distanceToPosition = bot->GetExactDist2d(position.GetPositionX(), position.GetPositionY());
|
||||||
|
|
||||||
if (bot->GetExactDist2d(position.x, position.y) > maxDistance)
|
if (distanceToPosition > maxDistance)
|
||||||
{
|
{
|
||||||
float dX = position.x - bot->GetPositionX();
|
float dX = position.GetPositionX() - bot->GetPositionX();
|
||||||
float dY = position.y - bot->GetPositionY();
|
float dY = position.GetPositionY() - bot->GetPositionY();
|
||||||
float dist = sqrt(dX * dX + dY * dY);
|
float moveX = bot->GetPositionX() + (dX / distanceToPosition) * maxDistance;
|
||||||
float moveX = bot->GetPositionX() + (dX / dist) * maxDistance;
|
float moveY = bot->GetPositionY() + (dY / distanceToPosition) * maxDistance;
|
||||||
float moveY = bot->GetPositionY() + (dY / dist) * maxDistance;
|
|
||||||
|
|
||||||
return MoveTo(bot->GetMapId(), moveX, moveY, position.z, false, false, false, false,
|
return MoveTo(MAGTHERIDON_MAP_ID, moveX, moveY, position.GetPositionZ(), false, false, false, false,
|
||||||
MovementPriority::MOVEMENT_COMBAT, true, true);
|
MovementPriority::MOVEMENT_COMBAT, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bot->SetFacingTo(position.orientation);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -440,13 +417,13 @@ bool MagtheridonSpreadRangedAction::Execute(Event event)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool isHealer = botAI->IsHeal(bot);
|
bool isHealer = botAI->IsHeal(bot);
|
||||||
const Location& center = isHealer
|
const Position& center = isHealer
|
||||||
? MagtheridonsLairLocations::HealerSpreadPosition
|
? HEALER_SPREAD_POSITION
|
||||||
: MagtheridonsLairLocations::RangedSpreadPosition;
|
: RANGED_SPREAD_POSITION;
|
||||||
float maxSpreadRadius = isHealer ? 15.0f : 20.0f;
|
float maxSpreadRadius = isHealer ? 15.0f : 20.0f;
|
||||||
float centerX = center.x;
|
float centerX = center.GetPositionX();
|
||||||
float centerY = center.y;
|
float centerY = center.GetPositionY();
|
||||||
float centerZ = bot->GetPositionZ();
|
float centerZ = center.GetPositionZ();
|
||||||
const float radiusBuffer = 3.0f;
|
const float radiusBuffer = 3.0f;
|
||||||
|
|
||||||
if (!initialPositions.count(bot->GetGUID()))
|
if (!initialPositions.count(bot->GetGUID()))
|
||||||
@@ -479,7 +456,7 @@ bool MagtheridonSpreadRangedAction::Execute(Event event)
|
|||||||
|
|
||||||
bot->AttackStop();
|
bot->AttackStop();
|
||||||
bot->InterruptNonMeleeSpells(false);
|
bot->InterruptNonMeleeSpells(false);
|
||||||
return MoveTo(bot->GetMapId(), destX, destY, destZ, false, false, false, false,
|
return MoveTo(MAGTHERIDON_MAP_ID, destX, destY, destZ, false, false, false, false,
|
||||||
MovementPriority::MOVEMENT_COMBAT, true, false);
|
MovementPriority::MOVEMENT_COMBAT, true, false);
|
||||||
}
|
}
|
||||||
hasReachedInitialPosition[bot->GetGUID()] = true;
|
hasReachedInitialPosition[bot->GetGUID()] = true;
|
||||||
@@ -499,7 +476,7 @@ bool MagtheridonSpreadRangedAction::Execute(Event event)
|
|||||||
{
|
{
|
||||||
bot->AttackStop();
|
bot->AttackStop();
|
||||||
bot->InterruptNonMeleeSpells(false);
|
bot->InterruptNonMeleeSpells(false);
|
||||||
return MoveTo(bot->GetMapId(), targetX, targetY, centerZ, false, false, false, false,
|
return MoveTo(MAGTHERIDON_MAP_ID, targetX, targetY, centerZ, false, false, false, false,
|
||||||
MovementPriority::MOVEMENT_COMBAT, true, false);
|
MovementPriority::MOVEMENT_COMBAT, true, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -593,7 +570,7 @@ bool MagtheridonUseManticronCubeAction::HandleWaitingPhase(const CubeInfo& cubeI
|
|||||||
{
|
{
|
||||||
bot->AttackStop();
|
bot->AttackStop();
|
||||||
bot->InterruptNonMeleeSpells(true);
|
bot->InterruptNonMeleeSpells(true);
|
||||||
return MoveTo(bot->GetMapId(), targetX, targetY, targetZ, false, false, false, false,
|
return MoveTo(MAGTHERIDON_MAP_ID, targetX, targetY, targetZ, false, false, false, false,
|
||||||
MovementPriority::MOVEMENT_COMBAT, true, false);
|
MovementPriority::MOVEMENT_COMBAT, true, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -603,7 +580,7 @@ bool MagtheridonUseManticronCubeAction::HandleWaitingPhase(const CubeInfo& cubeI
|
|||||||
float fallbackY = cubeInfo.y + sin(angle) * safeWaitDistance;
|
float fallbackY = cubeInfo.y + sin(angle) * safeWaitDistance;
|
||||||
float fallbackZ = bot->GetPositionZ();
|
float fallbackZ = bot->GetPositionZ();
|
||||||
|
|
||||||
return MoveTo(bot->GetMapId(), fallbackX, fallbackY, fallbackZ, false, false, false, false,
|
return MoveTo(MAGTHERIDON_MAP_ID, fallbackX, fallbackY, fallbackZ, false, false, false, false,
|
||||||
MovementPriority::MOVEMENT_COMBAT, true, false);
|
MovementPriority::MOVEMENT_COMBAT, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -638,7 +615,7 @@ bool MagtheridonUseManticronCubeAction::HandleCubeInteraction(const CubeInfo& cu
|
|||||||
|
|
||||||
bot->AttackStop();
|
bot->AttackStop();
|
||||||
bot->InterruptNonMeleeSpells(true);
|
bot->InterruptNonMeleeSpells(true);
|
||||||
return MoveTo(bot->GetMapId(), targetX, targetY, targetZ, false, false, false, false,
|
return MoveTo(MAGTHERIDON_MAP_ID, targetX, targetY, targetZ, false, false, false, false,
|
||||||
MovementPriority::MOVEMENT_FORCED, true, false);
|
MovementPriority::MOVEMENT_FORCED, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -663,14 +640,14 @@ bool MagtheridonManageTimersAndAssignmentsAction::Execute(Event event)
|
|||||||
magtheridon->FindCurrentSpellBySpellId(SPELL_BLAST_NOVA);
|
magtheridon->FindCurrentSpellBySpellId(SPELL_BLAST_NOVA);
|
||||||
bool lastBlastNova = lastBlastNovaState[instanceId];
|
bool lastBlastNova = lastBlastNovaState[instanceId];
|
||||||
|
|
||||||
if (lastBlastNova && !blastNovaActive && IsInstanceTimerManager(botAI, bot))
|
if (lastBlastNova && !blastNovaActive && IsMechanicTrackerBot(botAI, bot, MAGTHERIDON_MAP_ID, nullptr))
|
||||||
blastNovaTimer[instanceId] = now;
|
blastNovaTimer[instanceId] = now;
|
||||||
|
|
||||||
lastBlastNovaState[instanceId] = blastNovaActive;
|
lastBlastNovaState[instanceId] = blastNovaActive;
|
||||||
|
|
||||||
if (!magtheridon->HasAura(SPELL_SHADOW_CAGE))
|
if (!magtheridon->HasAura(SPELL_SHADOW_CAGE))
|
||||||
{
|
{
|
||||||
if (IsInstanceTimerManager(botAI, bot))
|
if (IsMechanicTrackerBot(botAI, bot, MAGTHERIDON_MAP_ID, nullptr))
|
||||||
{
|
{
|
||||||
spreadWaitTimer.try_emplace(instanceId, now);
|
spreadWaitTimer.try_emplace(instanceId, now);
|
||||||
blastNovaTimer.try_emplace(instanceId, now);
|
blastNovaTimer.try_emplace(instanceId, now);
|
||||||
@@ -679,11 +656,12 @@ bool MagtheridonManageTimersAndAssignmentsAction::Execute(Event event)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MagtheridonSpreadRangedAction::initialPositions.clear();
|
ObjectGuid guid = bot->GetGUID();
|
||||||
MagtheridonSpreadRangedAction::hasReachedInitialPosition.clear();
|
MagtheridonSpreadRangedAction::initialPositions.erase(guid);
|
||||||
botToCubeAssignment.clear();
|
MagtheridonSpreadRangedAction::hasReachedInitialPosition.erase(guid);
|
||||||
|
botToCubeAssignment.erase(guid);
|
||||||
|
|
||||||
if (IsInstanceTimerManager(botAI, bot))
|
if (IsMechanicTrackerBot(botAI, bot, MAGTHERIDON_MAP_ID, nullptr))
|
||||||
{
|
{
|
||||||
spreadWaitTimer.erase(instanceId);
|
spreadWaitTimer.erase(instanceId);
|
||||||
blastNovaTimer.erase(instanceId);
|
blastNovaTimer.erase(instanceId);
|
||||||
|
|||||||
@@ -6,8 +6,6 @@
|
|||||||
#include "AttackAction.h"
|
#include "AttackAction.h"
|
||||||
#include "MovementActions.h"
|
#include "MovementActions.h"
|
||||||
|
|
||||||
using namespace MagtheridonHelpers;
|
|
||||||
|
|
||||||
class MagtheridonMainTankAttackFirstThreeChannelersAction : public AttackAction
|
class MagtheridonMainTankAttackFirstThreeChannelersAction : public AttackAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -85,8 +83,8 @@ public:
|
|||||||
private:
|
private:
|
||||||
bool HandleCubeRelease(Unit* magtheridon, GameObject* cube);
|
bool HandleCubeRelease(Unit* magtheridon, GameObject* cube);
|
||||||
bool ShouldActivateCubeLogic(Unit* magtheridon);
|
bool ShouldActivateCubeLogic(Unit* magtheridon);
|
||||||
bool HandleWaitingPhase(const CubeInfo& cubeInfo);
|
bool HandleWaitingPhase(const MagtheridonHelpers::CubeInfo& cubeInfo);
|
||||||
bool HandleCubeInteraction(const CubeInfo& cubeInfo, GameObject* cube);
|
bool HandleCubeInteraction(const MagtheridonHelpers::CubeInfo& cubeInfo, GameObject* cube);
|
||||||
};
|
};
|
||||||
|
|
||||||
class MagtheridonManageTimersAndAssignmentsAction : public Action
|
class MagtheridonManageTimersAndAssignmentsAction : public Action
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include "GenericSpellActions.h"
|
#include "GenericSpellActions.h"
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
#include "WarlockActions.h"
|
#include "WarlockActions.h"
|
||||||
|
#include "WipeAction.h"
|
||||||
|
|
||||||
using namespace MagtheridonHelpers;
|
using namespace MagtheridonHelpers;
|
||||||
|
|
||||||
@@ -24,10 +25,10 @@ float MagtheridonUseManticronCubeMultiplier::GetValue(Action* action)
|
|||||||
auto it = botToCubeAssignment.find(bot->GetGUID());
|
auto it = botToCubeAssignment.find(bot->GetGUID());
|
||||||
if (it != botToCubeAssignment.end())
|
if (it != botToCubeAssignment.end())
|
||||||
{
|
{
|
||||||
if (dynamic_cast<MagtheridonUseManticronCubeAction*>(action))
|
if (dynamic_cast<WipeAction*>(action))
|
||||||
return 1.0f;
|
return 1.0f;
|
||||||
|
else if (!dynamic_cast<MagtheridonUseManticronCubeAction*>(action))
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,28 +42,31 @@ float MagtheridonWaitToAttackMultiplier::GetValue(Action* action)
|
|||||||
if (!magtheridon || magtheridon->HasAura(SPELL_SHADOW_CAGE))
|
if (!magtheridon || magtheridon->HasAura(SPELL_SHADOW_CAGE))
|
||||||
return 1.0f;
|
return 1.0f;
|
||||||
|
|
||||||
|
if (botAI->IsMainTank(bot))
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
const uint8 dpsWaitSeconds = 6;
|
const uint8 dpsWaitSeconds = 6;
|
||||||
auto it = dpsWaitTimer.find(magtheridon->GetMap()->GetInstanceId());
|
auto it = dpsWaitTimer.find(magtheridon->GetMap()->GetInstanceId());
|
||||||
if (it == dpsWaitTimer.end() ||
|
if (it == dpsWaitTimer.end() ||
|
||||||
(time(nullptr) - it->second) < dpsWaitSeconds)
|
(time(nullptr) - it->second) < dpsWaitSeconds)
|
||||||
{
|
{
|
||||||
if (!botAI->IsMainTank(bot) && (dynamic_cast<AttackAction*>(action) ||
|
if (dynamic_cast<AttackAction*>(action) ||
|
||||||
(!botAI->IsHeal(bot) && dynamic_cast<CastSpellAction*>(action))))
|
(!botAI->IsHeal(bot) && dynamic_cast<CastSpellAction*>(action)))
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1.0f;
|
return 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
// No tank assist for offtanks during the channeler phase
|
|
||||||
// So they don't try to pull channelers from each other or the main tank
|
|
||||||
float MagtheridonDisableOffTankAssistMultiplier::GetValue(Action* action)
|
float MagtheridonDisableOffTankAssistMultiplier::GetValue(Action* action)
|
||||||
{
|
{
|
||||||
Unit* magtheridon = AI_VALUE2(Unit*, "find target", "magtheridon");
|
Unit* magtheridon = AI_VALUE2(Unit*, "find target", "magtheridon");
|
||||||
Unit* channeler = AI_VALUE2(Unit*, "find target", "hellfire channeler");
|
|
||||||
if (!magtheridon)
|
if (!magtheridon)
|
||||||
return 1.0f;
|
return 1.0f;
|
||||||
|
|
||||||
|
if (bot->GetVictim() == nullptr)
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
if ((botAI->IsAssistTankOfIndex(bot, 0) || botAI->IsAssistTankOfIndex(bot, 1)) &&
|
if ((botAI->IsAssistTankOfIndex(bot, 0) || botAI->IsAssistTankOfIndex(bot, 1)) &&
|
||||||
dynamic_cast<TankAssistAction*>(action))
|
dynamic_cast<TankAssistAction*>(action))
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ bool MagtheridonNWChannelerEngagedByFirstAssistTankTrigger::IsActive()
|
|||||||
Creature* channelerDiamond = GetChanneler(bot, NORTHWEST_CHANNELER);
|
Creature* channelerDiamond = GetChanneler(bot, NORTHWEST_CHANNELER);
|
||||||
|
|
||||||
return magtheridon && botAI->IsAssistTankOfIndex(bot, 0) &&
|
return magtheridon && botAI->IsAssistTankOfIndex(bot, 0) &&
|
||||||
channelerDiamond && channelerDiamond->IsAlive();
|
channelerDiamond;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MagtheridonNEChannelerEngagedBySecondAssistTankTrigger::IsActive()
|
bool MagtheridonNEChannelerEngagedBySecondAssistTankTrigger::IsActive()
|
||||||
@@ -27,7 +27,7 @@ bool MagtheridonNEChannelerEngagedBySecondAssistTankTrigger::IsActive()
|
|||||||
Creature* channelerTriangle = GetChanneler(bot, NORTHEAST_CHANNELER);
|
Creature* channelerTriangle = GetChanneler(bot, NORTHEAST_CHANNELER);
|
||||||
|
|
||||||
return magtheridon && botAI->IsAssistTankOfIndex(bot, 1) &&
|
return magtheridon && botAI->IsAssistTankOfIndex(bot, 1) &&
|
||||||
channelerTriangle && channelerTriangle->IsAlive();
|
channelerTriangle;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MagtheridonPullingWestAndEastChannelersTrigger::IsActive()
|
bool MagtheridonPullingWestAndEastChannelersTrigger::IsActive()
|
||||||
@@ -38,8 +38,7 @@ bool MagtheridonPullingWestAndEastChannelersTrigger::IsActive()
|
|||||||
Creature* channelerCircle = GetChanneler(bot, EAST_CHANNELER);
|
Creature* channelerCircle = GetChanneler(bot, EAST_CHANNELER);
|
||||||
|
|
||||||
return magtheridon && bot->getClass() == CLASS_HUNTER &&
|
return magtheridon && bot->getClass() == CLASS_HUNTER &&
|
||||||
((channelerStar && channelerStar->IsAlive()) ||
|
(channelerStar || channelerCircle);
|
||||||
(channelerCircle && channelerCircle->IsAlive()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MagtheridonDeterminingKillOrderTrigger::IsActive()
|
bool MagtheridonDeterminingKillOrderTrigger::IsActive()
|
||||||
@@ -51,12 +50,11 @@ bool MagtheridonDeterminingKillOrderTrigger::IsActive()
|
|||||||
Creature* channelerTriangle = GetChanneler(bot, NORTHEAST_CHANNELER);
|
Creature* channelerTriangle = GetChanneler(bot, NORTHEAST_CHANNELER);
|
||||||
|
|
||||||
if (!magtheridon || botAI->IsHeal(bot) || botAI->IsMainTank(bot) ||
|
if (!magtheridon || botAI->IsHeal(bot) || botAI->IsMainTank(bot) ||
|
||||||
(botAI->IsAssistTankOfIndex(bot, 0) && channelerDiamond && channelerDiamond->IsAlive()) ||
|
(botAI->IsAssistTankOfIndex(bot, 0) && channelerDiamond) ||
|
||||||
(botAI->IsAssistTankOfIndex(bot, 1) && channelerTriangle && channelerTriangle->IsAlive()))
|
(botAI->IsAssistTankOfIndex(bot, 1) && channelerTriangle))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return (channeler && channeler->IsAlive()) || (magtheridon &&
|
return channeler || (magtheridon && !magtheridon->HasAura(SPELL_SHADOW_CAGE));
|
||||||
!magtheridon->HasAura(SPELL_SHADOW_CAGE));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MagtheridonBurningAbyssalSpawnedTrigger::IsActive()
|
bool MagtheridonBurningAbyssalSpawnedTrigger::IsActive()
|
||||||
@@ -84,10 +82,8 @@ bool MagtheridonBossEngagedByMainTankTrigger::IsActive()
|
|||||||
bool MagtheridonBossEngagedByRangedTrigger::IsActive()
|
bool MagtheridonBossEngagedByRangedTrigger::IsActive()
|
||||||
{
|
{
|
||||||
Unit* magtheridon = AI_VALUE2(Unit*, "find target", "magtheridon");
|
Unit* magtheridon = AI_VALUE2(Unit*, "find target", "magtheridon");
|
||||||
Unit* channeler = AI_VALUE2(Unit*, "find target", "hellfire channeler");
|
|
||||||
|
|
||||||
return magtheridon && botAI->IsRanged(bot) &&
|
return magtheridon && !magtheridon->HasAura(SPELL_SHADOW_CAGE) && botAI->IsRanged(bot);
|
||||||
!(channeler && channeler->IsAlive());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MagtheridonIncomingBlastNovaTrigger::IsActive()
|
bool MagtheridonIncomingBlastNovaTrigger::IsActive()
|
||||||
@@ -122,7 +118,5 @@ bool MagtheridonIncomingBlastNovaTrigger::IsActive()
|
|||||||
|
|
||||||
bool MagtheridonNeedToManageTimersAndAssignmentsTrigger::IsActive()
|
bool MagtheridonNeedToManageTimersAndAssignmentsTrigger::IsActive()
|
||||||
{
|
{
|
||||||
Unit* magtheridon = AI_VALUE2(Unit*, "find target", "magtheridon");
|
return AI_VALUE2(Unit*, "find target", "magtheridon");
|
||||||
|
|
||||||
return magtheridon;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,18 @@
|
|||||||
#include "RaidMagtheridonHelpers.h"
|
#include "RaidMagtheridonHelpers.h"
|
||||||
#include "Creature.h"
|
#include "Creature.h"
|
||||||
#include "GameObject.h"
|
#include "GameObject.h"
|
||||||
#include "GroupReference.h"
|
|
||||||
#include "Map.h"
|
#include "Map.h"
|
||||||
#include "ObjectGuid.h"
|
#include "ObjectGuid.h"
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
|
|
||||||
namespace MagtheridonHelpers
|
namespace MagtheridonHelpers
|
||||||
{
|
{
|
||||||
namespace MagtheridonsLairLocations
|
const Position WAITING_FOR_MAGTHERIDON_POSITION = { 1.359f, 2.048f, -0.406f, 3.135f };
|
||||||
{
|
const Position MAGTHERIDON_TANK_POSITION = { 22.827f, 2.105f, -0.406f, 3.135f };
|
||||||
const Location WaitingForMagtheridonPosition = { 1.359f, 2.048f, -0.406f, 3.135f };
|
const Position NW_CHANNELER_TANK_POSITION = { -11.764f, 30.818f, -0.411f, 0.0f };
|
||||||
const Location MagtheridonTankPosition = { 22.827f, 2.105f, -0.406f, 3.135f };
|
const Position NE_CHANNELER_TANK_POSITION = { -12.490f, -26.211f, -0.411f, 0.0f };
|
||||||
const Location NWChannelerTankPosition = { -11.764f, 30.818f, -0.411f, 0.0f };
|
const Position RANGED_SPREAD_POSITION = { -14.890f, 1.995f, -0.406f, 0.0f };
|
||||||
const Location NEChannelerTankPosition = { -12.490f, -26.211f, -0.411f, 0.0f };
|
const Position HEALER_SPREAD_POSITION = { -2.265f, 1.874f, -0.404f, 0.0f };
|
||||||
const Location RangedSpreadPosition = { -14.890f, 1.995f, -0.406f, 0.0f };
|
|
||||||
const Location HealerSpreadPosition = { -2.265f, 1.874f, -0.404f, 0.0f };
|
|
||||||
}
|
|
||||||
|
|
||||||
// Identify channelers by their database GUIDs
|
// Identify channelers by their database GUIDs
|
||||||
Creature* GetChanneler(Player* bot, uint32 dbGuid)
|
Creature* GetChanneler(Player* bot, uint32 dbGuid)
|
||||||
@@ -29,63 +25,11 @@ namespace MagtheridonHelpers
|
|||||||
if (it == map->GetCreatureBySpawnIdStore().end())
|
if (it == map->GetCreatureBySpawnIdStore().end())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
return it->second;
|
Creature* channeler = it->second;
|
||||||
}
|
if (!channeler->IsAlive())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
void MarkTargetWithIcon(Player* bot, Unit* target, uint8 iconId)
|
return channeler;
|
||||||
{
|
|
||||||
Group* group = bot->GetGroup();
|
|
||||||
if (!target || !group)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ObjectGuid currentGuid = group->GetTargetIcon(iconId);
|
|
||||||
if (currentGuid != target->GetGUID())
|
|
||||||
group->SetTargetIcon(iconId, bot->GetGUID(), target->GetGUID());
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetRtiTarget(PlayerbotAI* botAI, const std::string& rtiName, Unit* target)
|
|
||||||
{
|
|
||||||
if (!target)
|
|
||||||
return;
|
|
||||||
|
|
||||||
std::string currentRti = botAI->GetAiObjectContext()->GetValue<std::string>("rti")->Get();
|
|
||||||
Unit* currentTarget = botAI->GetAiObjectContext()->GetValue<Unit*>("rti target")->Get();
|
|
||||||
|
|
||||||
if (currentRti != rtiName || currentTarget != target)
|
|
||||||
{
|
|
||||||
botAI->GetAiObjectContext()->GetValue<std::string>("rti")->Set(rtiName);
|
|
||||||
botAI->GetAiObjectContext()->GetValue<Unit*>("rti target")->Set(target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MarkTargetWithSquare(Player* bot, Unit* target)
|
|
||||||
{
|
|
||||||
MarkTargetWithIcon(bot, target, RtiTargetValue::squareIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MarkTargetWithStar(Player* bot, Unit* target)
|
|
||||||
{
|
|
||||||
MarkTargetWithIcon(bot, target, RtiTargetValue::starIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MarkTargetWithCircle(Player* bot, Unit* target)
|
|
||||||
{
|
|
||||||
MarkTargetWithIcon(bot, target, RtiTargetValue::circleIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MarkTargetWithDiamond(Player* bot, Unit* target)
|
|
||||||
{
|
|
||||||
MarkTargetWithIcon(bot, target, RtiTargetValue::diamondIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MarkTargetWithTriangle(Player* bot, Unit* target)
|
|
||||||
{
|
|
||||||
MarkTargetWithIcon(bot, target, RtiTargetValue::triangleIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MarkTargetWithCross(Player* bot, Unit* target)
|
|
||||||
{
|
|
||||||
MarkTargetWithIcon(bot, target, RtiTargetValue::crossIndex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<uint32> MANTICRON_CUBE_DB_GUIDS = { 43157, 43158, 43159, 43160, 43161 };
|
const std::vector<uint32> MANTICRON_CUBE_DB_GUIDS = { 43157, 43158, 43159, 43160, 43161 };
|
||||||
@@ -208,19 +152,4 @@ namespace MagtheridonHelpers
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsInstanceTimerManager(PlayerbotAI* botAI, Player* bot)
|
|
||||||
{
|
|
||||||
if (Group* group = bot->GetGroup())
|
|
||||||
{
|
|
||||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
|
||||||
{
|
|
||||||
Player* member = ref->GetSource();
|
|
||||||
if (member && member->IsAlive() && botAI->IsDps(member) && GET_PLAYERBOT_AI(member))
|
|
||||||
return member == bot;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
#include "Group.h"
|
#include "Group.h"
|
||||||
#include "ObjectGuid.h"
|
#include "ObjectGuid.h"
|
||||||
#include "PlayerbotAI.h"
|
#include "PlayerbotAI.h"
|
||||||
#include "RtiTargetValue.h"
|
|
||||||
|
|
||||||
namespace MagtheridonHelpers
|
namespace MagtheridonHelpers
|
||||||
{
|
{
|
||||||
@@ -19,10 +18,6 @@ namespace MagtheridonHelpers
|
|||||||
SPELL_BLAST_NOVA = 30616,
|
SPELL_BLAST_NOVA = 30616,
|
||||||
SPELL_SHADOW_GRASP = 30410,
|
SPELL_SHADOW_GRASP = 30410,
|
||||||
|
|
||||||
// Warlock
|
|
||||||
SPELL_BANISH = 18647,
|
|
||||||
SPELL_FEAR = 6215,
|
|
||||||
|
|
||||||
// Hunter
|
// Hunter
|
||||||
SPELL_MISDIRECTION = 35079,
|
SPELL_MISDIRECTION = 35079,
|
||||||
};
|
};
|
||||||
@@ -38,6 +33,7 @@ namespace MagtheridonHelpers
|
|||||||
GO_BLAZE = 181832,
|
GO_BLAZE = 181832,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constexpr uint32 MAGTHERIDON_MAP_ID = 544;
|
||||||
constexpr uint32 SOUTH_CHANNELER = 90978;
|
constexpr uint32 SOUTH_CHANNELER = 90978;
|
||||||
constexpr uint32 WEST_CHANNELER = 90979;
|
constexpr uint32 WEST_CHANNELER = 90979;
|
||||||
constexpr uint32 NORTHWEST_CHANNELER = 90980;
|
constexpr uint32 NORTHWEST_CHANNELER = 90980;
|
||||||
@@ -45,31 +41,14 @@ namespace MagtheridonHelpers
|
|||||||
constexpr uint32 NORTHEAST_CHANNELER = 90981;
|
constexpr uint32 NORTHEAST_CHANNELER = 90981;
|
||||||
|
|
||||||
Creature* GetChanneler(Player* bot, uint32 dbGuid);
|
Creature* GetChanneler(Player* bot, uint32 dbGuid);
|
||||||
void MarkTargetWithIcon(Player* bot, Unit* target, uint8 iconId);
|
|
||||||
void MarkTargetWithSquare(Player* bot, Unit* target);
|
|
||||||
void MarkTargetWithStar(Player* bot, Unit* target);
|
|
||||||
void MarkTargetWithCircle(Player* bot, Unit* target);
|
|
||||||
void MarkTargetWithDiamond(Player* bot, Unit* target);
|
|
||||||
void MarkTargetWithTriangle(Player* bot, Unit* target);
|
|
||||||
void MarkTargetWithCross(Player* bot, Unit* target);
|
|
||||||
void SetRtiTarget(PlayerbotAI* botAI, const std::string& rtiName, Unit* target);
|
|
||||||
bool IsSafeFromMagtheridonHazards(PlayerbotAI* botAI, Player* bot, float x, float y, float z);
|
bool IsSafeFromMagtheridonHazards(PlayerbotAI* botAI, Player* bot, float x, float y, float z);
|
||||||
bool IsInstanceTimerManager(PlayerbotAI* botAI, Player* bot);
|
|
||||||
|
|
||||||
struct Location
|
extern const Position WAITING_FOR_MAGTHERIDON_POSITION;
|
||||||
{
|
extern const Position MAGTHERIDON_TANK_POSITION;
|
||||||
float x, y, z, orientation;
|
extern const Position NW_CHANNELER_TANK_POSITION;
|
||||||
};
|
extern const Position NE_CHANNELER_TANK_POSITION;
|
||||||
|
extern const Position RANGED_SPREAD_POSITION;
|
||||||
namespace MagtheridonsLairLocations
|
extern const Position HEALER_SPREAD_POSITION;
|
||||||
{
|
|
||||||
extern const Location WaitingForMagtheridonPosition;
|
|
||||||
extern const Location MagtheridonTankPosition;
|
|
||||||
extern const Location NWChannelerTankPosition;
|
|
||||||
extern const Location NEChannelerTankPosition;
|
|
||||||
extern const Location RangedSpreadPosition;
|
|
||||||
extern const Location HealerSpreadPosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct CubeInfo
|
struct CubeInfo
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#define _PLAYERBOT_RAIDMCACTIONCONTEXT_H
|
#define _PLAYERBOT_RAIDMCACTIONCONTEXT_H
|
||||||
|
|
||||||
#include "Action.h"
|
#include "Action.h"
|
||||||
|
#include "BossAuraActions.h"
|
||||||
#include "NamedObjectContext.h"
|
#include "NamedObjectContext.h"
|
||||||
#include "RaidMcActions.h"
|
#include "RaidMcActions.h"
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#define _PLAYERBOT_RAIDMCTRIGGERCONTEXT_H
|
#define _PLAYERBOT_RAIDMCTRIGGERCONTEXT_H
|
||||||
|
|
||||||
#include "AiObjectContext.h"
|
#include "AiObjectContext.h"
|
||||||
|
#include "BossAuraTriggers.h"
|
||||||
#include "NamedObjectContext.h"
|
#include "NamedObjectContext.h"
|
||||||
#include "RaidMcTriggers.h"
|
#include "RaidMcTriggers.h"
|
||||||
|
|
||||||
|
|||||||
142
src/Ai/Raid/RaidBossHelpers.cpp
Normal file
142
src/Ai/Raid/RaidBossHelpers.cpp
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
#include "RaidBossHelpers.h"
|
||||||
|
#include "Playerbots.h"
|
||||||
|
#include "RtiTargetValue.h"
|
||||||
|
|
||||||
|
// Functions to mark targets with raid target icons
|
||||||
|
// Note that these functions do not allow the player to change the icon during the encounter
|
||||||
|
void MarkTargetWithIcon(Player* bot, Unit* target, uint8 iconId)
|
||||||
|
{
|
||||||
|
if (!target)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (Group* group = bot->GetGroup())
|
||||||
|
{
|
||||||
|
ObjectGuid currentGuid = group->GetTargetIcon(iconId);
|
||||||
|
if (currentGuid != target->GetGUID())
|
||||||
|
group->SetTargetIcon(iconId, bot->GetGUID(), target->GetGUID());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MarkTargetWithSkull(Player* bot, Unit* target)
|
||||||
|
{
|
||||||
|
MarkTargetWithIcon(bot, target, RtiTargetValue::skullIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MarkTargetWithSquare(Player* bot, Unit* target)
|
||||||
|
{
|
||||||
|
MarkTargetWithIcon(bot, target, RtiTargetValue::squareIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MarkTargetWithStar(Player* bot, Unit* target)
|
||||||
|
{
|
||||||
|
MarkTargetWithIcon(bot, target, RtiTargetValue::starIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MarkTargetWithCircle(Player* bot, Unit* target)
|
||||||
|
{
|
||||||
|
MarkTargetWithIcon(bot, target, RtiTargetValue::circleIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MarkTargetWithDiamond(Player* bot, Unit* target)
|
||||||
|
{
|
||||||
|
MarkTargetWithIcon(bot, target, RtiTargetValue::diamondIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MarkTargetWithTriangle(Player* bot, Unit* target)
|
||||||
|
{
|
||||||
|
MarkTargetWithIcon(bot, target, RtiTargetValue::triangleIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MarkTargetWithCross(Player* bot, Unit* target)
|
||||||
|
{
|
||||||
|
MarkTargetWithIcon(bot, target, RtiTargetValue::crossIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MarkTargetWithMoon(Player* bot, Unit* target)
|
||||||
|
{
|
||||||
|
MarkTargetWithIcon(bot, target, RtiTargetValue::moonIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For bots to set their raid target icon to the specified icon on the specified target
|
||||||
|
void SetRtiTarget(PlayerbotAI* botAI, const std::string& rtiName, Unit* target)
|
||||||
|
{
|
||||||
|
if (!target)
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::string currentRti = botAI->GetAiObjectContext()->GetValue<std::string>("rti")->Get();
|
||||||
|
Unit* currentTarget = botAI->GetAiObjectContext()->GetValue<Unit*>("rti target")->Get();
|
||||||
|
|
||||||
|
if (currentRti != rtiName || currentTarget != target)
|
||||||
|
{
|
||||||
|
botAI->GetAiObjectContext()->GetValue<std::string>("rti")->Set(rtiName);
|
||||||
|
botAI->GetAiObjectContext()->GetValue<Unit*>("rti target")->Set(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the first alive DPS bot in the specified instance map, excluding any specified bot
|
||||||
|
// Intended for purposes of storing and erasing timers and trackers in associative containers
|
||||||
|
bool IsMechanicTrackerBot(PlayerbotAI* botAI, Player* bot, uint32 mapId, Player* exclude)
|
||||||
|
{
|
||||||
|
if (Group* group = bot->GetGroup())
|
||||||
|
{
|
||||||
|
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||||
|
{
|
||||||
|
Player* member = ref->GetSource();
|
||||||
|
if (!member || !member->IsAlive() || member->GetMapId() != mapId ||
|
||||||
|
!GET_PLAYERBOT_AI(member) || !botAI->IsDps(member))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (member != exclude)
|
||||||
|
return member == bot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the first matching alive unit from a cell search of nearby npcs
|
||||||
|
// More responsive than "find target," but performance cost is much higher
|
||||||
|
// Re: using the third parameter (false by default), some units are never considered
|
||||||
|
// to be in combat (e.g., totems)
|
||||||
|
Unit* GetFirstAliveUnitByEntry(PlayerbotAI* botAI, uint32 entry, bool requireInCombat)
|
||||||
|
{
|
||||||
|
auto const& npcs =
|
||||||
|
botAI->GetAiObjectContext()->GetValue<GuidVector>("nearest npcs")->Get();
|
||||||
|
for (auto const& npcGuid : npcs)
|
||||||
|
{
|
||||||
|
Unit* unit = botAI->GetUnit(npcGuid);
|
||||||
|
if (unit && unit->IsAlive() && unit->GetEntry() == entry)
|
||||||
|
{
|
||||||
|
if (!requireInCombat || unit->IsInCombat())
|
||||||
|
return unit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the nearest alive player (human or bot) within the specified radius
|
||||||
|
Unit* GetNearestPlayerInRadius(Player* bot, float radius)
|
||||||
|
{
|
||||||
|
Unit* nearestPlayer = nullptr;
|
||||||
|
float nearestDistance = radius;
|
||||||
|
|
||||||
|
if (Group* group = bot->GetGroup())
|
||||||
|
{
|
||||||
|
for (GroupReference* ref = group->GetFirstMember(); ref != nullptr; ref = ref->next())
|
||||||
|
{
|
||||||
|
Player* member = ref->GetSource();
|
||||||
|
if (!member || !member->IsAlive() || member == bot)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
float distance = bot->GetExactDist2d(member);
|
||||||
|
if (distance < nearestDistance)
|
||||||
|
{
|
||||||
|
nearestDistance = distance;
|
||||||
|
nearestPlayer = member;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nearestPlayer;
|
||||||
|
}
|
||||||
21
src/Ai/Raid/RaidBossHelpers.h
Normal file
21
src/Ai/Raid/RaidBossHelpers.h
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#ifndef _PLAYERBOT_RAIDBOSSHELPERS_H_
|
||||||
|
#define _PLAYERBOT_RAIDBOSSHELPERS_H_
|
||||||
|
|
||||||
|
#include "AiObject.h"
|
||||||
|
#include "Unit.h"
|
||||||
|
|
||||||
|
void MarkTargetWithIcon(Player* bot, Unit* target, uint8 iconId);
|
||||||
|
void MarkTargetWithSkull(Player* bot, Unit* target);
|
||||||
|
void MarkTargetWithSquare(Player* bot, Unit* target);
|
||||||
|
void MarkTargetWithStar(Player* bot, Unit* target);
|
||||||
|
void MarkTargetWithCircle(Player* bot, Unit* target);
|
||||||
|
void MarkTargetWithDiamond(Player* bot, Unit* target);
|
||||||
|
void MarkTargetWithTriangle(Player* bot, Unit* target);
|
||||||
|
void MarkTargetWithCross(Player* bot, Unit* target);
|
||||||
|
void MarkTargetWithMoon(Player* bot, Unit* target);
|
||||||
|
void SetRtiTarget(PlayerbotAI* botAI, const std::string& rtiName, Unit* target);
|
||||||
|
bool IsMechanicTrackerBot(PlayerbotAI* botAI, Player* bot, uint32 mapId, Player* exclude = nullptr);
|
||||||
|
Unit* GetFirstAliveUnitByEntry(PlayerbotAI* botAI, uint32 entry, bool requireInCombat = false);
|
||||||
|
Unit* GetNearestPlayerInRadius(Player* bot, float radius);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -29,7 +29,7 @@ public:
|
|||||||
creators["wotlk-os"] = &RaidStrategyContext::wotlk_os;
|
creators["wotlk-os"] = &RaidStrategyContext::wotlk_os;
|
||||||
creators["wotlk-eoe"] = &RaidStrategyContext::wotlk_eoe;
|
creators["wotlk-eoe"] = &RaidStrategyContext::wotlk_eoe;
|
||||||
creators["voa"] = &RaidStrategyContext::voa;
|
creators["voa"] = &RaidStrategyContext::voa;
|
||||||
creators["uld"] = &RaidStrategyContext::uld;
|
creators["ulduar"] = &RaidStrategyContext::ulduar;
|
||||||
creators["onyxia"] = &RaidStrategyContext::onyxia;
|
creators["onyxia"] = &RaidStrategyContext::onyxia;
|
||||||
creators["icc"] = &RaidStrategyContext::icc;
|
creators["icc"] = &RaidStrategyContext::icc;
|
||||||
}
|
}
|
||||||
@@ -45,7 +45,7 @@ private:
|
|||||||
static Strategy* wotlk_eoe(PlayerbotAI* botAI) { return new RaidEoEStrategy(botAI); }
|
static Strategy* wotlk_eoe(PlayerbotAI* botAI) { return new RaidEoEStrategy(botAI); }
|
||||||
static Strategy* voa(PlayerbotAI* botAI) { return new RaidVoAStrategy(botAI); }
|
static Strategy* voa(PlayerbotAI* botAI) { return new RaidVoAStrategy(botAI); }
|
||||||
static Strategy* onyxia(PlayerbotAI* botAI) { return new RaidOnyxiaStrategy(botAI); }
|
static Strategy* onyxia(PlayerbotAI* botAI) { return new RaidOnyxiaStrategy(botAI); }
|
||||||
static Strategy* uld(PlayerbotAI* botAI) { return new RaidUlduarStrategy(botAI); }
|
static Strategy* ulduar(PlayerbotAI* botAI) { return new RaidUlduarStrategy(botAI); }
|
||||||
static Strategy* icc(PlayerbotAI* botAI) { return new RaidIccStrategy(botAI); }
|
static Strategy* icc(PlayerbotAI* botAI) { return new RaidIccStrategy(botAI); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
#include "GameObject.h"
|
#include "GameObject.h"
|
||||||
#include "Group.h"
|
#include "Group.h"
|
||||||
#include "LastMovementValue.h"
|
#include "LastMovementValue.h"
|
||||||
#include "ObjectDefines.h"
|
|
||||||
#include "ObjectGuid.h"
|
#include "ObjectGuid.h"
|
||||||
#include "PlayerbotAI.h"
|
#include "PlayerbotAI.h"
|
||||||
#include "PlayerbotAIConfig.h"
|
#include "PlayerbotAIConfig.h"
|
||||||
@@ -19,11 +18,9 @@
|
|||||||
#include "Position.h"
|
#include "Position.h"
|
||||||
#include "RaidUlduarBossHelper.h"
|
#include "RaidUlduarBossHelper.h"
|
||||||
#include "RaidUlduarScripts.h"
|
#include "RaidUlduarScripts.h"
|
||||||
#include "RaidUlduarStrategy.h"
|
|
||||||
#include "RtiValue.h"
|
#include "RtiValue.h"
|
||||||
#include "ScriptedCreature.h"
|
#include "ScriptedCreature.h"
|
||||||
#include "ServerFacade.h"
|
#include "ServerFacade.h"
|
||||||
#include "SharedDefines.h"
|
|
||||||
#include "Unit.h"
|
#include "Unit.h"
|
||||||
#include "Vehicle.h"
|
#include "Vehicle.h"
|
||||||
#include <RtiTargetValue.h>
|
#include <RtiTargetValue.h>
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
#include "RaidUlduarMultipliers.h"
|
|
||||||
|
|
||||||
#include "ChooseTargetActions.h"
|
|
||||||
#include "DKActions.h"
|
|
||||||
#include "DruidActions.h"
|
|
||||||
#include "DruidBearActions.h"
|
|
||||||
#include "FollowActions.h"
|
|
||||||
#include "GenericActions.h"
|
|
||||||
#include "GenericSpellActions.h"
|
|
||||||
#include "HunterActions.h"
|
|
||||||
#include "MageActions.h"
|
|
||||||
#include "MovementActions.h"
|
|
||||||
#include "PaladinActions.h"
|
|
||||||
#include "PriestActions.h"
|
|
||||||
#include "RaidUlduarActions.h"
|
|
||||||
#include "ReachTargetActions.h"
|
|
||||||
#include "RogueActions.h"
|
|
||||||
#include "ScriptedCreature.h"
|
|
||||||
#include "ShamanActions.h"
|
|
||||||
#include "UseMeetingStoneAction.h"
|
|
||||||
#include "WarriorActions.h"
|
|
||||||
|
|
||||||
float FlameLeviathanMultiplier::GetValue(Action* action)
|
|
||||||
{
|
|
||||||
// if (dynamic_cast<FleeAction*>(action))
|
|
||||||
// return 0.0f;
|
|
||||||
return 1.0f;
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
|
|
||||||
#ifndef _PLAYERRBOT_RAIDULDUARMULTIPLIERS_H_
|
|
||||||
#define _PLAYERRBOT_RAIDULDUARMULTIPLIERS_H_
|
|
||||||
|
|
||||||
#include "Multiplier.h"
|
|
||||||
#include "Ai/Raid/Ulduar/RaidUlduarBossHelper.h"
|
|
||||||
|
|
||||||
class FlameLeviathanMultiplier : public Multiplier
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
FlameLeviathanMultiplier(PlayerbotAI* ai) : Multiplier(ai, "flame leviathan") {}
|
|
||||||
|
|
||||||
public:
|
|
||||||
virtual float GetValue(Action* action);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,169 +0,0 @@
|
|||||||
#ifndef _PLAYERBOT_RAIDULDUARBOSSHELPER_H
|
|
||||||
#define _PLAYERBOT_RAIDULDUARBOSSHELPER_H
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <vector>
|
|
||||||
#include <cmath>
|
|
||||||
#include <ctime>
|
|
||||||
#include <limits>
|
|
||||||
|
|
||||||
#include "AiObject.h"
|
|
||||||
#include "AiObjectContext.h"
|
|
||||||
#include "EventMap.h"
|
|
||||||
#include "Log.h"
|
|
||||||
#include "ObjectGuid.h"
|
|
||||||
#include "Player.h"
|
|
||||||
#include "PlayerbotAI.h"
|
|
||||||
#include "Playerbots.h"
|
|
||||||
#include "ScriptedCreature.h"
|
|
||||||
#include "SharedDefines.h"
|
|
||||||
|
|
||||||
const uint32 ULDUAR_MAP_ID = 603;
|
|
||||||
|
|
||||||
class RazorscaleBossHelper : public AiObject
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
// Enums and constants specific to Razorscale
|
|
||||||
enum RazorscaleUnits : uint32
|
|
||||||
{
|
|
||||||
UNIT_RAZORSCALE = 33186,
|
|
||||||
UNIT_DARK_RUNE_SENTINEL = 33846,
|
|
||||||
UNIT_DARK_RUNE_WATCHER = 33453,
|
|
||||||
UNIT_DARK_RUNE_GUARDIAN = 33388,
|
|
||||||
UNIT_DEVOURING_FLAME = 34188,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum RazorscaleGameObjects : uint32
|
|
||||||
{
|
|
||||||
GO_RAZORSCALE_HARPOON_1 = 194519,
|
|
||||||
GO_RAZORSCALE_HARPOON_2 = 194541,
|
|
||||||
GO_RAZORSCALE_HARPOON_3 = 194542,
|
|
||||||
GO_RAZORSCALE_HARPOON_4 = 194543,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum RazorscaleSpells : uint32
|
|
||||||
{
|
|
||||||
SPELL_CHAIN_1 = 49679,
|
|
||||||
SPELL_CHAIN_2 = 49682,
|
|
||||||
SPELL_CHAIN_3 = 49683,
|
|
||||||
SPELL_CHAIN_4 = 49684,
|
|
||||||
SPELL_SENTINEL_WHIRLWIND = 63806,
|
|
||||||
SPELL_STUN_AURA = 62794,
|
|
||||||
SPELL_FUSEARMOR = 64771
|
|
||||||
};
|
|
||||||
|
|
||||||
static constexpr uint32 FUSEARMOR_THRESHOLD = 2;
|
|
||||||
|
|
||||||
// Constants for arena parameters
|
|
||||||
static constexpr float RAZORSCALE_FLYING_Z_THRESHOLD = 440.0f;
|
|
||||||
static constexpr float RAZORSCALE_ARENA_CENTER_X = 587.54f;
|
|
||||||
static constexpr float RAZORSCALE_ARENA_CENTER_Y = -175.04f;
|
|
||||||
static constexpr float RAZORSCALE_ARENA_RADIUS = 30.0f;
|
|
||||||
|
|
||||||
// Harpoon cooldown (seconds)
|
|
||||||
static constexpr time_t HARPOON_COOLDOWN_DURATION = 5;
|
|
||||||
|
|
||||||
// Structure for harpoon data
|
|
||||||
struct HarpoonData
|
|
||||||
{
|
|
||||||
uint32 gameObjectEntry;
|
|
||||||
uint32 chainSpellId;
|
|
||||||
};
|
|
||||||
|
|
||||||
explicit RazorscaleBossHelper(PlayerbotAI* botAI)
|
|
||||||
: AiObject(botAI), _boss(nullptr) {}
|
|
||||||
|
|
||||||
bool UpdateBossAI();
|
|
||||||
Unit* GetBoss() const;
|
|
||||||
|
|
||||||
bool IsGroundPhase() const;
|
|
||||||
bool IsFlyingPhase() const;
|
|
||||||
|
|
||||||
bool IsHarpoonFired(uint32 chainSpellId) const;
|
|
||||||
static bool IsHarpoonReady(GameObject* harpoonGO);
|
|
||||||
static void SetHarpoonOnCooldown(GameObject* harpoonGO);
|
|
||||||
GameObject* FindNearestHarpoon(float x, float y, float z) const;
|
|
||||||
|
|
||||||
static const std::vector<HarpoonData>& GetHarpoonData();
|
|
||||||
|
|
||||||
void AssignRolesBasedOnHealth();
|
|
||||||
bool AreRolesAssigned() const;
|
|
||||||
bool CanSwapRoles() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
Unit* _boss;
|
|
||||||
|
|
||||||
// A map to track the last role swap *per bot* by their GUID
|
|
||||||
static std::unordered_map<ObjectGuid, std::time_t> _lastRoleSwapTime;
|
|
||||||
|
|
||||||
// The cooldown that applies to every bot
|
|
||||||
static const std::time_t _roleSwapCooldown = 10;
|
|
||||||
|
|
||||||
static std::unordered_map<ObjectGuid, time_t> _harpoonCooldowns;
|
|
||||||
};
|
|
||||||
|
|
||||||
// template <class BossAiType>
|
|
||||||
// class GenericBossHelper : public AiObject
|
|
||||||
// {
|
|
||||||
// public:
|
|
||||||
// GenericBossHelper(PlayerbotAI* botAI, std::string name) : AiObject(botAI), _name(name) {}
|
|
||||||
// virtual bool UpdateBossAI()
|
|
||||||
// {
|
|
||||||
// if (!bot->IsInCombat())
|
|
||||||
// {
|
|
||||||
// _unit = nullptr;
|
|
||||||
// }
|
|
||||||
// if (_unit && (!_unit->IsInWorld() || !_unit->IsAlive()))
|
|
||||||
// {
|
|
||||||
// _unit = nullptr;
|
|
||||||
// }
|
|
||||||
// if (!_unit)
|
|
||||||
// {
|
|
||||||
// _unit = AI_VALUE2(Unit*, "find target", _name);
|
|
||||||
// if (!_unit)
|
|
||||||
// {
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
// _target = _unit->ToCreature();
|
|
||||||
// if (!_target)
|
|
||||||
// {
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
// _ai = dynamic_cast<BossAiType*>(_target->GetAI());
|
|
||||||
// if (!_ai)
|
|
||||||
// {
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
// _event_map = &_ai->events;
|
|
||||||
// if (!_event_map)
|
|
||||||
// {
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// if (!_event_map)
|
|
||||||
// {
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
// _timer = _event_map->GetTimer();
|
|
||||||
// return true;
|
|
||||||
// }
|
|
||||||
// virtual void Reset()
|
|
||||||
// {
|
|
||||||
// _unit = nullptr;
|
|
||||||
// _target = nullptr;
|
|
||||||
// _ai = nullptr;
|
|
||||||
// _event_map = nullptr;
|
|
||||||
// _timer = 0;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// protected:
|
|
||||||
// std::string _name;
|
|
||||||
// Unit* _unit = nullptr;
|
|
||||||
// Creature* _target = nullptr;
|
|
||||||
// BossAiType* _ai = nullptr;
|
|
||||||
// EventMap* _event_map = nullptr;
|
|
||||||
// uint32 _timer = 0;
|
|
||||||
// };
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
#include "RaidUlduarStrategy.h"
|
#include "RaidUlduarStrategy.h"
|
||||||
|
|
||||||
#include "RaidUlduarMultipliers.h"
|
|
||||||
|
|
||||||
void RaidUlduarStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
void RaidUlduarStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
@@ -316,8 +314,3 @@ void RaidUlduarStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
"yogg-saron phase 3 positioning trigger",
|
"yogg-saron phase 3 positioning trigger",
|
||||||
{ NextAction("yogg-saron phase 3 positioning action", ACTION_RAID) }));
|
{ NextAction("yogg-saron phase 3 positioning action", ACTION_RAID) }));
|
||||||
}
|
}
|
||||||
|
|
||||||
void RaidUlduarStrategy::InitMultipliers(std::vector<Multiplier*>& multipliers)
|
|
||||||
{
|
|
||||||
multipliers.push_back(new FlameLeviathanMultiplier(botAI));
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -3,16 +3,14 @@
|
|||||||
#define _PLAYERBOT_RAIDULDUARSTRATEGY_H
|
#define _PLAYERBOT_RAIDULDUARSTRATEGY_H
|
||||||
|
|
||||||
#include "AiObjectContext.h"
|
#include "AiObjectContext.h"
|
||||||
#include "Multiplier.h"
|
|
||||||
#include "Strategy.h"
|
#include "Strategy.h"
|
||||||
|
|
||||||
class RaidUlduarStrategy : public Strategy
|
class RaidUlduarStrategy : public Strategy
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
RaidUlduarStrategy(PlayerbotAI* ai) : Strategy(ai) {}
|
RaidUlduarStrategy(PlayerbotAI* ai) : Strategy(ai) {}
|
||||||
virtual std::string const getName() override { return "uld"; }
|
virtual std::string const getName() override { return "ulduar"; }
|
||||||
virtual void InitTriggers(std::vector<TriggerNode*>& triggers) override;
|
virtual void InitTriggers(std::vector<TriggerNode*>& triggers) override;
|
||||||
virtual void InitMultipliers(std::vector<Multiplier*>& multipliers) override;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1634,7 +1634,7 @@ bool VezaxShadowCrashTrigger::IsActive()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return botAI->HasAura(SPELL_SHADOW_CRASH, bot);
|
return botAI->HasAura(SPELL_VEZAX_SHADOW_CRASH, bot);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VezaxMarkOfTheFacelessTrigger::IsActive()
|
bool VezaxMarkOfTheFacelessTrigger::IsActive()
|
||||||
|
|||||||
@@ -3,187 +3,9 @@
|
|||||||
|
|
||||||
#include "EventMap.h"
|
#include "EventMap.h"
|
||||||
#include "GenericTriggers.h"
|
#include "GenericTriggers.h"
|
||||||
#include "PlayerbotAIConfig.h"
|
|
||||||
#include "RaidUlduarBossHelper.h"
|
#include "RaidUlduarBossHelper.h"
|
||||||
#include "Trigger.h"
|
#include "Trigger.h"
|
||||||
|
|
||||||
enum UlduarIDs
|
|
||||||
{
|
|
||||||
// Iron Assembly
|
|
||||||
SPELL_LIGHTNING_TENDRILS_10_MAN = 61887,
|
|
||||||
SPELL_LIGHTNING_TENDRILS_25_MAN = 63486,
|
|
||||||
SPELL_OVERLOAD_10_MAN = 61869,
|
|
||||||
SPELL_OVERLOAD_25_MAN = 63481,
|
|
||||||
SPELL_OVERLOAD_10_MAN_2 = 63485,
|
|
||||||
SPELL_OVERLOAD_25_MAN_2 = 61886,
|
|
||||||
SPELL_RUNE_OF_POWER = 64320,
|
|
||||||
|
|
||||||
// Kologarn
|
|
||||||
NPC_RIGHT_ARM = 32934,
|
|
||||||
NPC_RUBBLE = 33768,
|
|
||||||
SPELL_CRUNCH_ARMOR = 64002,
|
|
||||||
|
|
||||||
SPELL_FOCUSED_EYEBEAM_10_2 = 63346,
|
|
||||||
SPELL_FOCUSED_EYEBEAM_10 = 63347,
|
|
||||||
SPELL_FOCUSED_EYEBEAM_25_2 = 63976,
|
|
||||||
SPELL_FOCUSED_EYEBEAM_25 = 63977,
|
|
||||||
|
|
||||||
// Hodir
|
|
||||||
NPC_SNOWPACKED_ICICLE = 33174,
|
|
||||||
NPC_TOASTY_FIRE = 33342,
|
|
||||||
SPELL_FLASH_FREEZE = 61968,
|
|
||||||
SPELL_BITING_COLD_PLAYER_AURA = 62039,
|
|
||||||
|
|
||||||
// Freya
|
|
||||||
NPC_SNAPLASHER = 32916,
|
|
||||||
NPC_STORM_LASHER = 32919,
|
|
||||||
NPC_DETONATING_LASHER = 32918,
|
|
||||||
NPC_ANCIENT_WATER_SPIRIT = 33202,
|
|
||||||
NPC_ANCIENT_CONSERVATOR = 33203,
|
|
||||||
NPC_HEALTHY_SPORE = 33215,
|
|
||||||
NPC_EONARS_GIFT = 33228,
|
|
||||||
GOBJECT_NATURE_BOMB = 194902,
|
|
||||||
|
|
||||||
// Thorim
|
|
||||||
NPC_DARK_RUNE_ACOLYTE_I = 32886,
|
|
||||||
NPC_CAPTURED_MERCENARY_SOLDIER_ALLY = 32885,
|
|
||||||
NPC_CAPTURED_MERCENARY_SOLDIER_HORDE = 32883,
|
|
||||||
NPC_CAPTURED_MERCENARY_CAPTAIN_ALLY = 32908,
|
|
||||||
NPC_CAPTURED_MERCENARY_CAPTAIN_HORDE = 32907,
|
|
||||||
NPC_JORMUNGAR_BEHEMOT = 32882,
|
|
||||||
NPC_DARK_RUNE_WARBRINGER = 32877,
|
|
||||||
NPC_DARK_RUNE_EVOKER = 32878,
|
|
||||||
NPC_DARK_RUNE_CHAMPION = 32876,
|
|
||||||
NPC_DARK_RUNE_COMMONER = 32904,
|
|
||||||
NPC_IRON_RING_GUARD = 32874,
|
|
||||||
NPC_RUNIC_COLOSSUS = 32872,
|
|
||||||
NPC_ANCIENT_RUNE_GIANT = 32873,
|
|
||||||
NPC_DARK_RUNE_ACOLYTE_G = 33110,
|
|
||||||
NPC_IRON_HONOR_GUARD = 32875,
|
|
||||||
SPELL_UNBALANCING_STRIKE = 62130,
|
|
||||||
|
|
||||||
// Mimiron
|
|
||||||
NPC_LEVIATHAN_MKII = 33432,
|
|
||||||
NPC_VX001 = 33651,
|
|
||||||
NPC_AERIAL_COMMAND_UNIT = 33670,
|
|
||||||
NPC_BOMB_BOT = 33836,
|
|
||||||
NPC_ROCKET_STRIKE_N = 34047,
|
|
||||||
NPC_ASSAULT_BOT = 34057,
|
|
||||||
NPC_PROXIMITY_MINE = 34362,
|
|
||||||
SPELL_P3WX2_LASER_BARRAGE_1 = 63293,
|
|
||||||
SPELL_P3WX2_LASER_BARRAGE_2 = 63297,
|
|
||||||
SPELL_SPINNING_UP = 63414,
|
|
||||||
SPELL_SHOCK_BLAST = 63631,
|
|
||||||
SPELL_P3WX2_LASER_BARRAGE_3 = 64042,
|
|
||||||
SPELL_P3WX2_LASER_BARRAGE_AURA_1 = 63274,
|
|
||||||
SPELL_P3WX2_LASER_BARRAGE_AURA_2 = 63300,
|
|
||||||
|
|
||||||
// General Vezax
|
|
||||||
SPELL_MARK_OF_THE_FACELESS = 63276,
|
|
||||||
SPELL_SHADOW_CRASH = 63277,
|
|
||||||
|
|
||||||
// Yogg-Saron
|
|
||||||
ACTION_ILLUSION_DRAGONS = 1,
|
|
||||||
ACTION_ILLUSION_ICECROWN = 2,
|
|
||||||
ACTION_ILLUSION_STORMWIND = 3,
|
|
||||||
NPC_GUARDIAN_OF_YS = 33136,
|
|
||||||
NPC_YOGG_SARON = 33288,
|
|
||||||
NPC_OMINOUS_CLOUD = 33292,
|
|
||||||
NPC_RUBY_CONSORT = 33716,
|
|
||||||
NPC_AZURE_CONSORT = 33717,
|
|
||||||
NPC_BRONZE_CONSORT = 33718,
|
|
||||||
NPC_EMERALD_CONSORT = 33719,
|
|
||||||
NPC_OBSIDIAN_CONSORT = 33720,
|
|
||||||
NPC_ALEXTRASZA = 33536,
|
|
||||||
NPC_MALYGOS_ILLUSION = 33535,
|
|
||||||
NPC_NELTHARION = 33523,
|
|
||||||
NPC_YSERA = 33495,
|
|
||||||
GO_DRAGON_SOUL = 194462,
|
|
||||||
NPC_SARA_PHASE_1 = 33134,
|
|
||||||
NPC_LICH_KING_ILLUSION = 33441,
|
|
||||||
NPC_IMMOLATED_CHAMPION = 33442,
|
|
||||||
NPC_SUIT_OF_ARMOR = 33433,
|
|
||||||
NPC_GARONA = 33436,
|
|
||||||
NPC_KING_LLANE = 33437,
|
|
||||||
NPC_DEATHSWORN_ZEALOT = 33567,
|
|
||||||
NPC_INFLUENCE_TENTACLE = 33943,
|
|
||||||
NPC_DEATH_ORB = 33882,
|
|
||||||
NPC_BRAIN = 33890,
|
|
||||||
NPC_CRUSHER_TENTACLE = 33966,
|
|
||||||
NPC_CONSTRICTOR_TENTACLE = 33983,
|
|
||||||
NPC_CORRUPTOR_TENTACLE = 33985,
|
|
||||||
NPC_IMMORTAL_GUARDIAN = 33988,
|
|
||||||
NPC_LAUGHING_SKULL = 33990,
|
|
||||||
NPC_SANITY_WELL = 33991,
|
|
||||||
NPC_DESCEND_INTO_MADNESS = 34072,
|
|
||||||
NPC_MARKED_IMMORTAL_GUARDIAN = 36064,
|
|
||||||
SPELL_SANITY = 63050,
|
|
||||||
SPELL_BRAIN_LINK = 63802,
|
|
||||||
SPELL_MALADY_OF_THE_MIND = 63830,
|
|
||||||
SPELL_SHADOW_BARRIER = 63894,
|
|
||||||
SPELL_TELEPORT_TO_CHAMBER = 63997,
|
|
||||||
SPELL_TELEPORT_TO_ICECROWN = 63998,
|
|
||||||
SPELL_TELEPORT_TO_STORMWIND = 63989,
|
|
||||||
SPELL_TELEPORT_BACK = 63992,
|
|
||||||
SPELL_CANCEL_ILLUSION_AURA = 63993,
|
|
||||||
SPELL_INDUCE_MADNESS = 64059,
|
|
||||||
SPELL_LUNATIC_GAZE_YS = 64163,
|
|
||||||
GO_FLEE_TO_THE_SURFACE_PORTAL = 194625,
|
|
||||||
|
|
||||||
// Buffs
|
|
||||||
SPELL_FROST_TRAP = 13809
|
|
||||||
};
|
|
||||||
|
|
||||||
const float ULDUAR_KOLOGARN_AXIS_Z_PATHING_ISSUE_DETECT = 420.0f;
|
|
||||||
const float ULDUAR_KOLOGARN_EYEBEAM_RADIUS = 3.0f;
|
|
||||||
const float ULDUAR_THORIM_AXIS_Z_FLOOR_THRESHOLD = 429.6094f;
|
|
||||||
const float ULDUAR_THORIM_AXIS_Z_PATHING_ISSUE_DETECT = 410.0f;
|
|
||||||
const float ULDUAR_AURIAYA_AXIS_Z_PATHING_ISSUE_DETECT = 410.0f;
|
|
||||||
const float ULDUAR_YOGG_SARON_BOSS_ROOM_AXIS_Z_PATHING_ISSUE_DETECT = 300.0f;
|
|
||||||
const float ULDUAR_YOGG_SARON_BRAIN_ROOM_AXIS_Z_PATHING_ISSUE_DETECT = 200.0f;
|
|
||||||
const float ULDUAR_YOGG_SARON_STORMWIND_KEEPER_RADIUS = 150.0f;
|
|
||||||
const float ULDUAR_YOGG_SARON_ICECROWN_CITADEL_RADIUS = 150.0f;
|
|
||||||
const float ULDUAR_YOGG_SARON_CHAMBER_OF_ASPECTS_RADIUS = 150.0f;
|
|
||||||
const float ULDUAR_YOGG_SARON_BRAIN_ROOM_RADIUS = 50.0f;
|
|
||||||
|
|
||||||
const Position ULDUAR_THORIM_NEAR_ARENA_CENTER = Position(2134.9854f, -263.11853f, 419.8465f);
|
|
||||||
const Position ULDUAR_THORIM_NEAR_ENTRANCE_POSITION = Position(2172.4355f, -258.27957f, 418.47162f);
|
|
||||||
const Position ULDUAR_THORIM_GAUNTLET_LEFT_SIDE_6_YARDS_1 = Position(2237.6187f, -265.08844f, 412.17548f);
|
|
||||||
const Position ULDUAR_THORIM_GAUNTLET_LEFT_SIDE_6_YARDS_2 = Position(2237.2498f, -275.81122f, 412.17548f);
|
|
||||||
const Position ULDUAR_THORIM_GAUNTLET_LEFT_SIDE_5_YARDS_1 = Position(2236.895f, -294.62448f, 412.1348f);
|
|
||||||
const Position ULDUAR_THORIM_GAUNTLET_LEFT_SIDE_10_YARDS_1 = Position(2242.1162f, -310.15308f, 412.1348f);
|
|
||||||
const Position ULDUAR_THORIM_GAUNTLET_LEFT_SIDE_10_YARDS_2 = Position(2242.018f, -318.66003f, 412.1348f);
|
|
||||||
const Position ULDUAR_THORIM_GAUNTLET_LEFT_SIDE_10_YARDS_3 = Position(2242.1904f, -329.0533f, 412.1348f);
|
|
||||||
const Position ULDUAR_THORIM_GAUNTLET_RIGHT_SIDE_6_YARDS_1 = Position(2219.5417f, -264.77167f, 412.17548f);
|
|
||||||
const Position ULDUAR_THORIM_GAUNTLET_RIGHT_SIDE_6_YARDS_2 = Position(2217.446f, -275.85248f, 412.17548f);
|
|
||||||
const Position ULDUAR_THORIM_GAUNTLET_RIGHT_SIDE_5_YARDS_1 = Position(2217.8877f, -295.01193f, 412.13434f);
|
|
||||||
const Position ULDUAR_THORIM_GAUNTLET_RIGHT_SIDE_10_YARDS_1 = Position(2212.193f, -307.44992f, 412.1348f);
|
|
||||||
const Position ULDUAR_THORIM_GAUNTLET_RIGHT_SIDE_10_YARDS_2 = Position(2212.1353f, -318.20795f, 412.1348f);
|
|
||||||
const Position ULDUAR_THORIM_GAUNTLET_RIGHT_SIDE_10_YARDS_3 = Position(2212.1956f, -328.0144f, 412.1348f);
|
|
||||||
const Position ULDUAR_THORIM_JUMP_END_POINT = Position(2137.8818f, -278.18942f, 419.66653f);
|
|
||||||
const Position ULDUAR_THORIM_PHASE2_TANK_SPOT = Position(2134.8572f, -287.0291f, 419.4935f);
|
|
||||||
const Position ULDUAR_THORIM_PHASE2_RANGE1_SPOT = Position(2112.8752f, -267.69305f, 419.52814f);
|
|
||||||
const Position ULDUAR_THORIM_PHASE2_RANGE2_SPOT = Position(2134.1296f, -257.3316f, 419.8462f);
|
|
||||||
const Position ULDUAR_THORIM_PHASE2_RANGE3_SPOT = Position(2156.798f, -267.57434f, 419.52722f);
|
|
||||||
const Position ULDUAR_MIMIRON_PHASE2_SIDE1RANGE_SPOT = Position(2753.708f, 2583.9617f, 364.31357f);
|
|
||||||
const Position ULDUAR_MIMIRON_PHASE2_SIDE1MELEE_SPOT = Position(2746.9792f, 2573.6716f, 364.31357f);
|
|
||||||
const Position ULDUAR_MIMIRON_PHASE2_SIDE2RANGE_SPOT = Position(2727.7224f, 2569.527f, 364.31357f);
|
|
||||||
const Position ULDUAR_MIMIRON_PHASE2_SIDE2MELEE_SPOT = Position(2739.4746f, 2569.4106f, 364.31357f);
|
|
||||||
const Position ULDUAR_MIMIRON_PHASE2_SIDE3RANGE_SPOT = Position(2754.1294f, 2553.9954f, 364.31357f);
|
|
||||||
const Position ULDUAR_MIMIRON_PHASE2_SIDE3MELEE_SPOT = Position(2746.8513f, 2565.4263f, 364.31357f);
|
|
||||||
const Position ULDUAR_MIMIRON_PHASE4_TANK_SPOT = Position(2744.5754f, 2570.8657f, 364.3138f);
|
|
||||||
const Position ULDUAR_VEZAX_MARK_OF_THE_FACELESS_SPOT = Position(1913.6501f, 122.93989f, 342.38083f);
|
|
||||||
const Position ULDUAR_YOGG_SARON_MIDDLE = Position(1980.28f, -25.5868f, 329.397f);
|
|
||||||
const Position ULDUAR_YOGG_SARON_STORMWIND_KEEPER_MIDDLE = Position(1927.1511f, 68.507256f, 242.37657f);
|
|
||||||
const Position ULDUAR_YOGG_SARON_ICECROWN_CITADEL_MIDDLE = Position(1925.6553f, -121.59296f, 239.98965f);
|
|
||||||
const Position ULDUAR_YOGG_SARON_CHAMBER_OF_ASPECTS_MIDDLE = Position(2104.5667f, -25.509348f, 242.64679f);
|
|
||||||
const Position ULDUAR_YOGG_SARON_BRAIN_ROOM_MIDDLE = Position(1980.1971f, -27.854689f, 236.06789f);
|
|
||||||
const Position ULDUAR_YOGG_SARON_STORMWIND_KEEPER_ENTRANCE = Position(1954.06f, 21.66f, 239.71f);
|
|
||||||
const Position ULDUAR_YOGG_SARON_ICECROWN_CITADEL_ENTRANCE = Position(1950.11f, -79.284f, 239.98982f);
|
|
||||||
const Position ULDUAR_YOGG_SARON_CHAMBER_OF_ASPECTS_ENTRANCE = Position(2048.63f, -25.5f, 239.72f);
|
|
||||||
const Position ULDUAR_YOGG_SARON_PHASE_3_MELEE_SPOT = Position(1998.5377f, -22.90317f, 324.8895f);
|
|
||||||
const Position ULDUAR_YOGG_SARON_PHASE_3_RANGED_SPOT = Position(2018.7628f, -18.896868f, 327.07245f);
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Flame Levi
|
// Flame Levi
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
#include "ChatHelper.h"
|
|
||||||
#include "RaidUlduarBossHelper.h"
|
#include "RaidUlduarBossHelper.h"
|
||||||
#include "ObjectAccessor.h"
|
#include "ObjectAccessor.h"
|
||||||
#include "GameObject.h"
|
#include "GameObject.h"
|
||||||
@@ -9,6 +8,44 @@
|
|||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
#include "World.h"
|
#include "World.h"
|
||||||
|
|
||||||
|
const Position ULDUAR_THORIM_NEAR_ARENA_CENTER = Position(2134.9854f, -263.11853f, 419.8465f);
|
||||||
|
const Position ULDUAR_THORIM_NEAR_ENTRANCE_POSITION = Position(2172.4355f, -258.27957f, 418.47162f);
|
||||||
|
const Position ULDUAR_THORIM_GAUNTLET_LEFT_SIDE_6_YARDS_1 = Position(2237.6187f, -265.08844f, 412.17548f);
|
||||||
|
const Position ULDUAR_THORIM_GAUNTLET_LEFT_SIDE_6_YARDS_2 = Position(2237.2498f, -275.81122f, 412.17548f);
|
||||||
|
const Position ULDUAR_THORIM_GAUNTLET_LEFT_SIDE_5_YARDS_1 = Position(2236.895f, -294.62448f, 412.1348f);
|
||||||
|
const Position ULDUAR_THORIM_GAUNTLET_LEFT_SIDE_10_YARDS_1 = Position(2242.1162f, -310.15308f, 412.1348f);
|
||||||
|
const Position ULDUAR_THORIM_GAUNTLET_LEFT_SIDE_10_YARDS_2 = Position(2242.018f, -318.66003f, 412.1348f);
|
||||||
|
const Position ULDUAR_THORIM_GAUNTLET_LEFT_SIDE_10_YARDS_3 = Position(2242.1904f, -329.0533f, 412.1348f);
|
||||||
|
const Position ULDUAR_THORIM_GAUNTLET_RIGHT_SIDE_6_YARDS_1 = Position(2219.5417f, -264.77167f, 412.17548f);
|
||||||
|
const Position ULDUAR_THORIM_GAUNTLET_RIGHT_SIDE_6_YARDS_2 = Position(2217.446f, -275.85248f, 412.17548f);
|
||||||
|
const Position ULDUAR_THORIM_GAUNTLET_RIGHT_SIDE_5_YARDS_1 = Position(2217.8877f, -295.01193f, 412.13434f);
|
||||||
|
const Position ULDUAR_THORIM_GAUNTLET_RIGHT_SIDE_10_YARDS_1 = Position(2212.193f, -307.44992f, 412.1348f);
|
||||||
|
const Position ULDUAR_THORIM_GAUNTLET_RIGHT_SIDE_10_YARDS_2 = Position(2212.1353f, -318.20795f, 412.1348f);
|
||||||
|
const Position ULDUAR_THORIM_GAUNTLET_RIGHT_SIDE_10_YARDS_3 = Position(2212.1956f, -328.0144f, 412.1348f);
|
||||||
|
const Position ULDUAR_THORIM_JUMP_END_POINT = Position(2137.8818f, -278.18942f, 419.66653f);
|
||||||
|
const Position ULDUAR_THORIM_PHASE2_TANK_SPOT = Position(2134.8572f, -287.0291f, 419.4935f);
|
||||||
|
const Position ULDUAR_THORIM_PHASE2_RANGE1_SPOT = Position(2112.8752f, -267.69305f, 419.52814f);
|
||||||
|
const Position ULDUAR_THORIM_PHASE2_RANGE2_SPOT = Position(2134.1296f, -257.3316f, 419.8462f);
|
||||||
|
const Position ULDUAR_THORIM_PHASE2_RANGE3_SPOT = Position(2156.798f, -267.57434f, 419.52722f);
|
||||||
|
const Position ULDUAR_MIMIRON_PHASE2_SIDE1RANGE_SPOT = Position(2753.708f, 2583.9617f, 364.31357f);
|
||||||
|
const Position ULDUAR_MIMIRON_PHASE2_SIDE1MELEE_SPOT = Position(2746.9792f, 2573.6716f, 364.31357f);
|
||||||
|
const Position ULDUAR_MIMIRON_PHASE2_SIDE2RANGE_SPOT = Position(2727.7224f, 2569.527f, 364.31357f);
|
||||||
|
const Position ULDUAR_MIMIRON_PHASE2_SIDE2MELEE_SPOT = Position(2739.4746f, 2569.4106f, 364.31357f);
|
||||||
|
const Position ULDUAR_MIMIRON_PHASE2_SIDE3RANGE_SPOT = Position(2754.1294f, 2553.9954f, 364.31357f);
|
||||||
|
const Position ULDUAR_MIMIRON_PHASE2_SIDE3MELEE_SPOT = Position(2746.8513f, 2565.4263f, 364.31357f);
|
||||||
|
const Position ULDUAR_MIMIRON_PHASE4_TANK_SPOT = Position(2744.5754f, 2570.8657f, 364.3138f);
|
||||||
|
const Position ULDUAR_VEZAX_MARK_OF_THE_FACELESS_SPOT = Position(1913.6501f, 122.93989f, 342.38083f);
|
||||||
|
const Position ULDUAR_YOGG_SARON_MIDDLE = Position(1980.28f, -25.5868f, 329.397f);
|
||||||
|
const Position ULDUAR_YOGG_SARON_STORMWIND_KEEPER_MIDDLE = Position(1927.1511f, 68.507256f, 242.37657f);
|
||||||
|
const Position ULDUAR_YOGG_SARON_ICECROWN_CITADEL_MIDDLE = Position(1925.6553f, -121.59296f, 239.98965f);
|
||||||
|
const Position ULDUAR_YOGG_SARON_CHAMBER_OF_ASPECTS_MIDDLE = Position(2104.5667f, -25.509348f, 242.64679f);
|
||||||
|
const Position ULDUAR_YOGG_SARON_BRAIN_ROOM_MIDDLE = Position(1980.1971f, -27.854689f, 236.06789f);
|
||||||
|
const Position ULDUAR_YOGG_SARON_STORMWIND_KEEPER_ENTRANCE = Position(1954.06f, 21.66f, 239.71f);
|
||||||
|
const Position ULDUAR_YOGG_SARON_ICECROWN_CITADEL_ENTRANCE = Position(1950.11f, -79.284f, 239.98982f);
|
||||||
|
const Position ULDUAR_YOGG_SARON_CHAMBER_OF_ASPECTS_ENTRANCE = Position(2048.63f, -25.5f, 239.72f);
|
||||||
|
const Position ULDUAR_YOGG_SARON_PHASE_3_MELEE_SPOT = Position(1998.5377f, -22.90317f, 324.8895f);
|
||||||
|
const Position ULDUAR_YOGG_SARON_PHASE_3_RANGED_SPOT = Position(2018.7628f, -18.896868f, 327.07245f);
|
||||||
|
|
||||||
// Prevent harpoon spam
|
// Prevent harpoon spam
|
||||||
std::unordered_map<ObjectGuid, time_t> RazorscaleBossHelper::_harpoonCooldowns;
|
std::unordered_map<ObjectGuid, time_t> RazorscaleBossHelper::_harpoonCooldowns;
|
||||||
// Prevent role assignment spam
|
// Prevent role assignment spam
|
||||||
341
src/Ai/Raid/Ulduar/Util/RaidUlduarBossHelper.h
Normal file
341
src/Ai/Raid/Ulduar/Util/RaidUlduarBossHelper.h
Normal file
@@ -0,0 +1,341 @@
|
|||||||
|
#ifndef _PLAYERBOT_RAIDULDUARBOSSHELPER_H
|
||||||
|
#define _PLAYERBOT_RAIDULDUARBOSSHELPER_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "AiObject.h"
|
||||||
|
#include "AiObjectContext.h"
|
||||||
|
#include "EventMap.h"
|
||||||
|
#include "ObjectGuid.h"
|
||||||
|
#include "Player.h"
|
||||||
|
#include "PlayerbotAI.h"
|
||||||
|
#include "Playerbots.h"
|
||||||
|
#include "ScriptedCreature.h"
|
||||||
|
|
||||||
|
constexpr uint32 ULDUAR_MAP_ID = 603;
|
||||||
|
|
||||||
|
enum UlduarIDs
|
||||||
|
{
|
||||||
|
// Iron Assembly
|
||||||
|
SPELL_LIGHTNING_TENDRILS_10_MAN = 61887,
|
||||||
|
SPELL_LIGHTNING_TENDRILS_25_MAN = 63486,
|
||||||
|
SPELL_OVERLOAD_10_MAN = 61869,
|
||||||
|
SPELL_OVERLOAD_25_MAN = 63481,
|
||||||
|
SPELL_OVERLOAD_10_MAN_2 = 63485,
|
||||||
|
SPELL_OVERLOAD_25_MAN_2 = 61886,
|
||||||
|
SPELL_RUNE_OF_POWER = 64320,
|
||||||
|
|
||||||
|
// Kologarn
|
||||||
|
NPC_RIGHT_ARM = 32934,
|
||||||
|
NPC_RUBBLE = 33768,
|
||||||
|
SPELL_CRUNCH_ARMOR = 64002,
|
||||||
|
|
||||||
|
SPELL_FOCUSED_EYEBEAM_10_2 = 63346,
|
||||||
|
SPELL_FOCUSED_EYEBEAM_10 = 63347,
|
||||||
|
SPELL_FOCUSED_EYEBEAM_25_2 = 63976,
|
||||||
|
SPELL_FOCUSED_EYEBEAM_25 = 63977,
|
||||||
|
|
||||||
|
// Hodir
|
||||||
|
NPC_SNOWPACKED_ICICLE = 33174,
|
||||||
|
NPC_TOASTY_FIRE = 33342,
|
||||||
|
SPELL_FLASH_FREEZE = 61968,
|
||||||
|
SPELL_BITING_COLD_PLAYER_AURA = 62039,
|
||||||
|
|
||||||
|
// Freya
|
||||||
|
NPC_SNAPLASHER = 32916,
|
||||||
|
NPC_STORM_LASHER = 32919,
|
||||||
|
NPC_DETONATING_LASHER = 32918,
|
||||||
|
NPC_ANCIENT_WATER_SPIRIT = 33202,
|
||||||
|
NPC_ANCIENT_CONSERVATOR = 33203,
|
||||||
|
NPC_HEALTHY_SPORE = 33215,
|
||||||
|
NPC_EONARS_GIFT = 33228,
|
||||||
|
GOBJECT_NATURE_BOMB = 194902,
|
||||||
|
|
||||||
|
// Thorim
|
||||||
|
NPC_DARK_RUNE_ACOLYTE_I = 32886,
|
||||||
|
NPC_CAPTURED_MERCENARY_SOLDIER_ALLY = 32885,
|
||||||
|
NPC_CAPTURED_MERCENARY_SOLDIER_HORDE = 32883,
|
||||||
|
NPC_CAPTURED_MERCENARY_CAPTAIN_ALLY = 32908,
|
||||||
|
NPC_CAPTURED_MERCENARY_CAPTAIN_HORDE = 32907,
|
||||||
|
NPC_JORMUNGAR_BEHEMOT = 32882,
|
||||||
|
NPC_DARK_RUNE_WARBRINGER = 32877,
|
||||||
|
NPC_DARK_RUNE_EVOKER = 32878,
|
||||||
|
NPC_DARK_RUNE_CHAMPION = 32876,
|
||||||
|
NPC_DARK_RUNE_COMMONER = 32904,
|
||||||
|
NPC_IRON_RING_GUARD = 32874,
|
||||||
|
NPC_RUNIC_COLOSSUS = 32872,
|
||||||
|
NPC_ANCIENT_RUNE_GIANT = 32873,
|
||||||
|
NPC_DARK_RUNE_ACOLYTE_G = 33110,
|
||||||
|
NPC_IRON_HONOR_GUARD = 32875,
|
||||||
|
SPELL_UNBALANCING_STRIKE = 62130,
|
||||||
|
|
||||||
|
// Mimiron
|
||||||
|
NPC_LEVIATHAN_MKII = 33432,
|
||||||
|
NPC_VX001 = 33651,
|
||||||
|
NPC_AERIAL_COMMAND_UNIT = 33670,
|
||||||
|
NPC_BOMB_BOT = 33836,
|
||||||
|
NPC_ROCKET_STRIKE_N = 34047,
|
||||||
|
NPC_ASSAULT_BOT = 34057,
|
||||||
|
NPC_PROXIMITY_MINE = 34362,
|
||||||
|
SPELL_P3WX2_LASER_BARRAGE_1 = 63293,
|
||||||
|
SPELL_P3WX2_LASER_BARRAGE_2 = 63297,
|
||||||
|
SPELL_SPINNING_UP = 63414,
|
||||||
|
SPELL_SHOCK_BLAST = 63631,
|
||||||
|
SPELL_P3WX2_LASER_BARRAGE_3 = 64042,
|
||||||
|
SPELL_P3WX2_LASER_BARRAGE_AURA_1 = 63274,
|
||||||
|
SPELL_P3WX2_LASER_BARRAGE_AURA_2 = 63300,
|
||||||
|
|
||||||
|
// General Vezax
|
||||||
|
SPELL_MARK_OF_THE_FACELESS = 63276,
|
||||||
|
SPELL_VEZAX_SHADOW_CRASH = 63277,
|
||||||
|
|
||||||
|
// Yogg-Saron
|
||||||
|
ACTION_ILLUSION_DRAGONS = 1,
|
||||||
|
ACTION_ILLUSION_ICECROWN = 2,
|
||||||
|
ACTION_ILLUSION_STORMWIND = 3,
|
||||||
|
NPC_GUARDIAN_OF_YS = 33136,
|
||||||
|
NPC_YOGG_SARON = 33288,
|
||||||
|
NPC_OMINOUS_CLOUD = 33292,
|
||||||
|
NPC_RUBY_CONSORT = 33716,
|
||||||
|
NPC_AZURE_CONSORT = 33717,
|
||||||
|
NPC_BRONZE_CONSORT = 33718,
|
||||||
|
NPC_EMERALD_CONSORT = 33719,
|
||||||
|
NPC_OBSIDIAN_CONSORT = 33720,
|
||||||
|
NPC_ALEXTRASZA = 33536,
|
||||||
|
NPC_MALYGOS_ILLUSION = 33535,
|
||||||
|
NPC_NELTHARION = 33523,
|
||||||
|
NPC_YSERA = 33495,
|
||||||
|
GO_DRAGON_SOUL = 194462,
|
||||||
|
NPC_SARA_PHASE_1 = 33134,
|
||||||
|
NPC_LICH_KING_ILLUSION = 33441,
|
||||||
|
NPC_IMMOLATED_CHAMPION = 33442,
|
||||||
|
NPC_SUIT_OF_ARMOR = 33433,
|
||||||
|
NPC_GARONA = 33436,
|
||||||
|
NPC_KING_LLANE = 33437,
|
||||||
|
NPC_DEATHSWORN_ZEALOT = 33567,
|
||||||
|
NPC_INFLUENCE_TENTACLE = 33943,
|
||||||
|
NPC_DEATH_ORB = 33882,
|
||||||
|
NPC_BRAIN = 33890,
|
||||||
|
NPC_CRUSHER_TENTACLE = 33966,
|
||||||
|
NPC_CONSTRICTOR_TENTACLE = 33983,
|
||||||
|
NPC_CORRUPTOR_TENTACLE = 33985,
|
||||||
|
NPC_IMMORTAL_GUARDIAN = 33988,
|
||||||
|
NPC_LAUGHING_SKULL = 33990,
|
||||||
|
NPC_SANITY_WELL = 33991,
|
||||||
|
NPC_DESCEND_INTO_MADNESS = 34072,
|
||||||
|
NPC_MARKED_IMMORTAL_GUARDIAN = 36064,
|
||||||
|
SPELL_SANITY = 63050,
|
||||||
|
SPELL_BRAIN_LINK = 63802,
|
||||||
|
SPELL_MALADY_OF_THE_MIND = 63830,
|
||||||
|
SPELL_SHADOW_BARRIER = 63894,
|
||||||
|
SPELL_TELEPORT_TO_CHAMBER = 63997,
|
||||||
|
SPELL_TELEPORT_TO_ICECROWN = 63998,
|
||||||
|
SPELL_TELEPORT_TO_STORMWIND = 63989,
|
||||||
|
SPELL_TELEPORT_BACK = 63992,
|
||||||
|
SPELL_CANCEL_ILLUSION_AURA = 63993,
|
||||||
|
SPELL_INDUCE_MADNESS = 64059,
|
||||||
|
SPELL_LUNATIC_GAZE_YS = 64163,
|
||||||
|
GO_FLEE_TO_THE_SURFACE_PORTAL = 194625,
|
||||||
|
|
||||||
|
// Buffs
|
||||||
|
SPELL_FROST_TRAP = 13809
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr float ULDUAR_KOLOGARN_AXIS_Z_PATHING_ISSUE_DETECT = 420.0f;
|
||||||
|
constexpr float ULDUAR_KOLOGARN_EYEBEAM_RADIUS = 3.0f;
|
||||||
|
constexpr float ULDUAR_THORIM_AXIS_Z_FLOOR_THRESHOLD = 429.6094f;
|
||||||
|
constexpr float ULDUAR_THORIM_AXIS_Z_PATHING_ISSUE_DETECT = 410.0f;
|
||||||
|
constexpr float ULDUAR_AURIAYA_AXIS_Z_PATHING_ISSUE_DETECT = 410.0f;
|
||||||
|
constexpr float ULDUAR_YOGG_SARON_BOSS_ROOM_AXIS_Z_PATHING_ISSUE_DETECT = 300.0f;
|
||||||
|
constexpr float ULDUAR_YOGG_SARON_BRAIN_ROOM_AXIS_Z_PATHING_ISSUE_DETECT = 200.0f;
|
||||||
|
constexpr float ULDUAR_YOGG_SARON_STORMWIND_KEEPER_RADIUS = 150.0f;
|
||||||
|
constexpr float ULDUAR_YOGG_SARON_ICECROWN_CITADEL_RADIUS = 150.0f;
|
||||||
|
constexpr float ULDUAR_YOGG_SARON_CHAMBER_OF_ASPECTS_RADIUS = 150.0f;
|
||||||
|
constexpr float ULDUAR_YOGG_SARON_BRAIN_ROOM_RADIUS = 50.0f;
|
||||||
|
|
||||||
|
extern const Position ULDUAR_THORIM_NEAR_ARENA_CENTER;
|
||||||
|
extern const Position ULDUAR_THORIM_NEAR_ENTRANCE_POSITION;
|
||||||
|
extern const Position ULDUAR_THORIM_GAUNTLET_LEFT_SIDE_6_YARDS_1;
|
||||||
|
extern const Position ULDUAR_THORIM_GAUNTLET_LEFT_SIDE_6_YARDS_2;
|
||||||
|
extern const Position ULDUAR_THORIM_GAUNTLET_LEFT_SIDE_5_YARDS_1;
|
||||||
|
extern const Position ULDUAR_THORIM_GAUNTLET_LEFT_SIDE_10_YARDS_1;
|
||||||
|
extern const Position ULDUAR_THORIM_GAUNTLET_LEFT_SIDE_10_YARDS_2;
|
||||||
|
extern const Position ULDUAR_THORIM_GAUNTLET_LEFT_SIDE_10_YARDS_3;
|
||||||
|
extern const Position ULDUAR_THORIM_GAUNTLET_RIGHT_SIDE_6_YARDS_1;
|
||||||
|
extern const Position ULDUAR_THORIM_GAUNTLET_RIGHT_SIDE_6_YARDS_2;
|
||||||
|
extern const Position ULDUAR_THORIM_GAUNTLET_RIGHT_SIDE_5_YARDS_1;
|
||||||
|
extern const Position ULDUAR_THORIM_GAUNTLET_RIGHT_SIDE_10_YARDS_1;
|
||||||
|
extern const Position ULDUAR_THORIM_GAUNTLET_RIGHT_SIDE_10_YARDS_2;
|
||||||
|
extern const Position ULDUAR_THORIM_GAUNTLET_RIGHT_SIDE_10_YARDS_3;
|
||||||
|
extern const Position ULDUAR_THORIM_JUMP_END_POINT;
|
||||||
|
extern const Position ULDUAR_THORIM_PHASE2_TANK_SPOT;
|
||||||
|
extern const Position ULDUAR_THORIM_PHASE2_RANGE1_SPOT;
|
||||||
|
extern const Position ULDUAR_THORIM_PHASE2_RANGE2_SPOT;
|
||||||
|
extern const Position ULDUAR_THORIM_PHASE2_RANGE3_SPOT;
|
||||||
|
extern const Position ULDUAR_MIMIRON_PHASE2_SIDE1RANGE_SPOT;
|
||||||
|
extern const Position ULDUAR_MIMIRON_PHASE2_SIDE1MELEE_SPOT;
|
||||||
|
extern const Position ULDUAR_MIMIRON_PHASE2_SIDE2RANGE_SPOT;
|
||||||
|
extern const Position ULDUAR_MIMIRON_PHASE2_SIDE2MELEE_SPOT;
|
||||||
|
extern const Position ULDUAR_MIMIRON_PHASE2_SIDE3RANGE_SPOT;
|
||||||
|
extern const Position ULDUAR_MIMIRON_PHASE2_SIDE3MELEE_SPOT;
|
||||||
|
extern const Position ULDUAR_MIMIRON_PHASE4_TANK_SPOT;
|
||||||
|
extern const Position ULDUAR_VEZAX_MARK_OF_THE_FACELESS_SPOT;
|
||||||
|
extern const Position ULDUAR_YOGG_SARON_MIDDLE;
|
||||||
|
extern const Position ULDUAR_YOGG_SARON_STORMWIND_KEEPER_MIDDLE;
|
||||||
|
extern const Position ULDUAR_YOGG_SARON_ICECROWN_CITADEL_MIDDLE;
|
||||||
|
extern const Position ULDUAR_YOGG_SARON_CHAMBER_OF_ASPECTS_MIDDLE;
|
||||||
|
extern const Position ULDUAR_YOGG_SARON_BRAIN_ROOM_MIDDLE;
|
||||||
|
extern const Position ULDUAR_YOGG_SARON_STORMWIND_KEEPER_ENTRANCE;
|
||||||
|
extern const Position ULDUAR_YOGG_SARON_ICECROWN_CITADEL_ENTRANCE;
|
||||||
|
extern const Position ULDUAR_YOGG_SARON_CHAMBER_OF_ASPECTS_ENTRANCE;
|
||||||
|
extern const Position ULDUAR_YOGG_SARON_PHASE_3_MELEE_SPOT;
|
||||||
|
extern const Position ULDUAR_YOGG_SARON_PHASE_3_RANGED_SPOT;
|
||||||
|
|
||||||
|
class RazorscaleBossHelper : public AiObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Enums and constants specific to Razorscale
|
||||||
|
enum RazorscaleUnits : uint32
|
||||||
|
{
|
||||||
|
UNIT_RAZORSCALE = 33186,
|
||||||
|
UNIT_DARK_RUNE_SENTINEL = 33846,
|
||||||
|
UNIT_DARK_RUNE_WATCHER = 33453,
|
||||||
|
UNIT_DARK_RUNE_GUARDIAN = 33388,
|
||||||
|
UNIT_DEVOURING_FLAME = 34188,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum RazorscaleGameObjects : uint32
|
||||||
|
{
|
||||||
|
GO_RAZORSCALE_HARPOON_1 = 194519,
|
||||||
|
GO_RAZORSCALE_HARPOON_2 = 194541,
|
||||||
|
GO_RAZORSCALE_HARPOON_3 = 194542,
|
||||||
|
GO_RAZORSCALE_HARPOON_4 = 194543,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum RazorscaleSpells : uint32
|
||||||
|
{
|
||||||
|
SPELL_CHAIN_1 = 49679,
|
||||||
|
SPELL_CHAIN_2 = 49682,
|
||||||
|
SPELL_CHAIN_3 = 49683,
|
||||||
|
SPELL_CHAIN_4 = 49684,
|
||||||
|
SPELL_SENTINEL_WHIRLWIND = 63806,
|
||||||
|
SPELL_STUN_AURA = 62794,
|
||||||
|
SPELL_FUSEARMOR = 64771
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr uint32 FUSEARMOR_THRESHOLD = 2;
|
||||||
|
|
||||||
|
// Constants for arena parameters
|
||||||
|
static constexpr float RAZORSCALE_FLYING_Z_THRESHOLD = 440.0f;
|
||||||
|
static constexpr float RAZORSCALE_ARENA_CENTER_X = 587.54f;
|
||||||
|
static constexpr float RAZORSCALE_ARENA_CENTER_Y = -175.04f;
|
||||||
|
static constexpr float RAZORSCALE_ARENA_RADIUS = 30.0f;
|
||||||
|
|
||||||
|
// Harpoon cooldown (seconds)
|
||||||
|
static constexpr time_t HARPOON_COOLDOWN_DURATION = 5;
|
||||||
|
|
||||||
|
// Structure for harpoon data
|
||||||
|
struct HarpoonData
|
||||||
|
{
|
||||||
|
uint32 gameObjectEntry;
|
||||||
|
uint32 chainSpellId;
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit RazorscaleBossHelper(PlayerbotAI* botAI)
|
||||||
|
: AiObject(botAI), _boss(nullptr) {}
|
||||||
|
|
||||||
|
bool UpdateBossAI();
|
||||||
|
Unit* GetBoss() const;
|
||||||
|
|
||||||
|
bool IsGroundPhase() const;
|
||||||
|
bool IsFlyingPhase() const;
|
||||||
|
|
||||||
|
bool IsHarpoonFired(uint32 chainSpellId) const;
|
||||||
|
static bool IsHarpoonReady(GameObject* harpoonGO);
|
||||||
|
static void SetHarpoonOnCooldown(GameObject* harpoonGO);
|
||||||
|
GameObject* FindNearestHarpoon(float x, float y, float z) const;
|
||||||
|
|
||||||
|
static const std::vector<HarpoonData>& GetHarpoonData();
|
||||||
|
|
||||||
|
void AssignRolesBasedOnHealth();
|
||||||
|
bool AreRolesAssigned() const;
|
||||||
|
bool CanSwapRoles() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Unit* _boss;
|
||||||
|
|
||||||
|
// A map to track the last role swap *per bot* by their GUID
|
||||||
|
static std::unordered_map<ObjectGuid, std::time_t> _lastRoleSwapTime;
|
||||||
|
|
||||||
|
// The cooldown that applies to every bot
|
||||||
|
static const std::time_t _roleSwapCooldown = 10;
|
||||||
|
|
||||||
|
static std::unordered_map<ObjectGuid, time_t> _harpoonCooldowns;
|
||||||
|
};
|
||||||
|
|
||||||
|
// template <class BossAiType>
|
||||||
|
// class GenericBossHelper : public AiObject
|
||||||
|
// {
|
||||||
|
// public:
|
||||||
|
// GenericBossHelper(PlayerbotAI* botAI, std::string name) : AiObject(botAI), _name(name) {}
|
||||||
|
// virtual bool UpdateBossAI()
|
||||||
|
// {
|
||||||
|
// if (!bot->IsInCombat())
|
||||||
|
// {
|
||||||
|
// _unit = nullptr;
|
||||||
|
// }
|
||||||
|
// if (_unit && (!_unit->IsInWorld() || !_unit->IsAlive()))
|
||||||
|
// {
|
||||||
|
// _unit = nullptr;
|
||||||
|
// }
|
||||||
|
// if (!_unit)
|
||||||
|
// {
|
||||||
|
// _unit = AI_VALUE2(Unit*, "find target", _name);
|
||||||
|
// if (!_unit)
|
||||||
|
// {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// _target = _unit->ToCreature();
|
||||||
|
// if (!_target)
|
||||||
|
// {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// _ai = dynamic_cast<BossAiType*>(_target->GetAI());
|
||||||
|
// if (!_ai)
|
||||||
|
// {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// _event_map = &_ai->events;
|
||||||
|
// if (!_event_map)
|
||||||
|
// {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// if (!_event_map)
|
||||||
|
// {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// _timer = _event_map->GetTimer();
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
// virtual void Reset()
|
||||||
|
// {
|
||||||
|
// _unit = nullptr;
|
||||||
|
// _target = nullptr;
|
||||||
|
// _ai = nullptr;
|
||||||
|
// _event_map = nullptr;
|
||||||
|
// _timer = 0;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// protected:
|
||||||
|
// std::string _name;
|
||||||
|
// Unit* _unit = nullptr;
|
||||||
|
// Creature* _target = nullptr;
|
||||||
|
// BossAiType* _ai = nullptr;
|
||||||
|
// EventMap* _event_map = nullptr;
|
||||||
|
// uint32 _timer = 0;
|
||||||
|
// };
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
#define _PLAYERBOT_RAIDVOAACTIONCONTEXT_H
|
#define _PLAYERBOT_RAIDVOAACTIONCONTEXT_H
|
||||||
|
|
||||||
#include "Action.h"
|
#include "Action.h"
|
||||||
|
#include "BossAuraActions.h"
|
||||||
#include "NamedObjectContext.h"
|
#include "NamedObjectContext.h"
|
||||||
#include "RaidVoAActions.h"
|
#include "RaidVoAActions.h"
|
||||||
#include "PlayerbotAI.h"
|
#include "PlayerbotAI.h"
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#define _PLAYERBOT_RAIDVOATRIGGERCONTEXT_H
|
#define _PLAYERBOT_RAIDVOATRIGGERCONTEXT_H
|
||||||
|
|
||||||
#include "AiObjectContext.h"
|
#include "AiObjectContext.h"
|
||||||
|
#include "BossAuraTriggers.h"
|
||||||
#include "NamedObjectContext.h"
|
#include "NamedObjectContext.h"
|
||||||
#include "RaidVoATriggers.h"
|
#include "RaidVoATriggers.h"
|
||||||
|
|
||||||
|
|||||||
@@ -15,8 +15,6 @@
|
|||||||
#include "PaladinAiObjectContext.h"
|
#include "PaladinAiObjectContext.h"
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
#include "PriestAiObjectContext.h"
|
#include "PriestAiObjectContext.h"
|
||||||
#include "RaidUlduarActionContext.h"
|
|
||||||
#include "RaidUlduarTriggerContext.h"
|
|
||||||
#include "RogueAiObjectContext.h"
|
#include "RogueAiObjectContext.h"
|
||||||
#include "ShamanAiObjectContext.h"
|
#include "ShamanAiObjectContext.h"
|
||||||
#include "SharedValueContext.h"
|
#include "SharedValueContext.h"
|
||||||
@@ -49,6 +47,8 @@
|
|||||||
#include "Ai/Raid/VaultOfArchavon/RaidVoATriggerContext.h"
|
#include "Ai/Raid/VaultOfArchavon/RaidVoATriggerContext.h"
|
||||||
#include "Ai/Raid/ObsidianSanctum/RaidOsActionContext.h"
|
#include "Ai/Raid/ObsidianSanctum/RaidOsActionContext.h"
|
||||||
#include "Ai/Raid/ObsidianSanctum/RaidOsTriggerContext.h"
|
#include "Ai/Raid/ObsidianSanctum/RaidOsTriggerContext.h"
|
||||||
|
#include "Ai/Raid/Ulduar/RaidUlduarActionContext.h"
|
||||||
|
#include "Ai/Raid/Ulduar/RaidUlduarTriggerContext.h"
|
||||||
#include "Ai/Raid/Onyxia/RaidOnyxiaActionContext.h"
|
#include "Ai/Raid/Onyxia/RaidOnyxiaActionContext.h"
|
||||||
#include "Ai/Raid/Onyxia/RaidOnyxiaTriggerContext.h"
|
#include "Ai/Raid/Onyxia/RaidOnyxiaTriggerContext.h"
|
||||||
#include "Ai/Raid/Icecrown/RaidIccActionContext.h"
|
#include "Ai/Raid/Icecrown/RaidIccActionContext.h"
|
||||||
|
|||||||
@@ -1799,10 +1799,6 @@ void PlayerbotFactory::InitEquipment(bool incremental, bool second_chance)
|
|||||||
{
|
{
|
||||||
for (uint32 itemId : sRandomItemMgr.GetCachedEquipments(requiredLevel, inventoryType))
|
for (uint32 itemId : sRandomItemMgr.GetCachedEquipments(requiredLevel, inventoryType))
|
||||||
{
|
{
|
||||||
if (itemId == 46978) // shaman earth ring totem
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
uint32 skipProb = 25;
|
uint32 skipProb = 25;
|
||||||
if (urand(1, 100) <= skipProb)
|
if (urand(1, 100) <= skipProb)
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -1585,7 +1585,7 @@ void PlayerbotAI::ApplyInstanceStrategies(uint32 mapId, bool tellMaster)
|
|||||||
strategyName = "wotlk-hol"; // Halls of Lightning
|
strategyName = "wotlk-hol"; // Halls of Lightning
|
||||||
break;
|
break;
|
||||||
case 603:
|
case 603:
|
||||||
strategyName = "uld"; // Ulduar
|
strategyName = "ulduar"; // Ulduar
|
||||||
break;
|
break;
|
||||||
case 604:
|
case 604:
|
||||||
strategyName = "wotlk-gd"; // Gundrak
|
strategyName = "wotlk-gd"; // Gundrak
|
||||||
|
|||||||
@@ -1784,7 +1784,7 @@ void RandomPlayerbotMgr::PrepareZone2LevelBracket()
|
|||||||
zone2LevelBracket[3525] = {10, 21}; // Bloodmyst Isle
|
zone2LevelBracket[3525] = {10, 21}; // Bloodmyst Isle
|
||||||
|
|
||||||
// Classic WoW - High - level zones
|
// Classic WoW - High - level zones
|
||||||
zone2LevelBracket[10] = {19, 33}; // Deadwind Pass
|
zone2LevelBracket[10] = {19, 33}; // Duskwood
|
||||||
zone2LevelBracket[11] = {21, 30}; // Wetlands
|
zone2LevelBracket[11] = {21, 30}; // Wetlands
|
||||||
zone2LevelBracket[44] = {16, 28}; // Redridge Mountains
|
zone2LevelBracket[44] = {16, 28}; // Redridge Mountains
|
||||||
zone2LevelBracket[267] = {20, 34}; // Hillsbrad Foothills
|
zone2LevelBracket[267] = {20, 34}; // Hillsbrad Foothills
|
||||||
|
|||||||
@@ -2256,10 +2256,13 @@ void RandomItemMgr::BuildEquipCacheNew()
|
|||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (itemId == 22784)
|
|
||||||
{ // Sunwell Orb
|
// Unobtainable or unusable items
|
||||||
|
if (itemId == 12468 || // Chilton Wand
|
||||||
|
itemId == 22784 || // Sunwell Orb
|
||||||
|
itemId == 46978) // Totem of the Earthen Ring
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
equipCacheNew[proto->RequiredLevel][proto->InventoryType].push_back(itemId);
|
equipCacheNew[proto->RequiredLevel][proto->InventoryType].push_back(itemId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user