Merge pull request #880 from liyunfan1223/improve_dps

Improve DPS rotation
This commit is contained in:
Yunfan Li
2025-01-20 15:50:45 +08:00
committed by GitHub
39 changed files with 383 additions and 113 deletions

View File

@@ -23,6 +23,7 @@
# LEVELS # LEVELS
# GEAR # GEAR
# QUESTS # QUESTS
# ACTIVITIES
# SPELLS # SPELLS
# STRATEGIES # STRATEGIES
# TELEPORTS # TELEPORTS
@@ -612,6 +613,50 @@ AiPlayerbot.EquipmentPersistenceLevel = 80
# Default: 1 (enabled) # Default: 1 (enabled)
AiPlayerbot.AutoUpgradeEquip = 1 AiPlayerbot.AutoUpgradeEquip = 1
# Only set wolf pets for hunters to have higher damage (0 = disabled, 1 = enabled only for max-level, 2 = enabled)
# Default: 0 (disabled)
AiPlayerbot.HunterWolfPet = 0
#
#
#
####################################################################################################
####################################################################################################
# ACTIVITIES
#
#
# Specify percent of active bots
# The default is 10. With 10% of all bots going active or inactive each minute. Regardless
# This value is only applied to inactive areas where no real-players are detected, when
# real-players are nearby, friend, group, guild, bg, instances etc the value is always
# enforced to 100%
AiPlayerbot.BotActiveAlone = 100
# Force botActiveAlone when bot is ... of real player
AiPlayerbot.BotActiveAloneForceWhenInRadius = 150
AiPlayerbot.BotActiveAloneForceWhenInZone = 1
AiPlayerbot.BotActiveAloneForceWhenInMap = 0
AiPlayerbot.BotActiveAloneForceWhenIsFriend = 1
AiPlayerbot.BotActiveAloneForceWhenInGuild = 1
# SmartScale is enabled or not.
# The default is 1. When enabled (smart) scales the 'BotActiveAlone' value.
# (The scaling will be overruled by the BotActiveAloneForceWhen...rules)
#
# Limitfloor - when DIFF (latency) above floor, activity scaling is applied starting with 90%
# LimitCeiling - when DIFF (latency) above ceiling, activity is 0%;
#
# MinLevel - only apply scaling when level is above or equal to min(bot)Level
# MaxLevel - only apply scaling when level is lower or equal of max(bot)Level
#
AiPlayerbot.botActiveAloneSmartScale = 1
AiPlayerbot.botActiveAloneSmartScaleDiffLimitfloor = 50
AiPlayerbot.botActiveAloneSmartScaleDiffLimitCeiling = 200
AiPlayerbot.botActiveAloneSmartScaleWhenMinLevel = 1
AiPlayerbot.botActiveAloneSmartScaleWhenMaxLevel = 80
# #
# #
# #
@@ -960,7 +1005,7 @@ AiPlayerbot.PremadeSpecGlyph.6.1 = 45805,43673,43547,43544,43672,43543
AiPlayerbot.PremadeSpecLink.6.1.60 = -32003350332203012300023101351 AiPlayerbot.PremadeSpecLink.6.1.60 = -32003350332203012300023101351
AiPlayerbot.PremadeSpecLink.6.1.80 = -32002350352203012300033101351-230200305003 AiPlayerbot.PremadeSpecLink.6.1.80 = -32002350352203012300033101351-230200305003
AiPlayerbot.PremadeSpecName.6.2 = unholy pve AiPlayerbot.PremadeSpecName.6.2 = unholy pve
AiPlayerbot.PremadeSpecGlyph.6.2 = 43542,43673,45804,43544,43672,43549 AiPlayerbot.PremadeSpecGlyph.6.2 = 43542,43673,43546,43544,43672,43549
AiPlayerbot.PremadeSpecLink.6.2.60 = --2301303050032151000150013131151 AiPlayerbot.PremadeSpecLink.6.2.60 = --2301303050032151000150013131151
AiPlayerbot.PremadeSpecLink.6.2.80 = -320033500002-2301303050032151000150013133151 AiPlayerbot.PremadeSpecLink.6.2.80 = -320033500002-2301303050032151000150013133151
AiPlayerbot.PremadeSpecName.6.3 = double aura blood pve AiPlayerbot.PremadeSpecName.6.3 = double aura blood pve
@@ -1551,36 +1596,6 @@ AiPlayerbot.RandombotsWalkingRPG = 0
# Set randombots movement speed to walking only inside buildings # Set randombots movement speed to walking only inside buildings
AiPlayerbot.RandombotsWalkingRPG.InDoors = 0 AiPlayerbot.RandombotsWalkingRPG.InDoors = 0
# Specify percent of active bots
# The default is 10. With 10% of all bots going active or inactive each minute. Regardless
# This value is only applied to inactive areas where no real-players are detected, when
# real-players are nearby, friend, group, guild, bg, instances etc the value is always
# enforced to 100%
AiPlayerbot.BotActiveAlone = 100
# Force botActiveAlone when bot is ... of real player
AiPlayerbot.BotActiveAloneForceWhenInRadius = 150
AiPlayerbot.BotActiveAloneForceWhenInZone = 1
AiPlayerbot.BotActiveAloneForceWhenInMap = 0
AiPlayerbot.BotActiveAloneForceWhenIsFriend = 1
AiPlayerbot.BotActiveAloneForceWhenInGuild = 1
# SmartScale is enabled or not.
# The default is 1. When enabled (smart) scales the 'BotActiveAlone' value.
# (The scaling will be overruled by the BotActiveAloneForceWhen...rules)
#
# Limitfloor - when DIFF (latency) above floor, activity scaling is applied starting with 90%
# LimitCeiling - when DIFF (latency) above ceiling, activity is 0%;
#
# MinLevel - only apply scaling when level is above or equal to min(bot)Level
# MaxLevel - only apply scaling when level is lower or equal of max(bot)Level
#
AiPlayerbot.botActiveAloneSmartScale = 1
AiPlayerbot.botActiveAloneSmartScaleDiffLimitfloor = 50
AiPlayerbot.botActiveAloneSmartScaleDiffLimitCeiling = 200
AiPlayerbot.botActiveAloneSmartScaleWhenMinLevel = 1
AiPlayerbot.botActiveAloneSmartScaleWhenMaxLevel = 80
# Premade spell to avoid (undetected spells) # Premade spell to avoid (undetected spells)
# spellid-radius, ... # spellid-radius, ...
AiPlayerbot.PremadeAvoidAoe = 62234-4 AiPlayerbot.PremadeAvoidAoe = 62234-4

View File

@@ -2928,7 +2928,10 @@ bool PlayerbotAI::CanCastSpell(uint32 spellid, Unit* target, bool checkHasSpell,
} }
Unit* oldSel = bot->GetSelectedUnit(); 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_targets.SetUnitTarget(target);
spell->m_CastItem = castItem; spell->m_CastItem = castItem;
@@ -2938,7 +2941,6 @@ bool PlayerbotAI::CanCastSpell(uint32 spellid, Unit* target, bool checkHasSpell,
; ;
} }
spell->m_targets.SetItemTarget(itemTarget); spell->m_targets.SetItemTarget(itemTarget);
SpellCastResult result = spell->CheckCast(true); SpellCastResult result = spell->CheckCast(true);
delete spell; delete spell;

