- Added generic boss aura triggers and actions (#1242)

- Added Freya strategy
- Added or updated aura resistance strategies for ulduar
This commit is contained in:
kadeshar
2025-04-27 12:48:16 +02:00
committed by GitHub
parent 34a888978e
commit d8436b8270
11 changed files with 713 additions and 409 deletions

View File

@@ -0,0 +1,52 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
* and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#include <HunterBuffStrategies.h>
#include <PaladinBuffStrategies.h>
#include <PlayerbotAI.h>
#include "BossAuraActions.h"
#include "BossAuraTriggers.h"
const std::string ADD_STRATEGY_CHAR = "+";
bool BossFireResistanceAction::isUseful()
{
BossFireResistanceTrigger bossFireResistanceTrigger(botAI, bossName);
return bossFireResistanceTrigger.IsActive();
}
bool BossFireResistanceAction::Execute(Event event)
{
PaladinFireResistanceStrategy paladinFireResistanceStrategy(botAI);
botAI->ChangeStrategy(ADD_STRATEGY_CHAR + paladinFireResistanceStrategy.getName(), BotState::BOT_STATE_COMBAT);
return true;
}
bool BossFrostResistanceAction::isUseful()
{
BossFrostResistanceTrigger bossFrostResistanceTrigger(botAI, bossName);
return bossFrostResistanceTrigger.IsActive();
}
bool BossFrostResistanceAction::Execute(Event event)
{
PaladinFrostResistanceStrategy paladinFrostResistanceStrategy(botAI);
botAI->ChangeStrategy(ADD_STRATEGY_CHAR + paladinFrostResistanceStrategy.getName(), BotState::BOT_STATE_COMBAT);
return true;
}
bool BossNatureResistanceAction::isUseful()
{
BossNatureResistanceTrigger bossNatureResistanceTrigger(botAI, bossName);
return bossNatureResistanceTrigger.IsActive();
}
bool BossNatureResistanceAction::Execute(Event event)
{
HunterNatureResistanceStrategy hunterNatureResistanceStrategy(botAI);
botAI->ChangeStrategy(ADD_STRATEGY_CHAR + hunterNatureResistanceStrategy.getName(), BotState::BOT_STATE_COMBAT);
return true;
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
* and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_BOSSAURAACTION_H
#define _PLAYERBOT_BOSSAURAACTION_H
#include <string>
#include "Action.h"
class PlayerbotAI;
class BossFireResistanceAction : public Action
{
public:
BossFireResistanceAction(PlayerbotAI* botAI, std::string const bossName)
: Action(botAI, bossName + " fire resistance action"), bossName(bossName)
{
}
bool Execute(Event event) override;
bool isUseful() override;
private:
std::string bossName;
};
class BossFrostResistanceAction : public Action
{
public:
BossFrostResistanceAction(PlayerbotAI* botAI, std::string const bossName)
: Action(botAI, bossName + " frost resistance action"), bossName(bossName)
{
}
bool Execute(Event event) override;
bool isUseful() override;
private:
std::string bossName;
};
class BossNatureResistanceAction : public Action
{
public:
BossNatureResistanceAction(PlayerbotAI* botAI, std::string const bossName)
: Action(botAI, bossName + " nature resistance action"), bossName(bossName)
{
}
bool Execute(Event event) override;
bool isUseful() override;
private:
std::string bossName;
};
#endif

View File

@@ -9,6 +9,7 @@
#include "Action.h" #include "Action.h"
#include "NamedObjectContext.h" #include "NamedObjectContext.h"
#include "RaidUlduarActions.h" #include "RaidUlduarActions.h"
#include "BossAuraActions.h"
class RaidUlduarActionContext : public NamedObjectContext<Action> class RaidUlduarActionContext : public NamedObjectContext<Action>
{ {
@@ -36,7 +37,12 @@ public:
creators["hodir biting cold jump"] = &RaidUlduarActionContext::hodir_biting_cold_jump; creators["hodir biting cold jump"] = &RaidUlduarActionContext::hodir_biting_cold_jump;
creators["hodir frost resistance action"] = &RaidUlduarActionContext::hodir_frost_resistance_action; creators["hodir frost resistance action"] = &RaidUlduarActionContext::hodir_frost_resistance_action;
creators["freya move away nature bomb"] = &RaidUlduarActionContext::freya_move_away_nature_bomb; creators["freya move away nature bomb"] = &RaidUlduarActionContext::freya_move_away_nature_bomb;
creators["freya mark eonars gift"] = &RaidUlduarActionContext::freya_mark_eonars_gift; creators["freya fire resistance action"] = &RaidUlduarActionContext::freya_fire_resistance_action;
creators["freya nature resistance action"] = &RaidUlduarActionContext::freya_nature_resistance_action;
creators["freya mark dps target action"] = &RaidUlduarActionContext::freya_mark_dps_target_action;
creators["freya move to healing spore action"] = &RaidUlduarActionContext::freya_move_to_healing_spore_action;
creators["thorim nature resistance action"] = &RaidUlduarActionContext::thorim_nature_resistance_action;
creators["mimiron fire resistance action"] = &RaidUlduarActionContext::mimiron_fire_resistance_action;
} }
private: private:
@@ -49,19 +55,24 @@ private:
static Action* razorscale_grounded(PlayerbotAI* ai) { return new RazorscaleGroundedAction(ai); } static Action* razorscale_grounded(PlayerbotAI* ai) { return new RazorscaleGroundedAction(ai); }
static Action* razorscale_harpoon_action(PlayerbotAI* ai) { return new RazorscaleHarpoonAction(ai); } static Action* razorscale_harpoon_action(PlayerbotAI* ai) { return new RazorscaleHarpoonAction(ai); }
static Action* razorscale_fuse_armor_action(PlayerbotAI* ai) { return new RazorscaleFuseArmorAction(ai); } static Action* razorscale_fuse_armor_action(PlayerbotAI* ai) { return new RazorscaleFuseArmorAction(ai); }
static Action* razorscale_fire_resistance_action(PlayerbotAI* ai) { return new RazorscaleFireResistanceAction(ai); } static Action* razorscale_fire_resistance_action(PlayerbotAI* ai) { return new BossFireResistanceAction(ai, "razorscale"); }
static Action* ignis_fire_resistance_action(PlayerbotAI* ai) { return new IgnisFireResistanceAction(ai); } static Action* ignis_fire_resistance_action(PlayerbotAI* ai) { return new BossFireResistanceAction(ai, "ignis the furnace master"); }
static Action* iron_assembly_lightning_tendrils_action(PlayerbotAI* ai) { return new IronAssemblyLightningTendrilsAction(ai); } static Action* iron_assembly_lightning_tendrils_action(PlayerbotAI* ai) { return new IronAssemblyLightningTendrilsAction(ai); }
static Action* iron_assembly_overload_action(PlayerbotAI* ai) { return new IronAssemblyOverloadAction(ai); } static Action* iron_assembly_overload_action(PlayerbotAI* ai) { return new IronAssemblyOverloadAction(ai); }
static Action* kologarn_mark_dps_target_action(PlayerbotAI* ai) { return new KologarnMarkDpsTargetAction(ai); } static Action* kologarn_mark_dps_target_action(PlayerbotAI* ai) { return new KologarnMarkDpsTargetAction(ai); }
static Action* kologarn_fall_from_floor_action(PlayerbotAI* ai) { return new KologarnFallFromFloorAction(ai); } static Action* kologarn_fall_from_floor_action(PlayerbotAI* ai) { return new KologarnFallFromFloorAction(ai); }
static Action* kologarn_nature_resistance_action(PlayerbotAI* ai) { return new KologarnNatureResistanceAction(ai); } static Action* kologarn_nature_resistance_action(PlayerbotAI* ai) { return new BossNatureResistanceAction(ai, "kologarn"); }
static Action* kologarn_rubble_slowdown_action(PlayerbotAI* ai) { return new KologarnRubbleSlowdownAction(ai); } static Action* kologarn_rubble_slowdown_action(PlayerbotAI* ai) { return new KologarnRubbleSlowdownAction(ai); }
static Action* hodir_move_snowpacked_icicle(PlayerbotAI* ai) { return new HodirMoveSnowpackedIcicleAction(ai); } static Action* hodir_move_snowpacked_icicle(PlayerbotAI* ai) { return new HodirMoveSnowpackedIcicleAction(ai); }
static Action* hodir_biting_cold_jump(PlayerbotAI* ai) { return new HodirBitingColdJumpAction(ai); } static Action* hodir_biting_cold_jump(PlayerbotAI* ai) { return new HodirBitingColdJumpAction(ai); }
static Action* hodir_frost_resistance_action(PlayerbotAI* ai) { return new HodirFrostResistanceAction(ai); } static Action* hodir_frost_resistance_action(PlayerbotAI* ai) { return new BossFrostResistanceAction(ai, "hodir"); }
static Action* freya_move_away_nature_bomb(PlayerbotAI* ai) { return new FreyaMoveAwayNatureBombAction(ai); } static Action* freya_move_away_nature_bomb(PlayerbotAI* ai) { return new FreyaMoveAwayNatureBombAction(ai); }
static Action* freya_mark_eonars_gift(PlayerbotAI* ai) { return new FreyaMarkEonarsGiftAction(ai); } static Action* freya_fire_resistance_action(PlayerbotAI* ai) { return new BossFireResistanceAction(ai, "freya"); }
static Action* freya_nature_resistance_action(PlayerbotAI* ai) { return new BossNatureResistanceAction(ai, "freya"); }
static Action* freya_mark_dps_target_action(PlayerbotAI* ai) { return new FreyaMarkDpsTargetAction(ai); }
static Action* freya_move_to_healing_spore_action(PlayerbotAI* ai) { return new FreyaMoveToHealingSporeAction(ai); }
static Action* thorim_nature_resistance_action(PlayerbotAI* ai) { return new BossNatureResistanceAction(ai, "thorim"); }
static Action* mimiron_fire_resistance_action(PlayerbotAI* ai) { return new BossFireResistanceAction(ai, "mimiron"); }
}; };
#endif #endif

