Warlock overhaul (#1397)

This is a complete overhaul of the warlock class, making 3 new strategies (affliction, demonology, and destruction), as well as finishing the warlock tank strategy (shadow ward and searing pain). It also includes a soulstone fix, where the bots can change who they soulstone based on the non-combat strategies you set for them. It also includes a self-resurrect action and trigger that allows the bots to resurrect using a soulstone or reincarnation. Many other skills were added to finish out the warlock skillset.
This commit is contained in:
ThePenguinMan96
2025-06-27 11:00:38 -07:00
committed by GitHub
parent cf8253579e
commit 00cc2468f1
29 changed files with 1762 additions and 573 deletions

View File

@@ -1341,8 +1341,8 @@ AiPlayerbot.PremadeSpecLink.9.1.70 = -003203301135112530135201051-55
AiPlayerbot.PremadeSpecLink.9.1.80 = -003203301135112530135221351-55000005
AiPlayerbot.PremadeSpecName.9.2 = destro pve
AiPlayerbot.PremadeSpecGlyph.9.2 = 45785,43390,50077,43394,43393,42454
AiPlayerbot.PremadeSpecLink.9.2.60 = --05203205210131051313230341
AiPlayerbot.PremadeSpecLink.9.2.80 = -03310030003-05203205210331051335230351
AiPlayerbot.PremadeSpecLink.9.2.60 = --05203215200231051305031151
AiPlayerbot.PremadeSpecLink.9.2.80 = 23-0302-05203215220331051335231351
#
#
@@ -1590,11 +1590,11 @@ AiPlayerbot.RandomClassSpecIndex.8.2 = 2
#
#
AiPlayerbot.RandomClassSpecProb.9.0 = 45
AiPlayerbot.RandomClassSpecProb.9.0 = 33
AiPlayerbot.RandomClassSpecIndex.9.0 = 0
AiPlayerbot.RandomClassSpecProb.9.1 = 45
AiPlayerbot.RandomClassSpecProb.9.1 = 34
AiPlayerbot.RandomClassSpecIndex.9.1 = 1
AiPlayerbot.RandomClassSpecProb.9.2 = 10
AiPlayerbot.RandomClassSpecProb.9.2 = 33
AiPlayerbot.RandomClassSpecIndex.9.2 = 2
#

View File

@@ -385,8 +385,16 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
}
break;
case CLASS_WARLOCK:
engine->addStrategiesNoInit("dps assist", "dps", "dps debuff", "aoe", nullptr);
if (tab == 0) // Affliction
engine->addStrategiesNoInit("affli", "affli aoe", nullptr);
else if (tab == 1) // Demonology
engine->addStrategiesNoInit("demo", "demo aoe", "meta melee", nullptr);
else if (tab == 2) // Destruction
engine->addStrategiesNoInit("destro", "destro aoe", "curse of elements", nullptr);
engine->addStrategiesNoInit("cc", "dps assist", nullptr);
break;
case CLASS_DEATH_KNIGHT:
if (tab == 0)
engine->addStrategiesNoInit("blood", "tank assist", nullptr);
@@ -588,15 +596,15 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const
case CLASS_WARLOCK:
if (tab == WARLOCK_TAB_AFFLICATION)
{
nonCombatEngine->addStrategiesNoInit("bmana", nullptr);
nonCombatEngine->addStrategiesNoInit("felhunter", nullptr);
}
else if (tab == WARLOCK_TAB_DEMONOLOGY)
{
nonCombatEngine->addStrategiesNoInit("bdps", nullptr);
nonCombatEngine->addStrategiesNoInit("felguard", nullptr);
}
else if (tab == WARLOCK_TAB_DESTRUCTION)
{
nonCombatEngine->addStrategiesNoInit("bhealth", nullptr);
nonCombatEngine->addStrategiesNoInit("imp", nullptr);
}
nonCombatEngine->addStrategiesNoInit("dps assist", nullptr);
break;

View File

@@ -3154,22 +3154,41 @@ bool PlayerbotAI::CastSpell(uint32 spellId, Unit* target, Item* itemTarget)
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
if (pet && pet->HasSpell(spellId))
{
bool autocast = false;
for (unsigned int& m_autospell : pet->m_autospells)
// List of spell IDs for which we do NOT want to toggle auto-cast or send message
// We are excluding Spell Lock and Devour Magic because they are casted in the GenericWarlockStrategy
// Without this exclusion, the skill would be togged for auto-cast and the player would
// be spammed with messages about enabling/disabling auto-cast
switch (spellId)
{
if (m_autospell == spellId)
{
autocast = true;
case 19244: // Spell Lock rank 1
case 19647: // Spell Lock rank 2
case 19505: // Devour Magic rank 1
case 19731: // Devour Magic rank 2
case 19734: // Devour Magic rank 3
case 19736: // Devour Magic rank 4
case 27276: // Devour Magic rank 5
case 27277: // Devour Magic rank 6
case 48011: // Devour Magic rank 7
// No message - just break out of the switch and let normal cast logic continue
break;
}
}
default:
bool autocast = false;
for (unsigned int& m_autospell : pet->m_autospells)
{
if (m_autospell == spellId)
{
autocast = true;
break;
}
}
pet->ToggleAutocast(spellInfo, !autocast);
std::ostringstream out;
out << (autocast ? "|cffff0000|Disabling" : "|cFF00ff00|Enabling") << " pet auto-cast for ";
out << chatHelper.FormatSpell(spellInfo);
TellMaster(out);
return true;
pet->ToggleAutocast(spellInfo, !autocast);
std::ostringstream out;
out << (autocast ? "|cffff0000|Disabling" : "|cFF00ff00|Enabling") << " pet auto-cast for ";
out << chatHelper.FormatSpell(spellInfo);
TellMaster(out);
return true;
}
}
// aiObjectContext->GetValue<LastMovement&>("last movement")->Get().Set(nullptr);

View File

@@ -14,10 +14,25 @@ enum PetSpells
PET_PROWL_2 = 24452,
PET_PROWL_3 = 24453,
PET_COWER = 1742,
PET_LEAP = 47482
PET_LEAP = 47482,
PET_SPELL_LOCK_1 = 19244,
PET_SPELL_LOCK_2 = 19647,
PET_DEVOUR_MAGIC_1 = 19505,
PET_DEVOUR_MAGIC_2 = 19731,
PET_DEVOUR_MAGIC_3 = 19734,
PET_DEVOUR_MAGIC_4 = 19736,
PET_DEVOUR_MAGIC_5 = 27276,
PET_DEVOUR_MAGIC_6 = 27277,
PET_DEVOUR_MAGIC_7 = 48011
};
static std::vector<uint32> disabledPetSpells = {PET_PROWL_1, PET_PROWL_2, PET_PROWL_3, PET_COWER, PET_LEAP};
static std::vector<uint32> disabledPetSpells = {
PET_PROWL_1, PET_PROWL_2, PET_PROWL_3,
PET_COWER, PET_LEAP,
PET_SPELL_LOCK_1, PET_SPELL_LOCK_2,
PET_DEVOUR_MAGIC_1, PET_DEVOUR_MAGIC_2, PET_DEVOUR_MAGIC_3,
PET_DEVOUR_MAGIC_4, PET_DEVOUR_MAGIC_5, PET_DEVOUR_MAGIC_6, PET_DEVOUR_MAGIC_7
};
bool MeleeAction::isUseful()
{

View File

@@ -4,7 +4,7 @@
*/
#include "ReleaseSpiritAction.h"
#include "ServerFacade.h"
#include "Event.h"
#include "GameGraveyard.h"
#include "NearestNpcsValue.h"
@@ -13,6 +13,7 @@
#include "Playerbots.h"
#include "ServerFacade.h"
#include "Corpse.h"
#include "Log.h"
// ReleaseSpiritAction implementation
bool ReleaseSpiritAction::Execute(Event event)
@@ -247,3 +248,19 @@ void RepopAction::PerformGraveyardTeleport(const GraveyardStruct* graveyard) con
RESET_AI_VALUE(bool, "combat::self target");
RESET_AI_VALUE(WorldPosition, "current position");
}
// SelfResurrectAction implementation for Warlock's Soulstone Resurrection/Shaman's Reincarnation
bool SelfResurrectAction::Execute(Event event)
{
if (!bot->IsAlive() && bot->GetUInt32Value(PLAYER_SELF_RES_SPELL))
{
WorldPacket packet(CMSG_SELF_RES);
bot->GetSession()->HandleSelfResOpcode(packet);
return true;
}
return false;
}
bool SelfResurrectAction::isUseful()
{
return !bot->IsAlive() && bot->GetUInt32Value(PLAYER_SELF_RES_SPELL);
}

View File

@@ -56,4 +56,13 @@ private:
void PerformGraveyardTeleport(const GraveyardStruct* graveyard) const;
};
// SelfResurrectAction action registration
class SelfResurrectAction : public Action
{
public:
SelfResurrectAction(PlayerbotAI* ai) : Action(ai, "self resurrect") {}
virtual bool Execute(Event event) override;
bool isUseful() override;
};
#endif

View File

@@ -238,9 +238,24 @@ bool UseItemAction::UseItem(Item* item, ObjectGuid goGuid, Item* itemTarget, Uni
{
targetFlag = TARGET_FLAG_NONE;
packet << targetFlag;
packet << bot->GetPackGUID();
targetSelected = true;
out << " on self";
// Use the actual target if provided
if (unitTarget)
{
packet << unitTarget->GetGUID();
targetSelected = true;
// If the target is bot or is an enemy, say "on self"
if (unitTarget == bot || (unitTarget->IsHostileTo(bot)))
out << " on self";
else
out << " on " << unitTarget->GetName();
}
else
{
packet << bot->GetPackGUID();
targetSelected = true;
out << " on self";
}
}
ItemTemplate const* proto = item->GetTemplate();

View File

@@ -40,6 +40,7 @@
#include "TradeStatusExtendedAction.h"
#include "UseMeetingStoneAction.h"
#include "NamedObjectContext.h"
#include "ReleaseSpiritAction.h"
class PlayerbotAI;
@@ -68,6 +69,7 @@ public:
creators["accept trade"] = &WorldPacketActionContext::accept_trade;
creators["trade status extended"] = &WorldPacketActionContext::trade_status_extended;
creators["store loot"] = &WorldPacketActionContext::store_loot;
creators["self resurrect"] = &WorldPacketActionContext::self_resurrect;
// quest
creators["talk to quest giver"] = &WorldPacketActionContext::turn_in_quest;
@@ -136,6 +138,7 @@ private:
static Action* tell_not_enough_money(PlayerbotAI* botAI) { return new TellMasterAction(botAI, "Not enough money"); }
static Action* tell_not_enough_reputation(PlayerbotAI* botAI) { return new TellMasterAction(botAI, "Not enough reputation"); }
static Action* tell_cannot_equip(PlayerbotAI* botAI) { return new InventoryChangeFailureAction(botAI); }
static Action* self_resurrect(PlayerbotAI* botAI) { return new SelfResurrectAction(botAI); }
// quest
static Action* quest_update_add_kill(PlayerbotAI* ai) { return new QuestUpdateAddKillAction(ai); }

View File

@@ -25,6 +25,8 @@ void DeadStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
new TriggerNode("falling far", NextAction::array(0, new NextAction("repop", relevance + 1.f), nullptr)));
triggers.push_back(
new TriggerNode("location stuck", NextAction::array(0, new NextAction("repop", relevance + 1), nullptr)));
triggers.push_back(new TriggerNode(
"can self resurrect", NextAction::array(0, new NextAction("self resurrect", relevance + 2.0f), nullptr)));
}
DeadStrategy::DeadStrategy(PlayerbotAI* botAI) : PassTroughStrategy(botAI) {}

View File

@@ -11,6 +11,7 @@
#include "HealthTriggers.h"
#include "RangeTriggers.h"
#include "Trigger.h"
#include "Player.h"
class PlayerbotAI;
class Unit;
@@ -922,4 +923,13 @@ public:
public:
virtual Value<Unit*>* GetTargetValue();
};
class SelfResurrectTrigger : public Trigger
{
public:
SelfResurrectTrigger(PlayerbotAI* ai) : Trigger(ai, "can self resurrect") {}
bool IsActive() override { return !bot->IsAlive() && bot->GetUInt32Value(PLAYER_SELF_RES_SPELL); }
};
#endif

View File

@@ -223,6 +223,7 @@ public:
creators["near random status"] = &TriggerContext::near_random_status;
creators["near npc status"] = &TriggerContext::near_npc_status;
creators["do quest status"] = &TriggerContext::do_quest_status;
creators["can self resurrect"] = &TriggerContext::can_self_resurrect;
}
private:
@@ -420,6 +421,7 @@ private:
static Trigger* near_random_status(PlayerbotAI* botAI) { return new NewRpgStatusTrigger(botAI, RPG_NEAR_RANDOM); }
static Trigger* near_npc_status(PlayerbotAI* botAI) { return new NewRpgStatusTrigger(botAI, RPG_NEAR_NPC); }
static Trigger* do_quest_status(PlayerbotAI* botAI) { return new NewRpgStatusTrigger(botAI, RPG_DO_QUEST); }
static Trigger* can_self_resurrect(PlayerbotAI* ai) { return new SelfResurrectTrigger(ai); }
};
#endif

View File

