diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index d7d02059..f158327a 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -1002,16 +1002,16 @@ AiPlayerbot.PremadeSpecLink.9.2.80 = -03310030003-05203205210331051335230351 AiPlayerbot.PremadeSpecName.11.0 = balance pve AiPlayerbot.PremadeSpecGlyph.11.0 = 40916,43331,40921,43335,44922,40919 -AiPlayerbot.PremadeSpecLink.11.0.60 = 5012203115331003213302301231 -AiPlayerbot.PremadeSpecLink.11.0.80 = 5012203125331103213305301231--205003212 +AiPlayerbot.PremadeSpecLink.11.0.60 = 5022203105331003213005301231 +AiPlayerbot.PremadeSpecLink.11.0.80 = 5032203105331303213305301231--205003012 AiPlayerbot.PremadeSpecName.11.1 = bear pve AiPlayerbot.PremadeSpecGlyph.11.1 = 40897,43331,46372,43335,43332,40899 AiPlayerbot.PremadeSpecLink.11.1.60 = -500232130322110353100301310501 AiPlayerbot.PremadeSpecLink.11.1.80 = -501232130322110353120303313511-20350001 AiPlayerbot.PremadeSpecName.11.2 = resto pve AiPlayerbot.PremadeSpecGlyph.11.2 = 40913,43331,40906,43335,44922,45602 -AiPlayerbot.PremadeSpecLink.11.2.60 = --230033312031501531050013051 -AiPlayerbot.PremadeSpecLink.11.2.80 = 05320001--230033312031512531153313051 +AiPlayerbot.PremadeSpecLink.11.2.60 = --230033312031500531050113051 +AiPlayerbot.PremadeSpecLink.11.2.80 = 05320031--230033312031501531053313051 AiPlayerbot.PremadeSpecName.11.3 = cat pve AiPlayerbot.PremadeSpecGlyph.11.3 = 40902,43331,40901,43335,44922,45604 AiPlayerbot.PremadeSpecLink.11.3.60 = -552202032322010053100030310501 diff --git a/src/AiFactory.cpp b/src/AiFactory.cpp index dadf327f..d3cd1ef3 100644 --- a/src/AiFactory.cpp +++ b/src/AiFactory.cpp @@ -277,10 +277,6 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa { engine->addStrategiesNoInit("racials", "chat", "default", "cast time", "duel", "boost", nullptr); } - if (sPlayerbotAIConfig->autoSaveMana) - { - engine->addStrategy("save mana", false); - } if (sPlayerbotAIConfig->autoAvoidAoe && facade->HasRealPlayerMaster()) { engine->addStrategy("avoid aoe", false); @@ -394,7 +390,12 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa if (PlayerbotAI::IsMelee(player, true) && PlayerbotAI::IsDps(player, true)) { engine->addStrategy("behind", false); } - + if (PlayerbotAI::IsHeal(player, true)) + { + if (sPlayerbotAIConfig->autoSaveMana) + engine->addStrategy("save mana", false); + engine->addStrategy("healer dps", false); + } if (facade->IsRealPlayer() || sRandomPlayerbotMgr->IsRandomBot(player)) { if (!player->GetGroup()) @@ -483,8 +484,8 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa engine->removeStrategy("threat", false); engine->addStrategy("boost", false); - if ((player->getClass() == CLASS_DRUID && tab == 2) || (player->getClass() == CLASS_SHAMAN && tab == 2)) - engine->addStrategiesNoInit("caster", "caster aoe", nullptr); + // if ((player->getClass() == CLASS_DRUID && tab == 2) || (player->getClass() == CLASS_SHAMAN && tab == 2)) + // engine->addStrategiesNoInit("caster", "caster aoe", nullptr); // if (player->getClass() == CLASS_DRUID && tab == 1) // engine->addStrategiesNoInit(/*"behind",*/ "dps", nullptr); diff --git a/src/PlayerbotAI.cpp b/src/PlayerbotAI.cpp index 4f79196f..1200e050 100644 --- a/src/PlayerbotAI.cpp +++ b/src/PlayerbotAI.cpp @@ -317,13 +317,13 @@ void PlayerbotAI::UpdateAI(uint32 elapsed, bool minimal) Spell* currentSpell = bot->GetCurrentSpell(CURRENT_GENERIC_SPELL); if (!currentSpell) currentSpell = bot->GetCurrentSpell(CURRENT_CHANNELED_SPELL); - if (currentSpell && currentSpell->getState() == SPELL_STATE_PREPARING) + if (currentSpell && currentSpell->GetSpellInfo() && currentSpell->getState() == SPELL_STATE_PREPARING) { const SpellInfo* spellInfo = currentSpell->GetSpellInfo(); // interrupt if target is dead if (currentSpell->m_targets.GetUnitTarget() && !currentSpell->m_targets.GetUnitTarget()->IsAlive() && - spellInfo && !spellInfo->IsAllowingDeadTarget()) + !spellInfo->IsAllowingDeadTarget()) { InterruptSpell(); SetNextCheckDelay(sPlayerbotAIConfig->reactDelay); @@ -703,8 +703,7 @@ void PlayerbotAI::HandleTeleportAck() p << (uint32)0; // supposed to be flags? not used currently p << (uint32)0; // time - not currently used bot->GetSession()->HandleMoveTeleportAck(p); - } - SetNextCheckDelay(urand(1000, 3000)); + }; } if (bot->IsBeingTeleportedFar()) { @@ -712,13 +711,13 @@ void PlayerbotAI::HandleTeleportAck() { bot->GetSession()->HandleMoveWorldportAck(); } - SetNextCheckDelay(urand(2000, 5000)); + // SetNextCheckDelay(urand(2000, 5000)); if (sPlayerbotAIConfig->applyInstanceStrategies) ApplyInstanceStrategies(bot->GetMapId(), true); + Reset(); } SetNextCheckDelay(sPlayerbotAIConfig->globalCoolDown); - Reset(); } void PlayerbotAI::Reset(bool full) @@ -1198,7 +1197,7 @@ void PlayerbotAI::HandleBotOutgoingPacket(WorldPacket const& packet) void PlayerbotAI::SpellInterrupted(uint32 spellid) { - for (uint8 type = CURRENT_MELEE_SPELL; type < CURRENT_CHANNELED_SPELL; type++) + for (uint8 type = CURRENT_MELEE_SPELL; type <= CURRENT_CHANNELED_SPELL; type++) { Spell* spell = bot->GetCurrentSpell((CurrentSpellTypes)type); if (!spell) @@ -1206,8 +1205,8 @@ void PlayerbotAI::SpellInterrupted(uint32 spellid) if (spell->GetSpellInfo()->Id == spellid) bot->InterruptSpell((CurrentSpellTypes)type); } - LastSpellCast& lastSpell = aiObjectContext->GetValue("last spell cast")->Get(); - lastSpell.id = 0; + // LastSpellCast& lastSpell = aiObjectContext->GetValue("last spell cast")->Get(); + // lastSpell.id = 0; } int32 PlayerbotAI::CalculateGlobalCooldown(uint32 spellid) @@ -3339,11 +3338,11 @@ bool PlayerbotAI::CastSpell(uint32 spellId, Unit* target, Item* itemTarget) // } // } - WaitForSpellCast(spell); - if (spell->GetCastTime()) - aiObjectContext->GetValue("last spell cast") - ->Get() - .Set(spellId, target->GetGUID(), time(nullptr)); + // WaitForSpellCast(spell); + + aiObjectContext->GetValue("last spell cast") + ->Get() + .Set(spellId, target->GetGUID(), time(nullptr)); aiObjectContext->GetValue("position")->Get()["random"].Reset(); @@ -3473,7 +3472,7 @@ bool PlayerbotAI::CastSpell(uint32 spellId, float x, float y, float z, Item* ite } } - WaitForSpellCast(spell); + // WaitForSpellCast(spell); aiObjectContext->GetValue("last spell cast")->Get().Set(spellId, bot->GetGUID(), time(nullptr)); aiObjectContext->GetValue("position")->Get()["random"].Reset(); @@ -3688,7 +3687,7 @@ bool PlayerbotAI::CastVehicleSpell(uint32 spellId, Unit* target) return false; } - WaitForSpellCast(spell); + // WaitForSpellCast(spell); // aiObjectContext->GetValue("last spell cast")->Get().Set(spellId, target->GetGUID(), time(0)); // aiObjectContext->GetValue("position")->Get()["random"].Reset(); @@ -3745,23 +3744,15 @@ bool PlayerbotAI::IsInVehicle(bool canControl, bool canCast, bool canAttack, boo void PlayerbotAI::WaitForSpellCast(Spell* spell) { - return; SpellInfo const* spellInfo = spell->GetSpellInfo(); uint32 castTime = spell->GetCastTime(); - // float castTime = spell->GetCastTime(); - // if (spellInfo->IsChanneled()) - // { - // int32 duration = spellInfo->GetDuration(); - // bot->ApplySpellMod(spellInfo->Id, SPELLMOD_DURATION, duration); - // if (duration > 0) - // castTime += duration; - // } - - // castTime = ceil(castTime); - - // uint32 globalCooldown = CalculateGlobalCooldown(spellInfo->Id); - // if (castTime < globalCooldown) - // castTime = globalCooldown; + if (spellInfo->IsChanneled()) + { + int32 duration = spellInfo->GetDuration(); + bot->ApplySpellMod(spellInfo->Id, SPELLMOD_DURATION, duration); + if (duration > 0) + castTime += duration; + } SetNextCheckDelay(castTime + sPlayerbotAIConfig->reactDelay); } diff --git a/src/strategy/AiObjectContext.h b/src/strategy/AiObjectContext.h index f7bd2694..07fa78a6 100644 --- a/src/strategy/AiObjectContext.h +++ b/src/strategy/AiObjectContext.h @@ -10,6 +10,7 @@ #include #include "Common.h" +#include "DynamicObject.h" #include "NamedObjectContext.h" #include "PlayerbotAIAware.h" #include "Strategy.h" diff --git a/src/strategy/Engine.cpp b/src/strategy/Engine.cpp index d298aaf5..a9569a20 100644 --- a/src/strategy/Engine.cpp +++ b/src/strategy/Engine.cpp @@ -202,9 +202,9 @@ bool Engine::DoNextAction(Unit* unit, uint32 depth, bool minimal) { LogAction("A:%s - PREREQ", action->getName().c_str()); - if (MultiplyAndPush(actionNode->getPrerequisites(), relevance + 0.02, false, event, "prereq")) + if (MultiplyAndPush(actionNode->getPrerequisites(), relevance + 0.002f, false, event, "prereq")) { - PushAgain(actionNode, relevance + 0.01, event); + PushAgain(actionNode, relevance + 0.001f, event); continue; } } @@ -226,7 +226,7 @@ bool Engine::DoNextAction(Unit* unit, uint32 depth, bool minimal) else { LogAction("A:%s - FAILED", action->getName().c_str()); - MultiplyAndPush(actionNode->getAlternatives(), relevance + 0.03, false, event, "alt"); + MultiplyAndPush(actionNode->getAlternatives(), relevance + 0.003f, false, event, "alt"); } } else @@ -246,7 +246,7 @@ bool Engine::DoNextAction(Unit* unit, uint32 depth, bool minimal) botAI->TellMasterNoFacing(out); } LogAction("A:%s - IMPOSSIBLE", action->getName().c_str()); - MultiplyAndPush(actionNode->getAlternatives(), relevance + 0.03, false, event, "alt"); + MultiplyAndPush(actionNode->getAlternatives(), relevance + 0.003f, false, event, "alt"); } } else diff --git a/src/strategy/actions/GenericActions.cpp b/src/strategy/actions/GenericActions.cpp index 9682d2ef..84997212 100644 --- a/src/strategy/actions/GenericActions.cpp +++ b/src/strategy/actions/GenericActions.cpp @@ -38,7 +38,7 @@ bool TogglePetSpellAutoCastAction::Execute(Event event) bool shouldApply = true; // imp's spell, felhunte's intelligence, cat stealth if (spellId == 4511 || spellId == 1742 || spellId == 54424 || spellId == 57564 || spellId == 57565 || - spellId == 57566 || spellId == 57567 || spellId == 24450 || spellId == 53477) + spellId == 57566 || spellId == 57567 || spellId == 24450) { shouldApply = false; } diff --git a/src/strategy/actions/GenericSpellActions.cpp b/src/strategy/actions/GenericSpellActions.cpp index 9285f20a..749bed14 100644 --- a/src/strategy/actions/GenericSpellActions.cpp +++ b/src/strategy/actions/GenericSpellActions.cpp @@ -196,8 +196,8 @@ bool CastEnchantItemAction::isPossible() } CastHealingSpellAction::CastHealingSpellAction(PlayerbotAI* botAI, std::string const spell, uint8 estAmount, - HealingManaEfficiency manaEfficiency) - : CastAuraSpellAction(botAI, spell, true), estAmount(estAmount), manaEfficiency(manaEfficiency) + HealingManaEfficiency manaEfficiency, bool isOwner) + : CastAuraSpellAction(botAI, spell, isOwner), estAmount(estAmount), manaEfficiency(manaEfficiency) { range = botAI->GetRange("heal"); } diff --git a/src/strategy/actions/GenericSpellActions.h b/src/strategy/actions/GenericSpellActions.h index 2ab49bb0..be1dc200 100644 --- a/src/strategy/actions/GenericSpellActions.h +++ b/src/strategy/actions/GenericSpellActions.h @@ -129,7 +129,7 @@ class CastHealingSpellAction : public CastAuraSpellAction { public: CastHealingSpellAction(PlayerbotAI* botAI, std::string const spell, uint8 estAmount = 15.0f, - HealingManaEfficiency manaEfficiency = HealingManaEfficiency::MEDIUM); + HealingManaEfficiency manaEfficiency = HealingManaEfficiency::MEDIUM, bool isOwner = true); std::string const GetTargetName() override { return "self target"; } bool isUseful() override; @@ -177,8 +177,8 @@ class HealPartyMemberAction : public CastHealingSpellAction, public PartyMemberA { public: HealPartyMemberAction(PlayerbotAI* botAI, std::string const spell, uint8 estAmount = 15.0f, - HealingManaEfficiency manaEfficiency = HealingManaEfficiency::MEDIUM) - : CastHealingSpellAction(botAI, spell, estAmount, manaEfficiency), PartyMemberActionNameSupport(spell) + HealingManaEfficiency manaEfficiency = HealingManaEfficiency::MEDIUM, bool isOwner = true) + : CastHealingSpellAction(botAI, spell, estAmount, manaEfficiency, isOwner), PartyMemberActionNameSupport(spell) { } diff --git a/src/strategy/actions/MovementActions.cpp b/src/strategy/actions/MovementActions.cpp index e07fc79a..569d7fcc 100644 --- a/src/strategy/actions/MovementActions.cpp +++ b/src/strategy/actions/MovementActions.cpp @@ -827,11 +827,12 @@ bool MovementAction::ReachCombatTo(Unit* target, float distance) float shortenTo = distance; // Avoid walking too far when moving towards each other - if (bot->GetDistance(tx, ty, tz) >= 10.0f) - shortenTo = std::max(distance, bot->GetDistance(tx, ty, tz) / 2); + float disToGo = bot->GetExactDist(tx, ty, tz) - distance; + if (disToGo >= 10.0f) + shortenTo = disToGo / 2 + distance; - if (bot->GetExactDist(tx, ty, tz) <= shortenTo) - return false; + // if (bot->GetExactDist(tx, ty, tz) <= shortenTo) + // return false; path.ShortenPathUntilDist(G3D::Vector3(tx, ty, tz), shortenTo); G3D::Vector3 endPos = path.GetPath().back(); @@ -2313,7 +2314,7 @@ bool TankFaceAction::Execute(Event event) if (!bot->GetGroup()) return false; - if (!bot->IsWithinMeleeRange(target)) + if (!bot->IsWithinMeleeRange(target) || target->isMoving()) return false; if (!AI_VALUE2(bool, "has aggro", "current target")) @@ -2513,7 +2514,7 @@ bool SetBehindTargetAction::Execute(Event event) if (target->GetVictim() == bot) return false; - if (!bot->IsWithinMeleeRange(target)) + if (!bot->IsWithinMeleeRange(target) || target->isMoving()) return false; float deltaAngle = Position::NormalizeOrientation(target->GetOrientation() - target->GetAngle(bot)); diff --git a/src/strategy/druid/CasterDruidStrategy.cpp b/src/strategy/druid/CasterDruidStrategy.cpp index 1dfeadfa..27080efe 100644 --- a/src/strategy/druid/CasterDruidStrategy.cpp +++ b/src/strategy/druid/CasterDruidStrategy.cpp @@ -145,15 +145,12 @@ void CasterDruidStrategy::InitTriggers(std::vector& triggers) new TriggerNode("medium mana", NextAction::array(0, new NextAction("innervate", ACTION_HIGH + 9), NULL))); triggers.push_back(new TriggerNode("enemy too close for spell", NextAction::array(0, new NextAction("flee", ACTION_MOVE + 9), nullptr))); - triggers.push_back( - new TriggerNode("party member remove curse", - NextAction::array(0, new NextAction("remove curse on party", ACTION_DISPEL + 7), NULL))); } void CasterDruidAoeStrategy::InitTriggers(std::vector& triggers) { triggers.push_back( - new TriggerNode("high aoe", NextAction::array(0, new NextAction("hurricane", ACTION_HIGH + 1), nullptr))); + new TriggerNode("medium aoe", NextAction::array(0, new NextAction("hurricane", ACTION_HIGH + 1), nullptr))); triggers.push_back(new TriggerNode( "light aoe", NextAction::array(0, new NextAction("starfall", ACTION_NORMAL + 5), new NextAction("insect swarm on attacker", ACTION_NORMAL + 3), diff --git a/src/strategy/druid/DruidActions.cpp b/src/strategy/druid/DruidActions.cpp index 739ac941..1743a339 100644 --- a/src/strategy/druid/DruidActions.cpp +++ b/src/strategy/druid/DruidActions.cpp @@ -47,4 +47,35 @@ bool CastRebirthAction::isUseful() { return CastSpellAction::isUseful() && AI_VALUE2(float, "distance", GetTargetName()) <= sPlayerbotAIConfig->spellDistance; +} + +Unit* CastRejuvenationOnNotFullAction::GetTarget() +{ + Group* group = bot->GetGroup(); + MinValueCalculator calc(100); + for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next()) + { + Player* player = gref->GetSource(); + if (!player) + continue; + if (player->isDead() || player->IsFullHealth()) + { + continue; + } + if (player->GetDistance2d(bot) > sPlayerbotAIConfig->spellDistance) + { + continue; + } + if (botAI->HasAura("rejuvenation", player)) + { + continue; + } + calc.probe(player->GetHealthPct(), player); + } + return (Unit*)calc.param; +} + +bool CastRejuvenationOnNotFullAction::isUseful() +{ + return GetTarget(); } \ No newline at end of file diff --git a/src/strategy/druid/DruidActions.h b/src/strategy/druid/DruidActions.h index 749ba3ea..ee90788a 100644 --- a/src/strategy/druid/DruidActions.h +++ b/src/strategy/druid/DruidActions.h @@ -311,4 +311,16 @@ public: CastEnrageAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "enrage") {} }; + +class CastRejuvenationOnNotFullAction : public HealPartyMemberAction +{ +public: + CastRejuvenationOnNotFullAction(PlayerbotAI* ai) + : HealPartyMemberAction(ai, "rejuvenation", 5.0f, HealingManaEfficiency::VERY_HIGH) + { + } + bool isUseful() override; + Unit* GetTarget() override; +}; + #endif diff --git a/src/strategy/druid/DruidAiObjectContext.cpp b/src/strategy/druid/DruidAiObjectContext.cpp index 04652487..e0d8c7de 100644 --- a/src/strategy/druid/DruidAiObjectContext.cpp +++ b/src/strategy/druid/DruidAiObjectContext.cpp @@ -14,6 +14,7 @@ #include "DruidShapeshiftActions.h" #include "DruidTriggers.h" #include "GenericDruidNonCombatStrategy.h" +#include "GenericDruidStrategy.h" #include "HealDruidStrategy.h" #include "MeleeDruidStrategy.h" #include "Playerbots.h" @@ -33,6 +34,7 @@ public: creators["buff"] = &DruidStrategyFactoryInternal::buff; creators["boost"] = &DruidStrategyFactoryInternal::boost; creators["cc"] = &DruidStrategyFactoryInternal::cc; + creators["healer dps"] = &DruidStrategyFactoryInternal::healer_dps; } private: @@ -45,6 +47,7 @@ private: static Strategy* buff(PlayerbotAI* botAI) { return new GenericDruidBuffStrategy(botAI); } static Strategy* boost(PlayerbotAI* botAI) { return new DruidBoostStrategy(botAI); } static Strategy* cc(PlayerbotAI* botAI) { return new DruidCcStrategy(botAI); } + static Strategy* healer_dps(PlayerbotAI* botAI) { return new DruidHealerDpsStrategy(botAI); } }; class DruidDruidStrategyFactoryInternal : public NamedObjectContext @@ -161,6 +164,7 @@ public: creators["travel form"] = &DruidAiObjectContextInternal::travel_form; creators["aquatic form"] = &DruidAiObjectContextInternal::aquatic_form; creators["caster form"] = &DruidAiObjectContextInternal::caster_form; + creators["cancel tree form"] = &DruidAiObjectContextInternal::cancel_tree_form; creators["mangle (bear)"] = &DruidAiObjectContextInternal::mangle_bear; creators["maul"] = &DruidAiObjectContextInternal::maul; creators["bash"] = &DruidAiObjectContextInternal::bash; @@ -205,6 +209,7 @@ public: creators["healing touch"] = &DruidAiObjectContextInternal::healing_touch; creators["regrowth on party"] = &DruidAiObjectContextInternal::regrowth_on_party; creators["rejuvenation on party"] = &DruidAiObjectContextInternal::rejuvenation_on_party; + creators["rejuvenation on not full"] = &DruidAiObjectContextInternal::rejuvenation_on_not_full; creators["healing touch on party"] = &DruidAiObjectContextInternal::healing_touch_on_party; creators["rebirth"] = &DruidAiObjectContextInternal::rebirth; creators["revive"] = &DruidAiObjectContextInternal::revive; @@ -246,6 +251,7 @@ private: static Action* travel_form(PlayerbotAI* botAI) { return new CastTravelFormAction(botAI); } static Action* aquatic_form(PlayerbotAI* botAI) { return new CastAquaticFormAction(botAI); } static Action* caster_form(PlayerbotAI* botAI) { return new CastCasterFormAction(botAI); } + static Action* cancel_tree_form(PlayerbotAI* botAI) { return new CastCancelTreeFormAction(botAI); } static Action* mangle_bear(PlayerbotAI* botAI) { return new CastMangleBearAction(botAI); } static Action* maul(PlayerbotAI* botAI) { return new CastMaulAction(botAI); } static Action* bash(PlayerbotAI* botAI) { return new CastBashAction(botAI); } @@ -290,6 +296,7 @@ private: static Action* healing_touch(PlayerbotAI* botAI) { return new CastHealingTouchAction(botAI); } static Action* regrowth_on_party(PlayerbotAI* botAI) { return new CastRegrowthOnPartyAction(botAI); } static Action* rejuvenation_on_party(PlayerbotAI* botAI) { return new CastRejuvenationOnPartyAction(botAI); } + static Action* rejuvenation_on_not_full(PlayerbotAI* botAI) { return new CastRejuvenationOnNotFullAction(botAI); } static Action* healing_touch_on_party(PlayerbotAI* botAI) { return new CastHealingTouchOnPartyAction(botAI); } static Action* rebirth(PlayerbotAI* botAI) { return new CastRebirthAction(botAI); } static Action* revive(PlayerbotAI* botAI) { return new CastReviveAction(botAI); } diff --git a/src/strategy/druid/DruidShapeshiftActions.cpp b/src/strategy/druid/DruidShapeshiftActions.cpp index 9894b1f5..4354328e 100644 --- a/src/strategy/druid/DruidShapeshiftActions.cpp +++ b/src/strategy/druid/DruidShapeshiftActions.cpp @@ -45,6 +45,17 @@ bool CastCasterFormAction::Execute(Event event) return true; } +bool CastCancelTreeFormAction::isUseful() +{ + return botAI->HasAura(33891, bot); +} + +bool CastCancelTreeFormAction::Execute(Event event) +{ + botAI->RemoveAura("tree of life"); + return true; +} + bool CastTreeFormAction::isUseful() { return GetTarget() && CastSpellAction::isUseful() && !botAI->HasAura(33891, bot); diff --git a/src/strategy/druid/DruidShapeshiftActions.h b/src/strategy/druid/DruidShapeshiftActions.h index 1f8fc082..6b24208b 100644 --- a/src/strategy/druid/DruidShapeshiftActions.h +++ b/src/strategy/druid/DruidShapeshiftActions.h @@ -70,4 +70,14 @@ public: bool Execute(Event event) override; }; +class CastCancelTreeFormAction : public CastBuffSpellAction +{ +public: + CastCancelTreeFormAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "cancel tree form") {} + + bool isUseful() override; + bool isPossible() override { return true; } + bool Execute(Event event) override; +}; + #endif diff --git a/src/strategy/druid/GenericDruidNonCombatStrategy.cpp b/src/strategy/druid/GenericDruidNonCombatStrategy.cpp index 398ba274..be5e822f 100644 --- a/src/strategy/druid/GenericDruidNonCombatStrategy.cpp +++ b/src/strategy/druid/GenericDruidNonCombatStrategy.cpp @@ -125,26 +125,34 @@ void GenericDruidNonCombatStrategy::InitTriggers(std::vector& trig triggers.push_back( new TriggerNode("party member critical health", - NextAction::array(0, new NextAction("rejuvenation on party", ACTION_MEDIUM_HEAL + 5), - new NextAction("regrowth on party", ACTION_MEDIUM_HEAL + 6), NULL))); + NextAction::array(0, + new NextAction("wild growth on party", ACTION_MEDIUM_HEAL + 7), + new NextAction("regrowth on party", ACTION_MEDIUM_HEAL + 6), + new NextAction("rejuvenation on party", ACTION_MEDIUM_HEAL + 5), + nullptr))); triggers.push_back( new TriggerNode("party member low health", - NextAction::array(0, new NextAction("rejuvenation on party", ACTION_MEDIUM_HEAL + 3), - new NextAction("regrowth on party", ACTION_MEDIUM_HEAL + 4), NULL))); + NextAction::array(0, + new NextAction("wild growth on party", ACTION_MEDIUM_HEAL + 5), + new NextAction("regrowth on party", ACTION_MEDIUM_HEAL + 4), + new NextAction("rejuvenation on party", ACTION_MEDIUM_HEAL + 3), + nullptr))); triggers.push_back( new TriggerNode("party member medium health", - NextAction::array(0, new NextAction("rejuvenation on party", ACTION_MEDIUM_HEAL + 1), - new NextAction("regrowth on party", ACTION_MEDIUM_HEAL + 2), NULL))); + NextAction::array(0, new NextAction("wild growth on party", ACTION_MEDIUM_HEAL + 3), + new NextAction("regrowth on party", ACTION_MEDIUM_HEAL + 2), + new NextAction("rejuvenation on party", ACTION_MEDIUM_HEAL + 1), + nullptr))); triggers.push_back( new TriggerNode("party member almost full health", - NextAction::array(0, new NextAction("rejuvenation on party", ACTION_LIGHT_HEAL + 2), NULL))); + NextAction::array(0, new NextAction("wild growth on party", ACTION_LIGHT_HEAL + 3), new NextAction("rejuvenation on party", ACTION_LIGHT_HEAL + 2), NULL))); triggers.push_back( new TriggerNode("party member remove curse", - NextAction::array(0, new NextAction("remove curse on party", ACTION_DISPEL + 7), NULL))); + NextAction::array(0, new NextAction("remove curse on party", ACTION_DISPEL + 7), nullptr))); } GenericDruidBuffStrategy::GenericDruidBuffStrategy(PlayerbotAI* botAI) : NonCombatStrategy(botAI) diff --git a/src/strategy/druid/GenericDruidStrategy.cpp b/src/strategy/druid/GenericDruidStrategy.cpp index c44668f7..d06a0e56 100644 --- a/src/strategy/druid/GenericDruidStrategy.cpp +++ b/src/strategy/druid/GenericDruidStrategy.cpp @@ -130,6 +130,11 @@ void DruidCureStrategy::InitTriggers(std::vector& triggers) triggers.push_back( new TriggerNode("party member cure poison", NextAction::array(0, new NextAction("abolish poison on party", ACTION_DISPEL + 1), nullptr))); + + triggers.push_back( + new TriggerNode("party member remove curse", + NextAction::array(0, new NextAction("remove curse on party", ACTION_DISPEL + 7), NULL))); + } void DruidBoostStrategy::InitTriggers(std::vector& triggers) @@ -147,3 +152,22 @@ void DruidCcStrategy::InitTriggers(std::vector& triggers) triggers.push_back(new TriggerNode( "hibernate", NextAction::array(0, new NextAction("hibernate on cc", ACTION_HIGH + 3), nullptr))); } + +void DruidHealerDpsStrategy::InitTriggers(std::vector& triggers) +{ + triggers.push_back( + new TriggerNode("healer should attack", + NextAction::array(0, + new NextAction("cancel tree form", ACTION_DEFAULT + 0.3f), + new NextAction("moonfire", ACTION_DEFAULT + 0.2f), + new NextAction("wrath", ACTION_DEFAULT + 0.1f), + new NextAction("starfire", ACTION_DEFAULT), + nullptr))); + + // long cast time + // triggers.push_back( + // new TriggerNode("medium aoe and healer should attack", + // NextAction::array(0, + // new NextAction("hurricane", ACTION_DEFAULT + 0.7f), + // nullptr))); +} diff --git a/src/strategy/druid/GenericDruidStrategy.h b/src/strategy/druid/GenericDruidStrategy.h index db6631b2..547b93b0 100644 --- a/src/strategy/druid/GenericDruidStrategy.h +++ b/src/strategy/druid/GenericDruidStrategy.h @@ -46,4 +46,13 @@ public: std::string const getName() override { return "cc"; } }; +class DruidHealerDpsStrategy : public Strategy +{ +public: + DruidHealerDpsStrategy(PlayerbotAI* botAI) : Strategy(botAI) {} + + void InitTriggers(std::vector& triggers) override; + std::string const getName() override { return "healer dps"; } +}; + #endif diff --git a/src/strategy/druid/HealDruidStrategy.cpp b/src/strategy/druid/HealDruidStrategy.cpp index 0da13563..b1e2f125 100644 --- a/src/strategy/druid/HealDruidStrategy.cpp +++ b/src/strategy/druid/HealDruidStrategy.cpp @@ -10,7 +10,12 @@ class HealDruidStrategyActionNodeFactory : public NamedObjectFactory { public: - HealDruidStrategyActionNodeFactory() { creators["nourish on party"] = &nourtish_on_party; } + HealDruidStrategyActionNodeFactory() { + creators["nourish on party"] = &nourtish_on_party; + // creators["wild growth on party"] = &wild_growth_on_party; + // creators["rejuvenation on party"] = &rejuvenation_on_party; + // creators["regrowth on party"] = ®rowth_on_party; + } private: static ActionNode* nourtish_on_party([[maybe_unused]] PlayerbotAI* botAI) @@ -20,6 +25,27 @@ private: /*A*/ NextAction::array(0, new NextAction("healing touch on party"), nullptr), /*C*/ nullptr); } + // static ActionNode* wild_growth_on_party([[maybe_unused]] PlayerbotAI* botAI) + // { + // return new ActionNode("wild growth on party", + // /*P*/ NextAction::array(0, new NextAction("tree form"), nullptr), + // /*A*/ nullptr, + // /*C*/ nullptr); + // } + // static ActionNode* rejuvenation_on_party([[maybe_unused]] PlayerbotAI* botAI) + // { + // return new ActionNode("rejuvenation on party", + // /*P*/ NextAction::array(0, new NextAction("tree form"), nullptr), + // /*A*/ nullptr, + // /*C*/ nullptr); + // } + // static ActionNode* regrowth_on_party([[maybe_unused]] PlayerbotAI* botAI) + // { + // return new ActionNode("regrowth on party", + // /*P*/ NextAction::array(0, new NextAction("tree form"), nullptr), + // /*A*/ nullptr, + // /*C*/ nullptr); + // } }; HealDruidStrategy::HealDruidStrategy(PlayerbotAI* botAI) : GenericDruidStrategy(botAI) @@ -31,61 +57,72 @@ void HealDruidStrategy::InitTriggers(std::vector& triggers) { GenericDruidStrategy::InitTriggers(triggers); - // triggers.push_back(new TriggerNode("enemy out of spell", NextAction::array(0, new NextAction("reach spell", - // ACTION_NORMAL + 9), nullptr))); - triggers.push_back( - new TriggerNode("tree form", NextAction::array(0, new NextAction("tree form", ACTION_HIGH + 1), nullptr))); + // triggers.push_back( + // new TriggerNode("tree form", NextAction::array(0, new NextAction("tree form", ACTION_HIGH + 1), nullptr))); + triggers.push_back(new TriggerNode( "party member to heal out of spell range", NextAction::array(0, new NextAction("reach party member to heal", ACTION_CRITICAL_HEAL + 9), nullptr))); - triggers.push_back( - new TriggerNode("party member remove curse", - NextAction::array(0, new NextAction("remove curse on party", ACTION_DISPEL + 7), NULL))); + // CRITICAL triggers.push_back( new TriggerNode("party member critical health", - NextAction::array(0, new NextAction("swiftmend on party", ACTION_CRITICAL_HEAL + 4), - new NextAction("wild growth", ACTION_CRITICAL_HEAL + 3), - new NextAction("regrowth on party", ACTION_CRITICAL_HEAL + 2), + NextAction::array(0, + new NextAction("tree form", ACTION_CRITICAL_HEAL + 4.1f), + new NextAction("swiftmend on party", ACTION_CRITICAL_HEAL + 4), + new NextAction("regrowth on party", ACTION_CRITICAL_HEAL + 3), + new NextAction("wild growth on party", ACTION_CRITICAL_HEAL + 2), new NextAction("nourish on party", ACTION_CRITICAL_HEAL + 1), // new NextAction("healing touch on party", ACTION_CRITICAL_HEAL + 0), - NULL))); + nullptr))); triggers.push_back( new TriggerNode("party member critical health", - NextAction::array(0, new NextAction("nature's swiftness", ACTION_CRITICAL_HEAL + 4), NULL))); + NextAction::array(0, new NextAction("nature's swiftness", ACTION_CRITICAL_HEAL + 4), nullptr))); + + triggers.push_back(new TriggerNode( + "group heal setting", + NextAction::array(0, + new NextAction("tree form", ACTION_MEDIUM_HEAL + 2.3f), + new NextAction("wild growth on party", ACTION_MEDIUM_HEAL + 2.2f), + new NextAction("rejuvenation on not full", ACTION_MEDIUM_HEAL + 2.1f), + nullptr))); triggers.push_back( - new TriggerNode("medium group heal occasion", - NextAction::array(0, new NextAction("tranquility", ACTION_CRITICAL_HEAL + 5), NULL))); + new TriggerNode("medium group heal setting", + NextAction::array(0, + new NextAction("tree form", ACTION_CRITICAL_HEAL + 0.6f), + new NextAction("tranquility", ACTION_CRITICAL_HEAL + 0.5f), nullptr))); // LOW triggers.push_back( new TriggerNode("party member low health", - NextAction::array(0, new NextAction("wild growth on party", ACTION_MEDIUM_HEAL + 9), - new NextAction("regrowth on party", ACTION_MEDIUM_HEAL + 8), - new NextAction("swiftmend on party", ACTION_MEDIUM_HEAL + 7), - new NextAction("nourish on party", ACTION_MEDIUM_HEAL + 6), - // new NextAction("healing touch on party", ACTION_MEDIUM_HEAL + 5), - NULL))); + NextAction::array(0, new NextAction("tree form", ACTION_MEDIUM_HEAL + 1.5f), + new NextAction("wild growth on party", ACTION_MEDIUM_HEAL + 1.4f), + new NextAction("regrowth on party", ACTION_MEDIUM_HEAL + 1.3f), + new NextAction("swiftmend on party", ACTION_MEDIUM_HEAL + 1.2), + new NextAction("nourish on party", ACTION_MEDIUM_HEAL + 1.1f), + nullptr))); // MEDIUM triggers.push_back( new TriggerNode("party member medium health", - NextAction::array(0, new NextAction("wild growth on party", ACTION_MEDIUM_HEAL + 4), - new NextAction("rejuvenation on party", ACTION_MEDIUM_HEAL + 3), - new NextAction("regrowth on party", ACTION_MEDIUM_HEAL + 2), - new NextAction("nourish on party", ACTION_MEDIUM_HEAL + 1), NULL))); + NextAction::array(0, + new NextAction("tree form", ACTION_MEDIUM_HEAL + 0.5f), + new NextAction("wild growth on party", ACTION_MEDIUM_HEAL + 0.4f), + new NextAction("rejuvenation on party", ACTION_MEDIUM_HEAL + 0.3f), + new NextAction("regrowth on party", ACTION_MEDIUM_HEAL + 0.2f), + new NextAction("nourish on party", ACTION_MEDIUM_HEAL + 0.1f), nullptr))); // almost full triggers.push_back( new TriggerNode("party member almost full health", - NextAction::array(0, new NextAction("wild growth on party", ACTION_LIGHT_HEAL + 3), - new NextAction("rejuvenation on party", ACTION_LIGHT_HEAL + 2), - new NextAction("regrowth on party", ACTION_LIGHT_HEAL + 1), NULL))); + NextAction::array(0, new NextAction("wild growth on party", ACTION_LIGHT_HEAL + 0.3f), + new NextAction("rejuvenation on party", ACTION_LIGHT_HEAL + 0.2f), + new NextAction("regrowth on party", ACTION_LIGHT_HEAL + 0.1f), nullptr))); triggers.push_back( - new TriggerNode("medium mana", NextAction::array(0, new NextAction("innervate", ACTION_HIGH + 5), NULL))); + new TriggerNode("medium mana", NextAction::array(0, new NextAction("innervate", ACTION_HIGH + 5), nullptr))); triggers.push_back(new TriggerNode("enemy too close for spell", NextAction::array(0, new NextAction("flee", ACTION_MOVE + 9), nullptr))); diff --git a/src/strategy/paladin/GenericPaladinNonCombatStrategy.cpp b/src/strategy/paladin/GenericPaladinNonCombatStrategy.cpp index 80e23cd3..d19320bd 100644 --- a/src/strategy/paladin/GenericPaladinNonCombatStrategy.cpp +++ b/src/strategy/paladin/GenericPaladinNonCombatStrategy.cpp @@ -22,7 +22,7 @@ void GenericPaladinNonCombatStrategy::InitTriggers(std::vector& tr triggers.push_back(new TriggerNode("party member almost full health", NextAction::array(0, new NextAction("flash of light on party", 25.0f), NULL))); triggers.push_back(new TriggerNode("party member medium health", - NextAction::array(0, new NextAction("holy light on party", 26.0f), NULL))); + NextAction::array(0, new NextAction("flash of light on party", 26.0f), NULL))); triggers.push_back(new TriggerNode("party member low health", NextAction::array(0, new NextAction("holy light on party", 27.0f), NULL))); triggers.push_back(new TriggerNode("party member critical health", diff --git a/src/strategy/paladin/GenericPaladinStrategy.cpp b/src/strategy/paladin/GenericPaladinStrategy.cpp index d25a7518..b5b77f58 100644 --- a/src/strategy/paladin/GenericPaladinStrategy.cpp +++ b/src/strategy/paladin/GenericPaladinStrategy.cpp @@ -71,3 +71,17 @@ void PaladinCcStrategy::InitTriggers(std::vector& triggers) triggers.push_back( new TriggerNode("turn undead", NextAction::array(0, new NextAction("turn undead", ACTION_HIGH + 1), nullptr))); } + +void PaladinHealerDpsStrategy::InitTriggers(std::vector& triggers) +{ + triggers.push_back( + new TriggerNode("healer should attack", + NextAction::array(0, + new NextAction("hammer of wrath", ACTION_DEFAULT + 0.6f), + new NextAction("holy shock", ACTION_DEFAULT + 0.5f), + new NextAction("shield of righteousness", ACTION_DEFAULT + 0.4f), + new NextAction("judgement of light", ACTION_DEFAULT + 0.3f), + new NextAction("consecration", ACTION_DEFAULT + 0.2f), + new NextAction("exorcism", ACTION_DEFAULT+ 0.1f), + nullptr))); +} diff --git a/src/strategy/paladin/GenericPaladinStrategy.h b/src/strategy/paladin/GenericPaladinStrategy.h index 4922a1bc..737048cc 100644 --- a/src/strategy/paladin/GenericPaladinStrategy.h +++ b/src/strategy/paladin/GenericPaladinStrategy.h @@ -46,4 +46,13 @@ public: std::string const getName() override { return "cc"; } }; +class PaladinHealerDpsStrategy : public Strategy +{ +public: + PaladinHealerDpsStrategy(PlayerbotAI* botAI) : Strategy(botAI) {} + + void InitTriggers(std::vector& triggers) override; + std::string const getName() override { return "healer dps"; } +}; + #endif diff --git a/src/strategy/paladin/GenericPaladinStrategyActionNodeFactory.h b/src/strategy/paladin/GenericPaladinStrategyActionNodeFactory.h index 68617eba..3503d773 100644 --- a/src/strategy/paladin/GenericPaladinStrategyActionNodeFactory.h +++ b/src/strategy/paladin/GenericPaladinStrategyActionNodeFactory.h @@ -22,7 +22,7 @@ public: creators["cleanse magic"] = &cleanse_magic; creators["cleanse poison on party"] = &cleanse_poison_on_party; creators["cleanse disease on party"] = &cleanse_disease_on_party; - // creators["seal of wisdom"] = &seal_of_wisdom; + creators["seal of wisdom"] = &seal_of_wisdom; creators["seal of justice"] = &seal_of_justice; creators["hand of reckoning"] = &hand_of_reckoning; creators["judgement"] = &judgement; @@ -147,13 +147,13 @@ private: /*A*/ NextAction::array(0, new NextAction("purify disease on party"), nullptr), /*C*/ nullptr); } - // static ActionNode* seal_of_wisdom(PlayerbotAI* ai) - // { - // return new ActionNode ("seal of wisdom", - // /*P*/ NULL, - // /*A*/ NextAction::array(0, new NextAction("seal of justice"), NULL), - // /*C*/ NULL); - // } + static ActionNode* seal_of_wisdom(PlayerbotAI* ai) + { + return new ActionNode ("seal of wisdom", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("seal of righteousness"), NULL), + /*C*/ NULL); + } static ActionNode* seal_of_justice(PlayerbotAI* ai) { return new ActionNode("seal of justice", diff --git a/src/strategy/paladin/HealPaladinStrategy.cpp b/src/strategy/paladin/HealPaladinStrategy.cpp index 70c461ce..5f1767dd 100644 --- a/src/strategy/paladin/HealPaladinStrategy.cpp +++ b/src/strategy/paladin/HealPaladinStrategy.cpp @@ -27,7 +27,7 @@ HealPaladinStrategy::HealPaladinStrategy(PlayerbotAI* botAI) : GenericPaladinStr NextAction** HealPaladinStrategy::getDefaultActions() { - return NextAction::array(0, new NextAction("judgement of light", ACTION_DEFAULT + 2), nullptr); + return NextAction::array(0, new NextAction("judgement of light", ACTION_DEFAULT), nullptr); } void HealPaladinStrategy::InitTriggers(std::vector& triggers) @@ -49,7 +49,7 @@ void HealPaladinStrategy::InitTriggers(std::vector& triggers) NextAction::array(0, new NextAction("reach party member to heal", ACTION_EMERGENCY + 3), nullptr))); triggers.push_back( - new TriggerNode("medium group heal occasion", + new TriggerNode("medium group heal setting", NextAction::array(0, new NextAction("divine sacrifice", ACTION_CRITICAL_HEAL + 5), new NextAction("avenging wrath", ACTION_HIGH + 4), nullptr))); diff --git a/src/strategy/paladin/PaladinAiObjectContext.cpp b/src/strategy/paladin/PaladinAiObjectContext.cpp index 094e2fb7..42e89a8a 100644 --- a/src/strategy/paladin/PaladinAiObjectContext.cpp +++ b/src/strategy/paladin/PaladinAiObjectContext.cpp @@ -25,6 +25,7 @@ public: creators["boost"] = &PaladinStrategyFactoryInternal::boost; creators["cc"] = &PaladinStrategyFactoryInternal::cc; creators["bthreat"] = &PaladinStrategyFactoryInternal::bthreat; + creators["healer dps"] = &PaladinStrategyFactoryInternal::healer_dps; } private: @@ -33,6 +34,7 @@ private: static Strategy* boost(PlayerbotAI* botAI) { return new PaladinBoostStrategy(botAI); } static Strategy* cc(PlayerbotAI* botAI) { return new PaladinCcStrategy(botAI); } static Strategy* bthreat(PlayerbotAI* botAI) { return new PaladinBuffThreatStrategy(botAI); } + static Strategy* healer_dps(PlayerbotAI* botAI) { return new PaladinHealerDpsStrategy(botAI); } }; class PaladinResistanceStrategyFactoryInternal : public NamedObjectContext diff --git a/src/strategy/paladin/TankPaladinStrategy.cpp b/src/strategy/paladin/TankPaladinStrategy.cpp index 553d2a7d..25e761b7 100644 --- a/src/strategy/paladin/TankPaladinStrategy.cpp +++ b/src/strategy/paladin/TankPaladinStrategy.cpp @@ -73,7 +73,7 @@ void TankPaladinStrategy::InitTriggers(std::vector& triggers) GenericPaladinStrategy::InitTriggers(triggers); triggers.push_back( - new TriggerNode("seal", NextAction::array(0, new NextAction("seal of command", ACTION_HIGH), nullptr))); + new TriggerNode("seal", NextAction::array(0, new NextAction("seal of corruption", ACTION_HIGH), nullptr))); triggers.push_back( new TriggerNode("low mana", NextAction::array(0, new NextAction("seal of wisdom", ACTION_HIGH + 9), nullptr))); // triggers.push_back(new TriggerNode("devotion aura", NextAction::array(0, new NextAction("devotion aura", 90.0f), @@ -106,7 +106,7 @@ void TankPaladinStrategy::InitTriggers(std::vector& triggers) triggers.push_back(new TriggerNode( "righteous fury", NextAction::array(0, new NextAction("righteous fury", ACTION_HIGH + 8), nullptr))); triggers.push_back( - new TriggerNode("medium group heal occasion", + new TriggerNode("medium group heal setting", NextAction::array(0, new NextAction("divine sacrifice", ACTION_HIGH + 5), nullptr))); triggers.push_back(new TriggerNode( "enough mana", NextAction::array(0, new NextAction("consecration", ACTION_HIGH + 4), nullptr))); diff --git a/src/strategy/priest/GenericPriestStrategy.cpp b/src/strategy/priest/GenericPriestStrategy.cpp index 40bae42d..82ca65e9 100644 --- a/src/strategy/priest/GenericPriestStrategy.cpp +++ b/src/strategy/priest/GenericPriestStrategy.cpp @@ -87,3 +87,23 @@ void PriestCcStrategy::InitTriggers(std::vector& triggers) triggers.push_back( new TriggerNode("shackle undead", NextAction::array(0, new NextAction("shackle undead", 31.0f), nullptr))); } + +void PriestHealerDpsStrategy::InitTriggers(std::vector& triggers) +{ + triggers.push_back( + new TriggerNode("healer should attack", + NextAction::array(0, + new NextAction("shadow word: pain", ACTION_DEFAULT + 0.5f), + new NextAction("holy fire", ACTION_DEFAULT + 0.4f), + new NextAction("smite", ACTION_DEFAULT + 0.3f), + new NextAction("mind blast", ACTION_DEFAULT + 0.2f), + new NextAction("shoot", ACTION_DEFAULT), + nullptr))); + + triggers.push_back( + new TriggerNode("medium aoe and healer should attack", + NextAction::array(0, + new NextAction("mind sear", ACTION_DEFAULT + 0.5f), + nullptr))); +} + diff --git a/src/strategy/priest/GenericPriestStrategy.h b/src/strategy/priest/GenericPriestStrategy.h index 7c6684af..2668723e 100644 --- a/src/strategy/priest/GenericPriestStrategy.h +++ b/src/strategy/priest/GenericPriestStrategy.h @@ -46,4 +46,13 @@ public: std::string const getName() override { return "cc"; } }; +class PriestHealerDpsStrategy : public Strategy +{ +public: + PriestHealerDpsStrategy(PlayerbotAI* botAI) : Strategy(botAI) {} + + void InitTriggers(std::vector& triggers) override; + std::string const getName() override { return "healer dps"; } +}; + #endif diff --git a/src/strategy/priest/HealPriestStrategy.cpp b/src/strategy/priest/HealPriestStrategy.cpp index 25f8e8bd..64c747fd 100644 --- a/src/strategy/priest/HealPriestStrategy.cpp +++ b/src/strategy/priest/HealPriestStrategy.cpp @@ -29,51 +29,56 @@ void HealPriestStrategy::InitTriggers(std::vector& triggers) // triggers.push_back(new TriggerNode( // "medium aoe heal", // NextAction::array(0, - // new NextAction("circle of healing", ACTION_MEDIUM_HEAL + 8), + // new NextAction("circle of healing on party", ACTION_MEDIUM_HEAL + 8), // // new NextAction("power word: shield on almost full health below", ACTION_MEDIUM_HEAL + 7), // NULL))); triggers.push_back(new TriggerNode( - "group heal occasion", - NextAction::array(0, new NextAction("circle of healing", ACTION_MEDIUM_HEAL + 8), - new NextAction("power word: shield on almost full health below", ACTION_MEDIUM_HEAL + 7), - NULL))); + "group heal setting", + NextAction::array(0, + new NextAction("prayer of mending on party", ACTION_MEDIUM_HEAL + 8), + new NextAction("power word: shield on not full", ACTION_MEDIUM_HEAL + 7), + nullptr))); triggers.push_back(new TriggerNode( - "medium group heal occasion", - NextAction::array(0, new NextAction("divine hymn", ACTION_CRITICAL_HEAL + 6), - new NextAction("prayer of healing on party", ACTION_CRITICAL_HEAL + 5), nullptr))); + "medium group heal setting", + NextAction::array(0, new NextAction("divine hymn", ACTION_CRITICAL_HEAL + 7), + new NextAction("prayer of mending on party", ACTION_CRITICAL_HEAL + 6), + new NextAction("power word: shield on not full", ACTION_CRITICAL_HEAL + 5), + new NextAction("prayer of healing on party", ACTION_CRITICAL_HEAL + 4), + nullptr))); triggers.push_back(new TriggerNode( "party member critical health", - NextAction::array(0, new NextAction("power word: shield on party", ACTION_CRITICAL_HEAL + 6), + NextAction::array(0, new NextAction("power word: shield on party", ACTION_CRITICAL_HEAL + 5), new NextAction("penance on party", ACTION_CRITICAL_HEAL + 4), - new NextAction("flash heal on party", ACTION_CRITICAL_HEAL + 3), - new NextAction("prayer of mending on party", ACTION_CRITICAL_HEAL + 2), NULL))); + new NextAction("prayer of mending on party", ACTION_CRITICAL_HEAL + 3), + new NextAction("flash heal on party", ACTION_CRITICAL_HEAL + 2), + nullptr))); triggers.push_back( new TriggerNode("party member low health", NextAction::array(0, new NextAction("power word: shield on party", ACTION_MEDIUM_HEAL + 4), + new NextAction("prayer of mending on party", ACTION_MEDIUM_HEAL + 3), new NextAction("penance on party", ACTION_MEDIUM_HEAL + 2), - new NextAction("circle of healing", ACTION_MEDIUM_HEAL + 2), - new NextAction("prayer of mending on party", ACTION_MEDIUM_HEAL + 1), - new NextAction("flash heal on party", ACTION_MEDIUM_HEAL + 0), NULL))); + new NextAction("flash heal on party", ACTION_MEDIUM_HEAL + 0), nullptr))); triggers.push_back( new TriggerNode("party member medium health", NextAction::array(0, new NextAction("power word: shield on party", ACTION_LIGHT_HEAL + 9), - new NextAction("penance on party", ACTION_LIGHT_HEAL + 7), - new NextAction("circle of healing", ACTION_LIGHT_HEAL + 7), - new NextAction("prayer of mending on party", ACTION_LIGHT_HEAL + 6), + new NextAction("prayer of mending on party", ACTION_LIGHT_HEAL + 7), + new NextAction("penance on party", ACTION_LIGHT_HEAL + 6), new NextAction("flash heal on party", ACTION_LIGHT_HEAL + 5), // new NextAction("renew on party", ACTION_LIGHT_HEAL + 8), - NULL))); + nullptr))); triggers.push_back( new TriggerNode("party member almost full health", NextAction::array(0, // new NextAction("penance on party", ACTION_LIGHT_HEAL + 3), - new NextAction("renew on party", ACTION_LIGHT_HEAL + 2), NULL))); + new NextAction("prayer of mending on party", ACTION_LIGHT_HEAL + 2), + new NextAction("renew on party", ACTION_LIGHT_HEAL + 1), + nullptr))); // triggers.push_back(new TriggerNode("almost full health", NextAction::array(0, new NextAction("renew", 43.f), // nullptr))); triggers.push_back(new TriggerNode("party member almost full health", NextAction::array(0, new @@ -86,7 +91,7 @@ void HealPriestStrategy::InitTriggers(std::vector& triggers) NextAction::array(0, new NextAction("reach party member to heal", ACTION_CRITICAL_HEAL + 10), nullptr))); // triggers.push_back(new TriggerNode("medium aoe heal", NextAction::array(0, new NextAction("prayer of // mending", 49.0f), nullptr))); triggers.push_back(new TriggerNode("medium aoe heal", NextAction::array(0, new - // NextAction("circle of healing", 48.0f), nullptr))); triggers.push_back(new TriggerNode("binding heal", + // NextAction("circle of healing on party", 48.0f), nullptr))); triggers.push_back(new TriggerNode("binding heal", // NextAction::array(0, new NextAction("binding heal", 52.0f), nullptr))); triggers.push_back(new TriggerNode("low // mana", NextAction::array(0, new NextAction("shadowfiend", ACTION_HIGH), nullptr))); diff --git a/src/strategy/priest/HolyPriestStrategy.cpp b/src/strategy/priest/HolyPriestStrategy.cpp index 40f34a28..7c073e05 100644 --- a/src/strategy/priest/HolyPriestStrategy.cpp +++ b/src/strategy/priest/HolyPriestStrategy.cpp @@ -63,42 +63,50 @@ void HolyHealPriestStrategy::InitTriggers(std::vector& triggers) GenericPriestStrategy::InitTriggers(triggers); triggers.push_back( - new TriggerNode("group heal occasion", - NextAction::array(0, new NextAction("circle of healing", ACTION_MEDIUM_HEAL + 8), NULL))); + new TriggerNode("group heal setting", + NextAction::array(0, + new NextAction("prayer of mending on party", ACTION_MEDIUM_HEAL + 9), + new NextAction("circle of healing on party", ACTION_MEDIUM_HEAL + 8), nullptr))); triggers.push_back(new TriggerNode( - "medium group heal occasion", - NextAction::array(0, new NextAction("divine hymn", ACTION_CRITICAL_HEAL + 6), - new NextAction("prayer of healing on party", ACTION_CRITICAL_HEAL + 5), nullptr))); + "medium group heal setting", + NextAction::array(0, new NextAction("divine hymn", ACTION_CRITICAL_HEAL + 7), + new NextAction("prayer of mending on party", ACTION_CRITICAL_HEAL + 6), + new NextAction("circle of healing on party", ACTION_CRITICAL_HEAL + 5), + new NextAction("prayer of healing on party", ACTION_CRITICAL_HEAL + 4), nullptr))); triggers.push_back(new TriggerNode( "party member critical health", NextAction::array(0, new NextAction("guardian spirit on party", ACTION_CRITICAL_HEAL + 6), new NextAction("power word: shield on party", ACTION_CRITICAL_HEAL + 5), - new NextAction("flash heal on party", ACTION_CRITICAL_HEAL + 3), - new NextAction("prayer of mending on party", ACTION_CRITICAL_HEAL + 2), NULL))); + new NextAction("prayer of mending on party", ACTION_CRITICAL_HEAL + 3), + new NextAction("greater heal on party", ACTION_MEDIUM_HEAL + 2), + new NextAction("flash heal on party", ACTION_CRITICAL_HEAL + 1), + nullptr))); triggers.push_back( new TriggerNode("party member low health", - NextAction::array(0, new NextAction("circle of healing", ACTION_MEDIUM_HEAL + 4), - new NextAction("greater heal on party", ACTION_MEDIUM_HEAL + 3), - new NextAction("prayer of mending on party", ACTION_MEDIUM_HEAL + 2), - new NextAction("flash heal on party", ACTION_MEDIUM_HEAL + 1), NULL))); + NextAction::array(0, new NextAction("circle of healing on party", ACTION_MEDIUM_HEAL + 4), + new NextAction("prayer of mending on party", ACTION_MEDIUM_HEAL + 3), + new NextAction("greater heal on party", ACTION_MEDIUM_HEAL + 2), + new NextAction("flash heal on party", ACTION_MEDIUM_HEAL + 1), nullptr))); triggers.push_back( new TriggerNode("party member medium health", - NextAction::array(0, new NextAction("circle of healing", ACTION_LIGHT_HEAL + 7), + NextAction::array(0, new NextAction("circle of healing on party", ACTION_LIGHT_HEAL + 7), new NextAction("prayer of mending on party", ACTION_LIGHT_HEAL + 6), - new NextAction("flash heal on party", ACTION_LIGHT_HEAL + 5), + new NextAction("greater heal on party", ACTION_MEDIUM_HEAL + 5), + new NextAction("flash heal on party", ACTION_LIGHT_HEAL + 4), // new NextAction("renew on party", ACTION_LIGHT_HEAL + 8), - NULL))); + nullptr))); triggers.push_back( new TriggerNode("party member almost full health", - NextAction::array(0, new NextAction("renew on party", ACTION_LIGHT_HEAL + 2), - // new NextAction("flash heal on party", ACTION_LIGHT_HEAL + 1), - NULL))); + NextAction::array(0, + new NextAction("renew on party", ACTION_LIGHT_HEAL + 2), + new NextAction("prayer of mending on party", ACTION_LIGHT_HEAL + 1), + nullptr))); triggers.push_back(new TriggerNode( "party member to heal out of spell range", diff --git a/src/strategy/priest/PriestActions.cpp b/src/strategy/priest/PriestActions.cpp index 3a94dafc..2364a5e2 100644 --- a/src/strategy/priest/PriestActions.cpp +++ b/src/strategy/priest/PriestActions.cpp @@ -18,7 +18,7 @@ bool CastRemoveShadowformAction::Execute(Event event) return true; } -Unit* CastPowerWordShieldOnAlmostFullHealthBelow::GetTarget() +Unit* CastPowerWordShieldOnAlmostFullHealthBelowAction::GetTarget() { Group* group = bot->GetGroup(); for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next()) @@ -47,7 +47,7 @@ Unit* CastPowerWordShieldOnAlmostFullHealthBelow::GetTarget() return nullptr; } -bool CastPowerWordShieldOnAlmostFullHealthBelow::isUseful() +bool CastPowerWordShieldOnAlmostFullHealthBelowAction::isUseful() { Group* group = bot->GetGroup(); for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next()) @@ -74,4 +74,35 @@ bool CastPowerWordShieldOnAlmostFullHealthBelow::isUseful() return true; } return false; +} + +Unit* CastPowerWordShieldOnNotFullAction::GetTarget() +{ + Group* group = bot->GetGroup(); + MinValueCalculator calc(100); + for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next()) + { + Player* player = gref->GetSource(); + if (!player) + continue; + if (player->isDead() || player->IsFullHealth()) + { + continue; + } + if (player->GetDistance2d(bot) > sPlayerbotAIConfig->spellDistance) + { + continue; + } + if (botAI->HasAnyAuraOf(player, "weakened soul", "power word: shield", nullptr)) + { + continue; + } + calc.probe(player->GetHealthPct(), player); + } + return (Unit*)calc.param; +} + +bool CastPowerWordShieldOnNotFullAction::isUseful() +{ + return GetTarget(); } \ No newline at end of file diff --git a/src/strategy/priest/PriestActions.h b/src/strategy/priest/PriestActions.h index 468694c8..c84bfc7d 100644 --- a/src/strategy/priest/PriestActions.h +++ b/src/strategy/priest/PriestActions.h @@ -52,10 +52,23 @@ HEAL_PARTY_ACTION(CastGreaterHealOnPartyAction, "greater heal", 50.0f, HealingMa HEAL_PARTY_ACTION(CastPowerWordShieldOnPartyAction, "power word: shield", 15.0f, HealingManaEfficiency::VERY_HIGH); HEAL_PARTY_ACTION(CastFlashHealOnPartyAction, "flash heal", 15.0f, HealingManaEfficiency::LOW); HEAL_PARTY_ACTION(CastRenewOnPartyAction, "renew", 15.0f, HealingManaEfficiency::VERY_HIGH); -HEAL_PARTY_ACTION(CastPrayerOfMendingAction, "prayer of mending", 15.0f, HealingManaEfficiency::MEDIUM); +// HEAL_PARTY_ACTION(CastPrayerOfMendingAction, "prayer of mending", 10.0f, HealingManaEfficiency::HIGH); +class CastPrayerOfMendingAction : public HealPartyMemberAction +{ +public: + CastPrayerOfMendingAction(PlayerbotAI* botAI) : HealPartyMemberAction(botAI, "prayer of mending", 10.0f, HealingManaEfficiency::HIGH, false) {} +}; + HEAL_PARTY_ACTION(CastBindingHealAction, "binding heal", 15.0f, HealingManaEfficiency::MEDIUM); HEAL_PARTY_ACTION(CastPrayerOfHealingAction, "prayer of healing", 15.0f, HealingManaEfficiency::MEDIUM); -AOE_HEAL_ACTION(CastCircleOfHealingAction, "circle of healing", 15.0f, HealingManaEfficiency::HIGH); +// AOE_HEAL_ACTION(CastCircleOfHealingAction, "circle of healing", 15.0f, HealingManaEfficiency::HIGH); +class CastCircleOfHealingAction : public HealPartyMemberAction +{ +public: + CastCircleOfHealingAction(PlayerbotAI* ai) : HealPartyMemberAction(ai, "circle of healing", 15.0f, HealingManaEfficiency::HIGH) + { + } +}; AOE_HEAL_ACTION(CastLightwellAction, "lightwell", 15.0f, HealingManaEfficiency::MEDIUM); SPELL_ACTION(CastSmiteAction, "smite"); @@ -68,7 +81,13 @@ CURE_PARTY_ACTION(CastCureDiseaseOnPartyAction, "cure disease", DISPEL_DISEASE); CURE_ACTION(CastAbolishDiseaseAction, "abolish disease"); CURE_PARTY_ACTION(CastAbolishDiseaseOnPartyAction, "abolish disease", DISPEL_DISEASE); -DEBUFF_CHECKISOWNER_ACTION(CastHolyFireAction, "holy fire"); +// DEBUFF_CHECKISOWNER_ACTION(CastHolyFireAction, "holy fire"); +class CastHolyFireAction : public CastDebuffSpellAction +{ +public: + CastHolyFireAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "holy fire", true, 0.0f) {} +}; + // shadow 2.4.3 // BUFF_ACTION(CastShadowfiendAction, "shadowfiend"); SPELL_ACTION(CastShadowWordDeathAction, "shadow word: death"); @@ -156,10 +175,10 @@ public: virtual std::string const GetTargetName() { return "current target"; } }; -class CastPowerWordShieldOnAlmostFullHealthBelow : public HealPartyMemberAction +class CastPowerWordShieldOnAlmostFullHealthBelowAction : public HealPartyMemberAction { public: - CastPowerWordShieldOnAlmostFullHealthBelow(PlayerbotAI* ai) + CastPowerWordShieldOnAlmostFullHealthBelowAction(PlayerbotAI* ai) : HealPartyMemberAction(ai, "power word: shield", 15.0f, HealingManaEfficiency::HIGH) { } @@ -167,6 +186,17 @@ public: Unit* GetTarget() override; }; +class CastPowerWordShieldOnNotFullAction : public HealPartyMemberAction +{ +public: + CastPowerWordShieldOnNotFullAction(PlayerbotAI* ai) + : HealPartyMemberAction(ai, "power word: shield", 5.0f, HealingManaEfficiency::HIGH) + { + } + bool isUseful() override; + Unit* GetTarget() override; +}; + class CastMindSearAction : public CastSpellAction { public: diff --git a/src/strategy/priest/PriestAiObjectContext.cpp b/src/strategy/priest/PriestAiObjectContext.cpp index 0df50eec..4f057718 100644 --- a/src/strategy/priest/PriestAiObjectContext.cpp +++ b/src/strategy/priest/PriestAiObjectContext.cpp @@ -5,6 +5,7 @@ #include "PriestAiObjectContext.h" +#include "GenericPriestStrategy.h" #include "HolyPriestStrategy.h" #include "NamedObjectContext.h" #include "Playerbots.h" @@ -30,6 +31,7 @@ public: creators["boost"] = &PriestStrategyFactoryInternal::boost; creators["rshadow"] = &PriestStrategyFactoryInternal::rshadow; creators["cc"] = &PriestStrategyFactoryInternal::cc; + creators["healer dps"] = &PriestStrategyFactoryInternal::healer_dps; } private: @@ -42,6 +44,7 @@ private: static Strategy* pull(PlayerbotAI* botAI) { return new PullStrategy(botAI, "shoot"); } static Strategy* shadow_debuff(PlayerbotAI* botAI) { return new ShadowPriestDebuffStrategy(botAI); } static Strategy* cure(PlayerbotAI* botAI) { return new PriestCureStrategy(botAI); } + static Strategy* healer_dps(PlayerbotAI* botAI) { return new PriestHealerDpsStrategy(botAI); } }; class PriestCombatStrategyFactoryInternal : public NamedObjectContext @@ -172,6 +175,8 @@ public: creators["power word: shield on party"] = &PriestAiObjectContextInternal::power_word_shield_on_party; creators["power word: shield on almost full health below"] = &PriestAiObjectContextInternal::power_word_shield_on_almost_full_health_below; + creators["power word: shield on not full"] = + &PriestAiObjectContextInternal::power_word_shield_on_not_full; creators["renew"] = &PriestAiObjectContextInternal::renew; creators["renew on party"] = &PriestAiObjectContextInternal::renew_on_party; creators["greater heal"] = &PriestAiObjectContextInternal::greater_heal; @@ -192,7 +197,7 @@ public: creators["fade"] = &PriestAiObjectContextInternal::fade; creators["inner fire"] = &PriestAiObjectContextInternal::inner_fire; creators["resurrection"] = &PriestAiObjectContextInternal::resurrection; - creators["circle of healing"] = &PriestAiObjectContextInternal::circle_of_healing; + creators["circle of healing on party"] = &PriestAiObjectContextInternal::circle_of_healing; creators["psychic scream"] = &PriestAiObjectContextInternal::psychic_scream; creators["vampiric touch"] = &PriestAiObjectContextInternal::vampiric_touch; creators["vampiric touch on attacker"] = &PriestAiObjectContextInternal::vampiric_touch_on_attacker; @@ -282,7 +287,11 @@ private: } static Action* power_word_shield_on_almost_full_health_below(PlayerbotAI* ai) { - return new CastPowerWordShieldOnAlmostFullHealthBelow(ai); + return new CastPowerWordShieldOnAlmostFullHealthBelowAction(ai); + } + static Action* power_word_shield_on_not_full(PlayerbotAI* ai) + { + return new CastPowerWordShieldOnNotFullAction(ai); } static Action* renew(PlayerbotAI* botAI) { return new CastRenewAction(botAI); } static Action* renew_on_party(PlayerbotAI* botAI) { return new CastRenewOnPartyAction(botAI); } diff --git a/src/strategy/priest/PriestNonCombatStrategy.cpp b/src/strategy/priest/PriestNonCombatStrategy.cpp index 161ac361..be596054 100644 --- a/src/strategy/priest/PriestNonCombatStrategy.cpp +++ b/src/strategy/priest/PriestNonCombatStrategy.cpp @@ -55,7 +55,7 @@ void PriestNonCombatStrategy::InitTriggers(std::vector& triggers) NextAction::array(0, new NextAction("renew on party", ACTION_LIGHT_HEAL + 3), NULL))); triggers.push_back( - new TriggerNode("medium aoe heal", NextAction::array(0, new NextAction("circle of healing", 27.0f), NULL))); + new TriggerNode("group heal setting", NextAction::array(0, new NextAction("circle of healing on party", 27.0f), NULL))); } void PriestBuffStrategy::InitTriggers(std::vector& triggers) diff --git a/src/strategy/priest/PriestNonCombatStrategyActionNodeFactory.h b/src/strategy/priest/PriestNonCombatStrategyActionNodeFactory.h index 84318fcb..c1084610 100644 --- a/src/strategy/priest/PriestNonCombatStrategyActionNodeFactory.h +++ b/src/strategy/priest/PriestNonCombatStrategyActionNodeFactory.h @@ -29,7 +29,7 @@ public: creators["lesser heal on party"] = &lesser_heal_on_party; creators["flash heal"] = &flash_heal; creators["flash heal on party"] = &flash_heal_on_party; - creators["circle of healing"] = &circle_of_healing; + creators["circle of healing on party"] = &circle_of_healing; creators["prayer of fortitude on party"] = &prayer_of_fortitude_on_party; creators["prayer of spirit on party"] = &prayer_of_spirit_on_party; } @@ -128,7 +128,7 @@ private: } static ActionNode* circle_of_healing(PlayerbotAI* ai) { - return new ActionNode("circle of healing", + return new ActionNode("circle of healing on party", /*P*/ NextAction::array(0, new NextAction("remove shadowform"), NULL), // /*A*/ NextAction::array(0, new NextAction("flash heal on party"), NULL), /*A*/ NULL, diff --git a/src/strategy/shaman/CasterShamanStrategy.cpp b/src/strategy/shaman/CasterShamanStrategy.cpp index 746abf86..c11c523d 100644 --- a/src/strategy/shaman/CasterShamanStrategy.cpp +++ b/src/strategy/shaman/CasterShamanStrategy.cpp @@ -51,8 +51,8 @@ void CasterShamanStrategy::InitTriggers(std::vector& triggers) // triggers.push_back(new TriggerNode("enemy out of spell", NextAction::array(0, new NextAction("reach spell", // ACTION_NORMAL + 9), nullptr))); triggers.push_back(new TriggerNode("shaman weapon", NextAction::array(0, new // NextAction("flametongue weapon", 23.0f), nullptr))); - // triggers.push_back(new TriggerNode( - // "enough mana", NextAction::array(0, new NextAction("chain lightning", ACTION_DEFAULT + 0.1f), nullptr))); + triggers.push_back(new TriggerNode( + "enough mana", NextAction::array(0, new NextAction("chain lightning", ACTION_DEFAULT + 0.1f), nullptr))); triggers.push_back(new TriggerNode("main hand weapon no imbue", NextAction::array(0, new NextAction("flametongue weapon", 22.0f), nullptr))); diff --git a/src/strategy/shaman/GenericShamanStrategy.cpp b/src/strategy/shaman/GenericShamanStrategy.cpp index 7110036d..95ed14f2 100644 --- a/src/strategy/shaman/GenericShamanStrategy.cpp +++ b/src/strategy/shaman/GenericShamanStrategy.cpp @@ -3,6 +3,7 @@ * and/or modify it under version 2 of the License, or (at your option), any later version. */ +#include "GenericShamanStrategy.h" #include "HealShamanStrategy.h" #include "Playerbots.h" #include "Strategy.h" @@ -17,7 +18,7 @@ public: creators["windfury weapon"] = &windfury_weapon; creators["lesser healing wave"] = &lesser_healing_wave; creators["lesser healing wave on party"] = &lesser_healing_wave_on_party; - creators["chain heal"] = &chain_heal; + creators["chain heal on party"] = &chain_heal; creators["riptide"] = &riptide; creators["riptide on party"] = &riptide_on_party; creators["earth shock"] = &earth_shock; @@ -74,9 +75,9 @@ private: static ActionNode* chain_heal([[maybe_unused]] PlayerbotAI* botAI) { - return new ActionNode("chain heal", + return new ActionNode("chain heal on party", /*P*/ nullptr, - /*A*/ NextAction::array(0, new NextAction("lesser healing wave"), nullptr), + /*A*/ NextAction::array(0, new NextAction("lesser healing wave on party"), nullptr), /*C*/ nullptr); } @@ -116,7 +117,7 @@ void GenericShamanStrategy::InitTriggers(std::vector& triggers) // triggers.push_back(new TriggerNode("party member medium health", NextAction::array(0, new NextAction("lesser // healing wave on party", 25.0f), nullptr))); triggers.push_back(new TriggerNode("party member low health", // NextAction::array(0, new NextAction("riptide on party", 25.0f), nullptr))); triggers.push_back(new - // TriggerNode("medium aoe heal", NextAction::array(0, new NextAction("chain heal", 27.0f), nullptr))); + // TriggerNode("medium aoe heal", NextAction::array(0, new NextAction("chain heal on party", 27.0f), nullptr))); // triggers.push_back(new TriggerNode("medium health", NextAction::array(0, new NextAction("lesser healing // wave", 26.0f), nullptr))); triggers.push_back(new TriggerNode("low health", NextAction::array(0, new // NextAction("riptide", 26.0f), nullptr))); @@ -162,3 +163,18 @@ void ShamanCureStrategy::InitTriggers(std::vector& triggers) new TriggerNode("party member cleanse spirit curse", NextAction::array(0, new NextAction("cleanse spirit curse on party", 23.0f), nullptr))); } + +void ShamanHealerDpsStrategy::InitTriggers(std::vector& triggers) +{ + triggers.push_back( + new TriggerNode("healer should attack", + NextAction::array(0, + new NextAction("flame shock", ACTION_DEFAULT + 0.2f), + new NextAction("lava burst", ACTION_DEFAULT + 0.1f), + new NextAction("lightning bolt", ACTION_DEFAULT), nullptr))); + + triggers.push_back( + new TriggerNode("medium aoe and healer should attack", + NextAction::array(0, + new NextAction("chain lightning", ACTION_DEFAULT + 0.3f), nullptr))); +} \ No newline at end of file diff --git a/src/strategy/shaman/GenericShamanStrategy.h b/src/strategy/shaman/GenericShamanStrategy.h index 49753e7b..5fa0ff83 100644 --- a/src/strategy/shaman/GenericShamanStrategy.h +++ b/src/strategy/shaman/GenericShamanStrategy.h @@ -45,4 +45,13 @@ public: std::string const getName() override { return "cure"; } }; +class ShamanHealerDpsStrategy : public Strategy +{ +public: + ShamanHealerDpsStrategy(PlayerbotAI* botAI) : Strategy(botAI) {} + + void InitTriggers(std::vector& triggers) override; + std::string const getName() override { return "healer dps"; } +}; + #endif diff --git a/src/strategy/shaman/HealShamanStrategy.cpp b/src/strategy/shaman/HealShamanStrategy.cpp index ff305559..17d4ff44 100644 --- a/src/strategy/shaman/HealShamanStrategy.cpp +++ b/src/strategy/shaman/HealShamanStrategy.cpp @@ -49,8 +49,8 @@ void HealShamanStrategy::InitTriggers(std::vector& triggers) triggers.push_back(new TriggerNode("main hand weapon no imbue", NextAction::array(0, new NextAction("earthliving weapon", 22.0f), nullptr))); triggers.push_back(new TriggerNode( - "group heal occasion", - NextAction::array(0, new NextAction("riptide on party", 23.0f), new NextAction("chain heal", 22.0f), NULL))); + "group heal setting", + NextAction::array(0, new NextAction("riptide on party", 23.0f), new NextAction("chain heal on party", 22.0f), NULL))); triggers.push_back(new TriggerNode( "party member critical health", diff --git a/src/strategy/shaman/ShamanActions.h b/src/strategy/shaman/ShamanActions.h index c4f6ce38..2d110e51 100644 --- a/src/strategy/shaman/ShamanActions.h +++ b/src/strategy/shaman/ShamanActions.h @@ -42,11 +42,11 @@ public: } }; -class CastChainHealAction : public CastAoeHealSpellAction +class CastChainHealAction : public HealPartyMemberAction { public: CastChainHealAction(PlayerbotAI* botAI) - : CastAoeHealSpellAction(botAI, "chain heal", 15.0f, HealingManaEfficiency::HIGH) + : HealPartyMemberAction(botAI, "chain heal", 15.0f, HealingManaEfficiency::HIGH) { } }; @@ -335,7 +335,7 @@ public: class CastFlameShockAction : public CastDebuffSpellAction { public: - CastFlameShockAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "flame shock", true) {} + CastFlameShockAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "flame shock", true, 6.0f) {} }; class CastEarthShockAction : public CastSpellAction diff --git a/src/strategy/shaman/ShamanAiObjectContext.cpp b/src/strategy/shaman/ShamanAiObjectContext.cpp index e67f4230..9e79f792 100644 --- a/src/strategy/shaman/ShamanAiObjectContext.cpp +++ b/src/strategy/shaman/ShamanAiObjectContext.cpp @@ -6,6 +6,7 @@ #include "ShamanAiObjectContext.h" #include "CasterShamanStrategy.h" +#include "GenericShamanStrategy.h" #include "HealShamanStrategy.h" #include "MeleeShamanStrategy.h" #include "NamedObjectContext.h" @@ -25,6 +26,7 @@ public: creators["melee aoe"] = &ShamanStrategyFactoryInternal::melee_aoe; creators["caster aoe"] = &ShamanStrategyFactoryInternal::caster_aoe; creators["cure"] = &ShamanStrategyFactoryInternal::cure; + creators["healer dps"] = &ShamanStrategyFactoryInternal::healer_dps; } private: @@ -33,6 +35,7 @@ private: static Strategy* melee_aoe(PlayerbotAI* botAI) { return new MeleeAoeShamanStrategy(botAI); } static Strategy* caster_aoe(PlayerbotAI* botAI) { return new CasterAoeShamanStrategy(botAI); } static Strategy* cure(PlayerbotAI* botAI) { return new ShamanCureStrategy(botAI); } + static Strategy* healer_dps(PlayerbotAI* botAI) { return new ShamanHealerDpsStrategy(botAI); } }; class ShamanBuffStrategyFactoryInternal : public NamedObjectContext @@ -207,7 +210,7 @@ public: creators["lesser healing wave on party"] = &ShamanAiObjectContextInternal::lesser_healing_wave_on_party; creators["earth shield"] = &ShamanAiObjectContextInternal::earth_shield; creators["earth shield on party"] = &ShamanAiObjectContextInternal::earth_shield_on_party; - creators["chain heal"] = &ShamanAiObjectContextInternal::chain_heal; + creators["chain heal on party"] = &ShamanAiObjectContextInternal::chain_heal; creators["riptide"] = &ShamanAiObjectContextInternal::riptide; creators["riptide on party"] = &ShamanAiObjectContextInternal::riptide_on_party; creators["stormstrike"] = &ShamanAiObjectContextInternal::stormstrike; diff --git a/src/strategy/shaman/ShamanNonCombatStrategy.cpp b/src/strategy/shaman/ShamanNonCombatStrategy.cpp index 3d544419..ad4dcb82 100644 --- a/src/strategy/shaman/ShamanNonCombatStrategy.cpp +++ b/src/strategy/shaman/ShamanNonCombatStrategy.cpp @@ -39,7 +39,7 @@ void ShamanNonCombatStrategy::InitTriggers(std::vector& triggers) new NextAction("lesser healing wave on party", 24.0f), NULL))); triggers.push_back( - new TriggerNode("medium aoe heal", NextAction::array(0, new NextAction("chain heal", 27.0f), NULL))); + new TriggerNode("group heal setting", NextAction::array(0, new NextAction("chain heal on party", 27.0f), NULL))); triggers.push_back( new TriggerNode("cure poison", NextAction::array(0, new NextAction("cure poison", 21.0f), nullptr))); diff --git a/src/strategy/triggers/GenericTriggers.cpp b/src/strategy/triggers/GenericTriggers.cpp index f700e472..26572394 100644 --- a/src/strategy/triggers/GenericTriggers.cpp +++ b/src/strategy/triggers/GenericTriggers.cpp @@ -9,6 +9,8 @@ #include "BattlegroundWS.h" #include "CreatureAI.h" +#include "GameTime.h" +#include "LastSpellCastValue.h" #include "ObjectGuid.h" #include "PlayerbotAIConfig.h" #include "Playerbots.h" @@ -76,7 +78,7 @@ bool AlmostFullManaTrigger::IsActive() bool EnoughManaTrigger::IsActive() { - return AI_VALUE2(bool, "has mana", "self target") && AI_VALUE2(uint8, "mana", "self target") > 65; + return AI_VALUE2(bool, "has mana", "self target") && AI_VALUE2(uint8, "mana", "self target") > sPlayerbotAIConfig->highMana; } bool RageAvailable::IsActive() { return AI_VALUE2(uint8, "rage", "self target") >= amount; } @@ -366,6 +368,39 @@ bool GenericBoostTrigger::IsActive() return AI_VALUE(uint8, "balance") <= balance; } +bool HealerShouldAttackTrigger::IsActive() +{ + // nobody can help me + if (botAI->GetNearGroupMemberCount(sPlayerbotAIConfig->sightDistance) <= 1) + return true; + + if (AI_VALUE2(uint8, "health", "party member to heal") < sPlayerbotAIConfig->almostFullHealth) + return false; + + // special check for resto druid (dont remove tree of life frequently) + if (bot->GetAura(33891)) + { + LastSpellCast& lastSpell = botAI->GetAiObjectContext()->GetValue("last spell cast")->Get(); + if (lastSpell.timer + 5 > time(nullptr)) + return false; + } + + int manaThreshold; + int balance = AI_VALUE(uint8, "balance"); + // higher threshold in higher pressure + if (balance <= 50) + manaThreshold = 85; + else if (balance <= 100) + manaThreshold = sPlayerbotAIConfig->highMana; + else + manaThreshold = sPlayerbotAIConfig->mediumMana; + + if (AI_VALUE2(bool, "has mana", "self target") && AI_VALUE2(uint8, "mana", "self target") < manaThreshold) + return false; + + return true; +} + bool ItemCountTrigger::IsActive() { return AI_VALUE2(uint32, "item count", item) < count; } bool InterruptSpellTrigger::IsActive() diff --git a/src/strategy/triggers/GenericTriggers.h b/src/strategy/triggers/GenericTriggers.h index e9990c3e..f93cb156 100644 --- a/src/strategy/triggers/GenericTriggers.h +++ b/src/strategy/triggers/GenericTriggers.h @@ -459,6 +459,16 @@ protected: float balance; }; +class HealerShouldAttackTrigger : public Trigger +{ +public: + HealerShouldAttackTrigger(PlayerbotAI* botAI) + : Trigger(botAI, "healer should attack", 1) + { + } + + bool IsActive() override; +}; class RandomTrigger : public Trigger { diff --git a/src/strategy/triggers/HealthTriggers.cpp b/src/strategy/triggers/HealthTriggers.cpp index d4c971ac..3bc8d4f3 100644 --- a/src/strategy/triggers/HealthTriggers.cpp +++ b/src/strategy/triggers/HealthTriggers.cpp @@ -24,7 +24,18 @@ bool AoeHealTrigger::IsActive() { return AI_VALUE2(uint8, "aoe heal", type) >= c bool AoeInGroupTrigger::IsActive() { - Group* group = bot->GetGroup(); - return group && group->GetMembersCount() >= 5 && - AI_VALUE2(uint8, "aoe heal", type) >= (group->GetMembersCount() * ratio); + int32 member = botAI->GetNearGroupMemberCount(); + if (member < 5) + return false; + int threshold = member * 0.5; + if (member <= 5) + threshold = 3; + else if (member <= 10) + threshold = std::min(threshold, 5); + else if (member <= 25) + threshold = std::min(threshold, 10); + else + threshold = std::min(threshold, 15); + + return AI_VALUE2(uint8, "aoe heal", type) >= threshold; } \ No newline at end of file diff --git a/src/strategy/triggers/HealthTriggers.h b/src/strategy/triggers/HealthTriggers.h index d9f3253c..279bc3fe 100644 --- a/src/strategy/triggers/HealthTriggers.h +++ b/src/strategy/triggers/HealthTriggers.h @@ -186,14 +186,13 @@ protected: class AoeInGroupTrigger : public Trigger { public: - AoeInGroupTrigger(PlayerbotAI* ai, std::string name, std::string type, float ratio) - : Trigger(ai, name), ratio(ratio), type(type) + AoeInGroupTrigger(PlayerbotAI* ai, std::string name, std::string type) + : Trigger(ai, name), type(type) { } bool IsActive() override; protected: - float ratio; std::string type; }; diff --git a/src/strategy/triggers/TriggerContext.h b/src/strategy/triggers/TriggerContext.h index 860ee682..cbfeec6f 100644 --- a/src/strategy/triggers/TriggerContext.h +++ b/src/strategy/triggers/TriggerContext.h @@ -48,6 +48,7 @@ public: creators["almost full mana"] = &TriggerContext::AlmostFullMana; creators["enough mana"] = &TriggerContext::EnoughMana; + creators["party member critical health"] = &TriggerContext::PartyMemberCriticalHealth; creators["party member low health"] = &TriggerContext::PartyMemberLowHealth; creators["party member medium health"] = &TriggerContext::PartyMemberMediumHealth; @@ -83,6 +84,9 @@ public: creators["medium aoe"] = &TriggerContext::MediumAoe; creators["high aoe"] = &TriggerContext::HighAoe; + creators["healer should attack"] = &TriggerContext::healer_should_attack; + creators["medium aoe and healer should attack"] = &TriggerContext::medium_aoe_and_healer_should_attack; + creators["has area debuff"] = &TriggerContext::HasAreaDebuff; creators["enemy out of melee"] = &TriggerContext::EnemyOutOfMelee; @@ -135,8 +139,8 @@ public: creators["medium aoe heal"] = &TriggerContext::medium_aoe_heal; creators["almost full aoe heal"] = &TriggerContext::almost_full_aoe_heal; - creators["group heal occasion"] = &TriggerContext::group_heal_occasion; - creators["medium group heal occasion"] = &TriggerContext::medium_group_heal_occasion; + creators["group heal setting"] = &TriggerContext::group_heal_occasion; + creators["medium group heal setting"] = &TriggerContext::medium_group_heal_occasion; creators["invalid target"] = &TriggerContext::invalid_target; creators["lfg proposal active"] = &TriggerContext::lfg_proposal_active; @@ -242,11 +246,11 @@ private: } static Trigger* group_heal_occasion(PlayerbotAI* ai) { - return new AoeInGroupTrigger(ai, "group heal occasion", "almost full", 0.6); + return new AoeInGroupTrigger(ai, "group heal setting", "almost full"); } static Trigger* medium_group_heal_occasion(PlayerbotAI* ai) { - return new AoeInGroupTrigger(ai, "group heal occasion", "medium", 0.6); + return new AoeInGroupTrigger(ai, "medium group heal setting", "medium"); } static Trigger* target_changed(PlayerbotAI* botAI) { return new TargetChangedTrigger(botAI); } static Trigger* swimming(PlayerbotAI* botAI) { return new IsSwimmingTrigger(botAI); } @@ -265,6 +269,8 @@ private: static Trigger* LightAoe(PlayerbotAI* botAI) { return new LightAoeTrigger(botAI); } static Trigger* MediumAoe(PlayerbotAI* botAI) { return new MediumAoeTrigger(botAI); } static Trigger* HighAoe(PlayerbotAI* botAI) { return new HighAoeTrigger(botAI); } + static Trigger* healer_should_attack(PlayerbotAI* botAI) { return new HealerShouldAttackTrigger(botAI); } + static Trigger* medium_aoe_and_healer_should_attack(PlayerbotAI* botAI) { return new TwoTriggers(botAI, "medium aoe", "healer should attack"); } static Trigger* HasAreaDebuff(PlayerbotAI* botAI) { return new HasAreaDebuffTrigger(botAI); } static Trigger* LoseAggro(PlayerbotAI* botAI) { return new LoseAggroTrigger(botAI); } static Trigger* HasAggro(PlayerbotAI* botAI) { return new HasAggroTrigger(botAI); } diff --git a/src/strategy/values/AttackerCountValues.cpp b/src/strategy/values/AttackerCountValues.cpp index 59de8995..17ba4562 100644 --- a/src/strategy/values/AttackerCountValues.cpp +++ b/src/strategy/values/AttackerCountValues.cpp @@ -94,7 +94,7 @@ uint8 BalancePercentValue::Calculate() level *= 3; break; case CREATURE_ELITE_WORLDBOSS: - level *= 30; + level *= 20; break; } diff --git a/src/strategy/warlock/GenericWarlockNonCombatStrategy.cpp b/src/strategy/warlock/GenericWarlockNonCombatStrategy.cpp index 7ed900cf..a46346fe 100644 --- a/src/strategy/warlock/GenericWarlockNonCombatStrategy.cpp +++ b/src/strategy/warlock/GenericWarlockNonCombatStrategy.cpp @@ -55,7 +55,7 @@ private: { return new ActionNode("summon felhunter", /*P*/ nullptr, - /*A*/ NextAction::array(0, new NextAction("summon voidwalker"), nullptr), + /*A*/ NextAction::array(0, new NextAction("summon succubus"), nullptr), /*C*/ nullptr); } static ActionNode* summon_felguard([[maybe_unused]] PlayerbotAI* botAI)