View File

@@ -24,8 +24,6 @@
#include "SharedDefines.h" #include "SharedDefines.h"
#include "Unit.h" #include "Unit.h"
#include "Vehicle.h" #include "Vehicle.h"
#include <HunterBuffStrategies.h>
#include <PaladinBuffStrategies.h>
const std::vector<uint32> availableVehicles = {NPC_VEHICLE_CHOPPER, NPC_SALVAGED_DEMOLISHER, const std::vector<uint32> availableVehicles = {NPC_VEHICLE_CHOPPER, NPC_SALVAGED_DEMOLISHER,
NPC_SALVAGED_DEMOLISHER_TURRET, NPC_SALVAGED_SIEGE_ENGINE, NPC_SALVAGED_DEMOLISHER_TURRET, NPC_SALVAGED_SIEGE_ENGINE,
@@ -1168,32 +1166,6 @@ bool RazorscaleFuseArmorAction::Execute(Event event)
return true; return true;
} }
bool RazorscaleFireResistanceAction::isUseful()
{
RazorscaleFireResistanceTrigger razorscaleFireResistanceTrigger(botAI);
return razorscaleFireResistanceTrigger.IsActive();
}
bool RazorscaleFireResistanceAction::Execute(Event event)
{
PaladinFireResistanceStrategy paladinFireResistanceStrategy(botAI);
botAI->ChangeStrategy(std::string("+") + paladinFireResistanceStrategy.getName(), BotState::BOT_STATE_COMBAT);
return true;
}
bool IgnisFireResistanceAction::isUseful()
{
IgnisFireResistanceTrigger ignisFireResistanceTrigger(botAI);
return ignisFireResistanceTrigger.IsActive();
}
bool IgnisFireResistanceAction::Execute(Event event)
{
PaladinFireResistanceStrategy paladinFireResistanceStrategy(botAI);
botAI->ChangeStrategy(std::string("+") + paladinFireResistanceStrategy.getName(), BotState::BOT_STATE_COMBAT);
return true;
}
bool IronAssemblyLightningTendrilsAction::isUseful() bool IronAssemblyLightningTendrilsAction::isUseful()
{ {
IronAssemblyLightningTendrilsTrigger ironAssemblyLightningTendrilsTrigger(botAI); IronAssemblyLightningTendrilsTrigger ironAssemblyLightningTendrilsTrigger(botAI);
@@ -1377,19 +1349,6 @@ bool KologarnFallFromFloorAction::isUseful()
return kologarnFallFromFloorTrigger.IsActive(); return kologarnFallFromFloorTrigger.IsActive();
} }
bool KologarnNatureResistanceAction::Execute(Event event)
{
HunterNatureResistanceStrategy hunterNatureResistanceStrategy(botAI);
botAI->ChangeStrategy(std::string("+") + hunterNatureResistanceStrategy.getName(), BotState::BOT_STATE_COMBAT);
return true;
}
bool KologarnNatureResistanceAction::isUseful()
{
KologarnNatureResistanceTrigger kologarnNatureResistanceTrigger(botAI);
return kologarnNatureResistanceTrigger.IsActive();
}
bool KologarnRubbleSlowdownAction::Execute(Event event) bool KologarnRubbleSlowdownAction::Execute(Event event)
{ {
Group* group = bot->GetGroup(); Group* group = bot->GetGroup();
@@ -1478,19 +1437,6 @@ bool HodirBitingColdJumpAction::Execute(Event event)
// return true; // return true;
} }
bool HodirFrostResistanceAction::isUseful()
{
HodirFrostResistanceTrigger hodirFrostResistanceTrigger(botAI);
return hodirFrostResistanceTrigger.IsActive();
}
bool HodirFrostResistanceAction::Execute(Event event)
{
PaladinFrostResistanceStrategy paladinFrostResistanceStrategy(botAI);
botAI->ChangeStrategy(std::string("+") + paladinFrostResistanceStrategy.getName(), BotState::BOT_STATE_COMBAT);
return true;
}
bool FreyaMoveAwayNatureBombAction::isUseful() bool FreyaMoveAwayNatureBombAction::isUseful()
{ {
// Check boss and it is alive // Check boss and it is alive
@@ -1517,79 +1463,118 @@ bool FreyaMoveAwayNatureBombAction::Execute(Event event)
return FleePosition(target->GetPosition(), 13.0f); return FleePosition(target->GetPosition(), 13.0f);
} }
bool FreyaMarkEonarsGiftAction::isUseful() bool FreyaMarkDpsTargetAction::isUseful()
{ {
// Only tank bot can mark target FreyaMarkDpsTargetTrigger freyaMarkDpsTargetTrigger(botAI);
if (!botAI->IsTank(bot)) return freyaMarkDpsTargetTrigger.IsActive();
{ }
bool FreyaMarkDpsTargetAction::Execute(Event event)
{
Unit* boss = AI_VALUE2(Unit*, "find target", "freya");
if (!boss || !boss->IsAlive())
return false; return false;
}
// Check Eonar's gift and it is alive Unit* targetToMark = nullptr;
// Check which adds is up
Unit* eonarsGift = nullptr;
Unit* ancientConservator = nullptr;
Unit* snaplasher = nullptr;
Unit* ancientWaterSpirit = nullptr;
Unit* stormLasher = nullptr;
Unit* firstDetonatingLasher = nullptr;
// Target is not findable from threat table using AI_VALUE2(),
// therefore need to search manually for the unit id
GuidVector targets = AI_VALUE(GuidVector, "possible targets"); GuidVector targets = AI_VALUE(GuidVector, "possible targets");
Unit* target = nullptr; Unit* target = nullptr;
for (auto i = targets.begin(); i != targets.end(); ++i) for (auto i = targets.begin(); i != targets.end(); ++i)
{ {
target = botAI->GetUnit(*i); target = botAI->GetUnit(*i);
if (!target) if (!target || !target->IsAlive())
{
continue; continue;
}
uint32 creatureId = target->GetEntry(); if (target->GetEntry() == NPC_EONARS_GIFT)
if (creatureId == NPC_EONARS_GIFT && target->IsAlive())
{ {
break; eonarsGift = target;
}
else if (target->GetEntry() == NPC_ANCIENT_CONSERVATOR)
{
ancientConservator = target;
}
else if (target->GetEntry() == NPC_SNAPLASHER)
{
snaplasher = target;
}
else if (target->GetEntry() == NPC_ANCIENT_WATER_SPIRIT)
{
ancientWaterSpirit = target;
}
else if (target->GetEntry() == NPC_STORM_LASHER)
{
stormLasher = target;
}
else if (target->GetEntry() == NPC_DETONATING_LASHER && !firstDetonatingLasher)
{
firstDetonatingLasher = target;
} }
} }
// Check if Eonar's Gift is already set as the skull marker // Check that eonars gift is need to be mark
Group* group = bot->GetGroup(); if (eonarsGift)
if (!group)
{ {
return false; targetToMark = eonarsGift;
} }
int8 skullIndex = 7; // Check that ancient conservator is need to be mark
ObjectGuid currentSkullTarget = group->GetTargetIcon(skullIndex); if (ancientConservator && !targetToMark)
if (!target || currentSkullTarget == target->GetGUID())
{ {
return false; // Skull marker is already correctly set or no Eonar's Gift found targetToMark = ancientConservator;
} }
return true; // Check that trio of adds is need to be mark
} if ((snaplasher || ancientWaterSpirit || stormLasher) && !targetToMark)
{
Unit* highestHealthUnit = nullptr;
uint32 highestHealth = 0;
if (snaplasher && snaplasher->GetHealth() > highestHealth)
{
highestHealth = snaplasher->GetHealth();
highestHealthUnit = snaplasher;
}
if (ancientWaterSpirit && ancientWaterSpirit->GetHealth() > highestHealth)
{
highestHealth = ancientWaterSpirit->GetHealth();
highestHealthUnit = ancientWaterSpirit;
}
if (stormLasher && stormLasher->GetHealth() > highestHealth)
{
highestHealthUnit = stormLasher;
}
// If the highest health unit is not already marked, mark it
if (highestHealthUnit)
{
targetToMark = highestHealthUnit;
}
}
// Check that detonating lasher is need to be mark
if (firstDetonatingLasher && !targetToMark)
{
targetToMark = firstDetonatingLasher;
}
if (!targetToMark)
{
return false; // No target to mark
}
bool FreyaMarkEonarsGiftAction::Execute(Event event)
{
bool isMainTank = botAI->IsMainTank(bot); bool isMainTank = botAI->IsMainTank(bot);
Unit* mainTankUnit = AI_VALUE(Unit*, "main tank"); Unit* mainTankUnit = AI_VALUE(Unit*, "main tank");
Player* mainTank = mainTankUnit ? mainTankUnit->ToPlayer() : nullptr; Player* mainTank = mainTankUnit ? mainTankUnit->ToPlayer() : nullptr;
int8 squareIndex = 5; // Square
GuidVector targets = AI_VALUE(GuidVector, "possible targets"); int8 skullIndex = 7; // Skull
Unit* target = nullptr;
for (auto i = targets.begin(); i != targets.end(); ++i)
{
Unit* unit = botAI->GetUnit(*i);
if (!unit)
{
continue;
}
uint32 creatureId = unit->GetEntry();
if (creatureId == NPC_EONARS_GIFT && unit->IsAlive())
{
target = unit;
}
}
if (!target)
{
return false;
}
if (mainTank && !GET_PLAYERBOT_AI(mainTank)) // Main tank is a real player if (mainTank && !GET_PLAYERBOT_AI(mainTank)) // Main tank is a real player
{ {
@@ -1599,19 +1584,18 @@ bool FreyaMarkEonarsGiftAction::Execute(Event event)
if (botAI->IsAssistTankOfIndex(bot, i) && GET_PLAYERBOT_AI(bot)) // Bot is a valid tank if (botAI->IsAssistTankOfIndex(bot, i) && GET_PLAYERBOT_AI(bot)) // Bot is a valid tank
{ {
Group* group = bot->GetGroup(); Group* group = bot->GetGroup();
if (group && target) if (group)
{ {
int8 skullIndex = 7; // Skull
ObjectGuid currentSkullTarget = group->GetTargetIcon(skullIndex); ObjectGuid currentSkullTarget = group->GetTargetIcon(skullIndex);
// If there's no skull set yet, or the skull is on a different target, set the Eonar's Gift if (!currentSkullTarget || (targetToMark->GetGUID() != currentSkullTarget))
if (!currentSkullTarget || (target->GetGUID() != currentSkullTarget))
{ {
group->SetTargetIcon(skullIndex, bot->GetGUID(), target->GetGUID()); group->SetTargetIcon(skullIndex, bot->GetGUID(), targetToMark->GetGUID());
group->SetTargetIcon(squareIndex, bot->GetGUID(), boss->GetGUID());
return true; return true;
} }
} }
break; // Stop after finding the first valid bot tank break;
} }
} }
} }
@@ -1620,13 +1604,13 @@ bool FreyaMarkEonarsGiftAction::Execute(Event event)
Group* group = bot->GetGroup(); Group* group = bot->GetGroup();
if (group) if (group)
{ {
int8 skullIndex = 7; // Skull
ObjectGuid currentSkullTarget = group->GetTargetIcon(skullIndex); ObjectGuid currentSkullTarget = group->GetTargetIcon(skullIndex);
// If there's no skull set yet, or the skull is on a different target, set the Eonar's Gift if (!currentSkullTarget || (targetToMark->GetGUID() != currentSkullTarget))
if (!currentSkullTarget || (target->GetGUID() != currentSkullTarget))
{ {
group->SetTargetIcon(skullIndex, bot->GetGUID(), target->GetGUID()); group->SetTargetIcon(skullIndex, bot->GetGUID(), targetToMark->GetGUID());
group->SetTargetIcon(squareIndex, bot->GetGUID(), boss->GetGUID());
botAI->GetAiObjectContext()->GetValue<std::string>("rti")->Set("square");
return true; return true;
} }
} }
@@ -1634,3 +1618,40 @@ bool FreyaMarkEonarsGiftAction::Execute(Event event)
return false; return false;
} }
bool FreyaMoveToHealingSporeAction::isUseful()
{
FreyaMoveToHealingSporeTrigger freyaMoveToHealingSporeTrigger(botAI);
return freyaMoveToHealingSporeTrigger.IsActive();
}
bool FreyaMoveToHealingSporeAction::Execute(Event event)
{
GuidVector targets = AI_VALUE(GuidVector, "nearest npcs");
Creature* nearestSpore = nullptr;
float nearestDistance = std::numeric_limits<float>::max();
for (auto guid : targets)
{
Unit* unit = botAI->GetUnit(guid);
if (!unit)
continue;
// Check if this unit is a healthy spore and alive
if (unit->GetEntry() != NPC_HEALTHY_SPORE || !unit->IsAlive())
continue;
float distance = bot->GetDistance2d(unit);
if (distance < nearestDistance)
{
nearestDistance = distance;
nearestSpore = static_cast<Creature*>(unit);
}
}
if (!nearestSpore)
return false;
return MoveTo(nearestSpore->GetMapId(), nearestSpore->GetPositionX(), nearestSpore->GetPositionY(),
nearestSpore->GetPositionZ(), false, false, false, true, MovementPriority::MOVEMENT_COMBAT);
}