View File

@@ -511,6 +511,7 @@ bool PlayerbotAIConfig::Initialize()
autoTrainSpells = sConfigMgr->GetOption<std::string>("AiPlayerbot.AutoTrainSpells", "yes"); autoTrainSpells = sConfigMgr->GetOption<std::string>("AiPlayerbot.AutoTrainSpells", "yes");
autoPickTalents = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoPickTalents", true); autoPickTalents = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoPickTalents", true);
autoUpgradeEquip = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoUpgradeEquip", false); autoUpgradeEquip = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoUpgradeEquip", false);
hunterWolfPet = sConfigMgr->GetOption<int32>("AiPlayerbot.HunterWolfPet", 0);
autoLearnTrainerSpells = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoLearnTrainerSpells", true); autoLearnTrainerSpells = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoLearnTrainerSpells", true);
autoLearnQuestSpells = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoLearnQuestSpells", false); autoLearnQuestSpells = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoLearnQuestSpells", false);
autoTeleportForLevel = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoTeleportForLevel", false); autoTeleportForLevel = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoTeleportForLevel", false);

View File

@@ -289,6 +289,7 @@ public:
std::string autoTrainSpells; std::string autoTrainSpells;
bool autoPickTalents; bool autoPickTalents;
bool autoUpgradeEquip; bool autoUpgradeEquip;
int32 hunterWolfPet;
bool autoLearnTrainerSpells; bool autoLearnTrainerSpells;
bool autoDoQuests; bool autoDoQuests;
bool enableNewRpgStrategy; bool enableNewRpgStrategy;

View File

@@ -484,10 +484,11 @@ void PlayerbotHolder::OnBotLogin(Player* const bot)
if (!groupValid) if (!groupValid)
{ {
WorldPacket p; bot->RemoveFromGroup();
std::string const member = bot->GetName(); // WorldPacket p;
p << uint32(PARTY_OP_LEAVE) << member << uint32(0); // std::string const member = bot->GetName();
bot->GetSession()->HandleGroupDisbandOpcode(p); // p << uint32(PARTY_OP_LEAVE) << member << uint32(0);
// bot->GetSession()->HandleGroupDisbandOpcode(p);
} }
} }

View File

@@ -36,6 +36,7 @@
#include "SharedDefines.h" #include "SharedDefines.h"
#include "SpellAuraDefines.h" #include "SpellAuraDefines.h"
#include "StatsWeightCalculator.h" #include "StatsWeightCalculator.h"
#include "World.h"
#define PLAYER_SKILL_INDEX(x) (PLAYER_SKILL_INFO_1_1 + ((x)*3)) #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()) if (itr->second.minlevel > bot->GetLevel())
continue; 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); ids.push_back(itr->first);
} }
@@ -2807,11 +2815,11 @@ void PlayerbotFactory::InitAmmo()
uint32 entry = sRandomItemMgr->GetAmmo(level, subClass); uint32 entry = sRandomItemMgr->GetAmmo(level, subClass);
uint32 count = bot->GetItemCount(entry); 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); newItem->AddToUpdateQueueOf(bot);
} }

View File

@@ -84,9 +84,7 @@ bool LeaveGroupAction::Leave(Player* player)
bool shouldStay = randomBot && bot->GetGroup() && player == bot; bool shouldStay = randomBot && bot->GetGroup() && player == bot;
if (!shouldStay) if (!shouldStay)
{ {
WorldPacket p; bot->RemoveFromGroup();
p << uint32(PARTY_OP_LEAVE) << bot->GetName() << uint32(0);
bot->GetSession()->HandleGroupDisbandOpcode(p);
} }
if (randomBot) if (randomBot)

View File