@@ -0,0 +1,99 @@
/*
* 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 "AfflictionWarlockStrategy.h"
#include "Playerbots.h"
// ===== Action Node Factory =====
class AfflictionWarlockStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
{
public:
AfflictionWarlockStrategyActionNodeFactory()
{
creators["corruption"] = &corruption;
creators["corruption on attacker"] = &corruption;
creators["unstable affliction"] = &unstable_affliction;
creators["unstable affliction on attacker"] = &unstable_affliction;
creators["curse of agony"] = &curse_of_agony;
creators["curse of agony on attacker"] = &curse_of_agony;
creators["haunt"] = &haunt;
creators["shadow bolt"] = &shadow_bolt;
creators["drain soul"] = &drain_soul;
creators["life tap"] = &life_tap;
creators["shadowflame"] = &shadowflame;
creators["seed of corruption on attacker"] = &seed_of_corruption;
creators["seed of corruption"] = &seed_of_corruption;
creators["rain of fire"] = &rain_of_fire;
}
private:
static ActionNode* corruption(PlayerbotAI*) { return new ActionNode("corruption", nullptr, nullptr, nullptr); }
static ActionNode* corruption_on_attacker(PlayerbotAI*) { return new ActionNode("corruption on attacker", nullptr, nullptr, nullptr); }
static ActionNode* unstable_affliction(PlayerbotAI*) { return new ActionNode("unstable affliction", nullptr, nullptr, nullptr); }
static ActionNode* unstable_affliction_on_attacker(PlayerbotAI*) { return new ActionNode("unstable affliction on attacker", nullptr, nullptr, nullptr); }
static ActionNode* curse_of_agony(PlayerbotAI*) { return new ActionNode("curse of agony", nullptr, nullptr, nullptr); }
static ActionNode* curse_of_agony_on_attacker(PlayerbotAI*) { return new ActionNode("curse of agony on attacker", nullptr, nullptr, nullptr); }
static ActionNode* haunt(PlayerbotAI*) { return new ActionNode("haunt", nullptr, nullptr, nullptr); }
static ActionNode* shadow_bolt(PlayerbotAI*) { return new ActionNode("shadow bolt", nullptr, nullptr, nullptr); }
static ActionNode* drain_soul(PlayerbotAI*) { return new ActionNode("drain soul", nullptr, nullptr, nullptr); }
static ActionNode* life_tap(PlayerbotAI*) { return new ActionNode("life tap", nullptr, nullptr, nullptr); }
static ActionNode* shadowflame(PlayerbotAI*) { return new ActionNode("shadowflame", nullptr, nullptr, nullptr); }
static ActionNode* seed_of_corruption_on_attacker(PlayerbotAI*) { return new ActionNode("seed of corruption on attacker", nullptr, nullptr, nullptr); }
static ActionNode* seed_of_corruption(PlayerbotAI*) { return new ActionNode("seed of corruption", nullptr, nullptr, nullptr); }
static ActionNode* rain_of_fire(PlayerbotAI*) { return new ActionNode("rain of fire", nullptr, nullptr, nullptr); }
};
// ===== Single Target Strategy =====
AfflictionWarlockStrategy::AfflictionWarlockStrategy(PlayerbotAI* botAI) : GenericWarlockStrategy(botAI)
{
actionNodeFactories.Add(new AfflictionWarlockStrategyActionNodeFactory());
}
// ===== Default Actions =====
NextAction** AfflictionWarlockStrategy::getDefaultActions()
{
return NextAction::array( 0,
new NextAction("corruption", 5.6f),
new NextAction("unstable affliction", 5.5f),
new NextAction("curse of agony", 5.4f),
new NextAction("haunt", 5.3f),
new NextAction("shadow bolt", 5.2f),
new NextAction("shoot", 5.0f), nullptr);
}
// ===== Trigger Initialization ===
void AfflictionWarlockStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
GenericWarlockStrategy::InitTriggers(triggers);
// Main DoT triggers for high uptime
triggers.push_back(new TriggerNode("corruption on attacker", NextAction::array(0, new NextAction("corruption on attacker", 19.5f), nullptr)));
triggers.push_back(new TriggerNode("unstable affliction on attacker", NextAction::array(0, new NextAction("unstable affliction on attacker", 19.0f), nullptr)));
triggers.push_back(new TriggerNode("curse of agony on attacker", NextAction::array(0, new NextAction("curse of agony on attacker", 18.5f), nullptr)));
triggers.push_back(new TriggerNode("corruption", NextAction::array(0, new NextAction("corruption", 18.0f), nullptr)));
triggers.push_back(new TriggerNode("unstable affliction", NextAction::array(0, new NextAction("unstable affliction", 17.5f), nullptr)));
triggers.push_back(new TriggerNode("curse of agony", NextAction::array(0, new NextAction("curse of agony", 17.0f), nullptr)));
triggers.push_back(new TriggerNode("haunt", NextAction::array(0, new NextAction("haunt", 16.5f), nullptr)));
// Drain Soul as execute if target is low HP // Shadow Trance for free casts
triggers.push_back(new TriggerNode("shadow trance", NextAction::array(0, new NextAction("shadow bolt", 16.0f), nullptr)));
triggers.push_back(new TriggerNode("target critical health", NextAction::array(0, new NextAction("drain soul", 15.5f), nullptr)));
// Life Tap glyph buff, and Life Tap as filler
triggers.push_back(new TriggerNode("life tap glyph buff", NextAction::array(0, new NextAction("life tap", 29.0f), nullptr)));
triggers.push_back(new TriggerNode("life tap", NextAction::array(0, new NextAction("life tap", 5.1f), nullptr)));
}
// ===== AoE Strategy, 3+ enemies =====
AfflictionWarlockAoeStrategy::AfflictionWarlockAoeStrategy(PlayerbotAI* botAI) : CombatStrategy(botAI) {}
void AfflictionWarlockAoeStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(new TriggerNode("medium aoe", NextAction::array(0,
new NextAction("shadowflame", 22.5f),
new NextAction("seed of corruption on attacker", 22.0f),
new NextAction("seed of corruption", 21.5f),
new NextAction("rain of fire", 21.0f), nullptr)));
}

View File

@@ -0,0 +1,32 @@
/*
* 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_AFFLICTIONWARLOCKSTRATEGY_H
#define _PLAYERBOT_AFFLICTIONWARLOCKSTRATEGY_H
#include "GenericWarlockStrategy.h"
#include "CombatStrategy.h"
class PlayerbotAI;
class AfflictionWarlockStrategy : public GenericWarlockStrategy
{
public:
AfflictionWarlockStrategy(PlayerbotAI* botAI);
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
std::string const getName() override { return "affli"; }
NextAction** getDefaultActions() override;
};
class AfflictionWarlockAoeStrategy : public CombatStrategy
{
public:
AfflictionWarlockAoeStrategy(PlayerbotAI* botAI);
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
std::string const getName() override { return "affli aoe"; }
};
#endif

View File

@@ -0,0 +1,127 @@
/*
* 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 "DemonologyWarlockStrategy.h"
#include "Playerbots.h"
// ===== Action Node Factory =====
class DemonologyWarlockStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
{
public:
DemonologyWarlockStrategyActionNodeFactory()
{
creators["metamorphosis"] = &metamorphosis;
creators["demonic empowerment"] = &demonic_empowerment;
creators["curse of agony"] = &curse_of_agony;
creators["curse of agony on attacker"] = &curse_of_agony_on_attacker;
creators["corruption"] = &corruption;
creators["corruption on attacker"] = &corruption_on_attacker;
creators["immolate"] = &immolate;
creators["immolate on attacker"] = &immolate_on_attacker;
creators["incinerate"] = &incinerate;
creators["soul fire"] = &soul_fire;
creators["shadow bolt"] = &shadow_bolt;
creators["life tap"] = &life_tap;
creators["immolation aura"] = &immolation_aura;
creators["shadowflame"] = &shadowflame;
creators["seed of corruption on attacker"] = &seed_of_corruption_on_attacker;
creators["seed of corruption"] = &seed_of_corruption;
creators["rain of fire"] = &rain_of_fire;
creators["demon charge"] = &demon_charge;
creators["shadow cleave"] = &shadow_cleave;
}
private:
static ActionNode* metamorphosis(PlayerbotAI*) { return new ActionNode("metamorphosis", nullptr, nullptr, nullptr); }
static ActionNode* demonic_empowerment(PlayerbotAI*) { return new ActionNode("demonic empowerment", nullptr, nullptr, nullptr); }
static ActionNode* curse_of_agony(PlayerbotAI*) { return new ActionNode("curse of agony", nullptr, nullptr, nullptr); }
static ActionNode* curse_of_agony_on_attacker(PlayerbotAI*) { return new ActionNode("curse of agony on attacker", nullptr, nullptr, nullptr); }
static ActionNode* corruption(PlayerbotAI*) { return new ActionNode("corruption", nullptr, nullptr, nullptr); }
static ActionNode* corruption_on_attacker(PlayerbotAI*) { return new ActionNode("corruption on attacker", nullptr, nullptr, nullptr); }
static ActionNode* immolate(PlayerbotAI*) { return new ActionNode("immolate", nullptr, nullptr, nullptr); }
static ActionNode* immolate_on_attacker(PlayerbotAI*) { return new ActionNode("immolate on attacker", nullptr, nullptr, nullptr); }
static ActionNode* incinerate(PlayerbotAI*) { return new ActionNode("incinerate", nullptr, nullptr, nullptr); }
static ActionNode* soul_fire(PlayerbotAI*) { return new ActionNode("soul fire", nullptr, nullptr, nullptr); }
static ActionNode* shadow_bolt(PlayerbotAI*) { return new ActionNode("shadow bolt", nullptr, nullptr, nullptr); }
static ActionNode* life_tap(PlayerbotAI*) { return new ActionNode("life tap", nullptr, nullptr, nullptr); }
static ActionNode* immolation_aura(PlayerbotAI*) { return new ActionNode("immolation aura", nullptr, nullptr, nullptr); }
static ActionNode* shadowflame(PlayerbotAI*) { return new ActionNode("shadowflame", nullptr, nullptr, nullptr); }
static ActionNode* seed_of_corruption_on_attacker(PlayerbotAI*) { return new ActionNode("seed of corruption on attacker", nullptr, nullptr, nullptr); }
static ActionNode* seed_of_corruption(PlayerbotAI*) { return new ActionNode("seed of corruption", nullptr, nullptr, nullptr); }
static ActionNode* rain_of_fire(PlayerbotAI*) { return new ActionNode("rain of fire", nullptr, nullptr, nullptr); }
static ActionNode* demon_charge(PlayerbotAI*) { return new ActionNode("demon charge", nullptr, nullptr, nullptr); }
static ActionNode* shadow_cleave(PlayerbotAI*) { return new ActionNode("shadow cleave", nullptr, nullptr, nullptr); }
};
// ===== Single Target Strategy =====
DemonologyWarlockStrategy::DemonologyWarlockStrategy(PlayerbotAI* botAI) : GenericWarlockStrategy(botAI)
{
actionNodeFactories.Add(new DemonologyWarlockStrategyActionNodeFactory());
}
// ===== Default Actions =====
NextAction** DemonologyWarlockStrategy::getDefaultActions()
{
return NextAction::array(0,
new NextAction("corruption", 5.6f),
new NextAction("curse of agony", 5.5f),
new NextAction("immolate", 5.4f),
new NextAction("shadow bolt", 5.3f),
new NextAction("incinerate", 5.2f),
new NextAction("shoot", 5.0f), nullptr);
}
// ===== Trigger Initialization ===
void DemonologyWarlockStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
GenericWarlockStrategy::InitTriggers(triggers);
// High priority cooldowns
triggers.push_back(new TriggerNode("metamorphosis", NextAction::array(0, new NextAction("metamorphosis", 28.5f), nullptr)));
triggers.push_back(new TriggerNode("demonic empowerment", NextAction::array(0, new NextAction("demonic empowerment", 28.0f), nullptr)));
// Main DoT triggers for high uptime
triggers.push_back(new TriggerNode("corruption on attacker", NextAction::array(0, new NextAction("corruption on attacker", 20.0f), nullptr)));
triggers.push_back(new TriggerNode("curse of agony on attacker", NextAction::array(0, new NextAction("curse of agony on attacker", 19.5f), nullptr)));
triggers.push_back(new TriggerNode("immolate on attacker", NextAction::array(0, new NextAction("immolate on attacker", 19.0f), nullptr)));
triggers.push_back(new TriggerNode("corruption", NextAction::array(0, new NextAction("corruption", 18.5f), nullptr)));
triggers.push_back(new TriggerNode("curse of agony", NextAction::array(0, new NextAction("curse of agony", 18.0f), nullptr)));
triggers.push_back(new TriggerNode("immolate", NextAction::array(0, new NextAction("immolate", 17.5f), nullptr)));
// Procs
triggers.push_back(new TriggerNode("decimation", NextAction::array(0, new NextAction("soul fire", 17.0f), nullptr)));
triggers.push_back(new TriggerNode("molten core", NextAction::array(0, new NextAction("incinerate", 16.5f), nullptr)));
// Life Tap glyph buff, and Life Tap as filler
triggers.push_back(new TriggerNode("life tap glyph buff", NextAction::array(0, new NextAction("life tap", 29.0f), nullptr)));
triggers.push_back(new TriggerNode("life tap", NextAction::array(0, new NextAction("life tap", 5.1f), nullptr)));
}
// ===== AoE Strategy, 3+ enemies =====
DemonologyWarlockAoeStrategy::DemonologyWarlockAoeStrategy(PlayerbotAI* botAI) : CombatStrategy(botAI) {}
void DemonologyWarlockAoeStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(new TriggerNode("medium aoe", NextAction::array(0,
new NextAction("immolation aura", 26.0f),
new NextAction("shadowflame", 22.5f),
new NextAction("seed of corruption on attacker", 22.0f),
new NextAction("seed of corruption", 21.5f),
new NextAction("rain of fire", 21.0f), nullptr)));
}
// Combat strategy to run to melee for Immolation Aura
// Enabled by default for the Demonology spec
// To enable, type "co +meta melee"
// To disable, type "co -meta melee"
MetaMeleeAoeStrategy::MetaMeleeAoeStrategy(PlayerbotAI* botAI) : CombatStrategy(botAI) {}
void MetaMeleeAoeStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(new TriggerNode("immolation aura active", NextAction::array(0,
new NextAction("reach melee", 25.5f),
new NextAction("demon charge", 25.0f),
new NextAction("shadow cleave", 24.5f), nullptr)));
}

View File

@@ -0,0 +1,41 @@
/*
* 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_DEMONOLOGYWARLOCKSTRATEGY_H
#define _PLAYERBOT_DEMONOLOGYWARLOCKSTRATEGY_H
#include "GenericWarlockStrategy.h"
#include "CombatStrategy.h"
class PlayerbotAI;
class DemonologyWarlockStrategy : public GenericWarlockStrategy
{
public:
DemonologyWarlockStrategy(PlayerbotAI* botAI);
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
std::string const getName() override { return "demo"; }
NextAction** getDefaultActions() override;
};
class DemonologyWarlockAoeStrategy : public CombatStrategy
{
public:
DemonologyWarlockAoeStrategy(PlayerbotAI* botAI);
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
std::string const getName() override { return "demo aoe"; }
};
class MetaMeleeAoeStrategy : public CombatStrategy
{
public:
MetaMeleeAoeStrategy(PlayerbotAI* botAI);
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
std::string const getName() override { return "meta melee"; }
};
#endif

View File

@@ -0,0 +1,107 @@
/*
* 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 "DestructionWarlockStrategy.h"
#include "Playerbots.h"
// ===== Action Node Factory =====
class DestructionWarlockStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
{
public:
DestructionWarlockStrategyActionNodeFactory()
{
creators["immolate"] = &immolate;
creators["conflagrate"] = &conflagrate;
creators["chaos bolt"] = &chaos_bolt;
creators["incinerate"] = &incinerate;
creators["corruption"] = &corruption;
creators["corruption on attacker"] = &corruption_on_attacker;
creators["curse of agony"] = &curse_of_agony;
creators["curse of agony on attacker"] = &curse_of_agony_on_attacker;
creators["shadow bolt"] = &shadow_bolt;
creators["shadowburn"] = &shadowburn;
creators["life tap"] = &life_tap;
creators["shadowfury"] = &shadowfury;
creators["shadowflame"] = &shadowflame;
creators["seed of corruption"] = &seed_of_corruption;
creators["seed of corruption on attacker"] = &seed_of_corruption;
creators["rain of fire"] = &rain_of_fire;
}
private:
static ActionNode* immolate(PlayerbotAI*) { return new ActionNode("immolate", nullptr, nullptr, nullptr); }
static ActionNode* conflagrate(PlayerbotAI*) { return new ActionNode("conflagrate", nullptr, nullptr, nullptr); }
static ActionNode* chaos_bolt(PlayerbotAI*) { return new ActionNode("chaos bolt", nullptr, nullptr, nullptr); }
static ActionNode* incinerate(PlayerbotAI*) { return new ActionNode("incinerate", nullptr, nullptr, nullptr); }
static ActionNode* corruption(PlayerbotAI*) { return new ActionNode("corruption", nullptr, nullptr, nullptr); }
static ActionNode* corruption_on_attacker(PlayerbotAI*) { return new ActionNode("corruption on attacker", nullptr, nullptr, nullptr); }
static ActionNode* curse_of_agony(PlayerbotAI*) { return new ActionNode("curse of agony", nullptr, nullptr, nullptr); }
static ActionNode* curse_of_agony_on_attacker(PlayerbotAI*) { return new ActionNode("curse of agony on attacker", nullptr, nullptr, nullptr); }
static ActionNode* shadow_bolt(PlayerbotAI*) { return new ActionNode("shadow bolt", nullptr, nullptr, nullptr); }
static ActionNode* shadowburn(PlayerbotAI*) { return new ActionNode("shadowburn", nullptr, nullptr, nullptr); }
static ActionNode* life_tap(PlayerbotAI*) { return new ActionNode("life tap", nullptr, nullptr, nullptr); }
static ActionNode* shadowfury(PlayerbotAI*) { return new ActionNode("shadowfury", nullptr, nullptr, nullptr); }
static ActionNode* shadowflame(PlayerbotAI*) { return new ActionNode("shadowflame", nullptr, nullptr, nullptr); }
static ActionNode* seed_of_corruption(PlayerbotAI*) { return new ActionNode("seed of corruption", nullptr, nullptr, nullptr); }
static ActionNode* seed_of_corruption_on_attacker(PlayerbotAI*) { return new ActionNode("seed of corruption on attacker", nullptr, nullptr, nullptr); }
static ActionNode* rain_of_fire(PlayerbotAI*) { return new ActionNode("rain of fire", nullptr, nullptr, nullptr); }
};
// ===== Single Target Strategy =====
DestructionWarlockStrategy::DestructionWarlockStrategy(PlayerbotAI* botAI) : GenericWarlockStrategy(botAI)
{
actionNodeFactories.Add(new DestructionWarlockStrategyActionNodeFactory());
}
// ===== Default Actions =====
NextAction** DestructionWarlockStrategy::getDefaultActions()
{
return NextAction::array( 0,
new NextAction("immolate", 6.1f),
new NextAction("conflagrate", 6.0f),
new NextAction("chaos bolt", 5.9f),
new NextAction("incinerate", 5.8f),
new NextAction("corruption", 5.4f), // Note: Corruption, Curse of Agony, and Shadow Bolt won't be used after
new NextAction("curse of agony", 5.3f), // the character learns Incinerate at level 64
new NextAction("shadow bolt", 5.2f),
new NextAction("shoot", 5.0f), nullptr);
}
// ===== Trigger Initialization ===
void DestructionWarlockStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
GenericWarlockStrategy::InitTriggers(triggers);
// Main DoT triggers for high uptime + high priority cooldowns
triggers.push_back(new TriggerNode("immolate", NextAction::array(0, new NextAction("immolate", 20.0f), nullptr)));
triggers.push_back(new TriggerNode("conflagrate", NextAction::array(0, new NextAction("conflagrate", 19.5f), nullptr)));
triggers.push_back(new TriggerNode("chaos bolt", NextAction::array(0, new NextAction("chaos bolt", 19.0f), nullptr)));
// Note: These DoTs won't be used after the character learns Incinerate at level 64
triggers.push_back(new TriggerNode("corruption on attacker", NextAction::array(0, new NextAction("corruption on attacker", 5.6f), nullptr)));
triggers.push_back(new TriggerNode("curse of agony on attacker", NextAction::array(0, new NextAction("curse of agony on attacker", 5.5f), nullptr)));
triggers.push_back(new TriggerNode("corruption", NextAction::array(0, new NextAction("corruption", 5.4f), nullptr)));
triggers.push_back(new TriggerNode("curse of agony", NextAction::array(0, new NextAction("curse of agony", 5.3f), nullptr)));
// Shadowburn as execute if target is low HP
triggers.push_back(new TriggerNode("target critical health", NextAction::array(0, new NextAction("shadowburn", 18.0f), nullptr)));
// Life Tap glyph buff, and Life Tap as filler
triggers.push_back(new TriggerNode("life tap glyph buff", NextAction::array(0, new NextAction("life tap", 29.0f), nullptr)));
triggers.push_back(new TriggerNode("life tap", NextAction::array(0, new NextAction("life tap", 5.1f), nullptr)));
}
// ===== AoE Strategy, 3+ enemies =====
DestructionWarlockAoeStrategy::DestructionWarlockAoeStrategy(PlayerbotAI* botAI) : CombatStrategy(botAI) {}
void DestructionWarlockAoeStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(new TriggerNode("medium aoe", NextAction::array(0,
new NextAction("shadowfury", 23.0f),
new NextAction("shadowflame", 22.5f),
new NextAction("seed of corruption on attacker", 22.0f),
new NextAction("seed of corruption", 21.5f),
new NextAction("rain of fire", 21.0f), nullptr)));
}

View File

@@ -0,0 +1,33 @@
/*
* 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_DESTRUCTIONWARLOCKSTRATEGY_H
#define _PLAYERBOT_DESTRUCTIONWARLOCKSTRATEGY_H
#include "GenericWarlockStrategy.h"
#include "CombatStrategy.h"
class PlayerbotAI;
class DestructionWarlockStrategy : public GenericWarlockStrategy
{
public:
DestructionWarlockStrategy(PlayerbotAI* botAI);
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
std::string const getName() override { return "destro"; }
NextAction** getDefaultActions() override;
};
class DestructionWarlockAoeStrategy : public CombatStrategy
{
public:
DestructionWarlockAoeStrategy(PlayerbotAI* botAI);
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
std::string const getName() override { return "destro aoe"; }
};
#endif

View File

@@ -4,105 +4,85 @@
*/
#include "DpsWarlockStrategy.h"
#include "Playerbots.h"
// This strategy is designed for low-level Warlocks without talents.
// All of the important spells/cooldowns have been migrated to
// their respective specs.
// ===== Action Node Factory =====
class DpsWarlockStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
{
public:
DpsWarlockStrategyActionNodeFactory()
{
creators["corruption"] = &corruption;
creators["curse of agony"] = &curse_of_agony;
creators["immolate"] = &immolate;
creators["shadow bolt"] = &shadow_bolt;
creators["unstable affliction"] = &unstable_affliction;
creators["unstable affliction on attacker"] = &unstable_affliction_on_attacker;
creators["life tap"] = &life_tap;
creators["shadowflame"] = &shadowflame;
creators["seed of corruption"] = &seed_of_corruption;
creators["rain of fire"] = &rain_of_fire;
creators["drain soul"] = &drain_soul;
}
private:
static ActionNode* shadow_bolt([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode("shadow bolt",
/*P*/ nullptr,
/*A*/ NextAction::array(0, new NextAction("shoot"), nullptr),
/*C*/ nullptr);
}
static ActionNode* unstable_affliction([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode("unstable affliction",
/*P*/ NULL,
/*A*/ NextAction::array(0, new NextAction("immolate"), NULL),
/*C*/ NULL);
}
static ActionNode* unstable_affliction_on_attacker([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode("unstable affliction on attacker",
/*P*/ NULL,
/*A*/ NextAction::array(0, new NextAction("immolate on attacker"), NULL),
/*C*/ NULL);
}
static ActionNode* corruption(PlayerbotAI*) { return new ActionNode("corruption", nullptr, nullptr, nullptr); }
static ActionNode* curse_of_agony(PlayerbotAI*){return new ActionNode("curse of agony", nullptr, nullptr, nullptr);}
static ActionNode* immolate(PlayerbotAI*) { return new ActionNode("immolate", nullptr, nullptr, nullptr); }
static ActionNode* shadow_bolt(PlayerbotAI*) { return new ActionNode("shadow bolt", nullptr, nullptr, nullptr); }
static ActionNode* life_tap(PlayerbotAI*) { return new ActionNode("life tap", nullptr, nullptr, nullptr); }
static ActionNode* shadowflame(PlayerbotAI*) { return new ActionNode("shadowflame", nullptr, nullptr, nullptr); }
static ActionNode* seed_of_corruption(PlayerbotAI*){return new ActionNode("seed of corruption", nullptr, nullptr, nullptr);}
static ActionNode* rain_of_fire(PlayerbotAI*) { return new ActionNode("rain of fire", nullptr, nullptr, nullptr); }
static ActionNode* drain_soul(PlayerbotAI*) { return new ActionNode("drain soul", nullptr, nullptr, nullptr); }
};
// ===== Single Target Strategy =====
DpsWarlockStrategy::DpsWarlockStrategy(PlayerbotAI* botAI) : GenericWarlockStrategy(botAI)
{
actionNodeFactories.Add(new DpsWarlockStrategyActionNodeFactory());
}
// ===== Default Actions =====
NextAction** DpsWarlockStrategy::getDefaultActions()
{
return NextAction::array(
0, new NextAction("haunt", ACTION_DEFAULT + 0.4f), new NextAction("demonic empowerment", ACTION_DEFAULT + 0.3f),
new NextAction("shadow bolt", ACTION_DEFAULT + 0.2f), new NextAction("shoot", ACTION_DEFAULT), nullptr);
return NextAction::array(0,
new NextAction("immolate", 5.5f),
new NextAction("corruption", 5.4f),
new NextAction("curse of agony", 5.3f),
new NextAction("shadow bolt", 5.2f),
new NextAction("shoot", 5.0f), nullptr);
}
// ===== Trigger Initialization ===
void DpsWarlockStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
GenericWarlockStrategy::InitTriggers(triggers);
triggers.push_back(
new TriggerNode("backlash", NextAction::array(0, new NextAction("shadow bolt", 20.0f), nullptr)));
// Main DoT triggers for high uptime
triggers.push_back(new TriggerNode("corruption on attacker", NextAction::array(0, new NextAction("corruption on attacker", 20.0f), nullptr)));
triggers.push_back(new TriggerNode("curse of agony on attacker", NextAction::array(0, new NextAction("curse of agony on attacker", 19.5f), nullptr)));
triggers.push_back(new TriggerNode("immolate on attacker", NextAction::array(0, new NextAction("immolate on attacker", 19.0f), nullptr)));
triggers.push_back(new TriggerNode("corruption", NextAction::array(0, new NextAction("corruption", 18.5f), nullptr)));
triggers.push_back(new TriggerNode("curse of agony", NextAction::array(0, new NextAction("curse of agony", 18.0f), nullptr)));
triggers.push_back(new TriggerNode("immolate", NextAction::array(0, new NextAction("immolate", 17.5f), nullptr)));
triggers.push_back(new TriggerNode("haunt", NextAction::array(0, new NextAction("haunt", 26.0f), NULL)));
triggers.push_back(
new TriggerNode("shadow trance", NextAction::array(0, new NextAction("shadow bolt", 15.0f), NULL)));
triggers.push_back(new TriggerNode("backlash", NextAction::array(0, new NextAction("shadow bolt", 15.0f), NULL)));
triggers.push_back(new TriggerNode("molten core", NextAction::array(0, new NextAction("incinerate", 15.0f), NULL)));
triggers.push_back(new TriggerNode("decimation", NextAction::array(0, new NextAction("soul fire", 16.0f), NULL)));
// cast during movement
triggers.push_back(
new TriggerNode("high mana", NextAction::array(0, new NextAction("life tap", ACTION_DEFAULT + 0.1f), nullptr)));
// Drain Soul as execute if target is low HP
triggers.push_back(new TriggerNode("target critical health", NextAction::array(0, new NextAction("drain soul", 17.0f), nullptr)));
// Cast during movement or to activate glyph buff
triggers.push_back(new TriggerNode("life tap", NextAction::array(0, new NextAction("life tap", ACTION_DEFAULT + 0.1f), nullptr)));
triggers.push_back(new TriggerNode("life tap glyph buff", NextAction::array(0, new NextAction("life tap", 28.0f), NULL)));
triggers.push_back(
new TriggerNode("metamorphosis", NextAction::array(0, new NextAction("metamorphosis", 20.0f), NULL)));
}
// ===== AoE Strategy, 3+ enemies =====
void DpsAoeWarlockStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(
new TriggerNode("medium aoe", NextAction::array(0, new NextAction("seed of corruption", 33.0f),
new NextAction("seed of corruption on attacker", 32.0f),
new NextAction("rain of fire", 31.0f), nullptr)));
triggers.push_back(new TriggerNode("corruption on attacker",
NextAction::array(0, new NextAction("corruption on attacker", 27.0f), nullptr)));
triggers.push_back(
new TriggerNode("unstable affliction on attacker",
NextAction::array(0, new NextAction("unstable affliction on attacker", 26.0f), NULL)));
triggers.push_back(
new TriggerNode("curse of agony on attacker",
NextAction::array(0, new NextAction("curse of agony on attacker", 25.0f), nullptr)));
}
void DpsWarlockDebuffStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(
new TriggerNode("corruption", NextAction::array(0, new NextAction("corruption", 22.0f), nullptr)));
triggers.push_back(new TriggerNode("unstable affliction",
NextAction::array(0, new NextAction("unstable affliction", 21.0f), NULL)));
triggers.push_back(
new TriggerNode("curse of agony", NextAction::array(0, new NextAction("curse of agony", 20.0f), nullptr)));
triggers.push_back(new TriggerNode("medium aoe", NextAction::array(0,
new NextAction("shadowflame", 22.5f),
new NextAction("seed of corruption on attacker", 22.0f),
new NextAction("seed of corruption", 21.5f),
new NextAction("rain of fire", 21.0f), nullptr)));
}

