mirror of
https://github.com/mod-playerbots/mod-playerbots
synced 2025-11-29 15:58:20 +08:00
Merge pull request #880 from liyunfan1223/improve_dps
Improve DPS rotation
This commit is contained in:
@@ -2928,7 +2928,10 @@ bool PlayerbotAI::CanCastSpell(uint32 spellid, Unit* target, bool checkHasSpell,
|
||||
}
|
||||
|
||||
Unit* oldSel = bot->GetSelectedUnit();
|
||||
Spell* spell = new Spell(bot, spellInfo, TRIGGERED_NONE);
|
||||
// TRIGGERED_IGNORE_POWER_AND_REAGENT_COST flag for not calling CheckPower in check
|
||||
// which avoids buff charge to be ineffectively reduced (e.g. dk freezing fog for howling blast)
|
||||
/// @TODO: Fix all calls to ApplySpellMod
|
||||
Spell* spell = new Spell(bot, spellInfo, TRIGGERED_IGNORE_POWER_AND_REAGENT_COST);
|
||||
|
||||
spell->m_targets.SetUnitTarget(target);
|
||||
spell->m_CastItem = castItem;
|
||||
@@ -2938,7 +2941,6 @@ bool PlayerbotAI::CanCastSpell(uint32 spellid, Unit* target, bool checkHasSpell,
|
||||
;
|
||||
}
|
||||
spell->m_targets.SetItemTarget(itemTarget);
|
||||
|
||||
SpellCastResult result = spell->CheckCast(true);
|
||||
delete spell;
|
||||
|
||||
|
||||
@@ -511,6 +511,7 @@ bool PlayerbotAIConfig::Initialize()
|
||||
autoTrainSpells = sConfigMgr->GetOption<std::string>("AiPlayerbot.AutoTrainSpells", "yes");
|
||||
autoPickTalents = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoPickTalents", true);
|
||||
autoUpgradeEquip = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoUpgradeEquip", false);
|
||||
hunterWolfPet = sConfigMgr->GetOption<int32>("AiPlayerbot.HunterWolfPet", 0);
|
||||
autoLearnTrainerSpells = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoLearnTrainerSpells", true);
|
||||
autoLearnQuestSpells = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoLearnQuestSpells", false);
|
||||
autoTeleportForLevel = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoTeleportForLevel", false);
|
||||
|
||||
@@ -289,6 +289,7 @@ public:
|
||||
std::string autoTrainSpells;
|
||||
bool autoPickTalents;
|
||||
bool autoUpgradeEquip;
|
||||
int32 hunterWolfPet;
|
||||
bool autoLearnTrainerSpells;
|
||||
bool autoDoQuests;
|
||||
bool enableNewRpgStrategy;
|
||||
|
||||
@@ -484,10 +484,11 @@ void PlayerbotHolder::OnBotLogin(Player* const bot)
|
||||
|
||||
if (!groupValid)
|
||||
{
|
||||
WorldPacket p;
|
||||
std::string const member = bot->GetName();
|
||||
p << uint32(PARTY_OP_LEAVE) << member << uint32(0);
|
||||
bot->GetSession()->HandleGroupDisbandOpcode(p);
|
||||
bot->RemoveFromGroup();
|
||||
// WorldPacket p;
|
||||
// std::string const member = bot->GetName();
|
||||
// p << uint32(PARTY_OP_LEAVE) << member << uint32(0);
|
||||
// bot->GetSession()->HandleGroupDisbandOpcode(p);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "SharedDefines.h"
|
||||
#include "SpellAuraDefines.h"
|
||||
#include "StatsWeightCalculator.h"
|
||||
#include "World.h"
|
||||
|
||||
#define PLAYER_SKILL_INDEX(x) (PLAYER_SKILL_INFO_1_1 + ((x)*3))
|
||||
|
||||
@@ -786,6 +787,13 @@ void PlayerbotFactory::InitPet()
|
||||
if (itr->second.minlevel > bot->GetLevel())
|
||||
continue;
|
||||
|
||||
bool onlyWolf = sPlayerbotAIConfig->hunterWolfPet == 2 ||
|
||||
(sPlayerbotAIConfig->hunterWolfPet == 1 &&
|
||||
bot->GetLevel() >= sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL));
|
||||
// Wolf only (for higher dps)
|
||||
if (onlyWolf && itr->second.family != CREATURE_FAMILY_WOLF)
|
||||
continue;
|
||||
|
||||
ids.push_back(itr->first);
|
||||
}
|
||||
|
||||
@@ -2807,11 +2815,11 @@ void PlayerbotFactory::InitAmmo()
|
||||
|
||||
uint32 entry = sRandomItemMgr->GetAmmo(level, subClass);
|
||||
uint32 count = bot->GetItemCount(entry);
|
||||
uint32 maxCount = 6000;
|
||||
uint32 maxCount = bot->getClass() == CLASS_HUNTER ? 6000 : 1000;
|
||||
|
||||
if (count < maxCount / 2)
|
||||
if (count < maxCount)
|
||||
{
|
||||
if (Item* newItem = StoreNewItemInInventorySlot(bot, entry, maxCount / 2))
|
||||
if (Item* newItem = StoreNewItemInInventorySlot(bot, entry, maxCount - count))
|
||||
{
|
||||
newItem->AddToUpdateQueueOf(bot);
|
||||
}
|
||||
|
||||
@@ -84,9 +84,7 @@ bool LeaveGroupAction::Leave(Player* player)
|
||||
bool shouldStay = randomBot && bot->GetGroup() && player == bot;
|
||||
if (!shouldStay)
|
||||
{
|
||||
WorldPacket p;
|
||||
p << uint32(PARTY_OP_LEAVE) << bot->GetName() << uint32(0);
|
||||
bot->GetSession()->HandleGroupDisbandOpcode(p);
|
||||
bot->RemoveFromGroup();
|
||||
}
|
||||
|
||||
if (randomBot)
|
||||
|
||||
@@ -74,14 +74,14 @@ public:
|
||||
creators["plague strike"] = &DeathKnightTriggerFactoryInternal::plague_strike;
|
||||
creators["plague strike on attacker"] = &DeathKnightTriggerFactoryInternal::plague_strike_on_attacker;
|
||||
creators["icy touch"] = &DeathKnightTriggerFactoryInternal::icy_touch;
|
||||
creators["icy touch 8s"] = &DeathKnightTriggerFactoryInternal::icy_touch_8s;
|
||||
creators["dd cd and icy touch 8s"] = &DeathKnightTriggerFactoryInternal::dd_cd_and_icy_touch_8s;
|
||||
creators["icy touch 3s"] = &DeathKnightTriggerFactoryInternal::icy_touch_3s;
|
||||
creators["dd cd and icy touch 3s"] = &DeathKnightTriggerFactoryInternal::dd_cd_and_icy_touch_3s;
|
||||
creators["death coil"] = &DeathKnightTriggerFactoryInternal::death_coil;
|
||||
creators["icy touch on attacker"] = &DeathKnightTriggerFactoryInternal::icy_touch_on_attacker;
|
||||
creators["improved icy talons"] = &DeathKnightTriggerFactoryInternal::improved_icy_talons;
|
||||
creators["plague strike"] = &DeathKnightTriggerFactoryInternal::plague_strike;
|
||||
creators["plague strike 8s"] = &DeathKnightTriggerFactoryInternal::plague_strike_8s;
|
||||
creators["dd cd and plague strike 8s"] = &DeathKnightTriggerFactoryInternal::dd_cd_and_plague_strike_8s;
|
||||
creators["plague strike 3s"] = &DeathKnightTriggerFactoryInternal::plague_strike_3s;
|
||||
creators["dd cd and plague strike 3s"] = &DeathKnightTriggerFactoryInternal::dd_cd_and_plague_strike_3s;
|
||||
creators["horn of winter"] = &DeathKnightTriggerFactoryInternal::horn_of_winter;
|
||||
creators["mind freeze"] = &DeathKnightTriggerFactoryInternal::mind_freeze;
|
||||
creators["mind freeze on enemy healer"] = &DeathKnightTriggerFactoryInternal::mind_freeze_on_enemy_healer;
|
||||
@@ -94,6 +94,7 @@ public:
|
||||
creators["high blood rune"] = &DeathKnightTriggerFactoryInternal::high_blood_rune;
|
||||
creators["high frost rune"] = &DeathKnightTriggerFactoryInternal::high_frost_rune;
|
||||
creators["high unholy rune"] = &DeathKnightTriggerFactoryInternal::high_unholy_rune;
|
||||
creators["no rune"] = &DeathKnightTriggerFactoryInternal::no_rune;
|
||||
creators["freezing fog"] = &DeathKnightTriggerFactoryInternal::freezing_fog;
|
||||
creators["no desolation"] = &DeathKnightTriggerFactoryInternal::no_desolation;
|
||||
creators["dd cd and no desolation"] = &DeathKnightTriggerFactoryInternal::dd_cd_and_no_desolation;
|
||||
@@ -106,15 +107,15 @@ private:
|
||||
static Trigger* pestilence_glyph(PlayerbotAI* botAI) { return new PestilenceGlyphTrigger(botAI); }
|
||||
static Trigger* blood_strike(PlayerbotAI* botAI) { return new BloodStrikeTrigger(botAI); }
|
||||
static Trigger* plague_strike(PlayerbotAI* botAI) { return new PlagueStrikeDebuffTrigger(botAI); }
|
||||
static Trigger* plague_strike_8s(PlayerbotAI* botAI) { return new PlagueStrike8sDebuffTrigger(botAI); }
|
||||
static Trigger* dd_cd_and_plague_strike_8s(PlayerbotAI* botAI) { return new TwoTriggers(botAI, "death and decay cooldown", "plague strike 8s"); }
|
||||
static Trigger* plague_strike_3s(PlayerbotAI* botAI) { return new PlagueStrike3sDebuffTrigger(botAI); }
|
||||
static Trigger* dd_cd_and_plague_strike_3s(PlayerbotAI* botAI) { return new TwoTriggers(botAI, "death and decay cooldown", "plague strike 3s"); }
|
||||
static Trigger* plague_strike_on_attacker(PlayerbotAI* botAI)
|
||||
{
|
||||
return new PlagueStrikeDebuffOnAttackerTrigger(botAI);
|
||||
}
|
||||
static Trigger* icy_touch(PlayerbotAI* botAI) { return new IcyTouchDebuffTrigger(botAI); }
|
||||
static Trigger* icy_touch_8s(PlayerbotAI* botAI) { return new IcyTouch8sDebuffTrigger(botAI); }
|
||||
static Trigger* dd_cd_and_icy_touch_8s(PlayerbotAI* botAI) { return new TwoTriggers(botAI, "death and decay cooldown", "icy touch 8s"); }
|
||||
static Trigger* icy_touch_3s(PlayerbotAI* botAI) { return new IcyTouch3sDebuffTrigger(botAI); }
|
||||
static Trigger* dd_cd_and_icy_touch_3s(PlayerbotAI* botAI) { return new TwoTriggers(botAI, "death and decay cooldown", "icy touch 3s"); }
|
||||
static Trigger* death_coil(PlayerbotAI* botAI) { return new DeathCoilTrigger(botAI); }
|
||||
static Trigger* icy_touch_on_attacker(PlayerbotAI* botAI) { return new IcyTouchDebuffOnAttackerTrigger(botAI); }
|
||||
static Trigger* improved_icy_talons(PlayerbotAI* botAI) { return new ImprovedIcyTalonsTrigger(botAI); }
|
||||
@@ -136,6 +137,7 @@ private:
|
||||
static Trigger* high_blood_rune(PlayerbotAI* botAI) { return new HighBloodRuneTrigger(botAI); }
|
||||
static Trigger* high_frost_rune(PlayerbotAI* botAI) { return new HighFrostRuneTrigger(botAI); }
|
||||
static Trigger* high_unholy_rune(PlayerbotAI* botAI) { return new HighUnholyRuneTrigger(botAI); }
|
||||
static Trigger* no_rune(PlayerbotAI* botAI) { return new NoRuneTrigger(botAI); }
|
||||
static Trigger* freezing_fog(PlayerbotAI* botAI) { return new FreezingFogTrigger(botAI); }
|
||||
static Trigger* no_desolation(PlayerbotAI* botAI) { return new DesolationTrigger(botAI); }
|
||||
static Trigger* dd_cd_and_no_desolation(PlayerbotAI* botAI) { return new TwoTriggers(botAI, "death and decay cooldown", "no desolation"); }
|
||||
|
||||
@@ -37,20 +37,32 @@ bool PestilenceGlyphTrigger::IsActive()
|
||||
return false;
|
||||
}
|
||||
|
||||
// Based on runeSlotTypes
|
||||
bool HighBloodRuneTrigger::IsActive()
|
||||
{
|
||||
return !bot->GetRuneCooldown(0) && !bot->GetRuneCooldown(1);
|
||||
return bot->GetRuneCooldown(0) <= 2000 && bot->GetRuneCooldown(1) <= 2000;
|
||||
}
|
||||
|
||||
bool HighFrostRuneTrigger::IsActive()
|
||||
{
|
||||
return !bot->GetRuneCooldown(2) && !bot->GetRuneCooldown(3);
|
||||
return bot->GetRuneCooldown(4) <= 2000 && bot->GetRuneCooldown(5) <= 2000;
|
||||
}
|
||||
|
||||
bool HighUnholyRuneTrigger::IsActive()
|
||||
{
|
||||
return !bot->GetRuneCooldown(4) && !bot->GetRuneCooldown(5);
|
||||
return bot->GetRuneCooldown(2) <= 2000 && bot->GetRuneCooldown(3) <= 2000;
|
||||
}
|
||||
|
||||
bool NoRuneTrigger::IsActive()
|
||||
{
|
||||
for (uint32 i = 0; i < MAX_RUNES; ++i)
|
||||
{
|
||||
if (!bot->GetRuneCooldown(i))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DesolationTrigger::IsActive()
|
||||
{
|
||||
return bot->HasAura(66817) && BuffTrigger::IsActive();
|
||||
@@ -62,5 +74,5 @@ bool DeathAndDecayCooldownTrigger::IsActive()
|
||||
if (!spellId)
|
||||
return true;
|
||||
|
||||
return bot->GetSpellCooldownDelay(spellId) >= 3000;
|
||||
return bot->GetSpellCooldownDelay(spellId) >= 2000;
|
||||
}
|
||||
@@ -20,10 +20,10 @@ public:
|
||||
PlagueStrikeDebuffTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "blood plague", 1, true, .0f) {}
|
||||
};
|
||||
|
||||
class PlagueStrike8sDebuffTrigger : public DebuffTrigger
|
||||
class PlagueStrike3sDebuffTrigger : public DebuffTrigger
|
||||
{
|
||||
public:
|
||||
PlagueStrike8sDebuffTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "blood plague", 1, true, .0f, 3000) {}
|
||||
PlagueStrike3sDebuffTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "blood plague", 1, true, .0f, 3000) {}
|
||||
};
|
||||
|
||||
// DEBUFF_CHECKISOWNER_TRIGGER(IcyTouchDebuffTrigger, "frost fever");
|
||||
@@ -33,10 +33,10 @@ public:
|
||||
IcyTouchDebuffTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "frost fever", 1, true, .0f) {}
|
||||
};
|
||||
|
||||
class IcyTouch8sDebuffTrigger : public DebuffTrigger
|
||||
class IcyTouch3sDebuffTrigger : public DebuffTrigger
|
||||
{
|
||||
public:
|
||||
IcyTouch8sDebuffTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "frost fever", 1, true, .0f, 3000) {}
|
||||
IcyTouch3sDebuffTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "frost fever", 1, true, .0f, 3000) {}
|
||||
};
|
||||
|
||||
BUFF_TRIGGER(UnbreakableArmorTrigger, "unbreakable armor");
|
||||
@@ -165,6 +165,13 @@ public:
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class NoRuneTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
NoRuneTrigger(PlayerbotAI* botAI) : Trigger(botAI, "no rune") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class FreezingFogTrigger : public HasAuraTrigger
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -80,7 +80,7 @@ NextAction** UnholyDKStrategy::getDefaultActions()
|
||||
return NextAction::array(
|
||||
0, new NextAction("death and decay", ACTION_HIGH + 5),
|
||||
new NextAction("summon gargoyle", ACTION_DEFAULT + 0.4f),
|
||||
new NextAction("empower rune weapon", ACTION_DEFAULT + 0.3f),
|
||||
// new NextAction("empower rune weapon", ACTION_DEFAULT + 0.3f),
|
||||
new NextAction("horn of winter", ACTION_DEFAULT + 0.2f),
|
||||
new NextAction("death coil", ACTION_DEFAULT + 0.1f),
|
||||
new NextAction("melee", ACTION_DEFAULT), nullptr);
|
||||
@@ -93,8 +93,8 @@ void UnholyDKStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
"death and decay cooldown", NextAction::array(0,
|
||||
new NextAction("ghoul frenzy", ACTION_DEFAULT + 0.9f),
|
||||
new NextAction("scourge strike", ACTION_DEFAULT + 0.8f),
|
||||
new NextAction("blood boil", ACTION_DEFAULT + 0.7f),
|
||||
new NextAction("icy touch", ACTION_DEFAULT + 0.6f),
|
||||
new NextAction("icy touch", ACTION_DEFAULT + 0.7f),
|
||||
new NextAction("blood strike", ACTION_DEFAULT + 0.6f),
|
||||
new NextAction("plague strike", ACTION_DEFAULT + 0.5f),
|
||||
nullptr)));
|
||||
|
||||
@@ -111,24 +111,26 @@ void UnholyDKStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
new NextAction("icy touch", ACTION_NORMAL + 3), nullptr)));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"high unholy rune", NextAction::array(0,
|
||||
new NextAction("plague strike", ACTION_NORMAL + 2), nullptr)));
|
||||
"high blood rune", NextAction::array(0, new NextAction("blood strike", ACTION_NORMAL + 2), nullptr)));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"high blood rune", NextAction::array(0, new NextAction("blood strike", ACTION_NORMAL + 1), nullptr)));
|
||||
"high unholy rune", NextAction::array(0,
|
||||
new NextAction("plague strike", ACTION_NORMAL + 1), nullptr)));
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("dd cd and plague strike 8s", NextAction::array(0, new NextAction("plague strike", ACTION_HIGH + 2), nullptr)));
|
||||
new TriggerNode("dd cd and plague strike 3s", NextAction::array(0, new NextAction("plague strike", ACTION_HIGH + 1), nullptr)));
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("dd cd and icy touch 8s", NextAction::array(0, new NextAction("icy touch", ACTION_HIGH + 1), nullptr)));
|
||||
new TriggerNode("dd cd and icy touch 3s", NextAction::array(0, new NextAction("icy touch", ACTION_HIGH + 2), nullptr)));
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("no rune", NextAction::array(0, new NextAction("empower rune weapon", ACTION_HIGH + 1), nullptr)));
|
||||
|
||||
// triggers.push_back(new TriggerNode("often", NextAction::array(0, new NextAction(, ACTION_NORMAL + 2), nullptr)));
|
||||
triggers.push_back(new TriggerNode(
|
||||
"army of the dead", NextAction::array(0, new NextAction("army of the dead", ACTION_HIGH + 6), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("bone shield", NextAction::array(0, new NextAction("bone shield", ACTION_HIGH + 1), nullptr)));
|
||||
new TriggerNode("bone shield", NextAction::array(0, new NextAction("bone shield", ACTION_HIGH + 3), nullptr)));
|
||||
}
|
||||
|
||||
void UnholyDKAoeStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
|
||||
@@ -41,8 +41,11 @@ DpsHunterStrategy::DpsHunterStrategy(PlayerbotAI* botAI) : GenericHunterStrategy
|
||||
NextAction** DpsHunterStrategy::getDefaultActions()
|
||||
{
|
||||
return NextAction::array(
|
||||
0, new NextAction("kill shot", ACTION_DEFAULT + 0.8f), new NextAction("chimera shot", ACTION_DEFAULT + 0.7f),
|
||||
new NextAction("explosive shot", ACTION_DEFAULT + 0.6f), new NextAction("aimed shot", ACTION_DEFAULT + 0.5f),
|
||||
0,
|
||||
new NextAction("explosive shot", ACTION_HIGH + 1.0f),
|
||||
new NextAction("kill shot", ACTION_DEFAULT + 0.8f),
|
||||
new NextAction("chimera shot", ACTION_DEFAULT + 0.6f),
|
||||
new NextAction("aimed shot", ACTION_DEFAULT + 0.5f),
|
||||
new NextAction("silencing shot", ACTION_DEFAULT + 0.4f),
|
||||
new NextAction("kill command", ACTION_DEFAULT + 0.3f),
|
||||
// new NextAction("arcane shot", ACTION_DEFAULT + 0.2f),
|
||||
@@ -55,7 +58,7 @@ void DpsHunterStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
GenericHunterStrategy::InitTriggers(triggers);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("black arrow", NextAction::array(0, new NextAction("black arrow", 15.0f), nullptr)));
|
||||
new TriggerNode("black arrow", NextAction::array(0, new NextAction("black arrow", 19.0f), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("low mana", NextAction::array(0, new NextAction("viper sting", 23.0f), nullptr)));
|
||||
triggers.push_back(
|
||||
|
||||
@@ -49,6 +49,8 @@ void GenericHunterNonCombatStrategy::InitTriggers(std::vector<TriggerNode*>& tri
|
||||
triggers.push_back(new TriggerNode("often", NextAction::array(0, new NextAction("apply oil", 1.0f), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("low ammo", NextAction::array(0, new NextAction("say::low ammo", ACTION_NORMAL), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("no track", NextAction::array(0, new NextAction("track humanoids", ACTION_NORMAL), nullptr)));
|
||||
// triggers.push_back(new TriggerNode("no ammo", NextAction::array(0, new NextAction("switch to melee",
|
||||
// ACTION_NORMAL + 1), new NextAction("say::no ammo", ACTION_NORMAL), nullptr))); triggers.push_back(new
|
||||
// TriggerNode("has ammo", NextAction::array(0, new NextAction("switch to ranged", ACTION_NORMAL), nullptr)));
|
||||
|
||||
@@ -75,6 +75,7 @@ public:
|
||||
creators["aspect of the wild"] = &HunterTriggerFactoryInternal::aspect_of_the_wild;
|
||||
creators["aspect of the viper"] = &HunterTriggerFactoryInternal::aspect_of_the_viper;
|
||||
creators["trueshot aura"] = &HunterTriggerFactoryInternal::trueshot_aura;
|
||||
creators["no track"] = &HunterTriggerFactoryInternal::no_track;
|
||||
creators["serpent sting on attacker"] = &HunterTriggerFactoryInternal::serpent_sting_on_attacker;
|
||||
creators["pet not happy"] = &HunterTriggerFactoryInternal::pet_not_happy;
|
||||
creators["concussive shot on snare target"] = &HunterTriggerFactoryInternal::concussive_shot_on_snare_target;
|
||||
@@ -99,6 +100,7 @@ private:
|
||||
static Trigger* pet_not_happy(PlayerbotAI* botAI) { return new HunterPetNotHappy(botAI); }
|
||||
static Trigger* serpent_sting_on_attacker(PlayerbotAI* botAI) { return new SerpentStingOnAttackerTrigger(botAI); }
|
||||
static Trigger* trueshot_aura(PlayerbotAI* botAI) { return new TrueshotAuraTrigger(botAI); }
|
||||
static Trigger* no_track(PlayerbotAI* botAI) { return new NoTrackTrigger(botAI); }
|
||||
static Trigger* aspect_of_the_viper(PlayerbotAI* botAI) { return new HunterAspectOfTheViperTrigger(botAI); }
|
||||
static Trigger* black_arrow(PlayerbotAI* botAI) { return new BlackArrowTrigger(botAI); }
|
||||
static Trigger* NoStings(PlayerbotAI* botAI) { return new HunterNoStingsActiveTrigger(botAI); }
|
||||
@@ -159,6 +161,7 @@ public:
|
||||
creators["aspect of the pack"] = &HunterAiObjectContextInternal::aspect_of_the_pack;
|
||||
creators["aspect of the cheetah"] = &HunterAiObjectContextInternal::aspect_of_the_cheetah;
|
||||
creators["trueshot aura"] = &HunterAiObjectContextInternal::trueshot_aura;
|
||||
creators["track humanoids"] = &HunterAiObjectContextInternal::track_humanoids;
|
||||
creators["feign death"] = &HunterAiObjectContextInternal::feign_death;
|
||||
creators["wing clip"] = &HunterAiObjectContextInternal::wing_clip;
|
||||
creators["raptor strike"] = &HunterAiObjectContextInternal::raptor_strike;
|
||||
@@ -182,6 +185,7 @@ private:
|
||||
static Action* feed_pet(PlayerbotAI* botAI) { return new FeedPetAction(botAI); }
|
||||
static Action* feign_death(PlayerbotAI* botAI) { return new CastFeignDeathAction(botAI); }
|
||||
static Action* trueshot_aura(PlayerbotAI* botAI) { return new CastTrueshotAuraAction(botAI); }
|
||||
static Action* track_humanoids(PlayerbotAI* botAI) { return new CastBuffSpellAction(botAI, "track humanoids"); }
|
||||
static Action* auto_shot(PlayerbotAI* botAI) { return new CastAutoShotAction(botAI); }
|
||||
static Action* aimed_shot(PlayerbotAI* botAI) { return new CastAimedShotAction(botAI); }
|
||||
static Action* chimera_shot(PlayerbotAI* botAI) { return new CastChimeraShotAction(botAI); }
|
||||
|
||||
@@ -56,7 +56,7 @@ bool HunterPetNotHappy::IsActive()
|
||||
bool HunterAspectOfTheViperTrigger::IsActive()
|
||||
{
|
||||
return SpellTrigger::IsActive() && !botAI->HasAura(spell, GetTarget()) &&
|
||||
AI_VALUE2(uint8, "mana", "self target") < sPlayerbotAIConfig->lowMana;
|
||||
AI_VALUE2(uint8, "mana", "self target") < (sPlayerbotAIConfig->lowMana / 2);
|
||||
;
|
||||
}
|
||||
|
||||
@@ -88,3 +88,36 @@ bool SwitchToMeleeTrigger::IsActive()
|
||||
(target->GetVictim() == bot &&
|
||||
sServerFacade->IsDistanceLessOrEqualThan(AI_VALUE2(float, "distance", "current target"), 8.0f));
|
||||
}
|
||||
|
||||
bool NoTrackTrigger::IsActive()
|
||||
{
|
||||
std::vector<std::string> track_list = {
|
||||
"track beasts",
|
||||
"track demons",
|
||||
"track dragonkin",
|
||||
"track elementals",
|
||||
"track giants",
|
||||
"track hidden",
|
||||
"track humanoids"
|
||||
};
|
||||
|
||||
for (auto &track: track_list)
|
||||
{
|
||||
if (botAI->HasAura(track, bot))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SerpentStingOnAttackerTrigger::IsActive()
|
||||
{
|
||||
if (!DebuffOnAttackerTrigger::IsActive())
|
||||
return false;
|
||||
Unit* target = GetTarget();
|
||||
if (!target)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return !botAI->HasAura("scorpid sting", target, false, true) &&
|
||||
!botAI->HasAura("viper sting", target, false, true);
|
||||
}
|
||||
@@ -101,10 +101,18 @@ public:
|
||||
TrueshotAuraTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "trueshot aura") {}
|
||||
};
|
||||
|
||||
class NoTrackTrigger : public BuffTrigger
|
||||
{
|
||||
public:
|
||||
NoTrackTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "no track") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class SerpentStingOnAttackerTrigger : public DebuffOnAttackerTrigger
|
||||
{
|
||||
public:
|
||||
SerpentStingOnAttackerTrigger(PlayerbotAI* botAI) : DebuffOnAttackerTrigger(botAI, "serpent sting", true) {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
BEGIN_TRIGGER(HunterPetNotHappy, Trigger)
|
||||
|
||||
@@ -31,7 +31,7 @@ private:
|
||||
{
|
||||
return new ActionNode("arcane barrage",
|
||||
/*P*/ nullptr,
|
||||
/*A*/ NextAction::array(0, new NextAction("arcane missiles"), nullptr),
|
||||
/*A*/ nullptr,
|
||||
/*C*/ nullptr);
|
||||
}
|
||||
|
||||
@@ -59,8 +59,10 @@ ArcaneMageStrategy::ArcaneMageStrategy(PlayerbotAI* botAI) : GenericMageStrategy
|
||||
|
||||
NextAction** ArcaneMageStrategy::getDefaultActions()
|
||||
{
|
||||
return NextAction::array(0, new NextAction("arcane blast", ACTION_DEFAULT + 0.1f),
|
||||
new NextAction("shoot", ACTION_DEFAULT), NULL);
|
||||
return NextAction::array(0, new NextAction("arcane blast", ACTION_DEFAULT + 0.3f),
|
||||
// new NextAction("arcane barrage", ACTION_DEFAULT + 0.2f), // cast during movement
|
||||
new NextAction("fire blast", ACTION_DEFAULT + 0.1f), // cast during movement
|
||||
new NextAction("shoot", ACTION_DEFAULT), nullptr);
|
||||
}
|
||||
|
||||
void ArcaneMageStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
|
||||
NextAction** FireMageStrategy::getDefaultActions()
|
||||
{
|
||||
return NextAction::array(0, new NextAction("fireball", ACTION_DEFAULT + 0.1f),
|
||||
return NextAction::array(0, new NextAction("fireball", ACTION_DEFAULT + 0.2f),
|
||||
new NextAction("fire blast", ACTION_DEFAULT + 0.1f), // cast during movement
|
||||
new NextAction("shoot", ACTION_DEFAULT), NULL);
|
||||
}
|
||||
|
||||
@@ -23,6 +24,8 @@ void FireMageStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
new TriggerNode("hot streak", NextAction::array(0, new NextAction("pyroblast", 25.0f), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("combustion", NextAction::array(0, new NextAction("combustion", 50.0f), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("living bomb", NextAction::array(0, new NextAction("living bomb", 19.0f), nullptr)));
|
||||
// triggers.push_back(new TriggerNode("enemy too close for spell", NextAction::array(0, new NextAction("dragon's
|
||||
// breath", 70.0f), nullptr)));
|
||||
}
|
||||
@@ -30,7 +33,10 @@ void FireMageStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
void FireMageAoeStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode("medium aoe", NextAction::array(0, new NextAction("flamestrike", 20.0f), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("living bomb", NextAction::array(0, new NextAction("living bomb", 25.0f), nullptr)));
|
||||
new TriggerNode("medium aoe", NextAction::array(0,
|
||||
new NextAction("dragon's breath", 24.0f),
|
||||
new NextAction("flamestrike", 23.0f),
|
||||
new NextAction("blast wave", 22.0f),
|
||||
new NextAction("living bomb on attackers", 21.0f),
|
||||
new NextAction("blizzard", 20.0f), nullptr)));
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ void FrostMageStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
triggers.push_back(
|
||||
new TriggerNode("has pet", NextAction::array(0, new NextAction("toggle pet spell", ACTION_HIGH + 1), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("ice barrier", NextAction::array(0, new NextAction("ice barrier", ACTION_NORMAL), nullptr)));
|
||||
new TriggerNode("medium health", NextAction::array(0, new NextAction("ice barrier", ACTION_NORMAL), nullptr)));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"brain freeze", NextAction::array(0, new NextAction("frostfire bolt", ACTION_NORMAL + 3), nullptr)));
|
||||
|
||||
@@ -54,6 +54,9 @@ void GenericMageNonCombatStrategy::InitTriggers(std::vector<TriggerNode*>& trigg
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("arcane intellect", NextAction::array(0, new NextAction("arcane intellect", 21.0f), nullptr)));
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("no focus magic", NextAction::array(0, new NextAction("focus magic on party", 19.0f), nullptr)));
|
||||
// triggers.push_back(new TriggerNode("no drink", NextAction::array(0, new NextAction("conjure water", 16.0f),
|
||||
// nullptr))); triggers.push_back(new TriggerNode("no food", NextAction::array(0, new NextAction("conjure
|
||||
// food", 15.0f), nullptr)));
|
||||
|
||||
@@ -59,7 +59,7 @@ private:
|
||||
{
|
||||
return new ActionNode("fire blast",
|
||||
/*P*/ nullptr,
|
||||
/*A*/ NextAction::array(0, new NextAction("scorch"), nullptr),
|
||||
/*A*/ nullptr,
|
||||
/*C*/ nullptr);
|
||||
}
|
||||
|
||||
@@ -115,16 +115,16 @@ private:
|
||||
{
|
||||
return new ActionNode("dragon's breath",
|
||||
/*P*/ nullptr,
|
||||
/*A*/ NextAction::array(0, new NextAction("blast wave"), nullptr),
|
||||
/*C*/ NextAction::array(0, new NextAction("flamestrike", 71.0f), nullptr));
|
||||
/*A*/ nullptr,
|
||||
/*C*/ nullptr);
|
||||
}
|
||||
|
||||
static ActionNode* blast_wave([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("blast wave",
|
||||
/*P*/ nullptr,
|
||||
/*A*/ NextAction::array(0, new NextAction("frost nova"), nullptr),
|
||||
/*C*/ NextAction::array(0, new NextAction("flamestrike", 71.0f), nullptr));
|
||||
/*A*/ nullptr,
|
||||
/*C*/ nullptr);
|
||||
}
|
||||
|
||||
static ActionNode* remove_curse([[maybe_unused]] PlayerbotAI* botAI)
|
||||
@@ -194,8 +194,7 @@ void MageBoostStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
triggers.push_back(new TriggerNode("icy veins", NextAction::array(0, new NextAction("icy veins", 50.0f), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("presence of mind", NextAction::array(0, new NextAction("presence of mind", 42.0f), nullptr)));
|
||||
// triggers.push_back(new TriggerNode("arcane power", NextAction::array(0, new NextAction("arcane power", 41.0f),
|
||||
// nullptr)));
|
||||
// triggers.push_back(new TriggerNode("arcane power", NextAction::array(0, new NextAction("arcane power", 41.0f), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("mirror image", NextAction::array(0, new NextAction("mirror image", 41.0f), nullptr)));
|
||||
}
|
||||
|
||||
@@ -5,13 +5,18 @@
|
||||
|
||||
#include "MageActions.h"
|
||||
|
||||
#include "PlayerbotAIConfig.h"
|
||||
#include "Playerbots.h"
|
||||
#include "ServerFacade.h"
|
||||
#include "SharedDefines.h"
|
||||
|
||||
Value<Unit*>* CastPolymorphAction::GetTargetValue() { return context->GetValue<Unit*>("cc target", getName()); }
|
||||
|
||||
bool CastFrostNovaAction::isUseful()
|
||||
{
|
||||
Unit* target = AI_VALUE(Unit*, "current target");
|
||||
if (target && target->ToCreature() && target->ToCreature()->HasMechanicTemplateImmunity(1 << (MECHANIC_FREEZE - 1)))
|
||||
return false;
|
||||
return sServerFacade->IsDistanceLessOrEqualThan(AI_VALUE2(float, "distance", GetTargetName()), 10.f);
|
||||
}
|
||||
|
||||
@@ -21,3 +26,65 @@ bool CastConeOfColdAction::isUseful()
|
||||
bool targetClose = sServerFacade->IsDistanceLessOrEqualThan(AI_VALUE2(float, "distance", GetTargetName()), 10.f);
|
||||
return facingTarget && targetClose;
|
||||
}
|
||||
|
||||
bool CastDragonsBreathAction::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, 10.0f);
|
||||
return facingTarget && targetClose;
|
||||
}
|
||||
|
||||
bool CastBlastWaveAction::isUseful()
|
||||
{
|
||||
Unit* target = AI_VALUE(Unit*, "current target");
|
||||
if (!target)
|
||||
return false;
|
||||
bool targetClose = bot->IsWithinCombatRange(target, 10.0f);
|
||||
return targetClose;
|
||||
}
|
||||
|
||||
Unit* CastFocusMagicOnPartyAction::GetTarget()
|
||||
{
|
||||
Group* group = bot->GetGroup();
|
||||
if (!group)
|
||||
return nullptr;
|
||||
|
||||
Unit* casterDps = nullptr;
|
||||
Unit* healer = nullptr;
|
||||
Unit* target = nullptr;
|
||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||
{
|
||||
Player* member = ref->GetSource();
|
||||
if (!member || member == bot || !member->IsAlive())
|
||||
continue;
|
||||
|
||||
if (member->GetMap() != bot->GetMap() || bot->GetDistance(member) > sPlayerbotAIConfig->spellDistance)
|
||||
continue;
|
||||
|
||||
if (member->HasAura(54646))
|
||||
continue;
|
||||
|
||||
if (member->getClass() == CLASS_MAGE)
|
||||
return member;
|
||||
|
||||
if (!casterDps && botAI->IsCaster(member) && botAI->IsDps(member))
|
||||
casterDps = member;
|
||||
|
||||
if (!healer && botAI->IsHeal(member))
|
||||
healer = member;
|
||||
|
||||
if (!target)
|
||||
target = member;
|
||||
}
|
||||
|
||||
if (casterDps)
|
||||
return casterDps;
|
||||
|
||||
if (healer)
|
||||
return healer;
|
||||
|
||||
return target;
|
||||
}
|
||||
@@ -57,10 +57,10 @@ public:
|
||||
CastPyroblastAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "pyroblast") {}
|
||||
};
|
||||
|
||||
class CastFlamestrikeAction : public CastSpellAction
|
||||
class CastFlamestrikeAction : public CastDebuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastFlamestrikeAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "flamestrike") {}
|
||||
CastFlamestrikeAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "flamestrike", true, 0.0f) {}
|
||||
ActionThreatType getThreatType() override { return ActionThreatType::Aoe; }
|
||||
};
|
||||
|
||||
@@ -243,11 +243,18 @@ public:
|
||||
CastLivingBombAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "living bomb", true) {}
|
||||
};
|
||||
|
||||
class CastLivingBombOnAttackersAction : public CastDebuffSpellOnAttackerAction
|
||||
{
|
||||
public:
|
||||
CastLivingBombOnAttackersAction(PlayerbotAI* botAI) : CastDebuffSpellOnAttackerAction(botAI, "living bomb", true) {}
|
||||
};
|
||||
|
||||
class CastDragonsBreathAction : public CastSpellAction
|
||||
{
|
||||
public:
|
||||
CastDragonsBreathAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "dragon's breath") {}
|
||||
ActionThreatType getThreatType() override { return ActionThreatType::Aoe; }
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
class CastBlastWaveAction : public CastSpellAction
|
||||
@@ -255,6 +262,7 @@ class CastBlastWaveAction : public CastSpellAction
|
||||
public:
|
||||
CastBlastWaveAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "blast wave") {}
|
||||
ActionThreatType getThreatType() override { return ActionThreatType::Aoe; }
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
class CastInvisibilityAction : public CastBuffSpellAction
|
||||
@@ -294,4 +302,11 @@ public:
|
||||
CastMirrorImageAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "mirror image") {}
|
||||
};
|
||||
|
||||
class CastFocusMagicOnPartyAction : public CastSpellAction
|
||||
{
|
||||
public:
|
||||
CastFocusMagicOnPartyAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "focus magic") {}
|
||||
Unit* GetTarget() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -108,6 +108,7 @@ public:
|
||||
creators["mirror image"] = &MageTriggerFactoryInternal::mirror_image;
|
||||
creators["frost nova on target"] = &MageTriggerFactoryInternal::frost_nova_on_target;
|
||||
creators["frostbite on target"] = &MageTriggerFactoryInternal::frostbite_on_target;
|
||||
creators["no focus magic"] = &MageTriggerFactoryInternal::no_focus_magic;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -141,6 +142,7 @@ private:
|
||||
static Trigger* mirror_image(PlayerbotAI* botAI) { return new MirrorImageTrigger(botAI); }
|
||||
static Trigger* frost_nova_on_target(PlayerbotAI* botAI) { return new FrostNovaOnTargetTrigger(botAI); }
|
||||
static Trigger* frostbite_on_target(PlayerbotAI* botAI) { return new FrostbiteOnTargetTrigger(botAI); }
|
||||
static Trigger* no_focus_magic(PlayerbotAI* botAI) { return new NoFocusMagicTrigger(botAI); }
|
||||
};
|
||||
|
||||
class MageAiObjectContextInternal : public NamedObjectContext<Action>
|
||||
@@ -184,6 +186,7 @@ public:
|
||||
creators["polymorph"] = &MageAiObjectContextInternal::polymorph;
|
||||
creators["spellsteal"] = &MageAiObjectContextInternal::spellsteal;
|
||||
creators["living bomb"] = &MageAiObjectContextInternal::living_bomb;
|
||||
creators["living bomb on attackers"] = &MageAiObjectContextInternal::living_bomb_on_attackers;
|
||||
creators["dragon's breath"] = &MageAiObjectContextInternal::dragons_breath;
|
||||
creators["blast wave"] = &MageAiObjectContextInternal::blast_wave;
|
||||
creators["invisibility"] = &MageAiObjectContextInternal::invisibility;
|
||||
@@ -195,6 +198,7 @@ public:
|
||||
creators["fire ward"] = &MageAiObjectContextInternal::fire_ward;
|
||||
creators["frost ward"] = &MageAiObjectContextInternal::frost_ward;
|
||||
creators["mirror image"] = &MageAiObjectContextInternal::mirror_image;
|
||||
creators["focus magic on party"] = &MageAiObjectContextInternal::focus_magic_on_party;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -242,6 +246,7 @@ private:
|
||||
static Action* polymorph(PlayerbotAI* botAI) { return new CastPolymorphAction(botAI); }
|
||||
static Action* spellsteal(PlayerbotAI* botAI) { return new CastSpellstealAction(botAI); }
|
||||
static Action* living_bomb(PlayerbotAI* botAI) { return new CastLivingBombAction(botAI); }
|
||||
static Action* living_bomb_on_attackers(PlayerbotAI* botAI) { return new CastLivingBombOnAttackersAction(botAI); }
|
||||
static Action* dragons_breath(PlayerbotAI* botAI) { return new CastDragonsBreathAction(botAI); }
|
||||
static Action* blast_wave(PlayerbotAI* botAI) { return new CastBlastWaveAction(botAI); }
|
||||
static Action* invisibility(PlayerbotAI* botAI) { return new CastInvisibilityAction(botAI); }
|
||||
@@ -251,6 +256,7 @@ private:
|
||||
return new CastCounterspellOnEnemyHealerAction(botAI);
|
||||
}
|
||||
static Action* mirror_image(PlayerbotAI* botAI) { return new CastMirrorImageAction(botAI); }
|
||||
static Action* focus_magic_on_party(PlayerbotAI* botAI) { return new CastFocusMagicOnPartyAction(botAI); }
|
||||
};
|
||||
|
||||
MageAiObjectContext::MageAiObjectContext(PlayerbotAI* botAI) : AiObjectContext(botAI)
|
||||
|
||||
@@ -33,6 +33,17 @@ bool FingersOfFrostSingleTrigger::IsActive()
|
||||
return (aura && aura->GetCharges() == 1);
|
||||
}
|
||||
|
||||
bool ArcaneBlastStackTrigger::IsActive()
|
||||
{
|
||||
Aura* aura = botAI->GetAura(getName(), GetTarget(), false, true, 3);
|
||||
if (!aura)
|
||||
return false;
|
||||
if (aura->GetStackAmount() >= 4)
|
||||
return true;
|
||||
bool hasMissileBarrage = botAI->HasAura(44401, bot);
|
||||
return hasMissileBarrage;
|
||||
}
|
||||
|
||||
bool FrostNovaOnTargetTrigger::IsActive()
|
||||
{
|
||||
Unit* target = GetTarget();
|
||||
@@ -52,3 +63,24 @@ bool FrostbiteOnTargetTrigger::IsActive()
|
||||
}
|
||||
return botAI->HasAura(spell, target);
|
||||
}
|
||||
|
||||
bool NoFocusMagicTrigger::IsActive()
|
||||
{
|
||||
if (!bot->HasSpell(54646))
|
||||
return false;
|
||||
|
||||
Group* group = bot->GetGroup();
|
||||
if (!group)
|
||||
return false;
|
||||
|
||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||
{
|
||||
Player* member = ref->GetSource();
|
||||
if (!member || member == bot || !member->IsAlive())
|
||||
continue;
|
||||
|
||||
if (member->HasAura(54646, bot->GetGUID()))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -171,6 +171,7 @@ class ArcaneBlastStackTrigger : public HasAuraStackTrigger
|
||||
{
|
||||
public:
|
||||
ArcaneBlastStackTrigger(PlayerbotAI* botAI) : HasAuraStackTrigger(botAI, "arcane blast", 3, 1) {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class MirrorImageTrigger : public BoostTrigger
|
||||
@@ -193,4 +194,11 @@ public:
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class NoFocusMagicTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
NoFocusMagicTrigger(PlayerbotAI* botAI) : Trigger(botAI, "no focus magic") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -15,10 +15,10 @@ ShadowPriestStrategy::ShadowPriestStrategy(PlayerbotAI* botAI) : GenericPriestSt
|
||||
|
||||
NextAction** ShadowPriestStrategy::getDefaultActions()
|
||||
{
|
||||
return NextAction::array(0, new NextAction("mind blast", ACTION_DEFAULT + 0.2f),
|
||||
// new NextAction("shadow word: death", 12.0f),
|
||||
new NextAction("mind flay", ACTION_DEFAULT + 0.1f),
|
||||
new NextAction("shoot", ACTION_DEFAULT), NULL);
|
||||
return NextAction::array(0, new NextAction("mind blast", ACTION_DEFAULT + 0.3f),
|
||||
new NextAction("mind flay", ACTION_DEFAULT + 0.2f),
|
||||
new NextAction("shadow word: death", ACTION_DEFAULT + 0.1f), // cast during movement
|
||||
new NextAction("shoot", ACTION_DEFAULT), nullptr);
|
||||
}
|
||||
|
||||
void ShadowPriestStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
|
||||
@@ -41,7 +41,9 @@ CasterShamanStrategy::CasterShamanStrategy(PlayerbotAI* botAI) : GenericShamanSt
|
||||
NextAction** CasterShamanStrategy::getDefaultActions()
|
||||
{
|
||||
return NextAction::array(0, new NextAction("lava burst", ACTION_DEFAULT + 0.2f),
|
||||
new NextAction("lightning bolt", ACTION_DEFAULT), NULL);
|
||||
new NextAction("lightning bolt", ACTION_DEFAULT + 0.1f),
|
||||
// new NextAction("earth shock", ACTION_DEFAULT), // cast during movement
|
||||
nullptr);
|
||||
}
|
||||
|
||||
void CasterShamanStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include "ShamanTriggers.h"
|
||||
|
||||
#include "ItemTemplate.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
/*
|
||||
@@ -46,8 +47,12 @@ bool MainHandWeaponNoImbueTrigger::IsActive()
|
||||
bool OffHandWeaponNoImbueTrigger::IsActive()
|
||||
{
|
||||
Item* const itemForSpell = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
|
||||
if (!itemForSpell || itemForSpell->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT) ||
|
||||
itemForSpell->GetTemplate()->InventoryType != INVTYPE_WEAPON)
|
||||
if (!itemForSpell)
|
||||
return false;
|
||||
uint32 invType = itemForSpell->GetTemplate()->InventoryType;
|
||||
bool allowedType = (invType == INVTYPE_WEAPON) || (invType == INVTYPE_WEAPONOFFHAND);
|
||||
if (itemForSpell->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT) ||
|
||||
!allowedType)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -302,7 +302,7 @@ public:
|
||||
class FlameShockTrigger : public DebuffTrigger
|
||||
{
|
||||
public:
|
||||
FlameShockTrigger(PlayerbotAI* ai) : DebuffTrigger(ai, "flame shock", 1, true) {}
|
||||
FlameShockTrigger(PlayerbotAI* ai) : DebuffTrigger(ai, "flame shock", 1, true, 6.0f) {}
|
||||
};
|
||||
|
||||
class WrathOfAirTotemTrigger : public TotemTrigger
|
||||
|
||||
@@ -618,8 +618,8 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
std::string const GetTargetName() { return "self target"; }
|
||||
virtual bool IsActive();
|
||||
std::string const GetTargetName() override { return "self target"; }
|
||||
bool IsActive() override;
|
||||
|
||||
private:
|
||||
int stack;
|
||||
|
||||
@@ -36,7 +36,7 @@ float EstimatedGroupDpsValue::Calculate()
|
||||
if (member == bot) // calculated
|
||||
continue;
|
||||
|
||||
if (!member || !member->IsInWorld())
|
||||
if (!member || !member->IsInWorld() || !member->IsAlive())
|
||||
continue;
|
||||
|
||||
if (member->GetMapId() != bot->GetMapId())
|
||||
|
||||
@@ -49,8 +49,8 @@ DpsWarlockStrategy::DpsWarlockStrategy(PlayerbotAI* botAI) : GenericWarlockStrat
|
||||
NextAction** DpsWarlockStrategy::getDefaultActions()
|
||||
{
|
||||
return NextAction::array(
|
||||
0, new NextAction("haunt", ACTION_DEFAULT + 0.3f), new NextAction("demonic empowerment", ACTION_DEFAULT + 0.2f),
|
||||
new NextAction("shadow bolt", ACTION_DEFAULT + 0.1f), new NextAction("shoot", ACTION_DEFAULT), nullptr);
|
||||
0, new NextAction("haunt", ACTION_DEFAULT + 0.4f), new NextAction("demonic empowerment", ACTION_DEFAULT + 0.3f),
|
||||
new NextAction("shadow bolt", ACTION_DEFAULT + 0.2f), new NextAction("shoot", ACTION_DEFAULT), nullptr);
|
||||
}
|
||||
|
||||
void DpsWarlockStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
@@ -71,6 +71,12 @@ void DpsWarlockStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
|
||||
triggers.push_back(new TriggerNode("decimation", NextAction::array(0, new NextAction("soul fire", 16.0f), NULL)));
|
||||
|
||||
// cast during movement
|
||||
triggers.push_back(
|
||||
new TriggerNode("high mana", 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)));
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("metamorphosis", NextAction::array(0, new NextAction("metamorphosis", 20.0f), NULL)));
|
||||
}
|
||||
@@ -78,9 +84,9 @@ void DpsWarlockStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
void DpsAoeWarlockStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode("medium aoe", NextAction::array(0, new NextAction("seed of corruption", 39.0f),
|
||||
new NextAction("seed of corruption on attacker", 38.0f),
|
||||
new NextAction("rain of fire", 37.0f), nullptr)));
|
||||
new TriggerNode("medium aoe", NextAction::array(0, new NextAction("seed of corruption", 33.0f),
|
||||
new NextAction("seed of corruption on attacker", 32.0f),
|
||||
new NextAction("rain of fire", 31.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("corruption on attacker",
|
||||
NextAction::array(0, new NextAction("corruption on attacker", 27.0f), nullptr)));
|
||||
triggers.push_back(
|
||||
|
||||
@@ -18,7 +18,7 @@ Value<Unit*>* CastFearOnCcAction::GetTargetValue() { return context->GetValue<Un
|
||||
|
||||
bool CastFearOnCcAction::Execute(Event event) { return botAI->CastSpell("fear", GetTarget()); }
|
||||
|
||||
bool CastFearOnCcAction::isPossible() { return botAI->CanCastSpell("fear", GetTarget()); }
|
||||
bool CastFearOnCcAction::isPossible() { return true; }
|
||||
|
||||
bool CastFearOnCcAction::isUseful() { return true; }
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "WarlockAiObjectContext.h"
|
||||
|
||||
#include "DpsWarlockStrategy.h"
|
||||
#include "GenericTriggers.h"
|
||||
#include "GenericWarlockNonCombatStrategy.h"
|
||||
#include "NamedObjectContext.h"
|
||||
#include "Playerbots.h"
|
||||
@@ -98,6 +99,7 @@ public:
|
||||
creators["unstable affliction on attacker"] = &WarlockTriggerFactoryInternal::unstable_affliction_on_attacker;
|
||||
creators["haunt"] = &WarlockTriggerFactoryInternal::haunt;
|
||||
creators["decimation"] = &WarlockTriggerFactoryInternal::decimation;
|
||||
creators["life tap glyph buff"] = &WarlockTriggerFactoryInternal::life_tap_glyph_buff;
|
||||
creators["molten core"] = &WarlockTriggerFactoryInternal::molten_core;
|
||||
creators["metamorphosis"] = &WarlockTriggerFactoryInternal::metamorphosis;
|
||||
}
|
||||
@@ -131,6 +133,7 @@ private:
|
||||
}
|
||||
static Trigger* haunt(PlayerbotAI* ai) { return new HauntTrigger(ai); }
|
||||
static Trigger* decimation(PlayerbotAI* ai) { return new DecimationTrigger(ai); }
|
||||
static Trigger* life_tap_glyph_buff(PlayerbotAI* ai) { return new LifeTapGlyphBuffTrigger(ai); }
|
||||
static Trigger* molten_core(PlayerbotAI* ai) { return new MoltenCoreTrigger(ai); }
|
||||
static Trigger* metamorphosis(PlayerbotAI* ai) { return new MetamorphosisTrigger(ai); }
|
||||
};
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include "WarlockTriggers.h"
|
||||
|
||||
#include "GenericTriggers.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
bool DemonArmorTrigger::IsActive()
|
||||
@@ -44,4 +45,13 @@ bool DecimationTrigger::IsActive()
|
||||
{
|
||||
Aura* aura = botAI->GetAura(getName(), GetTarget(), false, true);
|
||||
return aura && aura->GetDuration() > 3000;
|
||||
}
|
||||
|
||||
bool LifeTapGlyphBuffTrigger::IsActive()
|
||||
{
|
||||
// Check life tap glyph first
|
||||
if (!botAI->HasAura(63320, bot))
|
||||
return false;
|
||||
|
||||
return BuffTrigger::IsActive();
|
||||
}
|
||||
@@ -163,6 +163,13 @@ public:
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class LifeTapGlyphBuffTrigger : public BuffTrigger
|
||||
{
|
||||
public:
|
||||
LifeTapGlyphBuffTrigger(PlayerbotAI* ai) : BuffTrigger(ai, "life tap") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class MoltenCoreTrigger : public HasAuraTrigger
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -13,12 +13,12 @@ bool CastSunderArmorAction::isUseful()
|
||||
return !aura || aura->GetStackAmount() < 5 || aura->GetDuration() <= 6000;
|
||||
}
|
||||
|
||||
Value<Unit*>* CastVigilanceAction::GetTargetValue()
|
||||
Unit* CastVigilanceAction::GetTarget()
|
||||
{
|
||||
Group* group = bot->GetGroup();
|
||||
if (!group)
|
||||
{
|
||||
return new ManualSetValue<Unit*>(botAI, nullptr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Player* currentVigilanceTarget = nullptr;
|
||||
@@ -74,23 +74,23 @@ Value<Unit*>* CastVigilanceAction::GetTargetValue()
|
||||
// If no valid target, return nullptr
|
||||
if (!highestPriorityTarget)
|
||||
{
|
||||
return new ManualSetValue<Unit*>(botAI, nullptr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// If the current target is already the highest-priority target, do nothing
|
||||
if (currentVigilanceTarget == highestPriorityTarget)
|
||||
{
|
||||
return new ManualSetValue<Unit*>(botAI, nullptr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Assign the new target
|
||||
Unit* targetUnit = highestPriorityTarget->ToUnit();
|
||||
if (targetUnit)
|
||||
{
|
||||
return new ManualSetValue<Unit*>(botAI, targetUnit);
|
||||
return targetUnit;
|
||||
}
|
||||
|
||||
return new ManualSetValue<Unit*>(botAI, nullptr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool CastVigilanceAction::Execute(Event event)
|
||||
|
||||
@@ -140,7 +140,7 @@ class CastVigilanceAction : public BuffOnPartyAction
|
||||
public:
|
||||
CastVigilanceAction(PlayerbotAI* botAI) : BuffOnPartyAction(botAI, "vigilance") {}
|
||||
|
||||
Value<Unit*>* GetTargetValue() override;
|
||||
Unit* GetTarget() override;
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user