Merge pull request #1430 from ThePenguinMan96/Warlock-Curse/Spellstone-and-Firestone-Strategies,-Soul-Shard-Replenish

Warlock Curse strategies, Spellstone and Firestone strategies, Soul Shard Replenish
This commit is contained in:
kadeshar
2025-07-08 18:57:50 +02:00
committed by GitHub
14 changed files with 446 additions and 185 deletions

View File

@@ -1440,7 +1440,7 @@ AiPlayerbot.PremadeSpecName.9.0 = affli pve
AiPlayerbot.PremadeSpecGlyph.9.0 = 45785,43390,50077,43394,43393,45779
AiPlayerbot.PremadeSpecLink.9.0.60 = 2350022001113510053500131151
AiPlayerbot.PremadeSpecLink.9.0.70 = 2350022001113510053500131151--55
AiPlayerbot.PremadeSpecLink.9.0.80 = 2350022001113510253500331151--5500000501
AiPlayerbot.PremadeSpecLink.9.0.80 = 2350022001123510253500331151--55000005
AiPlayerbot.PremadeSpecName.9.1 = demo pve
AiPlayerbot.PremadeSpecGlyph.9.1 = 45785,43390,50077,43394,43393,42459
AiPlayerbot.PremadeSpecLink.9.1.60 = -003203301135112530135201051

View File

@@ -386,9 +386,9 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
break;
case CLASS_WARLOCK:
if (tab == 0) // Affliction
engine->addStrategiesNoInit("affli", "affli aoe", nullptr);
engine->addStrategiesNoInit("affli", "affli aoe", "curse of agony", nullptr);
else if (tab == 1) // Demonology
engine->addStrategiesNoInit("demo", "demo aoe", "meta melee", nullptr);
engine->addStrategiesNoInit("demo", "demo aoe", "curse of agony", "meta melee", nullptr);
else if (tab == 2) // Destruction
engine->addStrategiesNoInit("destro", "destro aoe", "curse of elements", nullptr);
@@ -596,17 +596,17 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const
case CLASS_WARLOCK:
if (tab == WARLOCK_TAB_AFFLICATION)
{
nonCombatEngine->addStrategiesNoInit("felhunter", nullptr);
nonCombatEngine->addStrategiesNoInit("felhunter", "spellstone", nullptr);
}
else if (tab == WARLOCK_TAB_DEMONOLOGY)
{
nonCombatEngine->addStrategiesNoInit("felguard", nullptr);
nonCombatEngine->addStrategiesNoInit("felguard", "spellstone", nullptr);
}
else if (tab == WARLOCK_TAB_DESTRUCTION)
{
nonCombatEngine->addStrategiesNoInit("imp", nullptr);
nonCombatEngine->addStrategiesNoInit("imp", "firestone", nullptr);
}
nonCombatEngine->addStrategiesNoInit("dps assist", nullptr);
nonCombatEngine->addStrategiesNoInit("dps assist", "ss self", nullptr);
break;
case CLASS_DEATH_KNIGHT:
if (tab == 0)

View File