View File

@@ -30,14 +30,4 @@ public:
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
std::string const getName() override { return "aoe"; }
};
class DpsWarlockDebuffStrategy : public CombatStrategy
{
public:
DpsWarlockDebuffStrategy(PlayerbotAI* botAI) : CombatStrategy(botAI) {}
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
std::string const getName() override { return "dps debuff"; }
};
#endif

View File

@@ -4,7 +4,7 @@
*/
#include "GenericWarlockNonCombatStrategy.h"
#include "AiFactory.h"
#include "Playerbots.h"
class GenericWarlockNonCombatStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
@@ -20,6 +20,10 @@ public:
creators["summon felhunter"] = &summon_felhunter;
}
// Pet skills are setup in pass-through fashion, so if one fails, it attempts to cast the next one
// The order goes Felguard -> Felhunter -> Succubus -> Voidwalker -> Imp
// Pets are summoned based on the non-combat strategy you have active, the warlock's level, and if they have a soulstone available
private:
static ActionNode* fel_armor([[maybe_unused]] PlayerbotAI* botAI)
{
@@ -36,7 +40,6 @@ private:
/*A*/ NextAction::array(0, new NextAction("demon skin"), nullptr),
/*C*/ nullptr);
}
static ActionNode* summon_voidwalker([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode("summon voidwalker",
@@ -62,7 +65,7 @@ private:
{
return new ActionNode("summon felguard",
/*P*/ nullptr,
/*A*/ NextAction::array(0, new NextAction("summon succubus"), nullptr),
/*A*/ NextAction::array(0, new NextAction("summon felhunter"), nullptr),
/*C*/ nullptr);
}
};
@@ -75,45 +78,133 @@ GenericWarlockNonCombatStrategy::GenericWarlockNonCombatStrategy(PlayerbotAI* bo
void GenericWarlockNonCombatStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
NonCombatStrategy::InitTriggers(triggers);
triggers.push_back(new TriggerNode("has pet", NextAction::array(0, new NextAction("toggle pet spell", 60.0f), nullptr)));
triggers.push_back(new TriggerNode("no pet", NextAction::array(0, new NextAction("fel domination", 30.0f), nullptr)));
triggers.push_back(new TriggerNode("soul link", NextAction::array(0, new NextAction("soul link", 28.0f), nullptr)));
triggers.push_back(new TriggerNode("demon armor", NextAction::array(0, new NextAction("fel armor", 27.0f), nullptr)));
triggers.push_back(new TriggerNode("no healthstone", NextAction::array(0, new NextAction("create healthstone", 26.0f), nullptr)));
triggers.push_back(new TriggerNode("no soulstone", NextAction::array(0, new NextAction("create soulstone", 25.0f), nullptr)));
triggers.push_back(new TriggerNode("life tap", NextAction::array(0, new NextAction("life tap", 23.0f), nullptr)));
triggers.push_back(
new TriggerNode("demon armor", NextAction::array(0, new NextAction("fel armor", 21.0f), nullptr)));
// triggers.push_back(new TriggerNode("often", NextAction::array(0, new NextAction("apply oil", 1.0f), nullptr)));
triggers.push_back(
new TriggerNode("has pet", NextAction::array(0, new NextAction("toggle pet spell", 60.0f), nullptr)));
triggers.push_back(
new TriggerNode("no healthstone", NextAction::array(0, new NextAction("create healthstone", 15.0f), nullptr)));
triggers.push_back(
new TriggerNode("no spellstone", NextAction::array(0, new NextAction("create spellstone", 13.0f), nullptr)));
triggers.push_back(
new TriggerNode("spellstone", NextAction::array(0, new NextAction("spellstone", 13.0f), nullptr)));
}
void WarlockPetStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
// triggers.push_back(new TriggerNode("no pet", NextAction::array(0, new NextAction("summon felguard", 60.0f),
// nullptr)));
// TODO Warlock pets
Player* bot = botAI->GetBot();
int tab = AiFactory::GetPlayerSpecTab(bot);
if (tab == 2) // Destruction uses Firestone
{
triggers.push_back(
new TriggerNode("no firestone", NextAction::array(0, new NextAction("create firestone", 24.0f), nullptr)));
triggers.push_back(
new TriggerNode("firestone", NextAction::array(0, new NextAction("firestone", 24.0f), nullptr)));
}
else // Affliction and Demonology use Spellstone
{
triggers.push_back(new TriggerNode("no spellstone",
NextAction::array(0, new NextAction("create spellstone", 24.0f), nullptr)));
triggers.push_back(
new TriggerNode("spellstone", NextAction::array(0, new NextAction("spellstone", 24.0f), nullptr)));
}
}
// Non-combat strategy for summoning a Imp
// Enabled by default for the Destruction spec
// To enable, type "nc +imp"
// To disable, type "nc -imp"
SummonImpStrategy::SummonImpStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) {}
void SummonImpStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(new TriggerNode("no pet", NextAction::array(0, new NextAction("summon imp", 11.0f), NULL)));
triggers.push_back(new TriggerNode("no pet", NextAction::array(0, new NextAction("summon imp", 29.0f), NULL)));
}
SummonFelguardStrategy::SummonFelguardStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) {}
// Non-combat strategy for summoning a Voidwalker
// Disabled by default
// To enable, type "nc +voidwalker"
// To disable, type "nc -voidwalker"
SummonVoidwalkerStrategy::SummonVoidwalkerStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) {}
void SummonFelguardStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
void SummonVoidwalkerStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(new TriggerNode("no pet", NextAction::array(0, new NextAction("summon felguard", 11.0f), NULL)));
triggers.push_back(
new TriggerNode("no pet", NextAction::array(0, new NextAction("summon voidwalker", 29.0f), NULL)));
}
// Non-combat strategy for summoning a Succubus
// Disabled by default
// To enable, type "nc +succubus"
// To disable, type "nc -succubus"
SummonSuccubusStrategy::SummonSuccubusStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) {}
void SummonSuccubusStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(new TriggerNode("no pet", NextAction::array(0, new NextAction("summon succubus", 29.0f), NULL)));
}
// Non-combat strategy for summoning a Felhunter
// Enabled by default for the Affliction spec
// To enable, type "nc +felhunter"
// To disable, type "nc -felhunter"
SummonFelhunterStrategy::SummonFelhunterStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) {}
void SummonFelhunterStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(
new TriggerNode("no pet", NextAction::array(0, new NextAction("summon felhunter", 11.0f), NULL)));
new TriggerNode("no pet", NextAction::array(0, new NextAction("summon felhunter", 29.0f), NULL)));
}
// Non-combat strategy for summoning a Felguard
// Enabled by default for the Demonology spec
// To enable, type "nc +felguard"
// To disable, type "nc -felguard"
SummonFelguardStrategy::SummonFelguardStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) {}
void SummonFelguardStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(new TriggerNode("no pet", NextAction::array(0, new NextAction("summon felguard", 29.0f), NULL)));
}
// Non-combat strategy for selecting themselves to receive soulstone
// Disabled by default
// To enable, type "nc +ss self"
// To disable, type "nc -ss self"
SoulstoneSelfStrategy::SoulstoneSelfStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) {}
void SoulstoneSelfStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(new TriggerNode("soulstone", NextAction::array(0, new NextAction("soulstone self", 24.0f), NULL)));
}
// Non-combat strategy for selecting the master to receive soulstone
// Disabled by default
// To enable, type "nc +ss master"
// To disable, type "nc -ss master"
SoulstoneMasterStrategy::SoulstoneMasterStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) {}
void SoulstoneMasterStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(
new TriggerNode("soulstone", NextAction::array(0, new NextAction("soulstone master", 24.0f), NULL)));
}
// Non-combat strategy for selecting tanks to receive soulstone
// Disabled by default
// To enable, type "nc +ss tank"
// To disable, type "nc -ss tank"
SoulstoneTankStrategy::SoulstoneTankStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) {}
void SoulstoneTankStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(
new TriggerNode("soulstone", NextAction::array(0, new NextAction("soulstone tank", 24.0f), NULL)));
}
// Non-combat strategy for selecting healers to receive soulstone
// Disabled by default
// To enable, type "nc +ss healer"
// To disable, type "nc -ss healer"
SoulstoneHealerStrategy::SoulstoneHealerStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) {}
void SoulstoneHealerStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(
new TriggerNode("soulstone", NextAction::array(0, new NextAction("soulstone healer", 24.0f), NULL)));
}