@@ -74,14 +74,14 @@ public:
creators["plague strike"] = &DeathKnightTriggerFactoryInternal::plague_strike; creators["plague strike"] = &DeathKnightTriggerFactoryInternal::plague_strike;
creators["plague strike on attacker"] = &DeathKnightTriggerFactoryInternal::plague_strike_on_attacker; creators["plague strike on attacker"] = &DeathKnightTriggerFactoryInternal::plague_strike_on_attacker;
creators["icy touch"] = &DeathKnightTriggerFactoryInternal::icy_touch; creators["icy touch"] = &DeathKnightTriggerFactoryInternal::icy_touch;
creators["icy touch 8s"] = &DeathKnightTriggerFactoryInternal::icy_touch_8s; creators["icy touch 3s"] = &DeathKnightTriggerFactoryInternal::icy_touch_3s;
creators["dd cd and icy touch 8s"] = &DeathKnightTriggerFactoryInternal::dd_cd_and_icy_touch_8s; creators["dd cd and icy touch 3s"] = &DeathKnightTriggerFactoryInternal::dd_cd_and_icy_touch_3s;
creators["death coil"] = &DeathKnightTriggerFactoryInternal::death_coil; creators["death coil"] = &DeathKnightTriggerFactoryInternal::death_coil;
creators["icy touch on attacker"] = &DeathKnightTriggerFactoryInternal::icy_touch_on_attacker; creators["icy touch on attacker"] = &DeathKnightTriggerFactoryInternal::icy_touch_on_attacker;
creators["improved icy talons"] = &DeathKnightTriggerFactoryInternal::improved_icy_talons; creators["improved icy talons"] = &DeathKnightTriggerFactoryInternal::improved_icy_talons;
creators["plague strike"] = &DeathKnightTriggerFactoryInternal::plague_strike; creators["plague strike"] = &DeathKnightTriggerFactoryInternal::plague_strike;
creators["plague strike 8s"] = &DeathKnightTriggerFactoryInternal::plague_strike_8s; creators["plague strike 3s"] = &DeathKnightTriggerFactoryInternal::plague_strike_3s;
creators["dd cd and plague strike 8s"] = &DeathKnightTriggerFactoryInternal::dd_cd_and_plague_strike_8s; creators["dd cd and plague strike 3s"] = &DeathKnightTriggerFactoryInternal::dd_cd_and_plague_strike_3s;
creators["horn of winter"] = &DeathKnightTriggerFactoryInternal::horn_of_winter; creators["horn of winter"] = &DeathKnightTriggerFactoryInternal::horn_of_winter;
creators["mind freeze"] = &DeathKnightTriggerFactoryInternal::mind_freeze; creators["mind freeze"] = &DeathKnightTriggerFactoryInternal::mind_freeze;
creators["mind freeze on enemy healer"] = &DeathKnightTriggerFactoryInternal::mind_freeze_on_enemy_healer; 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 blood rune"] = &DeathKnightTriggerFactoryInternal::high_blood_rune;
creators["high frost rune"] = &DeathKnightTriggerFactoryInternal::high_frost_rune; creators["high frost rune"] = &DeathKnightTriggerFactoryInternal::high_frost_rune;
creators["high unholy rune"] = &DeathKnightTriggerFactoryInternal::high_unholy_rune; creators["high unholy rune"] = &DeathKnightTriggerFactoryInternal::high_unholy_rune;
creators["no rune"] = &DeathKnightTriggerFactoryInternal::no_rune;
creators["freezing fog"] = &DeathKnightTriggerFactoryInternal::freezing_fog; creators["freezing fog"] = &DeathKnightTriggerFactoryInternal::freezing_fog;
creators["no desolation"] = &DeathKnightTriggerFactoryInternal::no_desolation; creators["no desolation"] = &DeathKnightTriggerFactoryInternal::no_desolation;
creators["dd cd and no desolation"] = &DeathKnightTriggerFactoryInternal::dd_cd_and_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* pestilence_glyph(PlayerbotAI* botAI) { return new PestilenceGlyphTrigger(botAI); }
static Trigger* blood_strike(PlayerbotAI* botAI) { return new BloodStrikeTrigger(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(PlayerbotAI* botAI) { return new PlagueStrikeDebuffTrigger(botAI); }
static Trigger* plague_strike_8s(PlayerbotAI* botAI) { return new PlagueStrike8sDebuffTrigger(botAI); } static Trigger* plague_strike_3s(PlayerbotAI* botAI) { return new PlagueStrike3sDebuffTrigger(botAI); }
static Trigger* dd_cd_and_plague_strike_8s(PlayerbotAI* botAI) { return new TwoTriggers(botAI, "death and decay cooldown", "plague strike 8s"); } 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) static Trigger* plague_strike_on_attacker(PlayerbotAI* botAI)
{ {
return new PlagueStrikeDebuffOnAttackerTrigger(botAI); return new PlagueStrikeDebuffOnAttackerTrigger(botAI);
} }
static Trigger* icy_touch(PlayerbotAI* botAI) { return new IcyTouchDebuffTrigger(botAI); } static Trigger* icy_touch(PlayerbotAI* botAI) { return new IcyTouchDebuffTrigger(botAI); }
static Trigger* icy_touch_8s(PlayerbotAI* botAI) { return new IcyTouch8sDebuffTrigger(botAI); } static Trigger* icy_touch_3s(PlayerbotAI* botAI) { return new IcyTouch3sDebuffTrigger(botAI); }
static Trigger* dd_cd_and_icy_touch_8s(PlayerbotAI* botAI) { return new TwoTriggers(botAI, "death and decay cooldown", "icy touch 8s"); } 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* death_coil(PlayerbotAI* botAI) { return new DeathCoilTrigger(botAI); }
static Trigger* icy_touch_on_attacker(PlayerbotAI* botAI) { return new IcyTouchDebuffOnAttackerTrigger(botAI); } static Trigger* icy_touch_on_attacker(PlayerbotAI* botAI) { return new IcyTouchDebuffOnAttackerTrigger(botAI); }
static Trigger* improved_icy_talons(PlayerbotAI* botAI) { return new ImprovedIcyTalonsTrigger(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_blood_rune(PlayerbotAI* botAI) { return new HighBloodRuneTrigger(botAI); }
static Trigger* high_frost_rune(PlayerbotAI* botAI) { return new HighFrostRuneTrigger(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* 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* freezing_fog(PlayerbotAI* botAI) { return new FreezingFogTrigger(botAI); }
static Trigger* no_desolation(PlayerbotAI* botAI) { return new DesolationTrigger(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"); } static Trigger* dd_cd_and_no_desolation(PlayerbotAI* botAI) { return new TwoTriggers(botAI, "death and decay cooldown", "no desolation"); }

View File

@@ -37,20 +37,32 @@ bool PestilenceGlyphTrigger::IsActive()
return false; return false;
} }
// Based on runeSlotTypes
bool HighBloodRuneTrigger::IsActive() bool HighBloodRuneTrigger::IsActive()
{ {
return !bot->GetRuneCooldown(0) && !bot->GetRuneCooldown(1); return bot->GetRuneCooldown(0) <= 2000 && bot->GetRuneCooldown(1) <= 2000;
} }
bool HighFrostRuneTrigger::IsActive() bool HighFrostRuneTrigger::IsActive()
{ {
return !bot->GetRuneCooldown(2) && !bot->GetRuneCooldown(3); return bot->GetRuneCooldown(4) <= 2000 && bot->GetRuneCooldown(5) <= 2000;
} }
bool HighUnholyRuneTrigger::IsActive() 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() bool DesolationTrigger::IsActive()
{ {
return bot->HasAura(66817) && BuffTrigger::IsActive(); return bot->HasAura(66817) && BuffTrigger::IsActive();
@@ -62,5 +74,5 @@ bool DeathAndDecayCooldownTrigger::IsActive()
if (!spellId) if (!spellId)
return true; return true;
return bot->GetSpellCooldownDelay(spellId) >= 3000; return bot->GetSpellCooldownDelay(spellId) >= 2000;
} }

View File

@@ -20,10 +20,10 @@ public:
PlagueStrikeDebuffTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "blood plague", 1, true, .0f) {} PlagueStrikeDebuffTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "blood plague", 1, true, .0f) {}
}; };
class PlagueStrike8sDebuffTrigger : public DebuffTrigger class PlagueStrike3sDebuffTrigger : public DebuffTrigger
{ {
public: 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"); // DEBUFF_CHECKISOWNER_TRIGGER(IcyTouchDebuffTrigger, "frost fever");
@@ -33,10 +33,10 @@ public:
IcyTouchDebuffTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "frost fever", 1, true, .0f) {} IcyTouchDebuffTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "frost fever", 1, true, .0f) {}
}; };
class IcyTouch8sDebuffTrigger : public DebuffTrigger class IcyTouch3sDebuffTrigger : public DebuffTrigger
{ {
public: 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"); BUFF_TRIGGER(UnbreakableArmorTrigger, "unbreakable armor");
@@ -165,6 +165,13 @@ public:
bool IsActive() override; bool IsActive() override;
}; };
class NoRuneTrigger : public Trigger
{
public:
NoRuneTrigger(PlayerbotAI* botAI) : Trigger(botAI, "no rune") {}
bool IsActive() override;
};
class FreezingFogTrigger : public HasAuraTrigger class FreezingFogTrigger : public HasAuraTrigger
{ {
public: public:

View File

@@ -80,7 +80,7 @@ NextAction** UnholyDKStrategy::getDefaultActions()
return NextAction::array( return NextAction::array(
0, new NextAction("death and decay", ACTION_HIGH + 5), 0, new NextAction("death and decay", ACTION_HIGH + 5),
new NextAction("summon gargoyle", ACTION_DEFAULT + 0.4f), 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("horn of winter", ACTION_DEFAULT + 0.2f),
new NextAction("death coil", ACTION_DEFAULT + 0.1f), new NextAction("death coil", ACTION_DEFAULT + 0.1f),
new NextAction("melee", ACTION_DEFAULT), nullptr); new NextAction("melee", ACTION_DEFAULT), nullptr);
@@ -93,8 +93,8 @@ void UnholyDKStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
"death and decay cooldown", NextAction::array(0, "death and decay cooldown", NextAction::array(0,
new NextAction("ghoul frenzy", ACTION_DEFAULT + 0.9f), new NextAction("ghoul frenzy", ACTION_DEFAULT + 0.9f),
new NextAction("scourge strike", ACTION_DEFAULT + 0.8f), new NextAction("scourge strike", ACTION_DEFAULT + 0.8f),
new NextAction("blood boil", ACTION_DEFAULT + 0.7f), new NextAction("icy touch", ACTION_DEFAULT + 0.7f),
new NextAction("icy touch", ACTION_DEFAULT + 0.6f), new NextAction("blood strike", ACTION_DEFAULT + 0.6f),
new NextAction("plague strike", ACTION_DEFAULT + 0.5f), new NextAction("plague strike", ACTION_DEFAULT + 0.5f),
nullptr))); nullptr)));
@@ -111,24 +111,26 @@ void UnholyDKStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
new NextAction("icy touch", ACTION_NORMAL + 3), nullptr))); new NextAction("icy touch", ACTION_NORMAL + 3), nullptr)));
triggers.push_back(new TriggerNode( triggers.push_back(new TriggerNode(
"high unholy rune", NextAction::array(0, "high blood rune", NextAction::array(0, new NextAction("blood strike", ACTION_NORMAL + 2), nullptr)));
new NextAction("plague strike", ACTION_NORMAL + 2), nullptr)));
triggers.push_back(new TriggerNode( 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( 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( 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("often", NextAction::array(0, new NextAction(, ACTION_NORMAL + 2), nullptr)));
triggers.push_back(new TriggerNode( triggers.push_back(new TriggerNode(
"army of the dead", NextAction::array(0, new NextAction("army of the dead", ACTION_HIGH + 6), nullptr))); "army of the dead", NextAction::array(0, new NextAction("army of the dead", ACTION_HIGH + 6), nullptr)));
triggers.push_back( 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) void UnholyDKAoeStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)

View File

@@ -41,8 +41,11 @@ DpsHunterStrategy::DpsHunterStrategy(PlayerbotAI* botAI) : GenericHunterStrategy
NextAction** DpsHunterStrategy::getDefaultActions() NextAction** DpsHunterStrategy::getDefaultActions()
{ {
return NextAction::array( return NextAction::array(
0, new NextAction("kill shot", ACTION_DEFAULT + 0.8f), new NextAction("chimera shot", ACTION_DEFAULT + 0.7f), 0,
new NextAction("explosive shot", ACTION_DEFAULT + 0.6f), new NextAction("aimed shot", ACTION_DEFAULT + 0.5f), 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("silencing shot", ACTION_DEFAULT + 0.4f),
new NextAction("kill command", ACTION_DEFAULT + 0.3f), new NextAction("kill command", ACTION_DEFAULT + 0.3f),
// new NextAction("arcane shot", ACTION_DEFAULT + 0.2f), // new NextAction("arcane shot", ACTION_DEFAULT + 0.2f),
@@ -55,7 +58,7 @@ void DpsHunterStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
GenericHunterStrategy::InitTriggers(triggers); GenericHunterStrategy::InitTriggers(triggers);
triggers.push_back( 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( triggers.push_back(
new TriggerNode("low mana", NextAction::array(0, new NextAction("viper sting", 23.0f), nullptr))); new TriggerNode("low mana", NextAction::array(0, new NextAction("viper sting", 23.0f), nullptr)));
triggers.push_back( triggers.push_back(

View File

@@ -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("often", NextAction::array(0, new NextAction("apply oil", 1.0f), nullptr)));
triggers.push_back( triggers.push_back(
new TriggerNode("low ammo", NextAction::array(0, new NextAction("say::low ammo", ACTION_NORMAL), nullptr))); 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", // 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 // 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))); // TriggerNode("has ammo", NextAction::array(0, new NextAction("switch to ranged", ACTION_NORMAL), nullptr)));

View File

@@ -75,6 +75,7 @@ public:
creators["aspect of the wild"] = &HunterTriggerFactoryInternal::aspect_of_the_wild; creators["aspect of the wild"] = &HunterTriggerFactoryInternal::aspect_of_the_wild;
creators["aspect of the viper"] = &HunterTriggerFactoryInternal::aspect_of_the_viper; creators["aspect of the viper"] = &HunterTriggerFactoryInternal::aspect_of_the_viper;
creators["trueshot aura"] = &HunterTriggerFactoryInternal::trueshot_aura; creators["trueshot aura"] = &HunterTriggerFactoryInternal::trueshot_aura;
creators["no track"] = &HunterTriggerFactoryInternal::no_track;
creators["serpent sting on attacker"] = &HunterTriggerFactoryInternal::serpent_sting_on_attacker; creators["serpent sting on attacker"] = &HunterTriggerFactoryInternal::serpent_sting_on_attacker;
creators["pet not happy"] = &HunterTriggerFactoryInternal::pet_not_happy; creators["pet not happy"] = &HunterTriggerFactoryInternal::pet_not_happy;
creators["concussive shot on snare target"] = &HunterTriggerFactoryInternal::concussive_shot_on_snare_target; 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* pet_not_happy(PlayerbotAI* botAI) { return new HunterPetNotHappy(botAI); }
static Trigger* serpent_sting_on_attacker(PlayerbotAI* botAI) { return new SerpentStingOnAttackerTrigger(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* 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* aspect_of_the_viper(PlayerbotAI* botAI) { return new HunterAspectOfTheViperTrigger(botAI); }
static Trigger* black_arrow(PlayerbotAI* botAI) { return new BlackArrowTrigger(botAI); } static Trigger* black_arrow(PlayerbotAI* botAI) { return new BlackArrowTrigger(botAI); }
static Trigger* NoStings(PlayerbotAI* botAI) { return new HunterNoStingsActiveTrigger(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 pack"] = &HunterAiObjectContextInternal::aspect_of_the_pack;
creators["aspect of the cheetah"] = &HunterAiObjectContextInternal::aspect_of_the_cheetah; creators["aspect of the cheetah"] = &HunterAiObjectContextInternal::aspect_of_the_cheetah;
creators["trueshot aura"] = &HunterAiObjectContextInternal::trueshot_aura; creators["trueshot aura"] = &HunterAiObjectContextInternal::trueshot_aura;
creators["track humanoids"] = &HunterAiObjectContextInternal::track_humanoids;
creators["feign death"] = &HunterAiObjectContextInternal::feign_death; creators["feign death"] = &HunterAiObjectContextInternal::feign_death;
creators["wing clip"] = &HunterAiObjectContextInternal::wing_clip; creators["wing clip"] = &HunterAiObjectContextInternal::wing_clip;
creators["raptor strike"] = &HunterAiObjectContextInternal::raptor_strike; creators["raptor strike"] = &HunterAiObjectContextInternal::raptor_strike;
@@ -182,6 +185,7 @@ private:
static Action* feed_pet(PlayerbotAI* botAI) { return new FeedPetAction(botAI); } static Action* feed_pet(PlayerbotAI* botAI) { return new FeedPetAction(botAI); }
static Action* feign_death(PlayerbotAI* botAI) { return new CastFeignDeathAction(botAI); } static Action* feign_death(PlayerbotAI* botAI) { return new CastFeignDeathAction(botAI); }
static Action* trueshot_aura(PlayerbotAI* botAI) { return new CastTrueshotAuraAction(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* auto_shot(PlayerbotAI* botAI) { return new CastAutoShotAction(botAI); }
static Action* aimed_shot(PlayerbotAI* botAI) { return new CastAimedShotAction(botAI); } static Action* aimed_shot(PlayerbotAI* botAI) { return new CastAimedShotAction(botAI); }
static Action* chimera_shot(PlayerbotAI* botAI) { return new CastChimeraShotAction(botAI); } static Action* chimera_shot(PlayerbotAI* botAI) { return new CastChimeraShotAction(botAI); }

View File

@@ -56,7 +56,7 @@ bool HunterPetNotHappy::IsActive()
bool HunterAspectOfTheViperTrigger::IsActive() bool HunterAspectOfTheViperTrigger::IsActive()
{ {
return SpellTrigger::IsActive() && !botAI->HasAura(spell, GetTarget()) && 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 && (target->GetVictim() == bot &&
sServerFacade->IsDistanceLessOrEqualThan(AI_VALUE2(float, "distance", "current target"), 8.0f)); 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);
}

View File

@@ -101,10 +101,18 @@ public:
TrueshotAuraTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "trueshot aura") {} 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 class SerpentStingOnAttackerTrigger : public DebuffOnAttackerTrigger
{ {
public: public:
SerpentStingOnAttackerTrigger(PlayerbotAI* botAI) : DebuffOnAttackerTrigger(botAI, "serpent sting", true) {} SerpentStingOnAttackerTrigger(PlayerbotAI* botAI) : DebuffOnAttackerTrigger(botAI, "serpent sting", true) {}
bool IsActive() override;
}; };
BEGIN_TRIGGER(HunterPetNotHappy, Trigger) BEGIN_TRIGGER(HunterPetNotHappy, Trigger)

View File

@@ -31,7 +31,7 @@ private:
{ {
return new ActionNode("arcane barrage", return new ActionNode("arcane barrage",
/*P*/ nullptr, /*P*/ nullptr,
/*A*/ NextAction::array(0, new NextAction("arcane missiles"), nullptr), /*A*/ nullptr,
/*C*/ nullptr); /*C*/ nullptr);
} }
@@ -59,8 +59,10 @@ ArcaneMageStrategy::ArcaneMageStrategy(PlayerbotAI* botAI) : GenericMageStrategy
NextAction** ArcaneMageStrategy::getDefaultActions() NextAction** ArcaneMageStrategy::getDefaultActions()
{ {
return NextAction::array(0, new NextAction("arcane blast", ACTION_DEFAULT + 0.1f), return NextAction::array(0, new NextAction("arcane blast", ACTION_DEFAULT + 0.3f),
new NextAction("shoot", ACTION_DEFAULT), NULL); // 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) void ArcaneMageStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)

View File

@@ -9,7 +9,8 @@
NextAction** FireMageStrategy::getDefaultActions() 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); 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))); new TriggerNode("hot streak", NextAction::array(0, new NextAction("pyroblast", 25.0f), nullptr)));
triggers.push_back( triggers.push_back(
new TriggerNode("combustion", NextAction::array(0, new NextAction("combustion", 50.0f), nullptr))); 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 // triggers.push_back(new TriggerNode("enemy too close for spell", NextAction::array(0, new NextAction("dragon's
// breath", 70.0f), nullptr))); // breath", 70.0f), nullptr)));
} }
@@ -30,7 +33,10 @@ void FireMageStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
void FireMageAoeStrategy::InitTriggers(std::vector<TriggerNode*>& triggers) void FireMageAoeStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{ {
triggers.push_back( triggers.push_back(
new TriggerNode("medium aoe", NextAction::array(0, new NextAction("flamestrike", 20.0f), nullptr))); new TriggerNode("medium aoe", NextAction::array(0,
triggers.push_back( new NextAction("dragon's breath", 24.0f),
new TriggerNode("living bomb", NextAction::array(0, new NextAction("living bomb", 25.0f), nullptr))); 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)));
} }

View File

@@ -77,7 +77,7 @@ void FrostMageStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
triggers.push_back( triggers.push_back(
new TriggerNode("has pet", NextAction::array(0, new NextAction("toggle pet spell", ACTION_HIGH + 1), nullptr))); new TriggerNode("has pet", NextAction::array(0, new NextAction("toggle pet spell", ACTION_HIGH + 1), nullptr)));
triggers.push_back( 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( triggers.push_back(new TriggerNode(
"brain freeze", NextAction::array(0, new NextAction("frostfire bolt", ACTION_NORMAL + 3), nullptr))); "brain freeze", NextAction::array(0, new NextAction("frostfire bolt", ACTION_NORMAL + 3), nullptr)));

View File

@@ -54,6 +54,9 @@ void GenericMageNonCombatStrategy::InitTriggers(std::vector<TriggerNode*>& trigg
triggers.push_back( triggers.push_back(
new TriggerNode("arcane intellect", NextAction::array(0, new NextAction("arcane intellect", 21.0f), nullptr))); 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), // 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 // nullptr))); triggers.push_back(new TriggerNode("no food", NextAction::array(0, new NextAction("conjure
// food", 15.0f), nullptr))); // food", 15.0f), nullptr)));

View File

@@ -59,7 +59,7 @@ private:
{ {
return new ActionNode("fire blast", return new ActionNode("fire blast",
/*P*/ nullptr, /*P*/ nullptr,
/*A*/ NextAction::array(0, new NextAction("scorch"), nullptr), /*A*/ nullptr,
/*C*/ nullptr); /*C*/ nullptr);
} }
@@ -115,16 +115,16 @@ private:
{ {
return new ActionNode("dragon's breath", return new ActionNode("dragon's breath",
/*P*/ nullptr, /*P*/ nullptr,
/*A*/ NextAction::array(0, new NextAction("blast wave"), nullptr), /*A*/ nullptr,
/*C*/ NextAction::array(0, new NextAction("flamestrike", 71.0f), nullptr)); /*C*/ nullptr);
} }
static ActionNode* blast_wave([[maybe_unused]] PlayerbotAI* botAI) static ActionNode* blast_wave([[maybe_unused]] PlayerbotAI* botAI)
{ {
return new ActionNode("blast wave", return new ActionNode("blast wave",
/*P*/ nullptr, /*P*/ nullptr,
/*A*/ NextAction::array(0, new NextAction("frost nova"), nullptr), /*A*/ nullptr,
/*C*/ NextAction::array(0, new NextAction("flamestrike", 71.0f), nullptr)); /*C*/ nullptr);
} }
static ActionNode* remove_curse([[maybe_unused]] PlayerbotAI* botAI) 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("icy veins", NextAction::array(0, new NextAction("icy veins", 50.0f), nullptr)));
triggers.push_back( triggers.push_back(
new TriggerNode("presence of mind", NextAction::array(0, new NextAction("presence of mind", 42.0f), nullptr))); 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), // triggers.push_back(new TriggerNode("arcane power", NextAction::array(0, new NextAction("arcane power", 41.0f), nullptr)));
// nullptr)));
triggers.push_back( triggers.push_back(
new TriggerNode("mirror image", NextAction::array(0, new NextAction("mirror image", 41.0f), nullptr))); new TriggerNode("mirror image", NextAction::array(0, new NextAction("mirror image", 41.0f), nullptr)));
} }

View File

@@ -5,13 +5,18 @@
#include "MageActions.h" #include "MageActions.h"
#include "PlayerbotAIConfig.h"
#include "Playerbots.h" #include "Playerbots.h"
#include "ServerFacade.h" #include "ServerFacade.h"
#include "SharedDefines.h"
Value<Unit*>* CastPolymorphAction::GetTargetValue() { return context->GetValue<Unit*>("cc target", getName()); } Value<Unit*>* CastPolymorphAction::GetTargetValue() { return context->GetValue<Unit*>("cc target", getName()); }
bool CastFrostNovaAction::isUseful() 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); 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); bool targetClose = sServerFacade->IsDistanceLessOrEqualThan(AI_VALUE2(float, "distance", GetTargetName()), 10.f);
return facingTarget && targetClose; 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;
}

View File

@@ -57,10 +57,10 @@ public:
CastPyroblastAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "pyroblast") {} CastPyroblastAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "pyroblast") {}
}; };
class CastFlamestrikeAction : public CastSpellAction class CastFlamestrikeAction : public CastDebuffSpellAction
{ {
public: public:
CastFlamestrikeAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "flamestrike") {} CastFlamestrikeAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "flamestrike", true, 0.0f) {}
ActionThreatType getThreatType() override { return ActionThreatType::Aoe; } ActionThreatType getThreatType() override { return ActionThreatType::Aoe; }
}; };
@@ -243,11 +243,18 @@ public:
CastLivingBombAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "living bomb", true) {} 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 class CastDragonsBreathAction : public CastSpellAction
{ {
public: public:
CastDragonsBreathAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "dragon's breath") {} CastDragonsBreathAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "dragon's breath") {}
ActionThreatType getThreatType() override { return ActionThreatType::Aoe; } ActionThreatType getThreatType() override { return ActionThreatType::Aoe; }
bool isUseful() override;
}; };
class CastBlastWaveAction : public CastSpellAction class CastBlastWaveAction : public CastSpellAction
@@ -255,6 +262,7 @@ class CastBlastWaveAction : public CastSpellAction
public: public:
CastBlastWaveAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "blast wave") {} CastBlastWaveAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "blast wave") {}
ActionThreatType getThreatType() override { return ActionThreatType::Aoe; } ActionThreatType getThreatType() override { return ActionThreatType::Aoe; }
bool isUseful() override;
}; };
class CastInvisibilityAction : public CastBuffSpellAction class CastInvisibilityAction : public CastBuffSpellAction
@@ -294,4 +302,11 @@ public:
CastMirrorImageAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "mirror image") {} CastMirrorImageAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "mirror image") {}
}; };
class CastFocusMagicOnPartyAction : public CastSpellAction
{
public:
CastFocusMagicOnPartyAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "focus magic") {}
Unit* GetTarget() override;
};
#endif #endif