View File

@@ -106,25 +106,6 @@ public:
bool isUseful() override; bool isUseful() override;
}; };
class RazorscaleFireResistanceAction : public Action
{
public:
RazorscaleFireResistanceAction(PlayerbotAI* botAI) : Action(botAI, "razorscale fire resistance action") {}
bool Execute(Event event) override;
bool isUseful() override;
};
//
// Ignis
//
class IgnisFireResistanceAction : public Action
{
public:
IgnisFireResistanceAction(PlayerbotAI* botAI) : Action(botAI, "ignis fire resistance action") {}
bool Execute(Event event) override;
bool isUseful() override;
};
class HodirMoveSnowpackedIcicleAction : public MovementAction class HodirMoveSnowpackedIcicleAction : public MovementAction
{ {
public: public:
@@ -133,14 +114,6 @@ public:
bool isUseful() override; bool isUseful() override;
}; };
class HodirFrostResistanceAction : public Action
{
public:
HodirFrostResistanceAction(PlayerbotAI* botAI) : Action(botAI, "hodir frost resistance action") {}
bool Execute(Event event) override;
bool isUseful() override;
};
class IronAssemblyLightningTendrilsAction : public MovementAction class IronAssemblyLightningTendrilsAction : public MovementAction
{ {
public: public:
@@ -173,14 +146,6 @@ public:
bool isUseful() override; bool isUseful() override;
}; };
class KologarnNatureResistanceAction : public Action
{
public:
KologarnNatureResistanceAction(PlayerbotAI* botAI) : Action(botAI, "kologarn nature resistance action") {}
bool Execute(Event event) override;
bool isUseful() override;
};
class KologarnRubbleSlowdownAction : public Action class KologarnRubbleSlowdownAction : public Action
{ {
public: public:
@@ -203,10 +168,19 @@ public:
bool isUseful() override; bool isUseful() override;
}; };
class FreyaMarkEonarsGiftAction : public MovementAction class FreyaMarkDpsTargetAction : public MovementAction
{ {
public: public:
FreyaMarkEonarsGiftAction(PlayerbotAI* botAI) : MovementAction(botAI, "freya mark eonars gift") {} FreyaMarkDpsTargetAction(PlayerbotAI* botAI) : MovementAction(botAI, "freya mark dps target action") {}
bool Execute(Event event) override;
bool isUseful() override;
};
class FreyaMoveToHealingSporeAction : public MovementAction
{
public:
FreyaMoveToHealingSporeAction(PlayerbotAI* ai) : MovementAction(ai, "freya move to healing spore action") {}
bool Execute(Event event) override; bool Execute(Event event) override;
bool isUseful() override; bool isUseful() override;
}; };