View File

@@ -19,30 +19,31 @@ public:
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
};
class WarlockPetStrategy : public Strategy
{
public:
WarlockPetStrategy(PlayerbotAI* botAI) : Strategy(botAI) {}
std::string const getName() override { return "pet"; }
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
};
class SummonImpStrategy : public NonCombatStrategy
{
public:
SummonImpStrategy(PlayerbotAI* ai);
virtual std::string const getName() override { return "bhealth"; }
virtual std::string const getName() override { return "imp"; }
public:
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
};
class SummonFelguardStrategy : public NonCombatStrategy
class SummonVoidwalkerStrategy : public NonCombatStrategy
{
public:
SummonFelguardStrategy(PlayerbotAI* ai);
virtual std::string const getName() override { return "bdps"; }
SummonVoidwalkerStrategy(PlayerbotAI* ai);
virtual std::string const getName() override { return "voidwalker"; }
public:
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
};
class SummonSuccubusStrategy : public NonCombatStrategy
{
public:
SummonSuccubusStrategy(PlayerbotAI* ai);
virtual std::string const getName() override { return "succubus"; }
public:
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
@@ -52,7 +53,57 @@ class SummonFelhunterStrategy : public NonCombatStrategy
{
public:
SummonFelhunterStrategy(PlayerbotAI* ai);
virtual std::string const getName() override { return "bmana"; }
virtual std::string const getName() override { return "felhunter"; }
public:
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
};
class SummonFelguardStrategy : public NonCombatStrategy
{
public:
SummonFelguardStrategy(PlayerbotAI* ai);
virtual std::string const getName() override { return "felguard"; }
public:
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
};
class SoulstoneSelfStrategy : public NonCombatStrategy
{
public:
SoulstoneSelfStrategy(PlayerbotAI* ai);
virtual std::string const getName() override { return "ss self"; }
public:
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
};
class SoulstoneMasterStrategy : public NonCombatStrategy
{
public:
SoulstoneMasterStrategy(PlayerbotAI* ai);
virtual std::string const getName() override { return "ss master"; }
public:
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
};
class SoulstoneTankStrategy : public NonCombatStrategy
{
public:
SoulstoneTankStrategy(PlayerbotAI* ai);
virtual std::string const getName() override { return "ss tank"; }
public:
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
};
class SoulstoneHealerStrategy : public NonCombatStrategy
{
public:
SoulstoneHealerStrategy(PlayerbotAI* ai);
virtual std::string const getName() override { return "ss healer"; }
public:
void InitTriggers(std::vector<TriggerNode*>& triggers) override;

View File

@@ -4,7 +4,7 @@
*/
#include "GenericWarlockStrategy.h"
#include "Strategy.h"
#include "Playerbots.h"
class GenericWarlockStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
@@ -12,28 +12,22 @@ class GenericWarlockStrategyActionNodeFactory : public NamedObjectFactory<Action
public:
GenericWarlockStrategyActionNodeFactory()
{
// creators["summon voidwalker"] = &summon_voidwalker;
creators["banish"] = &banish;
creators["banish on cc"] = &banish_on_cc;
creators["fear on cc"] = &fear_on_cc;
creators["spell lock"] = &spell_lock;
creators["devour magic purge"] = &devour_magic_purge;
creators["devour magic cleanse"] = &devour_magic_cleanse;
}
private:
// static ActionNode* summon_voidwalker([[maybe_unused]] PlayerbotAI* botAI)
//{
// return new ActionNode ("summon voidwalker",
/*P*/ // nullptr,
/*A*/ // NextAction::array(0, new NextAction("drain soul"), nullptr),
/*C*/ // nullptr);
//}
static ActionNode* banish([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode("banish",
/*P*/ nullptr,
/*A*/ NextAction::array(0, new NextAction("fear"), nullptr),
/*C*/ nullptr);
}
static ActionNode* banish_on_cc(PlayerbotAI*) { return new ActionNode("banish on cc", nullptr, nullptr, nullptr); }
static ActionNode* fear_on_cc(PlayerbotAI*) { return new ActionNode("fear on cc", nullptr, nullptr, nullptr); }
static ActionNode* spell_lock(PlayerbotAI*) { return new ActionNode("spell lock", nullptr, nullptr, nullptr); }
static ActionNode* devour_magic_purge(PlayerbotAI*) { return new ActionNode("devour magic purge", nullptr, nullptr, nullptr); }
static ActionNode* devour_magic_cleanse(PlayerbotAI*) { return new ActionNode("devour magic cleanse", nullptr, nullptr, nullptr); }
};
GenericWarlockStrategy::GenericWarlockStrategy(PlayerbotAI* botAI) : RangedCombatStrategy(botAI)
GenericWarlockStrategy::GenericWarlockStrategy(PlayerbotAI* botAI) : CombatStrategy(botAI)
{
actionNodeFactories.Add(new GenericWarlockStrategyActionNodeFactory());
}
@@ -42,28 +36,38 @@ NextAction** GenericWarlockStrategy::getDefaultActions() { return NextAction::ar
void GenericWarlockStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
RangedCombatStrategy::InitTriggers(triggers);
CombatStrategy::InitTriggers(triggers);
// triggers.push_back(new TriggerNode("shadow trance", NextAction::array(0, new NextAction("shadow bolt", 20.0f),
// nullptr))); triggers.push_back(new TriggerNode("low health", NextAction::array(0, new NextAction("drain
// life", 40.0f), nullptr)));
triggers.push_back(
new TriggerNode("low mana", NextAction::array(0, new NextAction("life tap", ACTION_EMERGENCY + 5), nullptr)));
triggers.push_back(
new TriggerNode("target critical health", NextAction::array(0, new NextAction("drain soul", 30.0f), nullptr)));
// triggers.push_back(new TriggerNode("immolate", NextAction::array(0, new NextAction("immolate", 13.0f), new
// NextAction("conflagrate", 13.0f), nullptr))); triggers.push_back(new TriggerNode("enemy too close for spell",
// NextAction::array(0, new NextAction("flee", 49.0f), NULL)));
triggers.push_back(new TriggerNode("low mana", NextAction::array(0, new NextAction("life tap", ACTION_EMERGENCY + 5), nullptr)));
triggers.push_back(new TriggerNode("medium threat", NextAction::array(0, new NextAction("soulshatter", 55.0f), nullptr)));
triggers.push_back(new TriggerNode("spell lock", NextAction::array(0, new NextAction("spell lock", ACTION_INTERRUPT), nullptr)));
triggers.push_back(new TriggerNode("devour magic purge", NextAction::array(0, new NextAction("devour magic purge", ACTION_DISPEL), nullptr)));
triggers.push_back(new TriggerNode("devour magic cleanse", NextAction::array(0, new NextAction("devour magic cleanse", ACTION_DISPEL), nullptr)));
}
void WarlockBoostStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(
new TriggerNode("amplify curse", NextAction::array(0, new NextAction("amplify curse", 41.0f), nullptr)));
// Placeholder for future boost triggers
}
void WarlockPetStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
// Placeholder for future pet triggers
}
void WarlockCcStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(new TriggerNode("banish", NextAction::array(0, new NextAction("banish on cc", 32.0f), nullptr)));
triggers.push_back(new TriggerNode("fear", NextAction::array(0, new NextAction("fear on cc", 33.0f), nullptr)));
triggers.push_back(new TriggerNode("banish", NextAction::array(0, new NextAction("banish on cc", 33.0f), nullptr)));
triggers.push_back(new TriggerNode("fear", NextAction::array(0, new NextAction("fear on cc", 32.0f), nullptr)));
}
// Combat strategy for using Curse of the Elements
// Enabling this will turn off their use of Curse of Agony
// Enabled by default for the Destruction spec
// To enable, type "co +curse of elements"
// To disable, type "co -curse of elements"
void WarlockCurseOfTheElementsStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(new TriggerNode("curse of the elements", NextAction::array(0, new NextAction("curse of the elements", 30.0f), nullptr)));
}

View File

@@ -7,11 +7,10 @@
#define _PLAYERBOT_GENERICWARLOCKSTRATEGY_H
#include "CombatStrategy.h"
#include "RangedCombatStrategy.h"
class PlayerbotAI;
class GenericWarlockStrategy : public RangedCombatStrategy
class GenericWarlockStrategy : public CombatStrategy
{
public:
GenericWarlockStrategy(PlayerbotAI* botAI);
@@ -30,6 +29,15 @@ public:
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
};
class WarlockPetStrategy : public Strategy
{
public:
WarlockPetStrategy(PlayerbotAI* botAI) : Strategy(botAI) {}
std::string const getName() override { return "pet"; }
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
};
class WarlockCcStrategy : public Strategy
{
public:
@@ -39,4 +47,13 @@ public:
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
};
class WarlockCurseOfTheElementsStrategy : public Strategy
{
public:
WarlockCurseOfTheElementsStrategy(PlayerbotAI* botAI) : Strategy(botAI) {}
std::string const getName() override { return "curse of elements"; }
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
};
#endif

View File

