From 0f483047e50f774082902f50b471d8f42628a614 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Sat, 3 Jun 2023 14:01:20 +0800 Subject: [PATCH] warlock and dk strategy port --- src/AiFactory.cpp | 15 +- src/PlayerbotAI.cpp | 133 ++++++++++++++---- src/PlayerbotAI.h | 2 + src/PlayerbotMgr.cpp | 11 +- src/strategy/actions/GenericSpellActions.cpp | 13 +- src/strategy/actions/InventoryAction.cpp | 6 + src/strategy/actions/UseItemAction.cpp | 10 +- src/strategy/deathknight/BloodDKStrategy.cpp | 21 ++- src/strategy/deathknight/DKActions.cpp | 16 +++ src/strategy/deathknight/DKActions.h | 28 +++- src/strategy/deathknight/DKTriggers.cpp | 15 ++ src/strategy/deathknight/DKTriggers.h | 9 +- src/strategy/deathknight/FrostDKStrategy.cpp | 13 +- .../deathknight/GenericDKStrategy.cpp | 13 +- src/strategy/deathknight/UnholyDKStrategy.cpp | 17 ++- src/strategy/triggers/GenericTriggers.cpp | 23 ++- src/strategy/triggers/GenericTriggers.h | 4 +- src/strategy/warlock/DpsWarlockStrategy.cpp | 50 ++++++- .../GenericWarlockNonCombatStrategy.cpp | 39 ++++- .../warlock/GenericWarlockNonCombatStrategy.h | 27 ++++ .../warlock/GenericWarlockStrategy.cpp | 9 +- src/strategy/warlock/TankWarlockStrategy.cpp | 9 ++ src/strategy/warlock/WarlockActions.cpp | 2 +- src/strategy/warlock/WarlockActions.h | 47 +++++++ .../warlock/WarlockAiObjectContext.cpp | 50 +++++++ src/strategy/warlock/WarlockTriggers.cpp | 22 +++ src/strategy/warlock/WarlockTriggers.h | 46 +++++- 27 files changed, 562 insertions(+), 88 deletions(-) diff --git a/src/AiFactory.cpp b/src/AiFactory.cpp index 165526cd..f57d425c 100644 --- a/src/AiFactory.cpp +++ b/src/AiFactory.cpp @@ -4,6 +4,7 @@ #include "AiFactory.h" #include "BattlegroundMgr.h" +#include "PlayerbotAI.h" #include "Playerbots.h" #include "Engine.h" #include "Group.h" @@ -346,10 +347,7 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa engine->addStrategies("dps", "threat", "dps assist", "aoe", "close", "behind", "stealth", nullptr); break; case CLASS_WARLOCK: - if (player->getLevel() > 19) - engine->addStrategy("dps debuff"); - - engine->addStrategies("dps assist", "dps", "aoe", "ranged", "pet", "threat", nullptr); + engine->addStrategies("dps assist", "dps", "dps debuff", "aoe", "ranged", "threat", nullptr); break; case CLASS_DEATH_KNIGHT: if (tab == 0) @@ -518,7 +516,14 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const nonCombatEngine->addStrategy("dps assist"); break; case CLASS_WARLOCK: - nonCombatEngine->addStrategies("pet", "dps assist", nullptr); + if (tab == WARLOCK_TAB_AFFLICATION) { + nonCombatEngine->addStrategies("bmana", nullptr); + } else if (tab == WARLOCK_TAB_DEMONOLOGY) { + nonCombatEngine->addStrategies("bdps", nullptr); + } else if (tab == WARLOCK_TAB_DESTRUCTION) { + nonCombatEngine->addStrategies("bhealth", nullptr); + } + nonCombatEngine->addStrategies("dps assist", nullptr); break; case CLASS_DEATH_KNIGHT: if (tab == 0) diff --git a/src/PlayerbotAI.cpp b/src/PlayerbotAI.cpp index 6c607480..49af98bf 100644 --- a/src/PlayerbotAI.cpp +++ b/src/PlayerbotAI.cpp @@ -23,6 +23,7 @@ #include "PlayerbotMgr.h" #include "PositionValue.h" #include "ServerFacade.h" +#include "SharedDefines.h" #include "SocialMgr.h" #include "SpellAuraEffects.h" #include "UpdateTime.h" @@ -1680,6 +1681,57 @@ bool PlayerbotAI::HasAura(uint32 spellId, Unit const* unit) return false; } +Aura* PlayerbotAI::GetAura(std::string const name, Unit* unit, bool checkIsOwner, bool checkDuration, int checkStack) +{ + if (!unit) + return nullptr; + + std::wstring wnamepart; + if (!Utf8toWStr(name, wnamepart)) + return nullptr; + + wstrToLower(wnamepart); + + for (uint32 auraType = SPELL_AURA_BIND_SIGHT; auraType < TOTAL_AURAS; auraType++) + { + Unit::AuraEffectList const& auras = unit->GetAuraEffectsByType((AuraType)auraType); + if (auras.empty()) + continue; + + for (AuraEffect const* aurEff : auras) + { + SpellInfo const* spellInfo = aurEff->GetSpellInfo(); + + std::string const auraName = spellInfo->SpellName[0]; + if (auraName.empty() || auraName.length() != wnamepart.length() || !Utf8FitTo(auraName, wnamepart)) + continue; + + if (IsRealAura(bot, aurEff, unit)) + { + if (checkIsOwner && aurEff) { + if (aurEff->GetCasterGUID() != bot->GetGUID()) + continue; + } + + if (checkDuration && aurEff) { + if (aurEff->GetBase()->GetDuration() == -1) { + continue; + } + } + + if (checkStack != -1 && aurEff) { + if (aurEff->GetBase()->GetStackAmount() < checkStack) { + continue; + } + } + return aurEff->GetBase(); + } + } + } + + return nullptr; +} + bool PlayerbotAI::HasAnyAuraOf(Unit* player, ...) { if (!player) @@ -1711,15 +1763,30 @@ bool PlayerbotAI::CanCastSpell(std::string const name, Unit* target, Item* itemT bool PlayerbotAI::CanCastSpell(uint32 spellid, Unit* target, bool checkHasSpell, Item* itemTarget) { - if (!spellid) + if (!spellid) { + if (!sPlayerbotAIConfig->logInGroupOnly || bot->GetGroup()) { + LOG_DEBUG("playerbots", "Can cast spell failed. No spellid. - spellid: {}, bot name: {}", + spellid, bot->GetName()); + } return false; + } - if (bot->HasUnitState(UNIT_STATE_LOST_CONTROL)) + if (bot->HasUnitState(UNIT_STATE_LOST_CONTROL)) { + if (!sPlayerbotAIConfig->logInGroupOnly || bot->GetGroup()) { + LOG_DEBUG("playerbots", "Can cast spell failed. Unit state lost control. - spellid: {}, bot name: {}", + spellid, bot->GetName()); + } return false; + } + if (!target) target = bot; + if (!sPlayerbotAIConfig->logInGroupOnly || bot->GetGroup()) + LOG_DEBUG("playerbots", "Can cast spell? - target name: {}, spellid: {}, bot name: {}", + target->GetName(), spellid, bot->GetName()); + if (Pet* pet = bot->GetPet()) if (pet->HasSpell(spellid)) return true; @@ -1741,8 +1808,13 @@ bool PlayerbotAI::CanCastSpell(uint32 spellid, Unit* target, bool checkHasSpell, } SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellid); - if (!spellInfo) + if (!spellInfo) { + if (!sPlayerbotAIConfig->logInGroupOnly || bot->GetGroup()) { + LOG_DEBUG("playerbots", "Can cast spell failed. No spellInfo. - target name: {}, spellid: {}, bot name: {}", + target->GetName(), spellid, bot->GetName()); + } return false; + } uint32 CastingTime = !spellInfo->IsChanneled() ? spellInfo->CalcCastTime(bot) : spellInfo->GetDuration(); if (CastingTime && bot->isMoving()) { @@ -1762,15 +1834,15 @@ bool PlayerbotAI::CanCastSpell(uint32 spellid, Unit* target, bool checkHasSpell, // if (!positiveSpell && bot->IsFriendlyTo(target)) // return false; - bool damage = false; - for (uint8 i = EFFECT_0; i <= EFFECT_2; i++) - { - if (spellInfo->Effects[i].Effect == SPELL_EFFECT_SCHOOL_DAMAGE) - { - damage = true; - break; - } - } + // bool damage = false; + // for (uint8 i = EFFECT_0; i <= EFFECT_2; i++) + // { + // if (spellInfo->Effects[i].Effect == SPELL_EFFECT_SCHOOL_DAMAGE) + // { + // damage = true; + // break; + // } + // } if (target->IsImmunedToSpell(spellInfo)) { if (!sPlayerbotAIConfig->logInGroupOnly || bot->GetGroup()) { @@ -1780,19 +1852,19 @@ bool PlayerbotAI::CanCastSpell(uint32 spellid, Unit* target, bool checkHasSpell, return false; } - if (!damage) - { - for (uint8 i = EFFECT_0; i <= EFFECT_2; i++) - { - if (target->IsImmunedToSpellEffect(spellInfo, i)) { - if (!sPlayerbotAIConfig->logInGroupOnly || bot->GetGroup()) { - LOG_DEBUG("playerbots", "target is immuned to spell effect - target name: {}, spellid: {}, bot name: {}", - target->GetName(), spellid, bot->GetName()); - } - return false; - } - } - } + // if (!damage) + // { + // for (uint8 i = EFFECT_0; i <= EFFECT_2; i++) + // { + // if (target->IsImmunedToSpellEffect(spellInfo, i)) { + // if (!sPlayerbotAIConfig->logInGroupOnly || bot->GetGroup()) { + // LOG_DEBUG("playerbots", "target is immuned to spell effect - target name: {}, spellid: {}, bot name: {}", + // target->GetName(), spellid, bot->GetName()); + // } + // return false; + // } + // } + // } if (bot != target && sServerFacade->GetDistance2d(bot, target) > sPlayerbotAIConfig->sightDistance) { if (!sPlayerbotAIConfig->logInGroupOnly || bot->GetGroup()) { @@ -2050,7 +2122,7 @@ bool PlayerbotAI::CastSpell(uint32 spellId, Unit* target, Item* itemTarget) bot->GetTradeData()->SetSpell(spellId); delete spell; if (!sPlayerbotAIConfig->logInGroupOnly || bot->GetGroup()) { - LOG_DEBUG("playerbots", "Spell cast no item - target name: {}, spellid: {}, bot name: {}}", + LOG_DEBUG("playerbots", "Spell cast no item - target name: {}, spellid: {}, bot name: {}", target->GetName(), spellId, bot->GetName()); } return true; @@ -2111,8 +2183,15 @@ bool PlayerbotAI::CastSpell(uint32 spellId, Unit* target, Item* itemTarget) // if (spellSuccess != SPELL_CAST_OK) // return false; - spell->prepare(&targets); + SpellCastResult result = spell->prepare(&targets); + if (result != SPELL_CAST_OK) { + if (!sPlayerbotAIConfig->logInGroupOnly || bot->GetGroup()) { + LOG_DEBUG("playerbots", "Spell cast failed. - target name: {}, spellid: {}, bot name: {}, result: {}", + target->GetName(), spellId, bot->GetName(), result); + } + return false; + } // if (spellInfo->Effects[0].Effect == SPELL_EFFECT_OPEN_LOCK || spellInfo->Effects[0].Effect == SPELL_EFFECT_SKINNING) // { // LootObject loot = *aiObjectContext->GetValue("loot target"); diff --git a/src/PlayerbotAI.h b/src/PlayerbotAI.h index 661dab7d..01d4dac7 100644 --- a/src/PlayerbotAI.h +++ b/src/PlayerbotAI.h @@ -13,6 +13,7 @@ #include "PlayerbotAIBase.h" #include "PlayerbotAIConfig.h" #include "PlayerbotSecurity.h" +#include "SpellAuras.h" #include "WorldPacket.h" #include "PlayerbotTextMgr.h" @@ -376,6 +377,7 @@ class PlayerbotAI : public PlayerbotAIBase bool CanCastSpell(uint32 spellid, float x, float y, float z, uint8 effectMask, bool checkHasSpell = true, Item* itemTarget = nullptr); bool HasAura(uint32 spellId, Unit const* player); + Aura* GetAura(std::string const spellName, Unit* unit, bool checkIsOwner = false, bool checkDuration = false, int checkStack = -1); bool CastSpell(uint32 spellId, Unit* target, Item* itemTarget = nullptr); bool CastSpell(uint32 spellId, float x, float y, float z, Item* itemTarget = nullptr); bool canDispel(SpellInfo const* spellInfo, uint32 dispelType); diff --git a/src/PlayerbotMgr.cpp b/src/PlayerbotMgr.cpp index 39b53188..5d31b072 100644 --- a/src/PlayerbotMgr.cpp +++ b/src/PlayerbotMgr.cpp @@ -2,6 +2,7 @@ * Copyright (C) 2016+ AzerothCore , released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version. */ +#include "CharacterCache.h" #include "CharacterPackets.h" #include "Common.h" #include "ObjectAccessor.h" @@ -776,10 +777,12 @@ std::vector PlayerbotHolder::HandlePlayerbotCommand(char const* arg if (!charname) { - Player* tPlayer = ObjectAccessor::FindConnectedPlayer(master->GetTarget()); - if (tPlayer) { - charname = new char[tPlayer->GetName().size() + 1]; - strcpy(charname, tPlayer->GetName().c_str()); + std::string name; + bool isPlayer = sCharacterCache->GetCharacterNameByGuid(master->GetTarget(), name); + // Player* tPlayer = ObjectAccessor::FindConnectedPlayer(master->GetTarget()); + if (isPlayer) { + charname = new char[name.size() + 1]; + strcpy(charname, name.c_str()); } else { messages.push_back("usage: list/reload/tweak/self or add/init/remove PLAYERNAME"); return messages; diff --git a/src/strategy/actions/GenericSpellActions.cpp b/src/strategy/actions/GenericSpellActions.cpp index 323d3b5c..e3900e5e 100644 --- a/src/strategy/actions/GenericSpellActions.cpp +++ b/src/strategy/actions/GenericSpellActions.cpp @@ -62,14 +62,23 @@ bool CastSpellAction::Execute(Event event) bool CastSpellAction::isPossible() { - if (botAI->IsInVehicle() && !botAI->IsInVehicle(false, false, true)) + if (botAI->IsInVehicle() && !botAI->IsInVehicle(false, false, true)) { + if (!sPlayerbotAIConfig->logInGroupOnly || bot->GetGroup()) { + LOG_DEBUG("playerbots", "Can cast spell failed. Vehicle. - bot name: {}", + bot->GetName()); + } return false; + } if (spell == "mount" && !bot->IsMounted() && !bot->IsInCombat()) return true; if (spell == "mount" && bot->IsInCombat()) { + if (!sPlayerbotAIConfig->logInGroupOnly || bot->GetGroup()) { + LOG_DEBUG("playerbots", "Can cast spell failed. Mount. - bot name: {}", + bot->GetName()); + } bot->Dismount(); return false; } @@ -118,7 +127,7 @@ CastMeleeSpellAction::CastMeleeSpellAction(PlayerbotAI* botAI, std::string const bool CastAuraSpellAction::isUseful() { - return GetTarget() && (GetTarget() != nullptr) && (GetTarget() != nullptr) && CastSpellAction::isUseful() && !botAI->HasAura(spell, GetTarget(), true, isOwner); + return GetTarget() && (GetTarget() != nullptr) && CastSpellAction::isUseful() && !botAI->HasAura(spell, GetTarget(), false, isOwner); } CastEnchantItemAction::CastEnchantItemAction(PlayerbotAI* botAI, std::string const spell) : CastSpellAction(botAI, spell) diff --git a/src/strategy/actions/InventoryAction.cpp b/src/strategy/actions/InventoryAction.cpp index 1dd16b5a..416d9d52 100644 --- a/src/strategy/actions/InventoryAction.cpp +++ b/src/strategy/actions/InventoryAction.cpp @@ -222,6 +222,12 @@ std::vector InventoryAction::parseItems(std::string const text, IterateIt FindFoodVisitor visitor(bot, 59, text == "conjured drink" || text == "conjured water"); IterateItems(&visitor, ITERATE_ITEMS_IN_BAGS); found.insert(visitor.GetResult().begin(), visitor.GetResult().end()); + + if (found.empty()) { + FindFoodVisitor visitor(bot, 11); + IterateItems(&visitor, ITERATE_ITEMS_IN_BAGS); + found.insert(visitor.GetResult().begin(), visitor.GetResult().end()); + } } if (text == "mana potion") diff --git a/src/strategy/actions/UseItemAction.cpp b/src/strategy/actions/UseItemAction.cpp index ad4917dc..f7925c2b 100644 --- a/src/strategy/actions/UseItemAction.cpp +++ b/src/strategy/actions/UseItemAction.cpp @@ -254,9 +254,8 @@ bool UseItemAction::UseItem(Item* item, ObjectGuid goGuid, Item* itemTarget, Uni if (bot->IsInCombat()) return false; - bot->SetStandState(UNIT_STAND_STATE_SIT); + // bot->SetStandState(UNIT_STAND_STATE_SIT); botAI->InterruptSpell(); - float hp = bot->GetHealthPct(); float mp = bot->GetPower(POWER_MANA) * 100.0f / bot->GetMaxPower(POWER_MANA); float p = 0.f; @@ -272,17 +271,18 @@ bool UseItemAction::UseItem(Item* item, ObjectGuid goGuid, Item* itemTarget, Uni } else if (isFood) { - p = hp; + p = std::min(hp, mp); TellConsumableUse(item, "Eating", p); } if (!bot->IsInCombat() && !bot->InBattleground()) - botAI->SetNextCheckDelay(27000.0f * (100 - p) / 100.0f); + botAI->SetNextCheckDelay(std::max(10000.0f, 27000.0f * (100 - p) / 100.0f)); if (!bot->IsInCombat() && bot->InBattleground()) - botAI->SetNextCheckDelay(20000.0f * (100 - p) / 100.0f); + botAI->SetNextCheckDelay(std::max(10000.0f,20000.0f * (100 - p) / 100.0f)); //botAI->SetNextCheckDelay(27000.0f * (100 - p) / 100.0f); + // botAI->SetNextCheckDelay(20000); bot->GetSession()->HandleUseItemOpcode(packet); return true; diff --git a/src/strategy/deathknight/BloodDKStrategy.cpp b/src/strategy/deathknight/BloodDKStrategy.cpp index 3a4476b2..656bc566 100644 --- a/src/strategy/deathknight/BloodDKStrategy.cpp +++ b/src/strategy/deathknight/BloodDKStrategy.cpp @@ -30,6 +30,7 @@ class BloodDKStrategyActionNodeFactory : public NamedObjectFactory //creators["hysteria"] = &hysteria; //creators["dancing weapon"] = &dancing_weapon; //creators["dark command"] = &dark_command; + creators["taunt spell"] = &dark_command; } private: @@ -37,7 +38,7 @@ class BloodDKStrategyActionNodeFactory : public NamedObjectFactory { return new ActionNode("rune strike", /*P*/ NextAction::array(0, new NextAction("frost presence"), nullptr), - /*A*/ NextAction::array(0, new NextAction("death coil"), nullptr), + /*A*/ nullptr, /*C*/ nullptr); } @@ -56,6 +57,13 @@ class BloodDKStrategyActionNodeFactory : public NamedObjectFactory /*A*/ nullptr, /*C*/ nullptr); } + static ActionNode* dark_command([[maybe_unused]] PlayerbotAI* botAI) + { + return new ActionNode("dark command", + /*P*/ NextAction::array(0, new NextAction("frost presence"), NULL), + /*A*/ NextAction::array(0, new NextAction("death grip"), NULL), + /*C*/ NULL); + } }; BloodDKStrategy::BloodDKStrategy(PlayerbotAI* botAI) : GenericDKStrategy(botAI) @@ -65,8 +73,15 @@ BloodDKStrategy::BloodDKStrategy(PlayerbotAI* botAI) : GenericDKStrategy(botAI) NextAction** BloodDKStrategy::getDefaultActions() { - return NextAction::array(0, new NextAction("melee", ACTION_NORMAL + 2), new NextAction("heart strike", ACTION_NORMAL + 5), - new NextAction("death strike", ACTION_NORMAL + 4), new NextAction("rune strike", ACTION_NORMAL + 3), nullptr); + return NextAction::array(0, + new NextAction("rune strike", ACTION_NORMAL + 7), + new NextAction("heart strike", ACTION_NORMAL + 6), + new NextAction("icy touch", ACTION_NORMAL + 5), + new NextAction("death coil", ACTION_NORMAL + 4), + new NextAction("plague strike", ACTION_NORMAL + 3), + new NextAction("blood strike", ACTION_NORMAL + 2), + new NextAction("melee", ACTION_NORMAL), + NULL); } void BloodDKStrategy::InitTriggers(std::vector& triggers) diff --git a/src/strategy/deathknight/DKActions.cpp b/src/strategy/deathknight/DKActions.cpp index 4cd97ebd..a686b512 100644 --- a/src/strategy/deathknight/DKActions.cpp +++ b/src/strategy/deathknight/DKActions.cpp @@ -3,7 +3,11 @@ */ #include "DKActions.h" +#include "Duration.h" +#include "GenericSpellActions.h" #include "Playerbots.h" +#include "SpellInfo.h" +#include "SpellMgr.h" NextAction** CastDeathchillAction::getPrerequisites() { @@ -29,3 +33,15 @@ NextAction** CastBloodMeleeSpellAction::getPrerequisites() { return NextAction::merge(NextAction::array(0, new NextAction("blood presence"), nullptr), CastMeleeSpellAction::getPrerequisites()); } + +bool CastRaiseDeadAction::Execute(Event event) +{ + bool result = CastBuffSpellAction::Execute(event); + if (!result) { + return false; + } + uint32 spellId = AI_VALUE2(uint32, "spell id", spell); + // const SpellInfo *spellInfo = sSpellMgr->GetSpellInfo(spellId); + bot->AddSpellCooldown(spellId, 0, 3 * 60 * 1000); + return true; +} \ No newline at end of file diff --git a/src/strategy/deathknight/DKActions.h b/src/strategy/deathknight/DKActions.h index 5b73957f..1a6805ac 100644 --- a/src/strategy/deathknight/DKActions.h +++ b/src/strategy/deathknight/DKActions.h @@ -5,6 +5,7 @@ #ifndef _PLAYERBOT_DKACTIONS_H #define _PLAYERBOT_DKACTIONS_H +#include "Event.h" #include "GenericSpellActions.h" class PlayerbotAI; @@ -80,16 +81,30 @@ class CastRuneStrikeAction : public CastMeleeSpellAction }; //debuff -BEGIN_DEBUFF_ACTION(CastPestilenceAction, "pestilence") -END_SPELL_ACTION() +// BEGIN_DEBUFF_ACTION(CastPestilenceAction, "pestilence") +// END_SPELL_ACTION() + +class CastPestilenceAction : public CastSpellAction +{ + public: + CastPestilenceAction(PlayerbotAI* ai) : CastSpellAction(ai, "pestilence") {} + ActionThreatType getThreatType() override { return ActionThreatType::None; } +}; + //debuff BEGIN_DEBUFF_ACTION(CastHowlingBlastAction, "howling blast") END_SPELL_ACTION() //debuff it -BEGIN_DEBUFF_ACTION(CastIcyTouchAction, "icy touch") -END_SPELL_ACTION() +// BEGIN_DEBUFF_ACTION(CastIcyTouchAction, "icy touch") +// END_SPELL_ACTION() + +class CastIcyTouchAction : public CastSpellAction +{ + public: + CastIcyTouchAction(PlayerbotAI* ai) : CastSpellAction(ai, "icy touch") {} +}; class CastIcyTouchOnAttackerAction : public CastDebuffSpellOnAttackerAction { @@ -189,13 +204,13 @@ class CastDeathStrikeAction : public CastMeleeSpellAction class CastScourgeStrikeAction : public CastMeleeSpellAction { public: - CastScourgeStrikeAction(PlayerbotAI* botAI) : CastMeleeSpellAction(botAI, "scorgue strike") { } + CastScourgeStrikeAction(PlayerbotAI* botAI) : CastMeleeSpellAction(botAI, "scourge strike") { } }; class CastDeathCoilAction : public CastSpellAction { public: - CastDeathCoilAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "death coill") { } + CastDeathCoilAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "death coil") { } }; class CastBloodBoilAction : public CastBuffSpellAction @@ -262,6 +277,7 @@ class CastRaiseDeadAction : public CastBuffSpellAction { public: CastRaiseDeadAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "raise dead") { } + virtual bool Execute(Event event) override; }; class CastKillingMachineAction : public CastBuffSpellAction diff --git a/src/strategy/deathknight/DKTriggers.cpp b/src/strategy/deathknight/DKTriggers.cpp index 8e30ba37..30e591c9 100644 --- a/src/strategy/deathknight/DKTriggers.cpp +++ b/src/strategy/deathknight/DKTriggers.cpp @@ -4,9 +4,24 @@ #include "DKTriggers.h" #include "Playerbots.h" +#include "SharedDefines.h" +#include bool DKPresenceTrigger::IsActive() { Unit* target = GetTarget(); return !botAI->HasAura("blood presence", target) && !botAI->HasAura("unholy presence", target) && !botAI->HasAura("frost presence", target); } + +bool PestilenceTrigger::IsActive() { + if (!SpellTrigger::IsActive()) { + return false; + } + Aura *blood_plague = botAI->GetAura("blood plague", GetTarget(), true, true); + Aura *frost_fever = botAI->GetAura("frost fever", GetTarget(), true, true); + if ((blood_plague && blood_plague->GetDuration() <= 5000) || + (frost_fever && frost_fever->GetDuration() <= 5000)) { + return true; + } + return false; +} \ No newline at end of file diff --git a/src/strategy/deathknight/DKTriggers.h b/src/strategy/deathknight/DKTriggers.h index c71f93a4..f588c98e 100644 --- a/src/strategy/deathknight/DKTriggers.h +++ b/src/strategy/deathknight/DKTriggers.h @@ -12,19 +12,19 @@ class PlayerbotAI; BUFF_TRIGGER(HornOfWinterTrigger, "horn of winter"); BUFF_TRIGGER(BoneShieldTrigger, "bone shield"); BUFF_TRIGGER(ImprovedIcyTalonsTrigger, "improved icy talons"); -DEBUFF_CHECKISOWNER_TRIGGER(PlagueStrikeDebuffTrigger, "plague strike"); -DEBUFF_CHECKISOWNER_TRIGGER(IcyTouchDebuffTrigger, "icy touch"); +DEBUFF_CHECKISOWNER_TRIGGER(PlagueStrikeDebuffTrigger, "blood plague"); +DEBUFF_CHECKISOWNER_TRIGGER(IcyTouchDebuffTrigger, "frost fever"); class PlagueStrikeDebuffOnAttackerTrigger : public DebuffOnAttackerTrigger { public: - PlagueStrikeDebuffOnAttackerTrigger(PlayerbotAI* botAI) : DebuffOnAttackerTrigger(botAI, "plague strike", true) { } + PlagueStrikeDebuffOnAttackerTrigger(PlayerbotAI* botAI) : DebuffOnAttackerTrigger(botAI, "blood plague", true) { } }; class IcyTouchDebuffOnAttackerTrigger : public DebuffOnAttackerTrigger { public: - IcyTouchDebuffOnAttackerTrigger(PlayerbotAI* botAI) : DebuffOnAttackerTrigger(botAI, "icy touch", true) { } + IcyTouchDebuffOnAttackerTrigger(PlayerbotAI* botAI) : DebuffOnAttackerTrigger(botAI, "frost fever", true) { } }; class DKPresenceTrigger : public BuffTrigger @@ -63,6 +63,7 @@ class PestilenceTrigger : public DebuffTrigger { public: PestilenceTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "pestilence") { } + virtual bool IsActive() override; }; class BloodStrikeTrigger : public DebuffTrigger diff --git a/src/strategy/deathknight/FrostDKStrategy.cpp b/src/strategy/deathknight/FrostDKStrategy.cpp index cecc476e..e9827ee2 100644 --- a/src/strategy/deathknight/FrostDKStrategy.cpp +++ b/src/strategy/deathknight/FrostDKStrategy.cpp @@ -34,7 +34,7 @@ class FrostDKStrategyActionNodeFactory : public NamedObjectFactory { return new ActionNode("obliterate", /*P*/ NextAction::array(0, new NextAction("blood presence"), nullptr), - /*A*/ NextAction::array(0, new NextAction("frost strike"), nullptr), + /*A*/ nullptr, /*C*/ nullptr); } @@ -58,7 +58,7 @@ class FrostDKStrategyActionNodeFactory : public NamedObjectFactory { return new ActionNode("howling blast", /*P*/ NextAction::array(0, new NextAction("blood presence"), nullptr), - /*A*/ NextAction::array(0, new NextAction("icy touch"), nullptr), + /*A*/ nullptr, /*C*/ nullptr); } }; @@ -70,7 +70,13 @@ FrostDKStrategy::FrostDKStrategy(PlayerbotAI* botAI) : GenericDKStrategy(botAI) NextAction** FrostDKStrategy::getDefaultActions() { - return NextAction::array(0, new NextAction("melee", ACTION_NORMAL), new NextAction("frost strike", ACTION_NORMAL + 5), new NextAction("obliterate", ACTION_NORMAL + 4), nullptr); + return NextAction::array(0, + new NextAction("obliterate", ACTION_NORMAL + 5), + new NextAction("frost strike", ACTION_NORMAL + 4), + // new NextAction("death strike", ACTION_NORMAL + 3), + new NextAction("melee", ACTION_NORMAL), + NULL + ); } void FrostDKStrategy::InitTriggers(std::vector& triggers) @@ -78,6 +84,7 @@ void FrostDKStrategy::InitTriggers(std::vector& triggers) GenericDKStrategy::InitTriggers(triggers); triggers.push_back(new TriggerNode("empower weapon", NextAction::array(0, new NextAction("empower weapon", ACTION_NORMAL + 4), nullptr))); + triggers.push_back(new TriggerNode("pestilence", NextAction::array(0, new NextAction("pestilence", ACTION_HIGH + 9), NULL))); } void FrostDKAoeStrategy::InitTriggers(std::vector& triggers) diff --git a/src/strategy/deathknight/GenericDKStrategy.cpp b/src/strategy/deathknight/GenericDKStrategy.cpp index 270c25f2..ccdc74f8 100644 --- a/src/strategy/deathknight/GenericDKStrategy.cpp +++ b/src/strategy/deathknight/GenericDKStrategy.cpp @@ -54,7 +54,7 @@ class GenericDKStrategyActionNodeFactory : public NamedObjectFactory { return new ActionNode("death coil", /*P*/ nullptr, - /*A*/ NextAction::array(0, new NextAction("death strike"), nullptr), + /*A*/ nullptr, /*C*/ nullptr); } @@ -86,7 +86,7 @@ class GenericDKStrategyActionNodeFactory : public NamedObjectFactory { return new ActionNode("heart strike", /*P*/ nullptr, - /*A*/ NextAction::array(0, new NextAction("blood strike"), nullptr), + /*A*/ nullptr, /*C*/ nullptr); } @@ -158,21 +158,20 @@ void GenericDKStrategy::InitTriggers(std::vector& triggers) MeleeCombatStrategy::InitTriggers(triggers); triggers.push_back(new TriggerNode("high aoe", NextAction::array(0, new NextAction("anti magic shell", ACTION_NORMAL + 3), nullptr))); - triggers.push_back(new TriggerNode("death coil", NextAction::array(0, new NextAction("death coil", ACTION_NORMAL + 3), nullptr))); + // triggers.push_back(new TriggerNode("death coil", NextAction::array(0, new NextAction("death coil", ACTION_NORMAL + 3), nullptr))); triggers.push_back(new TriggerNode("critical aoe heal", NextAction::array(0, new NextAction("anti magic zone", ACTION_EMERGENCY + 1), nullptr))); triggers.push_back(new TriggerNode("no pet", NextAction::array(0, new NextAction("raise dead", ACTION_NORMAL + 5), nullptr))); triggers.push_back(new TriggerNode("mind freeze", NextAction::array(0, new NextAction("mind freeze", ACTION_HIGH + 1), nullptr))); triggers.push_back(new TriggerNode("bone shield", NextAction::array(0, new NextAction("bone shield", ACTION_NORMAL + 1), nullptr))); triggers.push_back(new TriggerNode("horn of winter", NextAction::array(0, new NextAction("horn of winter", ACTION_NORMAL + 1), nullptr))); triggers.push_back(new TriggerNode("mind freeze on enemy healer", NextAction::array(0, new NextAction("mind freeze on enemy healer", ACTION_HIGH + 1), nullptr))); - triggers.push_back(new TriggerNode("enemy out of melee", NextAction::array(0, new NextAction("icy touch", ACTION_NORMAL + 9), - new NextAction("death grip", ACTION_NORMAL + 9), new NextAction("reach melee", ACTION_NORMAL + 8), nullptr))); + triggers.push_back(new TriggerNode("enemy out of melee", NextAction::array(0, new NextAction("reach melee", ACTION_NORMAL + 8), nullptr))); triggers.push_back(new TriggerNode("low health", NextAction::array(0, new NextAction("icebound fortitude", ACTION_HIGH + 5), new NextAction("rune tap", ACTION_HIGH + 4), nullptr))); triggers.push_back(new TriggerNode("medium health", NextAction::array(0, new NextAction("rune tap", ACTION_NORMAL + 4), new NextAction("death strike", ACTION_NORMAL + 3), nullptr))); - triggers.push_back(new TriggerNode("icy touch on attacker", NextAction::array(0, new NextAction("icy touch", ACTION_HIGH + 1), nullptr))); triggers.push_back(new TriggerNode("icy touch", NextAction::array(0, new NextAction("icy touch", ACTION_HIGH + 1), nullptr))); + // triggers.push_back(new TriggerNode("icy touch on attacker", NextAction::array(0, new NextAction("icy touch on attacker", ACTION_HIGH + 1), nullptr))); triggers.push_back(new TriggerNode("plague strike", NextAction::array(0, new NextAction("plague strike", ACTION_HIGH + 1), nullptr))); - triggers.push_back(new TriggerNode("plague strike on attacker", NextAction::array(0, new NextAction("plague strike", ACTION_HIGH + 1), nullptr))); + // triggers.push_back(new TriggerNode("plague strike on attacker", NextAction::array(0, new NextAction("plague strike on attacker", ACTION_HIGH + 1), nullptr))); triggers.push_back(new TriggerNode("high aoe", NextAction::array(0, new NextAction("unholy blight", ACTION_NORMAL + 6), new NextAction("death and decay", ACTION_NORMAL + 5), new NextAction("pestilence", ACTION_NORMAL + 4), new NextAction("blood boil", ACTION_NORMAL + 3), nullptr))); triggers.push_back(new TriggerNode("medium aoe", NextAction::array(0, new NextAction("death and decay", ACTION_NORMAL + 5), diff --git a/src/strategy/deathknight/UnholyDKStrategy.cpp b/src/strategy/deathknight/UnholyDKStrategy.cpp index 44cd0fd2..ad6f58ee 100644 --- a/src/strategy/deathknight/UnholyDKStrategy.cpp +++ b/src/strategy/deathknight/UnholyDKStrategy.cpp @@ -33,7 +33,7 @@ class UnholyDKStrategyActionNodeFactory : public NamedObjectFactory static ActionNode* death_strike([[maybe_unused]] PlayerbotAI* botAI) { return new ActionNode("death strike", - /*P*/ NextAction::array(0, new NextAction("unholy pressence"), nullptr), + /*P*/ NextAction::array(0, new NextAction("blood presence"), nullptr), /*A*/ nullptr, /*C*/ nullptr); } @@ -41,7 +41,7 @@ class UnholyDKStrategyActionNodeFactory : public NamedObjectFactory static ActionNode* corpse_explosion([[maybe_unused]] PlayerbotAI* botAI) { return new ActionNode("corpse explosion", - /*P*/ NextAction::array(0, new NextAction("unholy pressence"), nullptr), + /*P*/ NextAction::array(0, new NextAction("blood presence"), nullptr), /*A*/ nullptr, /*C*/ nullptr); } @@ -49,15 +49,22 @@ class UnholyDKStrategyActionNodeFactory : public NamedObjectFactory static ActionNode* scourge_strike([[maybe_unused]] PlayerbotAI* botAI) { return new ActionNode("scourge strike", - /*P*/ NextAction::array(0, new NextAction("unholy pressence"), nullptr), - /*A*/ NextAction::array(0, new NextAction("death strike"), nullptr), + /*P*/ NextAction::array(0, new NextAction("blood presence"), nullptr), + /*A*/ nullptr, /*C*/ nullptr); } }; NextAction** UnholyDKStrategy::getDefaultActions() { - return NextAction::array(0, new NextAction("melee", ACTION_NORMAL), new NextAction("scourge strike" , ACTION_NORMAL + 3), nullptr); + return NextAction::array(0, + new NextAction("scourge strike", ACTION_NORMAL + 6), + new NextAction("blood strike", ACTION_NORMAL + 5), + new NextAction("death coil", ACTION_NORMAL + 4), + new NextAction("plague strike", ACTION_NORMAL + 3), + new NextAction("icy touch", ACTION_NORMAL + 2), + new NextAction("melee", ACTION_NORMAL), + NULL); } void UnholyDKStrategy::InitTriggers(std::vector& triggers) diff --git a/src/strategy/triggers/GenericTriggers.cpp b/src/strategy/triggers/GenericTriggers.cpp index 00830735..684151d9 100644 --- a/src/strategy/triggers/GenericTriggers.cpp +++ b/src/strategy/triggers/GenericTriggers.cpp @@ -4,7 +4,11 @@ #include "GenericTriggers.h" #include "BattlegroundWS.h" +#include "ObjectGuid.h" #include "Playerbots.h" +#include "SharedDefines.h" +#include "TemporarySummon.h" +#include bool LowManaTrigger::IsActive() { @@ -18,7 +22,20 @@ bool MediumManaTrigger::IsActive() bool NoPetTrigger::IsActive() { - return (!AI_VALUE(Unit*, "pet target")) && (!bot->GetGuardianPet()) && (!bot->GetFirstControlled()) && (!AI_VALUE2(bool, "mounted", "self target")); + // Guardian* gp = bot->GetGuardianPet(); + // bot->getpet + // if (gp) { + // bot->Yell("Guardian name: " + gp->GetName(), LANG_UNIVERSAL); + // } + // Minion* minion = bot->GetFirstMinion(); + // if (minion) { + // bot->Yell("has minion: " + minion->GetName(), LANG_UNIVERSAL); + // } + return (bot->GetMinionGUID().IsEmpty()) && + (!AI_VALUE(Unit*, "pet target")) && + (!bot->GetGuardianPet()) && + (!bot->GetFirstControlled()) && + (!AI_VALUE2(bool, "mounted", "self target")); } bool HasPetTrigger::IsActive() { @@ -193,7 +210,7 @@ bool TargetInSightTrigger::IsActive() bool DebuffTrigger::IsActive() { - return BuffTrigger::IsActive() && AI_VALUE2(uint8, "health", GetTargetName()) > 15; + return BuffTrigger::IsActive() && AI_VALUE2(uint8, "health", GetTargetName()) > life_bound; } bool SpellTrigger::IsActive() @@ -331,7 +348,7 @@ bool AttackerCountTrigger::IsActive() bool HasAuraTrigger::IsActive() { - return botAI->HasAura(getName(), GetTarget()); + return botAI->HasAura(getName(), GetTarget(), false, false, -1, true); } bool TimerTrigger::IsActive() diff --git a/src/strategy/triggers/GenericTriggers.h b/src/strategy/triggers/GenericTriggers.h index e9a0bd8f..d1d3802a 100644 --- a/src/strategy/triggers/GenericTriggers.h +++ b/src/strategy/triggers/GenericTriggers.h @@ -306,10 +306,12 @@ class TargetInSightTrigger : public Trigger class DebuffTrigger : public BuffTrigger { public: - DebuffTrigger(PlayerbotAI* botAI, std::string const spell, int32 checkInterval = 1, bool checkIsOwner = false) : BuffTrigger(botAI, spell, checkInterval, checkIsOwner) { } + DebuffTrigger(PlayerbotAI* botAI, std::string const spell, int32 checkInterval = 1, bool checkIsOwner = false, float life_bound = 0.25) : BuffTrigger(botAI, spell, checkInterval, checkIsOwner), life_bound(life_bound) { } std::string const GetTargetName() override { return "current target"; } bool IsActive() override; + protected: + float life_bound; }; class DebuffOnAttackerTrigger : public DebuffTrigger diff --git a/src/strategy/warlock/DpsWarlockStrategy.cpp b/src/strategy/warlock/DpsWarlockStrategy.cpp index 88eedf83..d68b4a6e 100644 --- a/src/strategy/warlock/DpsWarlockStrategy.cpp +++ b/src/strategy/warlock/DpsWarlockStrategy.cpp @@ -11,6 +11,8 @@ class DpsWarlockStrategyActionNodeFactory : public NamedObjectFactory& triggers) @@ -38,19 +58,39 @@ void DpsWarlockStrategy::InitTriggers(std::vector& triggers) GenericWarlockStrategy::InitTriggers(triggers); triggers.push_back(new TriggerNode("backlash", NextAction::array(0, new NextAction("shadow bolt", 20.0f), nullptr))); + + triggers.push_back(new TriggerNode( + "haunt", + NextAction::array(0, new NextAction("haunt", 26.0f), NULL))); + + triggers.push_back(new TriggerNode( + "shadow trance", + NextAction::array(0, new NextAction("shadow bolt", 15.0f), NULL))); + + triggers.push_back(new TriggerNode( + "backlash", + NextAction::array(0, new NextAction("shadow bolt", 15.0f), NULL))); + + triggers.push_back(new TriggerNode( + "molten core", + NextAction::array(0, new NextAction("incinerate", 15.0f), NULL))); + + triggers.push_back(new TriggerNode( + "decimation", + NextAction::array(0, new NextAction("soul fire", 16.0f), NULL))); } void DpsAoeWarlockStrategy::InitTriggers(std::vector& triggers) { triggers.push_back(new TriggerNode("medium aoe", NextAction::array(0, new NextAction("rain of fire", 37.0f), nullptr))); triggers.push_back(new TriggerNode("corruption on attacker", NextAction::array(0, new NextAction("corruption on attacker", 27.0f), nullptr))); - triggers.push_back(new TriggerNode("curse of agony on attacker", NextAction::array(0, new NextAction("curse of agony on attacker", 28.0f), nullptr))); - triggers.push_back(new TriggerNode("siphon life on attacker", NextAction::array(0, new NextAction("siphon life on attacker", 29.0f), nullptr))); + // triggers.push_back(new TriggerNode("curse of agony on attacker", NextAction::array(0, new NextAction("curse of agony on attacker", 28.0f), nullptr))); + triggers.push_back(new TriggerNode("unstable affliction on attacker", NextAction::array(0, new NextAction("unstable affliction on attacker", 22.0f), NULL))); } void DpsWarlockDebuffStrategy::InitTriggers(std::vector& triggers) { triggers.push_back(new TriggerNode("corruption", NextAction::array(0, new NextAction("corruption", 22.0f), nullptr))); - triggers.push_back(new TriggerNode("curse of agony", NextAction::array(0, new NextAction("curse of agony", 21.0f), nullptr))); - triggers.push_back(new TriggerNode("siphon life", NextAction::array(0, new NextAction("siphon life", 23.0f), nullptr))); + triggers.push_back(new TriggerNode("curse of agony", NextAction::array(0, new NextAction("curse of agony", 20.0f), nullptr))); + triggers.push_back(new TriggerNode("unstable affliction", NextAction::array(0, new NextAction("unstable affliction", 21.0f), NULL))); } diff --git a/src/strategy/warlock/GenericWarlockNonCombatStrategy.cpp b/src/strategy/warlock/GenericWarlockNonCombatStrategy.cpp index 32f32873..f09d7556 100644 --- a/src/strategy/warlock/GenericWarlockNonCombatStrategy.cpp +++ b/src/strategy/warlock/GenericWarlockNonCombatStrategy.cpp @@ -15,6 +15,7 @@ class GenericWarlockNonCombatStrategyActionNodeFactory : public NamedObjectFacto creators["summon voidwalker"] = &summon_voidwalker; creators["summon felguard"] = &summon_felguard; creators["summon succubus"] = &summon_succubus; + creators["summon felhunter"] = &summon_felhunter; } private: @@ -57,6 +58,14 @@ class GenericWarlockNonCombatStrategyActionNodeFactory : public NamedObjectFacto /*A*/ NextAction::array(0, new NextAction("summon voidwalker"), nullptr), /*C*/ nullptr); } + + static ActionNode* summon_felhunter([[maybe_unused]] PlayerbotAI* botAI) + { + return new ActionNode("summon felhunter", + /*P*/ nullptr, + /*A*/ NextAction::array(0, new NextAction("summon imp"), nullptr), + /*C*/ nullptr); + } }; GenericWarlockNonCombatStrategy::GenericWarlockNonCombatStrategy(PlayerbotAI* botAI) : NonCombatStrategy(botAI) @@ -69,12 +78,38 @@ void GenericWarlockNonCombatStrategy::InitTriggers(std::vector& tr NonCombatStrategy::InitTriggers(triggers); triggers.push_back(new TriggerNode("demon armor", NextAction::array(0, new NextAction("fel armor", 21.0f), nullptr))); + triggers.push_back(new TriggerNode("often", NextAction::array(0, new NextAction("apply oil", 1.0f), nullptr))); } void WarlockPetStrategy::InitTriggers(std::vector& triggers) { triggers.push_back(new TriggerNode("no pet", NextAction::array(0, new NextAction("summon felguard", 60.0f), nullptr))); // TODO Warlock pets - - triggers.push_back(new TriggerNode("often", NextAction::array(0, new NextAction("apply oil", 1.0f), nullptr))); } + +SummonImpStrategy::SummonImpStrategy(PlayerbotAI* ai): NonCombatStrategy(ai) {} + +void SummonImpStrategy::InitTriggers(std::vector& triggers) +{ + triggers.push_back(new TriggerNode( + "no pet", + NextAction::array(0, new NextAction("summon imp", 11.0f), NULL))); +} + +SummonFelguardStrategy::SummonFelguardStrategy(PlayerbotAI* ai): NonCombatStrategy(ai) {} + +void SummonFelguardStrategy::InitTriggers(std::vector& triggers) +{ + triggers.push_back(new TriggerNode( + "no pet", + NextAction::array(0, new NextAction("summon felguard", 11.0f), NULL))); +} + +SummonFelhunterStrategy::SummonFelhunterStrategy(PlayerbotAI* ai): NonCombatStrategy(ai) {} + +void SummonFelhunterStrategy::InitTriggers(std::vector& triggers) +{ + triggers.push_back(new TriggerNode( + "no pet", + NextAction::array(0, new NextAction("summon felhunter", 11.0f), NULL))); +} \ No newline at end of file diff --git a/src/strategy/warlock/GenericWarlockNonCombatStrategy.h b/src/strategy/warlock/GenericWarlockNonCombatStrategy.h index 5acd2665..e20c36b1 100644 --- a/src/strategy/warlock/GenericWarlockNonCombatStrategy.h +++ b/src/strategy/warlock/GenericWarlockNonCombatStrategy.h @@ -27,4 +27,31 @@ class WarlockPetStrategy : public Strategy void InitTriggers(std::vector& triggers) override; }; +class SummonImpStrategy : public NonCombatStrategy +{ + public: + SummonImpStrategy(PlayerbotAI* ai); + virtual std::string const getName() override { return "bhealth"; } + public: + void InitTriggers(std::vector& triggers) override; +}; + +class SummonFelguardStrategy : public NonCombatStrategy +{ + public: + SummonFelguardStrategy(PlayerbotAI* ai); + virtual std::string const getName() override { return "bdps"; } + public: + void InitTriggers(std::vector& triggers) override; +}; + +class SummonFelhunterStrategy : public NonCombatStrategy +{ + public: + SummonFelhunterStrategy(PlayerbotAI* ai); + virtual std::string const getName() override { return "bmana"; } + public: + void InitTriggers(std::vector& triggers) override; +}; + #endif diff --git a/src/strategy/warlock/GenericWarlockStrategy.cpp b/src/strategy/warlock/GenericWarlockStrategy.cpp index e383075d..b5fabe3c 100644 --- a/src/strategy/warlock/GenericWarlockStrategy.cpp +++ b/src/strategy/warlock/GenericWarlockStrategy.cpp @@ -45,11 +45,12 @@ void GenericWarlockStrategy::InitTriggers(std::vector& triggers) { CombatStrategy::InitTriggers(triggers); - triggers.push_back(new TriggerNode("shadow trance", NextAction::array(0, new NextAction("shadow bolt", 20.0f), nullptr))); - triggers.push_back(new TriggerNode("low health", NextAction::array(0, new NextAction("drain life", 40.0f), nullptr))); - triggers.push_back(new TriggerNode("medium mana", NextAction::array(0, new NextAction("life tap", ACTION_EMERGENCY + 5), nullptr))); + // triggers.push_back(new TriggerNode("shadow trance", NextAction::array(0, new NextAction("shadow bolt", 20.0f), nullptr))); + // triggers.push_back(new TriggerNode("low health", NextAction::array(0, new NextAction("drain life", 40.0f), nullptr))); + triggers.push_back(new TriggerNode("low mana", NextAction::array(0, new NextAction("life tap", ACTION_EMERGENCY + 5), nullptr))); triggers.push_back(new TriggerNode("target critical health", NextAction::array(0, new NextAction("drain soul", 30.0f), nullptr))); - triggers.push_back(new TriggerNode("immolate", NextAction::array(0, new NextAction("immolate", 13.0f), new NextAction("conflagrate", 13.0f), nullptr))); + // triggers.push_back(new TriggerNode("immolate", NextAction::array(0, new NextAction("immolate", 13.0f), new NextAction("conflagrate", 13.0f), nullptr))); + triggers.push_back(new TriggerNode("enemy too close for spell", NextAction::array(0, new NextAction("flee", 49.0f), NULL))); } void WarlockBoostStrategy::InitTriggers(std::vector& triggers) diff --git a/src/strategy/warlock/TankWarlockStrategy.cpp b/src/strategy/warlock/TankWarlockStrategy.cpp index fe1eb16c..ca1fae48 100644 --- a/src/strategy/warlock/TankWarlockStrategy.cpp +++ b/src/strategy/warlock/TankWarlockStrategy.cpp @@ -13,6 +13,7 @@ class GenericWarlockStrategyActionNodeFactory : public NamedObjectFactory* CastBanishAction::GetTargetValue() diff --git a/src/strategy/warlock/WarlockActions.h b/src/strategy/warlock/WarlockActions.h index 71fd5faa..0527711e 100644 --- a/src/strategy/warlock/WarlockActions.h +++ b/src/strategy/warlock/WarlockActions.h @@ -93,6 +93,12 @@ class CastSummonFelguardAction : public CastBuffSpellAction CastSummonFelguardAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "summon felguard") { } }; +class CastSummonFelhunterAction : public CastBuffSpellAction +{ + public: + CastSummonFelhunterAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "summon felhunter") { } +}; + class CastSummonImpAction : public CastBuffSpellAction { public: @@ -218,4 +224,45 @@ class CastSiphonLifeOnAttackerAction : public CastDebuffSpellOnAttackerAction CastSiphonLifeOnAttackerAction(PlayerbotAI* botAI) : CastDebuffSpellOnAttackerAction(botAI, "siphon life") { } }; +class CastUnstableAfflictionAction: public CastDebuffSpellAction +{ + public: + CastUnstableAfflictionAction(PlayerbotAI* ai) : CastDebuffSpellAction(ai, "unstable affliction", true) {} +}; + +class CastHauntAction: public CastSpellAction +{ + public: + CastHauntAction(PlayerbotAI* ai) : CastSpellAction(ai, "haunt") {} +}; + +class CastDemonicEmpowermentAction : public CastBuffSpellAction +{ + public: + CastDemonicEmpowermentAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "demonic empowerment") {} +}; + +class CastMetamorphosisAction : public CastBuffSpellAction +{ + public: + CastMetamorphosisAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "metamorphosis") {} +}; + +class CastUnstableAfflictionOnAttackerAction : public CastDebuffSpellOnAttackerAction +{ + public: + CastUnstableAfflictionOnAttackerAction(PlayerbotAI* ai) : CastDebuffSpellOnAttackerAction(ai, "unstable affliction", true) {} +}; + +class CastSoulFireAction : public CastSpellAction +{ + public: + CastSoulFireAction(PlayerbotAI* ai) : CastSpellAction(ai, "soul fire") {} +}; + +class CastIncinerateAction : public CastSpellAction +{ + public: + CastIncinerateAction(PlayerbotAI* ai) : CastSpellAction(ai, "incinerate") {} +}; #endif diff --git a/src/strategy/warlock/WarlockAiObjectContext.cpp b/src/strategy/warlock/WarlockAiObjectContext.cpp index 12fd8188..e52032c2 100644 --- a/src/strategy/warlock/WarlockAiObjectContext.cpp +++ b/src/strategy/warlock/WarlockAiObjectContext.cpp @@ -5,6 +5,7 @@ #include "WarlockAiObjectContext.h" #include "DpsWarlockStrategy.h" #include "GenericWarlockNonCombatStrategy.h" +#include "Strategy.h" #include "TankWarlockStrategy.h" #include "WarlockActions.h" #include "WarlockTriggers.h" @@ -51,6 +52,21 @@ class WarlockCombatStrategyFactoryInternal : public NamedObjectContext static Strategy* dps(PlayerbotAI* botAI) { return new DpsWarlockStrategy(botAI); } }; +class NonCombatBuffStrategyFactoryInternal : public NamedObjectContext +{ +public: + NonCombatBuffStrategyFactoryInternal() : NamedObjectContext(false, true) + { + creators["bdps"] = &NonCombatBuffStrategyFactoryInternal::felguard; + creators["bmana"] = &NonCombatBuffStrategyFactoryInternal::felhunter; + creators["bhealth"] = &NonCombatBuffStrategyFactoryInternal::imp; + } +private: + static Strategy* imp(PlayerbotAI* ai) { return new SummonImpStrategy(ai); } + static Strategy* felhunter(PlayerbotAI* ai) { return new SummonFelhunterStrategy(ai); } + static Strategy* felguard(PlayerbotAI* ai) { return new SummonFelguardStrategy(ai); } +}; + class WarlockTriggerFactoryInternal : public NamedObjectContext { public: @@ -73,6 +89,15 @@ class WarlockTriggerFactoryInternal : public NamedObjectContext creators["amplify curse"] = &WarlockTriggerFactoryInternal::amplify_curse; creators["siphon life"] = &WarlockTriggerFactoryInternal::siphon_life; creators["siphon life on attacker"] = &WarlockTriggerFactoryInternal::siphon_life_on_attacker; + + creators["immolate on attacker"] = &WarlockTriggerFactoryInternal::immolate_on_attacker; + creators["unstable affliction"] = &WarlockTriggerFactoryInternal::unstable_affliction; + creators["unstable affliction on attacker"] = &WarlockTriggerFactoryInternal::unstable_affliction_on_attacker; + creators["haunt"] = &WarlockTriggerFactoryInternal::haunt; + creators["decimation"] = &WarlockTriggerFactoryInternal::decimation; + creators["molten core"] = &WarlockTriggerFactoryInternal::molten_core; + creators["metamorphosis"] = &WarlockTriggerFactoryInternal::metamorphosis; + } private: @@ -93,6 +118,13 @@ class WarlockTriggerFactoryInternal : public NamedObjectContext static Trigger* backlash(PlayerbotAI* botAI) { return new BacklashTrigger(botAI); } static Trigger* fear(PlayerbotAI* botAI) { return new FearTrigger(botAI); } static Trigger* immolate(PlayerbotAI* botAI) { return new ImmolateTrigger(botAI); } + static Trigger* immolate_on_attacker(PlayerbotAI* ai) { return new ImmolateOnAttackerTrigger(ai); } + static Trigger* unstable_affliction(PlayerbotAI* ai) { return new UnstableAfflictionTrigger(ai); } + static Trigger* unstable_affliction_on_attacker(PlayerbotAI* ai) { return new UnstableAfflictionOnAttackerTrigger(ai); } + static Trigger* haunt(PlayerbotAI* ai) { return new HauntTrigger(ai); } + static Trigger* decimation(PlayerbotAI* ai) { return new DecimationTrigger(ai); } + static Trigger* molten_core(PlayerbotAI* ai) { return new MoltenCoreTrigger(ai); } + static Trigger* metamorphosis(PlayerbotAI* ai) { return new MetamorphosisTrigger(ai); } }; class WarlockAiObjectContextInternal : public NamedObjectContext @@ -109,6 +141,7 @@ class WarlockAiObjectContextInternal : public NamedObjectContext creators["spellstone"] = &WarlockAiObjectContextInternal::spellstone; creators["summon voidwalker"] = &WarlockAiObjectContextInternal::summon_voidwalker; creators["summon felguard"] = &WarlockAiObjectContextInternal::summon_felguard; + creators["summon felhunter"] = &WarlockAiObjectContextInternal::summon_felhunter; creators["summon succubus"] = &WarlockAiObjectContextInternal::summon_succubus; creators["summon imp"] = &WarlockAiObjectContextInternal::summon_imp; creators["immolate"] = &WarlockAiObjectContextInternal::immolate; @@ -133,6 +166,14 @@ class WarlockAiObjectContextInternal : public NamedObjectContext creators["incinirate"] = &WarlockAiObjectContextInternal::incinirate; creators["conflagrate"] = &WarlockAiObjectContextInternal::conflagrate; creators["amplify curse"] = &WarlockAiObjectContextInternal::amplify_curse; + + creators["unstable affliction"] = &WarlockAiObjectContextInternal::unstable_affliction; + creators["unstable affliction on attacker"] = &WarlockAiObjectContextInternal::unstable_affliction_on_attacker; + creators["haunt"] = &WarlockAiObjectContextInternal::haunt; + creators["demonic empowerment"] = &WarlockAiObjectContextInternal::demonic_empowerment; + creators["metamorphosis"] = &WarlockAiObjectContextInternal::metamorphosis; + creators["soul fire"] = &WarlockAiObjectContextInternal::soul_fire; + creators["incinerate"] = &WarlockAiObjectContextInternal::incinerate; } private: @@ -153,6 +194,7 @@ class WarlockAiObjectContextInternal : public NamedObjectContext static Action* spellstone(PlayerbotAI* botAI) { return new UseSpellItemAction(botAI, "spellstone", true); } static Action* summon_voidwalker(PlayerbotAI* botAI) { return new CastSummonVoidwalkerAction(botAI); } static Action* summon_felguard(PlayerbotAI* botAI) { return new CastSummonFelguardAction(botAI); } + static Action* summon_felhunter(PlayerbotAI* botAI) { return new CastSummonFelhunterAction(botAI); } static Action* corruption(PlayerbotAI* botAI) { return new CastCorruptionAction(botAI); } static Action* corruption_on_attacker(PlayerbotAI* botAI) { return new CastCorruptionOnAttackerAction(botAI); } static Action* siphon_life(PlayerbotAI* botAI) { return new CastSiphonLifeAction(botAI); } @@ -169,12 +211,20 @@ class WarlockAiObjectContextInternal : public NamedObjectContext static Action* rain_of_fire(PlayerbotAI* botAI) { return new CastRainOfFireAction(botAI); } static Action* shadowfury(PlayerbotAI* botAI) { return new CastShadowfuryAction(botAI); } static Action* life_tap(PlayerbotAI* botAI) { return new CastLifeTapAction(botAI); } + static Action* unstable_affliction(PlayerbotAI* ai) { return new CastUnstableAfflictionAction(ai); } + static Action* unstable_affliction_on_attacker(PlayerbotAI* ai) { return new CastUnstableAfflictionOnAttackerAction(ai); } + static Action* haunt(PlayerbotAI* ai) { return new CastHauntAction(ai); } + static Action* demonic_empowerment(PlayerbotAI* ai) { return new CastDemonicEmpowermentAction(ai); } + static Action* metamorphosis(PlayerbotAI* ai) { return new CastMetamorphosisAction(ai); } + static Action* soul_fire(PlayerbotAI* ai) { return new CastSoulFireAction(ai); } + static Action* incinerate(PlayerbotAI* ai) { return new CastIncinerateAction(ai); } }; WarlockAiObjectContext::WarlockAiObjectContext(PlayerbotAI* botAI) : AiObjectContext(botAI) { strategyContexts.Add(new WarlockStrategyFactoryInternal()); strategyContexts.Add(new WarlockCombatStrategyFactoryInternal()); + strategyContexts.Add(new NonCombatBuffStrategyFactoryInternal()); actionContexts.Add(new WarlockAiObjectContextInternal()); triggerContexts.Add(new WarlockTriggerFactoryInternal()); } diff --git a/src/strategy/warlock/WarlockTriggers.cpp b/src/strategy/warlock/WarlockTriggers.cpp index 8e5a1731..8fa44758 100644 --- a/src/strategy/warlock/WarlockTriggers.cpp +++ b/src/strategy/warlock/WarlockTriggers.cpp @@ -20,3 +20,25 @@ bool WarlockConjuredItemTrigger::IsActive() { return ItemCountTrigger::IsActive() && AI_VALUE2(uint32, "item count", "soul shard") > 0; } + +bool ImmolateOnAttackerTrigger::IsActive() +{ + return DebuffOnAttackerTrigger::IsActive() && + // !botAI->HasAura("immolate", GetTarget(), false, true) && + !botAI->HasAura("unstable affliction", GetTarget(), false, true); +} + +bool UnstableAfflictionTrigger::IsActive() +{ + return DebuffTrigger::IsActive() && + !botAI->HasAura("immolate", GetTarget(), false, true); + // !botAI->HasAura("unstable affliction", GetTarget(), false, true); +} + +bool UnstableAfflictionOnAttackerTrigger::IsActive() +{ + return DebuffOnAttackerTrigger::IsActive() && + !botAI->HasAura("immolate", GetTarget(), false, true); + // !botAI->HasAura("unstable affliction", GetTarget(), false, true); +} + diff --git a/src/strategy/warlock/WarlockTriggers.h b/src/strategy/warlock/WarlockTriggers.h index f622eeac..8feac44c 100644 --- a/src/strategy/warlock/WarlockTriggers.h +++ b/src/strategy/warlock/WarlockTriggers.h @@ -32,7 +32,7 @@ DEBUFF_CHECKISOWNER_TRIGGER(SiphonLifeTrigger, "siphon life"); class CorruptionOnAttackerTrigger : public DebuffOnAttackerTrigger { public: - CorruptionOnAttackerTrigger(PlayerbotAI* botAI) : DebuffOnAttackerTrigger(botAI, "corruption") { } + CorruptionOnAttackerTrigger(PlayerbotAI* botAI) : DebuffOnAttackerTrigger(botAI, "corruption", true) { } }; class CastCurseOfAgonyOnAttackerTrigger : public DebuffOnAttackerTrigger @@ -49,6 +49,13 @@ class SiphonLifeOnAttackerTrigger : public DebuffOnAttackerTrigger DEBUFF_CHECKISOWNER_TRIGGER(ImmolateTrigger, "immolate"); +class ImmolateOnAttackerTrigger : public DebuffOnAttackerTrigger +{ +public: + ImmolateOnAttackerTrigger(PlayerbotAI* ai) : DebuffOnAttackerTrigger(ai, "immolate") {} + virtual bool IsActive(); +}; + class ShadowTranceTrigger : public HasAuraTrigger { public: @@ -105,4 +112,41 @@ class AmplifyCurseTrigger : public BuffTrigger AmplifyCurseTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "amplify curse") { } }; +class UnstableAfflictionTrigger : public DebuffTrigger // SpellTrigger +{ + public: + UnstableAfflictionTrigger(PlayerbotAI* ai) : DebuffTrigger(ai, "unstable affliction", 1, true) {} + bool IsActive() override; +}; + +class UnstableAfflictionOnAttackerTrigger : public DebuffOnAttackerTrigger +{ + public: + UnstableAfflictionOnAttackerTrigger(PlayerbotAI* ai) : DebuffOnAttackerTrigger(ai, "unstable affliction", true) {} + bool IsActive() override; +}; + +class HauntTrigger : public DebuffTrigger +{ + public: + HauntTrigger(PlayerbotAI* ai) : DebuffTrigger(ai, "haunt", 1, true, 0) {} +}; + +class DecimationTrigger : public HasAuraTrigger +{ + public: + DecimationTrigger(PlayerbotAI* ai) : HasAuraTrigger(ai, "decimation") {} +}; + +class MoltenCoreTrigger : public HasAuraTrigger +{ + public: + MoltenCoreTrigger(PlayerbotAI* ai) : HasAuraTrigger(ai, "molten core") {} +}; + +class MetamorphosisTrigger : public BoostTrigger +{ + public: + MetamorphosisTrigger(PlayerbotAI* ai) : BoostTrigger(ai, "metamorphosis") {} +}; #endif