View File

@@ -105,13 +105,39 @@ void RaidUlduarStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
// //
// Freya // Freya
// //
triggers.push_back(new TriggerNode(
"freya tank near eonars gift",
NextAction::array(0, new NextAction("freya mark eonars gift", ACTION_RAID + 1), nullptr)));
triggers.push_back(new TriggerNode( triggers.push_back(new TriggerNode(
"freya near nature bomb", "freya near nature bomb",
NextAction::array(0, new NextAction("freya move away nature bomb", ACTION_RAID), nullptr))); NextAction::array(0, new NextAction("freya move away nature bomb", ACTION_RAID), nullptr)));
triggers.push_back(new TriggerNode(
"freya nature resistance trigger",
NextAction::array(0, new NextAction("freya nature resistance action", ACTION_RAID), nullptr)));
triggers.push_back(new TriggerNode(
"freya fire resistance trigger",
NextAction::array(0, new NextAction("freya fire resistance action", ACTION_RAID), nullptr)));
triggers.push_back(new TriggerNode(
"freya mark dps target trigger",
NextAction::array(0, new NextAction("freya mark dps target action", ACTION_RAID), nullptr)));
triggers.push_back(new TriggerNode(
"freya move to healing spore trigger",
NextAction::array(0, new NextAction("freya move to healing spore action", ACTION_RAID), nullptr)));
//
// Thorim
//
triggers.push_back(new TriggerNode(
"thorim nature resistance trigger",
NextAction::array(0, new NextAction("thorim nature resistance action", ACTION_RAID), nullptr)));
//
// Mimiron
//
triggers.push_back(new TriggerNode(
"mimiron fire resistance trigger",
NextAction::array(0, new NextAction("mimiron fire resistance action", ACTION_RAID), nullptr)));
} }
void RaidUlduarStrategy::InitMultipliers(std::vector<Multiplier*>& multipliers) void RaidUlduarStrategy::InitMultipliers(std::vector<Multiplier*>& multipliers)

View File