@@ -16,8 +16,6 @@ public:
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;
@@ -33,8 +31,6 @@ private:
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); }
@@ -55,9 +51,8 @@ AfflictionWarlockStrategy::AfflictionWarlockStrategy(PlayerbotAI* botAI) : Gener
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("corruption", 5.5f),
new NextAction("unstable affliction", 5.4f),
new NextAction("haunt", 5.3f),
new NextAction("shadow bolt", 5.2f),
new NextAction("shoot", 5.0f), nullptr);
@@ -71,10 +66,8 @@ void AfflictionWarlockStrategy::InitTriggers(std::vector<TriggerNode*>& 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
@@ -82,7 +75,7 @@ void AfflictionWarlockStrategy::InitTriggers(std::vector<TriggerNode*>& triggers
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 glyph buff", NextAction::array(0, new NextAction("life tap", 29.5f), nullptr)));
triggers.push_back(new TriggerNode("life tap", NextAction::array(0, new NextAction("life tap", 5.1f), nullptr)));
triggers.push_back(new TriggerNode("enemy too close for spell", NextAction::array(0, new NextAction("flee", 39.0f), nullptr)));

View File

@@ -14,8 +14,6 @@ public:
{
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;
@@ -35,8 +33,6 @@ public:
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); }
@@ -63,8 +59,7 @@ DemonologyWarlockStrategy::DemonologyWarlockStrategy(PlayerbotAI* botAI) : Gener
NextAction** DemonologyWarlockStrategy::getDefaultActions()
{
return NextAction::array(0,
new NextAction("corruption", 5.6f),
new NextAction("curse of agony", 5.5f),
new NextAction("corruption", 5.5f),
new NextAction("immolate", 5.4f),
new NextAction("shadow bolt", 5.3f),
new NextAction("incinerate", 5.2f),
@@ -81,11 +76,9 @@ void DemonologyWarlockStrategy::InitTriggers(std::vector<TriggerNode*>& triggers
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("corruption on attacker", NextAction::array(0, new NextAction("corruption 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("corruption", NextAction::array(0, new NextAction("corruption", 18.0f), nullptr)));
triggers.push_back(new TriggerNode("immolate", NextAction::array(0, new NextAction("immolate", 17.5f), nullptr)));
// Procs
@@ -93,7 +86,7 @@ void DemonologyWarlockStrategy::InitTriggers(std::vector<TriggerNode*>& triggers
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 glyph buff", NextAction::array(0, new NextAction("life tap", 29.5f), nullptr)));
triggers.push_back(new TriggerNode("life tap", NextAction::array(0, new NextAction("life tap", 5.1f), nullptr)));
triggers.push_back(new TriggerNode("meta melee flee check", NextAction::array(0, new NextAction("flee", 39.0f), nullptr)));

View File

@@ -18,8 +18,6 @@ public:
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;
@@ -37,8 +35,6 @@ private:
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); }
@@ -59,12 +55,11 @@ DestructionWarlockStrategy::DestructionWarlockStrategy(PlayerbotAI* botAI) : Gen
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("immolate", 5.9f),
new NextAction("conflagrate", 5.8f),
new NextAction("chaos bolt", 5.7f),
new NextAction("incinerate", 5.6f),
new NextAction("corruption", 5.3f), // Note: Corruption and Shadow Bolt won't be used after the character learns Incinerate at level 64
new NextAction("shadow bolt", 5.2f),
new NextAction("shoot", 5.0f), nullptr);
}
@@ -79,17 +74,15 @@ void DestructionWarlockStrategy::InitTriggers(std::vector<TriggerNode*>& trigger
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)));
// Note: Corruption 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.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 glyph buff", NextAction::array(0, new NextAction("life tap", 29.5f), nullptr)));
triggers.push_back(new TriggerNode("life tap", NextAction::array(0, new NextAction("life tap", 5.1f), nullptr)));
triggers.push_back(new TriggerNode("enemy too close for spell", NextAction::array(0, new NextAction("flee", 39.0f), nullptr)));

View File

@@ -22,7 +22,7 @@ public:
// 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
// Pets are summoned based on the non-combat strategy you have active, the warlock's level, and if they have a soul shard available
private:
static ActionNode* fel_armor([[maybe_unused]] PlayerbotAI* botAI)
@@ -80,27 +80,12 @@ void GenericWarlockNonCombatStrategy::InitTriggers(std::vector<TriggerNode*>& tr
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("no soul shard", NextAction::array(0, new NextAction("create soul shard", 29.5f), 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)));
Player* bot = botAI->GetBot();
int tab = AiFactory::GetPlayerSpecTab(bot);
// Firestone/Spellstone triggers
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
@@ -177,8 +162,7 @@ SoulstoneMasterStrategy::SoulstoneMasterStrategy(PlayerbotAI* ai) : NonCombatStr
void SoulstoneMasterStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(
new TriggerNode("soulstone", NextAction::array(0, new NextAction("soulstone master", 24.0f), NULL)));
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
@@ -189,8 +173,7 @@ SoulstoneTankStrategy::SoulstoneTankStrategy(PlayerbotAI* ai) : NonCombatStrateg
void SoulstoneTankStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(
new TriggerNode("soulstone", NextAction::array(0, new NextAction("soulstone tank", 24.0f), NULL)));
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
@@ -201,6 +184,29 @@ SoulstoneHealerStrategy::SoulstoneHealerStrategy(PlayerbotAI* ai) : NonCombatStr
void SoulstoneHealerStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(
new TriggerNode("soulstone", NextAction::array(0, new NextAction("soulstone healer", 24.0f), NULL)));
triggers.push_back(new TriggerNode("soulstone", NextAction::array(0, new NextAction("soulstone healer", 24.0f), NULL)));
}
// Non-combat strategy for using Spellstone
// Enabled by default for Affliction and Demonology specs
// To enable, type "nc +spellstone"
// To disable, type "nc -spellstone"
UseSpellstoneStrategy::UseSpellstoneStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) {}
void UseSpellstoneStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
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 using Firestone
// Enabled by default for the Destruction spec
// To enable, type "nc +firestone"
// To disable, type "nc -firestone"
UseFirestoneStrategy::UseFirestoneStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) {}
void UseFirestoneStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
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)));
}