@@ -4,65 +4,41 @@
*/
#include "TankWarlockStrategy.h"
#include "Playerbots.h"
class GenericWarlockStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
// Combat strategy for a Warlock Tank, for certain bosses like Twin Emperors
// Priority is set to spam Searing Pain and use Shadow Ward on CD
// Disabled by default
// To enable, type "co +tank"
// To disable, type "co -tank"
// ===== Action Node Factory =====
class TankWarlockStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
{
public:
GenericWarlockStrategyActionNodeFactory()
TankWarlockStrategyActionNodeFactory()
{
creators["summon voidwalker"] = &summon_voidwalker;
creators["summon felguard"] = &summon_felguard;
creators["summon succubus"] = &summon_succubus;
creators["summon felhunter"] = &summon_felhunter;
creators["shadow ward"] = &shadow_ward;
creators["searing pain"] = &searing_pain;
}
private:
static ActionNode* summon_voidwalker([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode("summon voidwalker",
/*P*/ nullptr,
/*A*/ NextAction::array(0, new NextAction("summon imp"), nullptr),
/*C*/ nullptr);
}
static ActionNode* summon_felguard([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode("summon felguard",
/*P*/ nullptr,
/*A*/ NextAction::array(0, new NextAction("summon succubus"), nullptr),
/*C*/ nullptr);
}
static ActionNode* summon_succubus([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode("summon succubus",
/*P*/ nullptr,
/*A*/ NextAction::array(0, new NextAction("summon voidwalker"), nullptr),
/*C*/ nullptr);
}
static ActionNode* summon_felhunter([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode("summon felhunter",
/*P*/ nullptr,
/*A*/ NextAction::array(0, new NextAction("summon imp"), nullptr),
/*C*/ nullptr);
}
static ActionNode* shadow_ward(PlayerbotAI*) { return new ActionNode("shadow ward", nullptr, nullptr, nullptr); }
static ActionNode* searing_pain(PlayerbotAI*) { return new ActionNode("searing pain", nullptr, nullptr, nullptr); }
};
// ===== Warlock Tank Combat Strategy =====
TankWarlockStrategy::TankWarlockStrategy(PlayerbotAI* botAI) : GenericWarlockStrategy(botAI)
{
actionNodeFactories.Add(new GenericWarlockStrategyActionNodeFactory());
actionNodeFactories.Add(new TankWarlockStrategyActionNodeFactory());
}
NextAction** TankWarlockStrategy::getDefaultActions()
{
return NextAction::array(0, new NextAction("shoot", ACTION_DEFAULT), nullptr);
// Shadow Ward is the highest priority, Searing Pain next.
return NextAction::array(0, new NextAction("shadow ward", 27.5f), new NextAction("searing pain", 27.0f), nullptr);
}
void TankWarlockStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
GenericWarlockStrategy::InitTriggers(triggers);
}

View File

@@ -5,23 +5,204 @@
#include "WarlockActions.h"
#include <string>
#include <vector>
#include "Event.h"
#include "Item.h"
#include "ObjectGuid.h"
#include "Player.h"
#include "PlayerbotAI.h"
#include "Playerbots.h"
#include "ServerFacade.h"
#include "Unit.h"
bool CastDrainSoulAction::isUseful() { return AI_VALUE2(uint32, "item count", "soul shard") < 10; }
Value<Unit*>* CastBanishAction::GetTargetValue() { return context->GetValue<Unit*>("cc target", "banish"); }
bool CastBanishAction::Execute(Event event) { return botAI->CastSpell("banish", GetTarget()); }
Value<Unit*>* CastFearOnCcAction::GetTargetValue() { return context->GetValue<Unit*>("cc target", "fear"); }
bool CastFearOnCcAction::Execute(Event event) { return botAI->CastSpell("fear", GetTarget()); }
bool CastFearOnCcAction::isPossible() { return true; }
bool CastFearOnCcAction::isUseful() { return true; }
// Checks if the bot has less than 32 soul shards, and if so, allows casting Drain Soul
bool CastDrainSoulAction::isUseful() { return AI_VALUE2(uint32, "item count", "soul shard") < 32; }
// Checks if the bot's health is above a certain threshold, and if so, allows casting Life Tap
bool CastLifeTapAction::isUseful() { return AI_VALUE2(uint8, "health", "self target") > sPlayerbotAIConfig->lowHealth; }
Unit* UseSoulstoneAction::GetTarget() { return botAI->GetMaster(); }
// Checks if the target marked with the moon icon can be banished
bool CastBanishOnCcAction::isPossible()
{
Unit* target = GetTarget();
if (!target)
return false;
// Only possible on elementals or demons
uint32 creatureType = target->GetCreatureType();
if (creatureType != CREATURE_TYPE_DEMON && creatureType != CREATURE_TYPE_ELEMENTAL)
return false;
// Use base class to check spell available, range, etc
return CastCrowdControlSpellAction::isPossible();
}
// Checks if the target marked with the moon icon can be feared
bool CastFearOnCcAction::isPossible()
{
Unit* target = GetTarget();
if (!target)
return false;
// Fear cannot be cast on mechanical or undead creatures
uint32 creatureType = target->GetCreatureType();
if (creatureType == CREATURE_TYPE_MECHANICAL || creatureType == CREATURE_TYPE_UNDEAD)
return false;
// Use base class to check spell available, range, etc
return CastCrowdControlSpellAction::isPossible();
}
// Checks if the enemies are close enough to use Shadowflame
bool CastShadowflameAction::isUseful()
{
Unit* target = AI_VALUE(Unit*, "current target");
if (!target)
return false;
bool facingTarget = AI_VALUE2(bool, "facing", "current target");
bool targetClose = bot->IsWithinCombatRange(target, 7.0f); // 7 yard cone
return facingTarget && targetClose;
}
// Checks if the bot knows Seed of Corruption, and prevents the use of Rain of Fire if it does
bool CastRainOfFireAction::isUseful()
{
Unit* target = GetTarget();
if (!target)
return false;
if (bot->HasSpell(27243) || bot->HasSpell(47835) || bot->HasSpell(47836)) // Seed of Corruption spell IDs
return false;
return true;
}
// Checks if the enemies are close enough to use Hellfire
bool CastHellfireAction::isUseful()
{
Unit* target = AI_VALUE(Unit*, "current target");
if (!target)
return false;
return bot->IsWithinCombatRange(target, 5.0f); // 5 yard AoE radius
}
// Checks if the "meta melee aoe" strategy is active, OR if the bot is in melee range of the target
bool CastImmolationAuraAction::isUseful()
{
if (botAI->HasStrategy("meta melee", BOT_STATE_COMBAT))
return true;
Unit* target = AI_VALUE(Unit*, "current target");
if (!target)
return false;
if (!bot->HasAura(47241)) // 47241 is Metamorphosis spell ID (WotLK)
return false;
return bot->IsWithinCombatRange(target, 5.0f); // 5 yard AoE radius
}
// Checks if the "warlock tank" strategy is active, and if so, prevents the use of Soulshatter
bool CastSoulshatterAction::isUseful()
{
if (botAI->HasStrategy("tank", BOT_STATE_COMBAT))
return false;
return true;
}
// Checks if the target has a soulstone aura
static bool HasSoulstoneAura(Unit* unit)
{
static const std::vector<uint32> soulstoneAuraIds = {20707, 20762, 20763, 20764, 20765, 27239, 47883};
for (uint32 spellId : soulstoneAuraIds)
if (unit->HasAura(spellId))
return true;
return false;
}
// Use the soulstone item on the bot itself with nc strategy "ss self"
bool UseSoulstoneSelfAction::Execute(Event event)
{
std::vector<Item*> items = AI_VALUE2(std::vector<Item*>, "inventory items", "soulstone");
if (items.empty())
return false;
if (HasSoulstoneAura(bot))
return false;
bot->SetSelection(bot->GetGUID());
return UseItem(items[0], ObjectGuid::Empty, nullptr, bot);
}
// Use the soulstone item on the bot's master with nc strategy "ss master"
bool UseSoulstoneMasterAction::Execute(Event event)
{
std::vector<Item*> items = AI_VALUE2(std::vector<Item*>, "inventory items", "soulstone");
if (items.empty())
return false;
Player* master = botAI->GetMaster();
if (!master || HasSoulstoneAura(master))
return false;
bot->SetSelection(master->GetGUID());
return UseItem(items[0], ObjectGuid::Empty, nullptr, master);
}
// Use the soulstone item on a tank in the group with nc strategy "ss tank"
bool UseSoulstoneTankAction::Execute(Event event)
{
std::vector<Item*> items = AI_VALUE2(std::vector<Item*>, "inventory items", "soulstone");
if (items.empty())
return false;
Player* tank = nullptr;
Group* group = bot->GetGroup();
if (group)
{
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
{
Player* member = gref->GetSource();
if (member && member->IsAlive() && botAI->IsTank(member) && !HasSoulstoneAura(member))
{
tank = member;
break;
}
}
}
if (!tank)
return false;
bot->SetSelection(tank->GetGUID());
return UseItem(items[0], ObjectGuid::Empty, nullptr, tank);
}
// Use the soulstone item on a healer in the group with nc strategy "ss healer"
bool UseSoulstoneHealerAction::Execute(Event event)
{
std::vector<Item*> items = AI_VALUE2(std::vector<Item*>, "inventory items", "soulstone");
if (items.empty())
return false;
Player* healer = nullptr;
Group* group = bot->GetGroup();
if (group)
{
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
{
Player* member = gref->GetSource();
if (member && member->IsAlive() && botAI->IsHeal(member) && !HasSoulstoneAura(member))
{
healer = member;
break;
}
}
}
if (!healer)
return false;
bot->SetSelection(healer->GetGUID());
return UseItem(items[0], ObjectGuid::Empty, nullptr, healer);
}

View File

@@ -8,10 +8,13 @@
#include "GenericSpellActions.h"
#include "UseItemAction.h"
#include "Action.h"
class PlayerbotAI;
class Unit;
// Buff and Out of Combat Spells
class CastDemonSkinAction : public CastBuffSpellAction
{
public:
@@ -30,71 +33,67 @@ public:
CastFelArmorAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "fel armor") {}
};
BEGIN_RANGED_SPELL_ACTION(CastShadowBoltAction, "shadow bolt")
END_SPELL_ACTION()
class CastDrainSoulAction : public CastSpellAction
class CastSoulLinkAction : public CastBuffSpellAction
{
public:
CastDrainSoulAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "drain soul") {}
bool isUseful() override;
CastSoulLinkAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "soul link", false, 5000) {}
std::string const GetTargetName() override { return "pet target"; }
};
class CastDrainManaAction : public CastSpellAction
class CastCreateHealthstoneAction : public CastBuffSpellAction
{
public:
CastDrainManaAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "drain mana") {}
CastCreateHealthstoneAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "create healthstone") {}
};
class CastDrainLifeAction : public CastSpellAction
class CastCreateFirestoneAction : public CastBuffSpellAction
{
public:
CastDrainLifeAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "drain life") {}
CastCreateFirestoneAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "create firestone") {}
};
class CastCurseOfAgonyAction : public CastDebuffSpellAction
class CastCreateSpellstoneAction : public CastBuffSpellAction
{
public:
CastCurseOfAgonyAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "curse of agony", true) {}
CastCreateSpellstoneAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "create spellstone") {}
};
class CastCurseOfWeaknessAction : public CastDebuffSpellAction
class CastCreateSoulstoneAction : public CastBuffSpellAction
{
public:
CastCurseOfWeaknessAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "curse of weakness") {}
CastCreateSoulstoneAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "create soulstone") {}
};
class CastCorruptionAction : public CastDebuffSpellAction
class UseSoulstoneSelfAction : public UseSpellItemAction
{
public:
CastCorruptionAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "corruption", true) {}
bool isUseful() override
{
return CastDebuffSpellAction::isUseful() && !botAI->HasAura("seed of corruption", GetTarget(), false, true);
}
UseSoulstoneSelfAction(PlayerbotAI* botAI) : UseSpellItemAction(botAI, "soulstone") {}
bool Execute(Event event) override;
};
class CastCorruptionOnAttackerAction : public CastDebuffSpellOnAttackerAction
class UseSoulstoneMasterAction : public UseSpellItemAction
{
public:
CastCorruptionOnAttackerAction(PlayerbotAI* botAI) : CastDebuffSpellOnAttackerAction(botAI, "corruption", true) {}
bool isUseful() override
{
return CastDebuffSpellOnAttackerAction::isUseful() &&
!botAI->HasAura("seed of corruption", GetTarget(), false, true);
}
UseSoulstoneMasterAction(PlayerbotAI* botAI) : UseSpellItemAction(botAI, "soulstone") {}
bool Execute(Event event) override;
};
class CastCurseOfAgonyOnAttackerAction : public CastDebuffSpellOnAttackerAction
class UseSoulstoneTankAction : public UseSpellItemAction
{
public:
CastCurseOfAgonyOnAttackerAction(PlayerbotAI* botAI)
: CastDebuffSpellOnAttackerAction(botAI, "curse of agony", true)
{
}
UseSoulstoneTankAction(PlayerbotAI* botAI) : UseSpellItemAction(botAI, "soulstone") {}
bool Execute(Event event) override;
};
class UseSoulstoneHealerAction : public UseSpellItemAction
{
public:
UseSoulstoneHealerAction(PlayerbotAI* botAI) : UseSpellItemAction(botAI, "soulstone") {}
bool Execute(Event event) override;
};
// Summoning Spells
class CastSummonVoidwalkerAction : public CastBuffSpellAction
{
public:
@@ -124,41 +123,293 @@ class CastSummonSuccubusAction : public CastBuffSpellAction
public:
CastSummonSuccubusAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "summon succubus") {}
};
class CastCreateHealthstoneAction : public CastBuffSpellAction
class CastFelDominationAction : public CastBuffSpellAction
{
public:
CastCreateHealthstoneAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "create healthstone") {}
CastFelDominationAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "fel domination") {}
};
class CastCreateFirestoneAction : public CastBuffSpellAction
// CC and Pet Spells
class CastBanishOnCcAction : public CastCrowdControlSpellAction
{
public:
CastCreateFirestoneAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "create firestone") {}
CastBanishOnCcAction(PlayerbotAI* botAI) : CastCrowdControlSpellAction(botAI, "banish") {}
bool isPossible() override;
};
class CastCreateSpellstoneAction : public CastBuffSpellAction
class CastFearOnCcAction : public CastCrowdControlSpellAction
{
public:
CastCreateSpellstoneAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "create spellstone") {}
CastFearOnCcAction(PlayerbotAI* botAI) : CastCrowdControlSpellAction(botAI, "fear") {}
bool isPossible() override;
};
class CastBanishAction : public CastBuffSpellAction
class CastSpellLockAction : public CastSpellAction
{
public:
CastBanishAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "banish on cc") {}
Value<Unit*>* GetTargetValue() override;
bool Execute(Event event) override;
CastSpellLockAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "spell lock") {}
};
class CastDevourMagicPurgeAction : public CastSpellAction
{
public:
CastDevourMagicPurgeAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "devour magic") {}
std::string const GetTargetName() override { return "current target"; }
};
class CastDevourMagicCleanseAction : public CastSpellAction
{
public:
CastDevourMagicCleanseAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "devour magic cleanse") {}
std::string const getName() override { return "cleanse magic on party"; }
};
// Utility Spells
class CastShadowWardAction : public CastBuffSpellAction
{
public:
CastShadowWardAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "shadow ward") {}
};
class CastSoulshatterAction : public CastSpellAction
{
public:
CastSoulshatterAction(PlayerbotAI* ai) : CastSpellAction(ai, "soulshatter") {}
bool isUseful() override;
};
class CastLifeTapAction : public CastSpellAction
{
public:
CastLifeTapAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "life tap") {}
std::string const GetTargetName() override { return "self target"; }
bool isUseful() override;
};
class CastCurseOfWeaknessAction : public CastDebuffSpellAction
{
public:
CastCurseOfWeaknessAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "curse of weakness") {}
};
class CastCurseOfTheElementsAction : public CastDebuffSpellAction
{
public:
CastCurseOfTheElementsAction(PlayerbotAI* ai) : CastDebuffSpellAction(ai, "curse of the elements", true) {}
bool isUseful() override
{
// Bypass TTL check
return CastAuraSpellAction::isUseful();
}
};
class DemonChargeAction : public CastSpellAction
{
public:
DemonChargeAction(PlayerbotAI* ai) : CastSpellAction(ai, "demon charge") {}
};
// Cooldown Spells
class CastMetamorphosisAction : public CastBuffSpellAction
{
public:
CastMetamorphosisAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "metamorphosis") {}
};
class CastDemonicEmpowermentAction : public CastBuffSpellAction
{
public:
CastDemonicEmpowermentAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "demonic empowerment") {}
std::string const GetTargetName() override { return "pet target"; }
};
// DoT Spells
class CastCurseOfAgonyAction : public CastDebuffSpellAction
{
public:
CastCurseOfAgonyAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "curse of agony", true) {}
bool isUseful() override
{
if (botAI->HasStrategy(
"curse of elements", BOT_STATE_COMBAT)) // If Curse of the Elements strategy is active, do not cast Curse of Agony
return false;
// Bypass TTL check
return CastAuraSpellAction::isUseful();
}
};
class CastCurseOfAgonyOnAttackerAction : public CastDebuffSpellOnAttackerAction
{
public:
CastCurseOfAgonyOnAttackerAction(PlayerbotAI* botAI)
: CastDebuffSpellOnAttackerAction(botAI, "curse of agony", true)
{
}
bool isUseful() override
{
if (botAI->HasStrategy(
"curse of elements", BOT_STATE_COMBAT)) // If Curse of the Elements strategy is active, do not cast Curse of Agony
return false;
// Bypass TTL check
return CastAuraSpellAction::isUseful();
}
};
class CastCorruptionAction : public CastDebuffSpellAction
{
public:
CastCorruptionAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "corruption", true) {}
bool isUseful() override
{
// Bypass TTL check and prevent casting if Seed of Corruption is present
return CastAuraSpellAction::isUseful() && !botAI->HasAura("seed of corruption", GetTarget(), false, true);
}
};
class CastCorruptionOnAttackerAction : public CastDebuffSpellOnAttackerAction
{
public:
CastCorruptionOnAttackerAction(PlayerbotAI* botAI) : CastDebuffSpellOnAttackerAction(botAI, "corruption", true) {}
bool isUseful() override
{
// Bypass TTL check and prevent casting if Seed of Corruption is present
return CastAuraSpellAction::isUseful() && !botAI->HasAura("seed of corruption", GetTarget(), false, true);
}
};
class CastImmolateAction : public CastDebuffSpellAction
{
public:
CastImmolateAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "immolate", true) {}
bool isUseful() override
{
// Bypass TTL check
return CastAuraSpellAction::isUseful();
}
};
class CastImmolateOnAttackerAction : public CastDebuffSpellOnAttackerAction
{
public:
CastImmolateOnAttackerAction(PlayerbotAI* botAI) : CastDebuffSpellOnAttackerAction(botAI, "immolate", true) {}
bool isUseful() override
{
// Bypass TTL check
return CastAuraSpellAction::isUseful();
}
};
class CastUnstableAfflictionAction : public CastDebuffSpellAction
{
public:
CastUnstableAfflictionAction(PlayerbotAI* ai) : CastDebuffSpellAction(ai, "unstable affliction", true) {}
bool isUseful() override
{
// Bypass TTL check
return CastAuraSpellAction::isUseful();
}
};
class CastUnstableAfflictionOnAttackerAction : public CastDebuffSpellOnAttackerAction
{
public:
CastUnstableAfflictionOnAttackerAction(PlayerbotAI* ai)
: CastDebuffSpellOnAttackerAction(ai, "unstable affliction", true)
{
}
bool isUseful() override
{
// Bypass TTL check
return CastAuraSpellAction::isUseful();
}
};
// Damage Spells
class CastShadowBoltAction : public CastSpellAction
{
public:
CastShadowBoltAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "shadow bolt") {}
};
class CastDrainSoulAction : public CastSpellAction
{
public:
CastDrainSoulAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "drain soul") {}
bool isUseful() override;
};
class CastDrainManaAction : public CastSpellAction
{
public:
CastDrainManaAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "drain mana") {}
};
class CastDrainLifeAction : public CastSpellAction
{
public:
CastDrainLifeAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "drain life") {}
};
class CastConflagrateAction : public CastSpellAction
{
public:
CastConflagrateAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "conflagrate") {}
};
class CastIncinerateAction : public CastSpellAction
{
public:
CastIncinerateAction(PlayerbotAI* ai) : CastSpellAction(ai, "incinerate") {}
};
class CastHauntAction : public CastSpellAction
{
public:
CastHauntAction(PlayerbotAI* ai) : CastSpellAction(ai, "haunt") {}
};
class CastSoulFireAction : public CastSpellAction
{
public:
CastSoulFireAction(PlayerbotAI* ai) : CastSpellAction(ai, "soul fire") {}
};
class CastShadowburnAction : public CastSpellAction
{
public:
CastShadowburnAction(PlayerbotAI* ai) : CastSpellAction(ai, "shadowburn") {}
};
class CastChaosBoltAction : public CastSpellAction
{
public:
CastChaosBoltAction(PlayerbotAI* ai) : CastSpellAction(ai, "chaos bolt") {}
};
class CastSearingPainAction : public CastSpellAction
{
public:
CastSearingPainAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "searing pain") {}
};
// AoE Spells
class CastSeedOfCorruptionAction : public CastDebuffSpellAction
{
public:
CastSeedOfCorruptionAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "seed of corruption", true, 0) {}
bool isUseful() override
{
return CastDebuffSpellAction::isUseful() && !botAI->HasAura("corruption", GetTarget(), false, true);
// Bypass TTL check
return CastAuraSpellAction::isUseful();
}
ActionThreatType getThreatType() override { return ActionThreatType::Aoe; }
};
@@ -172,7 +423,8 @@ public:
}
bool isUseful() override
{
return CastDebuffSpellOnAttackerAction::isUseful() && !botAI->HasAura("corruption", GetTarget(), false, true);
// Bypass TTL check
return CastAuraSpellAction::isUseful();
}
ActionThreatType getThreatType() override { return ActionThreatType::Aoe; }
};
@@ -182,6 +434,22 @@ class CastRainOfFireAction : public CastSpellAction
public:
CastRainOfFireAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "rain of fire") {}
ActionThreatType getThreatType() override { return ActionThreatType::Aoe; }
bool isUseful() override;
};
class CastHellfireAction : public CastSpellAction
{
public:
CastHellfireAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "hellfire") {}
ActionThreatType getThreatType() override { return ActionThreatType::Aoe; }
bool isUseful() override;
};
class CastShadowflameAction : public CastSpellAction
{
public:
CastShadowflameAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "shadowflame") {}
bool isUseful() override;
};
class CastShadowfuryAction : public CastSpellAction
@@ -190,125 +458,17 @@ public:
CastShadowfuryAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "shadowfury") {}
};
class CastImmolateAction : public CastDebuffSpellAction
class CastImmolationAuraAction : public CastSpellAction
{
public:
CastImmolateAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "immolate", true) {}
};
class CastImmolateOnAttackerAction : public CastDebuffSpellOnAttackerAction
{
public:
CastImmolateOnAttackerAction(PlayerbotAI* botAI) : CastDebuffSpellOnAttackerAction(botAI, "immolate", true) {}
};
class CastConflagrateAction : public CastSpellAction
{
public:
CastConflagrateAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "conflagrate") {}
};
class CastIncinirateAction : public CastSpellAction
{
public:
CastIncinirateAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "incinirate") {}
};
class CastFearAction : public CastDebuffSpellAction
{
public:
CastFearAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "fear") {}
};
class CastFearOnCcAction : public CastBuffSpellAction
{
public:
CastFearOnCcAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "fear on cc") {}
Value<Unit*>* GetTargetValue() override;
bool Execute(Event event) override;
bool isPossible() override;
CastImmolationAuraAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "immolation aura") {}
ActionThreatType getThreatType() override { return ActionThreatType::Aoe; }
bool isUseful() override;
};
class CastLifeTapAction : public CastSpellAction
class ShadowCleaveAction : public CastMeleeSpellAction
{
public:
CastLifeTapAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "life tap") {}
std::string const GetTargetName() override { return "self target"; }
bool isUseful() override;
};
class CastAmplifyCurseAction : public CastBuffSpellAction
{
public:
CastAmplifyCurseAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "amplify curse") {}
};
class CastSiphonLifeAction : public CastDebuffSpellAction
{
public:
CastSiphonLifeAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "siphon life", true) {}
};
class CastSiphonLifeOnAttackerAction : public CastDebuffSpellOnAttackerAction
{
public:
CastSiphonLifeOnAttackerAction(PlayerbotAI* botAI) : CastDebuffSpellOnAttackerAction(botAI, "siphon life") {}
};
class CastUnstableAfflictionAction : public CastDebuffSpellAction
{
public:
CastUnstableAfflictionAction(PlayerbotAI* ai) : CastDebuffSpellAction(ai, "unstable affliction", true) {}
};
class CastHauntAction : public CastSpellAction
{
public:
CastHauntAction(PlayerbotAI* ai) : CastSpellAction(ai, "haunt") {}
};
class CastDemonicEmpowermentAction : public CastBuffSpellAction
{
public:
CastDemonicEmpowermentAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "demonic empowerment") {}
std::string const GetTargetName() override { return "pet target"; }
};
class CastMetamorphosisAction : public CastBuffSpellAction
{
public:
CastMetamorphosisAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "metamorphosis") {}
};
class CastUnstableAfflictionOnAttackerAction : public CastDebuffSpellOnAttackerAction
{
public:
CastUnstableAfflictionOnAttackerAction(PlayerbotAI* ai)
: CastDebuffSpellOnAttackerAction(ai, "unstable affliction", true)
{
}
};
class CastSoulFireAction : public CastSpellAction
{
public:
CastSoulFireAction(PlayerbotAI* ai) : CastSpellAction(ai, "soul fire") {}
};
class CastIncinerateAction : public CastSpellAction
{
public:
CastIncinerateAction(PlayerbotAI* ai) : CastSpellAction(ai, "incinerate") {}
};
class UseSoulstoneAction : public UseSpellItemAction
{
public:
UseSoulstoneAction(PlayerbotAI* ai) : UseSpellItemAction(ai, "soulstone") {}
Unit* GetTarget() override;
ShadowCleaveAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "shadow cleave") {}
};
#endif