@@ -9,6 +9,7 @@
#include "AiObjectContext.h" #include "AiObjectContext.h"
#include "NamedObjectContext.h" #include "NamedObjectContext.h"
#include "RaidUlduarTriggers.h" #include "RaidUlduarTriggers.h"
#include "BossAuraTriggers.h"
class RaidUlduarTriggerContext : public NamedObjectContext<Trigger> class RaidUlduarTriggerContext : public NamedObjectContext<Trigger>
{ {
@@ -36,7 +37,12 @@ public:
creators["hodir near snowpacked icicle"] = &RaidUlduarTriggerContext::hodir_near_snowpacked_icicle; creators["hodir near snowpacked icicle"] = &RaidUlduarTriggerContext::hodir_near_snowpacked_icicle;
creators["hodir frost resistance trigger"] = &RaidUlduarTriggerContext::hodir_frost_resistance_trigger; creators["hodir frost resistance trigger"] = &RaidUlduarTriggerContext::hodir_frost_resistance_trigger;
creators["freya near nature bomb"] = &RaidUlduarTriggerContext::freya_near_nature_bomb; creators["freya near nature bomb"] = &RaidUlduarTriggerContext::freya_near_nature_bomb;
creators["freya tank near eonars gift"] = &RaidUlduarTriggerContext::freya_tank_near_eonars_gift; creators["freya fire resistance trigger"] = &RaidUlduarTriggerContext::freya_fire_resistance_trigger;
creators["freya nature resistance trigger"] = &RaidUlduarTriggerContext::freya_nature_resistance_trigger;
creators["freya mark dps target trigger"] = &RaidUlduarTriggerContext::freya_mark_dps_target_trigger;
creators["freya move to healing spore trigger"] = &RaidUlduarTriggerContext::freya_move_to_healing_spore_trigger;
creators["thorim nature resistance trigger"] = &RaidUlduarTriggerContext::thorim_nature_resistance_trigger;
creators["mimiron fire resistance trigger"] = &RaidUlduarTriggerContext::mimiron_fire_resistance_trigger;
} }
private: private:
@@ -49,19 +55,24 @@ private:
static Trigger* razorscale_grounded(PlayerbotAI* ai) { return new RazorscaleGroundedTrigger(ai); } static Trigger* razorscale_grounded(PlayerbotAI* ai) { return new RazorscaleGroundedTrigger(ai); }
static Trigger* razorscale_harpoon_trigger(PlayerbotAI* ai) { return new RazorscaleHarpoonAvailableTrigger(ai); } static Trigger* razorscale_harpoon_trigger(PlayerbotAI* ai) { return new RazorscaleHarpoonAvailableTrigger(ai); }
static Trigger* razorscale_fuse_armor_trigger(PlayerbotAI* ai) { return new RazorscaleFuseArmorTrigger(ai); } static Trigger* razorscale_fuse_armor_trigger(PlayerbotAI* ai) { return new RazorscaleFuseArmorTrigger(ai); }
static Trigger* razorscale_fire_resistance_trigger(PlayerbotAI* ai) { return new RazorscaleFireResistanceTrigger(ai); } static Trigger* razorscale_fire_resistance_trigger(PlayerbotAI* ai) { return new BossFireResistanceTrigger(ai, "razorscale"); }
static Trigger* ignis_fire_resistance_trigger(PlayerbotAI* ai) { return new IgnisFireResistanceTrigger(ai); } static Trigger* ignis_fire_resistance_trigger(PlayerbotAI* ai) { return new BossFireResistanceTrigger(ai, "ignis the furnace master"); }
static Trigger* iron_assembly_lightning_tendrils_trigger(PlayerbotAI* ai) { return new IronAssemblyLightningTendrilsTrigger(ai); } static Trigger* iron_assembly_lightning_tendrils_trigger(PlayerbotAI* ai) { return new IronAssemblyLightningTendrilsTrigger(ai); }
static Trigger* iron_assembly_overload_trigger(PlayerbotAI* ai) { return new IronAssemblyOverloadTrigger(ai); } static Trigger* iron_assembly_overload_trigger(PlayerbotAI* ai) { return new IronAssemblyOverloadTrigger(ai); }
static Trigger* kologarn_mark_dps_target_trigger(PlayerbotAI* ai) { return new KologarnMarkDpsTargetTrigger(ai); } static Trigger* kologarn_mark_dps_target_trigger(PlayerbotAI* ai) { return new KologarnMarkDpsTargetTrigger(ai); }
static Trigger* kologarn_fall_from_floor_trigger(PlayerbotAI* ai) { return new KologarnFallFromFloorTrigger(ai); } static Trigger* kologarn_fall_from_floor_trigger(PlayerbotAI* ai) { return new KologarnFallFromFloorTrigger(ai); }
static Trigger* kologarn_nature_resistance_trigger(PlayerbotAI* ai) { return new KologarnNatureResistanceTrigger(ai); } static Trigger* kologarn_nature_resistance_trigger(PlayerbotAI* ai) { return new BossNatureResistanceTrigger(ai, "kologarn"); }
static Trigger* kologarn_rubble_slowdown_trigger(PlayerbotAI* ai) { return new KologarnRubbleSlowdownTrigger(ai); } static Trigger* kologarn_rubble_slowdown_trigger(PlayerbotAI* ai) { return new KologarnRubbleSlowdownTrigger(ai); }
static Trigger* hodir_biting_cold(PlayerbotAI* ai) { return new HodirBitingColdTrigger(ai); } static Trigger* hodir_biting_cold(PlayerbotAI* ai) { return new HodirBitingColdTrigger(ai); }
static Trigger* hodir_near_snowpacked_icicle(PlayerbotAI* ai) { return new HodirNearSnowpackedIcicleTrigger(ai); } static Trigger* hodir_near_snowpacked_icicle(PlayerbotAI* ai) { return new HodirNearSnowpackedIcicleTrigger(ai); }
static Trigger* hodir_frost_resistance_trigger(PlayerbotAI* ai) { return new HodirFrostResistanceTrigger(ai); } static Trigger* hodir_frost_resistance_trigger(PlayerbotAI* ai) { return new BossFrostResistanceTrigger(ai, "hodir"); }
static Trigger* freya_near_nature_bomb(PlayerbotAI* ai) { return new FreyaNearNatureBombTrigger(ai); } static Trigger* freya_near_nature_bomb(PlayerbotAI* ai) { return new FreyaNearNatureBombTrigger(ai); }
static Trigger* freya_tank_near_eonars_gift(PlayerbotAI* ai) { return new FreyaTankNearEonarsGiftTrigger(ai); } static Trigger* freya_fire_resistance_trigger(PlayerbotAI* ai) { return new BossFireResistanceTrigger(ai, "freya"); }
static Trigger* freya_nature_resistance_trigger(PlayerbotAI* ai) { return new BossNatureResistanceTrigger(ai, "freya"); }
static Trigger* freya_mark_dps_target_trigger(PlayerbotAI* ai) { return new FreyaMarkDpsTargetTrigger(ai); }
static Trigger* freya_move_to_healing_spore_trigger(PlayerbotAI* ai) { return new FreyaMoveToHealingSporeTrigger(ai); }
static Trigger* thorim_nature_resistance_trigger(PlayerbotAI* ai) { return new BossNatureResistanceTrigger(ai, "thorim"); }
static Trigger* mimiron_fire_resistance_trigger(PlayerbotAI* ai) { return new BossFireResistanceTrigger(ai, "mimiron"); }
}; };
#endif #endif

View File