View File

@@ -108,6 +108,7 @@ public:
creators["mirror image"] = &MageTriggerFactoryInternal::mirror_image; creators["mirror image"] = &MageTriggerFactoryInternal::mirror_image;
creators["frost nova on target"] = &MageTriggerFactoryInternal::frost_nova_on_target; creators["frost nova on target"] = &MageTriggerFactoryInternal::frost_nova_on_target;
creators["frostbite on target"] = &MageTriggerFactoryInternal::frostbite_on_target; creators["frostbite on target"] = &MageTriggerFactoryInternal::frostbite_on_target;
creators["no focus magic"] = &MageTriggerFactoryInternal::no_focus_magic;
} }
private: private:
@@ -141,6 +142,7 @@ private:
static Trigger* mirror_image(PlayerbotAI* botAI) { return new MirrorImageTrigger(botAI); } static Trigger* mirror_image(PlayerbotAI* botAI) { return new MirrorImageTrigger(botAI); }
static Trigger* frost_nova_on_target(PlayerbotAI* botAI) { return new FrostNovaOnTargetTrigger(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* 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> class MageAiObjectContextInternal : public NamedObjectContext<Action>
@@ -184,6 +186,7 @@ public:
creators["polymorph"] = &MageAiObjectContextInternal::polymorph; creators["polymorph"] = &MageAiObjectContextInternal::polymorph;
creators["spellsteal"] = &MageAiObjectContextInternal::spellsteal; creators["spellsteal"] = &MageAiObjectContextInternal::spellsteal;
creators["living bomb"] = &MageAiObjectContextInternal::living_bomb; creators["living bomb"] = &MageAiObjectContextInternal::living_bomb;
creators["living bomb on attackers"] = &MageAiObjectContextInternal::living_bomb_on_attackers;
creators["dragon's breath"] = &MageAiObjectContextInternal::dragons_breath; creators["dragon's breath"] = &MageAiObjectContextInternal::dragons_breath;
creators["blast wave"] = &MageAiObjectContextInternal::blast_wave; creators["blast wave"] = &MageAiObjectContextInternal::blast_wave;
creators["invisibility"] = &MageAiObjectContextInternal::invisibility; creators["invisibility"] = &MageAiObjectContextInternal::invisibility;
@@ -195,6 +198,7 @@ public:
creators["fire ward"] = &MageAiObjectContextInternal::fire_ward; creators["fire ward"] = &MageAiObjectContextInternal::fire_ward;
creators["frost ward"] = &MageAiObjectContextInternal::frost_ward; creators["frost ward"] = &MageAiObjectContextInternal::frost_ward;
creators["mirror image"] = &MageAiObjectContextInternal::mirror_image; creators["mirror image"] = &MageAiObjectContextInternal::mirror_image;
creators["focus magic on party"] = &MageAiObjectContextInternal::focus_magic_on_party;
} }
private: private:
@@ -242,6 +246,7 @@ private:
static Action* polymorph(PlayerbotAI* botAI) { return new CastPolymorphAction(botAI); } static Action* polymorph(PlayerbotAI* botAI) { return new CastPolymorphAction(botAI); }
static Action* spellsteal(PlayerbotAI* botAI) { return new CastSpellstealAction(botAI); } static Action* spellsteal(PlayerbotAI* botAI) { return new CastSpellstealAction(botAI); }
static Action* living_bomb(PlayerbotAI* botAI) { return new CastLivingBombAction(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* dragons_breath(PlayerbotAI* botAI) { return new CastDragonsBreathAction(botAI); }
static Action* blast_wave(PlayerbotAI* botAI) { return new CastBlastWaveAction(botAI); } static Action* blast_wave(PlayerbotAI* botAI) { return new CastBlastWaveAction(botAI); }
static Action* invisibility(PlayerbotAI* botAI) { return new CastInvisibilityAction(botAI); } static Action* invisibility(PlayerbotAI* botAI) { return new CastInvisibilityAction(botAI); }
@@ -251,6 +256,7 @@ private:
return new CastCounterspellOnEnemyHealerAction(botAI); return new CastCounterspellOnEnemyHealerAction(botAI);
} }
static Action* mirror_image(PlayerbotAI* botAI) { return new CastMirrorImageAction(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) MageAiObjectContext::MageAiObjectContext(PlayerbotAI* botAI) : AiObjectContext(botAI)

View File

@@ -33,6 +33,17 @@ bool FingersOfFrostSingleTrigger::IsActive()
return (aura && aura->GetCharges() == 1); 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() bool FrostNovaOnTargetTrigger::IsActive()
{ {
Unit* target = GetTarget(); Unit* target = GetTarget();
@@ -52,3 +63,24 @@ bool FrostbiteOnTargetTrigger::IsActive()
} }
return botAI->HasAura(spell, target); 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;
}

