mirror of
https://github.com/mod-playerbots/mod-playerbots
synced 2025-11-29 15:58:20 +08:00
Warlock overhaul (#1397)
This is a complete overhaul of the warlock class, making 3 new strategies (affliction, demonology, and destruction), as well as finishing the warlock tank strategy (shadow ward and searing pain). It also includes a soulstone fix, where the bots can change who they soulstone based on the non-combat strategies you set for them. It also includes a self-resurrect action and trigger that allows the bots to resurrect using a soulstone or reincarnation. Many other skills were added to finish out the warlock skillset.
This commit is contained in:
@@ -5,23 +5,204 @@
|
||||
|
||||
#include "WarlockActions.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "Event.h"
|
||||
#include "Item.h"
|
||||
#include "ObjectGuid.h"
|
||||
#include "Player.h"
|
||||
#include "PlayerbotAI.h"
|
||||
#include "Playerbots.h"
|
||||
#include "ServerFacade.h"
|
||||
#include "Unit.h"
|
||||
|
||||
bool CastDrainSoulAction::isUseful() { return AI_VALUE2(uint32, "item count", "soul shard") < 10; }
|
||||
|
||||
Value<Unit*>* CastBanishAction::GetTargetValue() { return context->GetValue<Unit*>("cc target", "banish"); }
|
||||
|
||||
bool CastBanishAction::Execute(Event event) { return botAI->CastSpell("banish", GetTarget()); }
|
||||
|
||||
Value<Unit*>* CastFearOnCcAction::GetTargetValue() { return context->GetValue<Unit*>("cc target", "fear"); }
|
||||
|
||||
bool CastFearOnCcAction::Execute(Event event) { return botAI->CastSpell("fear", GetTarget()); }
|
||||
|
||||
bool CastFearOnCcAction::isPossible() { return true; }
|
||||
|
||||
bool CastFearOnCcAction::isUseful() { return true; }
|
||||
// Checks if the bot has less than 32 soul shards, and if so, allows casting Drain Soul
|
||||
bool CastDrainSoulAction::isUseful() { return AI_VALUE2(uint32, "item count", "soul shard") < 32; }
|
||||
|
||||
// Checks if the bot's health is above a certain threshold, and if so, allows casting Life Tap
|
||||
bool CastLifeTapAction::isUseful() { return AI_VALUE2(uint8, "health", "self target") > sPlayerbotAIConfig->lowHealth; }
|
||||
|
||||
Unit* UseSoulstoneAction::GetTarget() { return botAI->GetMaster(); }
|
||||
// Checks if the target marked with the moon icon can be banished
|
||||
bool CastBanishOnCcAction::isPossible()
|
||||
{
|
||||
Unit* target = GetTarget();
|
||||
if (!target)
|
||||
return false;
|
||||
|
||||
// Only possible on elementals or demons
|
||||
uint32 creatureType = target->GetCreatureType();
|
||||
if (creatureType != CREATURE_TYPE_DEMON && creatureType != CREATURE_TYPE_ELEMENTAL)
|
||||
return false;
|
||||
|
||||
// Use base class to check spell available, range, etc
|
||||
return CastCrowdControlSpellAction::isPossible();
|
||||
}
|
||||
|
||||
// Checks if the target marked with the moon icon can be feared
|
||||
bool CastFearOnCcAction::isPossible()
|
||||
{
|
||||
Unit* target = GetTarget();
|
||||
if (!target)
|
||||
return false;
|
||||
|
||||
// Fear cannot be cast on mechanical or undead creatures
|
||||
uint32 creatureType = target->GetCreatureType();
|
||||
if (creatureType == CREATURE_TYPE_MECHANICAL || creatureType == CREATURE_TYPE_UNDEAD)
|
||||
return false;
|
||||
|
||||
// Use base class to check spell available, range, etc
|
||||
return CastCrowdControlSpellAction::isPossible();
|
||||
}
|
||||
|
||||
// Checks if the enemies are close enough to use Shadowflame
|
||||
bool CastShadowflameAction::isUseful()
|
||||
{
|
||||
Unit* target = AI_VALUE(Unit*, "current target");
|
||||
if (!target)
|
||||
return false;
|
||||
bool facingTarget = AI_VALUE2(bool, "facing", "current target");
|
||||
bool targetClose = bot->IsWithinCombatRange(target, 7.0f); // 7 yard cone
|
||||
return facingTarget && targetClose;
|
||||
}
|
||||
|
||||
// Checks if the bot knows Seed of Corruption, and prevents the use of Rain of Fire if it does
|
||||
bool CastRainOfFireAction::isUseful()
|
||||
{
|
||||
Unit* target = GetTarget();
|
||||
if (!target)
|
||||
return false;
|
||||
if (bot->HasSpell(27243) || bot->HasSpell(47835) || bot->HasSpell(47836)) // Seed of Corruption spell IDs
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Checks if the enemies are close enough to use Hellfire
|
||||
bool CastHellfireAction::isUseful()
|
||||
{
|
||||
Unit* target = AI_VALUE(Unit*, "current target");
|
||||
if (!target)
|
||||
return false;
|
||||
|
||||
return bot->IsWithinCombatRange(target, 5.0f); // 5 yard AoE radius
|
||||
}
|
||||
|
||||
// Checks if the "meta melee aoe" strategy is active, OR if the bot is in melee range of the target
|
||||
bool CastImmolationAuraAction::isUseful()
|
||||
{
|
||||
if (botAI->HasStrategy("meta melee", BOT_STATE_COMBAT))
|
||||
return true;
|
||||
|
||||
Unit* target = AI_VALUE(Unit*, "current target");
|
||||
if (!target)
|
||||
return false;
|
||||
|
||||
if (!bot->HasAura(47241)) // 47241 is Metamorphosis spell ID (WotLK)
|
||||
return false;
|
||||
|
||||
return bot->IsWithinCombatRange(target, 5.0f); // 5 yard AoE radius
|
||||
}
|
||||
|
||||
// Checks if the "warlock tank" strategy is active, and if so, prevents the use of Soulshatter
|
||||
bool CastSoulshatterAction::isUseful()
|
||||
{
|
||||
if (botAI->HasStrategy("tank", BOT_STATE_COMBAT))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Checks if the target has a soulstone aura
|
||||
static bool HasSoulstoneAura(Unit* unit)
|
||||
{
|
||||
static const std::vector<uint32> soulstoneAuraIds = {20707, 20762, 20763, 20764, 20765, 27239, 47883};
|
||||
for (uint32 spellId : soulstoneAuraIds)
|
||||
if (unit->HasAura(spellId))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Use the soulstone item on the bot itself with nc strategy "ss self"
|
||||
bool UseSoulstoneSelfAction::Execute(Event event)
|
||||
{
|
||||
std::vector<Item*> items = AI_VALUE2(std::vector<Item*>, "inventory items", "soulstone");
|
||||
if (items.empty())
|
||||
return false;
|
||||
|
||||
if (HasSoulstoneAura(bot))
|
||||
return false;
|
||||
|
||||
bot->SetSelection(bot->GetGUID());
|
||||
return UseItem(items[0], ObjectGuid::Empty, nullptr, bot);
|
||||
}
|
||||
|
||||
// Use the soulstone item on the bot's master with nc strategy "ss master"
|
||||
bool UseSoulstoneMasterAction::Execute(Event event)
|
||||
{
|
||||
std::vector<Item*> items = AI_VALUE2(std::vector<Item*>, "inventory items", "soulstone");
|
||||
if (items.empty())
|
||||
return false;
|
||||
|
||||
Player* master = botAI->GetMaster();
|
||||
if (!master || HasSoulstoneAura(master))
|
||||
return false;
|
||||
|
||||
bot->SetSelection(master->GetGUID());
|
||||
return UseItem(items[0], ObjectGuid::Empty, nullptr, master);
|
||||
}
|
||||
|
||||
// Use the soulstone item on a tank in the group with nc strategy "ss tank"
|
||||
bool UseSoulstoneTankAction::Execute(Event event)
|
||||
{
|
||||
std::vector<Item*> items = AI_VALUE2(std::vector<Item*>, "inventory items", "soulstone");
|
||||
if (items.empty())
|
||||
return false;
|
||||
|
||||
Player* tank = nullptr;
|
||||
Group* group = bot->GetGroup();
|
||||
if (group)
|
||||
{
|
||||
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
|
||||
{
|
||||
Player* member = gref->GetSource();
|
||||
if (member && member->IsAlive() && botAI->IsTank(member) && !HasSoulstoneAura(member))
|
||||
{
|
||||
tank = member;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!tank)
|
||||
return false;
|
||||
|
||||
bot->SetSelection(tank->GetGUID());
|
||||
return UseItem(items[0], ObjectGuid::Empty, nullptr, tank);
|
||||
}
|
||||
|
||||
// Use the soulstone item on a healer in the group with nc strategy "ss healer"
|
||||
bool UseSoulstoneHealerAction::Execute(Event event)
|
||||
{
|
||||
std::vector<Item*> items = AI_VALUE2(std::vector<Item*>, "inventory items", "soulstone");
|
||||
if (items.empty())
|
||||
return false;
|
||||
|
||||
Player* healer = nullptr;
|
||||
Group* group = bot->GetGroup();
|
||||
if (group)
|
||||
{
|
||||
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
|
||||
{
|
||||
Player* member = gref->GetSource();
|
||||
if (member && member->IsAlive() && botAI->IsHeal(member) && !HasSoulstoneAura(member))
|
||||
{
|
||||
healer = member;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!healer)
|
||||
return false;
|
||||
|
||||
bot->SetSelection(healer->GetGUID());
|
||||
return UseItem(items[0], ObjectGuid::Empty, nullptr, healer);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user