@@ -11,8 +11,6 @@
#include "SharedDefines.h" #include "SharedDefines.h"
#include "Trigger.h" #include "Trigger.h"
#include "Vehicle.h" #include "Vehicle.h"
#include <HunterBuffStrategies.h>
#include <PaladinBuffStrategies.h>
const std::vector<uint32> availableVehicles = {NPC_VEHICLE_CHOPPER, NPC_SALVAGED_DEMOLISHER, const std::vector<uint32> availableVehicles = {NPC_VEHICLE_CHOPPER, NPC_SALVAGED_DEMOLISHER,
NPC_SALVAGED_DEMOLISHER_TURRET, NPC_SALVAGED_SIEGE_ENGINE, NPC_SALVAGED_DEMOLISHER_TURRET, NPC_SALVAGED_SIEGE_ENGINE,
@@ -244,100 +242,6 @@ bool RazorscaleFuseArmorTrigger::IsActive()
return false; return false;
} }
bool RazorscaleFireResistanceTrigger::IsActive()
{
// Check boss and it is alive
Unit* boss = AI_VALUE2(Unit*, "find target", "razorscale");
if (!boss || !boss->IsAlive())
return false;
// Check if bot is paladin
if (bot->getClass() != CLASS_PALADIN)
return false;
// Check if bot have fire resistance aura
if (bot->HasAura(SPELL_FIRE_RESISTANCE_AURA))
return false;
// Check if bot dont have already have fire resistance strategy
PaladinFireResistanceStrategy paladinFireResistanceStrategy(botAI);
if (botAI->HasStrategy(paladinFireResistanceStrategy.getName(), BotState::BOT_STATE_COMBAT))
return false;
// Check that the bot actually knows the spell
if (!bot->HasActiveSpell(SPELL_FIRE_RESISTANCE_AURA))
return false;
// Get the group and ensure it's a raid group
Group* group = bot->GetGroup();
if (!group || !group->isRaidGroup())
return false;
// Iterate through group members to find the first alive paladin
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
{
Player* member = gref->GetSource();
if (!member || !member->IsAlive())
continue;
// Check if the member is a hunter
if (member->getClass() == CLASS_PALADIN)
{
// Return true only if the current bot is the first alive paladin
return member == bot;
}
}
return false;
}
bool IgnisFireResistanceTrigger::IsActive()
{
// Check boss and it is alive
Unit* boss = AI_VALUE2(Unit*, "find target", "ignis the furnace master");
if (!boss || !boss->IsAlive())
return false;
// Check if bot is paladin
if (bot->getClass() != CLASS_PALADIN)
return false;
// Check if bot have fire resistance aura
if (bot->HasAura(SPELL_FIRE_RESISTANCE_AURA))
return false;
// Check if bot dont have already have fire resistance strategy
PaladinFireResistanceStrategy paladinFireResistanceStrategy(botAI);
if (botAI->HasStrategy(paladinFireResistanceStrategy.getName(), BotState::BOT_STATE_COMBAT))
return false;
// Check that the bot actually knows the spell
if (!bot->HasActiveSpell(SPELL_FIRE_RESISTANCE_AURA))
return false;
// Get the group and ensure it's a raid group
Group* group = bot->GetGroup();
if (!group || !group->isRaidGroup())
return false;
// Iterate through group members to find the first alive paladin
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
{
Player* member = gref->GetSource();
if (!member || !member->IsAlive())
continue;
// Check if the member is a hunter
if (member->getClass() == CLASS_PALADIN)
{
// Return true only if the current bot is the first alive paladin
return member == bot;
}
}
return false;
}
bool IronAssemblyLightningTendrilsTrigger::IsActive() bool IronAssemblyLightningTendrilsTrigger::IsActive()
{ {
// Check boss and it is alive // Check boss and it is alive
@@ -451,57 +355,6 @@ bool KologarnFallFromFloorTrigger::IsActive()
return bot->GetPositionZ() < ULDUAR_KOLOGARN_AXIS_Z_PATHING_ISSUE_DETECT; return bot->GetPositionZ() < ULDUAR_KOLOGARN_AXIS_Z_PATHING_ISSUE_DETECT;
} }
bool KologarnNatureResistanceTrigger::IsActive()
{
// Check boss and it is alive
Unit* boss = AI_VALUE2(Unit*, "find target", "kologarn");
if (!boss || !boss->IsAlive())
return false;
// Check if bot is alive
if (!bot->IsAlive())
return false;
// Check if bot is hunter
if (bot->getClass() != CLASS_HUNTER)
return false;
// Check if bot have nature resistance aura
if (bot->HasAura(SPELL_ASPECT_OF_THE_WILD))
return false;
// Check if bot dont have already setted nature resistance aura
HunterNatureResistanceStrategy hunterNatureResistanceStrategy(botAI);
if (botAI->HasStrategy(hunterNatureResistanceStrategy.getName(), BotState::BOT_STATE_COMBAT))
return false;
// Check that the bot actually knows Aspect of the Wild
if (!bot->HasActiveSpell(SPELL_ASPECT_OF_THE_WILD))
return false;
// Get the group and ensure it's a raid group
Group* group = bot->GetGroup();
if (!group || !group->isRaidGroup())
return false;
// Iterate through group members to find the first alive hunter
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
{
Player* member = gref->GetSource();
if (!member || !member->IsAlive())
continue;
// Check if the member is a hunter
if (member->getClass() == CLASS_HUNTER)
{
// Return true only if the current bot is the first alive hunter
return member == bot;
}
}
return false;
}
bool KologarnRubbleSlowdownTrigger::IsActive() bool KologarnRubbleSlowdownTrigger::IsActive()
{ {
Unit* boss = AI_VALUE2(Unit*, "find target", "kologarn"); Unit* boss = AI_VALUE2(Unit*, "find target", "kologarn");
@@ -579,53 +432,6 @@ bool HodirNearSnowpackedIcicleTrigger::IsActive()
return true; return true;
} }
bool HodirFrostResistanceTrigger::IsActive()
{
// Check boss and it is alive
Unit* boss = AI_VALUE2(Unit*, "find target", "hodir");
if (!boss || !boss->IsAlive())
return false;
// Check if bot is paladin
if (bot->getClass() != CLASS_PALADIN)
return false;
// Check if bot have frost resistance aura
if (bot->HasAura(SPELL_FROST_RESISTANCE_AURA))
return false;
// Check if bot dont have already have frost resistance strategy
PaladinFrostResistanceStrategy paladinFrostResistanceStrategy(botAI);
if (botAI->HasStrategy(paladinFrostResistanceStrategy.getName(), BotState::BOT_STATE_COMBAT))
return false;
// Check that the bot actually knows the spell
if (!bot->HasActiveSpell(SPELL_FROST_RESISTANCE_AURA))
return false;
// Get the group and ensure it's a raid group
Group* group = bot->GetGroup();
if (!group || !group->isRaidGroup())
return false;
// Iterate through group members to find the first alive paladin
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
{
Player* member = gref->GetSource();
if (!member || !member->IsAlive())
continue;
// Check if the member is a hunter
if (member->getClass() == CLASS_PALADIN)
{
// Return true only if the current bot is the first alive paladin
return member == bot;
}
}
return false;
}
bool FreyaNearNatureBombTrigger::IsActive() bool FreyaNearNatureBombTrigger::IsActive()
{ {
// Check boss and it is alive // Check boss and it is alive
@@ -640,34 +446,185 @@ bool FreyaNearNatureBombTrigger::IsActive()
return target != nullptr; return target != nullptr;
} }
bool FreyaTankNearEonarsGiftTrigger::IsActive() bool FreyaMarkDpsTargetTrigger::IsActive()
{ {
// Check boss and it is alive
Unit* boss = AI_VALUE2(Unit*, "find target", "freya");
if (!boss || !boss->IsAlive())
return false;
// Only tank bot can mark target // Only tank bot can mark target
if (!botAI->IsTank(bot)) if (!botAI->IsTank(bot))
{
return false; return false;
// Get current raid dps target
Group* group = bot->GetGroup();
if (!group)
return false;
int8 skullIndex = 7;
ObjectGuid currentSkullTarget = group->GetTargetIcon(skullIndex);
Unit* currentSkullUnit = botAI->GetUnit(currentSkullTarget);
if (currentSkullUnit && !currentSkullUnit->IsAlive())
{
currentSkullUnit = nullptr;
} }
// Check Eonar's gift and it is alive // Check which adds is up
Unit* eonarsGift = nullptr;
Unit* ancientConservator = nullptr;
Unit* snaplasher = nullptr;
Unit* ancientWaterSpirit = nullptr;
Unit* stormLasher = nullptr;
Unit* firstDetonatingLasher = nullptr;
// Target is not findable from threat table using AI_VALUE2(),
// therefore need to search manually for the unit id
GuidVector targets = AI_VALUE(GuidVector, "possible targets"); GuidVector targets = AI_VALUE(GuidVector, "possible targets");
Unit* target = nullptr;
for (auto i = targets.begin(); i != targets.end(); ++i) for (auto i = targets.begin(); i != targets.end(); ++i)
{ {
Unit* unit = botAI->GetUnit(*i); target = botAI->GetUnit(*i);
if (!unit) if (!target || !target->IsAlive())
{
continue; continue;
if (target->GetEntry() == NPC_EONARS_GIFT)
{
eonarsGift = target;
}
else if (target->GetEntry() == NPC_ANCIENT_CONSERVATOR)
{
ancientConservator = target;
}
else if (target->GetEntry() == NPC_SNAPLASHER)
{
snaplasher = target;
}
else if (target->GetEntry() == NPC_ANCIENT_WATER_SPIRIT)
{
ancientWaterSpirit = target;
}
else if (target->GetEntry() == NPC_STORM_LASHER)
{
stormLasher = target;
}
else if (target->GetEntry() == NPC_DETONATING_LASHER && !firstDetonatingLasher)
{
firstDetonatingLasher = target;
}
}
// Check that eonars gift is need to be mark
if (eonarsGift &&
(!currentSkullUnit || currentSkullUnit->GetEntry() != eonarsGift->GetEntry()))
{
return true;
}
// Check that ancient conservator is need to be mark
if (ancientConservator &&
(!currentSkullUnit || currentSkullUnit->GetEntry() != ancientConservator->GetEntry()))
{
return true;
}
// Check that trio of adds is need to be mark
if (snaplasher || ancientWaterSpirit || stormLasher)
{
Unit* highestHealthUnit = nullptr;
uint32 highestHealth = 0;
if (snaplasher && snaplasher->GetHealth() > highestHealth)
{
highestHealth = snaplasher->GetHealth();
highestHealthUnit = snaplasher;
}
if (ancientWaterSpirit && ancientWaterSpirit->GetHealth() > highestHealth)
{
highestHealth = ancientWaterSpirit->GetHealth();
highestHealthUnit = ancientWaterSpirit;
}
if (stormLasher && stormLasher->GetHealth() > highestHealth)
{
highestHealthUnit = stormLasher;
} }
uint32 creatureId = unit->GetEntry(); // If the highest health unit is not already marked, mark it
if (creatureId == NPC_EONARS_GIFT && unit->IsAlive()) if (highestHealthUnit &&
(!currentSkullUnit || currentSkullUnit->GetEntry() != highestHealthUnit->GetEntry()))
{ {
return true; return true;
} }
} }
// Check that detonating lasher is need to be mark
if (firstDetonatingLasher &&
(!currentSkullUnit || currentSkullUnit->GetEntry() != firstDetonatingLasher->GetEntry()))
{
Map* map = bot->GetMap();
if (!map || !map->IsRaid())
return false;
uint32 healthThreshold = map->Is25ManRaid() ? 7200 : 4900; // Detonate maximum damage
// Check that detonate lasher dont kill raid members
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
{
Player* member = gref->GetSource();
if (!member || !member->IsAlive())
continue;
if (member->GetHealth() < healthThreshold)
return false;
}
return true;
}
return false; return false;
} }
bool FreyaMoveToHealingSporeTrigger::IsActive()
{
// Check for the Freya boss
Unit* boss = AI_VALUE2(Unit*, "find target", "freya");
if (!boss || !boss->IsAlive())
return false;
if (!botAI->IsRanged(bot))
return false;
Unit* conservatory = AI_VALUE2(Unit*, "find target", "ancient conservator");
if (!conservatory || !conservatory->IsAlive())
return false;
GuidVector targets = AI_VALUE(GuidVector, "nearest npcs");
float nearestDistance = std::numeric_limits<float>::max();
bool foundSpore = false;
// Iterate through all targets to find healthy spores
for (const ObjectGuid& guid : targets)
{
Unit* unit = botAI->GetUnit(guid);
if (!unit || !unit->IsAlive())
continue;
// Check if the unit is a healthy spore
if (unit->GetEntry() == NPC_HEALTHY_SPORE)
{
foundSpore = true;
float distance = bot->GetDistance(unit);
if (distance < nearestDistance)
{
nearestDistance = distance;
}
}
}
// If no healthy spores are found, return false
if (!foundSpore)
return false;
// If the nearest spore is farther than 6 yards, a move is required
return nearestDistance > 6.0f;
}

