mirror of
https://github.com/mod-playerbots/mod-playerbots
synced 2025-11-29 15:58:20 +08:00
This PR aims to achieve 4 main things: 1. Manual Curse Strategies - Each curse has it's own toggleable combat strategy, with curse of agony being the default for affliction and demonology, and curse of the elements being default for destro. The other curses that are available are curse of exhaustion (if specced for it), curse of doom, curse of weakness, and curse of tongues (6 total). You can add these by typing "co +curse of weakness", or similar. Note: Curses are part of the WarlockCurseStrategyFactoryInternal(), so there can only be one active. 2. Firestone/Spellstone Non-Combat Strategies - Players requested to me that they can decide if they want to use a spellstone or firestone for their weapon enchant, so I added them as non-combat strategies. Spellstone is the default for affliction and demonology, firestone is the default for destro. To add these, type "nc +firestone" or similar. 3. Soul Shard Replenishment - I noticed after hours of running a server (15+ hours) that altbots and rndbots would only cast imp and not use their soul shards. This is because they were actually running out of soul shards, without the ability to maintain themselves accordingly. I added a trigger (no soul shard) and action (create soul shard) that triggers if they are out of soul shards, creating only 1 soul shard (to not clog up the inventory). This way, you should never have a warlock using the wrong pet, or failing to cast shadowburn, failing to create soulstone/spellstone/firestone/healthstone, or failing to cast soul shatter. 4. Tidying up the code - I removed the built-in curse code from the DPS strategies, and migrated it to the manual curse strategies. I clumped the curse triggers and actions together in the associated files. I added logic for Curse of Weakness to check for conflicting debuffs. I moved the summoning strategies and curse strategies to their own strategy factories - WarlockPetStrategyFactoryInternal, and WarlockCurseStrategyFactoryInternal. This way they can only have one curse and one pet strategy active at once. I also renamed the "NonCombatBuffStrategyFactoryInternal" to "WarlockSoulstoneStrategyFactoryInternal", which was more accurate. I changed a single talent point in the Affliction Warlock PVE spec, taking one from destructive reach and adding it into nightfall for those sweet, sweet free shadowbolts. I added "ss self" as the default non-combat soulstone strategy, as before, they didn't have one assigned. The player can still of course remove that NC strategy and apply another, such as "ss master", "ss tank", or "ss healer".
95 lines
5.4 KiB
C++
95 lines
5.4 KiB
C++
/*
|
|
* 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["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* 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.5f),
|
|
new NextAction("unstable affliction", 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("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("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.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)));
|
|
}
|
|
|
|
// ===== 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)));
|
|
}
|