View File

@@ -4,7 +4,10 @@
*/
#include "WarlockAiObjectContext.h"
#include "AfflictionWarlockStrategy.h"
#include "DemonologyWarlockStrategy.h"
#include "DestructionWarlockStrategy.h"
#include "TankWarlockStrategy.h"
#include "DpsWarlockStrategy.h"
#include "GenericTriggers.h"
#include "GenericWarlockNonCombatStrategy.h"
@@ -12,7 +15,6 @@
#include "Playerbots.h"
#include "PullStrategy.h"
#include "Strategy.h"
#include "TankWarlockStrategy.h"
#include "UseItemAction.h"
#include "WarlockActions.h"
#include "WarlockTriggers.h"
@@ -24,21 +26,37 @@ public:
{
creators["nc"] = &WarlockStrategyFactoryInternal::nc;
creators["pull"] = &WarlockStrategyFactoryInternal::pull;
creators["aoe"] = &WarlockStrategyFactoryInternal::aoe;
creators["dps debuff"] = &WarlockStrategyFactoryInternal::dps_debuff;
creators["boost"] = &WarlockStrategyFactoryInternal::boost;
creators["cc"] = &WarlockStrategyFactoryInternal::cc;
creators["pet"] = &WarlockStrategyFactoryInternal::pet;
creators["affli"] = &WarlockStrategyFactoryInternal::affliction;
creators["affli aoe"] = &WarlockStrategyFactoryInternal::affliction_aoe;
creators["demo"] = &WarlockStrategyFactoryInternal::demonology;
creators["demo aoe"] = &WarlockStrategyFactoryInternal::demonology_aoe;
creators["destro"] = &WarlockStrategyFactoryInternal::destruction;
creators["destro aoe"] = &WarlockStrategyFactoryInternal::destruction_aoe;
creators["meta melee"] = &WarlockStrategyFactoryInternal::meta_melee_aoe;
creators["dps"] = &WarlockStrategyFactoryInternal::dps;
creators["aoe"] = &WarlockStrategyFactoryInternal::aoe;
creators["curse of elements"] = &WarlockStrategyFactoryInternal::curse_of_elements;
}
private:
static Strategy* pet(PlayerbotAI* botAI) { return new WarlockPetStrategy(botAI); }
static Strategy* nc(PlayerbotAI* botAI) { return new GenericWarlockNonCombatStrategy(botAI); }
static Strategy* aoe(PlayerbotAI* botAI) { return new DpsAoeWarlockStrategy(botAI); }
static Strategy* dps_debuff(PlayerbotAI* botAI) { return new DpsWarlockDebuffStrategy(botAI); }
static Strategy* pull(PlayerbotAI* botAI) { return new PullStrategy(botAI, "shoot"); }
static Strategy* boost(PlayerbotAI* botAI) { return new WarlockBoostStrategy(botAI); }
static Strategy* cc(PlayerbotAI* botAI) { return new WarlockCcStrategy(botAI); }
static Strategy* affliction(PlayerbotAI* botAI) { return new AfflictionWarlockStrategy(botAI); }
static Strategy* affliction_aoe(PlayerbotAI* botAI) { return new AfflictionWarlockAoeStrategy(botAI); }
static Strategy* demonology(PlayerbotAI* botAI) { return new DemonologyWarlockStrategy(botAI); }
static Strategy* demonology_aoe(PlayerbotAI* botAI) { return new DemonologyWarlockAoeStrategy(botAI); }
static Strategy* destruction(PlayerbotAI* botAI) { return new DestructionWarlockStrategy(botAI); }
static Strategy* destruction_aoe(PlayerbotAI* botAI) { return new DestructionWarlockAoeStrategy(botAI); }
static Strategy* meta_melee_aoe(PlayerbotAI* botAI) { return new MetaMeleeAoeStrategy(botAI); }
static Strategy* dps(PlayerbotAI* botAI) { return new DpsWarlockStrategy(botAI); }
static Strategy* aoe(PlayerbotAI* botAI) { return new DpsAoeWarlockStrategy(botAI); }
static Strategy* curse_of_elements(PlayerbotAI* botAI) { return new WarlockCurseOfTheElementsStrategy(botAI); }
};
class WarlockCombatStrategyFactoryInternal : public NamedObjectContext<Strategy>
@@ -46,13 +64,11 @@ class WarlockCombatStrategyFactoryInternal : public NamedObjectContext<Strategy>
public:
WarlockCombatStrategyFactoryInternal() : NamedObjectContext<Strategy>(false, true)
{
creators["dps"] = &WarlockCombatStrategyFactoryInternal::dps;
creators["tank"] = &WarlockCombatStrategyFactoryInternal::tank;
}
private:
static Strategy* tank(PlayerbotAI* botAI) { return new TankWarlockStrategy(botAI); }
static Strategy* dps(PlayerbotAI* botAI) { return new DpsWarlockStrategy(botAI); }
};
class NonCombatBuffStrategyFactoryInternal : public NamedObjectContext<Strategy>
@@ -60,15 +76,27 @@ class NonCombatBuffStrategyFactoryInternal : public NamedObjectContext<Strategy>
public:
NonCombatBuffStrategyFactoryInternal() : NamedObjectContext<Strategy>(false, true)
{
creators["bdps"] = &NonCombatBuffStrategyFactoryInternal::felguard;
creators["bmana"] = &NonCombatBuffStrategyFactoryInternal::felhunter;
creators["bhealth"] = &NonCombatBuffStrategyFactoryInternal::imp;
creators["imp"] = &NonCombatBuffStrategyFactoryInternal::imp;
creators["voidwalker"] = &NonCombatBuffStrategyFactoryInternal::voidwalker;
creators["succubus"] = &NonCombatBuffStrategyFactoryInternal::succubus;
creators["felhunter"] = &NonCombatBuffStrategyFactoryInternal::felhunter;
creators["felguard"] = &NonCombatBuffStrategyFactoryInternal::felguard;
creators["ss self"] = &NonCombatBuffStrategyFactoryInternal::soulstone_self;
creators["ss master"] = &NonCombatBuffStrategyFactoryInternal::soulstone_master;
creators["ss tank"] = &NonCombatBuffStrategyFactoryInternal::soulstone_tank;
creators["ss healer"] = &NonCombatBuffStrategyFactoryInternal::soulstone_healer;
}
private:
static Strategy* imp(PlayerbotAI* ai) { return new SummonImpStrategy(ai); }
static Strategy* voidwalker(PlayerbotAI* ai) { return new SummonVoidwalkerStrategy(ai); }
static Strategy* succubus(PlayerbotAI* ai) { return new SummonSuccubusStrategy(ai); }
static Strategy* felhunter(PlayerbotAI* ai) { return new SummonFelhunterStrategy(ai); }
static Strategy* felguard(PlayerbotAI* ai) { return new SummonFelguardStrategy(ai); }
static Strategy* soulstone_self(PlayerbotAI* ai) { return new SoulstoneSelfStrategy(ai); }
static Strategy* soulstone_master(PlayerbotAI* ai) { return new SoulstoneMasterStrategy(ai); }
static Strategy* soulstone_tank(PlayerbotAI* ai) { return new SoulstoneTankStrategy(ai); }
static Strategy* soulstone_healer(PlayerbotAI* ai) { return new SoulstoneHealerStrategy(ai); }
};
class WarlockTriggerFactoryInternal : public NamedObjectContext<Trigger>
@@ -78,64 +106,73 @@ public:
{
creators["shadow trance"] = &WarlockTriggerFactoryInternal::shadow_trance;
creators["demon armor"] = &WarlockTriggerFactoryInternal::demon_armor;
creators["soul link"] = &WarlockTriggerFactoryInternal::soul_link;
creators["no healthstone"] = &WarlockTriggerFactoryInternal::HasHealthstone;
creators["no firestone"] = &WarlockTriggerFactoryInternal::HasFirestone;
creators["no spellstone"] = &WarlockTriggerFactoryInternal::HasSpellstone;
creators["no soulstone"] = &WarlockTriggerFactoryInternal::HasSoulstone;
creators["firestone"] = &WarlockTriggerFactoryInternal::firestone;
creators["spellstone"] = &WarlockTriggerFactoryInternal::spellstone;
creators["soulstone"] = &WarlockTriggerFactoryInternal::soulstone;
creators["banish"] = &WarlockTriggerFactoryInternal::banish;
creators["fear"] = &WarlockTriggerFactoryInternal::fear;
creators["spell lock"] = &WarlockTriggerFactoryInternal::spell_lock;
creators["devour magic purge"] = &WarlockTriggerFactoryInternal::devour_magic_purge;
creators["devour magic cleanse"] = &WarlockTriggerFactoryInternal::devour_magic_cleanse;
creators["backlash"] = &WarlockTriggerFactoryInternal::backlash;
creators["corruption"] = &WarlockTriggerFactoryInternal::corruption;
creators["corruption on attacker"] = &WarlockTriggerFactoryInternal::corruption_on_attacker;
creators["curse of agony"] = &WarlockTriggerFactoryInternal::curse_of_agony;
creators["curse of agony on attacker"] = &WarlockTriggerFactoryInternal::curse_of_agony_on_attacker;
creators["banish"] = &WarlockTriggerFactoryInternal::banish;
creators["spellstone"] = &WarlockTriggerFactoryInternal::spellstone;
creators["backlash"] = &WarlockTriggerFactoryInternal::backlash;
creators["fear"] = &WarlockTriggerFactoryInternal::fear;
creators["immolate"] = &WarlockTriggerFactoryInternal::immolate;
creators["amplify curse"] = &WarlockTriggerFactoryInternal::amplify_curse;
creators["siphon life"] = &WarlockTriggerFactoryInternal::siphon_life;
creators["siphon life on attacker"] = &WarlockTriggerFactoryInternal::siphon_life_on_attacker;
creators["immolate on attacker"] = &WarlockTriggerFactoryInternal::immolate_on_attacker;
creators["unstable affliction"] = &WarlockTriggerFactoryInternal::unstable_affliction;
creators["unstable affliction on attacker"] = &WarlockTriggerFactoryInternal::unstable_affliction_on_attacker;
creators["haunt"] = &WarlockTriggerFactoryInternal::haunt;
creators["curse of the elements"] = &WarlockTriggerFactoryInternal::curse_of_the_elements;
creators["decimation"] = &WarlockTriggerFactoryInternal::decimation;
creators["life tap"] = &WarlockTriggerFactoryInternal::life_tap;
creators["life tap glyph buff"] = &WarlockTriggerFactoryInternal::life_tap_glyph_buff;
creators["molten core"] = &WarlockTriggerFactoryInternal::molten_core;
creators["metamorphosis"] = &WarlockTriggerFactoryInternal::metamorphosis;
creators["demonic empowerment"] = &WarlockTriggerFactoryInternal::demonic_empowerment;
creators["immolation aura active"] = &WarlockTriggerFactoryInternal::immolation_aura_active;
}
private:
static Trigger* amplify_curse(PlayerbotAI* botAI) { return new AmplifyCurseTrigger(botAI); }
static Trigger* shadow_trance(PlayerbotAI* botAI) { return new ShadowTranceTrigger(botAI); }
static Trigger* demon_armor(PlayerbotAI* botAI) { return new DemonArmorTrigger(botAI); }
static Trigger* soul_link(PlayerbotAI* botAI) { return new SoulLinkTrigger(botAI); }
static Trigger* HasHealthstone(PlayerbotAI* botAI) { return new HasHealthstoneTrigger(botAI); }
static Trigger* HasFirestone(PlayerbotAI* botAI) { return new HasFirestoneTrigger(botAI); }
static Trigger* HasSpellstone(PlayerbotAI* botAI) { return new HasSpellstoneTrigger(botAI); }
static Trigger* HasSoulstone(PlayerbotAI* botAI) { return new HasSoulstoneTrigger(botAI); }
static Trigger* firestone(PlayerbotAI* botAI) { return new FirestoneTrigger(botAI); }
static Trigger* spellstone(PlayerbotAI* botAI) { return new SpellstoneTrigger(botAI); }
static Trigger* soulstone(PlayerbotAI* botAI) { return new SoulstoneTrigger(botAI); }
static Trigger* corruption(PlayerbotAI* botAI) { return new CorruptionTrigger(botAI); }
static Trigger* corruption_on_attacker(PlayerbotAI* botAI) { return new CorruptionOnAttackerTrigger(botAI); }
static Trigger* siphon_life(PlayerbotAI* botAI) { return new SiphonLifeTrigger(botAI); }
static Trigger* siphon_life_on_attacker(PlayerbotAI* botAI) { return new SiphonLifeOnAttackerTrigger(botAI); }
static Trigger* curse_of_agony(PlayerbotAI* botAI) { return new CurseOfAgonyTrigger(botAI); }
static Trigger* curse_of_agony_on_attacker(PlayerbotAI* botAI)
{
return new CastCurseOfAgonyOnAttackerTrigger(botAI);
}
static Trigger* curse_of_agony_on_attacker(PlayerbotAI* botAI) { return new CurseOfAgonyOnAttackerTrigger(botAI); }
static Trigger* banish(PlayerbotAI* botAI) { return new BanishTrigger(botAI); }
static Trigger* spellstone(PlayerbotAI* botAI) { return new SpellstoneTrigger(botAI); }
static Trigger* backlash(PlayerbotAI* botAI) { return new BacklashTrigger(botAI); }
static Trigger* fear(PlayerbotAI* botAI) { return new FearTrigger(botAI); }
static Trigger* spell_lock(PlayerbotAI* botAI) { return new SpellLockInterruptSpellTrigger(botAI); }
static Trigger* devour_magic_purge(PlayerbotAI* botAI) { return new DevourMagicPurgeTrigger(botAI); }
static Trigger* devour_magic_cleanse(PlayerbotAI* botAI) { return new DevourMagicCleanseTrigger(botAI); }
static Trigger* backlash(PlayerbotAI* botAI) { return new BacklashTrigger(botAI); }
static Trigger* immolate(PlayerbotAI* botAI) { return new ImmolateTrigger(botAI); }
static Trigger* immolate_on_attacker(PlayerbotAI* ai) { return new ImmolateOnAttackerTrigger(ai); }
static Trigger* unstable_affliction(PlayerbotAI* ai) { return new UnstableAfflictionTrigger(ai); }
static Trigger* unstable_affliction_on_attacker(PlayerbotAI* ai)
{
return new UnstableAfflictionOnAttackerTrigger(ai);
}
static Trigger* unstable_affliction_on_attacker(PlayerbotAI* ai) { return new UnstableAfflictionOnAttackerTrigger(ai); }
static Trigger* haunt(PlayerbotAI* ai) { return new HauntTrigger(ai); }
static Trigger* curse_of_the_elements(PlayerbotAI* ai) { return new CurseOfTheElementsTrigger(ai); }
static Trigger* decimation(PlayerbotAI* ai) { return new DecimationTrigger(ai); }
static Trigger* life_tap(PlayerbotAI* ai) { return new LifeTapTrigger(ai); }
static Trigger* life_tap_glyph_buff(PlayerbotAI* ai) { return new LifeTapGlyphBuffTrigger(ai); }
static Trigger* molten_core(PlayerbotAI* ai) { return new MoltenCoreTrigger(ai); }
static Trigger* metamorphosis(PlayerbotAI* ai) { return new MetamorphosisTrigger(ai); }
static Trigger* demonic_empowerment(PlayerbotAI* ai) { return new DemonicEmpowermentTrigger(ai); }
static Trigger* immolation_aura_active(PlayerbotAI* ai) { return new ImmolationAuraActiveTrigger(ai); }
};
class WarlockAiObjectContextInternal : public NamedObjectContext<Action>
@@ -146,104 +183,125 @@ public:
creators["fel armor"] = &WarlockAiObjectContextInternal::fel_armor;
creators["demon armor"] = &WarlockAiObjectContextInternal::demon_armor;
creators["demon skin"] = &WarlockAiObjectContextInternal::demon_skin;
creators["soul link"] = &WarlockAiObjectContextInternal::soul_link;
creators["create healthstone"] = &WarlockAiObjectContextInternal::create_healthstone;
creators["create firestone"] = &WarlockAiObjectContextInternal::create_firestone;
creators["create spellstone"] = &WarlockAiObjectContextInternal::create_spellstone;
creators["create soulstone"] = &WarlockAiObjectContextInternal::create_soulstone;
creators["firestone"] = &WarlockAiObjectContextInternal::firestone;
creators["spellstone"] = &WarlockAiObjectContextInternal::spellstone;
creators["soulstone self"] = &WarlockAiObjectContextInternal::soulstone_self;
creators["soulstone master"] = &WarlockAiObjectContextInternal::soulstone_master;
creators["soulstone tank"] = &WarlockAiObjectContextInternal::soulstone_tank;
creators["soulstone healer"] = &WarlockAiObjectContextInternal::soulstone_healer;
creators["summon voidwalker"] = &WarlockAiObjectContextInternal::summon_voidwalker;
creators["summon felguard"] = &WarlockAiObjectContextInternal::summon_felguard;
creators["summon felhunter"] = &WarlockAiObjectContextInternal::summon_felhunter;
creators["summon succubus"] = &WarlockAiObjectContextInternal::summon_succubus;
creators["summon imp"] = &WarlockAiObjectContextInternal::summon_imp;
creators["fel domination"] = &WarlockAiObjectContextInternal::fel_domination;
creators["immolate"] = &WarlockAiObjectContextInternal::immolate;
creators["immolate on attacker"] = &WarlockAiObjectContextInternal::immolate_on_attacker;
creators["corruption"] = &WarlockAiObjectContextInternal::corruption;
creators["corruption on attacker"] = &WarlockAiObjectContextInternal::corruption_on_attacker;
creators["siphon life"] = &WarlockAiObjectContextInternal::siphon_life;
creators["siphon life on attacker"] = &WarlockAiObjectContextInternal::siphon_life_on_attacker;
creators["curse of agony"] = &WarlockAiObjectContextInternal::curse_of_agony;
creators["curse of agony on attacker"] = &WarlockAiObjectContextInternal::curse_of_agony_on_attacker;
creators["shadow bolt"] = &WarlockAiObjectContextInternal::shadow_bolt;
creators["drain soul"] = &WarlockAiObjectContextInternal::drain_soul;
creators["drain mana"] = &WarlockAiObjectContextInternal::drain_mana;
creators["drain life"] = &WarlockAiObjectContextInternal::drain_life;
creators["banish"] = &WarlockAiObjectContextInternal::banish;
creators["banish on cc"] = &WarlockAiObjectContextInternal::banish_on_cc;
creators["fear on cc"] = &WarlockAiObjectContextInternal::fear_on_cc;
creators["spell lock"] = &WarlockAiObjectContextInternal::spell_lock;
creators["devour magic purge"] = &WarlockAiObjectContextInternal::devour_magic_purge;
creators["devour magic cleanse"] = &WarlockAiObjectContextInternal::devour_magic_cleanse;
creators["seed of corruption"] = &WarlockAiObjectContextInternal::seed_of_corruption;
creators["seed of corruption on attacker"] = &WarlockAiObjectContextInternal::seed_of_corruption_on_attacker;
creators["rain of fire"] = &WarlockAiObjectContextInternal::rain_of_fire;
creators["hellfire"] = &WarlockAiObjectContextInternal::hellfire;
creators["shadowfury"] = &WarlockAiObjectContextInternal::shadowfury;
creators["life tap"] = &WarlockAiObjectContextInternal::life_tap;
creators["fear"] = &WarlockAiObjectContextInternal::fear;
creators["fear on cc"] = &WarlockAiObjectContextInternal::fear_on_cc;
creators["incinirate"] = &WarlockAiObjectContextInternal::incinirate;
creators["incinerate"] = &WarlockAiObjectContextInternal::incinerate;
creators["conflagrate"] = &WarlockAiObjectContextInternal::conflagrate;
creators["amplify curse"] = &WarlockAiObjectContextInternal::amplify_curse;
creators["immolate on attacker"] = &WarlockAiObjectContextInternal::immolate_on_attacker;
creators["unstable affliction"] = &WarlockAiObjectContextInternal::unstable_affliction;
creators["unstable affliction on attacker"] = &WarlockAiObjectContextInternal::unstable_affliction_on_attacker;
creators["haunt"] = &WarlockAiObjectContextInternal::haunt;
creators["curse of the elements"] = &WarlockAiObjectContextInternal::curse_of_the_elements;
creators["demonic empowerment"] = &WarlockAiObjectContextInternal::demonic_empowerment;
creators["metamorphosis"] = &WarlockAiObjectContextInternal::metamorphosis;
creators["soul fire"] = &WarlockAiObjectContextInternal::soul_fire;
creators["incinerate"] = &WarlockAiObjectContextInternal::incinerate;
creators["soulstone"] = &WarlockAiObjectContextInternal::soulstone;
}
creators["demon charge"] = &WarlockAiObjectContextInternal::demon_charge;
creators["shadow cleave"] = &WarlockAiObjectContextInternal::shadow_cleave;
creators["shadowburn"] = &WarlockAiObjectContextInternal::shadowburn;
creators["shadowflame"] = &WarlockAiObjectContextInternal::shadowflame;
creators["immolation aura"] = &WarlockAiObjectContextInternal::immolation_aura;
creators["chaos bolt"] = &WarlockAiObjectContextInternal::chaos_bolt;
creators["soulshatter"] = &WarlockAiObjectContextInternal::soulshatter;
creators["searing pain"] = WarlockAiObjectContextInternal::searing_pain;
creators["shadow ward"] = &WarlockAiObjectContextInternal::shadow_ward;
}
private:
static Action* amplify_curse(PlayerbotAI* botAI) { return new CastAmplifyCurseAction(botAI); }
static Action* conflagrate(PlayerbotAI* botAI) { return new CastConflagrateAction(botAI); }
static Action* incinirate(PlayerbotAI* botAI) { return new CastIncinirateAction(botAI); }
static Action* fear_on_cc(PlayerbotAI* botAI) { return new CastFearOnCcAction(botAI); }
static Action* fear(PlayerbotAI* botAI) { return new CastFearAction(botAI); }
static Action* incinerate(PlayerbotAI* botAI) { return new CastIncinerateAction(botAI); }
static Action* immolate(PlayerbotAI* botAI) { return new CastImmolateAction(botAI); }
static Action* summon_imp(PlayerbotAI* botAI) { return new CastSummonImpAction(botAI); }
static Action* summon_succubus(PlayerbotAI* botAI) { return new CastSummonSuccubusAction(botAI); }
static Action* immolate_on_attacker(PlayerbotAI* botAI) { return new CastImmolateOnAttackerAction(botAI); }
static Action* fel_armor(PlayerbotAI* botAI) { return new CastFelArmorAction(botAI); }
static Action* demon_armor(PlayerbotAI* botAI) { return new CastDemonArmorAction(botAI); }
static Action* demon_skin(PlayerbotAI* botAI) { return new CastDemonSkinAction(botAI); }
static Action* soul_link(PlayerbotAI* botAI) { return new CastSoulLinkAction(botAI); }
static Action* create_healthstone(PlayerbotAI* botAI) { return new CastCreateHealthstoneAction(botAI); }
static Action* create_firestone(PlayerbotAI* botAI) { return new CastCreateFirestoneAction(botAI); }
static Action* create_spellstone(PlayerbotAI* botAI) { return new CastCreateSpellstoneAction(botAI); }
static Action* create_soulstone(PlayerbotAI* botAI) { return new CastCreateSoulstoneAction(botAI); }
static Action* firestone(PlayerbotAI* botAI) { return new UseSpellItemAction(botAI, "firestone", true); }
static Action* spellstone(PlayerbotAI* botAI) { return new UseSpellItemAction(botAI, "spellstone", true); }
static Action* soulstone_self(PlayerbotAI* botAI) { return new UseSoulstoneSelfAction(botAI); }
static Action* soulstone_master(PlayerbotAI* botAI) { return new UseSoulstoneMasterAction(botAI); }
static Action* soulstone_tank(PlayerbotAI* botAI) { return new UseSoulstoneTankAction(botAI); }
static Action* soulstone_healer(PlayerbotAI* botAI) { return new UseSoulstoneHealerAction(botAI); }
static Action* summon_voidwalker(PlayerbotAI* botAI) { return new CastSummonVoidwalkerAction(botAI); }
static Action* summon_felguard(PlayerbotAI* botAI) { return new CastSummonFelguardAction(botAI); }
static Action* summon_felhunter(PlayerbotAI* botAI) { return new CastSummonFelhunterAction(botAI); }
static Action* summon_imp(PlayerbotAI* botAI) { return new CastSummonImpAction(botAI); }
static Action* summon_succubus(PlayerbotAI* botAI) { return new CastSummonSuccubusAction(botAI); }
static Action* fel_domination(PlayerbotAI* botAI) { return new CastFelDominationAction(botAI); }
static Action* corruption(PlayerbotAI* botAI) { return new CastCorruptionAction(botAI); }
static Action* corruption_on_attacker(PlayerbotAI* botAI) { return new CastCorruptionOnAttackerAction(botAI); }
static Action* siphon_life(PlayerbotAI* botAI) { return new CastSiphonLifeAction(botAI); }
static Action* siphon_life_on_attacker(PlayerbotAI* botAI) { return new CastSiphonLifeOnAttackerAction(botAI); }
static Action* curse_of_agony(PlayerbotAI* botAI) { return new CastCurseOfAgonyAction(botAI); }
static Action* curse_of_agony_on_attacker(PlayerbotAI* botAI)
{
return new CastCurseOfAgonyOnAttackerAction(botAI);
}
static Action* curse_of_agony_on_attacker(PlayerbotAI* botAI) { return new CastCurseOfAgonyOnAttackerAction(botAI); }
static Action* shadow_bolt(PlayerbotAI* botAI) { return new CastShadowBoltAction(botAI); }
static Action* drain_soul(PlayerbotAI* botAI) { return new CastDrainSoulAction(botAI); }
static Action* drain_mana(PlayerbotAI* botAI) { return new CastDrainManaAction(botAI); }
static Action* drain_life(PlayerbotAI* botAI) { return new CastDrainLifeAction(botAI); }
static Action* banish(PlayerbotAI* botAI) { return new CastBanishAction(botAI); }
static Action* banish_on_cc(PlayerbotAI* botAI) { return new CastBanishAction(botAI); }
static Action* banish_on_cc(PlayerbotAI* botAI) { return new CastBanishOnCcAction(botAI); }
static Action* fear_on_cc(PlayerbotAI* botAI) { return new CastFearOnCcAction(botAI); }
static Action* spell_lock(PlayerbotAI* botAI) { return new CastSpellLockAction(botAI); }
static Action* devour_magic_purge(PlayerbotAI* botAI) { return new CastDevourMagicPurgeAction(botAI); }
static Action* devour_magic_cleanse(PlayerbotAI* botAI) { return new CastDevourMagicCleanseAction(botAI); }
static Action* seed_of_corruption(PlayerbotAI* botAI) { return new CastSeedOfCorruptionAction(botAI); }
static Action* seed_of_corruption_on_attacker(PlayerbotAI* botAI)
{
return new CastSeedOfCorruptionOnAttackerAction(botAI);
}
static Action* seed_of_corruption_on_attacker(PlayerbotAI* botAI) { return new CastSeedOfCorruptionOnAttackerAction(botAI); }
static Action* rain_of_fire(PlayerbotAI* botAI) { return new CastRainOfFireAction(botAI); }
static Action* hellfire(PlayerbotAI* botAI) { return new CastHellfireAction(botAI); }
static Action* shadowfury(PlayerbotAI* botAI) { return new CastShadowfuryAction(botAI); }
static Action* life_tap(PlayerbotAI* botAI) { return new CastLifeTapAction(botAI); }
static Action* immolate_on_attacker(PlayerbotAI* ai) { return new CastImmolateOnAttackerAction(ai); }
static Action* unstable_affliction(PlayerbotAI* ai) { return new CastUnstableAfflictionAction(ai); }
static Action* unstable_affliction_on_attacker(PlayerbotAI* ai)
{
return new CastUnstableAfflictionOnAttackerAction(ai);
}
static Action* unstable_affliction_on_attacker(PlayerbotAI* ai) { return new CastUnstableAfflictionOnAttackerAction(ai); }
static Action* haunt(PlayerbotAI* ai) { return new CastHauntAction(ai); }
static Action* curse_of_the_elements(PlayerbotAI* ai) { return new CastCurseOfTheElementsAction(ai); }
static Action* demonic_empowerment(PlayerbotAI* ai) { return new CastDemonicEmpowermentAction(ai); }
static Action* metamorphosis(PlayerbotAI* ai) { return new CastMetamorphosisAction(ai); }
static Action* soul_fire(PlayerbotAI* ai) { return new CastSoulFireAction(ai); }
static Action* incinerate(PlayerbotAI* ai) { return new CastIncinerateAction(ai); }
static Action* soulstone(PlayerbotAI* ai) { return new UseSoulstoneAction(ai); }
static Action* demon_charge(PlayerbotAI* ai) { return new DemonChargeAction(ai); }
static Action* shadow_cleave(PlayerbotAI* ai) { return new ShadowCleaveAction(ai); }
static Action* shadowburn(PlayerbotAI* ai) { return new CastShadowburnAction(ai); }
static Action* shadowflame(PlayerbotAI* botAI) { return new CastShadowflameAction(botAI); }
static Action* immolation_aura(PlayerbotAI* botAI) { return new CastImmolationAuraAction(botAI); }
static Action* chaos_bolt(PlayerbotAI* botAI) { return new CastChaosBoltAction(botAI); }
static Action* soulshatter(PlayerbotAI* botAI) { return new CastSoulshatterAction(botAI);}
static Action* searing_pain(PlayerbotAI* botAI) { return new CastSearingPainAction(botAI); }
static Action* shadow_ward(PlayerbotAI* botAI) { return new CastShadowWardAction(botAI); }
};
WarlockAiObjectContext::WarlockAiObjectContext(PlayerbotAI* botAI) : AiObjectContext(botAI)