View File

@@ -171,6 +171,7 @@ class ArcaneBlastStackTrigger : public HasAuraStackTrigger
{ {
public: public:
ArcaneBlastStackTrigger(PlayerbotAI* botAI) : HasAuraStackTrigger(botAI, "arcane blast", 3, 1) {} ArcaneBlastStackTrigger(PlayerbotAI* botAI) : HasAuraStackTrigger(botAI, "arcane blast", 3, 1) {}
bool IsActive() override;
}; };
class MirrorImageTrigger : public BoostTrigger class MirrorImageTrigger : public BoostTrigger
@@ -193,4 +194,11 @@ public:
bool IsActive() override; bool IsActive() override;
}; };
class NoFocusMagicTrigger : public Trigger
{
public:
NoFocusMagicTrigger(PlayerbotAI* botAI) : Trigger(botAI, "no focus magic") {}
bool IsActive() override;
};
#endif #endif

View File

@@ -15,10 +15,10 @@ ShadowPriestStrategy::ShadowPriestStrategy(PlayerbotAI* botAI) : GenericPriestSt
NextAction** ShadowPriestStrategy::getDefaultActions() NextAction** ShadowPriestStrategy::getDefaultActions()
{ {
return NextAction::array(0, new NextAction("mind blast", ACTION_DEFAULT + 0.2f), return NextAction::array(0, new NextAction("mind blast", ACTION_DEFAULT + 0.3f),
// new NextAction("shadow word: death", 12.0f), new NextAction("mind flay", ACTION_DEFAULT + 0.2f),
new NextAction("mind flay", ACTION_DEFAULT + 0.1f), new NextAction("shadow word: death", ACTION_DEFAULT + 0.1f), // cast during movement
new NextAction("shoot", ACTION_DEFAULT), NULL); new NextAction("shoot", ACTION_DEFAULT), nullptr);
} }
void ShadowPriestStrategy::InitTriggers(std::vector<TriggerNode*>& triggers) void ShadowPriestStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)

