mirror of
https://github.com/mod-playerbots/mod-playerbots
synced 2025-11-29 15:58:20 +08:00
Warlock Ranged Designation/DPS Strategy Cleanup
Hello community,
This PR focuses on 4 things:
Recognizing the Warlock as a "ranged" bot, so they will follow ranged commands and strategies, in GenericWarlockStrategy.h:
uint32 GetType() const override { return CombatStrategy::GetType() | STRATEGY_TYPE_RANGED | STRATEGY_TYPE_DPS; }
Cleanup/deletion of the DpsWarlockStrategy.cpp and .h (no longer used or referenced anywhere)
Fixes soulstone logic so multiple Warlocks don't soulstone the same target, and don't try to soulstone a target that is too far away or out of line of sight (WarlockActions.cpp)
Moved summoning of pets to the main non-combat strategy inittriggers:
// Pet-summoning triggers based on spec
if (tab == 0) // Affliction
{
triggers.push_back(new TriggerNode("no pet", NextAction::array(0, new NextAction("summon felhunter", 29.0f), nullptr)));
}
else if (tab == 1) // Demonology
{
triggers.push_back(new TriggerNode("no pet", NextAction::array(0, new NextAction("summon felguard", 29.0f), nullptr)));
}
else if (tab == 2) // Destruction
{
triggers.push_back(new TriggerNode("no pet", NextAction::array(0, new NextAction("summon imp", 29.0f), nullptr)));
}
This commit is contained in:
@@ -594,18 +594,6 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const
|
||||
nonCombatEngine->addStrategy("dps assist", false);
|
||||
break;
|
||||
case CLASS_WARLOCK:
|
||||
if (tab == WARLOCK_TAB_AFFLICATION)
|
||||
{
|
||||
nonCombatEngine->addStrategiesNoInit("felhunter", nullptr);
|
||||
}
|
||||
else if (tab == WARLOCK_TAB_DEMONOLOGY)
|
||||
{
|
||||
nonCombatEngine->addStrategiesNoInit("felguard", nullptr);
|
||||
}
|
||||
else if (tab == WARLOCK_TAB_DESTRUCTION)
|
||||
{
|
||||
nonCombatEngine->addStrategiesNoInit("imp", nullptr);
|
||||
}
|
||||
nonCombatEngine->addStrategiesNoInit("dps assist", nullptr);
|
||||
break;
|
||||
case CLASS_DEATH_KNIGHT:
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
/*
|
||||
* 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 "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["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<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", 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<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)));
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* 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_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<TriggerNode*>& 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<TriggerNode*>& triggers) override;
|
||||
std::string const getName() override { return "aoe"; }
|
||||
};
|
||||
#endif
|
||||
@@ -89,77 +89,31 @@ void GenericWarlockNonCombatStrategy::InitTriggers(std::vector<TriggerNode*>& 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
|
||||
// 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", 29.0f), NULL)));
|
||||
}
|
||||
|
||||
// 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 SummonVoidwalkerStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
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", 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)));
|
||||
// Pet-summoning triggers based on spec
|
||||
if (tab == 0) // Affliction
|
||||
{
|
||||
triggers.push_back(new TriggerNode("no pet", NextAction::array(0, new NextAction("summon felhunter", 29.0f), nullptr)));
|
||||
}
|
||||
else if (tab == 1) // Demonology
|
||||
{
|
||||
triggers.push_back(new TriggerNode("no pet", NextAction::array(0, new NextAction("summon felguard", 29.0f), nullptr)));
|
||||
}
|
||||
else if (tab == 2) // Destruction
|
||||
{
|
||||
triggers.push_back(new TriggerNode("no pet", NextAction::array(0, new NextAction("summon imp", 29.0f), nullptr)));
|
||||
}
|
||||
}
|
||||
|
||||
// Non-combat strategy for selecting themselves to receive soulstone
|
||||
|
||||
@@ -19,56 +19,6 @@ public:
|
||||
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
|
||||
};
|
||||
|
||||
class SummonImpStrategy : public NonCombatStrategy
|
||||
{
|
||||
public:
|
||||
SummonImpStrategy(PlayerbotAI* ai);
|
||||
virtual std::string const getName() override { return "imp"; }
|
||||
|
||||
public:
|
||||
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
|
||||
};
|
||||
|
||||
class SummonVoidwalkerStrategy : public NonCombatStrategy
|
||||
{
|
||||
public:
|
||||
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;
|
||||
};
|
||||
|
||||
class SummonFelhunterStrategy : public NonCombatStrategy
|
||||
{
|
||||
public:
|
||||
SummonFelhunterStrategy(PlayerbotAI* ai);
|
||||
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:
|
||||
|
||||
@@ -18,6 +18,7 @@ public:
|
||||
std::string const getName() override { return "warlock"; }
|
||||
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
|
||||
NextAction** getDefaultActions() override;
|
||||
uint32 GetType() const override { return CombatStrategy::GetType() | STRATEGY_TYPE_RANGED | STRATEGY_TYPE_DPS; }
|
||||
};
|
||||
|
||||
class WarlockBoostStrategy : public Strategy
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
#include "Playerbots.h"
|
||||
#include "ServerFacade.h"
|
||||
#include "Unit.h"
|
||||
#include "Timer.h"
|
||||
#include <unordered_map>
|
||||
#include <mutex>
|
||||
|
||||
// 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<ObjectGuid, uint32> soulstoneReservations;
|
||||
static std::mutex soulstoneReservationsMutex;
|
||||
|
||||
// Helper to clean up expired reservations
|
||||
void CleanupSoulstoneReservations()
|
||||
{
|
||||
uint32 now = getMSTime();
|
||||
std::lock_guard<std::mutex> 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<Item*> items = AI_VALUE2(std::vector<Item*>, "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<std::mutex> 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<Item*> items = AI_VALUE2(std::vector<Item*>, "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<std::mutex> 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<std::mutex> 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<Item*> items = AI_VALUE2(std::vector<Item*>, "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<std::mutex> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,15 +28,10 @@ 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;
|
||||
}
|
||||
|
||||
@@ -47,15 +41,10 @@ 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); }
|
||||
};
|
||||
|
||||
@@ -65,10 +54,16 @@ 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>
|
||||
@@ -76,11 +71,6 @@ class NonCombatBuffStrategyFactoryInternal : public NamedObjectContext<Strategy>
|
||||
public:
|
||||
NonCombatBuffStrategyFactoryInternal() : NamedObjectContext<Strategy>(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 +78,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); }
|
||||
|
||||
Reference in New Issue
Block a user