View File

@@ -34,14 +34,17 @@ enum UlduarIDs
SPELL_BITING_COLD_PLAYER_AURA = 62039, SPELL_BITING_COLD_PLAYER_AURA = 62039,
// Freya // 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, NPC_EONARS_GIFT = 33228,
GOBJECT_NATURE_BOMB = 194902, GOBJECT_NATURE_BOMB = 194902,
// Buffs // Buffs
SPELL_FROST_TRAP = 13809, SPELL_FROST_TRAP = 13809
SPELL_FROST_RESISTANCE_AURA = 48945,
SPELL_FIRE_RESISTANCE_AURA = 48947,
SPELL_ASPECT_OF_THE_WILD = 49071,
}; };
const float ULDUAR_KOLOGARN_AXIS_Z_PATHING_ISSUE_DETECT = 420.0f; const float ULDUAR_KOLOGARN_AXIS_Z_PATHING_ISSUE_DETECT = 420.0f;
@@ -115,23 +118,6 @@ public:
bool IsActive() override; bool IsActive() override;
}; };
class RazorscaleFireResistanceTrigger : public Trigger
{
public:
RazorscaleFireResistanceTrigger(PlayerbotAI* ai) : Trigger(ai, "razorscale fire resistance trigger") {}
bool IsActive() override;
};
//
// Ignis
//
class IgnisFireResistanceTrigger : public Trigger
{
public:
IgnisFireResistanceTrigger(PlayerbotAI* ai) : Trigger(ai, "ignis fire resistance trigger") {}
bool IsActive() override;
};
// //
// Iron Assembly // Iron Assembly
// //
@@ -166,13 +152,6 @@ public:
bool IsActive() override; bool IsActive() override;
}; };
class KologarnNatureResistanceTrigger : public Trigger
{
public:
KologarnNatureResistanceTrigger(PlayerbotAI* ai) : Trigger(ai, "kologarn nature resistance trigger") {}
bool IsActive() override;
};
class KologarnRubbleSlowdownTrigger : public Trigger class KologarnRubbleSlowdownTrigger : public Trigger
{ {
public: public:
@@ -197,13 +176,6 @@ public:
bool IsActive() override; bool IsActive() override;
}; };
class HodirFrostResistanceTrigger : public Trigger
{
public:
HodirFrostResistanceTrigger(PlayerbotAI* ai) : Trigger(ai, "hodir frost resistance trigger") {}
bool IsActive() override;
};
// //
// Freya // Freya
// //
@@ -214,10 +186,17 @@ public:
bool IsActive() override; bool IsActive() override;
}; };
class FreyaTankNearEonarsGiftTrigger : public Trigger class FreyaMarkDpsTargetTrigger : public Trigger
{ {
public: public:
FreyaTankNearEonarsGiftTrigger(PlayerbotAI* ai) : Trigger(ai, "freya tank near eonars gift") {} FreyaMarkDpsTargetTrigger(PlayerbotAI* ai) : Trigger(ai, "freya mark dps target trigger") {}
bool IsActive() override;
};
class FreyaMoveToHealingSporeTrigger : public Trigger
{
public:
FreyaMoveToHealingSporeTrigger(PlayerbotAI* ai) : Trigger(ai, "freya move to healing spore trigger") {}
bool IsActive() override; bool IsActive() override;
}; };