View File

@@ -109,4 +109,24 @@ public:
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
};
class UseSpellstoneStrategy : public NonCombatStrategy
{
public:
UseSpellstoneStrategy(PlayerbotAI* ai);
virtual std::string const getName() override { return "spellstone"; }
public:
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
};
class UseFirestoneStrategy : public NonCombatStrategy
{
public:
UseFirestoneStrategy(PlayerbotAI* ai);
virtual std::string const getName() override { return "firestone"; }
public:
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
};
#endif

View File

@@ -38,11 +38,12 @@ void GenericWarlockStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
CombatStrategy::InitTriggers(triggers);
triggers.push_back(new TriggerNode("low mana", NextAction::array(0, new NextAction("life tap", ACTION_EMERGENCY + 5), nullptr)));
triggers.push_back(new TriggerNode("low mana", NextAction::array(0, new NextAction("life tap", 95.0f), 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)));
triggers.push_back(new TriggerNode("spell lock", NextAction::array(0, new NextAction("spell lock", 40.0f), nullptr)));
triggers.push_back(new TriggerNode("no soul shard", NextAction::array(0, new NextAction("create soul shard", 60.0f), nullptr)));
triggers.push_back(new TriggerNode("devour magic purge", NextAction::array(0, new NextAction("devour magic purge", 50.0f), nullptr)));
triggers.push_back(new TriggerNode("devour magic cleanse", NextAction::array(0, new NextAction("devour magic cleanse", 50.0f), nullptr)));
}
void WarlockBoostStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
@@ -61,13 +62,57 @@ void WarlockCcStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
triggers.push_back(new TriggerNode("fear", NextAction::array(0, new NextAction("fear on cc", 32.0f), nullptr)));
}
// Combat strategy for using Curse of Agony
// Enabled by default for the Affliction spec
// To enable, type "co +curse of agony"
// To disable, type "co -curse of agony"
void WarlockCurseOfAgonyStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
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("curse of agony", NextAction::array(0, new NextAction("curse of agony", 17.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)));
triggers.push_back(new TriggerNode("curse of the elements", NextAction::array(0, new NextAction("curse of the elements", 29.0f), nullptr)));
}
// Combat strategy for using Curse of Doom
// Disabled by default
// To enable, type "co +curse of doom"
// To disable, type "co -curse of doom"
void WarlockCurseOfDoomStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(new TriggerNode("curse of doom", NextAction::array(0, new NextAction("curse of doom", 29.0f), nullptr)));
}
// Combat strategy for using Curse of Exhaustion
// Disabled by default
// To enable, type "co +curse of exhaustion"
// To disable, type "co -curse of exhaustion"
void WarlockCurseOfExhaustionStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(new TriggerNode("curse of exhaustion", NextAction::array(0, new NextAction("curse of exhaustion", 29.0f), nullptr)));
}
// Combat strategy for using Curse of Tongues
// Disabled by default
// To enable, type "co +curse of tongues"
// To disable, type "co -curse of tongues"
void WarlockCurseOfTonguesStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(new TriggerNode("curse of tongues", NextAction::array(0, new NextAction("curse of tongues", 29.0f), nullptr)));
}
// Combat strategy for using Curse of Weakness
// Disabled by default
// To enable, type "co +curse of weakness"
// To disable, type "co -curse of weakness"
void WarlockCurseOfWeaknessStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(new TriggerNode("curse of weakness", NextAction::array(0, new NextAction("curse of weakness", 29.0f), nullptr)));
}

View File

@@ -48,6 +48,15 @@ public:
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
};
class WarlockCurseOfAgonyStrategy : public Strategy
{
public:
WarlockCurseOfAgonyStrategy(PlayerbotAI* botAI) : Strategy(botAI) {}
std::string const getName() override { return "curse of agony"; }
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
};
class WarlockCurseOfTheElementsStrategy : public Strategy
{
public:
@@ -57,4 +66,40 @@ public:
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
};
class WarlockCurseOfDoomStrategy : public Strategy
{
public:
WarlockCurseOfDoomStrategy(PlayerbotAI* botAI) : Strategy(botAI) {}
std::string const getName() override { return "curse of doom"; }
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
};
class WarlockCurseOfExhaustionStrategy : public Strategy
{
public:
WarlockCurseOfExhaustionStrategy(PlayerbotAI* botAI) : Strategy(botAI) {}
std::string const getName() override { return "curse of exhaustion"; }
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
};
class WarlockCurseOfTonguesStrategy : public Strategy
{
public:
WarlockCurseOfTonguesStrategy(PlayerbotAI* botAI) : Strategy(botAI) {}
std::string const getName() override { return "curse of tongues"; }
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
};
class WarlockCurseOfWeaknessStrategy : public Strategy
{
public:
WarlockCurseOfWeaknessStrategy(PlayerbotAI* botAI) : Strategy(botAI) {}
std::string const getName() override { return "curse of weakness"; }
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
};
#endif