View File

@@ -4,10 +4,34 @@
*/
#include "WarlockTriggers.h"
#include "GenericTriggers.h"
#include "Playerbots.h"
bool SpellstoneTrigger::IsActive() { return BuffTrigger::IsActive() && AI_VALUE2(uint32, "item count", getName()) > 0; }
bool FirestoneTrigger::IsActive() { return BuffTrigger::IsActive() && AI_VALUE2(uint32, "item count", getName()) > 0; }
bool WarlockConjuredItemTrigger::IsActive()
{
return ItemCountTrigger::IsActive() && AI_VALUE2(uint32, "item count", "soul shard") > 0;
}
// Checks if the target marked with the moon icon can be banished
bool BanishTrigger::IsActive()
{
Unit* ccTarget = context->GetValue<Unit*>("cc target", "banish")->Get();
Unit* moonTarget = context->GetValue<Unit*>("rti cc target")->Get();
return ccTarget && moonTarget && ccTarget == moonTarget && HasCcTargetTrigger::IsActive();
}
// Checks if the target marked with the moon icon can be feared
bool FearTrigger::IsActive()
{
Unit* ccTarget = context->GetValue<Unit*>("cc target", "fear")->Get();
Unit* moonTarget = context->GetValue<Unit*>("rti cc target")->Get();
return ccTarget && moonTarget && ccTarget == moonTarget && HasCcTargetTrigger::IsActive();
}
bool DemonArmorTrigger::IsActive()
{
Unit* target = GetTarget();
@@ -15,30 +39,18 @@ bool DemonArmorTrigger::IsActive()
!botAI->HasAura("fel armor", target);
}
bool SpellstoneTrigger::IsActive() { return BuffTrigger::IsActive() && AI_VALUE2(uint32, "item count", getName()) > 0; }
bool WarlockConjuredItemTrigger::IsActive()
bool SoulLinkTrigger::IsActive()
{
return ItemCountTrigger::IsActive() && AI_VALUE2(uint32, "item count", "soul shard") > 0;
Unit* target = GetTarget();
return !botAI->HasAura("soul link", target);
}
bool ImmolateOnAttackerTrigger::IsActive()
bool DemonicEmpowermentTrigger::IsActive()
{
return DebuffOnAttackerTrigger::IsActive() &&
// !botAI->HasAura("immolate", GetTarget(), false, true) &&
!botAI->HasAura("unstable affliction", GetTarget(), false, true);
}
bool UnstableAfflictionTrigger::IsActive()
{
return DebuffTrigger::IsActive() && !botAI->HasAura("immolate", GetTarget(), false, true);
// !botAI->HasAura("unstable affliction", GetTarget(), false, true);
}
bool UnstableAfflictionOnAttackerTrigger::IsActive()
{
return DebuffOnAttackerTrigger::IsActive() && !botAI->HasAura("immolate", GetTarget(), false, true);
// !botAI->HasAura("unstable affliction", GetTarget(), false, true);
Pet* pet = bot->GetPet();
if (!pet)
return false;
return !botAI->HasAura("demonic empowerment", pet);
}
bool DecimationTrigger::IsActive()
@@ -47,11 +59,51 @@ bool DecimationTrigger::IsActive()
return aura && aura->GetDuration() > 3000;
}
// Checks if the bot's mana is below 85% and health is above a low health threshold
bool LifeTapTrigger::IsActive()
{
if (AI_VALUE2(uint8, "health", "self target") <= sPlayerbotAIConfig->lowHealth)
return false;
if (!AI_VALUE2(bool, "has mana", "self target"))
return false;
if (AI_VALUE2(uint8, "mana", "self target") >= 85)
return false;
return true;
}
// Checks if the Life Tap Glyph buff is active
bool LifeTapGlyphBuffTrigger::IsActive()
{
// Check life tap glyph first
if (!botAI->HasAura(63320, bot))
return false;
return BuffTrigger::IsActive();
}
// Checks if the target has a conflicting debuff that is equal to Curse of the Elements
bool CurseOfTheElementsTrigger::IsActive()
{
Unit* target = GetTarget();
if (!target || !target->IsAlive() || !target->IsInWorld())
return false;
// List of all spell IDs for Ebon Plague, Earth and Moon, and Curse of the Elements
static const uint32 CurseOfTheElementsExclusiveDebuffs[] = {// Ebon Plague
51735, 51734, 51726,
// Earth and Moon
48511, 48513, 48514,
// Curse of the Elements
1490, 11721, 11722, 27228, 47865};
// Check if target has any of the exclusive debuffs
for (uint32 spellId : CurseOfTheElementsExclusiveDebuffs)
{
if (target->HasAura(spellId))
return false;
}
// Use default BuffTrigger logic for the rest (only trigger if debuff is missing or expiring)
return BuffTrigger::IsActive();
}