View File

@@ -41,7 +41,9 @@ CasterShamanStrategy::CasterShamanStrategy(PlayerbotAI* botAI) : GenericShamanSt
NextAction** CasterShamanStrategy::getDefaultActions() NextAction** CasterShamanStrategy::getDefaultActions()
{ {
return NextAction::array(0, new NextAction("lava burst", ACTION_DEFAULT + 0.2f), 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) void CasterShamanStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)

View File

@@ -5,6 +5,7 @@
#include "ShamanTriggers.h" #include "ShamanTriggers.h"
#include "ItemTemplate.h"
#include "Playerbots.h" #include "Playerbots.h"
/* /*
@@ -46,8 +47,12 @@ bool MainHandWeaponNoImbueTrigger::IsActive()
bool OffHandWeaponNoImbueTrigger::IsActive() bool OffHandWeaponNoImbueTrigger::IsActive()
{ {
Item* const itemForSpell = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND); Item* const itemForSpell = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
if (!itemForSpell || itemForSpell->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT) || if (!itemForSpell)
itemForSpell->GetTemplate()->InventoryType != INVTYPE_WEAPON) 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 false;
return true; return true;
} }

View File

@@ -302,7 +302,7 @@ public:
class FlameShockTrigger : public DebuffTrigger class FlameShockTrigger : public DebuffTrigger
{ {
public: 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 class WrathOfAirTotemTrigger : public TotemTrigger

View File

@@ -618,8 +618,8 @@ public:
{ {
} }
std::string const GetTargetName() { return "self target"; } std::string const GetTargetName() override { return "self target"; }
virtual bool IsActive(); bool IsActive() override;
private: private:
int stack; int stack;

View File

@@ -36,7 +36,7 @@ float EstimatedGroupDpsValue::Calculate()
if (member == bot) // calculated if (member == bot) // calculated
continue; continue;
if (!member || !member->IsInWorld()) if (!member || !member->IsInWorld() || !member->IsAlive())
continue; continue;
if (member->GetMapId() != bot->GetMapId()) if (member->GetMapId() != bot->GetMapId())

View File

@@ -49,8 +49,8 @@ DpsWarlockStrategy::DpsWarlockStrategy(PlayerbotAI* botAI) : GenericWarlockStrat
NextAction** DpsWarlockStrategy::getDefaultActions() NextAction** DpsWarlockStrategy::getDefaultActions()
{ {
return NextAction::array( return NextAction::array(
0, new NextAction("haunt", ACTION_DEFAULT + 0.3f), new NextAction("demonic empowerment", ACTION_DEFAULT + 0.2f), 0, new NextAction("haunt", ACTION_DEFAULT + 0.4f), new NextAction("demonic empowerment", ACTION_DEFAULT + 0.3f),
new NextAction("shadow bolt", ACTION_DEFAULT + 0.1f), new NextAction("shoot", ACTION_DEFAULT), nullptr); new NextAction("shadow bolt", ACTION_DEFAULT + 0.2f), new NextAction("shoot", ACTION_DEFAULT), nullptr);
} }
void DpsWarlockStrategy::InitTriggers(std::vector<TriggerNode*>& triggers) 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))); 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( triggers.push_back(
new TriggerNode("metamorphosis", NextAction::array(0, new NextAction("metamorphosis", 20.0f), NULL))); 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) void DpsAoeWarlockStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{ {
triggers.push_back( triggers.push_back(
new TriggerNode("medium aoe", NextAction::array(0, new NextAction("seed of corruption", 39.0f), new TriggerNode("medium aoe", NextAction::array(0, new NextAction("seed of corruption", 33.0f),
new NextAction("seed of corruption on attacker", 38.0f), new NextAction("seed of corruption on attacker", 32.0f),
new NextAction("rain of fire", 37.0f), nullptr))); new NextAction("rain of fire", 31.0f), nullptr)));
triggers.push_back(new TriggerNode("corruption on attacker", triggers.push_back(new TriggerNode("corruption on attacker",
NextAction::array(0, new NextAction("corruption on attacker", 27.0f), nullptr))); NextAction::array(0, new NextAction("corruption on attacker", 27.0f), nullptr)));
triggers.push_back( triggers.push_back(

View File

@@ -18,7 +18,7 @@ Value<Unit*>* CastFearOnCcAction::GetTargetValue() { return context->GetValue<Un
bool CastFearOnCcAction::Execute(Event event) { return botAI->CastSpell("fear", GetTarget()); } 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; } bool CastFearOnCcAction::isUseful() { return true; }

View File

@@ -6,6 +6,7 @@
#include "WarlockAiObjectContext.h" #include "WarlockAiObjectContext.h"
#include "DpsWarlockStrategy.h" #include "DpsWarlockStrategy.h"
#include "GenericTriggers.h"
#include "GenericWarlockNonCombatStrategy.h" #include "GenericWarlockNonCombatStrategy.h"
#include "NamedObjectContext.h" #include "NamedObjectContext.h"
#include "Playerbots.h" #include "Playerbots.h"
@@ -98,6 +99,7 @@ public:
creators["unstable affliction on attacker"] = &WarlockTriggerFactoryInternal::unstable_affliction_on_attacker; creators["unstable affliction on attacker"] = &WarlockTriggerFactoryInternal::unstable_affliction_on_attacker;
creators["haunt"] = &WarlockTriggerFactoryInternal::haunt; creators["haunt"] = &WarlockTriggerFactoryInternal::haunt;
creators["decimation"] = &WarlockTriggerFactoryInternal::decimation; creators["decimation"] = &WarlockTriggerFactoryInternal::decimation;
creators["life tap glyph buff"] = &WarlockTriggerFactoryInternal::life_tap_glyph_buff;
creators["molten core"] = &WarlockTriggerFactoryInternal::molten_core; creators["molten core"] = &WarlockTriggerFactoryInternal::molten_core;
creators["metamorphosis"] = &WarlockTriggerFactoryInternal::metamorphosis; creators["metamorphosis"] = &WarlockTriggerFactoryInternal::metamorphosis;
} }
@@ -131,6 +133,7 @@ private:
} }
static Trigger* haunt(PlayerbotAI* ai) { return new HauntTrigger(ai); } static Trigger* haunt(PlayerbotAI* ai) { return new HauntTrigger(ai); }
static Trigger* decimation(PlayerbotAI* ai) { return new DecimationTrigger(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* molten_core(PlayerbotAI* ai) { return new MoltenCoreTrigger(ai); }
static Trigger* metamorphosis(PlayerbotAI* ai) { return new MetamorphosisTrigger(ai); } static Trigger* metamorphosis(PlayerbotAI* ai) { return new MetamorphosisTrigger(ai); }
}; };

View File

@@ -5,6 +5,7 @@
#include "WarlockTriggers.h" #include "WarlockTriggers.h"
#include "GenericTriggers.h"
#include "Playerbots.h" #include "Playerbots.h"
bool DemonArmorTrigger::IsActive() bool DemonArmorTrigger::IsActive()
@@ -44,4 +45,13 @@ bool DecimationTrigger::IsActive()
{ {
Aura* aura = botAI->GetAura(getName(), GetTarget(), false, true); Aura* aura = botAI->GetAura(getName(), GetTarget(), false, true);
return aura && aura->GetDuration() > 3000; return aura && aura->GetDuration() > 3000;
}
bool LifeTapGlyphBuffTrigger::IsActive()
{
// Check life tap glyph first
if (!botAI->HasAura(63320, bot))
return false;
return BuffTrigger::IsActive();
} }

View File

@@ -163,6 +163,13 @@ public:
bool IsActive() override; bool IsActive() override;
}; };
class LifeTapGlyphBuffTrigger : public BuffTrigger
{
public:
LifeTapGlyphBuffTrigger(PlayerbotAI* ai) : BuffTrigger(ai, "life tap") {}
bool IsActive() override;
};
class MoltenCoreTrigger : public HasAuraTrigger class MoltenCoreTrigger : public HasAuraTrigger
{ {
public: public:

View File

@@ -13,12 +13,12 @@ bool CastSunderArmorAction::isUseful()
return !aura || aura->GetStackAmount() < 5 || aura->GetDuration() <= 6000; return !aura || aura->GetStackAmount() < 5 || aura->GetDuration() <= 6000;
} }
Value<Unit*>* CastVigilanceAction::GetTargetValue() Unit* CastVigilanceAction::GetTarget()
{ {
Group* group = bot->GetGroup(); Group* group = bot->GetGroup();
if (!group) if (!group)
{ {
return new ManualSetValue<Unit*>(botAI, nullptr); return nullptr;
} }
Player* currentVigilanceTarget = nullptr; Player* currentVigilanceTarget = nullptr;
@@ -74,23 +74,23 @@ Value<Unit*>* CastVigilanceAction::GetTargetValue()
// If no valid target, return nullptr // If no valid target, return nullptr
if (!highestPriorityTarget) if (!highestPriorityTarget)
{ {
return new ManualSetValue<Unit*>(botAI, nullptr); return nullptr;
} }
// If the current target is already the highest-priority target, do nothing // If the current target is already the highest-priority target, do nothing
if (currentVigilanceTarget == highestPriorityTarget) if (currentVigilanceTarget == highestPriorityTarget)
{ {
return new ManualSetValue<Unit*>(botAI, nullptr); return nullptr;
} }
// Assign the new target // Assign the new target
Unit* targetUnit = highestPriorityTarget->ToUnit(); Unit* targetUnit = highestPriorityTarget->ToUnit();
if (targetUnit) if (targetUnit)
{ {
return new ManualSetValue<Unit*>(botAI, targetUnit); return targetUnit;
} }
return new ManualSetValue<Unit*>(botAI, nullptr); return nullptr;
} }
bool CastVigilanceAction::Execute(Event event) bool CastVigilanceAction::Execute(Event event)

View File

@@ -140,7 +140,7 @@ class CastVigilanceAction : public BuffOnPartyAction
public: public:
CastVigilanceAction(PlayerbotAI* botAI) : BuffOnPartyAction(botAI, "vigilance") {} CastVigilanceAction(PlayerbotAI* botAI) : BuffOnPartyAction(botAI, "vigilance") {}
Value<Unit*>* GetTargetValue() override; Unit* GetTarget() override;
bool Execute(Event event) override; bool Execute(Event event) override;
}; };