View File

@@ -113,6 +113,28 @@ bool CastSoulshatterAction::isUseful()
return true;
}
// Checks if the bot has enough bag space to create a soul shard, then does so
bool CreateSoulShardAction::Execute(Event event)
{
Player* bot = botAI->GetBot();
if (!bot)
return false;
// Soul Shard item ID is 6265
uint32 soulShardId = 6265;
ItemPosCountVec dest;
uint32 count = 1;
if (bot->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, soulShardId, count) == EQUIP_ERR_OK)
{
bot->StoreNewItem(dest, soulShardId, true, Item::GenerateItemRandomPropertyId(soulShardId));
SQLTransaction<CharacterDatabaseConnection> trans = CharacterDatabase.BeginTransaction();
bot->SaveInventoryAndGoldToDB(trans);
CharacterDatabase.CommitTransaction(trans);
return true;
}
return false;
}
// Checks if the target has a soulstone aura
static bool HasSoulstoneAura(Unit* unit)
{

View File

@@ -40,6 +40,13 @@ public:
std::string const GetTargetName() override { return "pet target"; }
};
class CreateSoulShardAction : public Action
{
public:
CreateSoulShardAction(PlayerbotAI* botAI) : Action(botAI, "create soul shard") {}
bool Execute(Event event) override;
};
class CastCreateHealthstoneAction : public CastBuffSpellAction
{
public:
@@ -190,23 +197,6 @@ public:
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:
@@ -228,38 +218,7 @@ public:
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();
}
};
// DoT/Curse Spells
class CastCorruptionAction : public CastDebuffSpellAction
{
@@ -330,6 +289,86 @@ public:
}
};
class CastCurseOfAgonyAction : public CastDebuffSpellAction
{
public:
CastCurseOfAgonyAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "curse of agony", true) {}
bool isUseful() override
{
// Bypass TTL check
return CastAuraSpellAction::isUseful();
}
};
class CastCurseOfAgonyOnAttackerAction : public CastDebuffSpellOnAttackerAction
{
public:
CastCurseOfAgonyOnAttackerAction(PlayerbotAI* botAI)
: CastDebuffSpellOnAttackerAction(botAI, "curse of agony", true)
{
}
bool isUseful() override
{
// Bypass TTL check
return CastAuraSpellAction::isUseful();
}
};
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 CastCurseOfDoomAction : public CastDebuffSpellAction
{
public:
CastCurseOfDoomAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "curse of doom", true, 0) {}
bool isUseful() override
{
// Bypass TTL check
return CastAuraSpellAction::isUseful();
}
};
class CastCurseOfExhaustionAction : public CastDebuffSpellAction
{
public:
CastCurseOfExhaustionAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "curse of exhaustion") {}
bool isUseful() override
{
// Bypass TTL check
return CastAuraSpellAction::isUseful();
}
};
class CastCurseOfTonguesAction : public CastDebuffSpellAction
{
public:
CastCurseOfTonguesAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "curse of tongues") {}
bool isUseful() override
{
// Bypass TTL check
return CastAuraSpellAction::isUseful();
}
};
class CastCurseOfWeaknessAction : public CastDebuffSpellAction
{
public:
CastCurseOfWeaknessAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "curse of weakness") {}
bool isUseful() override
{
// Bypass TTL check
return CastAuraSpellAction::isUseful();
}
};
// Damage Spells
class CastShadowBoltAction : public CastSpellAction

View File