View File

@@ -8,9 +8,13 @@
#include "GenericTriggers.h"
#include "PlayerbotAI.h"
#include "Playerbots.h"
#include "CureTriggers.h"
class PlayerbotAI;
// Buff and Out of Combat Triggers
class DemonArmorTrigger : public BuffTrigger
{
public:
@@ -19,90 +23,50 @@ public:
bool IsActive() override;
};
class SoulLinkTrigger : public BuffTrigger
{
public:
SoulLinkTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "soul link") {}
bool IsActive() override;
};
class FirestoneTrigger : public BuffTrigger
{
public:
FirestoneTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "firestone") {}
bool IsActive() override;
};
class SpellstoneTrigger : public BuffTrigger
{
public:
SpellstoneTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "spellstone") {}
bool IsActive() override;
};
// DEBUFF_CHECKISOWNER_TRIGGER(CurseOfAgonyTrigger, "curse of agony");
class CurseOfAgonyTrigger : public DebuffTrigger
class HasSoulstoneTrigger : public Trigger
{
public:
CurseOfAgonyTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "curse of agony", 1, true, 20.0f) {}
HasSoulstoneTrigger(PlayerbotAI* botAI) : Trigger(botAI, "no soulstone") {}
bool IsActive() override { return AI_VALUE2(uint32, "item count", "soulstone") == 0; }
};
class CorruptionTrigger : public DebuffTrigger
class SoulstoneTrigger : public Trigger
{
public:
CorruptionTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "corruption", 1, true) {}
SoulstoneTrigger(PlayerbotAI* botAI) : Trigger(botAI, "soulstone") {}
bool IsActive() override
{
return DebuffTrigger::IsActive() && !botAI->HasAura("seed of corruption", GetTarget(), false, true);
// Just check if we have a soulstone item available
return AI_VALUE2(uint32, "item count", "soulstone") > 0;
}
};
DEBUFF_CHECKISOWNER_TRIGGER(SiphonLifeTrigger, "siphon life");
class CorruptionOnAttackerTrigger : public DebuffOnAttackerTrigger
{
public:
CorruptionOnAttackerTrigger(PlayerbotAI* botAI) : DebuffOnAttackerTrigger(botAI, "corruption", true) {}
bool IsActive() override
{
return DebuffOnAttackerTrigger::IsActive() && !botAI->HasAura("seed of corruption", GetTarget(), false, true);
}
};
class CastCurseOfAgonyOnAttackerTrigger : public DebuffOnAttackerTrigger
{
public:
CastCurseOfAgonyOnAttackerTrigger(PlayerbotAI* botAI)
: DebuffOnAttackerTrigger(botAI, "curse of agony", true, 20.0f)
{
}
};
class SiphonLifeOnAttackerTrigger : public DebuffOnAttackerTrigger
{
public:
SiphonLifeOnAttackerTrigger(PlayerbotAI* botAI) : DebuffOnAttackerTrigger(botAI, "siphon life") {}
};
DEBUFF_CHECKISOWNER_TRIGGER(ImmolateTrigger, "immolate");
class ImmolateOnAttackerTrigger : public DebuffOnAttackerTrigger
{
public:
ImmolateOnAttackerTrigger(PlayerbotAI* ai) : DebuffOnAttackerTrigger(ai, "immolate") {}
virtual bool IsActive();
};
class ShadowTranceTrigger : public HasAuraTrigger
{
public:
ShadowTranceTrigger(PlayerbotAI* botAI) : HasAuraTrigger(botAI, "shadow trance") {}
};
class BacklashTrigger : public HasAuraTrigger
{
public:
BacklashTrigger(PlayerbotAI* botAI) : HasAuraTrigger(botAI, "backlash") {}
};
class BanishTrigger : public HasCcTargetTrigger
{
public:
BanishTrigger(PlayerbotAI* botAI) : HasCcTargetTrigger(botAI, "banish") {}
};
class WarlockConjuredItemTrigger : public ItemCountTrigger
{
public:
WarlockConjuredItemTrigger(PlayerbotAI* botAI, std::string const item) : ItemCountTrigger(botAI, item, 1) {}
bool IsActive() override;
};
@@ -124,30 +88,114 @@ public:
HasHealthstoneTrigger(PlayerbotAI* botAI) : WarlockConjuredItemTrigger(botAI, "healthstone") {}
};
// CC and Pet Triggers
class BanishTrigger : public HasCcTargetTrigger
{
public:
BanishTrigger(PlayerbotAI* botAI) : HasCcTargetTrigger(botAI, "banish") {}
bool IsActive() override;
};
class FearTrigger : public HasCcTargetTrigger
{
public:
FearTrigger(PlayerbotAI* botAI) : HasCcTargetTrigger(botAI, "fear") {}
};
class AmplifyCurseTrigger : public BuffTrigger
{
public:
AmplifyCurseTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "amplify curse") {}
};
class UnstableAfflictionTrigger : public DebuffTrigger // SpellTrigger
{
public:
UnstableAfflictionTrigger(PlayerbotAI* ai) : DebuffTrigger(ai, "unstable affliction", 1, true) {}
bool IsActive() override;
};
class SpellLockInterruptSpellTrigger : public InterruptSpellTrigger
{
public:
SpellLockInterruptSpellTrigger(PlayerbotAI* botAI) : InterruptSpellTrigger(botAI, "spell lock") {}
};
class DevourMagicPurgeTrigger : public TargetAuraDispelTrigger
{
public:
DevourMagicPurgeTrigger(PlayerbotAI* botAI) : TargetAuraDispelTrigger(botAI, "devour magic", DISPEL_MAGIC) {}
};
class DevourMagicCleanseTrigger : public PartyMemberNeedCureTrigger
{
public:
DevourMagicCleanseTrigger(PlayerbotAI* botAI) : PartyMemberNeedCureTrigger(botAI, "devour magic", DISPEL_MAGIC) {}
};
// DoT/Debuff Triggers
class CurseOfAgonyTrigger : public DebuffTrigger
{
public:
CurseOfAgonyTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "curse of agony", 1, true, 0.5f) {}
bool IsActive() override
{
if (botAI->HasStrategy(
"curse of elements", BOT_STATE_COMBAT)) // If Curse of the Elements strategy is active, do not cast Curse of Agony
return false;
return BuffTrigger::IsActive();
}
};
class CurseOfAgonyOnAttackerTrigger : public DebuffOnAttackerTrigger
{
public:
CurseOfAgonyOnAttackerTrigger(PlayerbotAI* botAI) : DebuffOnAttackerTrigger(botAI, "curse of agony", true) {}
bool IsActive() override
{
if (botAI->HasStrategy(
"curse of elements", BOT_STATE_COMBAT)) // If Curse of the Elements strategy is active, do not cast Curse of Agony
return false;
return BuffTrigger::IsActive();
}
};
class CorruptionTrigger : public DebuffTrigger
{
public:
CorruptionTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "corruption", 1, true, 0.5f) {}
bool IsActive() override
{
return BuffTrigger::IsActive() && !botAI->HasAura("seed of corruption", GetTarget(), false, true);
}
};
class CorruptionOnAttackerTrigger : public DebuffOnAttackerTrigger
{
public:
CorruptionOnAttackerTrigger(PlayerbotAI* botAI) : DebuffOnAttackerTrigger(botAI, "corruption", true) {}
bool IsActive() override
{
return BuffTrigger::IsActive() && !botAI->HasAura("seed of corruption", GetTarget(), false, true);
}
};
class ImmolateTrigger : public DebuffTrigger
{
public:
ImmolateTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "immolate", 1, true, 0.5f) {}
bool IsActive() override { return BuffTrigger::IsActive(); }
};
class ImmolateOnAttackerTrigger : public DebuffOnAttackerTrigger
{
public:
ImmolateOnAttackerTrigger(PlayerbotAI* ai) : DebuffOnAttackerTrigger(ai, "immolate", true) {}
bool IsActive() override { return BuffTrigger::IsActive(); }
};
class UnstableAfflictionTrigger : public DebuffTrigger
{
public:
UnstableAfflictionTrigger(PlayerbotAI* ai) : DebuffTrigger(ai, "unstable affliction", 1, true, 0.5f) {}
bool IsActive() override { return BuffTrigger::IsActive(); }
};
class UnstableAfflictionOnAttackerTrigger : public DebuffOnAttackerTrigger
{
public:
UnstableAfflictionOnAttackerTrigger(PlayerbotAI* ai) : DebuffOnAttackerTrigger(ai, "unstable affliction", true) {}
bool IsActive() override;
bool IsActive() override { return BuffTrigger::IsActive(); }
};
class HauntTrigger : public DebuffTrigger
@@ -156,10 +204,20 @@ public:
HauntTrigger(PlayerbotAI* ai) : DebuffTrigger(ai, "haunt", 1, true, 0) {}
};
class DecimationTrigger : public HasAuraTrigger
class CurseOfTheElementsTrigger : public DebuffTrigger
{
public:
DecimationTrigger(PlayerbotAI* ai) : HasAuraTrigger(ai, "decimation") {}
CurseOfTheElementsTrigger(PlayerbotAI* botAI)
: DebuffTrigger(botAI, "curse of the elements", 1, true, 0.5f) {}
bool IsActive() override;
};
// Proc/Cooldown Triggers
class LifeTapTrigger : public Trigger
{
public:
LifeTapTrigger(PlayerbotAI* ai) : Trigger(ai, "life tap") {}
bool IsActive() override;
};
@@ -170,15 +228,47 @@ public:
bool IsActive() override;
};
class MoltenCoreTrigger : public HasAuraTrigger
{
public:
MoltenCoreTrigger(PlayerbotAI* ai) : HasAuraTrigger(ai, "molten core") {}
};
class MetamorphosisTrigger : public BoostTrigger
{
public:
MetamorphosisTrigger(PlayerbotAI* ai) : BoostTrigger(ai, "metamorphosis") {}
};
class DemonicEmpowermentTrigger : public BuffTrigger
{
public:
DemonicEmpowermentTrigger(PlayerbotAI* ai) : BuffTrigger(ai, "demonic empowerment") {}
bool IsActive() override;
};
class ImmolationAuraActiveTrigger : public HasAuraTrigger
{
public:
ImmolationAuraActiveTrigger(PlayerbotAI* ai) : HasAuraTrigger(ai, "immolation aura") {}
};
class ShadowTranceTrigger : public HasAuraTrigger
{
public:
ShadowTranceTrigger(PlayerbotAI* botAI) : HasAuraTrigger(botAI, "shadow trance") {}
};
class BacklashTrigger : public HasAuraTrigger
{
public:
BacklashTrigger(PlayerbotAI* botAI) : HasAuraTrigger(botAI, "backlash") {}
};
class DecimationTrigger : public HasAuraTrigger
{
public:
DecimationTrigger(PlayerbotAI* ai) : HasAuraTrigger(ai, "decimation") {}
bool IsActive() override;
};
class MoltenCoreTrigger : public HasAuraTrigger
{
public:
MoltenCoreTrigger(PlayerbotAI* ai) : HasAuraTrigger(ai, "molten core") {}
};
#endif