diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index c6c0dfe1..9954da5e 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -996,7 +996,7 @@ AiPlayerbot.PremadeSpecLink.11.2.60 = --230033312031501531050013051 AiPlayerbot.PremadeSpecLink.11.2.80 = 05320001--230033312031512531153313051 AiPlayerbot.PremadeSpecName.11.3 = cat pve AiPlayerbot.PremadeSpecGlyph.11.3 = 40902,43331,40901,43335,44922,45604 -AiPlayerbot.PremadeSpecLink.11.3.60 = -553202032322010052100030310501 +AiPlayerbot.PremadeSpecLink.11.3.60 = -552202032322010053100030310501 AiPlayerbot.PremadeSpecLink.11.3.80 = -553202032322010053100030310511-205503012 # @@ -1183,11 +1183,12 @@ AiPlayerbot.RandomClassSpecIndex.9.2 = 2 AiPlayerbot.RandomClassSpecProb.11.0 = 20 AiPlayerbot.RandomClassSpecIndex.11.0 = 0 -AiPlayerbot.RandomClassSpecProb.11.1 = 40 +AiPlayerbot.RandomClassSpecProb.11.1 = 30 AiPlayerbot.RandomClassSpecIndex.11.1 = 1 -AiPlayerbot.RandomClassSpecProb.11.2 = 40 +AiPlayerbot.RandomClassSpecProb.11.2 = 30 AiPlayerbot.RandomClassSpecIndex.11.2 = 2 - +AiPlayerbot.RandomClassSpecProb.11.3 = 20 +AiPlayerbot.RandomClassSpecIndex.11.3 = 3 # # # diff --git a/src/AiFactory.cpp b/src/AiFactory.cpp index 05f2daec..75787511 100644 --- a/src/AiFactory.cpp +++ b/src/AiFactory.cpp @@ -71,7 +71,6 @@ uint8 AiFactory::GetPlayerSpecTab(Player* bot) max = tabs[i]; } } - return tab; } else diff --git a/src/PlayerbotAI.cpp b/src/PlayerbotAI.cpp index 07b07293..27214fc5 100644 --- a/src/PlayerbotAI.cpp +++ b/src/PlayerbotAI.cpp @@ -1998,6 +1998,10 @@ bool PlayerbotAI::IsDps(Player* player) { return true; } + if (tab == DRUID_TAB_FERAL && !IsTank(player)) + { + return true; + } break; case CLASS_SHAMAN: if (tab != SHAMAN_TAB_RESTORATION) @@ -2792,8 +2796,8 @@ bool PlayerbotAI::CanCastSpell(uint32 spellid, Unit* target, bool checkHasSpell, } uint32 CastingTime = !spellInfo->IsChanneled() ? spellInfo->CalcCastTime(bot) : spellInfo->GetDuration(); - bool interruptOnMove = spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_MOVEMENT; - if ((CastingTime || interruptOnMove) && bot->isMoving()) + // bool interruptOnMove = spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_MOVEMENT; + if ((CastingTime || spellInfo->IsAutoRepeatRangedSpell()) && bot->isMoving()) { if (!sPlayerbotAIConfig->logInGroupOnly || (bot->GetGroup() && HasRealPlayerMaster())) { diff --git a/src/PlayerbotAIConfig.cpp b/src/PlayerbotAIConfig.cpp index 1267591e..d6844aaf 100644 --- a/src/PlayerbotAIConfig.cpp +++ b/src/PlayerbotAIConfig.cpp @@ -329,15 +329,22 @@ bool PlayerbotAIConfig::Initialize() parsedSpecLinkOrder[cls][spec][level] = ParseTempTalentsOrder(cls, premadeSpecLink[cls][spec][level]); } } - for (uint32 spec = 0; spec < 3; ++spec) + for (uint32 spec = 0; spec < MAX_SPECNO; ++spec) { std::ostringstream os; os << "AiPlayerbot.RandomClassSpecProb." << cls << "." << spec; - randomClassSpecProb[cls][spec] = sConfigMgr->GetOption(os.str().c_str(), 33); + uint32 def; + if (spec <= 1) + def = 33; + else if (spec == 2) + def = 34; + else + def = 0; + randomClassSpecProb[cls][spec] = sConfigMgr->GetOption(os.str().c_str(), def, false); os.str(""); os.clear(); os << "AiPlayerbot.RandomClassSpecIndex." << cls << "." << spec; - randomClassSpecIndex[cls][spec] = sConfigMgr->GetOption(os.str().c_str(), spec + 1); + randomClassSpecIndex[cls][spec] = sConfigMgr->GetOption(os.str().c_str(), spec, false); } } diff --git a/src/factory/PlayerbotFactory.cpp b/src/factory/PlayerbotFactory.cpp index 511d92a0..be60bf1b 100644 --- a/src/factory/PlayerbotFactory.cpp +++ b/src/factory/PlayerbotFactory.cpp @@ -878,14 +878,31 @@ void PlayerbotFactory::InitTalentsTree(bool increment /*false*/, bool use_templa uint32 total_tabs = tabs[0] + tabs[1] + tabs[2]; if (increment && total_tabs != 0) { + /// @todo: match current talent with template specTab = AiFactory::GetPlayerSpecTab(bot); - } + /// @todo: fix cat druid hardcode + if (bot->getClass() == CLASS_DRUID && specTab == DRUID_TAB_FERAL && bot->GetLevel() >= 20 && PlayerbotAI::IsDps(bot)) + specTab = 3; + } else { - uint32 point = urand(0, 100); - uint32 p1 = sPlayerbotAIConfig->randomClassSpecProb[cls][0]; - uint32 p2 = p1 + sPlayerbotAIConfig->randomClassSpecProb[cls][1]; - specTab = point < p1 ? 0 : (point < p2 ? 1 : 2); + uint32 point = urand(1, 100); + uint32 currentP = 0; + int i; + for (i = 0; i < MAX_SPECNO; i++) + { + currentP += sPlayerbotAIConfig->randomClassSpecProb[cls][i]; + if (point <= currentP) + { + specTab = i; + break; + } + } + if (i == MAX_SPECNO) + { + specTab = 0; + LOG_ERROR("playerbots", "Fail to select spec num for bot {}! Set to 0.", bot->GetName()); + } } if (reset) { @@ -896,12 +913,13 @@ void PlayerbotFactory::InitTalentsTree(bool increment /*false*/, bool use_templa { InitTalentsByTemplate(specTab); } - else - { - InitTalents(specTab); - if (bot->GetFreeTalentPoints()) - InitTalents((specTab + 1) % 3); - } + // always use template now + // else + // { + // InitTalents(specTab); + // if (bot->GetFreeTalentPoints()) + // InitTalents((specTab + 1) % 3); + // } bot->SendTalentsInfoData(false); } @@ -1433,7 +1451,7 @@ void Shuffle(std::vector& items) void PlayerbotFactory::InitEquipment(bool incremental) { std::unordered_map> items; - int tab = AiFactory::GetPlayerSpecTab(bot); + // int tab = AiFactory::GetPlayerSpecTab(bot); uint32 blevel = bot->GetLevel(); int32 delta = 2; @@ -3062,6 +3080,9 @@ void PlayerbotFactory::InitGlyphs(bool increment) uint8 cls = bot->getClass(); uint8 tab = AiFactory::GetPlayerSpecTab(bot); + /// @todo: fix cat druid hardcode + if (bot->getClass() == CLASS_DRUID && tab == DRUID_TAB_FERAL && PlayerbotAI::IsDps(bot)) + tab = 3; std::list glyphs; ItemTemplateContainer const* itemTemplates = sObjectMgr->GetItemTemplateStore(); for (ItemTemplateContainer::const_iterator i = itemTemplates->begin(); i != itemTemplates->end(); ++i) diff --git a/src/strategy/druid/CatDpsDruidStrategy.cpp b/src/strategy/druid/CatDpsDruidStrategy.cpp index 80120330..bb860b02 100644 --- a/src/strategy/druid/CatDpsDruidStrategy.cpp +++ b/src/strategy/druid/CatDpsDruidStrategy.cpp @@ -70,7 +70,7 @@ private: { return new ActionNode("mangle (cat)", /*P*/ nullptr, - /*A*/ NextAction::array(0, new NextAction("claw"), nullptr), + /*A*/ nullptr, /*C*/ nullptr); } @@ -122,38 +122,49 @@ CatDpsDruidStrategy::CatDpsDruidStrategy(PlayerbotAI* botAI) : FeralDruidStrateg NextAction** CatDpsDruidStrategy::getDefaultActions() { - return NextAction::array(0, new NextAction("mangle (cat)", ACTION_DEFAULT + 0.1f), nullptr); + return NextAction::array(0, new NextAction("mangle (cat)", ACTION_DEFAULT + 0.3f), + new NextAction("shred", ACTION_DEFAULT + 0.2f), nullptr); } void CatDpsDruidStrategy::InitTriggers(std::vector& triggers) { FeralDruidStrategy::InitTriggers(triggers); + // Default priority + triggers.push_back(new TriggerNode("high energy available", + NextAction::array(0, new NextAction("claw", ACTION_DEFAULT + 0.1f), nullptr))); triggers.push_back( - new TriggerNode("cat form", NextAction::array(0, new NextAction("cat form", ACTION_HIGH + 2), nullptr))); + new TriggerNode("faerie fire (feral)", + NextAction::array(0, new NextAction("faerie fire (feral)", ACTION_DEFAULT + 0.0f), nullptr))); + + // Main spell triggers.push_back( - new TriggerNode("rake", NextAction::array(0, new NextAction("rake", ACTION_NORMAL + 5), nullptr))); + new TriggerNode("cat form", NextAction::array(0, new NextAction("cat form", ACTION_HIGH + 8), nullptr))); + + triggers.push_back(new TriggerNode("tiger's fury", + NextAction::array(0, new NextAction("tiger's fury", ACTION_HIGH + 7), nullptr))); + triggers.push_back( + new TriggerNode("savage roar", NextAction::array(0, new NextAction("savage roar", ACTION_HIGH + 5), nullptr))); + triggers.push_back(new TriggerNode("combo points available", + NextAction::array(0, new NextAction("rip", ACTION_HIGH + 4), nullptr))); triggers.push_back(new TriggerNode( - "combo points available", NextAction::array(0, new NextAction("ferocious bite", ACTION_NORMAL + 9), nullptr))); + "combo points available", NextAction::array(0, new NextAction("ferocious bite", ACTION_HIGH + 3), nullptr))); + triggers.push_back(new TriggerNode("target with combo points almost dead", + NextAction::array(0, new NextAction("ferocious bite", ACTION_HIGH + 2), nullptr))); + triggers.push_back(new TriggerNode("rake", NextAction::array(0, new NextAction("rake", ACTION_HIGH + 2), nullptr))); triggers.push_back( - new TriggerNode("medium threat", NextAction::array(0, new NextAction("cower", ACTION_EMERGENCY + 1), nullptr))); + new TriggerNode("medium threat", NextAction::array(0, new NextAction("cower", ACTION_HIGH + 1), nullptr))); + + // AOE + triggers.push_back( + new TriggerNode("medium aoe", NextAction::array(0, new NextAction("swipe (cat)", ACTION_HIGH + 3), nullptr))); triggers.push_back(new TriggerNode( - "faerie fire (feral)", NextAction::array(0, new NextAction("faerie fire (feral)", ACTION_HIGH), nullptr))); + "light aoe", NextAction::array(0, new NextAction("rake on attacker", ACTION_HIGH + 2), nullptr))); + // Reach target triggers.push_back(new TriggerNode( - "tiger's fury", NextAction::array(0, new NextAction("tiger's fury", ACTION_EMERGENCY + 1), nullptr))); + "enemy out of melee", NextAction::array(0, new NextAction("feral charge - cat", ACTION_HIGH + 9), nullptr))); triggers.push_back( - new TriggerNode("behind target", NextAction::array(0, new NextAction("pounce", ACTION_HIGH + 1), nullptr))); - // triggers.push_back(new TriggerNode("player has no flag", NextAction::array(0, new NextAction("prowl", - // ACTION_HIGH), nullptr))); triggers.push_back(new TriggerNode("enemy out of melee", NextAction::array(0, new - // NextAction("prowl", ACTION_INTERRUPT + 1), nullptr))); - triggers.push_back( - new TriggerNode("player has flag", NextAction::array(0, new NextAction("dash", ACTION_EMERGENCY), nullptr))); - triggers.push_back(new TriggerNode("enemy flagcarrier near", - NextAction::array(0, new NextAction("dash", ACTION_EMERGENCY), nullptr))); + new TriggerNode("enemy out of melee", NextAction::array(0, new NextAction("dash", ACTION_HIGH + 8), nullptr))); } -void CatAoeDruidStrategy::InitTriggers(std::vector& triggers) -{ - triggers.push_back( - new TriggerNode("medium aoe", NextAction::array(0, new NextAction("swipe (cat)", ACTION_HIGH + 2), nullptr))); -} +void CatAoeDruidStrategy::InitTriggers(std::vector& triggers) {} diff --git a/src/strategy/druid/DruidAiObjectContext.cpp b/src/strategy/druid/DruidAiObjectContext.cpp index b1181ae2..61e66e95 100644 --- a/src/strategy/druid/DruidAiObjectContext.cpp +++ b/src/strategy/druid/DruidAiObjectContext.cpp @@ -83,6 +83,8 @@ public: creators["moonfire"] = &DruidTriggerFactoryInternal::moonfire; creators["nature's grasp"] = &DruidTriggerFactoryInternal::natures_grasp; creators["tiger's fury"] = &DruidTriggerFactoryInternal::tigers_fury; + creators["berserk"] = &DruidTriggerFactoryInternal::berserk; + creators["savage roar"] = &DruidTriggerFactoryInternal::savage_roar; creators["rake"] = &DruidTriggerFactoryInternal::rake; creators["mark of the wild"] = &DruidTriggerFactoryInternal::mark_of_the_wild; creators["mark of the wild on party"] = &DruidTriggerFactoryInternal::mark_of_the_wild_on_party; @@ -117,6 +119,8 @@ private: static Trigger* faerie_fire(PlayerbotAI* botAI) { return new FaerieFireTrigger(botAI); } static Trigger* natures_grasp(PlayerbotAI* botAI) { return new NaturesGraspTrigger(botAI); } static Trigger* tigers_fury(PlayerbotAI* botAI) { return new TigersFuryTrigger(botAI); } + static Trigger* berserk(PlayerbotAI* botAI) { return new BerserkTrigger(botAI); } + static Trigger* savage_roar(PlayerbotAI* botAI) { return new SavageRoarTrigger(botAI); } static Trigger* rake(PlayerbotAI* botAI) { return new RakeTrigger(botAI); } static Trigger* mark_of_the_wild(PlayerbotAI* botAI) { return new MarkOfTheWildTrigger(botAI); } static Trigger* mark_of_the_wild_on_party(PlayerbotAI* botAI) { return new MarkOfTheWildOnPartyTrigger(botAI); } @@ -174,6 +178,7 @@ public: creators["mangle (cat)"] = &DruidAiObjectContextInternal::mangle_cat; creators["swipe (cat)"] = &DruidAiObjectContextInternal::swipe_cat; creators["rake"] = &DruidAiObjectContextInternal::rake; + creators["rake on attacker"] = &DruidAiObjectContextInternal::rake_on_attacker; creators["ferocious bite"] = &DruidAiObjectContextInternal::ferocious_bite; creators["rip"] = &DruidAiObjectContextInternal::rip; creators["cower"] = &DruidAiObjectContextInternal::cower; @@ -188,6 +193,7 @@ public: creators["abolish poison on party"] = &DruidAiObjectContextInternal::abolish_poison_on_party; creators["berserk"] = &DruidAiObjectContextInternal::berserk; creators["tiger's fury"] = &DruidAiObjectContextInternal::tigers_fury; + creators["savage roar"] = &DruidAiObjectContextInternal::savage_roar; creators["mark of the wild"] = &DruidAiObjectContextInternal::mark_of_the_wild; creators["mark of the wild on party"] = &DruidAiObjectContextInternal::mark_of_the_wild_on_party; creators["regrowth"] = &DruidAiObjectContextInternal::regrowth; @@ -257,6 +263,7 @@ private: static Action* mangle_cat(PlayerbotAI* botAI) { return new CastMangleCatAction(botAI); } static Action* swipe_cat(PlayerbotAI* botAI) { return new CastSwipeCatAction(botAI); } static Action* rake(PlayerbotAI* botAI) { return new CastRakeAction(botAI); } + static Action* rake_on_attacker(PlayerbotAI* botAI) { return new CastRakeOnMeleeAttackersAction(botAI); } static Action* ferocious_bite(PlayerbotAI* botAI) { return new CastFerociousBiteAction(botAI); } static Action* rip(PlayerbotAI* botAI) { return new CastRipAction(botAI); } static Action* cower(PlayerbotAI* botAI) { return new CastCowerAction(botAI); } @@ -271,6 +278,7 @@ private: static Action* abolish_poison_on_party(PlayerbotAI* botAI) { return new CastAbolishPoisonOnPartyAction(botAI); } static Action* berserk(PlayerbotAI* botAI) { return new CastBerserkAction(botAI); } static Action* tigers_fury(PlayerbotAI* botAI) { return new CastTigersFuryAction(botAI); } + static Action* savage_roar(PlayerbotAI* botAI) { return new CastSavageRoarAction(botAI); } static Action* mark_of_the_wild(PlayerbotAI* botAI) { return new CastMarkOfTheWildAction(botAI); } static Action* mark_of_the_wild_on_party(PlayerbotAI* botAI) { return new CastMarkOfTheWildOnPartyAction(botAI); } static Action* regrowth(PlayerbotAI* botAI) { return new CastRegrowthAction(botAI); } diff --git a/src/strategy/druid/DruidCatActions.cpp b/src/strategy/druid/DruidCatActions.cpp new file mode 100644 index 00000000..fb3a0e88 --- /dev/null +++ b/src/strategy/druid/DruidCatActions.cpp @@ -0,0 +1,6 @@ +#include "DruidCatActions.h" + +bool CastMangleCatAction::isUseful() +{ + return CastMeleeDebuffSpellAction::isUseful() && !botAI->HasAura("mangle (bear)", GetTarget(), false, isOwner); +} \ No newline at end of file diff --git a/src/strategy/druid/DruidCatActions.h b/src/strategy/druid/DruidCatActions.h index 579bdd00..8adddf98 100644 --- a/src/strategy/druid/DruidCatActions.h +++ b/src/strategy/druid/DruidCatActions.h @@ -35,10 +35,23 @@ public: CastTigersFuryAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "tiger's fury") {} }; +class CastSavageRoarAction : public CastBuffSpellAction +{ +public: + CastSavageRoarAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "savage roar") {} + std::string const GetTargetName() override { return "current target"; } +}; + class CastRakeAction : public CastDebuffSpellAction { public: - CastRakeAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "rake") {} + CastRakeAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "rake", true, 6.0f) {} +}; + +class CastRakeOnMeleeAttackersAction : public CastDebuffSpellOnMeleeAttackerAction +{ +public: + CastRakeOnMeleeAttackersAction(PlayerbotAI* botAI) : CastDebuffSpellOnMeleeAttackerAction(botAI, "rake", true, 6.0f) {} }; class CastClawAction : public CastMeleeSpellAction @@ -47,10 +60,11 @@ public: CastClawAction(PlayerbotAI* botAI) : CastMeleeSpellAction(botAI, "claw") {} }; -class CastMangleCatAction : public CastMeleeSpellAction +class CastMangleCatAction : public CastMeleeDebuffSpellAction { public: - CastMangleCatAction(PlayerbotAI* botAI) : CastMeleeSpellAction(botAI, "mangle (cat)") {} + CastMangleCatAction(PlayerbotAI* botAI) : CastMeleeDebuffSpellAction(botAI, "mangle (cat)", false, 0.0f) {} + bool isUseful() override; }; class CastSwipeCatAction : public CastMeleeSpellAction @@ -65,10 +79,10 @@ public: CastFerociousBiteAction(PlayerbotAI* botAI) : CastMeleeSpellAction(botAI, "ferocious bite") {} }; -class CastRipAction : public CastMeleeSpellAction +class CastRipAction : public CastMeleeDebuffSpellAction { public: - CastRipAction(PlayerbotAI* botAI) : CastMeleeSpellAction(botAI, "rip") {} + CastRipAction(PlayerbotAI* botAI) : CastMeleeDebuffSpellAction(botAI, "rip", true, 12.0f) {} }; class CastShredAction : public CastMeleeSpellAction diff --git a/src/strategy/druid/DruidTriggers.h b/src/strategy/druid/DruidTriggers.h index 392b487e..14b210fe 100644 --- a/src/strategy/druid/DruidTriggers.h +++ b/src/strategy/druid/DruidTriggers.h @@ -95,10 +95,22 @@ public: BashInterruptSpellTrigger(PlayerbotAI* botAI) : InterruptSpellTrigger(botAI, "bash") {} }; -class TigersFuryTrigger : public BoostTrigger +class TigersFuryTrigger : public BuffTrigger { public: - TigersFuryTrigger(PlayerbotAI* botAI) : BoostTrigger(botAI, "tiger's fury") {} + TigersFuryTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "tiger's fury") {} +}; + +class BerserkTrigger : public BoostTrigger +{ +public: + BerserkTrigger(PlayerbotAI* botAI) : BoostTrigger(botAI, "berserk") {} +}; + +class SavageRoarTrigger : public BuffTrigger +{ +public: + SavageRoarTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "savage roar") {} }; class NaturesGraspTrigger : public BoostTrigger diff --git a/src/strategy/druid/FeralDruidStrategy.cpp b/src/strategy/druid/FeralDruidStrategy.cpp index ed4b030b..91e315b2 100644 --- a/src/strategy/druid/FeralDruidStrategy.cpp +++ b/src/strategy/druid/FeralDruidStrategy.cpp @@ -112,4 +112,6 @@ void FeralDruidStrategy::InitTriggers(std::vector& triggers) NextAction::array(0, new NextAction("dash", ACTION_EMERGENCY + 2), nullptr))); triggers.push_back(new TriggerNode("enemy flagcarrier near", NextAction::array(0, new NextAction("dash", ACTION_EMERGENCY + 2), nullptr))); + triggers.push_back( + new TriggerNode("berserk", NextAction::array(0, new NextAction("berserk", ACTION_HIGH + 6), nullptr))); } diff --git a/src/strategy/values/AttackerWithoutAuraTargetValue.cpp b/src/strategy/values/AttackerWithoutAuraTargetValue.cpp index a3945e64..99489af4 100644 --- a/src/strategy/values/AttackerWithoutAuraTargetValue.cpp +++ b/src/strategy/values/AttackerWithoutAuraTargetValue.cpp @@ -36,3 +36,36 @@ Unit* AttackerWithoutAuraTargetValue::Calculate() return result; } + +Unit* MeleeAttackerWithoutAuraTargetValue::Calculate() +{ + GuidVector attackers = botAI->GetAiObjectContext()->GetValue("attackers")->Get(); + // Unit* target = botAI->GetAiObjectContext()->GetValue("current target")->Get(); + uint32 max_health = 0; + Unit* result = nullptr; + for (ObjectGuid const guid : attackers) + { + Unit* unit = botAI->GetUnit(guid); + if (!unit || !unit->IsAlive()) + continue; + + if (!bot->IsWithinMeleeRange(unit)) + continue; + + if (checkArc && !bot->HasInArc(CAST_ANGLE_IN_FRONT, unit)) + continue; + + if (unit->GetHealth() < max_health) + { + continue; + } + + if (!botAI->HasAura(qualifier, unit, false, true)) + { + max_health = unit->GetHealth(); + result = unit; + } + } + + return result; +} diff --git a/src/strategy/values/AttackerWithoutAuraTargetValue.h b/src/strategy/values/AttackerWithoutAuraTargetValue.h index 73867f9d..7d7d0666 100644 --- a/src/strategy/values/AttackerWithoutAuraTargetValue.h +++ b/src/strategy/values/AttackerWithoutAuraTargetValue.h @@ -28,7 +28,9 @@ protected: class MeleeAttackerWithoutAuraTargetValue : public AttackerWithoutAuraTargetValue { public: - MeleeAttackerWithoutAuraTargetValue(PlayerbotAI* botAI) : AttackerWithoutAuraTargetValue(botAI, "melee") {} + MeleeAttackerWithoutAuraTargetValue(PlayerbotAI* botAI, bool checkArc = true) : AttackerWithoutAuraTargetValue(botAI, "melee"), checkArc(checkArc) {} + Unit* Calculate() override; + bool checkArc; }; #endif diff --git a/src/strategy/values/ExpectedLifetimeValue.cpp b/src/strategy/values/ExpectedLifetimeValue.cpp index a8a554b6..0f3f4b83 100644 --- a/src/strategy/values/ExpectedLifetimeValue.cpp +++ b/src/strategy/values/ExpectedLifetimeValue.cpp @@ -13,6 +13,9 @@ float ExpectedLifetimeValue::Calculate() return 0.0f; } float dps = AI_VALUE(float, "expected group dps"); + bool aoePenalty = AI_VALUE(uint8, "attacker count") >= 3; + if (aoePenalty) + dps *= 0.75; float res = target->GetHealth() / dps; // bot->Say(target->GetName() + " lifetime: " + std::to_string(res), LANG_UNIVERSAL); return res;