@@ -28,34 +28,29 @@ public:
creators["boost"] = &WarlockStrategyFactoryInternal::boost;
creators["cc"] = &WarlockStrategyFactoryInternal::cc;
creators["pet"] = &WarlockStrategyFactoryInternal::pet;
creators["spellstone"] = &WarlockStrategyFactoryInternal::spellstone;
creators["firestone"] = &WarlockStrategyFactoryInternal::firestone;
creators["affli aoe"] = &WarlockStrategyFactoryInternal::affliction_aoe;
creators["demo aoe"] = &WarlockStrategyFactoryInternal::demonology_aoe;
creators["destro aoe"] = &WarlockStrategyFactoryInternal::destruction_aoe;
creators["meta melee"] = &WarlockStrategyFactoryInternal::meta_melee_aoe;
creators["curse of elements"] = &WarlockStrategyFactoryInternal::curse_of_elements;
creators["imp"] = &WarlockStrategyFactoryInternal::imp;
creators["voidwalker"] = &WarlockStrategyFactoryInternal::voidwalker;
creators["succubus"] = &WarlockStrategyFactoryInternal::succubus;
creators["felhunter"] = &WarlockStrategyFactoryInternal::felhunter;
creators["felguard"] = &WarlockStrategyFactoryInternal::felguard;
creators["tank"] = &WarlockStrategyFactoryInternal::tank;
}
private:
static Strategy* pet(PlayerbotAI* botAI) { return new WarlockPetStrategy(botAI); }
static Strategy* nc(PlayerbotAI* botAI) { return new GenericWarlockNonCombatStrategy(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* pet(PlayerbotAI* botAI) { return new WarlockPetStrategy(botAI); }
static Strategy* spellstone(PlayerbotAI* botAI) { return new UseSpellstoneStrategy(botAI); }
static Strategy* firestone(PlayerbotAI* botAI) { return new UseFirestoneStrategy(botAI); }
static Strategy* affliction_aoe(PlayerbotAI* botAI) { return new AfflictionWarlockAoeStrategy(botAI); }
static Strategy* demonology_aoe(PlayerbotAI* botAI) { return new DemonologyWarlockAoeStrategy(botAI); }
static Strategy* destruction_aoe(PlayerbotAI* botAI) { return new DestructionWarlockAoeStrategy(botAI); }
static Strategy* meta_melee_aoe(PlayerbotAI* botAI) { return new MetaMeleeAoeStrategy(botAI); }
static Strategy* curse_of_elements(PlayerbotAI* botAI) { return new WarlockCurseOfTheElementsStrategy(botAI); }
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* tank(PlayerbotAI* botAI) { return new TankWarlockStrategy(botAI); }
};
class WarlockCombatStrategyFactoryInternal : public NamedObjectContext<Strategy>
@@ -63,28 +58,46 @@ class WarlockCombatStrategyFactoryInternal : public NamedObjectContext<Strategy>
public:
WarlockCombatStrategyFactoryInternal() : NamedObjectContext<Strategy>(false, true)
{
creators["tank"] = &WarlockCombatStrategyFactoryInternal::tank;
creators["affli"] = &WarlockCombatStrategyFactoryInternal::affliction;
creators["demo"] = &WarlockCombatStrategyFactoryInternal::demonology;
creators["destro"] = &WarlockCombatStrategyFactoryInternal::destruction;
}
private:
static Strategy* tank(PlayerbotAI* botAI) { return new TankWarlockStrategy(botAI); }
static Strategy* affliction(PlayerbotAI* botAI) { return new AfflictionWarlockStrategy(botAI); }
static Strategy* demonology(PlayerbotAI* botAI) { return new DemonologyWarlockStrategy(botAI); }
static Strategy* destruction(PlayerbotAI* botAI) { return new DestructionWarlockStrategy(botAI); }
};
class NonCombatBuffStrategyFactoryInternal : public NamedObjectContext<Strategy>
class WarlockPetStrategyFactoryInternal : public NamedObjectContext<Strategy>
{
public:
NonCombatBuffStrategyFactoryInternal() : NamedObjectContext<Strategy>(false, true)
WarlockPetStrategyFactoryInternal() : NamedObjectContext<Strategy>(false, true)
{
creators["ss self"] = &NonCombatBuffStrategyFactoryInternal::soulstone_self;
creators["ss master"] = &NonCombatBuffStrategyFactoryInternal::soulstone_master;
creators["ss tank"] = &NonCombatBuffStrategyFactoryInternal::soulstone_tank;
creators["ss healer"] = &NonCombatBuffStrategyFactoryInternal::soulstone_healer;
creators["imp"] = &WarlockPetStrategyFactoryInternal::imp;
creators["voidwalker"] = &WarlockPetStrategyFactoryInternal::voidwalker;
creators["succubus"] = &WarlockPetStrategyFactoryInternal::succubus;
creators["felhunter"] = &WarlockPetStrategyFactoryInternal::felhunter;
creators["felguard"] = &WarlockPetStrategyFactoryInternal::felguard;
}
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); }
};
class WarlockSoulstoneStrategyFactoryInternal : public NamedObjectContext<Strategy>
{
public:
WarlockSoulstoneStrategyFactoryInternal() : NamedObjectContext<Strategy>(false, true)
{
creators["ss self"] = &WarlockSoulstoneStrategyFactoryInternal::soulstone_self;
creators["ss master"] = &WarlockSoulstoneStrategyFactoryInternal::soulstone_master;
creators["ss tank"] = &WarlockSoulstoneStrategyFactoryInternal::soulstone_tank;
creators["ss healer"] = &WarlockSoulstoneStrategyFactoryInternal::soulstone_healer;
}
private:
@@ -94,6 +107,28 @@ private:
static Strategy* soulstone_healer(PlayerbotAI* ai) { return new SoulstoneHealerStrategy(ai); }
};
class WarlockCurseStrategyFactoryInternal : public NamedObjectContext<Strategy>
{
public:
WarlockCurseStrategyFactoryInternal() : NamedObjectContext<Strategy>(false, true)
{
creators["curse of agony"] = &WarlockCurseStrategyFactoryInternal::curse_of_agony;
creators["curse of elements"] = &WarlockCurseStrategyFactoryInternal::curse_of_elements;
creators["curse of doom"] = &WarlockCurseStrategyFactoryInternal::curse_of_doom;
creators["curse of exhaustion"] = &WarlockCurseStrategyFactoryInternal::curse_of_exhaustion;
creators["curse of tongues"] = &WarlockCurseStrategyFactoryInternal::curse_of_tongues;
creators["curse of weakness"] = &WarlockCurseStrategyFactoryInternal::curse_of_weakness;
}
private:
static Strategy* curse_of_agony(PlayerbotAI* botAI) { return new WarlockCurseOfAgonyStrategy(botAI); }
static Strategy* curse_of_elements(PlayerbotAI* botAI) { return new WarlockCurseOfTheElementsStrategy(botAI); }
static Strategy* curse_of_doom(PlayerbotAI* botAI) { return new WarlockCurseOfDoomStrategy(botAI); }
static Strategy* curse_of_exhaustion(PlayerbotAI* botAI) { return new WarlockCurseOfExhaustionStrategy(botAI); }
static Strategy* curse_of_tongues(PlayerbotAI* botAI) { return new WarlockCurseOfTonguesStrategy(botAI); }
static Strategy* curse_of_weakness(PlayerbotAI* botAI) { return new WarlockCurseOfWeaknessStrategy(botAI); }
};
class WarlockTriggerFactoryInternal : public NamedObjectContext<Trigger>
{
public:
@@ -102,6 +137,7 @@ public:
creators["shadow trance"] = &WarlockTriggerFactoryInternal::shadow_trance;
creators["demon armor"] = &WarlockTriggerFactoryInternal::demon_armor;
creators["soul link"] = &WarlockTriggerFactoryInternal::soul_link;
creators["no soul shard"] = &WarlockTriggerFactoryInternal::no_soul_shard;
creators["no healthstone"] = &WarlockTriggerFactoryInternal::HasHealthstone;
creators["no firestone"] = &WarlockTriggerFactoryInternal::HasFirestone;
creators["no spellstone"] = &WarlockTriggerFactoryInternal::HasSpellstone;
@@ -117,14 +153,11 @@ public:
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["immolate"] = &WarlockTriggerFactoryInternal::immolate;
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;
@@ -134,12 +167,20 @@ public:
creators["immolation aura active"] = &WarlockTriggerFactoryInternal::immolation_aura_active;
creators["metamorphosis not active"] = &WarlockTriggerFactoryInternal::metamorphosis_not_active;
creators["meta melee flee check"] = &WarlockTriggerFactoryInternal::meta_melee_flee_check;
creators["curse of agony"] = &WarlockTriggerFactoryInternal::curse_of_agony;
creators["curse of agony on attacker"] = &WarlockTriggerFactoryInternal::curse_of_agony_on_attacker;
creators["curse of the elements"] = &WarlockTriggerFactoryInternal::curse_of_the_elements;
creators["curse of doom"] = &WarlockTriggerFactoryInternal::curse_of_doom;
creators["curse of exhaustion"] = &WarlockTriggerFactoryInternal::curse_of_exhaustion;
creators["curse of tongues"] = &WarlockTriggerFactoryInternal::curse_of_tongues;
creators["curse of weakness"] = &WarlockTriggerFactoryInternal::curse_of_weakness;
}
private:
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* no_soul_shard(PlayerbotAI* botAI) { return new OutOfSoulShardsTrigger(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); }
@@ -149,8 +190,6 @@ private:
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* curse_of_agony(PlayerbotAI* botAI) { return new CurseOfAgonyTrigger(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* fear(PlayerbotAI* botAI) { return new FearTrigger(botAI); }
static Trigger* spell_lock(PlayerbotAI* botAI) { return new SpellLockInterruptSpellTrigger(botAI); }
@@ -162,7 +201,6 @@ private:
static Trigger* unstable_affliction(PlayerbotAI* ai) { return new UnstableAfflictionTrigger(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); }
@@ -172,6 +210,13 @@ private:
static Trigger* immolation_aura_active(PlayerbotAI* ai) { return new ImmolationAuraActiveTrigger(ai); }
static Trigger* metamorphosis_not_active(PlayerbotAI* ai) { return new MetamorphosisNotActiveTrigger(ai); }
static Trigger* meta_melee_flee_check(PlayerbotAI* ai) { return new MetaMeleeEnemyTooCloseForSpellTrigger(ai); }
static Trigger* curse_of_agony(PlayerbotAI* botAI) { return new CurseOfAgonyTrigger(botAI); }
static Trigger* curse_of_agony_on_attacker(PlayerbotAI* botAI) { return new CurseOfAgonyOnAttackerTrigger(botAI); }
static Trigger* curse_of_the_elements(PlayerbotAI* ai) { return new CurseOfTheElementsTrigger(ai); }
static Trigger* curse_of_doom(PlayerbotAI* ai) { return new CurseOfDoomTrigger(ai); }
static Trigger* curse_of_exhaustion(PlayerbotAI* ai) { return new CurseOfExhaustionTrigger(ai); }
static Trigger* curse_of_tongues(PlayerbotAI* ai) { return new CurseOfTonguesTrigger(ai); }
static Trigger* curse_of_weakness(PlayerbotAI* ai) { return new CurseOfWeaknessTrigger(ai); }
};
class WarlockAiObjectContextInternal : public NamedObjectContext<Action>
@@ -183,6 +228,7 @@ public:
creators["demon armor"] = &WarlockAiObjectContextInternal::demon_armor;
creators["demon skin"] = &WarlockAiObjectContextInternal::demon_skin;
creators["soul link"] = &WarlockAiObjectContextInternal::soul_link;
creators["create soul shard"] = &WarlockAiObjectContextInternal::create_soul_shard;
creators["create healthstone"] = &WarlockAiObjectContextInternal::create_healthstone;
creators["create firestone"] = &WarlockAiObjectContextInternal::create_firestone;
creators["create spellstone"] = &WarlockAiObjectContextInternal::create_spellstone;
@@ -203,8 +249,6 @@ public:
creators["immolate on attacker"] = &WarlockAiObjectContextInternal::immolate_on_attacker;
creators["corruption"] = &WarlockAiObjectContextInternal::corruption;
creators["corruption on attacker"] = &WarlockAiObjectContextInternal::corruption_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;
@@ -225,7 +269,6 @@ public:
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;
@@ -239,6 +282,13 @@ public:
creators["soulshatter"] = &WarlockAiObjectContextInternal::soulshatter;
creators["searing pain"] = WarlockAiObjectContextInternal::searing_pain;
creators["shadow ward"] = &WarlockAiObjectContextInternal::shadow_ward;
creators["curse of agony"] = &WarlockAiObjectContextInternal::curse_of_agony;
creators["curse of agony on attacker"] = &WarlockAiObjectContextInternal::curse_of_agony_on_attacker;
creators["curse of the elements"] = &WarlockAiObjectContextInternal::curse_of_the_elements;
creators["curse of doom"] = &WarlockAiObjectContextInternal::curse_of_doom;
creators["curse of exhaustion"] = &WarlockAiObjectContextInternal::curse_of_exhaustion;
creators["curse of tongues"] = &WarlockAiObjectContextInternal::curse_of_tongues;
creators["curse of weakness"] = &WarlockAiObjectContextInternal::curse_of_weakness;
}
private:
@@ -250,6 +300,7 @@ private:
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_soul_shard(PlayerbotAI* botAI) { return new CreateSoulShardAction(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); }
@@ -268,8 +319,6 @@ private:
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* curse_of_agony(PlayerbotAI* botAI) { return new CastCurseOfAgonyAction(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); }
@@ -288,7 +337,6 @@ private:
static Action* unstable_affliction(PlayerbotAI* ai) { return new CastUnstableAfflictionAction(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); }
@@ -301,13 +349,22 @@ private:
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); }
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_the_elements(PlayerbotAI* ai) { return new CastCurseOfTheElementsAction(ai); }
static Action* curse_of_doom(PlayerbotAI* ai) { return new CastCurseOfDoomAction(ai); }
static Action* curse_of_exhaustion(PlayerbotAI* ai) { return new CastCurseOfExhaustionAction(ai); }
static Action* curse_of_tongues(PlayerbotAI* ai) { return new CastCurseOfTonguesAction(ai); }
static Action* curse_of_weakness(PlayerbotAI* ai) { return new CastCurseOfWeaknessAction(ai); }
};
WarlockAiObjectContext::WarlockAiObjectContext(PlayerbotAI* botAI) : AiObjectContext(botAI)
{
strategyContexts.Add(new WarlockStrategyFactoryInternal());
strategyContexts.Add(new WarlockCombatStrategyFactoryInternal());
strategyContexts.Add(new NonCombatBuffStrategyFactoryInternal());
strategyContexts.Add(new WarlockPetStrategyFactoryInternal());
strategyContexts.Add(new WarlockSoulstoneStrategyFactoryInternal());
strategyContexts.Add(new WarlockCurseStrategyFactoryInternal());
actionContexts.Add(new WarlockAiObjectContextInternal());
triggerContexts.Add(new WarlockTriggerFactoryInternal());
}

