diff --git a/src/strategy/warlock/AfflictionWarlockStrategy.cpp b/src/strategy/warlock/AfflictionWarlockStrategy.cpp index eaeef3be..968bb445 100644 --- a/src/strategy/warlock/AfflictionWarlockStrategy.cpp +++ b/src/strategy/warlock/AfflictionWarlockStrategy.cpp @@ -84,6 +84,8 @@ void AfflictionWarlockStrategy::InitTriggers(std::vector& triggers // 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))); + + triggers.push_back(new TriggerNode("enemy too close for spell", NextAction::array(0, new NextAction("flee", 39.0f), nullptr))); } // ===== AoE Strategy, 3+ enemies ===== diff --git a/src/strategy/warlock/DemonologyWarlockStrategy.cpp b/src/strategy/warlock/DemonologyWarlockStrategy.cpp index 2cfdfac7..1062d015 100644 --- a/src/strategy/warlock/DemonologyWarlockStrategy.cpp +++ b/src/strategy/warlock/DemonologyWarlockStrategy.cpp @@ -30,7 +30,6 @@ public: 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: @@ -52,7 +51,6 @@ private: 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 ===== @@ -97,6 +95,8 @@ void DemonologyWarlockStrategy::InitTriggers(std::vector& triggers // 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))); + + triggers.push_back(new TriggerNode("meta melee flee check", NextAction::array(0, new NextAction("flee", 39.0f), nullptr))); } // ===== AoE Strategy, 3+ enemies ===== @@ -122,6 +122,5 @@ void MetaMeleeAoeStrategy::InitTriggers(std::vector& 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))); + new NextAction("demon charge", 25.0f), nullptr))); } diff --git a/src/strategy/warlock/DestructionWarlockStrategy.cpp b/src/strategy/warlock/DestructionWarlockStrategy.cpp index 42498bde..2ecc6467 100644 --- a/src/strategy/warlock/DestructionWarlockStrategy.cpp +++ b/src/strategy/warlock/DestructionWarlockStrategy.cpp @@ -91,6 +91,8 @@ void DestructionWarlockStrategy::InitTriggers(std::vector& trigger // 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))); + + triggers.push_back(new TriggerNode("enemy too close for spell", NextAction::array(0, new NextAction("flee", 39.0f), nullptr))); } // ===== AoE Strategy, 3+ enemies ===== diff --git a/src/strategy/warlock/DpsWarlockStrategy.cpp b/src/strategy/warlock/DpsWarlockStrategy.cpp deleted file mode 100644 index 49b6a2be..00000000 --- a/src/strategy/warlock/DpsWarlockStrategy.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2016+ AzerothCore , 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 "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 -{ -public: - DpsWarlockStrategyActionNodeFactory() - { - creators["corruption"] = &corruption; - creators["curse of agony"] = &curse_of_agony; - creators["immolate"] = &immolate; - creators["shadow bolt"] = &shadow_bolt; - 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* 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("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& 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", 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))); - - // 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))); -} - -// ===== AoE Strategy, 3+ enemies ===== -void DpsAoeWarlockStrategy::InitTriggers(std::vector& 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))); -} diff --git a/src/strategy/warlock/DpsWarlockStrategy.h b/src/strategy/warlock/DpsWarlockStrategy.h deleted file mode 100644 index 4ae63930..00000000 --- a/src/strategy/warlock/DpsWarlockStrategy.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2016+ AzerothCore , 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_DPSWARLOCKSTRATEGY_H -#define _PLAYERBOT_DPSWARLOCKSTRATEGY_H - -#include "GenericWarlockStrategy.h" -#include "Strategy.h" - -class PlayerbotAI; - -class DpsWarlockStrategy : public GenericWarlockStrategy -{ -public: - DpsWarlockStrategy(PlayerbotAI* botAI); - - std::string const getName() override { return "dps"; } - void InitTriggers(std::vector& triggers) override; - NextAction** getDefaultActions() override; - uint32 GetType() const override { return GenericWarlockStrategy::GetType() | STRATEGY_TYPE_DPS; } -}; - -class DpsAoeWarlockStrategy : public CombatStrategy -{ -public: - DpsAoeWarlockStrategy(PlayerbotAI* botAI) : CombatStrategy(botAI) {} - - void InitTriggers(std::vector& triggers) override; - std::string const getName() override { return "aoe"; } -}; -#endif diff --git a/src/strategy/warlock/GenericWarlockNonCombatStrategy.cpp b/src/strategy/warlock/GenericWarlockNonCombatStrategy.cpp index f575750b..f99c06c5 100644 --- a/src/strategy/warlock/GenericWarlockNonCombatStrategy.cpp +++ b/src/strategy/warlock/GenericWarlockNonCombatStrategy.cpp @@ -89,20 +89,18 @@ void GenericWarlockNonCombatStrategy::InitTriggers(std::vector& tr 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))); + 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))); + 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 @@ -124,8 +122,7 @@ SummonVoidwalkerStrategy::SummonVoidwalkerStrategy(PlayerbotAI* ai) : NonCombatS void SummonVoidwalkerStrategy::InitTriggers(std::vector& triggers) { - triggers.push_back( - new TriggerNode("no pet", NextAction::array(0, new NextAction("summon voidwalker", 29.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 @@ -147,8 +144,7 @@ SummonFelhunterStrategy::SummonFelhunterStrategy(PlayerbotAI* ai) : NonCombatStr void SummonFelhunterStrategy::InitTriggers(std::vector& triggers) { - triggers.push_back( - new TriggerNode("no pet", NextAction::array(0, new NextAction("summon felhunter", 29.0f), NULL))); + triggers.push_back(new TriggerNode("no pet", NextAction::array(0, new NextAction("summon felhunter", 29.0f), NULL))); } // Non-combat strategy for summoning a Felguard diff --git a/src/strategy/warlock/GenericWarlockStrategy.h b/src/strategy/warlock/GenericWarlockStrategy.h index 23fa739b..6b134b60 100644 --- a/src/strategy/warlock/GenericWarlockStrategy.h +++ b/src/strategy/warlock/GenericWarlockStrategy.h @@ -18,6 +18,7 @@ public: std::string const getName() override { return "warlock"; } void InitTriggers(std::vector& triggers) override; NextAction** getDefaultActions() override; + uint32 GetType() const override { return CombatStrategy::GetType() | STRATEGY_TYPE_RANGED | STRATEGY_TYPE_DPS; } }; class WarlockBoostStrategy : public Strategy diff --git a/src/strategy/warlock/WarlockActions.cpp b/src/strategy/warlock/WarlockActions.cpp index 8b362cd6..3bb1724b 100644 --- a/src/strategy/warlock/WarlockActions.cpp +++ b/src/strategy/warlock/WarlockActions.cpp @@ -15,6 +15,9 @@ #include "Playerbots.h" #include "ServerFacade.h" #include "Unit.h" +#include "Timer.h" +#include +#include // 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; } @@ -134,9 +137,29 @@ bool UseSoulstoneSelfAction::Execute(Event event) return UseItem(items[0], ObjectGuid::Empty, nullptr, bot); } +// Reservation map for soulstone targets (GUID -> reservation expiry in ms) +static std::unordered_map soulstoneReservations; +static std::mutex soulstoneReservationsMutex; + +// Helper to clean up expired reservations +void CleanupSoulstoneReservations() +{ + uint32 now = getMSTime(); + std::lock_guard lock(soulstoneReservationsMutex); + for (auto it = soulstoneReservations.begin(); it != soulstoneReservations.end();) + { + if (it->second <= now) + it = soulstoneReservations.erase(it); + else + ++it; + } +} + // Use the soulstone item on the bot's master with nc strategy "ss master" bool UseSoulstoneMasterAction::Execute(Event event) { + CleanupSoulstoneReservations(); + std::vector items = AI_VALUE2(std::vector, "inventory items", "soulstone"); if (items.empty()) return false; @@ -145,6 +168,23 @@ bool UseSoulstoneMasterAction::Execute(Event event) if (!master || HasSoulstoneAura(master)) return false; + uint32 now = getMSTime(); + + { + std::lock_guard lock(soulstoneReservationsMutex); + if (soulstoneReservations.count(master->GetGUID()) && soulstoneReservations[master->GetGUID()] > now) + return false; // Already being soulstoned + + soulstoneReservations[master->GetGUID()] = now + 2500; // Reserve for 2.5 seconds + } + + float distance = sServerFacade->GetDistance2d(bot, master); + if (distance >= 30.0f) + return false; + + if (!bot->IsWithinLOSInMap(master)) + return false; + bot->SetSelection(master->GetGUID()); return UseItem(items[0], ObjectGuid::Empty, nullptr, master); } @@ -152,41 +192,83 @@ bool UseSoulstoneMasterAction::Execute(Event event) // Use the soulstone item on a tank in the group with nc strategy "ss tank" bool UseSoulstoneTankAction::Execute(Event event) { + CleanupSoulstoneReservations(); + std::vector items = AI_VALUE2(std::vector, "inventory items", "soulstone"); if (items.empty()) return false; - Player* tank = nullptr; + Player* chosenTank = nullptr; Group* group = bot->GetGroup(); + uint32 now = getMSTime(); + + // First: Try to soulstone the main tank if (group) { for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next()) { Player* member = gref->GetSource(); - if (member && member->IsAlive() && botAI->IsTank(member) && !HasSoulstoneAura(member)) + if (member && member->IsAlive() && botAI->IsTank(member) && botAI->IsMainTank(member) && + !HasSoulstoneAura(member)) { - tank = member; - break; + std::lock_guard lock(soulstoneReservationsMutex); + if (soulstoneReservations.count(member->GetGUID()) && soulstoneReservations[member->GetGUID()] > now) + continue; // Already being soulstoned + + float distance = sServerFacade->GetDistance2d(bot, member); + if (distance < 30.0f && bot->IsWithinLOSInMap(member)) + { + chosenTank = member; + soulstoneReservations[chosenTank->GetGUID()] = now + 2500; // Reserve for 2.5 seconds + break; + } + } + } + + // If no main tank found, soulstone another tank + if (!chosenTank) + { + for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next()) + { + Player* member = gref->GetSource(); + if (member && member->IsAlive() && botAI->IsTank(member) && !HasSoulstoneAura(member)) + { + std::lock_guard lock(soulstoneReservationsMutex); + if (soulstoneReservations.count(member->GetGUID()) && + soulstoneReservations[member->GetGUID()] > now) + continue; // Already being soulstoned + + float distance = sServerFacade->GetDistance2d(bot, member); + if (distance < 30.0f && bot->IsWithinLOSInMap(member)) + { + chosenTank = member; + soulstoneReservations[chosenTank->GetGUID()] = now + 2500; // Reserve for 2.5 seconds + break; + } + } } } } - if (!tank) + if (!chosenTank) return false; - bot->SetSelection(tank->GetGUID()); - return UseItem(items[0], ObjectGuid::Empty, nullptr, tank); + bot->SetSelection(chosenTank->GetGUID()); + return UseItem(items[0], ObjectGuid::Empty, nullptr, chosenTank); } // Use the soulstone item on a healer in the group with nc strategy "ss healer" bool UseSoulstoneHealerAction::Execute(Event event) { + CleanupSoulstoneReservations(); + std::vector items = AI_VALUE2(std::vector, "inventory items", "soulstone"); if (items.empty()) return false; Player* healer = nullptr; Group* group = bot->GetGroup(); + uint32 now = getMSTime(); if (group) { for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next()) @@ -194,8 +276,20 @@ bool UseSoulstoneHealerAction::Execute(Event event) Player* member = gref->GetSource(); if (member && member->IsAlive() && botAI->IsHeal(member) && !HasSoulstoneAura(member)) { - healer = member; - break; + { + std::lock_guard lock(soulstoneReservationsMutex); + if (soulstoneReservations.count(member->GetGUID()) && + soulstoneReservations[member->GetGUID()] > now) + continue; // Already being soulstoned + + float distance = sServerFacade->GetDistance2d(bot, member); + if (distance < 30.0f && bot->IsWithinLOSInMap(member)) + { + healer = member; + soulstoneReservations[healer->GetGUID()] = now + 2500; // Reserve for 2.5 seconds + break; + } + } } } } diff --git a/src/strategy/warlock/WarlockAiObjectContext.cpp b/src/strategy/warlock/WarlockAiObjectContext.cpp index e3dc6ca9..cd56398a 100644 --- a/src/strategy/warlock/WarlockAiObjectContext.cpp +++ b/src/strategy/warlock/WarlockAiObjectContext.cpp @@ -8,7 +8,6 @@ #include "DemonologyWarlockStrategy.h" #include "DestructionWarlockStrategy.h" #include "TankWarlockStrategy.h" -#include "DpsWarlockStrategy.h" #include "GenericTriggers.h" #include "GenericWarlockNonCombatStrategy.h" #include "NamedObjectContext.h" @@ -29,16 +28,16 @@ public: 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; + creators["imp"] = &WarlockStrategyFactoryInternal::imp; + creators["voidwalker"] = &WarlockStrategyFactoryInternal::voidwalker; + creators["succubus"] = &WarlockStrategyFactoryInternal::succubus; + creators["felhunter"] = &WarlockStrategyFactoryInternal::felhunter; + creators["felguard"] = &WarlockStrategyFactoryInternal::felguard; } private: @@ -47,16 +46,16 @@ private: 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); } + 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 WarlockCombatStrategyFactoryInternal : public NamedObjectContext @@ -65,10 +64,16 @@ public: WarlockCombatStrategyFactoryInternal() : NamedObjectContext(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 @@ -76,11 +81,6 @@ class NonCombatBuffStrategyFactoryInternal : public NamedObjectContext public: NonCombatBuffStrategyFactoryInternal() : NamedObjectContext(false, true) { - 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; @@ -88,11 +88,6 @@ public: } 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); } @@ -137,6 +132,8 @@ public: creators["metamorphosis"] = &WarlockTriggerFactoryInternal::metamorphosis; creators["demonic empowerment"] = &WarlockTriggerFactoryInternal::demonic_empowerment; 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; } private: @@ -173,6 +170,8 @@ private: 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); } + static Trigger* metamorphosis_not_active(PlayerbotAI* ai) { return new MetamorphosisNotActiveTrigger(ai); } + static Trigger* meta_melee_flee_check(PlayerbotAI* ai) { return new MetaMeleeEnemyTooCloseForSpellTrigger(ai); } }; class WarlockAiObjectContextInternal : public NamedObjectContext diff --git a/src/strategy/warlock/WarlockTriggers.h b/src/strategy/warlock/WarlockTriggers.h index da12c697..40f72e6a 100644 --- a/src/strategy/warlock/WarlockTriggers.h +++ b/src/strategy/warlock/WarlockTriggers.h @@ -271,4 +271,18 @@ class MoltenCoreTrigger : public HasAuraTrigger public: MoltenCoreTrigger(PlayerbotAI* ai) : HasAuraTrigger(ai, "molten core") {} }; + +class MetamorphosisNotActiveTrigger : public HasNoAuraTrigger +{ +public: + MetamorphosisNotActiveTrigger(PlayerbotAI* ai) : HasNoAuraTrigger(ai, "metamorphosis") {} +}; + +class MetaMeleeEnemyTooCloseForSpellTrigger : public TwoTriggers +{ +public: + MetaMeleeEnemyTooCloseForSpellTrigger(PlayerbotAI* ai) + : TwoTriggers(ai, "enemy too close for spell", "metamorphosis not active") {} +}; + #endif