View File

@@ -0,0 +1,157 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
* and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#include "BossAuraTriggers.h"
#include <HunterBuffStrategies.h>
#include <PaladinBuffStrategies.h>
#include <Unit.h>
#include "Playerbots.h"
bool BossFireResistanceTrigger::IsActive()
{
// Check boss and it is alive
Unit* boss = AI_VALUE2(Unit*, "find target", bossName);
if (!boss || !boss->IsAlive())
return false;
// Check if bot is paladin
if (bot->getClass() != CLASS_PALADIN)
return false;
// Check if bot have fire resistance aura
if (bot->HasAura(SPELL_FIRE_RESISTANCE_AURA))
return false;
// Check if bot dont have already have fire resistance strategy
PaladinFireResistanceStrategy paladinFireResistanceStrategy(botAI);
if (botAI->HasStrategy(paladinFireResistanceStrategy.getName(), BotState::BOT_STATE_COMBAT))
return false;
// Check that the bot actually knows the spell
if (!bot->HasActiveSpell(SPELL_FIRE_RESISTANCE_AURA))
return false;
// Get the group and ensure it's a raid group
Group* group = bot->GetGroup();
if (!group || !group->isRaidGroup())
return false;
// Iterate through group members to find the first alive paladin
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
{
Player* member = gref->GetSource();
if (!member || !member->IsAlive())
continue;
// Check if the member is a hunter
if (member->getClass() == CLASS_PALADIN)
{
// Return true only if the current bot is the first alive paladin
return member == bot;
}
}
return false;
}
bool BossFrostResistanceTrigger::IsActive()
{
// Check boss and it is alive
Unit* boss = AI_VALUE2(Unit*, "find target", bossName);
if (!boss || !boss->IsAlive())
return false;
// Check if bot is paladin
if (bot->getClass() != CLASS_PALADIN)
return false;
// Check if bot have frost resistance aura
if (bot->HasAura(SPELL_FROST_RESISTANCE_AURA))
return false;
// Check if bot dont have already have frost resistance strategy
PaladinFrostResistanceStrategy paladinFrostResistanceStrategy(botAI);
if (botAI->HasStrategy(paladinFrostResistanceStrategy.getName(), BotState::BOT_STATE_COMBAT))
return false;
// Check that the bot actually knows the spell
if (!bot->HasActiveSpell(SPELL_FROST_RESISTANCE_AURA))
return false;
// Get the group and ensure it's a raid group
Group* group = bot->GetGroup();
if (!group || !group->isRaidGroup())
return false;
// Iterate through group members to find the first alive paladin
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
{
Player* member = gref->GetSource();
if (!member || !member->IsAlive())
continue;
// Check if the member is a hunter
if (member->getClass() == CLASS_PALADIN)
{
// Return true only if the current bot is the first alive paladin
return member == bot;
}
}
return false;
}
bool BossNatureResistanceTrigger::IsActive()
{
// Check boss and it is alive
Unit* boss = AI_VALUE2(Unit*, "find target", bossName);
if (!boss || !boss->IsAlive())
return false;
// Check if bot is alive
if (!bot->IsAlive())
return false;
// Check if bot is hunter
if (bot->getClass() != CLASS_HUNTER)
return false;
// Check if bot have nature resistance aura
if (bot->HasAura(SPELL_ASPECT_OF_THE_WILD))
return false;
// Check if bot dont have already setted nature resistance aura
HunterNatureResistanceStrategy hunterNatureResistanceStrategy(botAI);
if (botAI->HasStrategy(hunterNatureResistanceStrategy.getName(), BotState::BOT_STATE_COMBAT))
return false;
// Check that the bot actually knows Aspect of the Wild
if (!bot->HasActiveSpell(SPELL_ASPECT_OF_THE_WILD))
return false;
// Get the group and ensure it's a raid group
Group* group = bot->GetGroup();
if (!group || !group->isRaidGroup())
return false;
// Iterate through group members to find the first alive hunter
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
{
Player* member = gref->GetSource();
if (!member || !member->IsAlive())
continue;
// Check if the member is a hunter
if (member->getClass() == CLASS_HUNTER)
{
// Return true only if the current bot is the first alive hunter
return member == bot;
}
}
return false;
}

View File

@@ -0,0 +1,59 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
* and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_BOSSAURATRIGGERS_H
#define _PLAYERBOT_BOSSAURATRIGGERS_H
#include "GenericTriggers.h"
class PlayerbotAI;
enum BossAuraIDs
{
SPELL_FROST_RESISTANCE_AURA = 48945,
SPELL_FIRE_RESISTANCE_AURA = 48947,
SPELL_ASPECT_OF_THE_WILD = 49071,
};
class BossFireResistanceTrigger : public Trigger
{
public:
BossFireResistanceTrigger(PlayerbotAI* ai, std::string const bossName)
: Trigger(ai, bossName + " fire resistance trigger"), bossName(bossName)
{
}
bool IsActive() override;
private:
std::string bossName;
};
class BossFrostResistanceTrigger : public Trigger
{
public:
BossFrostResistanceTrigger(PlayerbotAI* ai, std::string const bossName)
: Trigger(ai, bossName + " frost resistance trigger"), bossName(bossName)
{
}
bool IsActive() override;
private:
std::string bossName;
};
class BossNatureResistanceTrigger : public Trigger
{
public:
BossNatureResistanceTrigger(PlayerbotAI* ai, std::string const bossName)
: Trigger(ai, "kologarn nature resistance trigger"), bossName(bossName)
{
}
bool IsActive() override;
private:
std::string bossName;
};
#endif