View File

@@ -107,3 +107,29 @@ bool CurseOfTheElementsTrigger::IsActive()
// Use default BuffTrigger logic for the rest (only trigger if debuff is missing or expiring)
return BuffTrigger::IsActive();
}
// Checks if the target has a conflicting debuff that is equal to Curse of Weakness
bool CurseOfWeaknessTrigger::IsActive()
{
Unit* target = GetTarget();
if (!target || !target->IsAlive() || !target->IsInWorld())
return false;
// List of all spell IDs for Curse of Weakness, Demoralizing Roar, Demoralizing Shout, and Vindication
static const uint32 CurseOfWeaknessExclusiveDebuffs[] = {// Curse of Weakness
702, 1108, 6205, 7646, 11707, 11708, 27224, 30909, 50511,
// Demoralizing Roar
99, 1735, 9490, 9747, 9898, 26998, 48559, 48560,
// Demoralizing Shout
1160, 6190, 11554, 11555, 11556, 25202, 25203, 47437,
// Vindication
67, 26017};
// Check if target has any of the exclusive debuffs
for (uint32 spellId : CurseOfWeaknessExclusiveDebuffs)
{
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

@@ -30,6 +30,13 @@ public:
bool IsActive() override;
};
class OutOfSoulShardsTrigger : public Trigger
{
public:
OutOfSoulShardsTrigger(PlayerbotAI* botAI) : Trigger(botAI, "no soul shard") {}
bool IsActive() override { return AI_VALUE2(uint32, "item count", "soul shard") == 0; }
};
class FirestoneTrigger : public BuffTrigger
{
public:
@@ -122,33 +129,7 @@ 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();
}
};
// DoT/Curse Triggers
class CorruptionTrigger : public DebuffTrigger
{
@@ -204,11 +185,52 @@ public:
HauntTrigger(PlayerbotAI* ai) : DebuffTrigger(ai, "haunt", 1, true, 0) {}
};
class CurseOfAgonyTrigger : public DebuffTrigger
{
public:
CurseOfAgonyTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "curse of agony", 1, true, 0.5f) {}
bool IsActive() override { return BuffTrigger::IsActive(); }
};
class CurseOfAgonyOnAttackerTrigger : public DebuffOnAttackerTrigger
{
public:
CurseOfAgonyOnAttackerTrigger(PlayerbotAI* botAI) : DebuffOnAttackerTrigger(botAI, "curse of agony", true) {}
bool IsActive() override { return BuffTrigger::IsActive(); }
};
class CurseOfTheElementsTrigger : public DebuffTrigger
{
public:
CurseOfTheElementsTrigger(PlayerbotAI* botAI)
: DebuffTrigger(botAI, "curse of the elements", 1, true, 0.5f) {}
CurseOfTheElementsTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "curse of the elements", 1, true, 0.5f) {}
bool IsActive() override;
};
class CurseOfDoomTrigger : public DebuffTrigger
{
public:
CurseOfDoomTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "curse of doom", 1, true, 0.5f) {}
bool IsActive() override { return BuffTrigger::IsActive(); }
};
class CurseOfExhaustionTrigger : public DebuffTrigger
{
public:
CurseOfExhaustionTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "curse of exhaustion", 1, true, 0.5f) {}
bool IsActive() override { return BuffTrigger::IsActive(); }
};
class CurseOfTonguesTrigger : public DebuffTrigger
{
public:
CurseOfTonguesTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "curse of tongues", 1, true, 0.5f) {}
bool IsActive() override { return BuffTrigger::IsActive(); }
};
class CurseOfWeaknessTrigger : public DebuffTrigger
{
public:
CurseOfWeaknessTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "curse of weakness", 1, true, 0.5f) {}
bool IsActive() override;
};