mirror of
https://github.com/mod-playerbots/mod-playerbots.git
synced 2026-02-07 20:51:09 +00:00
Compare commits
6 Commits
c86032f43b
...
test-stagi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6ed3f24ecb | ||
|
|
76b6df9ea3 | ||
|
|
026df0dabe | ||
|
|
b31bda85ee | ||
|
|
bebac60c51 | ||
|
|
31765c77fa |
4
.github/workflows/check_pr_source.yml
vendored
4
.github/workflows/check_pr_source.yml
vendored
@@ -1,13 +1,15 @@
|
||||
name: Enforce test-staging → main
|
||||
name: Enforce test-staging → master
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
- test-staging
|
||||
|
||||
jobs:
|
||||
require-test-staging:
|
||||
runs-on: ubuntu-22.04
|
||||
if: github.event.pull_request.base.ref == 'master'
|
||||
steps:
|
||||
- name: Ensure PR source is test-staging
|
||||
run: |
|
||||
|
||||
4
.github/workflows/code_style.yml
vendored
4
.github/workflows/code_style.yml
vendored
@@ -2,9 +2,9 @@ name: Codestyle
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
branches: [ "master", "test-staging" ]
|
||||
pull_request:
|
||||
branches: [ "master" ]
|
||||
branches: [ "master", "test-staging" ]
|
||||
|
||||
concurrency:
|
||||
group: "codestyle-${{ github.event.pull_request.number }}"
|
||||
|
||||
4
.github/workflows/core_build.yml
vendored
4
.github/workflows/core_build.yml
vendored
@@ -2,9 +2,9 @@ name: ubuntu-build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
branches: [ "master", "test-staging" ]
|
||||
pull_request:
|
||||
branches: [ "master" ]
|
||||
branches: [ "master", "test-staging" ]
|
||||
|
||||
concurrency:
|
||||
group: "core-build-${{ github.event.pull_request.number }}"
|
||||
|
||||
4
.github/workflows/macos_build.yml
vendored
4
.github/workflows/macos_build.yml
vendored
@@ -1,9 +1,9 @@
|
||||
name: macos-build
|
||||
on:
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
branches: [ "master", "test-staging" ]
|
||||
pull_request:
|
||||
branches: [ "master" ]
|
||||
branches: [ "master", "test-staging" ]
|
||||
|
||||
concurrency:
|
||||
group: "macos-build-${{ github.event.pull_request.number }}"
|
||||
|
||||
4
.github/workflows/windows_build.yml
vendored
4
.github/workflows/windows_build.yml
vendored
@@ -1,9 +1,9 @@
|
||||
name: windows-build
|
||||
on:
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
branches: [ "master", "test-staging" ]
|
||||
pull_request:
|
||||
branches: [ "master" ]
|
||||
branches: [ "master", "test-staging" ]
|
||||
|
||||
concurrency:
|
||||
group: "windows-build-${{ github.event.pull_request.number }}"
|
||||
|
||||
@@ -66,38 +66,35 @@ Please answer the following:
|
||||
|
||||
## Complexity & Impact
|
||||
|
||||
- Does this change add new decision branches?
|
||||
- [ ] No
|
||||
- [ ] Yes (**explain below**)
|
||||
Does this change add new decision branches?
|
||||
- - [ ] No
|
||||
- - [ ] Yes (**explain below**)
|
||||
|
||||
- Does this change increase per-bot or per-tick processing?
|
||||
- [ ] No
|
||||
- [ ] Yes (**describe and justify impact**)
|
||||
|
||||
- Could this logic scale poorly under load?
|
||||
- [ ] No
|
||||
- [ ] Yes (**explain why**)
|
||||
Does this change increase per-bot or per-tick processing?
|
||||
- - [ ] No
|
||||
- - [ ] Yes (**describe and justify impact**)
|
||||
|
||||
Could this logic scale poorly under load?
|
||||
- - [ ] No
|
||||
- - [ ] Yes (**explain why**)
|
||||
---
|
||||
|
||||
## Defaults & Configuration
|
||||
|
||||
- Does this change modify default bot behavior?
|
||||
- [ ] No
|
||||
- [ ] Yes (**explain why**)
|
||||
Does this change modify default bot behavior?
|
||||
- - [ ] No
|
||||
- - [ ] Yes (**explain why**)
|
||||
|
||||
If this introduces more advanced or AI-heavy logic:
|
||||
|
||||
- [ ] Lightweight mode remains the default
|
||||
- [ ] More complex behavior is optional and thereby configurable
|
||||
|
||||
- - [ ] Lightweight mode remains the default
|
||||
- - [ ] More complex behavior is optional and thereby configurable
|
||||
---
|
||||
|
||||
## AI Assistance
|
||||
|
||||
- Was AI assistance (e.g. ChatGPT or similar tools) used while working on this change?
|
||||
- [ ] No
|
||||
- [ ] Yes (**explain below**)
|
||||
Was AI assistance (e.g. ChatGPT or similar tools) used while working on this change?
|
||||
- - [ ] No
|
||||
- - [ ] Yes (**explain below**)
|
||||
|
||||
If yes, please specify:
|
||||
|
||||
@@ -114,10 +111,10 @@ about what they do and do not understand.
|
||||
|
||||
## Final Checklist
|
||||
|
||||
- [ ] Stability is not compromised
|
||||
- [ ] Performance impact is understood, tested, and acceptable
|
||||
- [ ] Added logic complexity is justified and explained
|
||||
- [ ] Documentation updated if needed
|
||||
- - [ ] Stability is not compromised
|
||||
- - [ ] Performance impact is understood, tested, and acceptable
|
||||
- - [ ] Added logic complexity is justified and explained
|
||||
- - [ ] Documentation updated if needed
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -990,7 +990,7 @@ AiPlayerbot.ZoneBracket.3433 = 10,22
|
||||
AiPlayerbot.ZoneBracket.3525 = 10,21
|
||||
|
||||
# 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)
|
||||
# Redridge Mountains (Zone ID: 44 Default Min,Max: 16,28)
|
||||
# Hillsbrad Foothills (Zone ID: 267 Default Min,Max: 20,34)
|
||||
|
||||
@@ -17,9 +17,9 @@ public:
|
||||
SummonAction(PlayerbotAI* botAI, std::string const name = "summon") : MovementAction(botAI, name) {}
|
||||
|
||||
bool Execute(Event event) override;
|
||||
bool Teleport(Player* summoner, Player* player, bool preserveAuras);
|
||||
|
||||
protected:
|
||||
bool Teleport(Player* summoner, Player* player, bool preserveAuras);
|
||||
bool SummonUsingGos(Player* summoner, Player* player, bool preserveAuras);
|
||||
bool SummonUsingNpcs(Player* summoner, Player* player, bool preserveAuras);
|
||||
};
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "RaidGruulsLairHelpers.h"
|
||||
#include "CreatureAI.h"
|
||||
#include "Playerbots.h"
|
||||
#include "RaidBossHelpers.h"
|
||||
#include "Unit.h"
|
||||
|
||||
using namespace GruulsLairHelpers;
|
||||
@@ -12,6 +13,8 @@ using namespace GruulsLairHelpers;
|
||||
bool HighKingMaulgarMainTankAttackMaulgarAction::Execute(Event event)
|
||||
{
|
||||
Unit* maulgar = AI_VALUE2(Unit*, "find target", "high king maulgar");
|
||||
if (!maulgar)
|
||||
return false;
|
||||
|
||||
MarkTargetWithSquare(bot, maulgar);
|
||||
SetRtiTarget(botAI, "square", maulgar);
|
||||
@@ -21,31 +24,20 @@ bool HighKingMaulgarMainTankAttackMaulgarAction::Execute(Event event)
|
||||
|
||||
if (maulgar->GetVictim() == bot)
|
||||
{
|
||||
const Location& tankPosition = GruulsLairLocations::MaulgarTankPosition;
|
||||
const Position& position = MAULGAR_TANK_POSITION;
|
||||
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 dY = tankPosition.y - bot->GetPositionY();
|
||||
float dist = sqrt(dX * dX + dY * dY);
|
||||
float moveX = bot->GetPositionX() + (dX / dist) * maxDistance;
|
||||
float moveY = bot->GetPositionY() + (dY / dist) * maxDistance;
|
||||
return MoveTo(bot->GetMapId(), moveX, moveY, tankPosition.z, false, false, false, false,
|
||||
MovementPriority::MOVEMENT_COMBAT, true, false);
|
||||
float dX = position.GetPositionX() - bot->GetPositionX();
|
||||
float dY = position.GetPositionY() - bot->GetPositionY();
|
||||
float moveX = bot->GetPositionX() + (dX / distanceToPosition) * maxDistance;
|
||||
float moveY = bot->GetPositionY() + (dY / distanceToPosition) * maxDistance;
|
||||
return MoveTo(GRUULS_LAIR_MAP_ID, moveX, moveY, position.GetPositionZ(), false, false, false, false,
|
||||
MovementPriority::MOVEMENT_COMBAT, true, true);
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -55,6 +47,8 @@ bool HighKingMaulgarMainTankAttackMaulgarAction::Execute(Event event)
|
||||
bool HighKingMaulgarFirstAssistTankAttackOlmAction::Execute(Event event)
|
||||
{
|
||||
Unit* olm = AI_VALUE2(Unit*, "find target", "olm the summoner");
|
||||
if (!olm)
|
||||
return false;
|
||||
|
||||
MarkTargetWithCircle(bot, olm);
|
||||
SetRtiTarget(botAI, "circle", olm);
|
||||
@@ -64,29 +58,22 @@ bool HighKingMaulgarFirstAssistTankAttackOlmAction::Execute(Event event)
|
||||
|
||||
if (olm->GetVictim() == bot)
|
||||
{
|
||||
const Location& tankPosition = GruulsLairLocations::OlmTankPosition;
|
||||
const Position& position = OLM_TANK_POSITION;
|
||||
const float maxDistance = 3.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 dY = tankPosition.y - bot->GetPositionY();
|
||||
float dist = sqrt(dX * dX + dY * dY);
|
||||
float moveX = bot->GetPositionX() + (dX / dist) * maxDistance;
|
||||
float moveY = bot->GetPositionY() + (dY / dist) * maxDistance;
|
||||
return MoveTo(bot->GetMapId(), moveX, moveY, tankPosition.z, false, false, false, false,
|
||||
float dX = position.GetPositionX() - bot->GetPositionX();
|
||||
float dY = position.GetPositionY() - bot->GetPositionY();
|
||||
float moveX = bot->GetPositionX() + (dX / distanceOlmToPosition) * maxDistance;
|
||||
float moveY = bot->GetPositionY() + (dY / distanceOlmToPosition) * maxDistance;
|
||||
return MoveTo(GRUULS_LAIR_MAP_ID, moveX, moveY, position.GetPositionZ(), false, false, false, 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;
|
||||
}
|
||||
@@ -95,6 +82,8 @@ bool HighKingMaulgarFirstAssistTankAttackOlmAction::Execute(Event event)
|
||||
bool HighKingMaulgarSecondAssistTankAttackBlindeyeAction::Execute(Event event)
|
||||
{
|
||||
Unit* blindeye = AI_VALUE2(Unit*, "find target", "blindeye the seer");
|
||||
if (!blindeye)
|
||||
return false;
|
||||
|
||||
MarkTargetWithStar(bot, blindeye);
|
||||
SetRtiTarget(botAI, "star", blindeye);
|
||||
@@ -104,31 +93,20 @@ bool HighKingMaulgarSecondAssistTankAttackBlindeyeAction::Execute(Event event)
|
||||
|
||||
if (blindeye->GetVictim() == bot)
|
||||
{
|
||||
const Location& tankPosition = GruulsLairLocations::BlindeyeTankPosition;
|
||||
const Position& position = BLINDEYE_TANK_POSITION;
|
||||
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 dY = tankPosition.y - bot->GetPositionY();
|
||||
float dist = sqrt(dX * dX + dY * dY);
|
||||
float moveX = bot->GetPositionX() + (dX / dist) * maxDistance;
|
||||
float moveY = bot->GetPositionY() + (dY / dist) * maxDistance;
|
||||
return MoveTo(bot->GetMapId(), moveX, moveY, tankPosition.z, false, false, false, false,
|
||||
float dX = position.GetPositionX() - bot->GetPositionX();
|
||||
float dY = position.GetPositionY() - bot->GetPositionY();
|
||||
float moveX = bot->GetPositionX() + (dX / distanceToPosition) * maxDistance;
|
||||
float moveY = bot->GetPositionY() + (dY / distanceToPosition) * maxDistance;
|
||||
return MoveTo(GRUULS_LAIR_MAP_ID, moveX, moveY, position.GetPositionZ(), false, false, false, 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;
|
||||
@@ -138,6 +116,8 @@ bool HighKingMaulgarSecondAssistTankAttackBlindeyeAction::Execute(Event event)
|
||||
bool HighKingMaulgarMageTankAttackKroshAction::Execute(Event event)
|
||||
{
|
||||
Unit* krosh = AI_VALUE2(Unit*, "find target", "krosh firehand");
|
||||
if (!krosh)
|
||||
return false;
|
||||
|
||||
MarkTargetWithTriangle(bot, krosh);
|
||||
SetRtiTarget(botAI, "triangle", krosh);
|
||||
@@ -149,25 +129,22 @@ bool HighKingMaulgarMageTankAttackKroshAction::Execute(Event event)
|
||||
return botAI->CastSpell("fire ward", bot);
|
||||
|
||||
if (bot->GetTarget() != krosh->GetGUID())
|
||||
{
|
||||
bot->SetSelection(krosh->GetGUID());
|
||||
return true;
|
||||
}
|
||||
return Attack(krosh);
|
||||
|
||||
if (krosh->GetVictim() == bot)
|
||||
{
|
||||
const Location& tankPosition = GruulsLairLocations::KroshTankPosition;
|
||||
float distanceToKrosh = krosh->GetExactDist2d(tankPosition.x, tankPosition.y);
|
||||
const Position& position = KROSH_TANK_POSITION;
|
||||
float distanceToKrosh = krosh->GetExactDist2d(position.GetPositionX(), position.GetPositionY());
|
||||
const float minDistance = 16.0f;
|
||||
const float maxDistance = 29.0f;
|
||||
const float tankPositionLeeway = 1.0f;
|
||||
|
||||
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,
|
||||
false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false);
|
||||
return MoveTo(GRUULS_LAIR_MAP_ID, position.GetPositionX(), position.GetPositionY(), position.GetPositionZ(),
|
||||
false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false);
|
||||
}
|
||||
|
||||
float orientation = atan2(krosh->GetPositionY() - bot->GetPositionY(),
|
||||
@@ -179,7 +156,7 @@ bool HighKingMaulgarMageTankAttackKroshAction::Execute(Event event)
|
||||
Position 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);
|
||||
}
|
||||
}
|
||||
@@ -192,20 +169,19 @@ bool HighKingMaulgarMageTankAttackKroshAction::Execute(Event event)
|
||||
bool HighKingMaulgarMoonkinTankAttackKigglerAction::Execute(Event event)
|
||||
{
|
||||
Unit* kiggler = AI_VALUE2(Unit*, "find target", "kiggler the crazed");
|
||||
if (!kiggler)
|
||||
return false;
|
||||
|
||||
MarkTargetWithDiamond(bot, kiggler);
|
||||
SetRtiTarget(botAI, "diamond", kiggler);
|
||||
|
||||
if (bot->GetTarget() != kiggler->GetGUID())
|
||||
{
|
||||
bot->SetSelection(kiggler->GetGUID());
|
||||
return true;
|
||||
}
|
||||
return Attack(kiggler);
|
||||
|
||||
Position 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);
|
||||
}
|
||||
|
||||
@@ -216,120 +192,105 @@ bool HighKingMaulgarAssignDPSPriorityAction::Execute(Event event)
|
||||
{
|
||||
// Target priority 1: Blindeye
|
||||
Unit* blindeye = AI_VALUE2(Unit*, "find target", "blindeye the seer");
|
||||
if (blindeye && blindeye->IsAlive())
|
||||
if (blindeye)
|
||||
{
|
||||
Position safePos;
|
||||
if (TryGetNewSafePosition(botAI, bot, safePos))
|
||||
{
|
||||
bot->AttackStop();
|
||||
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);
|
||||
}
|
||||
|
||||
SetRtiTarget(botAI, "star", blindeye);
|
||||
|
||||
if (bot->GetTarget() != blindeye->GetGUID())
|
||||
{
|
||||
bot->SetSelection(blindeye->GetGUID());
|
||||
return Attack(blindeye);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Target priority 2: Olm
|
||||
Unit* olm = AI_VALUE2(Unit*, "find target", "olm the summoner");
|
||||
if (olm && olm->IsAlive())
|
||||
if (olm)
|
||||
{
|
||||
Position safePos;
|
||||
if (TryGetNewSafePosition(botAI, bot, safePos))
|
||||
{
|
||||
bot->AttackStop();
|
||||
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);
|
||||
}
|
||||
|
||||
SetRtiTarget(botAI, "circle", olm);
|
||||
|
||||
if (bot->GetTarget() != olm->GetGUID())
|
||||
{
|
||||
bot->SetSelection(olm->GetGUID());
|
||||
return Attack(olm);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Target priority 3a: Krosh (ranged only)
|
||||
Unit* krosh = AI_VALUE2(Unit*, "find target", "krosh firehand");
|
||||
if (krosh && krosh->IsAlive() && botAI->IsRanged(bot))
|
||||
if (krosh && botAI->IsRanged(bot))
|
||||
{
|
||||
Position safePos;
|
||||
if (TryGetNewSafePosition(botAI, bot, safePos))
|
||||
{
|
||||
bot->AttackStop();
|
||||
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);
|
||||
}
|
||||
|
||||
SetRtiTarget(botAI, "triangle", krosh);
|
||||
|
||||
if (bot->GetTarget() != krosh->GetGUID())
|
||||
{
|
||||
bot->SetSelection(krosh->GetGUID());
|
||||
return Attack(krosh);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Target priority 3b: Kiggler
|
||||
Unit* kiggler = AI_VALUE2(Unit*, "find target", "kiggler the crazed");
|
||||
if (kiggler && kiggler->IsAlive())
|
||||
if (kiggler)
|
||||
{
|
||||
Position safePos;
|
||||
if (TryGetNewSafePosition(botAI, bot, safePos))
|
||||
{
|
||||
bot->AttackStop();
|
||||
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);
|
||||
}
|
||||
|
||||
SetRtiTarget(botAI, "diamond", kiggler);
|
||||
|
||||
if (bot->GetTarget() != kiggler->GetGUID())
|
||||
{
|
||||
bot->SetSelection(kiggler->GetGUID());
|
||||
return Attack(kiggler);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Target priority 4: Maulgar
|
||||
Unit* maulgar = AI_VALUE2(Unit*, "find target", "high king maulgar");
|
||||
if (maulgar && maulgar->IsAlive())
|
||||
if (maulgar)
|
||||
{
|
||||
Position safePos;
|
||||
if (TryGetNewSafePosition(botAI, bot, safePos))
|
||||
{
|
||||
bot->AttackStop();
|
||||
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);
|
||||
}
|
||||
|
||||
SetRtiTarget(botAI, "square", maulgar);
|
||||
|
||||
if (bot->GetTarget() != maulgar->GetGUID())
|
||||
{
|
||||
bot->SetSelection(maulgar->GetGUID());
|
||||
return Attack(maulgar);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
bool HighKingMaulgarHealerFindSafePositionAction::Execute(Event event)
|
||||
{
|
||||
const Location& fightCenter = GruulsLairLocations::MaulgarRoomCenter;
|
||||
const float maxDistanceFromFight = 50.0f;
|
||||
float distToFight = bot->GetExactDist2d(fightCenter.x, fightCenter.y);
|
||||
const Position& center = MAULGAR_ROOM_CENTER;
|
||||
const float maxDistanceFromCenter = 50.0f;
|
||||
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 destX = fightCenter.x + 40.0f * cos(angle);
|
||||
float destY = fightCenter.y + 40.0f * sin(angle);
|
||||
float destZ = fightCenter.z;
|
||||
float angle = atan2(bot->GetPositionY() - center.GetPositionY(), bot->GetPositionX() - center.GetPositionX());
|
||||
float destX = center.GetPositionX() + 40.0f * cos(angle);
|
||||
float destY = center.GetPositionY() + 40.0f * sin(angle);
|
||||
float destZ = center.GetPositionZ();
|
||||
|
||||
if (!bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bot->GetPositionX(), bot->GetPositionY(),
|
||||
bot->GetPositionZ(), destX, destY, destZ))
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -362,7 +323,7 @@ bool HighKingMaulgarHealerFindSafePositionAction::Execute(Event event)
|
||||
{
|
||||
bot->AttackStop();
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -373,6 +334,8 @@ bool HighKingMaulgarHealerFindSafePositionAction::Execute(Event event)
|
||||
bool HighKingMaulgarRunAwayFromWhirlwindAction::Execute(Event event)
|
||||
{
|
||||
Unit* maulgar = AI_VALUE2(Unit*, "find target", "high king maulgar");
|
||||
if (!maulgar)
|
||||
return false;
|
||||
|
||||
const float safeDistance = 10.0f;
|
||||
float distance = bot->GetExactDist2d(maulgar);
|
||||
@@ -395,7 +358,7 @@ bool HighKingMaulgarRunAwayFromWhirlwindAction::Execute(Event event)
|
||||
{
|
||||
bot->AttackStop();
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -439,7 +402,7 @@ bool HighKingMaulgarBanishFelstalkerAction::Execute(Event event)
|
||||
if (warlockIndex >= 0 && warlockIndex < felStalkers.size())
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -528,40 +491,33 @@ bool HighKingMaulgarMisdirectOlmAndBlindeyeAction::Execute(Event event)
|
||||
// Gruul the Dragonkiller Actions
|
||||
|
||||
// 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");
|
||||
if (!gruul)
|
||||
return false;
|
||||
|
||||
if (bot->GetVictim() != gruul)
|
||||
return Attack(gruul);
|
||||
|
||||
if (gruul->GetVictim() == bot)
|
||||
{
|
||||
const Location& tankPosition = GruulsLairLocations::GruulTankPosition;
|
||||
const float maxDistance = 3.0f;
|
||||
const Position& position = GRUUL_TANK_POSITION;
|
||||
const float maxDistance = 5.0f;
|
||||
|
||||
float dX = tankPosition.x - bot->GetPositionX();
|
||||
float dY = tankPosition.y - bot->GetPositionY();
|
||||
float distanceToTankPosition = bot->GetExactDist2d(tankPosition.x, tankPosition.y);
|
||||
float dX = position.GetPositionX() - bot->GetPositionX();
|
||||
float dY = position.GetPositionY() - bot->GetPositionY();
|
||||
float distanceToTankPosition = bot->GetExactDist2d(position.GetPositionX(), position.GetPositionY());
|
||||
|
||||
if (distanceToTankPosition > maxDistance)
|
||||
{
|
||||
float step = std::min(maxDistance, distanceToTankPosition);
|
||||
float moveX = bot->GetPositionX() + (dX / distanceToTankPosition) * maxDistance;
|
||||
float moveY = bot->GetPositionY() + (dY / distanceToTankPosition) * maxDistance;
|
||||
const float moveZ = tankPosition.z;
|
||||
return MoveTo(bot->GetMapId(), moveX, moveY, moveZ, false, false, false, false,
|
||||
const float moveZ = position.GetPositionZ();
|
||||
return MoveTo(GRUULS_LAIR_MAP_ID, moveX, moveY, moveZ, false, false, false, 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;
|
||||
@@ -579,16 +535,16 @@ bool GruulTheDragonkillerSpreadRangedAction::Execute(Event event)
|
||||
static std::unordered_map<ObjectGuid, bool> hasReachedInitialPosition;
|
||||
|
||||
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();
|
||||
hasReachedInitialPosition.clear();
|
||||
initialPositions.erase(bot->GetGUID());
|
||||
hasReachedInitialPosition.erase(bot->GetGUID());
|
||||
}
|
||||
|
||||
const Location& tankPosition = GruulsLairLocations::GruulTankPosition;
|
||||
const float centerX = tankPosition.x;
|
||||
const float centerY = tankPosition.y;
|
||||
float centerZ = bot->GetPositionZ();
|
||||
const Position& position = GRUUL_TANK_POSITION;
|
||||
const float centerX = position.GetPositionX();
|
||||
const float centerY = position.GetPositionY();
|
||||
const float centerZ = position.GetPositionZ();
|
||||
const float minRadius = 25.0f;
|
||||
const float maxRadius = 40.0f;
|
||||
|
||||
@@ -642,7 +598,7 @@ bool GruulTheDragonkillerSpreadRangedAction::Execute(Event event)
|
||||
bot->GetPositionY(), bot->GetPositionZ(), destX, destY, destZ))
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -85,10 +85,10 @@ public:
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class GruulTheDragonkillerMainTankPositionBossAction : public AttackAction
|
||||
class GruulTheDragonkillerTanksPositionBossAction : public AttackAction
|
||||
{
|
||||
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;
|
||||
};
|
||||
|
||||
@@ -8,18 +8,11 @@
|
||||
#include "HunterActions.h"
|
||||
#include "MageActions.h"
|
||||
#include "Playerbots.h"
|
||||
#include "ReachTargetActions.h"
|
||||
#include "WarriorActions.h"
|
||||
|
||||
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)
|
||||
{
|
||||
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");
|
||||
|
||||
if (maulgar && maulgar->HasAura(SPELL_WHIRLWIND) &&
|
||||
(!kiggler || !kiggler->IsAlive()) &&
|
||||
(!krosh || !krosh->IsAlive()) &&
|
||||
(!olm || !olm->IsAlive()) &&
|
||||
(!blindeye || !blindeye->IsAlive()))
|
||||
!kiggler && !krosh && !olm && !blindeye)
|
||||
{
|
||||
if (IsChargeAction(action) || (dynamic_cast<MovementAction*>(action) &&
|
||||
if (dynamic_cast<CastReachTargetSpellAction*>(action) ||
|
||||
(dynamic_cast<MovementAction*>(action) &&
|
||||
!dynamic_cast<HighKingMaulgarRunAwayFromWhirlwindAction*>(action)))
|
||||
return 0.0f;
|
||||
}
|
||||
@@ -57,7 +48,8 @@ float HighKingMaulgarDisableArcaneShotOnKroshMultiplier::GetValue(Action* action
|
||||
Unit* krosh = AI_VALUE2(Unit*, "find target", "krosh firehand");
|
||||
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 1.0f;
|
||||
@@ -101,8 +93,9 @@ float GruulTheDragonkillerGroundSlamMultiplier::GetValue(Action* action)
|
||||
if (bot->HasAura(SPELL_GROUND_SLAM_1) ||
|
||||
bot->HasAura(SPELL_GROUND_SLAM_2))
|
||||
{
|
||||
if ((dynamic_cast<MovementAction*>(action) && !dynamic_cast<GruulTheDragonkillerShatterSpreadAction*>(action)) ||
|
||||
IsChargeAction(action))
|
||||
if ((dynamic_cast<MovementAction*>(action) &&
|
||||
!dynamic_cast<GruulTheDragonkillerShatterSpreadAction*>(action)) ||
|
||||
dynamic_cast<CastReachTargetSpellAction*>(action))
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ public:
|
||||
creators["high king maulgar misdirect olm and blindeye"] = &RaidGruulsLairActionContext::high_king_maulgar_misdirect_olm_and_blindeye;
|
||||
|
||||
// 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 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); }
|
||||
|
||||
// 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_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;
|
||||
|
||||
// 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 range"] = &RaidGruulsLairTriggerContext::gruul_the_dragonkiller_boss_engaged_by_range;
|
||||
creators["gruul the dragonkiller boss engaged by tanks"] = &RaidGruulsLairTriggerContext::gruul_the_dragonkiller_boss_engaged_by_tanks;
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -41,8 +41,8 @@ private:
|
||||
static Trigger* high_king_maulgar_pulling_olm_and_blindeye(PlayerbotAI* botAI) { return new HighKingMaulgarPullingOlmAndBlindeyeTrigger(botAI); }
|
||||
|
||||
// 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_range(PlayerbotAI* botAI) { return new GruulTheDragonkillerBossEngagedByRangeTrigger(botAI); }
|
||||
static Trigger* gruul_the_dragonkiller_boss_engaged_by_tanks(PlayerbotAI* botAI) { return new GruulTheDragonkillerBossEngagedByTanksTrigger(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); }
|
||||
};
|
||||
|
||||
|
||||
@@ -35,10 +35,10 @@ void RaidGruulsLairStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
NextAction("high king maulgar misdirect olm and blindeye", ACTION_RAID + 2) }));
|
||||
|
||||
// Gruul the Dragonkiller
|
||||
triggers.push_back(new TriggerNode("gruul the dragonkiller boss engaged by main tank", {
|
||||
NextAction("gruul the dragonkiller main tank position boss", ACTION_RAID + 1) }));
|
||||
triggers.push_back(new TriggerNode("gruul the dragonkiller boss engaged by tanks", {
|
||||
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) }));
|
||||
|
||||
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");
|
||||
|
||||
return botAI->IsMainTank(bot) && maulgar && maulgar->IsAlive();
|
||||
return botAI->IsMainTank(bot) && maulgar;
|
||||
}
|
||||
|
||||
bool HighKingMaulgarIsFirstAssistTankTrigger::IsActive()
|
||||
{
|
||||
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()
|
||||
{
|
||||
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()
|
||||
{
|
||||
Unit* krosh = AI_VALUE2(Unit*, "find target", "krosh firehand");
|
||||
|
||||
return IsKroshMageTank(botAI, bot) && krosh && krosh->IsAlive();
|
||||
return IsKroshMageTank(botAI, bot) && krosh;
|
||||
}
|
||||
|
||||
bool HighKingMaulgarIsMoonkinTankTrigger::IsActive()
|
||||
{
|
||||
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()
|
||||
@@ -50,11 +50,11 @@ bool HighKingMaulgarDeterminingKillOrderTrigger::IsActive()
|
||||
Unit* krosh = AI_VALUE2(Unit*, "find target", "krosh firehand");
|
||||
|
||||
return (botAI->IsDps(bot) || botAI->IsTank(bot)) &&
|
||||
!(botAI->IsMainTank(bot) && maulgar && maulgar->IsAlive()) &&
|
||||
!(botAI->IsAssistTankOfIndex(bot, 0) && olm && olm->IsAlive()) &&
|
||||
!(botAI->IsAssistTankOfIndex(bot, 1) && blindeye && blindeye->IsAlive()) &&
|
||||
!(IsKroshMageTank(botAI, bot) && krosh && krosh->IsAlive()) &&
|
||||
!(IsKigglerMoonkinTank(botAI, bot) && kiggler && kiggler->IsAlive());
|
||||
!(botAI->IsMainTank(bot) && maulgar) &&
|
||||
!(botAI->IsAssistTankOfIndex(bot, 0, false) && olm) &&
|
||||
!(botAI->IsAssistTankOfIndex(bot, 1, false) && blindeye) &&
|
||||
!(IsKroshMageTank(botAI, bot) && krosh) &&
|
||||
!(IsKigglerMoonkinTank(botAI, bot) && kiggler);
|
||||
}
|
||||
|
||||
bool HighKingMaulgarHealerInDangerTrigger::IsActive()
|
||||
@@ -66,7 +66,7 @@ bool HighKingMaulgarBossChannelingWhirlwindTrigger::IsActive()
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ bool HighKingMaulgarWildFelstalkerSpawnedTrigger::IsActive()
|
||||
{
|
||||
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()
|
||||
@@ -120,12 +120,12 @@ bool HighKingMaulgarPullingOlmAndBlindeyeTrigger::IsActive()
|
||||
switch (hunterIndex)
|
||||
{
|
||||
case 0:
|
||||
return olm && olm->IsAlive() && olm->GetHealthPct() > 98.0f &&
|
||||
olmTank && olmTank->IsAlive() && botAI->CanCastSpell("misdirection", olmTank);
|
||||
return olm && olm->GetHealthPct() > 98.0f &&
|
||||
olmTank && botAI->CanCastSpell("misdirection", olmTank);
|
||||
|
||||
case 1:
|
||||
return blindeye && blindeye->IsAlive() && blindeye->GetHealthPct() > 90.0f &&
|
||||
blindeyeTank && blindeyeTank->IsAlive() && botAI->CanCastSpell("misdirection", blindeyeTank);
|
||||
return blindeye && blindeye->GetHealthPct() > 90.0f &&
|
||||
blindeyeTank && botAI->CanCastSpell("misdirection", blindeyeTank);
|
||||
|
||||
default:
|
||||
break;
|
||||
@@ -136,25 +136,24 @@ bool HighKingMaulgarPullingOlmAndBlindeyeTrigger::IsActive()
|
||||
|
||||
// Gruul the Dragonkiller Triggers
|
||||
|
||||
bool GruulTheDragonkillerBossEngagedByMainTankTrigger::IsActive()
|
||||
bool GruulTheDragonkillerBossEngagedByTanksTrigger::IsActive()
|
||||
{
|
||||
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");
|
||||
|
||||
return gruul && gruul->IsAlive() && botAI->IsRanged(bot);
|
||||
return gruul && botAI->IsRanged(bot);
|
||||
}
|
||||
|
||||
bool GruulTheDragonkillerIncomingShatterTrigger::IsActive()
|
||||
{
|
||||
Unit* gruul = AI_VALUE2(Unit*, "find target", "gruul the dragonkiller");
|
||||
|
||||
return gruul && gruul->IsAlive() &&
|
||||
(bot->HasAura(SPELL_GROUND_SLAM_1) ||
|
||||
bot->HasAura(SPELL_GROUND_SLAM_2));
|
||||
return gruul && (bot->HasAura(SPELL_GROUND_SLAM_1) ||
|
||||
bot->HasAura(SPELL_GROUND_SLAM_2));
|
||||
}
|
||||
|
||||
@@ -73,17 +73,17 @@ public:
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class GruulTheDragonkillerBossEngagedByMainTankTrigger : public Trigger
|
||||
class GruulTheDragonkillerBossEngagedByTanksTrigger : public Trigger
|
||||
{
|
||||
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;
|
||||
};
|
||||
|
||||
class GruulTheDragonkillerBossEngagedByRangeTrigger : public Trigger
|
||||
class GruulTheDragonkillerBossEngagedByRangedTrigger : public Trigger
|
||||
{
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
@@ -6,19 +6,16 @@
|
||||
|
||||
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
|
||||
// It is the spot to which the OlmTank runs to to pull Olm to a decent tanking location
|
||||
// "MaulgarRoomCenter" is to keep healers in a centralized location
|
||||
const Location MaulgarTankPosition = { 90.686f, 167.047f, -13.234f };
|
||||
const Location OlmTankPosition = { 87.485f, 234.942f, -3.635f };
|
||||
const Location BlindeyeTankPosition = { 99.681f, 213.989f, -10.345f };
|
||||
const Location KroshTankPosition = { 116.880f, 166.208f, -14.231f };
|
||||
const Location MaulgarRoomCenter = { 88.754f, 150.759f, -11.569f };
|
||||
const Location GruulTankPosition = { 241.238f, 365.025f, -4.220f };
|
||||
}
|
||||
// Olm does not chase properly due to the Core's caster movement issues
|
||||
// Thus, the below "OlmTankPosition" is beyond the actual desired tanking location
|
||||
// It is the spot to which the OlmTank runs to to pull Olm to a decent tanking location
|
||||
// "MaulgarRoomCenter" is to keep healers in a centralized location
|
||||
const Position MAULGAR_TANK_POSITION = { 90.686f, 167.047f, -13.234f };
|
||||
const Position OLM_TANK_POSITION = { 87.485f, 234.942f, -3.635f };
|
||||
const Position BLINDEYE_TANK_POSITION = { 99.681f, 213.989f, -10.345f };
|
||||
const Position KROSH_TANK_POSITION = { 116.880f, 166.208f, -14.231f };
|
||||
const Position MAULGAR_ROOM_CENTER = { 88.754f, 150.759f, -11.569f };
|
||||
const Position GRUUL_TANK_POSITION = { 241.238f, 365.025f, -4.220f };
|
||||
|
||||
bool IsAnyOgreBossAlive(PlayerbotAI* botAI)
|
||||
{
|
||||
@@ -42,84 +39,43 @@ namespace GruulsLairHelpers
|
||||
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)
|
||||
{
|
||||
Group* group = bot->GetGroup();
|
||||
if (!group)
|
||||
return false;
|
||||
|
||||
Player* highestHpMage = nullptr;
|
||||
uint32 highestHp = 0;
|
||||
// (1) First loop: Return the first assistant Mage (real player or bot)
|
||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||
{
|
||||
Player* member = ref->GetSource();
|
||||
if (!member || !member->IsAlive() || !GET_PLAYERBOT_AI(member))
|
||||
if (!member || !member->IsAlive() || member->getClass() != CLASS_MAGE)
|
||||
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();
|
||||
if (!highestHpMage || hp > highestHp)
|
||||
{
|
||||
highestHpMage = member;
|
||||
highestHp = hp;
|
||||
}
|
||||
highestHpMage = member;
|
||||
highestHp = hp;
|
||||
}
|
||||
}
|
||||
|
||||
// (3) Return the found Mage tank, or nullptr if none found
|
||||
return highestHpMage == bot;
|
||||
}
|
||||
|
||||
@@ -129,30 +85,37 @@ namespace GruulsLairHelpers
|
||||
if (!group)
|
||||
return false;
|
||||
|
||||
Player* highestHpMoonkin = nullptr;
|
||||
uint32 highestHp = 0;
|
||||
|
||||
// (1) First loop: Return the first assistant Moonkin (real player or bot)
|
||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||
{
|
||||
Player* member = ref->GetSource();
|
||||
if (!member || !member->IsAlive() || !GET_PLAYERBOT_AI(member))
|
||||
if (!member || !member->IsAlive() || member->getClass() != CLASS_DRUID)
|
||||
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);
|
||||
if (tab == DRUID_TAB_BALANCE)
|
||||
{
|
||||
uint32 hp = member->GetMaxHealth();
|
||||
if (!highestHpMoonkin || hp > highestHp)
|
||||
{
|
||||
highestHpMoonkin = member;
|
||||
highestHp = hp;
|
||||
}
|
||||
}
|
||||
highestHpMoonkin = member;
|
||||
highestHp = hp;
|
||||
}
|
||||
}
|
||||
|
||||
// (3) Return the found Moonkin tank, or nullptr if none found
|
||||
return highestHpMoonkin == bot;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,23 +2,19 @@
|
||||
#define RAID_GRUULSLAIRHELPERS_H
|
||||
|
||||
#include "PlayerbotAI.h"
|
||||
#include "RtiTargetValue.h"
|
||||
|
||||
namespace GruulsLairHelpers
|
||||
{
|
||||
enum GruulsLairSpells
|
||||
{
|
||||
// High King Maulgar
|
||||
SPELL_WHIRLWIND = 33238,
|
||||
SPELL_WHIRLWIND = 33238,
|
||||
|
||||
// Krosh Firehand
|
||||
SPELL_SPELL_SHIELD = 33054,
|
||||
SPELL_SPELL_SHIELD = 33054,
|
||||
|
||||
// Hunter
|
||||
SPELL_MISDIRECTION = 35079,
|
||||
|
||||
// Warlock
|
||||
SPELL_BANISH = 18647, // Rank 2
|
||||
SPELL_MISDIRECTION = 35079,
|
||||
|
||||
// Gruul the Dragonkiller
|
||||
SPELL_GROUND_SLAM_1 = 33525,
|
||||
@@ -30,33 +26,20 @@ namespace GruulsLairHelpers
|
||||
NPC_WILD_FEL_STALKER = 18847,
|
||||
};
|
||||
|
||||
constexpr uint32 GRUULS_LAIR_MAP_ID = 565;
|
||||
|
||||
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 IsKigglerMoonkinTank(PlayerbotAI* botAI, Player* bot);
|
||||
bool IsPositionSafe(PlayerbotAI* botAI, Player* bot, Position pos);
|
||||
bool TryGetNewSafePosition(PlayerbotAI* botAI, Player* bot, Position& outPos);
|
||||
|
||||
struct Location
|
||||
{
|
||||
float x, y, z;
|
||||
};
|
||||
|
||||
namespace GruulsLairLocations
|
||||
{
|
||||
extern const Location MaulgarTankPosition;
|
||||
extern const Location OlmTankPosition;
|
||||
extern const Location BlindeyeTankPosition;
|
||||
extern const Location KroshTankPosition;
|
||||
extern const Location MaulgarRoomCenter;
|
||||
extern const Location GruulTankPosition;
|
||||
}
|
||||
extern const Position MAULGAR_TANK_POSITION;
|
||||
extern const Position OLM_TANK_POSITION;
|
||||
extern const Position BLINDEYE_TANK_POSITION;
|
||||
extern const Position KROSH_TANK_POSITION;
|
||||
extern const Position MAULGAR_ROOM_CENTER;
|
||||
extern const Position GRUUL_TANK_POSITION;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "RaidKarazhanHelpers.h"
|
||||
#include "Playerbots.h"
|
||||
#include "PlayerbotTextMgr.h"
|
||||
#include "RaidBossHelpers.h"
|
||||
|
||||
using namespace KarazhanHelpers;
|
||||
|
||||
@@ -44,7 +45,7 @@ bool AttumenTheHuntsmanMarkTargetAction::Execute(Event event)
|
||||
Unit* attumenMounted = GetFirstAliveUnitByEntry(botAI, NPC_ATTUMEN_THE_HUNTSMAN_MOUNTED);
|
||||
if (attumenMounted)
|
||||
{
|
||||
if (IsInstanceTimerManager(botAI, bot))
|
||||
if (IsMechanicTrackerBot(botAI, bot, KARAZHAN_MAP_ID, nullptr))
|
||||
MarkTargetWithStar(bot, attumenMounted);
|
||||
|
||||
SetRtiTarget(botAI, "star", attumenMounted);
|
||||
@@ -57,7 +58,7 @@ bool AttumenTheHuntsmanMarkTargetAction::Execute(Event event)
|
||||
}
|
||||
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);
|
||||
|
||||
if (!botAI->IsAssistTankOfIndex(bot, 0))
|
||||
@@ -180,7 +181,7 @@ bool MoroesMarkTargetAction::Execute(Event event)
|
||||
|
||||
if (target)
|
||||
{
|
||||
if (IsInstanceTimerManager(botAI, bot))
|
||||
if (IsMechanicTrackerBot(botAI, bot, KARAZHAN_MAP_ID, nullptr))
|
||||
MarkTargetWithSkull(bot, target);
|
||||
|
||||
SetRtiTarget(botAI, "skull", target);
|
||||
@@ -405,7 +406,7 @@ bool TheCuratorMarkAstralFlareAction::Execute(Event event)
|
||||
if (!flare)
|
||||
return false;
|
||||
|
||||
if (IsInstanceTimerManager(botAI, bot))
|
||||
if (IsMechanicTrackerBot(botAI, bot, KARAZHAN_MAP_ID, nullptr))
|
||||
MarkTargetWithSkull(bot, flare);
|
||||
|
||||
SetRtiTarget(botAI, "skull", flare);
|
||||
@@ -469,11 +470,11 @@ bool TheCuratorSpreadRangedAction::Execute(Event event)
|
||||
// Prioritize (1) Demon Chains, (2) Kil'rek, (3) Illhoof
|
||||
bool TerestianIllhoofMarkTargetAction::Execute(Event event)
|
||||
{
|
||||
Unit* demonChains = AI_VALUE2(Unit*, "find target", "demon chains");
|
||||
Unit* kilrek = AI_VALUE2(Unit*, "find target", "kil'rek");
|
||||
Unit* demonChains = GetFirstAliveUnitByEntry(botAI, NPC_DEMON_CHAINS);
|
||||
Unit* kilrek = GetFirstAliveUnitByEntry(botAI, NPC_KILREK);
|
||||
Unit* illhoof = AI_VALUE2(Unit*, "find target", "terestian illhoof");
|
||||
Unit* target = GetFirstAliveUnit({demonChains, kilrek, illhoof});
|
||||
|
||||
Unit* target = GetFirstAliveUnit({demonChains, kilrek, illhoof});
|
||||
if (target)
|
||||
MarkTargetWithSkull(bot, target);
|
||||
|
||||
@@ -1007,7 +1008,7 @@ bool NetherspiteManageTimersAndTrackersAction::Execute(Event event)
|
||||
if (netherspite->GetHealth() == netherspite->GetMaxHealth() &&
|
||||
!netherspite->HasAura(SPELL_GREEN_BEAM_HEAL))
|
||||
{
|
||||
if (IsInstanceTimerManager(botAI, bot))
|
||||
if (IsMechanicTrackerBot(botAI, bot, KARAZHAN_MAP_ID, nullptr))
|
||||
netherspiteDpsWaitTimer.insert_or_assign(instanceId, now);
|
||||
|
||||
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))
|
||||
{
|
||||
if (IsInstanceTimerManager(botAI, bot))
|
||||
if (IsMechanicTrackerBot(botAI, bot, KARAZHAN_MAP_ID, nullptr))
|
||||
netherspiteDpsWaitTimer.erase(instanceId);
|
||||
|
||||
if (botAI->IsTank(bot))
|
||||
@@ -1029,7 +1030,7 @@ bool NetherspiteManageTimersAndTrackersAction::Execute(Event event)
|
||||
}
|
||||
else if (!netherspite->HasAura(SPELL_NETHERSPITE_BANISHED))
|
||||
{
|
||||
if (IsInstanceTimerManager(botAI, bot))
|
||||
if (IsMechanicTrackerBot(botAI, bot, KARAZHAN_MAP_ID, nullptr))
|
||||
netherspiteDpsWaitTimer.try_emplace(instanceId, now);
|
||||
|
||||
if (botAI->IsTank(bot) && bot->HasAura(SPELL_RED_BEAM_DEBUFF))
|
||||
@@ -1458,7 +1459,7 @@ bool NightbaneManageTimersAndTrackersAction::Execute(Event event)
|
||||
if (botAI->IsRanged(bot))
|
||||
nightbaneRangedStep.erase(botGuid);
|
||||
|
||||
if (IsInstanceTimerManager(botAI, bot))
|
||||
if (IsMechanicTrackerBot(botAI, bot, KARAZHAN_MAP_ID, nullptr))
|
||||
nightbaneDpsWaitTimer.erase(instanceId);
|
||||
}
|
||||
// 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);
|
||||
|
||||
if (IsInstanceTimerManager(botAI, bot))
|
||||
if (IsMechanicTrackerBot(botAI, bot, KARAZHAN_MAP_ID, nullptr))
|
||||
{
|
||||
nightbaneFlightPhaseStartTimer.erase(instanceId);
|
||||
nightbaneDpsWaitTimer.try_emplace(instanceId, now);
|
||||
@@ -1482,7 +1483,7 @@ bool NightbaneManageTimersAndTrackersAction::Execute(Event event)
|
||||
if (botAI->IsRanged(bot))
|
||||
nightbaneRangedStep.erase(botGuid);
|
||||
|
||||
if (IsInstanceTimerManager(botAI, bot))
|
||||
if (IsMechanicTrackerBot(botAI, bot, KARAZHAN_MAP_ID, nullptr))
|
||||
{
|
||||
nightbaneDpsWaitTimer.erase(instanceId);
|
||||
nightbaneFlightPhaseStartTimer.try_emplace(instanceId, now);
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "MageActions.h"
|
||||
#include "Playerbots.h"
|
||||
#include "PriestActions.h"
|
||||
#include "RaidBossHelpers.h"
|
||||
#include "ReachTargetActions.h"
|
||||
#include "RogueActions.h"
|
||||
#include "ShamanActions.h"
|
||||
@@ -242,6 +243,9 @@ float PrinceMalchezaarEnfeebleKeepDistanceMultiplier::GetValue(Action* action)
|
||||
|
||||
if (bot->HasAura(SPELL_ENFEEBLE))
|
||||
{
|
||||
if (dynamic_cast<CastReachTargetSpellAction*>(action))
|
||||
return 0.0f;
|
||||
|
||||
if (dynamic_cast<MovementAction*>(action) &&
|
||||
!dynamic_cast<PrinceMalchezaarEnfeebledAvoidHazardAction*>(action))
|
||||
return 0.0f;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "RaidKarazhanHelpers.h"
|
||||
#include "RaidKarazhanActions.h"
|
||||
#include "Playerbots.h"
|
||||
#include "RaidBossHelpers.h"
|
||||
|
||||
using namespace KarazhanHelpers;
|
||||
|
||||
@@ -40,7 +41,7 @@ bool AttumenTheHuntsmanAttumenIsMountedTrigger::IsActive()
|
||||
|
||||
bool AttumenTheHuntsmanBossWipesAggroWhenMountingTrigger::IsActive()
|
||||
{
|
||||
if (!IsInstanceTimerManager(botAI, bot))
|
||||
if (!IsMechanicTrackerBot(botAI, bot, KARAZHAN_MAP_ID, nullptr))
|
||||
return false;
|
||||
|
||||
Unit* midnight = AI_VALUE2(Unit*, "find target", "midnight");
|
||||
@@ -110,7 +111,7 @@ bool BigBadWolfBossIsChasingLittleRedRidingHoodTrigger::IsActive()
|
||||
|
||||
bool RomuloAndJulianneBothBossesRevivedTrigger::IsActive()
|
||||
{
|
||||
if (!IsInstanceTimerManager(botAI, bot))
|
||||
if (!IsMechanicTrackerBot(botAI, bot, KARAZHAN_MAP_ID, nullptr))
|
||||
return false;
|
||||
|
||||
Unit* romulo = AI_VALUE2(Unit*, "find target", "romulo");
|
||||
@@ -126,7 +127,7 @@ bool RomuloAndJulianneBothBossesRevivedTrigger::IsActive()
|
||||
|
||||
bool WizardOfOzNeedTargetPriorityTrigger::IsActive()
|
||||
{
|
||||
if (!IsInstanceTimerManager(botAI, bot))
|
||||
if (!IsMechanicTrackerBot(botAI, bot, KARAZHAN_MAP_ID, nullptr))
|
||||
return false;
|
||||
|
||||
Unit* dorothee = AI_VALUE2(Unit*, "find target", "dorothee");
|
||||
@@ -178,7 +179,7 @@ bool TheCuratorBossAstralFlaresCastArcingSearTrigger::IsActive()
|
||||
|
||||
bool TerestianIllhoofNeedTargetPriorityTrigger::IsActive()
|
||||
{
|
||||
if (!IsInstanceTimerManager(botAI, bot))
|
||||
if (!IsMechanicTrackerBot(botAI, bot, KARAZHAN_MAP_ID, nullptr))
|
||||
return false;
|
||||
|
||||
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
|
||||
bool ShadeOfAranConjuredElementalsSummonedTrigger::IsActive()
|
||||
{
|
||||
if (!IsInstanceTimerManager(botAI, bot))
|
||||
if (!IsMechanicTrackerBot(botAI, bot, KARAZHAN_MAP_ID, nullptr))
|
||||
return false;
|
||||
|
||||
Unit* elemental = AI_VALUE2(Unit*, "find target", "conjured elemental");
|
||||
@@ -279,7 +280,7 @@ bool NetherspiteBossIsBanishedTrigger::IsActive()
|
||||
|
||||
bool NetherspiteNeedToManageTimersAndTrackersTrigger::IsActive()
|
||||
{
|
||||
if (!botAI->IsTank(bot) && !IsInstanceTimerManager(botAI, bot))
|
||||
if (!botAI->IsTank(bot) && !IsMechanicTrackerBot(botAI, bot, KARAZHAN_MAP_ID, nullptr))
|
||||
return false;
|
||||
|
||||
Unit* netherspite = AI_VALUE2(Unit*, "find target", "netherspite");
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "RaidKarazhanHelpers.h"
|
||||
#include "RaidKarazhanActions.h"
|
||||
#include "Playerbots.h"
|
||||
#include "RtiTargetValue.h"
|
||||
|
||||
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_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)
|
||||
{
|
||||
for (Unit* unit : units)
|
||||
@@ -132,44 +62,6 @@ namespace KarazhanHelpers
|
||||
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)
|
||||
{
|
||||
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_MOUNTED = 16152,
|
||||
|
||||
// Terestian Illhoof
|
||||
NPC_TERESTIAN_ILLHOOF = 15688,
|
||||
NPC_DEMON_CHAINS = 17248,
|
||||
NPC_KILREK = 17229,
|
||||
|
||||
// Shade of Aran
|
||||
NPC_CONJURED_ELEMENTAL = 17167,
|
||||
|
||||
@@ -74,8 +79,8 @@ namespace KarazhanHelpers
|
||||
NPC_NETHERSPITE_INFERNAL = 17646,
|
||||
};
|
||||
|
||||
const uint32 KARAZHAN_MAP_ID = 532;
|
||||
const float NIGHTBANE_FLIGHT_Z = 95.0f;
|
||||
constexpr uint32 KARAZHAN_MAP_ID = 532;
|
||||
constexpr float NIGHTBANE_FLIGHT_Z = 95.0f;
|
||||
|
||||
// Attumen the Huntsman
|
||||
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_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* GetFirstAliveUnitByEntry(PlayerbotAI* botAI, uint32 entry);
|
||||
Unit* GetNearestPlayerInRadius(Player* bot, float radius);
|
||||
bool IsFlameWreathActive(PlayerbotAI* botAI, Player* bot);
|
||||
std::vector<Player*> GetRedBlockers(PlayerbotAI* botAI, Player* bot);
|
||||
std::vector<Player*> GetBlueBlockers(PlayerbotAI* botAI, Player* bot);
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "ObjectAccessor.h"
|
||||
#include "ObjectGuid.h"
|
||||
#include "Playerbots.h"
|
||||
#include "RaidBossHelpers.h"
|
||||
|
||||
using namespace MagtheridonHelpers;
|
||||
|
||||
@@ -14,46 +15,45 @@ bool MagtheridonMainTankAttackFirstThreeChannelersAction::Execute(Event event)
|
||||
return false;
|
||||
|
||||
Creature* channelerSquare = GetChanneler(bot, SOUTH_CHANNELER);
|
||||
if (channelerSquare && channelerSquare->IsAlive())
|
||||
if (channelerSquare)
|
||||
MarkTargetWithSquare(bot, channelerSquare);
|
||||
|
||||
Creature* channelerStar = GetChanneler(bot, WEST_CHANNELER);
|
||||
if (channelerStar && channelerStar->IsAlive())
|
||||
if (channelerStar)
|
||||
MarkTargetWithStar(bot, channelerStar);
|
||||
|
||||
Creature* channelerCircle = GetChanneler(bot, EAST_CHANNELER);
|
||||
if (channelerCircle && channelerCircle->IsAlive())
|
||||
if (channelerCircle)
|
||||
MarkTargetWithCircle(bot, channelerCircle);
|
||||
|
||||
// After first three channelers are dead, wait for Magtheridon to activate
|
||||
if ((!channelerSquare || !channelerSquare->IsAlive()) &&
|
||||
(!channelerStar || !channelerStar->IsAlive()) &&
|
||||
(!channelerCircle || !channelerCircle->IsAlive()))
|
||||
if (!channelerSquare && !channelerStar && !channelerCircle)
|
||||
{
|
||||
const Location& position = MagtheridonsLairLocations::WaitingForMagtheridonPosition;
|
||||
if (!bot->IsWithinDist2d(position.x, position.y, 2.0f))
|
||||
const Position& position = WAITING_FOR_MAGTHERIDON_POSITION;
|
||||
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);
|
||||
}
|
||||
|
||||
bot->SetFacingTo(position.orientation);
|
||||
bot->SetFacingTo(position.GetOrientation());
|
||||
return true;
|
||||
}
|
||||
|
||||
Creature* currentTarget = nullptr;
|
||||
std::string rtiName;
|
||||
if (channelerSquare && channelerSquare->IsAlive())
|
||||
if (channelerSquare)
|
||||
{
|
||||
currentTarget = channelerSquare;
|
||||
rtiName = "square";
|
||||
}
|
||||
else if (channelerStar && channelerStar->IsAlive())
|
||||
else if (channelerStar)
|
||||
{
|
||||
currentTarget = channelerStar;
|
||||
rtiName = "star";
|
||||
}
|
||||
else if (channelerCircle && channelerCircle->IsAlive())
|
||||
else if (channelerCircle)
|
||||
{
|
||||
currentTarget = channelerCircle;
|
||||
rtiName = "circle";
|
||||
@@ -70,7 +70,7 @@ bool MagtheridonMainTankAttackFirstThreeChannelersAction::Execute(Event event)
|
||||
bool MagtheridonFirstAssistTankAttackNWChannelerAction::Execute(Event event)
|
||||
{
|
||||
Creature* channelerDiamond = GetChanneler(bot, NORTHWEST_CHANNELER);
|
||||
if (!channelerDiamond || !channelerDiamond->IsAlive())
|
||||
if (!channelerDiamond)
|
||||
return false;
|
||||
|
||||
MarkTargetWithDiamond(bot, channelerDiamond);
|
||||
@@ -81,18 +81,18 @@ bool MagtheridonFirstAssistTankAttackNWChannelerAction::Execute(Event event)
|
||||
|
||||
if (channelerDiamond->GetVictim() == bot)
|
||||
{
|
||||
const Location& position = MagtheridonsLairLocations::NWChannelerTankPosition;
|
||||
const Position& position = NW_CHANNELER_TANK_POSITION;
|
||||
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 dY = position.y - bot->GetPositionY();
|
||||
float dist = sqrt(dX * dX + dY * dY);
|
||||
float moveX = bot->GetPositionX() + (dX / dist) * maxDistance;
|
||||
float moveY = bot->GetPositionY() + (dY / dist) * maxDistance;
|
||||
float dX = position.GetPositionX() - bot->GetPositionX();
|
||||
float dY = position.GetPositionY() - bot->GetPositionY();
|
||||
float moveX = bot->GetPositionX() + (dX / distanceToPosition) * maxDistance;
|
||||
float moveY = bot->GetPositionY() + (dY / distanceToPosition) * 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);
|
||||
}
|
||||
}
|
||||
@@ -103,7 +103,7 @@ bool MagtheridonFirstAssistTankAttackNWChannelerAction::Execute(Event event)
|
||||
bool MagtheridonSecondAssistTankAttackNEChannelerAction::Execute(Event event)
|
||||
{
|
||||
Creature* channelerTriangle = GetChanneler(bot, NORTHEAST_CHANNELER);
|
||||
if (!channelerTriangle || !channelerTriangle->IsAlive())
|
||||
if (!channelerTriangle)
|
||||
return false;
|
||||
|
||||
MarkTargetWithTriangle(bot, channelerTriangle);
|
||||
@@ -114,18 +114,18 @@ bool MagtheridonSecondAssistTankAttackNEChannelerAction::Execute(Event event)
|
||||
|
||||
if (channelerTriangle->GetVictim() == bot)
|
||||
{
|
||||
const Location& position = MagtheridonsLairLocations::NEChannelerTankPosition;
|
||||
const Position& position = NE_CHANNELER_TANK_POSITION;
|
||||
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 dY = position.y - bot->GetPositionY();
|
||||
float dist = sqrt(dX * dX + dY * dY);
|
||||
float moveX = bot->GetPositionX() + (dX / dist) * maxDistance;
|
||||
float moveY = bot->GetPositionY() + (dY / dist) * maxDistance;
|
||||
float dX = position.GetPositionX() - bot->GetPositionX();
|
||||
float dY = position.GetPositionY() - bot->GetPositionY();
|
||||
float moveX = bot->GetPositionX() + (dX / distanceToPosition) * maxDistance;
|
||||
float moveY = bot->GetPositionY() + (dY / distanceToPosition) * 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);
|
||||
}
|
||||
}
|
||||
@@ -175,7 +175,7 @@ bool MagtheridonMisdirectHellfireChannelers::Execute(Event event)
|
||||
switch (hunterIndex)
|
||||
{
|
||||
case 0:
|
||||
if (mainTank && channelerStar && channelerStar->IsAlive() &&
|
||||
if (mainTank && channelerStar &&
|
||||
channelerStar->GetVictim() != mainTank)
|
||||
{
|
||||
if (botAI->CanCastSpell("misdirection", mainTank))
|
||||
@@ -190,7 +190,7 @@ bool MagtheridonMisdirectHellfireChannelers::Execute(Event event)
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if (mainTank && channelerCircle && channelerCircle->IsAlive() &&
|
||||
if (mainTank && channelerCircle &&
|
||||
channelerCircle->GetVictim() != mainTank)
|
||||
{
|
||||
if (botAI->CanCastSpell("misdirection", mainTank))
|
||||
@@ -215,90 +215,69 @@ bool MagtheridonAssignDPSPriorityAction::Execute(Event event)
|
||||
{
|
||||
// Listed in order of priority
|
||||
Creature* channelerSquare = GetChanneler(bot, SOUTH_CHANNELER);
|
||||
if (channelerSquare && channelerSquare->IsAlive())
|
||||
if (channelerSquare)
|
||||
{
|
||||
SetRtiTarget(botAI, "square", channelerSquare);
|
||||
|
||||
if (bot->GetTarget() != channelerSquare->GetGUID())
|
||||
{
|
||||
bot->SetSelection(channelerSquare->GetGUID());
|
||||
return Attack(channelerSquare);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Creature* channelerStar = GetChanneler(bot, WEST_CHANNELER);
|
||||
if (channelerStar && channelerStar->IsAlive())
|
||||
if (channelerStar)
|
||||
{
|
||||
SetRtiTarget(botAI, "star", channelerStar);
|
||||
|
||||
if (bot->GetTarget() != channelerStar->GetGUID())
|
||||
{
|
||||
bot->SetSelection(channelerStar->GetGUID());
|
||||
return Attack(channelerStar);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Creature* channelerCircle = GetChanneler(bot, EAST_CHANNELER);
|
||||
if (channelerCircle && channelerCircle->IsAlive())
|
||||
if (channelerCircle)
|
||||
{
|
||||
SetRtiTarget(botAI, "circle", channelerCircle);
|
||||
|
||||
if (bot->GetTarget() != channelerCircle->GetGUID())
|
||||
{
|
||||
bot->SetSelection(channelerCircle->GetGUID());
|
||||
return Attack(channelerCircle);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Creature* channelerDiamond = GetChanneler(bot, NORTHWEST_CHANNELER);
|
||||
if (channelerDiamond && channelerDiamond->IsAlive())
|
||||
if (channelerDiamond)
|
||||
{
|
||||
SetRtiTarget(botAI, "diamond", channelerDiamond);
|
||||
|
||||
if (bot->GetTarget() != channelerDiamond->GetGUID())
|
||||
{
|
||||
bot->SetSelection(channelerDiamond->GetGUID());
|
||||
return Attack(channelerDiamond);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Creature* channelerTriangle = GetChanneler(bot, NORTHEAST_CHANNELER);
|
||||
if (channelerTriangle && channelerTriangle->IsAlive())
|
||||
if (channelerTriangle)
|
||||
{
|
||||
SetRtiTarget(botAI, "triangle", channelerTriangle);
|
||||
|
||||
if (bot->GetTarget() != channelerTriangle->GetGUID())
|
||||
{
|
||||
bot->SetSelection(channelerTriangle->GetGUID());
|
||||
return Attack(channelerTriangle);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Unit* magtheridon = AI_VALUE2(Unit*, "find target", "magtheridon");
|
||||
if (magtheridon && !magtheridon->HasAura(SPELL_SHADOW_CAGE) &&
|
||||
(!channelerSquare || !channelerSquare->IsAlive()) &&
|
||||
(!channelerStar || !channelerStar->IsAlive()) &&
|
||||
(!channelerCircle || !channelerCircle->IsAlive()) &&
|
||||
(!channelerDiamond || !channelerDiamond->IsAlive()) &&
|
||||
(!channelerTriangle || !channelerTriangle->IsAlive()))
|
||||
!channelerSquare && !channelerStar && !channelerCircle &&
|
||||
!channelerDiamond && !channelerTriangle)
|
||||
{
|
||||
SetRtiTarget(botAI, "cross", magtheridon);
|
||||
|
||||
if (bot->GetTarget() != magtheridon->GetGUID())
|
||||
{
|
||||
bot->SetSelection(magtheridon->GetGUID());
|
||||
return Attack(magtheridon);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -343,15 +322,15 @@ bool MagtheridonWarlockCCBurningAbyssalAction::Execute(Event event)
|
||||
if (warlockIndex >= 0 && warlockIndex < abyssals.size())
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
for (size_t i = warlocks.size(); i < abyssals.size(); ++i)
|
||||
{
|
||||
Unit* excessAbyssal = abyssals[i];
|
||||
if (!excessAbyssal->HasAura(SPELL_BANISH) && !excessAbyssal->HasAura(SPELL_FEAR) &&
|
||||
botAI->CanCastSpell(SPELL_FEAR, excessAbyssal, true))
|
||||
if (!botAI->HasAura("banish", excessAbyssal) && !botAI->HasAura("fear", excessAbyssal) &&
|
||||
botAI->CanCastSpell("fear", excessAbyssal))
|
||||
return botAI->CastSpell("fear", excessAbyssal);
|
||||
}
|
||||
|
||||
@@ -373,22 +352,20 @@ bool MagtheridonMainTankPositionBossAction::Execute(Event event)
|
||||
|
||||
if (magtheridon->GetVictim() == bot)
|
||||
{
|
||||
const Location& position = MagtheridonsLairLocations::MagtheridonTankPosition;
|
||||
const Position& position = MAGTHERIDON_TANK_POSITION;
|
||||
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 dY = position.y - bot->GetPositionY();
|
||||
float dist = sqrt(dX * dX + dY * dY);
|
||||
float moveX = bot->GetPositionX() + (dX / dist) * maxDistance;
|
||||
float moveY = bot->GetPositionY() + (dY / dist) * maxDistance;
|
||||
float dX = position.GetPositionX() - bot->GetPositionX();
|
||||
float dY = position.GetPositionY() - bot->GetPositionY();
|
||||
float moveX = bot->GetPositionX() + (dX / distanceToPosition) * maxDistance;
|
||||
float moveY = bot->GetPositionY() + (dY / distanceToPosition) * 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);
|
||||
}
|
||||
|
||||
bot->SetFacingTo(position.orientation);
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -440,13 +417,13 @@ bool MagtheridonSpreadRangedAction::Execute(Event event)
|
||||
}
|
||||
|
||||
bool isHealer = botAI->IsHeal(bot);
|
||||
const Location& center = isHealer
|
||||
? MagtheridonsLairLocations::HealerSpreadPosition
|
||||
: MagtheridonsLairLocations::RangedSpreadPosition;
|
||||
const Position& center = isHealer
|
||||
? HEALER_SPREAD_POSITION
|
||||
: RANGED_SPREAD_POSITION;
|
||||
float maxSpreadRadius = isHealer ? 15.0f : 20.0f;
|
||||
float centerX = center.x;
|
||||
float centerY = center.y;
|
||||
float centerZ = bot->GetPositionZ();
|
||||
float centerX = center.GetPositionX();
|
||||
float centerY = center.GetPositionY();
|
||||
float centerZ = center.GetPositionZ();
|
||||
const float radiusBuffer = 3.0f;
|
||||
|
||||
if (!initialPositions.count(bot->GetGUID()))
|
||||
@@ -479,7 +456,7 @@ bool MagtheridonSpreadRangedAction::Execute(Event event)
|
||||
|
||||
bot->AttackStop();
|
||||
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);
|
||||
}
|
||||
hasReachedInitialPosition[bot->GetGUID()] = true;
|
||||
@@ -499,7 +476,7 @@ bool MagtheridonSpreadRangedAction::Execute(Event event)
|
||||
{
|
||||
bot->AttackStop();
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -593,7 +570,7 @@ bool MagtheridonUseManticronCubeAction::HandleWaitingPhase(const CubeInfo& cubeI
|
||||
{
|
||||
bot->AttackStop();
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -603,7 +580,7 @@ bool MagtheridonUseManticronCubeAction::HandleWaitingPhase(const CubeInfo& cubeI
|
||||
float fallbackY = cubeInfo.y + sin(angle) * safeWaitDistance;
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -638,7 +615,7 @@ bool MagtheridonUseManticronCubeAction::HandleCubeInteraction(const CubeInfo& cu
|
||||
|
||||
bot->AttackStop();
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -663,14 +640,14 @@ bool MagtheridonManageTimersAndAssignmentsAction::Execute(Event event)
|
||||
magtheridon->FindCurrentSpellBySpellId(SPELL_BLAST_NOVA);
|
||||
bool lastBlastNova = lastBlastNovaState[instanceId];
|
||||
|
||||
if (lastBlastNova && !blastNovaActive && IsInstanceTimerManager(botAI, bot))
|
||||
if (lastBlastNova && !blastNovaActive && IsMechanicTrackerBot(botAI, bot, MAGTHERIDON_MAP_ID, nullptr))
|
||||
blastNovaTimer[instanceId] = now;
|
||||
|
||||
lastBlastNovaState[instanceId] = blastNovaActive;
|
||||
|
||||
if (!magtheridon->HasAura(SPELL_SHADOW_CAGE))
|
||||
{
|
||||
if (IsInstanceTimerManager(botAI, bot))
|
||||
if (IsMechanicTrackerBot(botAI, bot, MAGTHERIDON_MAP_ID, nullptr))
|
||||
{
|
||||
spreadWaitTimer.try_emplace(instanceId, now);
|
||||
blastNovaTimer.try_emplace(instanceId, now);
|
||||
@@ -679,11 +656,12 @@ bool MagtheridonManageTimersAndAssignmentsAction::Execute(Event event)
|
||||
}
|
||||
else
|
||||
{
|
||||
MagtheridonSpreadRangedAction::initialPositions.clear();
|
||||
MagtheridonSpreadRangedAction::hasReachedInitialPosition.clear();
|
||||
botToCubeAssignment.clear();
|
||||
ObjectGuid guid = bot->GetGUID();
|
||||
MagtheridonSpreadRangedAction::initialPositions.erase(guid);
|
||||
MagtheridonSpreadRangedAction::hasReachedInitialPosition.erase(guid);
|
||||
botToCubeAssignment.erase(guid);
|
||||
|
||||
if (IsInstanceTimerManager(botAI, bot))
|
||||
if (IsMechanicTrackerBot(botAI, bot, MAGTHERIDON_MAP_ID, nullptr))
|
||||
{
|
||||
spreadWaitTimer.erase(instanceId);
|
||||
blastNovaTimer.erase(instanceId);
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
#include "AttackAction.h"
|
||||
#include "MovementActions.h"
|
||||
|
||||
using namespace MagtheridonHelpers;
|
||||
|
||||
class MagtheridonMainTankAttackFirstThreeChannelersAction : public AttackAction
|
||||
{
|
||||
public:
|
||||
@@ -85,8 +83,8 @@ public:
|
||||
private:
|
||||
bool HandleCubeRelease(Unit* magtheridon, GameObject* cube);
|
||||
bool ShouldActivateCubeLogic(Unit* magtheridon);
|
||||
bool HandleWaitingPhase(const CubeInfo& cubeInfo);
|
||||
bool HandleCubeInteraction(const CubeInfo& cubeInfo, GameObject* cube);
|
||||
bool HandleWaitingPhase(const MagtheridonHelpers::CubeInfo& cubeInfo);
|
||||
bool HandleCubeInteraction(const MagtheridonHelpers::CubeInfo& cubeInfo, GameObject* cube);
|
||||
};
|
||||
|
||||
class MagtheridonManageTimersAndAssignmentsAction : public Action
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "GenericSpellActions.h"
|
||||
#include "Playerbots.h"
|
||||
#include "WarlockActions.h"
|
||||
#include "WipeAction.h"
|
||||
|
||||
using namespace MagtheridonHelpers;
|
||||
|
||||
@@ -24,10 +25,10 @@ float MagtheridonUseManticronCubeMultiplier::GetValue(Action* action)
|
||||
auto it = botToCubeAssignment.find(bot->GetGUID());
|
||||
if (it != botToCubeAssignment.end())
|
||||
{
|
||||
if (dynamic_cast<MagtheridonUseManticronCubeAction*>(action))
|
||||
if (dynamic_cast<WipeAction*>(action))
|
||||
return 1.0f;
|
||||
|
||||
return 0.0f;
|
||||
else if (!dynamic_cast<MagtheridonUseManticronCubeAction*>(action))
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,28 +42,31 @@ float MagtheridonWaitToAttackMultiplier::GetValue(Action* action)
|
||||
if (!magtheridon || magtheridon->HasAura(SPELL_SHADOW_CAGE))
|
||||
return 1.0f;
|
||||
|
||||
if (botAI->IsMainTank(bot))
|
||||
return 1.0f;
|
||||
|
||||
const uint8 dpsWaitSeconds = 6;
|
||||
auto it = dpsWaitTimer.find(magtheridon->GetMap()->GetInstanceId());
|
||||
if (it == dpsWaitTimer.end() ||
|
||||
(time(nullptr) - it->second) < dpsWaitSeconds)
|
||||
{
|
||||
if (!botAI->IsMainTank(bot) && (dynamic_cast<AttackAction*>(action) ||
|
||||
(!botAI->IsHeal(bot) && dynamic_cast<CastSpellAction*>(action))))
|
||||
if (dynamic_cast<AttackAction*>(action) ||
|
||||
(!botAI->IsHeal(bot) && dynamic_cast<CastSpellAction*>(action)))
|
||||
return 0.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)
|
||||
{
|
||||
Unit* magtheridon = AI_VALUE2(Unit*, "find target", "magtheridon");
|
||||
Unit* channeler = AI_VALUE2(Unit*, "find target", "hellfire channeler");
|
||||
if (!magtheridon)
|
||||
return 1.0f;
|
||||
|
||||
if (bot->GetVictim() == nullptr)
|
||||
return 1.0f;
|
||||
|
||||
if ((botAI->IsAssistTankOfIndex(bot, 0) || botAI->IsAssistTankOfIndex(bot, 1)) &&
|
||||
dynamic_cast<TankAssistAction*>(action))
|
||||
return 0.0f;
|
||||
|
||||
@@ -18,7 +18,7 @@ bool MagtheridonNWChannelerEngagedByFirstAssistTankTrigger::IsActive()
|
||||
Creature* channelerDiamond = GetChanneler(bot, NORTHWEST_CHANNELER);
|
||||
|
||||
return magtheridon && botAI->IsAssistTankOfIndex(bot, 0) &&
|
||||
channelerDiamond && channelerDiamond->IsAlive();
|
||||
channelerDiamond;
|
||||
}
|
||||
|
||||
bool MagtheridonNEChannelerEngagedBySecondAssistTankTrigger::IsActive()
|
||||
@@ -27,7 +27,7 @@ bool MagtheridonNEChannelerEngagedBySecondAssistTankTrigger::IsActive()
|
||||
Creature* channelerTriangle = GetChanneler(bot, NORTHEAST_CHANNELER);
|
||||
|
||||
return magtheridon && botAI->IsAssistTankOfIndex(bot, 1) &&
|
||||
channelerTriangle && channelerTriangle->IsAlive();
|
||||
channelerTriangle;
|
||||
}
|
||||
|
||||
bool MagtheridonPullingWestAndEastChannelersTrigger::IsActive()
|
||||
@@ -38,8 +38,7 @@ bool MagtheridonPullingWestAndEastChannelersTrigger::IsActive()
|
||||
Creature* channelerCircle = GetChanneler(bot, EAST_CHANNELER);
|
||||
|
||||
return magtheridon && bot->getClass() == CLASS_HUNTER &&
|
||||
((channelerStar && channelerStar->IsAlive()) ||
|
||||
(channelerCircle && channelerCircle->IsAlive()));
|
||||
(channelerStar || channelerCircle);
|
||||
}
|
||||
|
||||
bool MagtheridonDeterminingKillOrderTrigger::IsActive()
|
||||
@@ -51,12 +50,11 @@ bool MagtheridonDeterminingKillOrderTrigger::IsActive()
|
||||
Creature* channelerTriangle = GetChanneler(bot, NORTHEAST_CHANNELER);
|
||||
|
||||
if (!magtheridon || botAI->IsHeal(bot) || botAI->IsMainTank(bot) ||
|
||||
(botAI->IsAssistTankOfIndex(bot, 0) && channelerDiamond && channelerDiamond->IsAlive()) ||
|
||||
(botAI->IsAssistTankOfIndex(bot, 1) && channelerTriangle && channelerTriangle->IsAlive()))
|
||||
(botAI->IsAssistTankOfIndex(bot, 0) && channelerDiamond) ||
|
||||
(botAI->IsAssistTankOfIndex(bot, 1) && channelerTriangle))
|
||||
return false;
|
||||
|
||||
return (channeler && channeler->IsAlive()) || (magtheridon &&
|
||||
!magtheridon->HasAura(SPELL_SHADOW_CAGE));
|
||||
return channeler || (magtheridon && !magtheridon->HasAura(SPELL_SHADOW_CAGE));
|
||||
}
|
||||
|
||||
bool MagtheridonBurningAbyssalSpawnedTrigger::IsActive()
|
||||
@@ -84,10 +82,8 @@ bool MagtheridonBossEngagedByMainTankTrigger::IsActive()
|
||||
bool MagtheridonBossEngagedByRangedTrigger::IsActive()
|
||||
{
|
||||
Unit* magtheridon = AI_VALUE2(Unit*, "find target", "magtheridon");
|
||||
Unit* channeler = AI_VALUE2(Unit*, "find target", "hellfire channeler");
|
||||
|
||||
return magtheridon && botAI->IsRanged(bot) &&
|
||||
!(channeler && channeler->IsAlive());
|
||||
return magtheridon && !magtheridon->HasAura(SPELL_SHADOW_CAGE) && botAI->IsRanged(bot);
|
||||
}
|
||||
|
||||
bool MagtheridonIncomingBlastNovaTrigger::IsActive()
|
||||
@@ -122,7 +118,5 @@ bool MagtheridonIncomingBlastNovaTrigger::IsActive()
|
||||
|
||||
bool MagtheridonNeedToManageTimersAndAssignmentsTrigger::IsActive()
|
||||
{
|
||||
Unit* magtheridon = AI_VALUE2(Unit*, "find target", "magtheridon");
|
||||
|
||||
return magtheridon;
|
||||
return AI_VALUE2(Unit*, "find target", "magtheridon");
|
||||
}
|
||||
|
||||
@@ -1,22 +1,18 @@
|
||||
#include "RaidMagtheridonHelpers.h"
|
||||
#include "Creature.h"
|
||||
#include "GameObject.h"
|
||||
#include "GroupReference.h"
|
||||
#include "Map.h"
|
||||
#include "ObjectGuid.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
namespace MagtheridonHelpers
|
||||
{
|
||||
namespace MagtheridonsLairLocations
|
||||
{
|
||||
const Location WaitingForMagtheridonPosition = { 1.359f, 2.048f, -0.406f, 3.135f };
|
||||
const Location MagtheridonTankPosition = { 22.827f, 2.105f, -0.406f, 3.135f };
|
||||
const Location NWChannelerTankPosition = { -11.764f, 30.818f, -0.411f, 0.0f };
|
||||
const Location NEChannelerTankPosition = { -12.490f, -26.211f, -0.411f, 0.0f };
|
||||
const Location RangedSpreadPosition = { -14.890f, 1.995f, -0.406f, 0.0f };
|
||||
const Location HealerSpreadPosition = { -2.265f, 1.874f, -0.404f, 0.0f };
|
||||
}
|
||||
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 Position NW_CHANNELER_TANK_POSITION = { -11.764f, 30.818f, -0.411f, 0.0f };
|
||||
const Position NE_CHANNELER_TANK_POSITION = { -12.490f, -26.211f, -0.411f, 0.0f };
|
||||
const Position RANGED_SPREAD_POSITION = { -14.890f, 1.995f, -0.406f, 0.0f };
|
||||
const Position HEALER_SPREAD_POSITION = { -2.265f, 1.874f, -0.404f, 0.0f };
|
||||
|
||||
// Identify channelers by their database GUIDs
|
||||
Creature* GetChanneler(Player* bot, uint32 dbGuid)
|
||||
@@ -29,63 +25,11 @@ namespace MagtheridonHelpers
|
||||
if (it == map->GetCreatureBySpawnIdStore().end())
|
||||
return nullptr;
|
||||
|
||||
return it->second;
|
||||
}
|
||||
Creature* channeler = it->second;
|
||||
if (!channeler->IsAlive())
|
||||
return nullptr;
|
||||
|
||||
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 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);
|
||||
return channeler;
|
||||
}
|
||||
|
||||
const std::vector<uint32> MANTICRON_CUBE_DB_GUIDS = { 43157, 43158, 43159, 43160, 43161 };
|
||||
@@ -208,19 +152,4 @@ namespace MagtheridonHelpers
|
||||
|
||||
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 "ObjectGuid.h"
|
||||
#include "PlayerbotAI.h"
|
||||
#include "RtiTargetValue.h"
|
||||
|
||||
namespace MagtheridonHelpers
|
||||
{
|
||||
@@ -19,10 +18,6 @@ namespace MagtheridonHelpers
|
||||
SPELL_BLAST_NOVA = 30616,
|
||||
SPELL_SHADOW_GRASP = 30410,
|
||||
|
||||
// Warlock
|
||||
SPELL_BANISH = 18647,
|
||||
SPELL_FEAR = 6215,
|
||||
|
||||
// Hunter
|
||||
SPELL_MISDIRECTION = 35079,
|
||||
};
|
||||
@@ -38,6 +33,7 @@ namespace MagtheridonHelpers
|
||||
GO_BLAZE = 181832,
|
||||
};
|
||||
|
||||
constexpr uint32 MAGTHERIDON_MAP_ID = 544;
|
||||
constexpr uint32 SOUTH_CHANNELER = 90978;
|
||||
constexpr uint32 WEST_CHANNELER = 90979;
|
||||
constexpr uint32 NORTHWEST_CHANNELER = 90980;
|
||||
@@ -45,31 +41,14 @@ namespace MagtheridonHelpers
|
||||
constexpr uint32 NORTHEAST_CHANNELER = 90981;
|
||||
|
||||
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 IsInstanceTimerManager(PlayerbotAI* botAI, Player* bot);
|
||||
|
||||
struct Location
|
||||
{
|
||||
float x, y, z, orientation;
|
||||
};
|
||||
|
||||
namespace MagtheridonsLairLocations
|
||||
{
|
||||
extern const Location WaitingForMagtheridonPosition;
|
||||
extern const Location MagtheridonTankPosition;
|
||||
extern const Location NWChannelerTankPosition;
|
||||
extern const Location NEChannelerTankPosition;
|
||||
extern const Location RangedSpreadPosition;
|
||||
extern const Location HealerSpreadPosition;
|
||||
}
|
||||
extern const Position WAITING_FOR_MAGTHERIDON_POSITION;
|
||||
extern const Position MAGTHERIDON_TANK_POSITION;
|
||||
extern const Position NW_CHANNELER_TANK_POSITION;
|
||||
extern const Position NE_CHANNELER_TANK_POSITION;
|
||||
extern const Position RANGED_SPREAD_POSITION;
|
||||
extern const Position HEALER_SPREAD_POSITION;
|
||||
|
||||
struct CubeInfo
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define _PLAYERBOT_RAIDMCACTIONCONTEXT_H
|
||||
|
||||
#include "Action.h"
|
||||
#include "BossAuraActions.h"
|
||||
#include "NamedObjectContext.h"
|
||||
#include "RaidMcActions.h"
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define _PLAYERBOT_RAIDMCTRIGGERCONTEXT_H
|
||||
|
||||
#include "AiObjectContext.h"
|
||||
#include "BossAuraTriggers.h"
|
||||
#include "NamedObjectContext.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-eoe"] = &RaidStrategyContext::wotlk_eoe;
|
||||
creators["voa"] = &RaidStrategyContext::voa;
|
||||
creators["uld"] = &RaidStrategyContext::uld;
|
||||
creators["ulduar"] = &RaidStrategyContext::ulduar;
|
||||
creators["onyxia"] = &RaidStrategyContext::onyxia;
|
||||
creators["icc"] = &RaidStrategyContext::icc;
|
||||
}
|
||||
@@ -45,7 +45,7 @@ private:
|
||||
static Strategy* wotlk_eoe(PlayerbotAI* botAI) { return new RaidEoEStrategy(botAI); }
|
||||
static Strategy* voa(PlayerbotAI* botAI) { return new RaidVoAStrategy(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); }
|
||||
};
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#include "GameObject.h"
|
||||
#include "Group.h"
|
||||
#include "LastMovementValue.h"
|
||||
#include "ObjectDefines.h"
|
||||
#include "ObjectGuid.h"
|
||||
#include "PlayerbotAI.h"
|
||||
#include "PlayerbotAIConfig.h"
|
||||
@@ -19,11 +18,9 @@
|
||||
#include "Position.h"
|
||||
#include "RaidUlduarBossHelper.h"
|
||||
#include "RaidUlduarScripts.h"
|
||||
#include "RaidUlduarStrategy.h"
|
||||
#include "RtiValue.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "ServerFacade.h"
|
||||
#include "SharedDefines.h"
|
||||
#include "Unit.h"
|
||||
#include "Vehicle.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 "RaidUlduarMultipliers.h"
|
||||
|
||||
void RaidUlduarStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
//
|
||||
@@ -316,8 +314,3 @@ void RaidUlduarStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
"yogg-saron phase 3 positioning trigger",
|
||||
{ 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
|
||||
|
||||
#include "AiObjectContext.h"
|
||||
#include "Multiplier.h"
|
||||
#include "Strategy.h"
|
||||
|
||||
class RaidUlduarStrategy : public Strategy
|
||||
{
|
||||
public:
|
||||
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 InitMultipliers(std::vector<Multiplier*>& multipliers) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1634,7 +1634,7 @@ bool VezaxShadowCrashTrigger::IsActive()
|
||||
return false;
|
||||
}
|
||||
|
||||
return botAI->HasAura(SPELL_SHADOW_CRASH, bot);
|
||||
return botAI->HasAura(SPELL_VEZAX_SHADOW_CRASH, bot);
|
||||
}
|
||||
|
||||
bool VezaxMarkOfTheFacelessTrigger::IsActive()
|
||||
|
||||
@@ -3,187 +3,9 @@
|
||||
|
||||
#include "EventMap.h"
|
||||
#include "GenericTriggers.h"
|
||||
#include "PlayerbotAIConfig.h"
|
||||
#include "RaidUlduarBossHelper.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
|
||||
//
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#include "ChatHelper.h"
|
||||
#include "RaidUlduarBossHelper.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "GameObject.h"
|
||||
@@ -9,6 +8,44 @@
|
||||
#include "Playerbots.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
|
||||
std::unordered_map<ObjectGuid, time_t> RazorscaleBossHelper::_harpoonCooldowns;
|
||||
// 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
|
||||
|
||||
#include "Action.h"
|
||||
#include "BossAuraActions.h"
|
||||
#include "NamedObjectContext.h"
|
||||
#include "RaidVoAActions.h"
|
||||
#include "PlayerbotAI.h"
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#define _PLAYERBOT_RAIDVOATRIGGERCONTEXT_H
|
||||
|
||||
#include "AiObjectContext.h"
|
||||
#include "BossAuraTriggers.h"
|
||||
#include "NamedObjectContext.h"
|
||||
#include "RaidVoATriggers.h"
|
||||
|
||||
|
||||
@@ -15,8 +15,6 @@
|
||||
#include "PaladinAiObjectContext.h"
|
||||
#include "Playerbots.h"
|
||||
#include "PriestAiObjectContext.h"
|
||||
#include "RaidUlduarActionContext.h"
|
||||
#include "RaidUlduarTriggerContext.h"
|
||||
#include "RogueAiObjectContext.h"
|
||||
#include "ShamanAiObjectContext.h"
|
||||
#include "SharedValueContext.h"
|
||||
@@ -49,6 +47,8 @@
|
||||
#include "Ai/Raid/VaultOfArchavon/RaidVoATriggerContext.h"
|
||||
#include "Ai/Raid/ObsidianSanctum/RaidOsActionContext.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/RaidOnyxiaTriggerContext.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))
|
||||
{
|
||||
if (itemId == 46978) // shaman earth ring totem
|
||||
{
|
||||
continue;
|
||||
}
|
||||
uint32 skipProb = 25;
|
||||
if (urand(1, 100) <= skipProb)
|
||||
continue;
|
||||
|
||||
@@ -1585,7 +1585,7 @@ void PlayerbotAI::ApplyInstanceStrategies(uint32 mapId, bool tellMaster)
|
||||
strategyName = "wotlk-hol"; // Halls of Lightning
|
||||
break;
|
||||
case 603:
|
||||
strategyName = "uld"; // Ulduar
|
||||
strategyName = "ulduar"; // Ulduar
|
||||
break;
|
||||
case 604:
|
||||
strategyName = "wotlk-gd"; // Gundrak
|
||||
|
||||
@@ -1784,7 +1784,7 @@ void RandomPlayerbotMgr::PrepareZone2LevelBracket()
|
||||
zone2LevelBracket[3525] = {10, 21}; // Bloodmyst Isle
|
||||
|
||||
// Classic WoW - High - level zones
|
||||
zone2LevelBracket[10] = {19, 33}; // Deadwind Pass
|
||||
zone2LevelBracket[10] = {19, 33}; // Duskwood
|
||||
zone2LevelBracket[11] = {21, 30}; // Wetlands
|
||||
zone2LevelBracket[44] = {16, 28}; // Redridge Mountains
|
||||
zone2LevelBracket[267] = {20, 34}; // Hillsbrad Foothills
|
||||
|
||||
@@ -2256,10 +2256,13 @@ void RandomItemMgr::BuildEquipCacheNew()
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
equipCacheNew[proto->RequiredLevel][proto->InventoryType].push_back(itemId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,9 +14,11 @@
|
||||
#include "PlayerbotOperation.h"
|
||||
#include "Player.h"
|
||||
#include "PlayerbotAI.h"
|
||||
#include "PlayerbotAIConfig.h"
|
||||
#include "PlayerbotMgr.h"
|
||||
#include "PlayerbotRepository.h"
|
||||
#include "RandomPlayerbotMgr.h"
|
||||
#include "UseMeetingStoneAction.h"
|
||||
#include "WorldSession.h"
|
||||
#include "WorldSessionMgr.h"
|
||||
|
||||
@@ -74,6 +76,15 @@ public:
|
||||
if (group->AddMember(target))
|
||||
{
|
||||
LOG_DEBUG("playerbots", "GroupInviteOperation: Successfully added {} to group", target->GetName());
|
||||
if (sPlayerbotAIConfig.summonWhenGroup && target->GetDistance(bot) > sPlayerbotAIConfig.sightDistance)
|
||||
{
|
||||
PlayerbotAI* targetAI = sPlayerbotsMgr.GetPlayerbotAI(target);
|
||||
if (targetAI)
|
||||
{
|
||||
SummonAction summonAction(targetAI, "group summon");
|
||||
summonAction.Teleport(bot, target, true);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
|
||||
Reference in New Issue
Block a user