From 07da4ad9591030a39ef0634039644f889b048158 Mon Sep 17 00:00:00 2001 From: chris Date: Wed, 30 Oct 2024 17:03:46 +0800 Subject: [PATCH 01/19] date: 2024-10-30 fos bronjahm v1 --- .../wotlk/forgeofsouls/FosActionContext.h | 25 ++++++++++++++++ .../wotlk/forgeofsouls/FosActions.cpp | 30 +++++++++++++++++++ .../dungeons/wotlk/forgeofsouls/FosActions.h | 26 ++++++++++++++++ .../wotlk/forgeofsouls/FosMultipliers.cpp | 26 ++++++++++++++++ .../wotlk/forgeofsouls/FosMultipliers.h | 24 +++++++++++++++ .../wotlk/forgeofsouls/FosStrategy.cpp | 5 ++++ .../dungeons/wotlk/forgeofsouls/FosStrategy.h | 16 ++++++++++ .../wotlk/forgeofsouls/FosTriggerContext.h | 7 +++++ .../forgeofsouls/{TODO => FosTriggers.cpp} | 0 .../dungeons/wotlk/forgeofsouls/FosTriggers.h | 11 +++++++ 10 files changed, 170 insertions(+) create mode 100644 src/strategy/dungeons/wotlk/forgeofsouls/FosActionContext.h create mode 100644 src/strategy/dungeons/wotlk/forgeofsouls/FosActions.cpp create mode 100644 src/strategy/dungeons/wotlk/forgeofsouls/FosActions.h create mode 100644 src/strategy/dungeons/wotlk/forgeofsouls/FosMultipliers.cpp create mode 100644 src/strategy/dungeons/wotlk/forgeofsouls/FosMultipliers.h create mode 100644 src/strategy/dungeons/wotlk/forgeofsouls/FosStrategy.cpp create mode 100644 src/strategy/dungeons/wotlk/forgeofsouls/FosStrategy.h create mode 100644 src/strategy/dungeons/wotlk/forgeofsouls/FosTriggerContext.h rename src/strategy/dungeons/wotlk/forgeofsouls/{TODO => FosTriggers.cpp} (100%) create mode 100644 src/strategy/dungeons/wotlk/forgeofsouls/FosTriggers.h diff --git a/src/strategy/dungeons/wotlk/forgeofsouls/FosActionContext.h b/src/strategy/dungeons/wotlk/forgeofsouls/FosActionContext.h new file mode 100644 index 00000000..33e66aab --- /dev/null +++ b/src/strategy/dungeons/wotlk/forgeofsouls/FosActionContext.h @@ -0,0 +1,25 @@ +#ifndef _PLAYERBOT_WOTLKDUNGEONNEXACTIONCONTEXT_H +#define _PLAYERBOT_WOTLKDUNGEONNEXACTIONCONTEXT_H + +#include "Action.h" +#include "NamedObjectContext.h" +#include "FosActions.h" + +class WotlkDungeonFosActionContext : public NamedObjectContext +{ + public: + WotlkDungeonFosActionContext() { + creators["csf target"] = &WotlkDungeonFosActionContext::move_from_whirlwind; + creators["firebomb spread"] = &WotlkDungeonNexActionContext::firebomb_spread; + } + private: + static Action* move_from_whirlwind(PlayerbotAI* ai) { return new MoveFromWhirlwindAction(ai); } + static Action* firebomb_spread(PlayerbotAI* ai) { return new FirebombSpreadAction(ai); } + static Action* telestra_split_target(PlayerbotAI* ai) { return new TelestraSplitTargetAction(ai); } + static Action* csf_target(PlayerbotAI* ai) { return new } + static Action* chaotic_rift_target(PlayerbotAI* ai) { return new ChaoticRiftTargetAction(ai); } + static Action* dodge_spikes(PlayerbotAI* ai) { return new DodgeSpikesAction(ai); } + static Action* intense_cold_jump(PlayerbotAI* ai) { return new IntenseColdJumpAction(ai); } +}; + +#endif diff --git a/src/strategy/dungeons/wotlk/forgeofsouls/FosActions.cpp b/src/strategy/dungeons/wotlk/forgeofsouls/FosActions.cpp new file mode 100644 index 00000000..b68e22d6 --- /dev/null +++ b/src/strategy/dungeons/wotlk/forgeofsouls/FosActions.cpp @@ -0,0 +1,30 @@ +#include "Playerbots.h" +#include "FosActions.h" +#include "FosStrategy.h" + +bool MoveFromBronjahmAction::Execute(Event event) +{ + Unit* boss = nullptr; + boss = AI_VALUE2(Unit*, "find target", "bronjahm"); + if (!boss) + return false; + + float distance = bot->GetExactDist2d(boss->GetPosition()); + float targetDis = 30.0f; + if (distance >= targetDis) + return false; + return MoveAway(boss, targetDis - distance); +} + +bool AttackCorruptedSoulFragmentAction::Execute(Event event) +{ + Unit* fragment = nullptr; + fragment = AI_VALUE2(Unit*, "find target", "corrupted soul fragment"); + if (!fragment) + return false; + + if (AI_VALUE(Unit*, "current target") == fragment) + return false; + + return Attack(fragment); +} diff --git a/src/strategy/dungeons/wotlk/forgeofsouls/FosActions.h b/src/strategy/dungeons/wotlk/forgeofsouls/FosActions.h new file mode 100644 index 00000000..11e9fde6 --- /dev/null +++ b/src/strategy/dungeons/wotlk/forgeofsouls/FosActions.h @@ -0,0 +1,26 @@ +#ifndef _PLAYERBOT_WOTLKDUNGEONFOSACTIONS_H +#define _PLAYERBOT_WOTLKDUNGEONFOSACTIONS_H + +#include "Action.h" +#include "AttackAction.h" +#include "PlayerbotAI.h" +#include "Playerbots.h" +#include "FosTriggers.h" + +class MoveFromBronjahmAction : public MovementAction +{ +public: + MoveFromBronjahmAction(PlayerbotAI* ai) : MovementAction(ai, "move from bronjahm") {} + bool Execute(Event event) override; +}; + +class AttackCorruptedSoulFragmentAction : public AttackAction +{ +public: + AttackCorruptedSoulFragmentAction(PlayerbotAI* ai) : AttackAction(ai, "attack corrupted soul fragment") {} + bool Execute(Event event) override; + bool isUseful() override; +}; + + +#endif diff --git a/src/strategy/dungeons/wotlk/forgeofsouls/FosMultipliers.cpp b/src/strategy/dungeons/wotlk/forgeofsouls/FosMultipliers.cpp new file mode 100644 index 00000000..a078c69c --- /dev/null +++ b/src/strategy/dungeons/wotlk/forgeofsouls/FosMultipliers.cpp @@ -0,0 +1,26 @@ +#include "FosMultipliers.h" +#include "FosActions.h" +#include "GenericSpellActions.h" +#include "ChooseTargetActions.h" +#include "MovementActions.h" +#include "FosTriggers.h" + + +float BronjahmMultiplier::GetValue(Action* action) { + Unit* boss = nullptr; + boss = AI_VALUE2(Unit *, "find target", "bronjahm"); + if (boss && boss->HasUnitState(UNIT_STATE_CASTING) && boss->FindCurrentSpellBySpellId(SPELL_CORRUPT_SOUL)) + { + if (dynamic_cast(action) && !dynamic_cast(action)) + { + return 0.0f; + } + } + return 1.0f; } + +float AttackFragmentMultiplier::GetValue(Action* action) +{ + auto isTank = botAI->IsTank(); + if (isTank && dynamic_cast(action)) + return 0.0f; + return 1.0f; } diff --git a/src/strategy/dungeons/wotlk/forgeofsouls/FosMultipliers.h b/src/strategy/dungeons/wotlk/forgeofsouls/FosMultipliers.h new file mode 100644 index 00000000..99d7e47b --- /dev/null +++ b/src/strategy/dungeons/wotlk/forgeofsouls/FosMultipliers.h @@ -0,0 +1,24 @@ +#ifndef _PLAYERBOT_WOTLKDUNGEONFOSMULTIPLIERS_H +#define _PLAYERBOT_WOTLKDUNGEONFOSMULTIPLIERS_H + +#include "Multiplier.h" + +class BronjahmMultiplier : public Multiplier +{ + public: + BronjahmMultiplier(PlayerbotAI* ai) : Multiplier(ai, "bronjahm") {} + + public: + virtual float GetValue(Action* action); +}; + +class AttackFragmentMultiplier : public Multiplier +{ +public: + AttackFragmentMultiplier(PlayerbotAI* ai) : Multiplier(ai, "attack fragment") { } + + float GetValue(Action* action) override; +}; + + +#endif diff --git a/src/strategy/dungeons/wotlk/forgeofsouls/FosStrategy.cpp b/src/strategy/dungeons/wotlk/forgeofsouls/FosStrategy.cpp new file mode 100644 index 00000000..2617b228 --- /dev/null +++ b/src/strategy/dungeons/wotlk/forgeofsouls/FosStrategy.cpp @@ -0,0 +1,5 @@ +#include "FosStrategy.h" + +void WotlkDungeonFosStrategy::InitTriggers(std::vector& triggers) {} + +void WotlkDungeonFosStrategy::InitMultipliers(std::vector& multipliers) {} diff --git a/src/strategy/dungeons/wotlk/forgeofsouls/FosStrategy.h b/src/strategy/dungeons/wotlk/forgeofsouls/FosStrategy.h new file mode 100644 index 00000000..5ecf3493 --- /dev/null +++ b/src/strategy/dungeons/wotlk/forgeofsouls/FosStrategy.h @@ -0,0 +1,16 @@ +#ifndef _PLAYERBOT_WOTLKDUNGEONFOSSTRATEGY_H +#define _PLAYERBOT_WOTLKDUNGEONFOSSTRATEGY_H +#include "Multiplier.h" +#include "Strategy.h" + +class WotlkDungeonFosStrategy : public Strategy +{ +public: + WotlkDungeonFosStrategy(PlayerbotAI* ai) : Strategy(ai) {} + std::string const getName() override { return "fos"; } + void InitTriggers(std::vector &triggers) override; + void InitMultipliers(std::vector &multipliers) override; + +}; + +#endif // !_PLAYERBOT_WOTLKDUNGEONFOSSTRATEGY_H diff --git a/src/strategy/dungeons/wotlk/forgeofsouls/FosTriggerContext.h b/src/strategy/dungeons/wotlk/forgeofsouls/FosTriggerContext.h new file mode 100644 index 00000000..89ae9b61 --- /dev/null +++ b/src/strategy/dungeons/wotlk/forgeofsouls/FosTriggerContext.h @@ -0,0 +1,7 @@ +#ifndef _PLAYERBOT_WOTLKDUNGEONFOSTRIGGERCONTEXT_H +#define _PLAYERBOT_WOTLKDUNGEONFOSTRIGGERCONTEXT_H + +#include "NamedObjectContext.h" +#include "AiObjectContext.h" +#include "FosTriggers.h" +#endif // !_PLAYERBOT_WOTLKDUNGEONFOSTRIGGERCONTEXT_H diff --git a/src/strategy/dungeons/wotlk/forgeofsouls/TODO b/src/strategy/dungeons/wotlk/forgeofsouls/FosTriggers.cpp similarity index 100% rename from src/strategy/dungeons/wotlk/forgeofsouls/TODO rename to src/strategy/dungeons/wotlk/forgeofsouls/FosTriggers.cpp diff --git a/src/strategy/dungeons/wotlk/forgeofsouls/FosTriggers.h b/src/strategy/dungeons/wotlk/forgeofsouls/FosTriggers.h new file mode 100644 index 00000000..dc53d973 --- /dev/null +++ b/src/strategy/dungeons/wotlk/forgeofsouls/FosTriggers.h @@ -0,0 +1,11 @@ +#include "Trigger.h" +#include "PlayerbotAIConfig.h" +#include "GenericTriggers.h" +#include "DungeonStrategyUtils.h" + +enum FosIDs +{ + //Boss1 + + SPELL_CORRUPT_SOUL = 68839 +}; From 3aa43cbb3cca6b31aba46574c4e3071c711c57dc Mon Sep 17 00:00:00 2001 From: Bobblybook Date: Mon, 21 Oct 2024 22:29:03 +1100 Subject: [PATCH 02/19] UP and CoS dungeons - Utgarde Pinnacle implementation - Culling of Stratholme implementation - Added additional value ("nearest hostile npcs") needed to expose some hidden trigger-type npc units (eg. frost breath on Skadi fight in UP) --- src/strategy/AiObjectContext.cpp | 4 + .../dungeons/DungeonStrategyContext.h | 15 ++-- .../wotlk/WotlkDungeonActionContext.h | 4 +- .../wotlk/WotlkDungeonTriggerContext.h | 4 +- .../CullingOfStratholmeActionContext.h | 20 +++++ .../CullingOfStratholmeActions.cpp | 54 ++++++++++++ .../CullingOfStratholmeActions.h | 26 ++++++ .../CullingOfStratholmeMultipliers.cpp | 19 +++++ .../CullingOfStratholmeMultipliers.h | 15 ++++ .../CullingOfStratholmeStrategy.cpp | 27 ++++++ .../CullingOfStratholmeStrategy.h | 18 ++++ .../CullingOfStratholmeTriggerContext.h | 22 +++++ .../CullingOfStratholmeTriggers.cpp | 32 +++++++ .../CullingOfStratholmeTriggers.h | 29 +++++++ .../dungeons/wotlk/cullingofstratholme/TODO | 0 .../draktharonkeep/DrakTharonKeepActions.cpp | 8 +- .../HallsOfLightningActions.cpp | 7 +- .../dungeons/wotlk/utgardepinnacle/TODO | 0 .../UtgardePinnacleActionContext.h | 20 +++++ .../UtgardePinnacleActions.cpp | 61 ++++++++++++++ .../utgardepinnacle/UtgardePinnacleActions.h | 24 ++++++ .../UtgardePinnacleMultipliers.cpp | 84 +++++++++++++++++++ .../UtgardePinnacleMultipliers.h | 15 ++++ .../UtgardePinnacleStrategy.cpp | 25 ++++++ .../utgardepinnacle/UtgardePinnacleStrategy.h | 18 ++++ .../UtgardePinnacleTriggerContext.h | 21 +++++ .../UtgardePinnacleTriggers.cpp | 48 +++++++++++ .../utgardepinnacle/UtgardePinnacleTriggers.h | 39 +++++++++ src/strategy/values/NearestNpcsValue.cpp | 9 ++ src/strategy/values/NearestNpcsValue.h | 13 +++ src/strategy/values/ValueContext.h | 2 + 31 files changed, 665 insertions(+), 18 deletions(-) create mode 100644 src/strategy/dungeons/wotlk/cullingofstratholme/CullingOfStratholmeActionContext.h create mode 100644 src/strategy/dungeons/wotlk/cullingofstratholme/CullingOfStratholmeActions.cpp create mode 100644 src/strategy/dungeons/wotlk/cullingofstratholme/CullingOfStratholmeActions.h create mode 100644 src/strategy/dungeons/wotlk/cullingofstratholme/CullingOfStratholmeMultipliers.cpp create mode 100644 src/strategy/dungeons/wotlk/cullingofstratholme/CullingOfStratholmeMultipliers.h create mode 100644 src/strategy/dungeons/wotlk/cullingofstratholme/CullingOfStratholmeStrategy.cpp create mode 100644 src/strategy/dungeons/wotlk/cullingofstratholme/CullingOfStratholmeStrategy.h create mode 100644 src/strategy/dungeons/wotlk/cullingofstratholme/CullingOfStratholmeTriggerContext.h create mode 100644 src/strategy/dungeons/wotlk/cullingofstratholme/CullingOfStratholmeTriggers.cpp create mode 100644 src/strategy/dungeons/wotlk/cullingofstratholme/CullingOfStratholmeTriggers.h delete mode 100644 src/strategy/dungeons/wotlk/cullingofstratholme/TODO delete mode 100644 src/strategy/dungeons/wotlk/utgardepinnacle/TODO create mode 100644 src/strategy/dungeons/wotlk/utgardepinnacle/UtgardePinnacleActionContext.h create mode 100644 src/strategy/dungeons/wotlk/utgardepinnacle/UtgardePinnacleActions.cpp create mode 100644 src/strategy/dungeons/wotlk/utgardepinnacle/UtgardePinnacleActions.h create mode 100644 src/strategy/dungeons/wotlk/utgardepinnacle/UtgardePinnacleMultipliers.cpp create mode 100644 src/strategy/dungeons/wotlk/utgardepinnacle/UtgardePinnacleMultipliers.h create mode 100644 src/strategy/dungeons/wotlk/utgardepinnacle/UtgardePinnacleStrategy.cpp create mode 100644 src/strategy/dungeons/wotlk/utgardepinnacle/UtgardePinnacleStrategy.h create mode 100644 src/strategy/dungeons/wotlk/utgardepinnacle/UtgardePinnacleTriggerContext.h create mode 100644 src/strategy/dungeons/wotlk/utgardepinnacle/UtgardePinnacleTriggers.cpp create mode 100644 src/strategy/dungeons/wotlk/utgardepinnacle/UtgardePinnacleTriggers.h diff --git a/src/strategy/AiObjectContext.cpp b/src/strategy/AiObjectContext.cpp index b8121320..9b52369e 100644 --- a/src/strategy/AiObjectContext.cpp +++ b/src/strategy/AiObjectContext.cpp @@ -59,6 +59,8 @@ AiObjectContext::AiObjectContext(PlayerbotAI* botAI) : PlayerbotAIAware(botAI) actionContexts.Add(new WotlkDungeonGDActionContext()); actionContexts.Add(new WotlkDungeonHoSActionContext()); actionContexts.Add(new WotlkDungeonHoLActionContext()); + actionContexts.Add(new WotlkDungeonUPActionContext()); + actionContexts.Add(new WotlkDungeonCoSActionContext()); triggerContexts.Add(new TriggerContext()); triggerContexts.Add(new ChatTriggerContext()); @@ -78,6 +80,8 @@ AiObjectContext::AiObjectContext(PlayerbotAI* botAI) : PlayerbotAIAware(botAI) triggerContexts.Add(new WotlkDungeonGDTriggerContext()); triggerContexts.Add(new WotlkDungeonHoSTriggerContext()); triggerContexts.Add(new WotlkDungeonHoLTriggerContext()); + triggerContexts.Add(new WotlkDungeonUPTriggerContext()); + triggerContexts.Add(new WotlkDungeonCoSTriggerContext()); valueContexts.Add(new ValueContext()); diff --git a/src/strategy/dungeons/DungeonStrategyContext.h b/src/strategy/dungeons/DungeonStrategyContext.h index 5ed70f6c..3bb39c18 100644 --- a/src/strategy/dungeons/DungeonStrategyContext.h +++ b/src/strategy/dungeons/DungeonStrategyContext.h @@ -11,16 +11,14 @@ #include "wotlk/gundrak/GundrakStrategy.h" #include "wotlk/hallsofstone/HallsOfStoneStrategy.h" #include "wotlk/hallsoflightning/HallsOfLightningStrategy.h" +#include "wotlk/utgardepinnacle/UtgardePinnacleStrategy.h" +#include "wotlk/cullingofstratholme/CullingOfStratholmeStrategy.h" /* Full list/TODO: The Oculus - Occ Drakos the Interrogator, Varos Cloudstrider, Mage-Lord Urom, Ley-Guardian Eregos -Utgarde Pinnacle - UP -Svala Sorrowgrave, Gortok Palehoof, Skadi the Ruthless, King Ymiron -The Culling of Stratholme - CoS -Meathook, Salramm the Fleshcrafter, Chrono-Lord Epoch, Mal'Ganis, Infinite Corruptor (Heroic only) Trial of the Champion - ToC Alliance Champions: Deathstalker Visceri, Eressea Dawnsinger, Mokra the Skullcrusher, Runok Wildmane, Zul'tore Horde Champions: Ambrose Boltspark, Colosos, Jacob Alerius, Jaelyne Evensong, Lana Stouthammer @@ -76,11 +74,12 @@ class DungeonStrategyContext : public NamedObjectContext static Strategy* wotlk_gd(PlayerbotAI* botAI) { return new WotlkDungeonGDStrategy(botAI); } static Strategy* wotlk_hos(PlayerbotAI* botAI) { return new WotlkDungeonHoSStrategy(botAI); } static Strategy* wotlk_hol(PlayerbotAI* botAI) { return new WotlkDungeonHoLStrategy(botAI); } - + // static Strategy* wotlk_occ(PlayerbotAI* botAI) { return new WotlkDungeonOccStrategy(botAI); } static Strategy* wotlk_occ(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); } - static Strategy* wotlk_up(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); } - static Strategy* wotlk_cos(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); } - static Strategy* wotlk_toc(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); } + static Strategy* wotlk_up(PlayerbotAI* botAI) { return new WotlkDungeonUPStrategy(botAI); } + static Strategy* wotlk_cos(PlayerbotAI* botAI) { return new WotlkDungeonCoSStrategy(botAI); } + + static Strategy* wotlk_toc(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); } // NYI from here down static Strategy* wotlk_hor(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); } static Strategy* wotlk_pos(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); } static Strategy* wotlk_fos(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); } diff --git a/src/strategy/dungeons/wotlk/WotlkDungeonActionContext.h b/src/strategy/dungeons/wotlk/WotlkDungeonActionContext.h index b1301868..81b47ae2 100644 --- a/src/strategy/dungeons/wotlk/WotlkDungeonActionContext.h +++ b/src/strategy/dungeons/wotlk/WotlkDungeonActionContext.h @@ -11,8 +11,8 @@ #include "hallsofstone/HallsOfStoneActionContext.h" #include "hallsoflightning/HallsOfLightningActionContext.h" // #include "oculus/OculusActionContext.h" -// #include "utgardepinnacle/UtgardePinnacleActionContext.h" -// #include "cullingofstratholme/CullingOfStratholmeActionContext.h" +#include "utgardepinnacle/UtgardePinnacleActionContext.h" +#include "cullingofstratholme/CullingOfStratholmeActionContext.h" // #include "trialofthechampion/TrialOfTheChampionActionContext.h" // #include "hallsofreflection/HallsOfReflectionActionContext.h" // #include "pitofsaron/PitOfSaronActionContext.h" diff --git a/src/strategy/dungeons/wotlk/WotlkDungeonTriggerContext.h b/src/strategy/dungeons/wotlk/WotlkDungeonTriggerContext.h index cb819430..0bafe36a 100644 --- a/src/strategy/dungeons/wotlk/WotlkDungeonTriggerContext.h +++ b/src/strategy/dungeons/wotlk/WotlkDungeonTriggerContext.h @@ -11,8 +11,8 @@ #include "hallsofstone/HallsOfStoneTriggerContext.h" #include "hallsoflightning/HallsOfLightningTriggerContext.h" // #include "oculus/OculusTriggerContext.h" -// #include "utgardepinnacle/UtgardePinnacleTriggerContext.h" -// #include "cullingofstratholme/CullingOfStratholmeTriggerContext.h" +#include "utgardepinnacle/UtgardePinnacleTriggerContext.h" +#include "cullingofstratholme/CullingOfStratholmeTriggerContext.h" // #include "trialofthechampion/TrialOfTheChampionTriggerContext.h" // #include "hallsofreflection/HallsOfReflectionTriggerContext.h" // #include "pitofsaron/PitOfSaronTriggerContext.h" diff --git a/src/strategy/dungeons/wotlk/cullingofstratholme/CullingOfStratholmeActionContext.h b/src/strategy/dungeons/wotlk/cullingofstratholme/CullingOfStratholmeActionContext.h new file mode 100644 index 00000000..0e12c908 --- /dev/null +++ b/src/strategy/dungeons/wotlk/cullingofstratholme/CullingOfStratholmeActionContext.h @@ -0,0 +1,20 @@ +#ifndef _PLAYERBOT_WOTLKDUNGEONCOSACTIONCONTEXT_H +#define _PLAYERBOT_WOTLKDUNGEONCOSACTIONCONTEXT_H + +#include "Action.h" +#include "NamedObjectContext.h" +#include "CullingOfStratholmeActions.h" + +class WotlkDungeonCoSActionContext : public NamedObjectContext +{ + public: + WotlkDungeonCoSActionContext() { + creators["explode ghoul spread"] = &WotlkDungeonCoSActionContext::explode_ghoul_spread; + creators["epoch stack"] = &WotlkDungeonCoSActionContext::epoch_stack; + } + private: + static Action* explode_ghoul_spread(PlayerbotAI* ai) { return new ExplodeGhoulSpreadAction(ai); } + static Action* epoch_stack(PlayerbotAI* ai) { return new EpochStackAction(ai); } +}; + +#endif diff --git a/src/strategy/dungeons/wotlk/cullingofstratholme/CullingOfStratholmeActions.cpp b/src/strategy/dungeons/wotlk/cullingofstratholme/CullingOfStratholmeActions.cpp new file mode 100644 index 00000000..dd857569 --- /dev/null +++ b/src/strategy/dungeons/wotlk/cullingofstratholme/CullingOfStratholmeActions.cpp @@ -0,0 +1,54 @@ +#include "Playerbots.h" +#include "CullingOfStratholmeActions.h" +#include "CullingOfStratholmeStrategy.h" + + +bool ExplodeGhoulSpreadAction::Execute(Event event) +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "salramm the fleshcrafter"); + if (!boss) { return false; } + + float distance = 10.0f; + float distanceExtra = 2.0f; + GuidVector corpses = AI_VALUE(GuidVector, "nearest corpses"); + for (auto i = corpses.begin(); i != corpses.end(); ++i) + { + Unit* unit = botAI->GetUnit(*i); + if (unit && unit->GetEntry() == NPC_GHOUL_MINION) + { + float currentDistance = bot->GetExactDist2d(unit); + if (currentDistance < distance + distanceExtra) + { + return MoveAway(unit, distance + distanceExtra - currentDistance); + } + } + } + return false; +} + +bool EpochStackAction::isUseful() +{ + // Minimum hunter range is 5, but values too close to this seem to cause issues.. + // Hunter bots will try and melee in between ranged attacks, or just melee entirely at 5 as they are in range. + // 7.5 or 8.0 solves this for this boss. + // Unfortunately at this range the boss will charge. So I guess just don't stack as a hunter.. + // if(bot->getClass() == CLASS_HUNTER) + // { + // return AI_VALUE2(float, "distance", "current target") > 7.5f; + // } + // else + return !(bot->getClass() == CLASS_HUNTER) && AI_VALUE2(float, "distance", "current target") > 5.0f; +} +bool EpochStackAction::Execute(Event event) +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "chrono-lord epoch"); + if (!boss) { return false; } + + float maxMovement = 10.0f; + // if(bot->getClass() == CLASS_HUNTER) + // { + // return Move(bot->GetAngle(boss), fmin(bot->GetExactDist2d(boss) - 6.5f, maxMovement)); + // } + // else + return Move(bot->GetAngle(boss), fmin(bot->GetExactDist2d(boss), maxMovement)); +} diff --git a/src/strategy/dungeons/wotlk/cullingofstratholme/CullingOfStratholmeActions.h b/src/strategy/dungeons/wotlk/cullingofstratholme/CullingOfStratholmeActions.h new file mode 100644 index 00000000..989cb6ab --- /dev/null +++ b/src/strategy/dungeons/wotlk/cullingofstratholme/CullingOfStratholmeActions.h @@ -0,0 +1,26 @@ +#ifndef _PLAYERBOT_WOTLKDUNGEONCOSACTIONS_H +#define _PLAYERBOT_WOTLKDUNGEONCOSACTIONS_H + +#include "Action.h" +#include "AttackAction.h" +#include "GenericSpellActions.h" +#include "PlayerbotAI.h" +#include "Playerbots.h" +#include "CullingOfStratholmeTriggers.h" + +class ExplodeGhoulSpreadAction : public MovementAction +{ +public: + ExplodeGhoulSpreadAction(PlayerbotAI* ai) : MovementAction(ai, "explode ghoul spread") {} + bool Execute(Event event) override; +}; + +class EpochStackAction : public MovementAction +{ +public: + EpochStackAction(PlayerbotAI* ai) : MovementAction(ai, "epoch stack") {} + bool Execute(Event event) override; + bool isUseful() override; +}; + +#endif diff --git a/src/strategy/dungeons/wotlk/cullingofstratholme/CullingOfStratholmeMultipliers.cpp b/src/strategy/dungeons/wotlk/cullingofstratholme/CullingOfStratholmeMultipliers.cpp new file mode 100644 index 00000000..31ec9283 --- /dev/null +++ b/src/strategy/dungeons/wotlk/cullingofstratholme/CullingOfStratholmeMultipliers.cpp @@ -0,0 +1,19 @@ +#include "CullingOfStratholmeMultipliers.h" +#include "CullingOfStratholmeActions.h" +#include "GenericSpellActions.h" +#include "ChooseTargetActions.h" +#include "MovementActions.h" +#include "CullingOfStratholmeTriggers.h" +#include "Action.h" + +float EpochMultiplier::GetValue(Action* action) +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "chrono-lord epoch"); + if (!boss) { return 1.0f; } + + if (bot->getClass() == CLASS_HUNTER) { return 1.0f; } + + if (dynamic_cast(action)) { return 0.0f; } + + return 1.0f; +} diff --git a/src/strategy/dungeons/wotlk/cullingofstratholme/CullingOfStratholmeMultipliers.h b/src/strategy/dungeons/wotlk/cullingofstratholme/CullingOfStratholmeMultipliers.h new file mode 100644 index 00000000..587b0f70 --- /dev/null +++ b/src/strategy/dungeons/wotlk/cullingofstratholme/CullingOfStratholmeMultipliers.h @@ -0,0 +1,15 @@ +#ifndef _PLAYERBOT_WOTLKDUNGEONCOSMULTIPLIERS_H +#define _PLAYERBOT_WOTLKDUNGEONCOSMULTIPLIERS_H + +#include "Multiplier.h" + +class EpochMultiplier : public Multiplier +{ + public: + EpochMultiplier(PlayerbotAI* ai) : Multiplier(ai, "chrono-lord epoch") {} + + public: + virtual float GetValue(Action* action); +}; + +#endif diff --git a/src/strategy/dungeons/wotlk/cullingofstratholme/CullingOfStratholmeStrategy.cpp b/src/strategy/dungeons/wotlk/cullingofstratholme/CullingOfStratholmeStrategy.cpp new file mode 100644 index 00000000..a78270d1 --- /dev/null +++ b/src/strategy/dungeons/wotlk/cullingofstratholme/CullingOfStratholmeStrategy.cpp @@ -0,0 +1,27 @@ +#include "CullingOfStratholmeStrategy.h" +#include "CullingOfStratholmeMultipliers.h" + + +void WotlkDungeonCoSStrategy::InitTriggers(std::vector &triggers) +{ + // Meathook + // Can tank this in a fixed position to allow healer to LoS the stun, probably not necessary + + // Salramm the Fleshcrafter + triggers.push_back(new TriggerNode("explode ghoul", + NextAction::array(0, new NextAction("explode ghoul spread", ACTION_MOVE + 5), nullptr))); + + // Chrono-Lord Epoch + // Not sure if this actually works, I think I've seen him charge melee characters..? + triggers.push_back(new TriggerNode("epoch ranged", + NextAction::array(0, new NextAction("epoch stack", ACTION_MOVE + 5), nullptr))); + + // Mal'Ganis + + // Infinite Corruptor (Heroic only) +} + +void WotlkDungeonCoSStrategy::InitMultipliers(std::vector &multipliers) +{ + multipliers.push_back(new EpochMultiplier(botAI)); +} diff --git a/src/strategy/dungeons/wotlk/cullingofstratholme/CullingOfStratholmeStrategy.h b/src/strategy/dungeons/wotlk/cullingofstratholme/CullingOfStratholmeStrategy.h new file mode 100644 index 00000000..9c687da9 --- /dev/null +++ b/src/strategy/dungeons/wotlk/cullingofstratholme/CullingOfStratholmeStrategy.h @@ -0,0 +1,18 @@ +#ifndef _PLAYERBOT_WOTLKDUNGEONCOSSTRATEGY_H +#define _PLAYERBOT_WOTLKDUNGEONCOSSTRATEGY_H + +#include "Multiplier.h" +#include "AiObjectContext.h" +#include "Strategy.h" + + +class WotlkDungeonCoSStrategy : public Strategy +{ +public: + WotlkDungeonCoSStrategy(PlayerbotAI* ai) : Strategy(ai) {} + virtual std::string const getName() override { return "culling of stratholme"; } + virtual void InitTriggers(std::vector &triggers) override; + virtual void InitMultipliers(std::vector &multipliers) override; +}; + +#endif diff --git a/src/strategy/dungeons/wotlk/cullingofstratholme/CullingOfStratholmeTriggerContext.h b/src/strategy/dungeons/wotlk/cullingofstratholme/CullingOfStratholmeTriggerContext.h new file mode 100644 index 00000000..723a1904 --- /dev/null +++ b/src/strategy/dungeons/wotlk/cullingofstratholme/CullingOfStratholmeTriggerContext.h @@ -0,0 +1,22 @@ +#ifndef _PLAYERBOT_WOTLKDUNGEONCOSTRIGGERCONTEXT_H +#define _PLAYERBOT_WOTLKDUNGEONCOSTRIGGERCONTEXT_H + +#include "NamedObjectContext.h" +#include "AiObjectContext.h" +#include "CullingOfStratholmeTriggers.h" + +class WotlkDungeonCoSTriggerContext : public NamedObjectContext +{ + public: + WotlkDungeonCoSTriggerContext() + { + creators["explode ghoul"] = &WotlkDungeonCoSTriggerContext::explode_ghoul; + creators["epoch ranged"] = &WotlkDungeonCoSTriggerContext::epoch_ranged; + + } + private: + static Trigger* explode_ghoul(PlayerbotAI* ai) { return new ExplodeGhoulTrigger(ai); } + static Trigger* epoch_ranged(PlayerbotAI* ai) { return new EpochRangedTrigger(ai); } +}; + +#endif diff --git a/src/strategy/dungeons/wotlk/cullingofstratholme/CullingOfStratholmeTriggers.cpp b/src/strategy/dungeons/wotlk/cullingofstratholme/CullingOfStratholmeTriggers.cpp new file mode 100644 index 00000000..a2b7dc11 --- /dev/null +++ b/src/strategy/dungeons/wotlk/cullingofstratholme/CullingOfStratholmeTriggers.cpp @@ -0,0 +1,32 @@ +#include "Playerbots.h" +#include "CullingOfStratholmeTriggers.h" +#include "AiObject.h" +#include "AiObjectContext.h" + + +bool ExplodeGhoulTrigger::IsActive() +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "salramm the fleshcrafter"); + if (!boss) { return false; } + + float distance = 10.0f; + float distanceExtra = 2.0f; + GuidVector corpses = AI_VALUE(GuidVector, "nearest corpses"); + for (auto i = corpses.begin(); i != corpses.end(); ++i) + { + Unit* unit = botAI->GetUnit(*i); + if (unit && unit->GetEntry() == NPC_RISEN_GHOUL) + { + if (bot->GetExactDist2d(unit) < distance + distanceExtra) + { + return true; + } + } + } + return false; +} + +bool EpochRangedTrigger::IsActive() +{ + return !botAI->IsMelee(bot) && AI_VALUE2(Unit*, "find target", "chrono-lord epoch"); +} diff --git a/src/strategy/dungeons/wotlk/cullingofstratholme/CullingOfStratholmeTriggers.h b/src/strategy/dungeons/wotlk/cullingofstratholme/CullingOfStratholmeTriggers.h new file mode 100644 index 00000000..28fafa36 --- /dev/null +++ b/src/strategy/dungeons/wotlk/cullingofstratholme/CullingOfStratholmeTriggers.h @@ -0,0 +1,29 @@ +#ifndef _PLAYERBOT_WOTLKDUNGEONCOSTRIGGERS_H +#define _PLAYERBOT_WOTLKDUNGEONCOSTRIGGERS_H + +#include "Trigger.h" +#include "PlayerbotAIConfig.h" +#include "GenericTriggers.h" +#include "DungeonStrategyUtils.h" + +enum CullingOfStratholmeIDs +{ + // Salramm the Fleshcrafter + NPC_GHOUL_MINION = 27733, +}; + +class ExplodeGhoulTrigger : public Trigger +{ +public: + ExplodeGhoulTrigger(PlayerbotAI* ai) : Trigger(ai, "explode ghoul") {} + bool IsActive() override; +}; + +class EpochRangedTrigger : public Trigger +{ +public: + EpochRangedTrigger(PlayerbotAI* ai) : Trigger(ai, "chrono-lord epoch ranged") {} + bool IsActive() override; +}; + +#endif diff --git a/src/strategy/dungeons/wotlk/cullingofstratholme/TODO b/src/strategy/dungeons/wotlk/cullingofstratholme/TODO deleted file mode 100644 index e69de29b..00000000 diff --git a/src/strategy/dungeons/wotlk/draktharonkeep/DrakTharonKeepActions.cpp b/src/strategy/dungeons/wotlk/draktharonkeep/DrakTharonKeepActions.cpp index e8863a12..0cfd6202 100644 --- a/src/strategy/dungeons/wotlk/draktharonkeep/DrakTharonKeepActions.cpp +++ b/src/strategy/dungeons/wotlk/draktharonkeep/DrakTharonKeepActions.cpp @@ -8,16 +8,18 @@ bool CorpseExplodeSpreadAction::Execute(Event event) Unit* boss = AI_VALUE2(Unit*, "find target", "trollgore"); if (!boss) { return false; } - float distance = 6.0f; // 5 unit radius, 1 unit added as buffer + float distance = 5.0f; + float distanceExtra = 2.0f; GuidVector corpses = AI_VALUE(GuidVector, "nearest corpses"); for (auto i = corpses.begin(); i != corpses.end(); ++i) { Unit* unit = botAI->GetUnit(*i); if (unit && unit->GetEntry() == NPC_DRAKKARI_INVADER) { - if (bot->GetExactDist2d(unit) < distance) + float currentDistance = bot->GetExactDist2d(unit); + if (currentDistance < distance + distanceExtra) { - return MoveAway(unit, distance - bot->GetExactDist2d(unit)); + return MoveAway(unit, distance + distanceExtra - currentDistance); } } } diff --git a/src/strategy/dungeons/wotlk/hallsoflightning/HallsOfLightningActions.cpp b/src/strategy/dungeons/wotlk/hallsoflightning/HallsOfLightningActions.cpp index ac469e95..6bb82079 100644 --- a/src/strategy/dungeons/wotlk/hallsoflightning/HallsOfLightningActions.cpp +++ b/src/strategy/dungeons/wotlk/hallsoflightning/HallsOfLightningActions.cpp @@ -125,7 +125,7 @@ bool LokenStackAction::isUseful() { // Minimum hunter range is 5, but values too close to this seem to cause issues.. // Hunter bots will try and melee in between ranged attacks, or just melee entirely at 5 as they are in range. - // 6.5 or 7.0 solves this. + // 6.5 or 7.0 solves this for this boss. if(bot->getClass() == CLASS_HUNTER) { return AI_VALUE2(float, "distance", "current target") > 6.5f; @@ -138,14 +138,15 @@ bool LokenStackAction::Execute(Event event) Unit* boss = AI_VALUE2(Unit*, "find target", "loken"); if (!boss) { return false; } + float maxMovement = 10.0f; if (!boss->HasUnitState(UNIT_STATE_CASTING)) { if(bot->getClass() == CLASS_HUNTER) { - return Move(bot->GetAngle(boss), fmin(bot->GetExactDist2d(boss) - 6.5f, 10.0f)); + return Move(bot->GetAngle(boss), fmin(bot->GetExactDist2d(boss) - 6.5f, maxMovement)); } // else - return Move(bot->GetAngle(boss), fmin(bot->GetExactDist2d(boss), 10.0f)); + return Move(bot->GetAngle(boss), fmin(bot->GetExactDist2d(boss), maxMovement)); } return false; diff --git a/src/strategy/dungeons/wotlk/utgardepinnacle/TODO b/src/strategy/dungeons/wotlk/utgardepinnacle/TODO deleted file mode 100644 index e69de29b..00000000 diff --git a/src/strategy/dungeons/wotlk/utgardepinnacle/UtgardePinnacleActionContext.h b/src/strategy/dungeons/wotlk/utgardepinnacle/UtgardePinnacleActionContext.h new file mode 100644 index 00000000..5a9dff5b --- /dev/null +++ b/src/strategy/dungeons/wotlk/utgardepinnacle/UtgardePinnacleActionContext.h @@ -0,0 +1,20 @@ +#ifndef _PLAYERBOT_WOTLKDUNGEONUPACTIONCONTEXT_H +#define _PLAYERBOT_WOTLKDUNGEONUPACTIONCONTEXT_H + +#include "Action.h" +#include "NamedObjectContext.h" +#include "UtgardePinnacleActions.h" + +class WotlkDungeonUPActionContext : public NamedObjectContext +{ + public: + WotlkDungeonUPActionContext() { + creators["avoid freezing cloud"] = &WotlkDungeonUPActionContext::avoid_freezing_cloud; + creators["avoid skadi whirlwind"] = &WotlkDungeonUPActionContext::avoid_whirlwind; + } + private: + static Action* avoid_freezing_cloud(PlayerbotAI* ai) { return new AvoidFreezingCloudAction(ai); } + static Action* avoid_whirlwind(PlayerbotAI* ai) { return new AvoidSkadiWhirlwindAction(ai); } +}; + +#endif diff --git a/src/strategy/dungeons/wotlk/utgardepinnacle/UtgardePinnacleActions.cpp b/src/strategy/dungeons/wotlk/utgardepinnacle/UtgardePinnacleActions.cpp new file mode 100644 index 00000000..f084ca15 --- /dev/null +++ b/src/strategy/dungeons/wotlk/utgardepinnacle/UtgardePinnacleActions.cpp @@ -0,0 +1,61 @@ +#include "Playerbots.h" +#include "UtgardePinnacleActions.h" +#include "UtgardePinnacleStrategy.h" + +bool AvoidFreezingCloudAction::Execute(Event event) +{ + Unit* closestTrigger = nullptr; + GuidVector objects = AI_VALUE(GuidVector, "nearest hostile npcs"); + + for (auto i = objects.begin(); i != objects.end(); ++i) + { + Unit* unit = botAI->GetUnit(*i); + if (unit && unit->GetEntry() == NPC_BREATH_TRIGGER) + { + if (!closestTrigger || bot->GetExactDist2d(unit) < bot->GetExactDist2d(closestTrigger)) + { + closestTrigger = unit; + } + } + } + + if (!closestTrigger) { return false; } + + float distance = bot->GetExactDist2d(closestTrigger->GetPosition()); + float radius = 3.0f; + // Large buffer for this - the radius of the breath is a lot smaller than the graphic, but it looks dumb + // if the bot stands just outside the hitbox but still visibly in the cloud patches. + float distanceExtra = 3.0f; + + if (distance < radius + distanceExtra - 1.0f) + { + // bot->Yell("MOVING", LANG_UNIVERSAL); + return MoveAway(closestTrigger, radius + distanceExtra - distance); + } + + return false; +} + +bool AvoidSkadiWhirlwindAction::Execute(Event event) +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "skadi the ruthless"); + if (!boss) { return false; } + + float distance = bot->GetExactDist2d(boss->GetPosition()); + float radius = 5.0f; + float distanceExtra = 2.0f; + + if (distance < radius + distanceExtra) + { + if (botAI->IsTank(bot)) + { + // The boss chases tank during this, leads to jittery stutter-stepping + // by the tank if we don't pre-move additional range. 2*radius seems ok + return MoveAway(boss, (2.0f * radius) + distanceExtra - distance); + } + // else + return MoveAway(boss, radius + distanceExtra - distance); + } + + return false; +} diff --git a/src/strategy/dungeons/wotlk/utgardepinnacle/UtgardePinnacleActions.h b/src/strategy/dungeons/wotlk/utgardepinnacle/UtgardePinnacleActions.h new file mode 100644 index 00000000..38e90dd1 --- /dev/null +++ b/src/strategy/dungeons/wotlk/utgardepinnacle/UtgardePinnacleActions.h @@ -0,0 +1,24 @@ +#ifndef _PLAYERBOT_WOTLKDUNGEONUPACTIONS_H +#define _PLAYERBOT_WOTLKDUNGEONUPACTIONS_H + +#include "Action.h" +#include "AttackAction.h" +#include "PlayerbotAI.h" +#include "Playerbots.h" +#include "UtgardePinnacleTriggers.h" + +class AvoidFreezingCloudAction : public MovementAction +{ +public: + AvoidFreezingCloudAction(PlayerbotAI* ai) : MovementAction(ai, "avoid freezing cloud") {} + bool Execute(Event event) override; +}; + +class AvoidSkadiWhirlwindAction : public MovementAction +{ +public: + AvoidSkadiWhirlwindAction(PlayerbotAI* ai) : MovementAction(ai, "avoid skadi whirlwind") {} + bool Execute(Event event) override; +}; + +#endif diff --git a/src/strategy/dungeons/wotlk/utgardepinnacle/UtgardePinnacleMultipliers.cpp b/src/strategy/dungeons/wotlk/utgardepinnacle/UtgardePinnacleMultipliers.cpp new file mode 100644 index 00000000..82e5fd53 --- /dev/null +++ b/src/strategy/dungeons/wotlk/utgardepinnacle/UtgardePinnacleMultipliers.cpp @@ -0,0 +1,84 @@ +#include "UtgardePinnacleMultipliers.h" +#include "UtgardePinnacleActions.h" +#include "GenericSpellActions.h" +#include "ChooseTargetActions.h" +#include "MovementActions.h" +#include "UtgardePinnacleTriggers.h" +#include "Action.h" + +float SkadiMultiplier::GetValue(Action* action) +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "skadi the ruthless"); + if (!boss) { return 1.0f; } + + Unit* bossMount = AI_VALUE2(Unit*, "find target", "grauf"); + + if (!bossMount) + // Actual bossfight (dismounted) + { + if (boss->HasAura(SPELL_SKADI_WHIRLWIND)) + { + if (dynamic_cast(action) && !dynamic_cast(action)) + { + return 0.0f; + } + } + } + else + { + // Bots tend to get stuck trying to attack the boss in the sky, not the adds on the ground + if (dynamic_cast(action) + && (action->GetTarget() == boss || action->GetTarget() == bossMount)) + { + return 0.0f; + } + + // TODO: BELOW IS EXPERIMENTAL + // Meant to stop the jittery movement when dodging the breath. + // Currently causes issues with making the bots unresponsive and often getting the healer killed. + // Semi-glitchy movement is better than semi-afk bots, so this is commented out until it gets improved + + // bool cloudActive = false; + // // Need to check two conditions here - the persistent ground effect doesn't + // // seem to be detectable until 3-5 secs in, despite it dealing damage. + // // The initial breath triggers straight away but once it's over, the bots will run back on + // // to the frezzing cloud and take damage. + // // Therefore check both conditions and trigger on either. + + // // Check this one early, if true then we don't need to iterate over any objects + // if (bossMount->HasAura(SPELL_FREEZING_CLOUD_BREATH)) + // { + // cloudActive = true; + // } + + // // Otherwise, check for persistent ground objects emitting the freezing cloud + // GuidVector objects = AI_VALUE(GuidVector, "nearest hostile npcs"); + // for (auto i = objects.begin(); i != objects.end(); ++i) + // { + // Unit* unit = botAI->GetUnit(*i); + // if (unit && unit->GetEntry() == NPC_BREATH_TRIGGER) + // { + // Unit::AuraApplicationMap const& Auras = unit->GetAppliedAuras(); + // for (Unit::AuraApplicationMap::const_iterator itr = Auras.begin(); itr != Auras.end(); ++itr) + // { + // Aura* aura = itr->second->GetBase(); + // if (aura && aura->GetId() == SPELL_FREEZING_CLOUD) + // { + // cloudActive = true; + // break; + // } + // } + // } + // } + + // if (cloudActive) + // { + // if (dynamic_cast(action) && !dynamic_cast(action)) + // { + // return 0.0f; + // } + // } + } + + return 1.0f; +} diff --git a/src/strategy/dungeons/wotlk/utgardepinnacle/UtgardePinnacleMultipliers.h b/src/strategy/dungeons/wotlk/utgardepinnacle/UtgardePinnacleMultipliers.h new file mode 100644 index 00000000..36576678 --- /dev/null +++ b/src/strategy/dungeons/wotlk/utgardepinnacle/UtgardePinnacleMultipliers.h @@ -0,0 +1,15 @@ +#ifndef _PLAYERBOT_WOTLKDUNGEONUPMULTIPLIERS_H +#define _PLAYERBOT_WOTLKDUNGEONUPMULTIPLIERS_H + +#include "Multiplier.h" + +class SkadiMultiplier : public Multiplier +{ + public: + SkadiMultiplier(PlayerbotAI* ai) : Multiplier(ai, "skadi the ruthless") {} + + public: + virtual float GetValue(Action* action); +}; + +#endif diff --git a/src/strategy/dungeons/wotlk/utgardepinnacle/UtgardePinnacleStrategy.cpp b/src/strategy/dungeons/wotlk/utgardepinnacle/UtgardePinnacleStrategy.cpp new file mode 100644 index 00000000..6877ba2c --- /dev/null +++ b/src/strategy/dungeons/wotlk/utgardepinnacle/UtgardePinnacleStrategy.cpp @@ -0,0 +1,25 @@ +#include "UtgardePinnacleStrategy.h" +#include "UtgardePinnacleMultipliers.h" + + +void WotlkDungeonUPStrategy::InitTriggers(std::vector &triggers) +{ + // Svala Sorrowgrave + + // Gortok Palehoof + + // Skadi the Ruthless + // TODO: Harpoons launchable via GameObject. For now players should do them + triggers.push_back(new TriggerNode("freezing cloud", + NextAction::array(0, new NextAction("avoid freezing cloud", ACTION_RAID + 5), nullptr))); + triggers.push_back(new TriggerNode("skadi whirlwind", + NextAction::array(0, new NextAction("avoid skadi whirlwind", ACTION_RAID + 4), nullptr))); + + // King Ymiron + // May need to avoid orb.. unclear if the generic avoid AoE does this well +} + +void WotlkDungeonUPStrategy::InitMultipliers(std::vector &multipliers) +{ + multipliers.push_back(new SkadiMultiplier(botAI)); +} diff --git a/src/strategy/dungeons/wotlk/utgardepinnacle/UtgardePinnacleStrategy.h b/src/strategy/dungeons/wotlk/utgardepinnacle/UtgardePinnacleStrategy.h new file mode 100644 index 00000000..e8f45363 --- /dev/null +++ b/src/strategy/dungeons/wotlk/utgardepinnacle/UtgardePinnacleStrategy.h @@ -0,0 +1,18 @@ +#ifndef _PLAYERBOT_WOTLKDUNGEONUPSTRATEGY_H +#define _PLAYERBOT_WOTLKDUNGEONUPSTRATEGY_H + +#include "Multiplier.h" +#include "AiObjectContext.h" +#include "Strategy.h" + + +class WotlkDungeonUPStrategy : public Strategy +{ +public: + WotlkDungeonUPStrategy(PlayerbotAI* ai) : Strategy(ai) {} + virtual std::string const getName() override { return "utgarde pinnacle"; } + virtual void InitTriggers(std::vector &triggers) override; + virtual void InitMultipliers(std::vector &multipliers) override; +}; + +#endif diff --git a/src/strategy/dungeons/wotlk/utgardepinnacle/UtgardePinnacleTriggerContext.h b/src/strategy/dungeons/wotlk/utgardepinnacle/UtgardePinnacleTriggerContext.h new file mode 100644 index 00000000..143f3df5 --- /dev/null +++ b/src/strategy/dungeons/wotlk/utgardepinnacle/UtgardePinnacleTriggerContext.h @@ -0,0 +1,21 @@ +#ifndef _PLAYERBOT_WOTLKDUNGEONUPTRIGGERCONTEXT_H +#define _PLAYERBOT_WOTLKDUNGEONUPTRIGGERCONTEXT_H + +#include "NamedObjectContext.h" +#include "AiObjectContext.h" +#include "UtgardePinnacleTriggers.h" + +class WotlkDungeonUPTriggerContext : public NamedObjectContext +{ + public: + WotlkDungeonUPTriggerContext() + { + creators["freezing cloud"] = &WotlkDungeonUPTriggerContext::freezing_cloud; + creators["skadi whirlwind"] = &WotlkDungeonUPTriggerContext::whirlwind; + } + private: + static Trigger* freezing_cloud(PlayerbotAI* ai) { return new SkadiFreezingCloudTrigger(ai); } + static Trigger* whirlwind(PlayerbotAI* ai) { return new SkadiWhirlwindTrigger(ai); } +}; + +#endif diff --git a/src/strategy/dungeons/wotlk/utgardepinnacle/UtgardePinnacleTriggers.cpp b/src/strategy/dungeons/wotlk/utgardepinnacle/UtgardePinnacleTriggers.cpp new file mode 100644 index 00000000..587f4e06 --- /dev/null +++ b/src/strategy/dungeons/wotlk/utgardepinnacle/UtgardePinnacleTriggers.cpp @@ -0,0 +1,48 @@ +#include "Playerbots.h" +#include "UtgardePinnacleTriggers.h" +#include "AiObject.h" +#include "AiObjectContext.h" + +bool SkadiFreezingCloudTrigger::IsActive() +{ + Unit* bossMount = AI_VALUE2(Unit*, "find target", "grauf"); + if (!bossMount) { return false; } + + // Need to check two conditions here - the persistent ground effect doesn't + // seem to be detectable until 3-5 secs in, despite it dealing damage. + // The initial breath triggers straight away but once it's over, the bots will run back on + // to the frezzing cloud and take damage. + // Therefore check both conditions and trigger on either. + + // Check this one first, if true then we don't need to iterate over any objects + if (bossMount->HasAura(SPELL_FREEZING_CLOUD_BREATH)) + { + return true; + } + + // Otherwise, check for persistent ground objects emitting the freezing cloud + GuidVector objects = AI_VALUE(GuidVector, "nearest hostile npcs"); + for (auto i = objects.begin(); i != objects.end(); ++i) + { + Unit* unit = botAI->GetUnit(*i); + if (unit && unit->GetEntry() == NPC_BREATH_TRIGGER) + { + Unit::AuraApplicationMap const& Auras = unit->GetAppliedAuras(); + for (Unit::AuraApplicationMap::const_iterator itr = Auras.begin(); itr != Auras.end(); ++itr) + { + Aura* aura = itr->second->GetBase(); + if (aura && aura->GetId() == SPELL_FREEZING_CLOUD) + { + return true; + } + } + } + } + return false; +} + +bool SkadiWhirlwindTrigger::IsActive() +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "skadi the ruthless"); + return boss && boss->HasAura(SPELL_SKADI_WHIRLWIND); +} diff --git a/src/strategy/dungeons/wotlk/utgardepinnacle/UtgardePinnacleTriggers.h b/src/strategy/dungeons/wotlk/utgardepinnacle/UtgardePinnacleTriggers.h new file mode 100644 index 00000000..bd42c3d6 --- /dev/null +++ b/src/strategy/dungeons/wotlk/utgardepinnacle/UtgardePinnacleTriggers.h @@ -0,0 +1,39 @@ +#ifndef _PLAYERBOT_WOTLKDUNGEONUPTRIGGERS_H +#define _PLAYERBOT_WOTLKDUNGEONUPTRIGGERS_H + +#include "Trigger.h" +#include "PlayerbotAIConfig.h" +#include "GenericTriggers.h" +#include "DungeonStrategyUtils.h" + +enum UtgardePinnacleIDs +{ + // Skadi the Ruthless + SPELL_FREEZING_CLOUD_N = 47579, + SPELL_FREEZING_CLOUD_H = 60020, + SPELL_FREEZING_CLOUD_BREATH = 47592, + NPC_BREATH_TRIGGER = 28351, + SPELL_SKADI_WHIRLWIND_N = 50228, + SPELL_SKADI_WHIRLWIND_H = 59322, +}; + +#define SPELL_FREEZING_CLOUD DUNGEON_MODE(bot, SPELL_FREEZING_CLOUD_N, SPELL_FREEZING_CLOUD_H) +#define SPELL_SKADI_WHIRLWIND DUNGEON_MODE(bot, SPELL_SKADI_WHIRLWIND_N, SPELL_SKADI_WHIRLWIND_H) + +// const float SKADI_BREATH_CENTRELINE = -512.46875f; + +class SkadiFreezingCloudTrigger : public Trigger +{ +public: + SkadiFreezingCloudTrigger(PlayerbotAI* ai) : Trigger(ai, "skadi freezing cloud") {} + bool IsActive() override; +}; + +class SkadiWhirlwindTrigger : public Trigger +{ +public: + SkadiWhirlwindTrigger(PlayerbotAI* ai) : Trigger(ai, "skadi whirlwind") {} + bool IsActive() override; +}; + +#endif diff --git a/src/strategy/values/NearestNpcsValue.cpp b/src/strategy/values/NearestNpcsValue.cpp index cbbc8894..1152842a 100644 --- a/src/strategy/values/NearestNpcsValue.cpp +++ b/src/strategy/values/NearestNpcsValue.cpp @@ -20,6 +20,15 @@ void NearestNpcsValue::FindUnits(std::list& targets) bool NearestNpcsValue::AcceptUnit(Unit* unit) { return !unit->IsHostileTo(bot) && !unit->IsPlayer(); } +void NearestHostileNpcsValue::FindUnits(std::list& targets) +{ + Acore::AnyUnitInObjectRangeCheck u_check(bot, range); + Acore::UnitListSearcher searcher(bot, targets, u_check); + Cell::VisitAllObjects(bot, searcher, range); +} + +bool NearestHostileNpcsValue::AcceptUnit(Unit* unit) { return unit->IsHostileTo(bot) && !unit->IsPlayer(); } + void NearestVehiclesValue::FindUnits(std::list& targets) { Acore::AnyUnitInObjectRangeCheck u_check(bot, range); diff --git a/src/strategy/values/NearestNpcsValue.h b/src/strategy/values/NearestNpcsValue.h index 3915dde3..9e192c57 100644 --- a/src/strategy/values/NearestNpcsValue.h +++ b/src/strategy/values/NearestNpcsValue.h @@ -24,6 +24,19 @@ protected: bool AcceptUnit(Unit* unit) override; }; +class NearestHostileNpcsValue : public NearestUnitsValue +{ +public: + NearestHostileNpcsValue(PlayerbotAI* botAI, float range = sPlayerbotAIConfig->sightDistance) + : NearestUnitsValue(botAI, "nearest hostile npcs", range) + { + } + +protected: + void FindUnits(std::list& targets) override; + bool AcceptUnit(Unit* unit) override; +}; + class NearestVehiclesValue : public NearestUnitsValue { public: diff --git a/src/strategy/values/ValueContext.h b/src/strategy/values/ValueContext.h index f8f4a8fe..f57c8083 100644 --- a/src/strategy/values/ValueContext.h +++ b/src/strategy/values/ValueContext.h @@ -104,6 +104,7 @@ public: creators["nearest game objects no los"] = &ValueContext::nearest_game_objects_no_los; creators["closest game objects"] = &ValueContext::closest_game_objects; creators["nearest npcs"] = &ValueContext::nearest_npcs; + creators["nearest hostile npcs"] = &ValueContext::nearest_hostile_npcs; creators["nearest totems"] = &ValueContext::nearest_totems; creators["nearest vehicles"] = &ValueContext::nearest_vehicles; creators["nearest vehicles far"] = &ValueContext::nearest_vehicles_far; @@ -393,6 +394,7 @@ private: } static UntypedValue* log_level(PlayerbotAI* botAI) { return new LogLevelValue(botAI); } static UntypedValue* nearest_npcs(PlayerbotAI* botAI) { return new NearestNpcsValue(botAI); } + static UntypedValue* nearest_hostile_npcs(PlayerbotAI* botAI) { return new NearestHostileNpcsValue(botAI); } static UntypedValue* nearest_totems(PlayerbotAI* botAI) { return new NearestTotemsValue(botAI); } static UntypedValue* nearest_vehicles(PlayerbotAI* botAI) { return new NearestVehiclesValue(botAI); } static UntypedValue* nearest_vehicles_far(PlayerbotAI* botAI) { return new NearestVehiclesValue(botAI, 200.0f); } From 531fc425097bc5e62b7f6d251f00dbb354153d59 Mon Sep 17 00:00:00 2001 From: Bobblybook Date: Mon, 21 Oct 2024 22:33:24 +1100 Subject: [PATCH 03/19] Typo --- .../dungeons/wotlk/utgardepinnacle/UtgardePinnacleTriggers.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strategy/dungeons/wotlk/utgardepinnacle/UtgardePinnacleTriggers.cpp b/src/strategy/dungeons/wotlk/utgardepinnacle/UtgardePinnacleTriggers.cpp index 587f4e06..168d16e6 100644 --- a/src/strategy/dungeons/wotlk/utgardepinnacle/UtgardePinnacleTriggers.cpp +++ b/src/strategy/dungeons/wotlk/utgardepinnacle/UtgardePinnacleTriggers.cpp @@ -11,7 +11,7 @@ bool SkadiFreezingCloudTrigger::IsActive() // Need to check two conditions here - the persistent ground effect doesn't // seem to be detectable until 3-5 secs in, despite it dealing damage. // The initial breath triggers straight away but once it's over, the bots will run back on - // to the frezzing cloud and take damage. + // to the freezing cloud and take damage. // Therefore check both conditions and trigger on either. // Check this one first, if true then we don't need to iterate over any objects From 565816fa2c2723c3f7e4a79d56621646a0aec393 Mon Sep 17 00:00:00 2001 From: avirar Date: Mon, 21 Oct 2024 14:42:32 +1100 Subject: [PATCH 04/19] Update OldKingdomActions.cpp Null checks added --- .../wotlk/oldkingdom/OldKingdomActions.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/strategy/dungeons/wotlk/oldkingdom/OldKingdomActions.cpp b/src/strategy/dungeons/wotlk/oldkingdom/OldKingdomActions.cpp index 41b410bf..d13fae54 100644 --- a/src/strategy/dungeons/wotlk/oldkingdom/OldKingdomActions.cpp +++ b/src/strategy/dungeons/wotlk/oldkingdom/OldKingdomActions.cpp @@ -10,7 +10,6 @@ bool AttackNadoxGuardianAction::Execute(Event event) { return false; } - return Attack(target); } @@ -24,6 +23,10 @@ bool AttackJedogaVolunteerAction::Execute(Event event) for (auto i = targets.begin(); i != targets.end(); ++i) { Unit* unit = botAI->GetUnit(*i); + if (!unit) // Null check for safety + { + continue; // Skip null or invalid units + } if (unit && unit->GetEntry() == NPC_TWILIGHT_VOLUNTEER) { target = unit; @@ -55,6 +58,10 @@ bool AvoidShadowCrashAction::Execute(Event event) // This doesn't seem to avoid casts very well, perhaps because this isn't checked while allies are casting. // TODO: Revisit if this is an issue in heroics, otherwise ignore shadow crashes for the most part. victim = botAI->GetUnit(unit->GetTarget()); + if (!victim) + { + return false; // Exit early if no victim is found + } if (victim && bot->GetExactDist2d(victim) < radius) { return MoveAway(victim, targetDist - bot->GetExactDist2d(victim->GetPosition())); @@ -65,12 +72,21 @@ bool AvoidShadowCrashAction::Execute(Event event) if (botAI->IsMelee(bot)) { return false; } GuidVector members = AI_VALUE(GuidVector, "group members"); + if (members.empty()) + { + return false; // Exit early if no group members are found + } for (auto& member : members) { if (bot->GetGUID() == member) { continue; } + Unit* memberUnit = botAI->GetUnit(member); + if (!memberUnit) + { + continue; // Skip if the memberUnit is null + } float currentDist = bot->GetExactDist2d(botAI->GetUnit(member)); if (currentDist < radius) { From afa32e8e51172bb54b9230aa4cf83e7b0742fde5 Mon Sep 17 00:00:00 2001 From: Revision Date: Wed, 23 Oct 2024 00:18:44 +0200 Subject: [PATCH 05/19] Fix the level when a quest becomes trivial (grey/gray) --- src/strategy/actions/DropQuestAction.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/strategy/actions/DropQuestAction.cpp b/src/strategy/actions/DropQuestAction.cpp index 910e5498..2a23c019 100644 --- a/src/strategy/actions/DropQuestAction.cpp +++ b/src/strategy/actions/DropQuestAction.cpp @@ -101,8 +101,24 @@ bool CleanQuestLogAction::Execute(Event event) questLevel = botLevel; } + // Set the level difference for when a quest becomes trivial + // This was determined by using the Lua code the client uses + int32 trivialLevel = 5; + if (botLevel >= 40) + { + trivialLevel = 8; + } + else if (botLevel >= 30) + { + trivialLevel = 7; + } + else if (botLevel >= 20) + { + trivialLevel = 6; + } + // Check if the quest is trivial (grey) for the bot - if ((botLevel - questLevel) >= 5) + if ((botLevel - questLevel) >= trivialLevel) { // Output only if "debug rpg" strategy is enabled if (botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT)) From 275756c3a3960c7c309732bcea5ac2dafa088eef Mon Sep 17 00:00:00 2001 From: Bobblybook Date: Sun, 27 Oct 2024 02:20:04 +1100 Subject: [PATCH 06/19] Oculus implementation --- src/strategy/AiObjectContext.cpp | 2 + .../dungeons/DungeonStrategyContext.h | 10 +- .../wotlk/WotlkDungeonActionContext.h | 2 +- .../wotlk/WotlkDungeonTriggerContext.h | 2 +- .../hallsofstone/HallsOfStoneActions.cpp | 3 +- .../wotlk/oculus/OculusActionContext.h | 30 ++ .../dungeons/wotlk/oculus/OculusActions.cpp | 355 ++++++++++++++++++ .../dungeons/wotlk/oculus/OculusActions.h | 77 ++++ .../wotlk/oculus/OculusMultipliers.cpp | 109 ++++++ .../dungeons/wotlk/oculus/OculusMultipliers.h | 53 +++ .../dungeons/wotlk/oculus/OculusStrategy.cpp | 42 +++ .../dungeons/wotlk/oculus/OculusStrategy.h | 18 + .../wotlk/oculus/OculusTriggerContext.h | 33 ++ .../dungeons/wotlk/oculus/OculusTriggers.cpp | 85 +++++ .../dungeons/wotlk/oculus/OculusTriggers.h | 129 +++++++ src/strategy/dungeons/wotlk/oculus/TODO | 0 .../wotlk/oldkingdom/OldKingdomActions.cpp | 25 +- 17 files changed, 949 insertions(+), 26 deletions(-) create mode 100644 src/strategy/dungeons/wotlk/oculus/OculusActionContext.h create mode 100644 src/strategy/dungeons/wotlk/oculus/OculusActions.cpp create mode 100644 src/strategy/dungeons/wotlk/oculus/OculusActions.h create mode 100644 src/strategy/dungeons/wotlk/oculus/OculusMultipliers.cpp create mode 100644 src/strategy/dungeons/wotlk/oculus/OculusMultipliers.h create mode 100644 src/strategy/dungeons/wotlk/oculus/OculusStrategy.cpp create mode 100644 src/strategy/dungeons/wotlk/oculus/OculusStrategy.h create mode 100644 src/strategy/dungeons/wotlk/oculus/OculusTriggerContext.h create mode 100644 src/strategy/dungeons/wotlk/oculus/OculusTriggers.cpp create mode 100644 src/strategy/dungeons/wotlk/oculus/OculusTriggers.h delete mode 100644 src/strategy/dungeons/wotlk/oculus/TODO diff --git a/src/strategy/AiObjectContext.cpp b/src/strategy/AiObjectContext.cpp index 9b52369e..b2ede465 100644 --- a/src/strategy/AiObjectContext.cpp +++ b/src/strategy/AiObjectContext.cpp @@ -59,6 +59,7 @@ AiObjectContext::AiObjectContext(PlayerbotAI* botAI) : PlayerbotAIAware(botAI) actionContexts.Add(new WotlkDungeonGDActionContext()); actionContexts.Add(new WotlkDungeonHoSActionContext()); actionContexts.Add(new WotlkDungeonHoLActionContext()); + actionContexts.Add(new WotlkDungeonOccActionContext()); actionContexts.Add(new WotlkDungeonUPActionContext()); actionContexts.Add(new WotlkDungeonCoSActionContext()); @@ -80,6 +81,7 @@ AiObjectContext::AiObjectContext(PlayerbotAI* botAI) : PlayerbotAIAware(botAI) triggerContexts.Add(new WotlkDungeonGDTriggerContext()); triggerContexts.Add(new WotlkDungeonHoSTriggerContext()); triggerContexts.Add(new WotlkDungeonHoLTriggerContext()); + triggerContexts.Add(new WotlkDungeonOccTriggerContext()); triggerContexts.Add(new WotlkDungeonUPTriggerContext()); triggerContexts.Add(new WotlkDungeonCoSTriggerContext()); diff --git a/src/strategy/dungeons/DungeonStrategyContext.h b/src/strategy/dungeons/DungeonStrategyContext.h index 3bb39c18..5b1914a2 100644 --- a/src/strategy/dungeons/DungeonStrategyContext.h +++ b/src/strategy/dungeons/DungeonStrategyContext.h @@ -11,14 +11,13 @@ #include "wotlk/gundrak/GundrakStrategy.h" #include "wotlk/hallsofstone/HallsOfStoneStrategy.h" #include "wotlk/hallsoflightning/HallsOfLightningStrategy.h" +#include "wotlk/oculus/OculusStrategy.h" #include "wotlk/utgardepinnacle/UtgardePinnacleStrategy.h" #include "wotlk/cullingofstratholme/CullingOfStratholmeStrategy.h" /* Full list/TODO: -The Oculus - Occ -Drakos the Interrogator, Varos Cloudstrider, Mage-Lord Urom, Ley-Guardian Eregos Trial of the Champion - ToC Alliance Champions: Deathstalker Visceri, Eressea Dawnsinger, Mokra the Skullcrusher, Runok Wildmane, Zul'tore Horde Champions: Ambrose Boltspark, Colosos, Jacob Alerius, Jaelyne Evensong, Lana Stouthammer @@ -74,12 +73,11 @@ class DungeonStrategyContext : public NamedObjectContext static Strategy* wotlk_gd(PlayerbotAI* botAI) { return new WotlkDungeonGDStrategy(botAI); } static Strategy* wotlk_hos(PlayerbotAI* botAI) { return new WotlkDungeonHoSStrategy(botAI); } static Strategy* wotlk_hol(PlayerbotAI* botAI) { return new WotlkDungeonHoLStrategy(botAI); } - // static Strategy* wotlk_occ(PlayerbotAI* botAI) { return new WotlkDungeonOccStrategy(botAI); } - static Strategy* wotlk_occ(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); } + static Strategy* wotlk_occ(PlayerbotAI* botAI) { return new WotlkDungeonOccStrategy(botAI); } static Strategy* wotlk_up(PlayerbotAI* botAI) { return new WotlkDungeonUPStrategy(botAI); } static Strategy* wotlk_cos(PlayerbotAI* botAI) { return new WotlkDungeonCoSStrategy(botAI); } - - static Strategy* wotlk_toc(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); } // NYI from here down + // NYI from here down + static Strategy* wotlk_toc(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); } static Strategy* wotlk_hor(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); } static Strategy* wotlk_pos(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); } static Strategy* wotlk_fos(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); } diff --git a/src/strategy/dungeons/wotlk/WotlkDungeonActionContext.h b/src/strategy/dungeons/wotlk/WotlkDungeonActionContext.h index 81b47ae2..e6f2e00a 100644 --- a/src/strategy/dungeons/wotlk/WotlkDungeonActionContext.h +++ b/src/strategy/dungeons/wotlk/WotlkDungeonActionContext.h @@ -10,7 +10,7 @@ #include "gundrak/GundrakActionContext.h" #include "hallsofstone/HallsOfStoneActionContext.h" #include "hallsoflightning/HallsOfLightningActionContext.h" -// #include "oculus/OculusActionContext.h" +#include "oculus/OculusActionContext.h" #include "utgardepinnacle/UtgardePinnacleActionContext.h" #include "cullingofstratholme/CullingOfStratholmeActionContext.h" // #include "trialofthechampion/TrialOfTheChampionActionContext.h" diff --git a/src/strategy/dungeons/wotlk/WotlkDungeonTriggerContext.h b/src/strategy/dungeons/wotlk/WotlkDungeonTriggerContext.h index 0bafe36a..455239ab 100644 --- a/src/strategy/dungeons/wotlk/WotlkDungeonTriggerContext.h +++ b/src/strategy/dungeons/wotlk/WotlkDungeonTriggerContext.h @@ -10,7 +10,7 @@ #include "gundrak/GundrakTriggerContext.h" #include "hallsofstone/HallsOfStoneTriggerContext.h" #include "hallsoflightning/HallsOfLightningTriggerContext.h" -// #include "oculus/OculusTriggerContext.h" +#include "oculus/OculusTriggerContext.h" #include "utgardepinnacle/UtgardePinnacleTriggerContext.h" #include "cullingofstratholme/CullingOfStratholmeTriggerContext.h" // #include "trialofthechampion/TrialOfTheChampionTriggerContext.h" diff --git a/src/strategy/dungeons/wotlk/hallsofstone/HallsOfStoneActions.cpp b/src/strategy/dungeons/wotlk/hallsofstone/HallsOfStoneActions.cpp index 29f9b3ca..54901249 100644 --- a/src/strategy/dungeons/wotlk/hallsofstone/HallsOfStoneActions.cpp +++ b/src/strategy/dungeons/wotlk/hallsofstone/HallsOfStoneActions.cpp @@ -5,10 +5,11 @@ bool ShatterSpreadAction::Execute(Event event) { Unit* boss = AI_VALUE2(Unit*, "find target", "krystallus"); - float radius = 40.0f; if (!boss) { return false; } + float radius = 40.0f; Unit* closestMember = nullptr; + GuidVector members = AI_VALUE(GuidVector, "group members"); for (auto& member : members) { diff --git a/src/strategy/dungeons/wotlk/oculus/OculusActionContext.h b/src/strategy/dungeons/wotlk/oculus/OculusActionContext.h new file mode 100644 index 00000000..38cd640b --- /dev/null +++ b/src/strategy/dungeons/wotlk/oculus/OculusActionContext.h @@ -0,0 +1,30 @@ +#ifndef _PLAYERBOT_WOTLKDUNGEONOCCACTIONCONTEXT_H +#define _PLAYERBOT_WOTLKDUNGEONOCCACTIONCONTEXT_H + +#include "Action.h" +#include "NamedObjectContext.h" +#include "OculusActions.h" + +class WotlkDungeonOccActionContext : public NamedObjectContext +{ + public: + WotlkDungeonOccActionContext() { + creators["avoid unstable sphere"] = &WotlkDungeonOccActionContext::avoid_unstable_sphere; + creators["mount drake"] = &WotlkDungeonOccActionContext::mount_drake; + creators["dismount drake"] = &WotlkDungeonOccActionContext::dismount_drake; + creators["fly drake"] = &WotlkDungeonOccActionContext::fly_drake; + creators["drake attack"] = &WotlkDungeonOccActionContext::drake_attack; + creators["avoid arcane explosion"] = &WotlkDungeonOccActionContext::avoid_arcane_explosion; + creators["time bomb spread"] = &WotlkDungeonOccActionContext::time_bomb_spread; + } + private: + static Action* avoid_unstable_sphere(PlayerbotAI* ai) { return new AvoidUnstableSphereAction(ai); } + static Action* mount_drake(PlayerbotAI* ai) { return new MountDrakeAction(ai); } + static Action* dismount_drake(PlayerbotAI* ai) { return new DismountDrakeAction(ai); } + static Action* fly_drake(PlayerbotAI* ai) { return new FlyDrakeAction(ai); } + static Action* drake_attack(PlayerbotAI* ai) { return new DrakeAttackAction(ai); } + static Action* avoid_arcane_explosion(PlayerbotAI* ai) { return new AvoidArcaneExplosionAction(ai); } + static Action* time_bomb_spread(PlayerbotAI* ai) { return new TimeBombSpreadAction(ai); } +}; + +#endif diff --git a/src/strategy/dungeons/wotlk/oculus/OculusActions.cpp b/src/strategy/dungeons/wotlk/oculus/OculusActions.cpp new file mode 100644 index 00000000..e50ae07d --- /dev/null +++ b/src/strategy/dungeons/wotlk/oculus/OculusActions.cpp @@ -0,0 +1,355 @@ +#include "Playerbots.h" +#include "OculusActions.h" +#include "OculusStrategy.h" +#include "LastSpellCastValue.h" + +bool AvoidUnstableSphereAction::Execute(Event event) +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "drakos the interrogator"); + if (!boss) { return false; } + + float radius = 12.0f; + float extraDistance = 1.0f; + Unit* closestSphere = nullptr; + + GuidVector npcs = AI_VALUE(GuidVector, "nearest hostile npcs"); + for (auto& npc : npcs) + { + Unit* unit = botAI->GetUnit(npc); + if (unit && unit->GetEntry() == NPC_UNSTABLE_SPHERE && !unit->isMoving()) + { + if (!closestSphere || bot->GetExactDist2d(unit) < bot->GetExactDist2d(closestSphere)) + { + closestSphere = unit; + } + } + } + + if (closestSphere && bot->GetExactDist2d(closestSphere) < radius + extraDistance) + { + return MoveAway(closestSphere, fmin(3.0f, bot->GetExactDist2d(closestSphere) - radius + extraDistance)); + } + + return false; +} + +bool MountDrakeAction::isPossible() { return bot->GetMapId() == OCULUS_MAP_ID; } +bool MountDrakeAction::Execute(Event event) +{ + std::map drakeAssignments; + // Composition can be adjusted - both 3/1/1 and 2/2/1 are good default comps + // {Amber, Emerald, Ruby} + std::vector composition = {2, 2, 1}; + // std::vector composition = {3, 1, 1}; + int32 myIndex = botAI->GetGroupSlotIndex(bot); + + Player* master = botAI->GetMaster(); + if (!master) { return false; } + Unit* vehicle = master->GetVehicleBase(); + if (!vehicle) { return false; } + + // Subtract the player's chosen mount type from the composition so player can play whichever they prefer + switch (vehicle->GetEntry()) + { + case NPC_AMBER_DRAKE: + composition[0]--; + break; + case NPC_EMERALD_DRAKE: + composition[1]--; + break; + case NPC_RUBY_DRAKE: + composition[2]--; + break; + } + + GuidVector members = AI_VALUE(GuidVector, "group members"); + for (auto& member : members) + { + Player* player = botAI->GetPlayer(member); + if (!player) { continue; } + + for (int i = 0; i < composition.size(); i++) + { + if (composition[i] > 0) + { + drakeAssignments[botAI->GetGroupSlotIndex(player)] = DRAKE_ITEMS[i]; + composition[i]--; + break; + } + } + } + + // Correct/update the drake items in inventories incase assignments have changed + for (uint32 itemId : DRAKE_ITEMS) + { + Item* item = bot->GetItemByEntry(itemId); + if (!item) { continue; } + + if (itemId == drakeAssignments[myIndex]) + { + // Use our assigned drake + return UseItemAuto(item); + } + // Else assigned drake is different, destroy old drake + uint32 count = 1; + bot->DestroyItemCount(item, count, true); + break; + } + + // Bot does not have the correct drake item + bot->AddItem(drakeAssignments[myIndex], 1); + return false; +} + +bool DismountDrakeAction::Execute(Event event) +{ + if (bot->GetVehicle()) + { + bot->ExitVehicle(); + return true; + } + return false; +} + +bool FlyDrakeAction::Execute(Event event) +{ + Player* master = botAI->GetMaster(); + if (!master) { return false; } + Unit* masterVehicle = master->GetVehicleBase(); + Unit* vehicleBase = bot->GetVehicleBase(); + if (!vehicleBase || !masterVehicle) { return false; } + + MotionMaster* mm = vehicleBase->GetMotionMaster(); + Unit* boss = AI_VALUE2(Unit*, "find target", "ley-guardian eregos"); + if (boss && !boss->HasAura(SPELL_PLANAR_SHIFT)) + { + // Handle as boss encounter instead of formation flight + mm->Clear(false); + float distance = vehicleBase->GetExactDist(boss); + float range = 55.0f; // Drake range is 60yd + if (distance > range) + { + mm->MoveForwards(boss, range - distance); + vehicleBase->SendMovementFlagUpdate(); + return true; + } + + vehicleBase->SetFacingToObject(boss); + mm->MoveIdle(); + vehicleBase->SendMovementFlagUpdate(); + return false; + } + + if (vehicleBase->GetExactDist(masterVehicle) > 20.0f) + { + // 3/4 of a circle, with frontal cone 90 deg unobstructed + float angle = botAI->GetGroupSlotIndex(bot) * (2*M_PI - M_PI_2)/5 + M_PI_2; + vehicleBase->SetCanFly(true); + mm->MoveFollow(masterVehicle, 15.0f, angle); + vehicleBase->SendMovementFlagUpdate(); + return true; + } + return false; +} + +bool DrakeAttackAction::Execute(Event event) +{ + vehicleBase = bot->GetVehicleBase(); + if (!vehicleBase) { return false; } + + Unit* target = AI_VALUE(Unit*, "current target"); + + if (!target) + { + GuidVector attackers = AI_VALUE(GuidVector, "attackers"); + for (auto& attacker : attackers) + { + Unit* unit = botAI->GetUnit(attacker); + if (!unit) { continue; } + + SET_AI_VALUE(Unit*, "current target", unit); + target = unit; + break; + } + } + + if (!target) { return false; } + + switch (vehicleBase->GetEntry()) + { + case NPC_AMBER_DRAKE: + return AmberDrakeAction(target); + case NPC_EMERALD_DRAKE: + return EmeraldDrakeAction(target); + case NPC_RUBY_DRAKE: + return RubyDrakeAction(target); + default: + break; + } + return false; +} + +bool DrakeAttackAction::CastDrakeSpellAction(Unit* target, uint32 spellId, uint32 cooldown) +{ + if (botAI->CanCastVehicleSpell(spellId, target)) + if (botAI->CastVehicleSpell(spellId, target)) + { + vehicleBase->AddSpellCooldown(spellId, 0, cooldown); + return true; + } + return false; +} + +bool DrakeAttackAction::AmberDrakeAction(Unit* target) +{ + Aura* shockCharges = target->GetAura(SPELL_SHOCK_CHARGE, vehicleBase->GetGUID()); + if (shockCharges && shockCharges->GetStackAmount() > 8) + { + // At 9 charges, better to detonate and re-channel rather than stacking the last charge due to gcd + // If stacking Amber drakes, may need to drop this even lower as the charges stack so fast + return CastDrakeSpellAction(target, SPELL_SHOCK_LANCE, 0); + } + + // Deal with enrage after shock charges, as Stop Time adds 5 charges and they may get wasted + if (target->HasAura(SPELL_ENRAGED_ASSAULT) && + !target->HasAura(SPELL_STOP_TIME) && + !vehicleBase->HasSpellCooldown(SPELL_STOP_TIME)) + { + return CastDrakeSpellAction(target, SPELL_STOP_TIME, 60000); + } + + if (!vehicleBase->FindCurrentSpellBySpellId(SPELL_TEMPORAL_RIFT)) + { + return CastDrakeSpellAction(target, SPELL_TEMPORAL_RIFT, 0); + } + + return false; +} + +bool DrakeAttackAction::EmeraldDrakeAction(Unit* target) +{ + Aura* poisonStacks = target->GetAura(SPELL_LEECHING_POISON, vehicleBase->GetGUID()); + if (!poisonStacks || (poisonStacks->GetStackAmount() < 3 || + poisonStacks->GetDuration() < 4000)) + { + return CastDrakeSpellAction(target, SPELL_LEECHING_POISON, 0); + } + + if (!vehicleBase->HasSpellCooldown(SPELL_TOUCH_THE_NIGHTMARE) && + (!target->HasAura(SPELL_TOUCH_THE_NIGHTMARE) || vehicleBase->HealthAbovePct(90))) + { + return CastDrakeSpellAction(target, SPELL_TOUCH_THE_NIGHTMARE, 10000); + } + + Unit* healingTarget = nullptr; + GuidVector members = AI_VALUE(GuidVector, "group members"); + for (auto& member : members) + { + Unit* unit = botAI->GetUnit(member); + if (!unit || bot->GetGUID() == member) + { + continue; + } + + Unit* drake = unit->GetVehicleBase(); + if (!drake || drake->IsFullHealth()) { continue; } + + if (!healingTarget || drake->GetHealthPct() < healingTarget->GetHealthPct() - 15.0f) + { + healingTarget = drake; + } + } + + Spell* currentSpell = vehicleBase->FindCurrentSpellBySpellId(SPELL_DREAM_FUNNEL); + if (healingTarget) + { + if (!currentSpell || currentSpell->m_targets.GetUnitTarget() != healingTarget) + { + float distance = vehicleBase->GetExactDist(healingTarget); + float range = 55.0f; + if (distance > range) + { + MotionMaster* mm = vehicleBase->GetMotionMaster(); + mm->Clear(false); + mm->MoveForwards(healingTarget, distance - range - 10.0f); + vehicleBase->SendMovementFlagUpdate(); + return false; + } + return CastDrakeSpellAction(healingTarget, SPELL_DREAM_FUNNEL, 0); + } + } + // Fill GCDs with Leeching Poison to refresh timer, rather than idling + if (!currentSpell) + { + return CastDrakeSpellAction(target, SPELL_LEECHING_POISON, 0); + } + + return false; +} + +bool DrakeAttackAction::RubyDrakeAction(Unit* target) +{ + Aura* evasiveCharges = vehicleBase->GetAura(SPELL_EVASIVE_CHARGES); + Aura* evasiveManeuvers = vehicleBase->GetAura(SPELL_EVASIVE_MANEUVERS); + + if (evasiveCharges) + { + if (evasiveManeuvers && + !vehicleBase->HasSpellCooldown(SPELL_MARTYR) && + evasiveManeuvers->GetDuration() > 10000 && + evasiveCharges->GetStackAmount() >= 5) + { + return CastDrakeSpellAction(vehicleBase, SPELL_MARTYR, 10000); + } + + if (!vehicleBase->HasSpellCooldown(SPELL_EVASIVE_MANEUVERS) && + evasiveCharges->GetStackAmount() >= 10) + { + return CastDrakeSpellAction(vehicleBase, SPELL_EVASIVE_MANEUVERS, 5000); + } + } + + return CastDrakeSpellAction(target, SPELL_SEARING_WRATH, 0); +} + +bool AvoidArcaneExplosionAction::Execute(Event event) +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "mage-lord urom"); + if (!boss) { return false; } + + const Position* closestPos = nullptr; + + for (auto& position : uromSafePositions) + { + if (!closestPos || bot->GetExactDist(position) < bot->GetExactDist(closestPos)) + { + closestPos = &position; + } + } + + if (!closestPos) { return false; } + + return MoveNear(bot->GetMapId(), closestPos->GetPositionX(), closestPos->GetPositionY(), closestPos->GetPositionZ(), 2.0f, MovementPriority::MOVEMENT_COMBAT); +} + +bool TimeBombSpreadAction::Execute(Event event) +{ + float radius = 10.0f; + float distanceExtra = 2.0f; + + GuidVector members = AI_VALUE(GuidVector, "group members"); + for (auto& member : members) + { + if (bot->GetGUID() == member) + { + continue; + } + + Unit* unit = botAI->GetUnit(member); + if (unit && bot->GetExactDist2d(unit) < radius) + { + return MoveAway(unit, radius + distanceExtra - bot->GetExactDist2d(unit)); + } + } + return false; +} diff --git a/src/strategy/dungeons/wotlk/oculus/OculusActions.h b/src/strategy/dungeons/wotlk/oculus/OculusActions.h new file mode 100644 index 00000000..2111461a --- /dev/null +++ b/src/strategy/dungeons/wotlk/oculus/OculusActions.h @@ -0,0 +1,77 @@ +#ifndef _PLAYERBOT_WOTLKDUNGEONOCCACTIONS_H +#define _PLAYERBOT_WOTLKDUNGEONOCCACTIONS_H + +#include "Action.h" +#include "AttackAction.h" +#include "PlayerbotAI.h" +#include "Playerbots.h" +#include "OculusTriggers.h" +#include "UseItemAction.h" +#include "GenericSpellActions.h" + +const Position uromSafePositions[3] = +{ + Position(1138.88f, 1052.22f, 508.36f), + Position(1084.62f, 1079.71f, 508.36f), + Position(1087.42f, 1020.132f, 508.36f) +}; + +class AvoidUnstableSphereAction : public MovementAction +{ +public: + AvoidUnstableSphereAction(PlayerbotAI* ai) : MovementAction(ai, "avoid unstable sphere") {} + bool Execute(Event event) override; +}; + +class MountDrakeAction : public UseItemAction +{ +public: + MountDrakeAction(PlayerbotAI* ai) : UseItemAction(ai, "mount drake") {} + bool Execute(Event event) override; + bool isPossible() override; +}; + +class DismountDrakeAction : public Action +{ +public: + DismountDrakeAction(PlayerbotAI* ai) : Action(ai, "dismount drake") {} + bool Execute(Event event) override; +}; + +class FlyDrakeAction : public MovementAction +{ +public: + FlyDrakeAction(PlayerbotAI* ai) : MovementAction(ai, "fly drake") {} + bool Execute(Event event) override; +}; + +class DrakeAttackAction : public Action +{ +public: + DrakeAttackAction(PlayerbotAI* botAI) : Action(botAI, "drake attack") {} + bool Execute(Event event) override; + +protected: + Unit* vehicleBase; + bool CastDrakeSpellAction(Unit* target, uint32 spellId, uint32 cooldown); + bool AmberDrakeAction(Unit* target); + bool EmeraldDrakeAction(Unit* target); + bool RubyDrakeAction(Unit* target); + +}; + +class AvoidArcaneExplosionAction : public MovementAction +{ +public: + AvoidArcaneExplosionAction(PlayerbotAI* ai) : MovementAction(ai, "avoid arcane explosion") {} + bool Execute(Event event) override; +}; + +class TimeBombSpreadAction : public MovementAction +{ +public: + TimeBombSpreadAction(PlayerbotAI* ai) : MovementAction(ai, "time bomb spread") {} + bool Execute(Event event) override; +}; + +#endif diff --git a/src/strategy/dungeons/wotlk/oculus/OculusMultipliers.cpp b/src/strategy/dungeons/wotlk/oculus/OculusMultipliers.cpp new file mode 100644 index 00000000..13490f93 --- /dev/null +++ b/src/strategy/dungeons/wotlk/oculus/OculusMultipliers.cpp @@ -0,0 +1,109 @@ +#include "OculusMultipliers.h" +#include "OculusActions.h" +#include "GenericSpellActions.h" +#include "ChooseTargetActions.h" +#include "MovementActions.h" +#include "OculusTriggers.h" +#include "FollowActions.h" +#include "ReachTargetActions.h" + +float MountingDrakeMultiplier::GetValue(Action* action) +{ + // P.I.T.A bug where the bots will somehow interrupt their item spell use, + // even though the 0.5 sec cast goes off, it puts the drake essence on 15 sec cd + // and no drake comes down. + // It seems like this is due to moving/other actions being processed during the 0.5 secs. + // If we suppress everything, they seem to mount properly. A bit of a ham-fisted solution but it works + Player* master = botAI->GetMaster(); + if (bot->GetMapId() != OCULUS_MAP_ID || !master->GetVehicleBase() || bot->GetVehicleBase()) { return 1.0f; } + + if (!dynamic_cast(action)) + { + return 0.0f; + } + return 1.0f; +} + +float FlyingMultiplier::GetValue(Action* action) +{ + if (bot->GetMapId() != OCULUS_MAP_ID || !bot->GetVehicleBase()) { return 1.0f; } + + // Suppresses FollowAction as well as some attack-based movements + if (dynamic_cast(action) && !dynamic_cast(action)) + { + return 0.0f; + } + return 1.0f; +} + +float UromMultiplier::GetValue(Action* action) +{ + if(GetPhaseByCurrentPosition(bot) < 3) + { + Unit* target = action->GetTarget(); + if (target && target->GetEntry() == NPC_MAGE_LORD_UROM) + { + return 0.0f; + } + } + + Unit* boss = AI_VALUE2(Unit*, "find target", "mage-lord urom"); + if (!boss) { return 1.0f; } + + // REAL BOSS FIGHT + if (boss->HasUnitState(UNIT_STATE_CASTING) && + boss->FindCurrentSpellBySpellId(SPELL_EMPOWERED_ARCANE_EXPLOSION)) + { + if (dynamic_cast(action) && !dynamic_cast(action)) + { + return 0.0f; + } + } + + // Don't bother avoiding Frostbomb for melee + if (botAI->IsMelee(bot)) + { + if (dynamic_cast(action)) + { + return 0.0f; + } + } + + if (bot->HasAura(SPELL_TIME_BOMB)) + { + if (dynamic_cast(action) && !dynamic_cast(action)) + { + return 0.0f; + } + } + + return 1.0f; +} + +uint8 UromMultiplier::GetPhaseByCurrentPosition(Unit* unit) +{ + // Distance to return a positive match for spawn platforms, tweak slightly if needed/ + // Make sure this doesn't get too large and reach the central ring as well + float distance = 60.0f; + + for (uint8 i = 0; i < 3; ++i) + { + if (unit->GetDistance(uromCoords[i][0], uromCoords[i][1], uromCoords[i][2]) < distance) + { + return i; + } + } + return 3; +} + +float EregosMultiplier::GetValue(Action* action) +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "ley-guardian eregos"); + if (!boss) { return 1.0f; } + + if (boss->HasAura(SPELL_PLANAR_SHIFT && dynamic_cast(action))) + { + return 0.0f; + } + return 1.0f; +} diff --git a/src/strategy/dungeons/wotlk/oculus/OculusMultipliers.h b/src/strategy/dungeons/wotlk/oculus/OculusMultipliers.h new file mode 100644 index 00000000..f2f86f79 --- /dev/null +++ b/src/strategy/dungeons/wotlk/oculus/OculusMultipliers.h @@ -0,0 +1,53 @@ +#ifndef _PLAYERBOT_WOTLKDUNGEONOCCMULTIPLIERS_H +#define _PLAYERBOT_WOTLKDUNGEONOCCMULTIPLIERS_H + +#include "Multiplier.h" +#include "Unit.h" + +const float uromCoords[4][4] = +{ // Platform coordinates + {1177.47f, 937.722f, 527.405f, 2.21657f}, + {968.66f, 1042.53f, 527.32f, 0.077f}, + {1164.02f, 1170.85f, 527.321f, 3.66f}, + {1118.31f, 1080.377f, 508.361f, 4.25f} // Inner ring, actual boss fight +}; + +class MountingDrakeMultiplier : public Multiplier +{ + public: + MountingDrakeMultiplier(PlayerbotAI* ai) : Multiplier(ai, "mounting drake") {} + + public: + virtual float GetValue(Action* action); +}; + +class FlyingMultiplier : public Multiplier +{ + public: + FlyingMultiplier(PlayerbotAI* ai) : Multiplier(ai, "flying drake") {} + + public: + virtual float GetValue(Action* action); +}; + +class UromMultiplier : public Multiplier +{ + public: + UromMultiplier(PlayerbotAI* ai) : Multiplier(ai, "mage-lord urom") {} + + public: + virtual float GetValue(Action* action); + protected: + uint8 GetPhaseByCurrentPosition(Unit* boss); +}; + +class EregosMultiplier : public Multiplier +{ + public: + EregosMultiplier(PlayerbotAI* ai) : Multiplier(ai, "ley-guardian eregos") {} + + public: + virtual float GetValue(Action* action); +}; + +#endif diff --git a/src/strategy/dungeons/wotlk/oculus/OculusStrategy.cpp b/src/strategy/dungeons/wotlk/oculus/OculusStrategy.cpp new file mode 100644 index 00000000..2b98e7da --- /dev/null +++ b/src/strategy/dungeons/wotlk/oculus/OculusStrategy.cpp @@ -0,0 +1,42 @@ +#include "OculusStrategy.h" +#include "OculusMultipliers.h" + + +void WotlkDungeonOccStrategy::InitTriggers(std::vector &triggers) +{ + // Drakos the Interrogator + // TODO: May need work, TBA. + triggers.push_back(new TriggerNode("unstable sphere", + NextAction::array(0, new NextAction("avoid unstable sphere", ACTION_MOVE + 5), nullptr))); + + // DRAKES + triggers.push_back(new TriggerNode("drake mount", + NextAction::array(0, new NextAction("mount drake", ACTION_RAID + 5), nullptr))); + triggers.push_back(new TriggerNode("drake dismount", + NextAction::array(0, new NextAction("dismount drake", ACTION_RAID + 5), nullptr))); + triggers.push_back(new TriggerNode("group flying", + NextAction::array(0, new NextAction("fly drake", ACTION_NORMAL + 1), nullptr))); + triggers.push_back(new TriggerNode("drake combat", + NextAction::array(0, new NextAction("drake attack", ACTION_NORMAL + 5), nullptr))); + + // Varos Cloudstrider + // Seems to be no way to identify the marked cores, may need to hook boss AI.. + // triggers.push_back(new TriggerNode("varos cloudstrider", + // NextAction::array(0, new NextAction("avoid energize cores", ACTION_RAID + 5), nullptr))); + + // Mage-Lord Urom + triggers.push_back(new TriggerNode("arcane explosion", + NextAction::array(0, new NextAction("avoid arcane explosion", ACTION_MOVE + 5), nullptr))); + triggers.push_back(new TriggerNode("time bomb", + NextAction::array(0, new NextAction("time bomb spread", ACTION_MOVE + 4), nullptr))); + + // Ley-Guardian Eregos +} + +void WotlkDungeonOccStrategy::InitMultipliers(std::vector &multipliers) +{ + multipliers.push_back(new MountingDrakeMultiplier(botAI)); + multipliers.push_back(new FlyingMultiplier(botAI)); + multipliers.push_back(new UromMultiplier(botAI)); + multipliers.push_back(new EregosMultiplier(botAI)); +} diff --git a/src/strategy/dungeons/wotlk/oculus/OculusStrategy.h b/src/strategy/dungeons/wotlk/oculus/OculusStrategy.h new file mode 100644 index 00000000..a734f2f4 --- /dev/null +++ b/src/strategy/dungeons/wotlk/oculus/OculusStrategy.h @@ -0,0 +1,18 @@ +#ifndef _PLAYERBOT_WOTLKDUNGEONOCCSTRATEGY_H +#define _PLAYERBOT_WOTLKDUNGEONOCCSTRATEGY_H + +#include "Multiplier.h" +#include "AiObjectContext.h" +#include "Strategy.h" + + +class WotlkDungeonOccStrategy : public Strategy +{ +public: + WotlkDungeonOccStrategy(PlayerbotAI* ai) : Strategy(ai) {} + virtual std::string const getName() override { return "oculus"; } + virtual void InitTriggers(std::vector &triggers) override; + virtual void InitMultipliers(std::vector &multipliers) override; +}; + +#endif diff --git a/src/strategy/dungeons/wotlk/oculus/OculusTriggerContext.h b/src/strategy/dungeons/wotlk/oculus/OculusTriggerContext.h new file mode 100644 index 00000000..8cbf88db --- /dev/null +++ b/src/strategy/dungeons/wotlk/oculus/OculusTriggerContext.h @@ -0,0 +1,33 @@ +#ifndef _PLAYERBOT_WOTLKDUNGEONOCCTRIGGERCONTEXT_H +#define _PLAYERBOT_WOTLKDUNGEONOCCTRIGGERCONTEXT_H + +#include "NamedObjectContext.h" +#include "AiObjectContext.h" +#include "OculusTriggers.h" + +class WotlkDungeonOccTriggerContext : public NamedObjectContext +{ + public: + WotlkDungeonOccTriggerContext() + { + creators["unstable sphere"] = &WotlkDungeonOccTriggerContext::unstable_sphere; + creators["drake mount"] = &WotlkDungeonOccTriggerContext::drake_mount; + creators["drake dismount"] = &WotlkDungeonOccTriggerContext::drake_dismount; + creators["group flying"] = &WotlkDungeonOccTriggerContext::group_flying; + creators["drake combat"] = &WotlkDungeonOccTriggerContext::drake_combat; + creators["varos cloudstrider"] = &WotlkDungeonOccTriggerContext::varos_cloudstrider; + creators["arcane explosion"] = &WotlkDungeonOccTriggerContext::arcane_explosion; + creators["time bomb"] = &WotlkDungeonOccTriggerContext::time_bomb; + } + private: + static Trigger* unstable_sphere(PlayerbotAI* ai) { return new DrakosUnstableSphereTrigger(ai); } + static Trigger* drake_mount(PlayerbotAI* ai) { return new DrakeMountTrigger(ai); } + static Trigger* drake_dismount(PlayerbotAI* ai) { return new DrakeDismountTrigger(ai); } + static Trigger* group_flying(PlayerbotAI* ai) { return new GroupFlyingTrigger(ai); } + static Trigger* drake_combat(PlayerbotAI* ai) { return new DrakeCombatTrigger(ai); } + static Trigger* varos_cloudstrider(PlayerbotAI* ai) { return new VarosCloudstriderTrigger(ai); } + static Trigger* arcane_explosion(PlayerbotAI* ai) { return new UromArcaneExplosionTrigger(ai); } + static Trigger* time_bomb(PlayerbotAI* ai) { return new UromTimeBombTrigger(ai); } +}; + +#endif diff --git a/src/strategy/dungeons/wotlk/oculus/OculusTriggers.cpp b/src/strategy/dungeons/wotlk/oculus/OculusTriggers.cpp new file mode 100644 index 00000000..38c99280 --- /dev/null +++ b/src/strategy/dungeons/wotlk/oculus/OculusTriggers.cpp @@ -0,0 +1,85 @@ +#include "Playerbots.h" +#include "OculusTriggers.h" +#include "AiObject.h" +#include "AiObjectContext.h" +#include "Unit.h" + +bool DrakosUnstableSphereTrigger::IsActive() +{ + // Doesn't seem to be much point trying to get melee to dodge this, + // they get hit anyway and it just causes a lot of running around and chaos + // if (botAI->IsMelee(bot)) { return false; } + if (botAI->IsTank(bot)) { return false; } + + GuidVector targets = AI_VALUE(GuidVector, "nearest hostile npcs"); + for (auto& target : targets) + { + Unit* unit = botAI->GetUnit(target); + if (unit && unit->GetEntry() == NPC_UNSTABLE_SPHERE) + { + return true; + } + } + return false; +} + +bool DrakeMountTrigger::IsActive() +{ + Player* master = botAI->GetMaster(); + if (!master) { return false; } + + return master->GetVehicleBase() && !bot->GetVehicleBase(); +} + +bool DrakeDismountTrigger::IsActive() +{ + Player* master = botAI->GetMaster(); + if (!master) { return false; } + + return !master->GetVehicleBase() && bot->GetVehicleBase(); +} + +bool GroupFlyingTrigger::IsActive() +{ + Player* master = botAI->GetMaster(); + if (!master) { return false; } + + return master->GetVehicleBase() && bot->GetVehicleBase(); +} + +bool DrakeCombatTrigger::IsActive() +{ + Unit* vehicleBase = bot->GetVehicleBase(); + if (!vehicleBase) { return false; } + + GuidVector attackers = AI_VALUE(GuidVector, "attackers"); + for (auto& attacker : attackers) + { + Unit* target = botAI->GetUnit(attacker); + if (!target) { continue; } + + return true; + } + return false; +} + +bool VarosCloudstriderTrigger::IsActive() +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "varos cloudstrider"); + if (!boss) { return false; } + + return true; +} + +bool UromArcaneExplosionTrigger::IsActive() +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "mage-lord urom"); + if (!boss) { return false; } + + return boss->HasUnitState(UNIT_STATE_CASTING) && boss->FindCurrentSpellBySpellId(SPELL_EMPOWERED_ARCANE_EXPLOSION); +} + +bool UromTimeBombTrigger::IsActive() +{ + return bot->HasAura(SPELL_TIME_BOMB); +} diff --git a/src/strategy/dungeons/wotlk/oculus/OculusTriggers.h b/src/strategy/dungeons/wotlk/oculus/OculusTriggers.h new file mode 100644 index 00000000..8d2d55d1 --- /dev/null +++ b/src/strategy/dungeons/wotlk/oculus/OculusTriggers.h @@ -0,0 +1,129 @@ +#ifndef _PLAYERBOT_WOTLKDUNGEONOCCTRIGGERS_H +#define _PLAYERBOT_WOTLKDUNGEONOCCTRIGGERS_H + +#include "Trigger.h" +#include "PlayerbotAIConfig.h" +#include "GenericTriggers.h" +#include "DungeonStrategyUtils.h" + +enum OculusIDs +{ + // Drakos the Interrogator + NPC_UNSTABLE_SPHERE = 28166, + SPELL_UNSTABLE_SPHERE_PASSIVE = 50756, + SPELL_UNSTABLE_SPHERE_PULSE = 50757, + SPELL_UNSTABLE_SPHERE_TIMER = 50758, + + // Drakes + NPC_AMBER_DRAKE = 27755, + NPC_EMERALD_DRAKE = 27692, + NPC_RUBY_DRAKE = 27756, + ITEM_AMBER_ESSENCE = 37859, + ITEM_EMERALD_ESSENCE = 37815, + ITEM_RUBY_ESSENCE = 37860, + SPELL_AMBER_ESSENCE = 49461, + SPELL_EMERALD_ESSENCE = 49345, + SPELL_RUBY_ESSENCE = 49462, + // Abilities: + // Amber + SPELL_SHOCK_LANCE = 49840, + SPELL_SHOCK_CHARGE = 49836, + SPELL_STOP_TIME = 49838, + SPELL_TEMPORAL_RIFT = 49592, + // Emerald + SPELL_LEECHING_POISON = 50328, + SPELL_TOUCH_THE_NIGHTMARE = 50341, + SPELL_DREAM_FUNNEL = 50344, + // Ruby + SPELL_SEARING_WRATH = 50232, + SPELL_EVASIVE_MANEUVERS = 50240, + SPELL_EVASIVE_CHARGES = 50241, + SPELL_MARTYR = 50253, + + // Varos Cloudstrider + NPC_CENTRIFUGE_CORE = 28183, + + // Mage-Lord Urom + NPC_MAGE_LORD_UROM = 27655, + SPELL_TIME_BOMB_N = 51121, + SPELL_TIME_BOMB_H = 59376, + SPELL_EMPOWERED_ARCANE_EXPLOSION_N = 51110, + SPELL_EMPOWERED_ARCANE_EXPLOSION_H = 59377, + + // Ley-Guardian Eregos + SPELL_ENRAGED_ASSAULT = 51170, + SPELL_PLANAR_SHIFT = 51162, +}; + +#define SPELL_EMPOWERED_ARCANE_EXPLOSION DUNGEON_MODE(bot, SPELL_EMPOWERED_ARCANE_EXPLOSION_N, SPELL_EMPOWERED_ARCANE_EXPLOSION_H) +#define SPELL_TIME_BOMB DUNGEON_MODE(bot, SPELL_TIME_BOMB_N, SPELL_TIME_BOMB_H) + +const std::vector DRAKE_ITEMS = {ITEM_AMBER_ESSENCE, ITEM_EMERALD_ESSENCE, ITEM_RUBY_ESSENCE}; +const std::vector DRAKE_SPELLS = {SPELL_AMBER_ESSENCE, SPELL_EMERALD_ESSENCE, SPELL_RUBY_ESSENCE}; +const uint32 OCULUS_MAP_ID = 578; + +// const float uromCoords[4][4] = +// { +// {1177.47f, 937.722f, 527.405f, 2.21657f}, +// {968.66f, 1042.53f, 527.32f, 0.077f}, +// {1164.02f, 1170.85f, 527.321f, 3.66f}, +// {1118.31f, 1080.377f, 508.361f, 4.25f} // Inner ring, actual boss fight +// }; + +class DrakosUnstableSphereTrigger : public Trigger +{ +public: + DrakosUnstableSphereTrigger(PlayerbotAI* ai) : Trigger(ai, "drakos unstable sphere") {} + bool IsActive() override; +}; + +class DrakeMountTrigger : public Trigger +{ +public: + DrakeMountTrigger(PlayerbotAI* ai) : Trigger(ai, "drake mount") {} + bool IsActive() override; +}; + +class DrakeDismountTrigger : public Trigger +{ +public: + DrakeDismountTrigger(PlayerbotAI* ai) : Trigger(ai, "drake dismount") {} + bool IsActive() override; +}; + +class GroupFlyingTrigger : public Trigger +{ +public: + GroupFlyingTrigger(PlayerbotAI* ai) : Trigger(ai, "drake fly") {} + bool IsActive() override; +}; + +class DrakeCombatTrigger : public Trigger +{ +public: + DrakeCombatTrigger(PlayerbotAI* ai) : Trigger(ai, "drake combat") {} + bool IsActive() override; +}; + +class VarosCloudstriderTrigger : public Trigger +{ +public: + VarosCloudstriderTrigger(PlayerbotAI* ai) : Trigger(ai, "varos cloudstrider") {} + bool IsActive() override; +}; + +class UromArcaneExplosionTrigger : public Trigger +{ +public: + UromArcaneExplosionTrigger(PlayerbotAI* ai) : Trigger(ai, "urom arcane explosion") {} + bool IsActive() override; +}; + +class UromTimeBombTrigger : public Trigger +{ +public: + UromTimeBombTrigger(PlayerbotAI* ai) : Trigger(ai, "urom time bomb") {} + bool IsActive() override; +}; + +#endif diff --git a/src/strategy/dungeons/wotlk/oculus/TODO b/src/strategy/dungeons/wotlk/oculus/TODO deleted file mode 100644 index e69de29b..00000000 diff --git a/src/strategy/dungeons/wotlk/oldkingdom/OldKingdomActions.cpp b/src/strategy/dungeons/wotlk/oldkingdom/OldKingdomActions.cpp index d13fae54..703c7454 100644 --- a/src/strategy/dungeons/wotlk/oldkingdom/OldKingdomActions.cpp +++ b/src/strategy/dungeons/wotlk/oldkingdom/OldKingdomActions.cpp @@ -46,10 +46,11 @@ bool AvoidShadowCrashAction::Execute(Event event) // Could check all enemy units in range as it's possible to pull multiple of these mobs. // They should really be killed 1 by 1, multipulls are messy so we just handle singles for now Unit* unit = AI_VALUE2(Unit*, "find target", "forgotten one"); + if (!unit) { return false; } + Unit* victim = nullptr; float radius = 10.0f; float targetDist = radius + 2.0f; - if (!unit) { return false; } // Actively move if targeted by a shadow crash. // Spell check not needed, they don't have any other non-instant casts @@ -58,13 +59,11 @@ bool AvoidShadowCrashAction::Execute(Event event) // This doesn't seem to avoid casts very well, perhaps because this isn't checked while allies are casting. // TODO: Revisit if this is an issue in heroics, otherwise ignore shadow crashes for the most part. victim = botAI->GetUnit(unit->GetTarget()); - if (!victim) - { - return false; // Exit early if no victim is found - } - if (victim && bot->GetExactDist2d(victim) < radius) + float distance = bot->GetExactDist2d(victim->GetPosition()); + + if (victim && distance < radius) { - return MoveAway(victim, targetDist - bot->GetExactDist2d(victim->GetPosition())); + return MoveAway(victim, targetDist - distance); } } @@ -72,21 +71,13 @@ bool AvoidShadowCrashAction::Execute(Event event) if (botAI->IsMelee(bot)) { return false; } GuidVector members = AI_VALUE(GuidVector, "group members"); - if (members.empty()) - { - return false; // Exit early if no group members are found - } for (auto& member : members) { - if (bot->GetGUID() == member) + Unit* unit = botAI->GetUnit(member); + if (!unit || bot->GetGUID() == member) { continue; } - Unit* memberUnit = botAI->GetUnit(member); - if (!memberUnit) - { - continue; // Skip if the memberUnit is null - } float currentDist = bot->GetExactDist2d(botAI->GetUnit(member)); if (currentDist < radius) { From 05542c97fc2eac1e28114779d514398dd4bdc082 Mon Sep 17 00:00:00 2001 From: Revision Date: Tue, 29 Oct 2024 01:02:30 +0100 Subject: [PATCH 07/19] Fix new compiler errors (#645) * Add missing include * Move include --- src/TravelMgr.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/TravelMgr.h b/src/TravelMgr.h index b054f436..af7d0717 100644 --- a/src/TravelMgr.h +++ b/src/TravelMgr.h @@ -10,6 +10,7 @@ #include #include "AiObject.h" +#include "Corpse.h" #include "CreatureData.h" #include "GameObject.h" #include "GridDefines.h" From 73831c16c001e987b01d4e43e5711b82445a0dd3 Mon Sep 17 00:00:00 2001 From: bash <31279994+hermensbas@users.noreply.github.com> Date: Tue, 29 Oct 2024 01:15:26 +0100 Subject: [PATCH 08/19] [performance] new baseline (#644) --- conf/playerbots.conf.dist | 10 +- src/PlayerbotAI.cpp | 207 +++++++++--------- src/PlayerbotAI.h | 9 +- src/PlayerbotAIConfig.cpp | 6 +- src/PlayerbotAIConfig.h | 2 - src/RandomPlayerbotMgr.cpp | 27 +-- src/RandomPlayerbotMgr.h | 11 +- .../actions/BattleGroundJoinAction.cpp | 15 -- 8 files changed, 115 insertions(+), 172 deletions(-) diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index b644c6c9..8d7bf12e 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -728,7 +728,7 @@ AiPlayerbot.FastReactInBG = 1 # # All In seconds -AiPlayerbot.RandomBotUpdateInterval = 20 +AiPlayerbot.RandomBotUpdateInterval = 1 AiPlayerbot.RandomBotCountChangeMinInterval = 1800 AiPlayerbot.RandomBotCountChangeMaxInterval = 7200 AiPlayerbot.MinRandomBotInWorldTime = 3600 @@ -1459,17 +1459,11 @@ AiPlayerbot.BotActiveAlone = 100 # Specify smart scaling is enabled or not. # The default is 1. When enabled (smart) scales the 'BotActiveAlone' value. -AiPlayerbot.botActiveAloneSmartScale = 1 - # Only when botLevel is between WhenMinLevel and WhenMaxLevel. +AiPlayerbot.botActiveAloneSmartScale = 1 AiPlayerbot.botActiveAloneSmartScaleWhenMinLevel = 1 AiPlayerbot.botActiveAloneSmartScaleWhenMaxLevel = 80 -# The server will tune bot activity to reach the desired server tick speed (in ms) -# bots will only join battleground when there is no lag based on latency diffs below -AiPlayerbot.botActiveAloneSmartScaleDiffWithPlayer = 100 -AiPlayerbot.botActiveAloneSmartScaleDiffEmpty = 200 - # Premade spell to avoid (undetected spells) # spellid-radius, ... AiPlayerbot.PremadeAvoidAoe = 62234-4 diff --git a/src/PlayerbotAI.cpp b/src/PlayerbotAI.cpp index 023ec7b6..af993980 100644 --- a/src/PlayerbotAI.cpp +++ b/src/PlayerbotAI.cpp @@ -31,6 +31,7 @@ #include "ObjectGuid.h" #include "PerformanceMonitor.h" #include "Player.h" +#include "GameTime.h" #include "PlayerbotAIConfig.h" #include "PlayerbotDbStore.h" #include "PlayerbotMgr.h" @@ -4095,7 +4096,7 @@ ActivePiorityType PlayerbotAI::GetPriorityType(ActivityType activityType) for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next()) { Player* member = gref->GetSource(); - if (!member || !member->IsInWorld() && member->GetMapId() != bot->GetMapId()) + if (!member || (!member->IsInWorld() && member->GetMapId() != bot->GetMapId())) continue; if (member == bot) @@ -4106,11 +4107,11 @@ ActivePiorityType PlayerbotAI::GetPriorityType(ActivityType activityType) if (!memberBotAI || memberBotAI->HasRealPlayerMaster()) return ActivePiorityType::IN_GROUP_WITH_REAL_PLAYER; - //IN_GROUP_WITH_REAL_PLAYER + //ALLOWED_PARTY_ACTIVITY if (group->IsLeader(member->GetGUID())) { if (!memberBotAI->AllowActivity(PARTY_ACTIVITY)) - return ActivePiorityType::IN_GROUP_WITH_REAL_PLAYER; + return ActivePiorityType::ALLOWED_PARTY_ACTIVITY; } } } @@ -4180,145 +4181,103 @@ ActivePiorityType PlayerbotAI::GetPriorityType(ActivityType activityType) if (IsInRealGuild()) return ActivePiorityType::PLAYER_GUILD; - //IN_INACTIVE_MAP - if (bot->IsBeingTeleported() || !bot->IsInWorld() || !HasRealPlayers(bot->GetMap())) - return ActivePiorityType::IN_INACTIVE_MAP; + + //IN_NOT_ACTIVE_MAP + if (Map* map = bot->GetMap()) + { + if (map->GetEntry()->IsWorldMap()) + { + if (!HasRealPlayers(map)) + return ActivePiorityType::IN_NOT_ACTIVE_MAP; + + if (!map->IsGridLoaded(bot->GetPositionX(), bot->GetPositionY())) + return ActivePiorityType::IN_NOT_ACTIVE_MAP; + } + } //IN_ACTIVE_MAP - if (!bot->IsBeingTeleported() && bot->IsInWorld() && HasRealPlayers(bot->GetMap())) - return ActivePiorityType::IN_ACTIVE_MAP; + if (Map* map = bot->GetMap()) + { + if (map->GetEntry()->IsWorldMap()) + { + if (HasRealPlayers(map)) + return ActivePiorityType::IN_ACTIVE_MAP; + } + } // IN_ACTIVE_AREA if (activityType == OUT_OF_PARTY_ACTIVITY || activityType == GRIND_ACTIVITY) { if (HasManyPlayersNearby(20, sPlayerbotAIConfig->sightDistance)) - return ActivePiorityType::IN_ACTIVE_AREA; + return ActivePiorityType::IN_VERY_ACTIVE_AREA; } - return ActivePiorityType::IN_ACTIVE_AREA; + return ActivePiorityType::DEFAULT; } -// Returns the lower and upper bracket for bots to be active. -// Ie. { 10, 20 } means all bots in this bracket will be inactive below 10% activityMod, -// and will be active above 20% activityMod and scale between those values. -std::pair PlayerbotAI::GetPriorityBracket(ActivePiorityType type) +bool PlayerbotAI::AllowActive(ActivityType activityType) { + // no activity allowed during bot initialization during first + // few minutes after starting the server based on maxRandomBots. + if (!sRandomPlayerbotMgr->isBotInitCompleted() && + GameTime::GetUptime().count() < sPlayerbotAIConfig->maxRandomBots * 0.15) + return false; + + // General exceptions + if (activityType == PACKET_ACTIVITY) + return true; + + ActivePiorityType type = GetPriorityType(activityType); switch (type) { case ActivePiorityType::HAS_REAL_PLAYER_MASTER: case ActivePiorityType::IS_REAL_PLAYER: case ActivePiorityType::IN_GROUP_WITH_REAL_PLAYER: case ActivePiorityType::IN_INSTANCE: - case ActivePiorityType::VISIBLE_FOR_PLAYER: - return {0, 0}; - case ActivePiorityType::IS_ALWAYS_ACTIVE: case ActivePiorityType::IN_COMBAT: - return {0, 10}; - case ActivePiorityType::IN_BG_QUEUE: - return {0, 20}; - case ActivePiorityType::IN_LFG: - return {0, 30}; case ActivePiorityType::NEARBY_PLAYER: - return {0, 40}; + case ActivePiorityType::VISIBLE_FOR_PLAYER: + case ActivePiorityType::IS_ALWAYS_ACTIVE: + return true; + break; + case ActivePiorityType::ALLOWED_PARTY_ACTIVITY: + return false; + break; + case ActivePiorityType::IN_BG_QUEUE: + case ActivePiorityType::IN_LFG: case ActivePiorityType::PLAYER_FRIEND: case ActivePiorityType::PLAYER_GUILD: - return {0, 50}; - case ActivePiorityType::IN_ACTIVE_AREA: - case ActivePiorityType::IN_EMPTY_SERVER: - return {50, 100}; case ActivePiorityType::IN_ACTIVE_MAP: - return {70, 100}; - case ActivePiorityType::IN_INACTIVE_MAP: - return {80, 100}; + case ActivePiorityType::IN_NOT_ACTIVE_MAP: + case ActivePiorityType::IN_EMPTY_SERVER: default: - return {90, 100}; + break; } - return {90, 100}; -} + // Bots do not need to move using PathGenerator. + if (activityType == DETAILED_MOVE_ACTIVITY) return false; -bool PlayerbotAI::AllowActive(ActivityType activityType) -{ - // General exceptions - if (activityType == PACKET_ACTIVITY) - return true; + // All exceptions are now done, below is the code to have a specified % of bots + // active at all times. The default is 10%. With 0.1% of all bots going active + // or inactive each minute. + if (sPlayerbotAIConfig->botActiveAlone <= 0) return false; - ActivePiorityType type = GetPriorityType(activityType); - if (activityType == DETAILED_MOVE_ACTIVITY) - { - switch (type) - { - case ActivePiorityType::HAS_REAL_PLAYER_MASTER: - case ActivePiorityType::IS_REAL_PLAYER: - case ActivePiorityType::IN_GROUP_WITH_REAL_PLAYER: - case ActivePiorityType::IN_INSTANCE: - case ActivePiorityType::VISIBLE_FOR_PLAYER: - case ActivePiorityType::IN_COMBAT: - case ActivePiorityType::NEARBY_PLAYER: - return true; - break; - case ActivePiorityType::IS_ALWAYS_ACTIVE: - case ActivePiorityType::IN_BG_QUEUE: - case ActivePiorityType::IN_LFG: - case ActivePiorityType::PLAYER_FRIEND: - case ActivePiorityType::PLAYER_GUILD: - case ActivePiorityType::IN_ACTIVE_AREA: - case ActivePiorityType::IN_EMPTY_SERVER: - case ActivePiorityType::IN_ACTIVE_MAP: - case ActivePiorityType::IN_INACTIVE_MAP: - default: - break; - } - } - else if (activityType == REACT_ACTIVITY) - { - switch (type) - { - case ActivePiorityType::HAS_REAL_PLAYER_MASTER: - case ActivePiorityType::IS_REAL_PLAYER: - case ActivePiorityType::IN_GROUP_WITH_REAL_PLAYER: - case ActivePiorityType::IN_INSTANCE: - case ActivePiorityType::VISIBLE_FOR_PLAYER: - case ActivePiorityType::IS_ALWAYS_ACTIVE: - case ActivePiorityType::IN_COMBAT: - return true; - break; - case ActivePiorityType::NEARBY_PLAYER: - case ActivePiorityType::IN_BG_QUEUE: - case ActivePiorityType::IN_LFG: - case ActivePiorityType::PLAYER_FRIEND: - case ActivePiorityType::PLAYER_GUILD: - case ActivePiorityType::IN_ACTIVE_AREA: - case ActivePiorityType::IN_EMPTY_SERVER: - case ActivePiorityType::IN_ACTIVE_MAP: - case ActivePiorityType::IN_INACTIVE_MAP: - default: - return false; - break; - } - } + // Normalize the configured botActiveAlone value, and set as default mod. + uint32 botActiveAlonePerc = sPlayerbotAIConfig->botActiveAlone > 100 ? 100 : sPlayerbotAIConfig->botActiveAlone; + uint32 mod = botActiveAlonePerc; - // GetPriorityBracket acitivity - float normalizedBotActiveAlone = sPlayerbotAIConfig->botActiveAlone > 100 ? 100 : sPlayerbotAIConfig->botActiveAlone; - float activePerc = normalizedBotActiveAlone; if (sPlayerbotAIConfig->botActiveAloneSmartScale && bot->GetLevel() >= sPlayerbotAIConfig->botActiveAloneSmartScaleWhenMinLevel && bot->GetLevel() <= sPlayerbotAIConfig->botActiveAloneSmartScaleWhenMaxLevel) { - std::pair priorityBracket = GetPriorityBracket(type); - if (!priorityBracket.second) return true; - float activityPercentage = sRandomPlayerbotMgr->getActivityPercentage(); - if (priorityBracket.first >= activityPercentage) return false; - if (priorityBracket.second <= activityPercentage && priorityBracket.second < 100) return true; - activePerc = (activityPercentage - priorityBracket.first) / (priorityBracket.second - priorityBracket.first); - activePerc *= (priorityBracket.second == 100) ? normalizedBotActiveAlone : 100; + mod = SmartScaleActivity(type, botActiveAlonePerc); } - // The last number if the amount it cycles per min. Currently set to 1% of the active bots. - uint32 ActivityNumber = GetFixedBotNumer(BotTypeNumber::ACTIVITY_TYPE_NUMBER, 100, activePerc * 0.01f); + uint32 ActivityNumber = GetFixedBotNumer(BotTypeNumber::ACTIVITY_TYPE_NUMBER, 100, + botActiveAlonePerc * static_cast(mod) / 100 * 0.01f); - // The given percentage of bots should be active and rotate 1% of those active bots each minute. - return ActivityNumber <= (activePerc); + // The given percentage of bots should be active and rotate 1% of those active bots each minute. + return ActivityNumber <= (botActiveAlonePerc * mod) / 100; } bool PlayerbotAI::AllowActivity(ActivityType activityType, bool checkNow) @@ -4335,6 +4294,42 @@ bool PlayerbotAI::AllowActivity(ActivityType activityType, bool checkNow) return allowed; } +uint32 PlayerbotAI::SmartScaleActivity(ActivePiorityType type, uint32 botActiveAlonePerc) +{ + uint32 maxDiff = sWorldUpdateTime.GetMaxUpdateTime(); + if (maxDiff > 1000) return false; + switch (type) + { + case ActivePiorityType::IN_BG_QUEUE: + case ActivePiorityType::IN_LFG: + if (maxDiff > 100) return 80; + if (maxDiff > 50) return 90; + break; + case ActivePiorityType::PLAYER_FRIEND: + case ActivePiorityType::PLAYER_GUILD: + case ActivePiorityType::IN_ACTIVE_MAP: + if (maxDiff > 200) return 10; + if (maxDiff > 150) return 25; + if (maxDiff > 100) return 50; + if (maxDiff > 50) return 80; + break; + case ActivePiorityType::IN_VERY_ACTIVE_AREA: // Many bots nearby. Do not do heavy area checks. + case ActivePiorityType::IN_NOT_ACTIVE_MAP: + if (maxDiff > 100) return 10; + if (maxDiff > 50) return 25; + else return 30; + case ActivePiorityType::IN_EMPTY_SERVER: + return 10; + default: + if (maxDiff > 200) return 10; + if (maxDiff > 150) return 25; + if (maxDiff > 100) return 50; + break; + } + + return botActiveAlonePerc; +} + bool PlayerbotAI::IsOpposing(Player* player) { return IsOpposing(player->getRace(), bot->getRace()); } bool PlayerbotAI::IsOpposing(uint8 race1, uint8 race2) diff --git a/src/PlayerbotAI.h b/src/PlayerbotAI.h index d1a2f292..03fbe7fe 100644 --- a/src/PlayerbotAI.h +++ b/src/PlayerbotAI.h @@ -255,11 +255,12 @@ enum class ActivePiorityType : uint8 NEARBY_PLAYER = 9, PLAYER_FRIEND = 10, PLAYER_GUILD = 11, - IN_ACTIVE_AREA = 12, + IN_VERY_ACTIVE_AREA = 12, IN_ACTIVE_MAP = 13, - IN_INACTIVE_MAP = 14, + IN_NOT_ACTIVE_MAP = 14, IN_EMPTY_SERVER = 15, - MAX_TYPE + ALLOWED_PARTY_ACTIVITY = 16, + DEFAULT }; enum ActivityType @@ -547,9 +548,9 @@ public: bool HasPlayerNearby(float range = sPlayerbotAIConfig->reactDistance); bool HasManyPlayersNearby(uint32 trigerrValue = 20, float range = sPlayerbotAIConfig->sightDistance); ActivePiorityType GetPriorityType(ActivityType activityType); - std::pair GetPriorityBracket(ActivePiorityType type); bool AllowActive(ActivityType activityType); bool AllowActivity(ActivityType activityType = ALL_ACTIVITY, bool checkNow = false); + uint32 SmartScaleActivity(ActivePiorityType type, uint32 botActiveAlonePerc); // Check if player is safe to use. bool IsSafe(Player* player); diff --git a/src/PlayerbotAIConfig.cpp b/src/PlayerbotAIConfig.cpp index 816a345f..7bf16079 100644 --- a/src/PlayerbotAIConfig.cpp +++ b/src/PlayerbotAIConfig.cpp @@ -156,7 +156,7 @@ bool PlayerbotAIConfig::Initialize() randomBotAutologin = sConfigMgr->GetOption("AiPlayerbot.RandomBotAutologin", true); minRandomBots = sConfigMgr->GetOption("AiPlayerbot.MinRandomBots", 50); maxRandomBots = sConfigMgr->GetOption("AiPlayerbot.MaxRandomBots", 200); - randomBotUpdateInterval = sConfigMgr->GetOption("AiPlayerbot.RandomBotUpdateInterval", 20); + randomBotUpdateInterval = sConfigMgr->GetOption("AiPlayerbot.RandomBotUpdateInterval", 1); randomBotCountChangeMinInterval = sConfigMgr->GetOption("AiPlayerbot.RandomBotCountChangeMinInterval", 30 * MINUTE); randomBotCountChangeMaxInterval = @@ -470,10 +470,6 @@ bool PlayerbotAIConfig::Initialize() sConfigMgr->GetOption("AiPlayerbot.botActiveAloneSmartScaleWhenMinLevel", 1); botActiveAloneSmartScaleWhenMaxLevel = sConfigMgr->GetOption("AiPlayerbot.botActiveAloneSmartScaleWhenMaxLevel", 80); - botActiveAloneSmartScaleDiffWithPlayer = - sConfigMgr->GetOption("AiPlayerbot.botActiveAloneSmartScaleDiffWithPlayer", 100); - botActiveAloneSmartScaleDiffEmpty = - sConfigMgr->GetOption("AiPlayerbot.botActiveAloneSmartScaleDiffEmpty", 200); randombotsWalkingRPG = sConfigMgr->GetOption("AiPlayerbot.RandombotsWalkingRPG", false); randombotsWalkingRPGInDoors = sConfigMgr->GetOption("AiPlayerbot.RandombotsWalkingRPG.InDoors", false); diff --git a/src/PlayerbotAIConfig.h b/src/PlayerbotAIConfig.h index 5ac3fa4a..0f34b41e 100644 --- a/src/PlayerbotAIConfig.h +++ b/src/PlayerbotAIConfig.h @@ -266,8 +266,6 @@ public: bool botActiveAloneSmartScale; uint32 botActiveAloneSmartScaleWhenMinLevel; uint32 botActiveAloneSmartScaleWhenMaxLevel; - uint32 botActiveAloneSmartScaleDiffWithPlayer; - uint32 botActiveAloneSmartScaleDiffEmpty; bool freeMethodLoot; int32 lootRollLevel; diff --git a/src/RandomPlayerbotMgr.cpp b/src/RandomPlayerbotMgr.cpp index 37acca8d..9020f8ce 100644 --- a/src/RandomPlayerbotMgr.cpp +++ b/src/RandomPlayerbotMgr.cpp @@ -292,11 +292,6 @@ void RandomPlayerbotMgr::UpdateAIInternal(uint32 elapsed, bool /*minimal*/) if (!sPlayerbotAIConfig->randomBotAutologin || !sPlayerbotAIConfig->enabled) return; - if (sPlayerbotAIConfig->botActiveAloneSmartScale) - { - ScaleBotActivity(); - } - uint32 maxAllowedBotCount = GetEventValue(0, "bot_count"); if (!maxAllowedBotCount || (maxAllowedBotCount < sPlayerbotAIConfig->minRandomBots || maxAllowedBotCount > sPlayerbotAIConfig->maxRandomBots)) @@ -318,6 +313,7 @@ void RandomPlayerbotMgr::UpdateAIInternal(uint32 elapsed, bool /*minimal*/) // when server is balancing bots then boost (decrease value of) the nextCheckDelay till // onlineBotCount reached the AllowedBotCount. + setIsBotInitCompleted(onlineBotCount < maxAllowedBotCount); uint32 updateIntervalTurboBoost = onlineBotCount < maxAllowedBotCount ? 1 : sPlayerbotAIConfig->randomBotUpdateInterval; SetNextCheckDelay(updateIntervalTurboBoost * (onlineBotFocus + 25) * 10); @@ -402,27 +398,6 @@ void RandomPlayerbotMgr::UpdateAIInternal(uint32 elapsed, bool /*minimal*/) } } -void RandomPlayerbotMgr::ScaleBotActivity() -{ - float activityPercentage = getActivityPercentage(); - - // if (activityPercentage >= 100.0f || activityPercentage <= 0.0f) pid.reset(); //Stop integer buildup during - // max/min activity - - // % increase/decrease wanted diff , avg diff - float activityPercentageMod = pid.calculate(sRandomPlayerbotMgr->GetPlayers().empty() ? - sPlayerbotAIConfig->botActiveAloneSmartScaleDiffEmpty : - sPlayerbotAIConfig->botActiveAloneSmartScaleDiffWithPlayer, - sWorldUpdateTime.GetAverageUpdateTime()); - - activityPercentage = activityPercentageMod + 50; - - // Cap the percentage between 0 and 100. - activityPercentage = std::max(0.0f, std::min(100.0f, activityPercentage)); - - setActivityPercentage(activityPercentage); -} - uint32 RandomPlayerbotMgr::AddRandomBots() { uint32 maxAllowedBotCount = GetEventValue(0, "bot_count"); diff --git a/src/RandomPlayerbotMgr.h b/src/RandomPlayerbotMgr.h index 5c35aefa..b5208656 100644 --- a/src/RandomPlayerbotMgr.h +++ b/src/RandomPlayerbotMgr.h @@ -103,8 +103,7 @@ public: void LogPlayerLocation(); void UpdateAIInternal(uint32 elapsed, bool minimal = false) override; -private: - void ScaleBotActivity(); +//private: public: uint32 activeBots = 0; @@ -164,11 +163,11 @@ public: return BattleMastersCache; } - float getActivityMod() { return activityMod; } - float getActivityPercentage() { return activityMod * 100.0f; } - void setActivityPercentage(float percentage) { activityMod = percentage / 100.0f; } static uint8 GetTeamClassIdx(bool isAlliance, uint8 claz) { return isAlliance * 20 + claz; } + bool isBotInitCompleted() const { return _isBotInitCompleted; } + void setIsBotInitCompleted(bool completed) { _isBotInitCompleted = completed; } + void PrepareAddclassCache(); std::map> addclassCache; protected: @@ -177,7 +176,7 @@ protected: private: // pid values are set in constructor botPID pid = botPID(1, 50, -50, 0, 0, 0); - float activityMod = 0.25; + bool _isBotInitCompleted = false; uint32 GetEventValue(uint32 bot, std::string const event); std::string const GetEventData(uint32 bot, std::string const event); uint32 SetEventValue(uint32 bot, std::string const event, uint32 value, uint32 validIn, diff --git a/src/strategy/actions/BattleGroundJoinAction.cpp b/src/strategy/actions/BattleGroundJoinAction.cpp index 349ae410..541ce2a4 100644 --- a/src/strategy/actions/BattleGroundJoinAction.cpp +++ b/src/strategy/actions/BattleGroundJoinAction.cpp @@ -234,17 +234,9 @@ bool BGJoinAction::shouldJoinBg(BattlegroundQueueTypeId queueTypeId, Battlegroun return false; TeamId teamId = bot->GetTeamId(); - bool noLag = sWorldUpdateTime.GetAverageUpdateTime() < (sRandomPlayerbotMgr->GetPlayers().empty() ? - sPlayerbotAIConfig->botActiveAloneSmartScaleDiffEmpty : - sPlayerbotAIConfig->botActiveAloneSmartScaleDiffWithPlayer) * 1.1; - uint32 BracketSize = bg->GetMaxPlayersPerTeam() * 2; uint32 TeamSize = bg->GetMaxPlayersPerTeam(); - // If performance diff is enabled, only queue if there is no lag - if (sPlayerbotAIConfig->botActiveAloneSmartScale && !noLag) - return false; - // If the bot is in a group, only the leader can queue if (bot->GetGroup() && !bot->GetGroup()->IsLeader(bot->GetGUID())) return false; @@ -577,17 +569,10 @@ bool FreeBGJoinAction::shouldJoinBg(BattlegroundQueueTypeId queueTypeId, Battleg return false; TeamId teamId = bot->GetTeamId(); - bool noLag = sWorldUpdateTime.GetAverageUpdateTime() < (sRandomPlayerbotMgr->GetPlayers().empty() ? - sPlayerbotAIConfig->botActiveAloneSmartScaleDiffEmpty : - sPlayerbotAIConfig->botActiveAloneSmartScaleDiffWithPlayer) * 1.1; uint32 BracketSize = bg->GetMaxPlayersPerTeam() * 2; uint32 TeamSize = bg->GetMaxPlayersPerTeam(); - // If performance diff is enabled, only queue if there is no lag - if (sPlayerbotAIConfig->botActiveAloneSmartScale && !noLag) - return false; - // If the bot is in a group, only the leader can queue if (bot->GetGroup() && !bot->GetGroup()->IsLeader(bot->GetGUID())) return false; From ba0332c9d5a5bd941e946c3cab6ac76277fe5a0b Mon Sep 17 00:00:00 2001 From: bash Date: Tue, 29 Oct 2024 10:57:26 +0000 Subject: [PATCH 09/19] [performance] initialize server and bots fase --- conf/playerbots.conf.dist | 2 +- src/PlayerbotAI.cpp | 3 +- src/PlayerbotAIConfig.cpp | 2 +- src/RandomPlayerbotMgr.cpp | 59 +++++++++++++++++++++----------------- src/RandomPlayerbotMgr.h | 6 ++-- 5 files changed, 38 insertions(+), 34 deletions(-) diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index 8d7bf12e..a8273767 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -728,7 +728,7 @@ AiPlayerbot.FastReactInBG = 1 # # All In seconds -AiPlayerbot.RandomBotUpdateInterval = 1 +AiPlayerbot.RandomBotUpdateInterval = 5 AiPlayerbot.RandomBotCountChangeMinInterval = 1800 AiPlayerbot.RandomBotCountChangeMaxInterval = 7200 AiPlayerbot.MinRandomBotInWorldTime = 3600 diff --git a/src/PlayerbotAI.cpp b/src/PlayerbotAI.cpp index af993980..6a36ed24 100644 --- a/src/PlayerbotAI.cpp +++ b/src/PlayerbotAI.cpp @@ -4219,8 +4219,7 @@ bool PlayerbotAI::AllowActive(ActivityType activityType) { // no activity allowed during bot initialization during first // few minutes after starting the server based on maxRandomBots. - if (!sRandomPlayerbotMgr->isBotInitCompleted() && - GameTime::GetUptime().count() < sPlayerbotAIConfig->maxRandomBots * 0.15) + if (sRandomPlayerbotMgr->isBotInitializing()) return false; // General exceptions diff --git a/src/PlayerbotAIConfig.cpp b/src/PlayerbotAIConfig.cpp index 7bf16079..9d9bdd44 100644 --- a/src/PlayerbotAIConfig.cpp +++ b/src/PlayerbotAIConfig.cpp @@ -156,7 +156,7 @@ bool PlayerbotAIConfig::Initialize() randomBotAutologin = sConfigMgr->GetOption("AiPlayerbot.RandomBotAutologin", true); minRandomBots = sConfigMgr->GetOption("AiPlayerbot.MinRandomBots", 50); maxRandomBots = sConfigMgr->GetOption("AiPlayerbot.MaxRandomBots", 200); - randomBotUpdateInterval = sConfigMgr->GetOption("AiPlayerbot.RandomBotUpdateInterval", 1); + randomBotUpdateInterval = sConfigMgr->GetOption("AiPlayerbot.RandomBotUpdateInterval", 5); randomBotCountChangeMinInterval = sConfigMgr->GetOption("AiPlayerbot.RandomBotCountChangeMinInterval", 30 * MINUTE); randomBotCountChangeMaxInterval = diff --git a/src/RandomPlayerbotMgr.cpp b/src/RandomPlayerbotMgr.cpp index 9020f8ce..669d9cea 100644 --- a/src/RandomPlayerbotMgr.cpp +++ b/src/RandomPlayerbotMgr.cpp @@ -40,6 +40,7 @@ #include "Unit.h" #include "UpdateTime.h" #include "World.h" +#include "GameTime.h" void PrintStatsThread() { sRandomPlayerbotMgr->PrintStats(); } @@ -309,12 +310,17 @@ void RandomPlayerbotMgr::UpdateAIInternal(uint32 elapsed, bool /*minimal*/) uint32 onlineBotFocus = 75; if (onlineBotCount < (uint32)(sPlayerbotAIConfig->minRandomBots * 90 / 100)) + { onlineBotFocus = 25; + } + + setBotInitializing( + onlineBotCount < maxAllowedBotCount && + GameTime::GetUptime().count() < sPlayerbotAIConfig->maxRandomBots * 0.15); // when server is balancing bots then boost (decrease value of) the nextCheckDelay till // onlineBotCount reached the AllowedBotCount. - setIsBotInitCompleted(onlineBotCount < maxAllowedBotCount); - uint32 updateIntervalTurboBoost = onlineBotCount < maxAllowedBotCount ? 1 : sPlayerbotAIConfig->randomBotUpdateInterval; + uint32 updateIntervalTurboBoost = isBotInitializing() ? 1 : sPlayerbotAIConfig->randomBotUpdateInterval; SetNextCheckDelay(updateIntervalTurboBoost * (onlineBotFocus + 25) * 10); PerformanceMonitorOperation* pmo = sPerformanceMonitor->start( @@ -987,35 +993,34 @@ bool RandomPlayerbotMgr::ProcessBot(uint32 bot) if (isLogginIn) return false; + uint32 randomTime; - if (!player) - { - AddPlayerBot(botGUID, 0); - randomTime = urand(1, 2); - SetEventValue(bot, "login", 1, randomTime); + if (!player) + { + AddPlayerBot(botGUID, 0); + randomTime = urand(1, 2); + SetEventValue(bot, "login", 1, randomTime); - randomTime = urand( - std::max(5, static_cast(sPlayerbotAIConfig->randomBotUpdateInterval * 0.5)), - std::max(12, static_cast(sPlayerbotAIConfig->randomBotUpdateInterval * 2))); - SetEventValue(bot, "update", 1, randomTime); + uint32 updateIntervalTurboBoost = isBotInitializing() ? 1 : sPlayerbotAIConfig->randomBotUpdateInterval; + randomTime = urand(std::max(5, static_cast(updateIntervalTurboBoost * 0.5)), + std::max(10, static_cast(updateIntervalTurboBoost * 2))); + SetEventValue(bot, "update", 1, randomTime); - // do not randomize or teleport immediately after server start (prevent lagging) - if (!GetEventValue(bot, "randomize")) - { - randomTime = urand( - 3,std::max(4, static_cast(sPlayerbotAIConfig->randomBotUpdateInterval * 0.4))); - ScheduleRandomize(bot, randomTime); - } - if (!GetEventValue(bot, "teleport")) - { - randomTime = urand( - std::max(7, static_cast(sPlayerbotAIConfig->randomBotUpdateInterval * 0.7)), - std::max(14, static_cast(sPlayerbotAIConfig->randomBotUpdateInterval * 1.4))); - ScheduleTeleport(bot, randomTime); - } + // do not randomize or teleport immediately after server start (prevent lagging) + if (!GetEventValue(bot, "randomize")) + { + randomTime = urand(3, std::max(4, static_cast(updateIntervalTurboBoost * 0.4))); + ScheduleRandomize(bot, randomTime); + } + if (!GetEventValue(bot, "teleport")) + { + randomTime = urand(std::max(7, static_cast(updateIntervalTurboBoost * 0.7)), + std::max(14, static_cast(updateIntervalTurboBoost * 1.4))); + ScheduleTeleport(bot, randomTime); + } - return true; - } + return true; + } SetEventValue(bot, "login", 0, 0); diff --git a/src/RandomPlayerbotMgr.h b/src/RandomPlayerbotMgr.h index b5208656..10405413 100644 --- a/src/RandomPlayerbotMgr.h +++ b/src/RandomPlayerbotMgr.h @@ -165,8 +165,8 @@ public: static uint8 GetTeamClassIdx(bool isAlliance, uint8 claz) { return isAlliance * 20 + claz; } - bool isBotInitCompleted() const { return _isBotInitCompleted; } - void setIsBotInitCompleted(bool completed) { _isBotInitCompleted = completed; } + bool isBotInitializing() const { return _isBotInitializing; } + void setBotInitializing(bool completed) { _isBotInitializing = completed; } void PrepareAddclassCache(); std::map> addclassCache; @@ -176,7 +176,7 @@ protected: private: // pid values are set in constructor botPID pid = botPID(1, 50, -50, 0, 0, 0); - bool _isBotInitCompleted = false; + bool _isBotInitializing = true; uint32 GetEventValue(uint32 bot, std::string const event); std::string const GetEventData(uint32 bot, std::string const event); uint32 SetEventValue(uint32 bot, std::string const event, uint32 value, uint32 validIn, From e070469439179664a8109da38aa388e2c3ae3098 Mon Sep 17 00:00:00 2001 From: Bobblybook Date: Tue, 29 Oct 2024 20:41:22 +1100 Subject: [PATCH 10/19] Limit JC jeweler's gems to 3 If bot has jewelcrafting, enforce limit of 3 of any type of jeweler's gems when autogearing/gemming --- src/factory/PlayerbotFactory.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/factory/PlayerbotFactory.cpp b/src/factory/PlayerbotFactory.cpp index 67344556..076500f6 100644 --- a/src/factory/PlayerbotFactory.cpp +++ b/src/factory/PlayerbotFactory.cpp @@ -3853,6 +3853,7 @@ void PlayerbotFactory::ApplyEnchantAndGemsNew(bool destoryOld) int32 bestGemEnchantId[4] = {-1, -1, -1, -1}; // 1, 2, 4, 8 color float bestGemScore[4] = {0, 0, 0, 0}; std::vector curCount = GetCurrentGemsCount(); + uint8 jewelersCount = 0; int requiredActive = bot->GetLevel() <= 70 ? 2 : 1; std::vector availableGems; for (const uint32& enchantGem : enchantGemIdCache) @@ -3982,6 +3983,7 @@ void PlayerbotFactory::ApplyEnchantAndGemsNew(bool destoryOld) } int32 enchantIdChosen = -1; int32 colorChosen; + bool jewelersGemChosen; float bestGemScore = -1; for (uint32& enchantGem : availableGems) { @@ -3989,6 +3991,11 @@ void PlayerbotFactory::ApplyEnchantAndGemsNew(bool destoryOld) if (!gemTemplate) continue; + // Limit jewelers (JC) epic gems to 3 + bool isJewelersGem = gemTemplate->ItemLimitCategory == 2; + if (isJewelersGem && jewelersCount >= 3) + continue; + const GemPropertiesEntry* gemProperties = sGemPropertiesStore.LookupEntry(gemTemplate->GemProperties); if (!gemProperties) continue; @@ -4022,6 +4029,7 @@ void PlayerbotFactory::ApplyEnchantAndGemsNew(bool destoryOld) enchantIdChosen = enchant_id; colorChosen = gemProperties->color; bestGemScore = score; + jewelersGemChosen = isJewelersGem; } } if (enchantIdChosen == -1) @@ -4030,6 +4038,8 @@ void PlayerbotFactory::ApplyEnchantAndGemsNew(bool destoryOld) item->SetEnchantment(EnchantmentSlot(enchant_slot), enchantIdChosen, 0, 0, bot->GetGUID()); bot->ApplyEnchantment(item, EnchantmentSlot(enchant_slot), true); curCount = GetCurrentGemsCount(); + if (jewelersGemChosen) + ++jewelersCount; } } } From ae2f2c6d04de9b786a127d30abc5f1fdb149bb4c Mon Sep 17 00:00:00 2001 From: bash <31279994+hermensbas@users.noreply.github.com> Date: Tue, 29 Oct 2024 13:08:46 +0100 Subject: [PATCH 11/19] [performance] server_and_bot_init_phase_patch1 (#652) --- conf/playerbots.conf.dist | 2 +- src/PlayerbotAIConfig.cpp | 2 +- src/RandomPlayerbotMgr.cpp | 46 +++++++++++++++++++------------------- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index a8273767..8d7bf12e 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -728,7 +728,7 @@ AiPlayerbot.FastReactInBG = 1 # # All In seconds -AiPlayerbot.RandomBotUpdateInterval = 5 +AiPlayerbot.RandomBotUpdateInterval = 1 AiPlayerbot.RandomBotCountChangeMinInterval = 1800 AiPlayerbot.RandomBotCountChangeMaxInterval = 7200 AiPlayerbot.MinRandomBotInWorldTime = 3600 diff --git a/src/PlayerbotAIConfig.cpp b/src/PlayerbotAIConfig.cpp index 9d9bdd44..7bf16079 100644 --- a/src/PlayerbotAIConfig.cpp +++ b/src/PlayerbotAIConfig.cpp @@ -156,7 +156,7 @@ bool PlayerbotAIConfig::Initialize() randomBotAutologin = sConfigMgr->GetOption("AiPlayerbot.RandomBotAutologin", true); minRandomBots = sConfigMgr->GetOption("AiPlayerbot.MinRandomBots", 50); maxRandomBots = sConfigMgr->GetOption("AiPlayerbot.MaxRandomBots", 200); - randomBotUpdateInterval = sConfigMgr->GetOption("AiPlayerbot.RandomBotUpdateInterval", 5); + randomBotUpdateInterval = sConfigMgr->GetOption("AiPlayerbot.RandomBotUpdateInterval", 1); randomBotCountChangeMinInterval = sConfigMgr->GetOption("AiPlayerbot.RandomBotCountChangeMinInterval", 30 * MINUTE); randomBotCountChangeMaxInterval = diff --git a/src/RandomPlayerbotMgr.cpp b/src/RandomPlayerbotMgr.cpp index 669d9cea..4fa098be 100644 --- a/src/RandomPlayerbotMgr.cpp +++ b/src/RandomPlayerbotMgr.cpp @@ -995,32 +995,32 @@ bool RandomPlayerbotMgr::ProcessBot(uint32 bot) uint32 randomTime; - if (!player) - { - AddPlayerBot(botGUID, 0); - randomTime = urand(1, 2); - SetEventValue(bot, "login", 1, randomTime); + if (!player) + { + AddPlayerBot(botGUID, 0); + randomTime = urand(1, 2); + SetEventValue(bot, "login", 1, randomTime); - uint32 updateIntervalTurboBoost = isBotInitializing() ? 1 : sPlayerbotAIConfig->randomBotUpdateInterval; - randomTime = urand(std::max(5, static_cast(updateIntervalTurboBoost * 0.5)), - std::max(10, static_cast(updateIntervalTurboBoost * 2))); - SetEventValue(bot, "update", 1, randomTime); + uint32 updateIntervalTurboBoost = isBotInitializing() ? 1 : sPlayerbotAIConfig->randomBotUpdateInterval; + randomTime = urand(std::max(5, static_cast(updateIntervalTurboBoost * 0.5)), + std::max(12, static_cast(updateIntervalTurboBoost * 2))); + SetEventValue(bot, "update", 1, randomTime); - // do not randomize or teleport immediately after server start (prevent lagging) - if (!GetEventValue(bot, "randomize")) - { - randomTime = urand(3, std::max(4, static_cast(updateIntervalTurboBoost * 0.4))); - ScheduleRandomize(bot, randomTime); - } - if (!GetEventValue(bot, "teleport")) - { - randomTime = urand(std::max(7, static_cast(updateIntervalTurboBoost * 0.7)), - std::max(14, static_cast(updateIntervalTurboBoost * 1.4))); - ScheduleTeleport(bot, randomTime); - } + // do not randomize or teleport immediately after server start (prevent lagging) + if (!GetEventValue(bot, "randomize")) + { + randomTime = urand(3, std::max(4, static_cast(updateIntervalTurboBoost * 0.4))); + ScheduleRandomize(bot, randomTime); + } + if (!GetEventValue(bot, "teleport")) + { + randomTime = urand(std::max(7, static_cast(updateIntervalTurboBoost * 0.7)), + std::max(14, static_cast(updateIntervalTurboBoost * 1.4))); + ScheduleTeleport(bot, randomTime); + } - return true; - } + return true; + } SetEventValue(bot, "login", 0, 0); From d246cdd5115816cf19f721d87db103917522e63d Mon Sep 17 00:00:00 2001 From: bash <31279994+hermensbas@users.noreply.github.com> Date: Tue, 29 Oct 2024 14:26:18 +0100 Subject: [PATCH 12/19] [performance] server_and_bot_init_phase_patch2 (#653) --- src/PlayerbotAI.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/PlayerbotAI.cpp b/src/PlayerbotAI.cpp index 6a36ed24..cc84034c 100644 --- a/src/PlayerbotAI.cpp +++ b/src/PlayerbotAI.cpp @@ -4254,7 +4254,7 @@ bool PlayerbotAI::AllowActive(ActivityType activityType) } // Bots do not need to move using PathGenerator. - if (activityType == DETAILED_MOVE_ACTIVITY) return false; + //if (activityType == DETAILED_MOVE_ACTIVITY) return false; // All exceptions are now done, below is the code to have a specified % of bots // active at all times. The default is 10%. With 0.1% of all bots going active @@ -4307,21 +4307,18 @@ uint32 PlayerbotAI::SmartScaleActivity(ActivePiorityType type, uint32 botActiveA case ActivePiorityType::PLAYER_FRIEND: case ActivePiorityType::PLAYER_GUILD: case ActivePiorityType::IN_ACTIVE_MAP: - if (maxDiff > 200) return 10; - if (maxDiff > 150) return 25; + if (maxDiff > 200) return 25; if (maxDiff > 100) return 50; if (maxDiff > 50) return 80; break; case ActivePiorityType::IN_VERY_ACTIVE_AREA: // Many bots nearby. Do not do heavy area checks. case ActivePiorityType::IN_NOT_ACTIVE_MAP: - if (maxDiff > 100) return 10; - if (maxDiff > 50) return 25; - else return 30; + if (maxDiff > 100) return 25; + if (maxDiff > 50) return 50; case ActivePiorityType::IN_EMPTY_SERVER: - return 10; + return 25; default: - if (maxDiff > 200) return 10; - if (maxDiff > 150) return 25; + if (maxDiff > 200) return 25; if (maxDiff > 100) return 50; break; } From 436774a7af054e409b0910a68dab773ec3f76218 Mon Sep 17 00:00:00 2001 From: bash <31279994+hermensbas@users.noreply.github.com> Date: Tue, 29 Oct 2024 23:32:16 +0100 Subject: [PATCH 13/19] [performance] Added additional circle of life, 600 yards (#655) --- src/PlayerbotAI.cpp | 49 +++++++++++++++++++++++++-------------------- src/PlayerbotAI.h | 28 ++++++++++++++------------ 2 files changed, 42 insertions(+), 35 deletions(-) diff --git a/src/PlayerbotAI.cpp b/src/PlayerbotAI.cpp index cc84034c..3c515ebb 100644 --- a/src/PlayerbotAI.cpp +++ b/src/PlayerbotAI.cpp @@ -4124,10 +4124,6 @@ ActivePiorityType PlayerbotAI::GetPriorityType(ActivityType activityType) if (!WorldPosition(bot).isOverworld()) return ActivePiorityType::IN_INSTANCE; - //VISIBLE_FOR_PLAYER - if (HasPlayerNearby(sPlayerbotAIConfig->reactDistance)) - return ActivePiorityType::VISIBLE_FOR_PLAYER; - //IN_COMBAT if (activityType != OUT_OF_PARTY_ACTIVITY && activityType != PACKET_ACTIVITY) { @@ -4136,9 +4132,15 @@ ActivePiorityType PlayerbotAI::GetPriorityType(ActivityType activityType) return ActivePiorityType::IN_COMBAT; } - //NEARBY_PLAYER + // IN_REACT_DISTANCE + if (HasPlayerNearby(sPlayerbotAIConfig->reactDistance)) + return ActivePiorityType::IN_REACT_DISTANCE; + + // NEARBY_PLAYER acitivity based on yards. if (HasPlayerNearby(300.f)) - return ActivePiorityType::NEARBY_PLAYER; + return ActivePiorityType::NEARBY_PLAYER_300; + if (HasPlayerNearby(600.f)) + return ActivePiorityType::NEARBY_PLAYER_600; //if (sPlayerbotAIConfig->IsFreeAltBot(bot) || HasStrategy("travel once", BotState::BOT_STATE_NON_COMBAT)) // return ActivePiorityType::IS_ALWAYS_ACTIVE; @@ -4205,7 +4207,7 @@ ActivePiorityType PlayerbotAI::GetPriorityType(ActivityType activityType) } } - // IN_ACTIVE_AREA + // IN_VERY_ACTIVE_AREA if (activityType == OUT_OF_PARTY_ACTIVITY || activityType == GRIND_ACTIVITY) { if (HasManyPlayersNearby(20, sPlayerbotAIConfig->sightDistance)) @@ -4226,7 +4228,10 @@ bool PlayerbotAI::AllowActive(ActivityType activityType) if (activityType == PACKET_ACTIVITY) return true; + uint32 botActiveAlonePerc = sPlayerbotAIConfig->botActiveAlone > 100 ? 100 : sPlayerbotAIConfig->botActiveAlone; + uint32 mod = botActiveAlonePerc; ActivePiorityType type = GetPriorityType(activityType); + switch (type) { case ActivePiorityType::HAS_REAL_PLAYER_MASTER: @@ -4234,8 +4239,8 @@ bool PlayerbotAI::AllowActive(ActivityType activityType) case ActivePiorityType::IN_GROUP_WITH_REAL_PLAYER: case ActivePiorityType::IN_INSTANCE: case ActivePiorityType::IN_COMBAT: - case ActivePiorityType::NEARBY_PLAYER: - case ActivePiorityType::VISIBLE_FOR_PLAYER: + case ActivePiorityType::IN_REACT_DISTANCE: + case ActivePiorityType::NEARBY_PLAYER_300: case ActivePiorityType::IS_ALWAYS_ACTIVE: return true; break; @@ -4260,11 +4265,6 @@ bool PlayerbotAI::AllowActive(ActivityType activityType) // active at all times. The default is 10%. With 0.1% of all bots going active // or inactive each minute. if (sPlayerbotAIConfig->botActiveAlone <= 0) return false; - - // Normalize the configured botActiveAlone value, and set as default mod. - uint32 botActiveAlonePerc = sPlayerbotAIConfig->botActiveAlone > 100 ? 100 : sPlayerbotAIConfig->botActiveAlone; - uint32 mod = botActiveAlonePerc; - if (sPlayerbotAIConfig->botActiveAloneSmartScale && bot->GetLevel() >= sPlayerbotAIConfig->botActiveAloneSmartScaleWhenMinLevel && bot->GetLevel() <= sPlayerbotAIConfig->botActiveAloneSmartScaleWhenMaxLevel) @@ -4302,23 +4302,28 @@ uint32 PlayerbotAI::SmartScaleActivity(ActivePiorityType type, uint32 botActiveA case ActivePiorityType::IN_BG_QUEUE: case ActivePiorityType::IN_LFG: if (maxDiff > 100) return 80; - if (maxDiff > 50) return 90; + if (maxDiff > 100) return 90; + break; + case ActivePiorityType::NEARBY_PLAYER_600: + if (maxDiff > 100) return 50; + if (maxDiff > 50) return 75; break; case ActivePiorityType::PLAYER_FRIEND: case ActivePiorityType::PLAYER_GUILD: case ActivePiorityType::IN_ACTIVE_MAP: - if (maxDiff > 200) return 25; + if (maxDiff > 200) return 30; if (maxDiff > 100) return 50; - if (maxDiff > 50) return 80; - break; - case ActivePiorityType::IN_VERY_ACTIVE_AREA: // Many bots nearby. Do not do heavy area checks. + if (maxDiff > 50) return 75; + break; + case ActivePiorityType::IN_VERY_ACTIVE_AREA: case ActivePiorityType::IN_NOT_ACTIVE_MAP: - if (maxDiff > 100) return 25; + if (maxDiff > 100) return 30; if (maxDiff > 50) return 50; + break; case ActivePiorityType::IN_EMPTY_SERVER: - return 25; + return 30; default: - if (maxDiff > 200) return 25; + if (maxDiff > 200) return 30; if (maxDiff > 100) return 50; break; } diff --git a/src/PlayerbotAI.h b/src/PlayerbotAI.h index 03fbe7fe..f7cf77ca 100644 --- a/src/PlayerbotAI.h +++ b/src/PlayerbotAI.h @@ -247,19 +247,21 @@ enum class ActivePiorityType : uint8 HAS_REAL_PLAYER_MASTER = 1, IN_GROUP_WITH_REAL_PLAYER = 2, IN_INSTANCE = 3, - VISIBLE_FOR_PLAYER = 4, - IS_ALWAYS_ACTIVE = 5, - IN_COMBAT = 6, - IN_BG_QUEUE = 7, - IN_LFG = 8, - NEARBY_PLAYER = 9, - PLAYER_FRIEND = 10, - PLAYER_GUILD = 11, - IN_VERY_ACTIVE_AREA = 12, - IN_ACTIVE_MAP = 13, - IN_NOT_ACTIVE_MAP = 14, - IN_EMPTY_SERVER = 15, - ALLOWED_PARTY_ACTIVITY = 16, + IS_ALWAYS_ACTIVE = 4, + IN_COMBAT = 5, + IN_BG_QUEUE = 6, + IN_LFG = 7, + IN_REACT_DISTANCE = 8, + NEARBY_PLAYER_300 = 9, + NEARBY_PLAYER_600 = 10, + NEARBY_PLAYER_900 = 11, + PLAYER_FRIEND = 12, + PLAYER_GUILD = 13, + IN_VERY_ACTIVE_AREA = 14, + IN_ACTIVE_MAP = 15, + IN_NOT_ACTIVE_MAP = 16, + IN_EMPTY_SERVER = 17, + ALLOWED_PARTY_ACTIVITY = 18, DEFAULT }; From 74ee7fa3a464ab85432339cbe7bf9010e0618b04 Mon Sep 17 00:00:00 2001 From: bash Date: Wed, 30 Oct 2024 01:49:42 +0000 Subject: [PATCH 14/19] [performance] side-effect of other bug causes to stay inactive when botAmount min/max not equal --- src/RandomPlayerbotMgr.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/RandomPlayerbotMgr.cpp b/src/RandomPlayerbotMgr.cpp index 4fa098be..ca9049ec 100644 --- a/src/RandomPlayerbotMgr.cpp +++ b/src/RandomPlayerbotMgr.cpp @@ -315,8 +315,8 @@ void RandomPlayerbotMgr::UpdateAIInternal(uint32 elapsed, bool /*minimal*/) } setBotInitializing( - onlineBotCount < maxAllowedBotCount && - GameTime::GetUptime().count() < sPlayerbotAIConfig->maxRandomBots * 0.15); + //onlineBotCount < maxAllowedBotCount && <-- these fields are incorrect when using bot amount min/max are not equal. + GameTime::GetUptime().count() < sPlayerbotAIConfig->maxRandomBots * 0.12); // when server is balancing bots then boost (decrease value of) the nextCheckDelay till // onlineBotCount reached the AllowedBotCount. From 16e2cac60dc8a0a2e8a7dc92a097ab7883682dfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A7=9C=E8=80=80?= Date: Wed, 30 Oct 2024 20:19:01 +0800 Subject: [PATCH 15/19] add strategy about bronjahm --- src/strategy/AiObjectContext.cpp | 2 + .../dungeons/DungeonStrategyContext.h | 4 +- src/strategy/dungeons/DungeonStrategyUtils.h | 2 +- .../wotlk/WotlkDungeonActionContext.h | 2 +- .../wotlk/WotlkDungeonTriggerContext.h | 2 +- .../wotlk/forgeofsouls/FosActionContext.h | 23 +++--- .../wotlk/forgeofsouls/FosActions.cpp | 77 ++++++++++++++++++- .../dungeons/wotlk/forgeofsouls/FosActions.h | 29 +++++++ .../wotlk/forgeofsouls/FosMultipliers.cpp | 36 +++++++-- .../wotlk/forgeofsouls/FosStrategy.cpp | 20 ++++- .../wotlk/forgeofsouls/FosTriggerContext.h | 17 ++++ .../wotlk/forgeofsouls/FosTriggers.cpp | 44 +++++++++++ .../dungeons/wotlk/forgeofsouls/FosTriggers.h | 31 +++++++- 13 files changed, 262 insertions(+), 27 deletions(-) diff --git a/src/strategy/AiObjectContext.cpp b/src/strategy/AiObjectContext.cpp index b2ede465..92ad0351 100644 --- a/src/strategy/AiObjectContext.cpp +++ b/src/strategy/AiObjectContext.cpp @@ -62,6 +62,7 @@ AiObjectContext::AiObjectContext(PlayerbotAI* botAI) : PlayerbotAIAware(botAI) actionContexts.Add(new WotlkDungeonOccActionContext()); actionContexts.Add(new WotlkDungeonUPActionContext()); actionContexts.Add(new WotlkDungeonCoSActionContext()); + actionContexts.Add(new WotlkDungeonFosActionContext()); triggerContexts.Add(new TriggerContext()); triggerContexts.Add(new ChatTriggerContext()); @@ -84,6 +85,7 @@ AiObjectContext::AiObjectContext(PlayerbotAI* botAI) : PlayerbotAIAware(botAI) triggerContexts.Add(new WotlkDungeonOccTriggerContext()); triggerContexts.Add(new WotlkDungeonUPTriggerContext()); triggerContexts.Add(new WotlkDungeonCoSTriggerContext()); + triggerContexts.Add(new WotlkDungeonFosTriggerContext()); valueContexts.Add(new ValueContext()); diff --git a/src/strategy/dungeons/DungeonStrategyContext.h b/src/strategy/dungeons/DungeonStrategyContext.h index 5b1914a2..296fc2ff 100644 --- a/src/strategy/dungeons/DungeonStrategyContext.h +++ b/src/strategy/dungeons/DungeonStrategyContext.h @@ -14,6 +14,7 @@ #include "wotlk/oculus/OculusStrategy.h" #include "wotlk/utgardepinnacle/UtgardePinnacleStrategy.h" #include "wotlk/cullingofstratholme/CullingOfStratholmeStrategy.h" +#include "wotlk/forgeofsouls/FosStrategy.h" /* Full list/TODO: @@ -76,11 +77,12 @@ class DungeonStrategyContext : public NamedObjectContext static Strategy* wotlk_occ(PlayerbotAI* botAI) { return new WotlkDungeonOccStrategy(botAI); } static Strategy* wotlk_up(PlayerbotAI* botAI) { return new WotlkDungeonUPStrategy(botAI); } static Strategy* wotlk_cos(PlayerbotAI* botAI) { return new WotlkDungeonCoSStrategy(botAI); } + static Strategy* wotlk_fos(PlayerbotAI* botAI) { return new WotlkDungeonFosStrategy(botAI); } // NYI from here down static Strategy* wotlk_toc(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); } static Strategy* wotlk_hor(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); } static Strategy* wotlk_pos(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); } - static Strategy* wotlk_fos(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); } + }; #endif diff --git a/src/strategy/dungeons/DungeonStrategyUtils.h b/src/strategy/dungeons/DungeonStrategyUtils.h index 2b738360..e5391f4b 100644 --- a/src/strategy/dungeons/DungeonStrategyUtils.h +++ b/src/strategy/dungeons/DungeonStrategyUtils.h @@ -1,6 +1,6 @@ #ifndef _PLAYERBOT_DUNGEONUTILS_H #define _PLAYERBOT_DUNGEONUTILS_H - +#include "Player.h" template inline const T& DUNGEON_MODE(Player* bot, const T& normal5, const T& heroic10) diff --git a/src/strategy/dungeons/wotlk/WotlkDungeonActionContext.h b/src/strategy/dungeons/wotlk/WotlkDungeonActionContext.h index e6f2e00a..06ca0381 100644 --- a/src/strategy/dungeons/wotlk/WotlkDungeonActionContext.h +++ b/src/strategy/dungeons/wotlk/WotlkDungeonActionContext.h @@ -13,9 +13,9 @@ #include "oculus/OculusActionContext.h" #include "utgardepinnacle/UtgardePinnacleActionContext.h" #include "cullingofstratholme/CullingOfStratholmeActionContext.h" +#include "forgeofsouls/FosActionContext.h" // #include "trialofthechampion/TrialOfTheChampionActionContext.h" // #include "hallsofreflection/HallsOfReflectionActionContext.h" // #include "pitofsaron/PitOfSaronActionContext.h" -// #include "forgeofsouls/ForgeOfSoulsActionContext.h" #endif diff --git a/src/strategy/dungeons/wotlk/WotlkDungeonTriggerContext.h b/src/strategy/dungeons/wotlk/WotlkDungeonTriggerContext.h index 455239ab..d7e1e169 100644 --- a/src/strategy/dungeons/wotlk/WotlkDungeonTriggerContext.h +++ b/src/strategy/dungeons/wotlk/WotlkDungeonTriggerContext.h @@ -13,9 +13,9 @@ #include "oculus/OculusTriggerContext.h" #include "utgardepinnacle/UtgardePinnacleTriggerContext.h" #include "cullingofstratholme/CullingOfStratholmeTriggerContext.h" +#include "forgeofsouls/FosTriggerContext.h" // #include "trialofthechampion/TrialOfTheChampionTriggerContext.h" // #include "hallsofreflection/HallsOfReflectionTriggerContext.h" // #include "pitofsaron/PitOfSaronTriggerContext.h" -// #include "forgeofsouls/ForgeOfSoulsTriggerContext.h" #endif diff --git a/src/strategy/dungeons/wotlk/forgeofsouls/FosActionContext.h b/src/strategy/dungeons/wotlk/forgeofsouls/FosActionContext.h index 33e66aab..8d8438c2 100644 --- a/src/strategy/dungeons/wotlk/forgeofsouls/FosActionContext.h +++ b/src/strategy/dungeons/wotlk/forgeofsouls/FosActionContext.h @@ -1,5 +1,5 @@ -#ifndef _PLAYERBOT_WOTLKDUNGEONNEXACTIONCONTEXT_H -#define _PLAYERBOT_WOTLKDUNGEONNEXACTIONCONTEXT_H +#ifndef _PLAYERBOT_WOTLKDUNGEONFOSACTIONCONTEXT_H +#define _PLAYERBOT_WOTLKDUNGEONFOSACTIONCONTEXT_H #include "Action.h" #include "NamedObjectContext.h" @@ -9,17 +9,18 @@ class WotlkDungeonFosActionContext : public NamedObjectContext { public: WotlkDungeonFosActionContext() { - creators["csf target"] = &WotlkDungeonFosActionContext::move_from_whirlwind; - creators["firebomb spread"] = &WotlkDungeonNexActionContext::firebomb_spread; + creators["move from bronjahm"] = &WotlkDungeonFosActionContext::move_from_bronjahm; + creators["attack corrupted soul fragment"] = &WotlkDungeonFosActionContext::attack_corrupted_soul_fragment; + creators["bronjahm tank position"] = &WotlkDungeonFosActionContext::bronjahm_tank_position; + creators["bronjahm tank target"] = &WotlkDungeonFosActionContext::bronjahm_tank_target; + creators["bronjahm dps position"] = &WotlkDungeonFosActionContext::bronjahm_dps_position; } private: - static Action* move_from_whirlwind(PlayerbotAI* ai) { return new MoveFromWhirlwindAction(ai); } - static Action* firebomb_spread(PlayerbotAI* ai) { return new FirebombSpreadAction(ai); } - static Action* telestra_split_target(PlayerbotAI* ai) { return new TelestraSplitTargetAction(ai); } - static Action* csf_target(PlayerbotAI* ai) { return new } - static Action* chaotic_rift_target(PlayerbotAI* ai) { return new ChaoticRiftTargetAction(ai); } - static Action* dodge_spikes(PlayerbotAI* ai) { return new DodgeSpikesAction(ai); } - static Action* intense_cold_jump(PlayerbotAI* ai) { return new IntenseColdJumpAction(ai); } + static Action* move_from_bronjahm(PlayerbotAI* ai) { return new MoveFromBronjahmAction(ai); } + static Action* attack_corrupted_soul_fragment(PlayerbotAI* ai) { return new AttackCorruptedSoulFragmentAction(ai); } + static Action* bronjahm_tank_position(PlayerbotAI* ai) { return new BronjahmTankPositionAction(ai); } + static Action* bronjahm_tank_target(PlayerbotAI* ai) { return new BronjahmTankTargetAction(ai); } + static Action* bronjahm_dps_position(PlayerbotAI* ai) { return new BronjahmDpsPositionAction(ai); } }; #endif diff --git a/src/strategy/dungeons/wotlk/forgeofsouls/FosActions.cpp b/src/strategy/dungeons/wotlk/forgeofsouls/FosActions.cpp index b68e22d6..42270190 100644 --- a/src/strategy/dungeons/wotlk/forgeofsouls/FosActions.cpp +++ b/src/strategy/dungeons/wotlk/forgeofsouls/FosActions.cpp @@ -9,22 +9,91 @@ bool MoveFromBronjahmAction::Execute(Event event) if (!boss) return false; + float distance = bot->GetExactDist2d(boss->GetPosition()); - float targetDis = 30.0f; + float targetDis = 20.0f; if (distance >= targetDis) return false; return MoveAway(boss, targetDis - distance); } +bool MoveFromBronjahmAction::isUseful() { return bot->HasAura(SPELL_CORRUPT_SOUL); } + bool AttackCorruptedSoulFragmentAction::Execute(Event event) { Unit* fragment = nullptr; - fragment = AI_VALUE2(Unit*, "find target", "corrupted soul fragment"); + + GuidVector targets = AI_VALUE(GuidVector, "possible targets no los"); + + for (auto i = targets.begin(); i != targets.end(); ++i) + { + Unit* unit = botAI->GetUnit(*i); + if (unit && unit->GetEntry() == NPC_CORRUPTED_SOUL_FRAGMENT) + { + fragment = unit; + break; + } + } + if (!fragment) return false; - if (AI_VALUE(Unit*, "current target") == fragment) + if (botAI->IsDps(bot)) + { + if (AI_VALUE(Unit*, "current target") == fragment) + return false; + + return Attack(fragment); + } + else + return false; + +} + +bool AttackCorruptedSoulFragmentAction::isUseful() { return botAI->IsDps(bot); } + +bool BronjahmTankPositionAction::Execute(Event event) +{ + return MoveTo(bot->GetMapId(), BRONJAHM_TANK_POSITION.GetPositionX(), BRONJAHM_TANK_POSITION.GetPositionY(), + BRONJAHM_TANK_POSITION.GetPositionZ(), false, false, false, true, MovementPriority::MOVEMENT_COMBAT); +} + +bool BronjahmTankPositionAction::isUseful() { return bot->GetExactDist2d(BRONJAHM_TANK_POSITION) > 5.0f; } + +bool BronjahmTankTargetAction::Execute(Event event) +{ + if (botAI->IsTank(bot)) + { + Unit* boss = AI_VALUE2(Unit*, "find target", "bronjahm"); + if (AI_VALUE(Unit*, "current target") == boss) + return false; + + return Attack(boss); + } + else + return false; +} + +bool BronjahmDpsPositionAction::Execute(Event event) +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "bronjahm"); + if (!boss) return false; - return Attack(fragment); + if (bot->getClass() == CLASS_HUNTER) + { + return Move(bot->GetAngle(boss), 8.0f); + } + else + { + return Move(bot->GetAngle(boss), 5.0f); + } +} + +bool BronjahmDpsPositionAction::isUseful() +{ + if (bot->GetExactDist2d(BRONJAHM_TANK_POSITION) <= 10.0f) + return false; + + return botAI->IsDps(bot) || botAI->IsHeal(bot); } diff --git a/src/strategy/dungeons/wotlk/forgeofsouls/FosActions.h b/src/strategy/dungeons/wotlk/forgeofsouls/FosActions.h index 11e9fde6..e3227019 100644 --- a/src/strategy/dungeons/wotlk/forgeofsouls/FosActions.h +++ b/src/strategy/dungeons/wotlk/forgeofsouls/FosActions.h @@ -7,11 +7,14 @@ #include "Playerbots.h" #include "FosTriggers.h" +const Position BRONJAHM_TANK_POSITION = Position(5297.9204f, 2506.698f, 686.06793f); + class MoveFromBronjahmAction : public MovementAction { public: MoveFromBronjahmAction(PlayerbotAI* ai) : MovementAction(ai, "move from bronjahm") {} bool Execute(Event event) override; + bool isUseful() override; }; class AttackCorruptedSoulFragmentAction : public AttackAction @@ -22,5 +25,31 @@ public: bool isUseful() override; }; +class BronjahmTankPositionAction : public MovementAction +{ +public: + BronjahmTankPositionAction(PlayerbotAI* ai) : MovementAction(ai, "bronjahm tank position") {} + + bool Execute(Event event) override; + + bool isUseful() override; +}; + +class BronjahmDpsPositionAction : public MovementAction +{ +public: + BronjahmDpsPositionAction(PlayerbotAI* ai) : MovementAction(ai, "bronjahm dps position") {} + + bool Execute(Event event) override; + + bool isUseful() override; +}; + +class BronjahmTankTargetAction : public AttackAction +{ +public: + BronjahmTankTargetAction(PlayerbotAI* ai) : AttackAction(ai, "bronjahm tank target") {} + bool Execute(Event event) override; +}; #endif diff --git a/src/strategy/dungeons/wotlk/forgeofsouls/FosMultipliers.cpp b/src/strategy/dungeons/wotlk/forgeofsouls/FosMultipliers.cpp index a078c69c..0666bdba 100644 --- a/src/strategy/dungeons/wotlk/forgeofsouls/FosMultipliers.cpp +++ b/src/strategy/dungeons/wotlk/forgeofsouls/FosMultipliers.cpp @@ -4,11 +4,18 @@ #include "ChooseTargetActions.h" #include "MovementActions.h" #include "FosTriggers.h" +#include "FosActions.h" float BronjahmMultiplier::GetValue(Action* action) { Unit* boss = nullptr; - boss = AI_VALUE2(Unit *, "find target", "bronjahm"); + boss = AI_VALUE2(Unit *, "find target", "bronjahm"); + if (!boss) + return 1.0f; + if (botAI->IsTank(bot)) + if (dynamic_cast(action)) + return 0.0f; + if (boss && boss->HasUnitState(UNIT_STATE_CASTING) && boss->FindCurrentSpellBySpellId(SPELL_CORRUPT_SOUL)) { if (dynamic_cast(action) && !dynamic_cast(action)) @@ -16,11 +23,30 @@ float BronjahmMultiplier::GetValue(Action* action) { return 0.0f; } } - return 1.0f; } + return 1.0f; +} float AttackFragmentMultiplier::GetValue(Action* action) { - auto isTank = botAI->IsTank(); - if (isTank && dynamic_cast(action)) + if (botAI->IsHeal(bot) && dynamic_cast(action)) return 0.0f; - return 1.0f; } + + Unit* fragment = nullptr; + + GuidVector targets = AI_VALUE(GuidVector, "possible targets no los"); + + for (auto i = targets.begin(); i != targets.end(); ++i) + { + Unit* unit = botAI->GetUnit(*i); + if (unit && unit->GetEntry() == NPC_CORRUPTED_SOUL_FRAGMENT) + { + fragment = unit; + break; + } + } + + if (fragment && dynamic_cast(action)) + return 0.0f; + + return 1.0f; +} diff --git a/src/strategy/dungeons/wotlk/forgeofsouls/FosStrategy.cpp b/src/strategy/dungeons/wotlk/forgeofsouls/FosStrategy.cpp index 2617b228..ba8d591a 100644 --- a/src/strategy/dungeons/wotlk/forgeofsouls/FosStrategy.cpp +++ b/src/strategy/dungeons/wotlk/forgeofsouls/FosStrategy.cpp @@ -1,5 +1,21 @@ #include "FosStrategy.h" +#include "FosMultipliers.h" -void WotlkDungeonFosStrategy::InitTriggers(std::vector& triggers) {} +void WotlkDungeonFosStrategy::InitTriggers(std::vector& triggers) { + triggers.push_back( + new TriggerNode("move from bronjahm", + NextAction::array(0, new NextAction("move from bronjahm", ACTION_MOVE + 5), nullptr))); + triggers.push_back(new TriggerNode( + "switch to soul fragment", NextAction::array(0, new NextAction("attack corrupted soul fragment", ACTION_RAID + 1), nullptr))); + triggers.push_back(new TriggerNode("bronjahm position", + NextAction::array(0, new NextAction("bronjahm tank position", ACTION_RAID + 1), + new NextAction("bronjahm tank target", ACTION_RAID), + new NextAction("bronjahm dps position", ACTION_RAID + 2), + nullptr))); +} -void WotlkDungeonFosStrategy::InitMultipliers(std::vector& multipliers) {} +void WotlkDungeonFosStrategy::InitMultipliers(std::vector& multipliers) +{ + multipliers.push_back(new BronjahmMultiplier(botAI)); + multipliers.push_back(new AttackFragmentMultiplier(botAI)); +} diff --git a/src/strategy/dungeons/wotlk/forgeofsouls/FosTriggerContext.h b/src/strategy/dungeons/wotlk/forgeofsouls/FosTriggerContext.h index 89ae9b61..a310db11 100644 --- a/src/strategy/dungeons/wotlk/forgeofsouls/FosTriggerContext.h +++ b/src/strategy/dungeons/wotlk/forgeofsouls/FosTriggerContext.h @@ -4,4 +4,21 @@ #include "NamedObjectContext.h" #include "AiObjectContext.h" #include "FosTriggers.h" + +class WotlkDungeonFosTriggerContext : public NamedObjectContext +{ +public: + WotlkDungeonFosTriggerContext() + { + creators["bronjahm position"] = &WotlkDungeonFosTriggerContext::bronjahm_position; + creators["move from bronjahm"] = &WotlkDungeonFosTriggerContext::move_from_bronjahm; + creators["switch to soul fragment"] = &WotlkDungeonFosTriggerContext::switch_to_soul_fragment; + } + +private: + static Trigger* move_from_bronjahm(PlayerbotAI* ai) { return new MoveFromBronjahmTrigger(ai); } + static Trigger* switch_to_soul_fragment(PlayerbotAI* ai) { return new SwitchToSoulFragment(ai); } + static Trigger* bronjahm_position(PlayerbotAI* ai) { return new BronjahmPositionTrigger(ai); } +}; + #endif // !_PLAYERBOT_WOTLKDUNGEONFOSTRIGGERCONTEXT_H diff --git a/src/strategy/dungeons/wotlk/forgeofsouls/FosTriggers.cpp b/src/strategy/dungeons/wotlk/forgeofsouls/FosTriggers.cpp index e69de29b..33e2a3fd 100644 --- a/src/strategy/dungeons/wotlk/forgeofsouls/FosTriggers.cpp +++ b/src/strategy/dungeons/wotlk/forgeofsouls/FosTriggers.cpp @@ -0,0 +1,44 @@ +#include "FosTriggers.h" +#include "Playerbots.h" +#include "AiObject.h" +#include "AiObjectContext.h" + +bool MoveFromBronjahmTrigger::IsActive() +{ + Unit* boss = nullptr; + boss = AI_VALUE2(Unit*, "find target", "bronjahm"); + if (boss && boss->HasUnitState(UNIT_STATE_CASTING)) + { + if (boss->FindCurrentSpellBySpellId(SPELL_CORRUPT_SOUL)) + return true; + } + return false; +} + +bool SwitchToSoulFragment::IsActive() +{ + Unit* fragment = nullptr; + GuidVector targets = AI_VALUE(GuidVector, "possible targets no los"); + + for (auto i = targets.begin(); i != targets.end(); ++i) + { + Unit* unit = botAI->GetUnit(*i); + if (unit && unit->GetEntry() == NPC_CORRUPTED_SOUL_FRAGMENT) + { + return true; + } + } + + return false; + +} + +bool BronjahmPositionTrigger::IsActive() +{ + + Unit* boss = AI_VALUE2(Unit*, "find target", "bronjahm"); + if (boss) + return true; + + return false; +} diff --git a/src/strategy/dungeons/wotlk/forgeofsouls/FosTriggers.h b/src/strategy/dungeons/wotlk/forgeofsouls/FosTriggers.h index dc53d973..d52c3f37 100644 --- a/src/strategy/dungeons/wotlk/forgeofsouls/FosTriggers.h +++ b/src/strategy/dungeons/wotlk/forgeofsouls/FosTriggers.h @@ -1,3 +1,6 @@ +#ifndef _PLAYERBOT_WOTLKDUNGEONFOSTRIGGERS_H +#define _PLAYERBOT_WOTLKDUNGEONFOSTRIGGERS_H + #include "Trigger.h" #include "PlayerbotAIConfig.h" #include "GenericTriggers.h" @@ -5,7 +8,33 @@ enum FosIDs { - //Boss1 + // Boss1 + NPC_CORRUPTED_SOUL_FRAGMENT = 36535, SPELL_CORRUPT_SOUL = 68839 }; + +class MoveFromBronjahmTrigger : public Trigger +{ +public: + MoveFromBronjahmTrigger(PlayerbotAI* ai) : Trigger(ai, "move from bronjahm") {} + + bool IsActive() override; +}; + +class SwitchToSoulFragment : public Trigger +{ +public: + SwitchToSoulFragment(PlayerbotAI* ai) : Trigger(ai, "switch to soul fragment") {} + + bool IsActive() override; +}; + +class BronjahmPositionTrigger : public Trigger +{ +public: + BronjahmPositionTrigger(PlayerbotAI* ai) : Trigger(ai, "bronjahm position") {} + bool IsActive() override; +}; + +#endif From f1cb2b070e92f4e02f8b2b19446d34562e2276d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A7=9C=E8=80=80?= Date: Sun, 3 Nov 2024 21:03:03 +0800 Subject: [PATCH 16/19] 2024-11-3 --- src/strategy/dungeons/wotlk/forgeofsouls/FosMultipliers.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/strategy/dungeons/wotlk/forgeofsouls/FosMultipliers.cpp b/src/strategy/dungeons/wotlk/forgeofsouls/FosMultipliers.cpp index 0666bdba..5eadea27 100644 --- a/src/strategy/dungeons/wotlk/forgeofsouls/FosMultipliers.cpp +++ b/src/strategy/dungeons/wotlk/forgeofsouls/FosMultipliers.cpp @@ -48,5 +48,8 @@ float AttackFragmentMultiplier::GetValue(Action* action) if (fragment && dynamic_cast(action)) return 0.0f; + if (fragment && dynamic_cast(action)) + return 0.0f; + return 1.0f; } From 2b358bc7b71b72dc62959f426aedc6799e99343e Mon Sep 17 00:00:00 2001 From: chris Date: Wed, 6 Nov 2024 17:29:59 +0800 Subject: [PATCH 17/19] date: 2024-11-06 --- src/strategy/AiObjectContext.cpp | 2 +- .../dungeons/DungeonStrategyContext.h | 4 +- src/strategy/dungeons/DungeonStrategyUtils.h | 1 - .../wotlk/WotlkDungeonActionContext.h | 2 +- .../wotlk/WotlkDungeonTriggerContext.h | 2 +- .../forgeofsouls/ForgeOfSoulsActionContext.h | 23 ++++++++ ...FosActions.cpp => ForgeOfSoulsActions.cpp} | 57 ++++++++++--------- .../{FosActions.h => ForgeOfSoulsActions.h} | 8 +-- ...pliers.cpp => ForgeOfSoulsMultipliers.cpp} | 12 ++-- ...ultipliers.h => ForgeOfSoulsMultipliers.h} | 0 ...sStrategy.cpp => ForgeOfSoulsStrategy.cpp} | 13 ++--- .../{FosStrategy.h => ForgeOfSoulsStrategy.h} | 6 +- ...Context.h => ForgeOfSoulsTriggerContext.h} | 2 +- ...sTriggers.cpp => ForgeOfSoulsTriggers.cpp} | 14 ++--- .../{FosTriggers.h => ForgeOfSoulsTriggers.h} | 0 .../wotlk/forgeofsouls/FosActionContext.h | 26 --------- 16 files changed, 83 insertions(+), 89 deletions(-) create mode 100644 src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsActionContext.h rename src/strategy/dungeons/wotlk/forgeofsouls/{FosActions.cpp => ForgeOfSoulsActions.cpp} (57%) rename src/strategy/dungeons/wotlk/forgeofsouls/{FosActions.h => ForgeOfSoulsActions.h} (83%) rename src/strategy/dungeons/wotlk/forgeofsouls/{FosMultipliers.cpp => ForgeOfSoulsMultipliers.cpp} (85%) rename src/strategy/dungeons/wotlk/forgeofsouls/{FosMultipliers.h => ForgeOfSoulsMultipliers.h} (100%) rename src/strategy/dungeons/wotlk/forgeofsouls/{FosStrategy.cpp => ForgeOfSoulsStrategy.cpp} (55%) rename src/strategy/dungeons/wotlk/forgeofsouls/{FosStrategy.h => ForgeOfSoulsStrategy.h} (65%) rename src/strategy/dungeons/wotlk/forgeofsouls/{FosTriggerContext.h => ForgeOfSoulsTriggerContext.h} (96%) rename src/strategy/dungeons/wotlk/forgeofsouls/{FosTriggers.cpp => ForgeOfSoulsTriggers.cpp} (66%) rename src/strategy/dungeons/wotlk/forgeofsouls/{FosTriggers.h => ForgeOfSoulsTriggers.h} (100%) delete mode 100644 src/strategy/dungeons/wotlk/forgeofsouls/FosActionContext.h diff --git a/src/strategy/AiObjectContext.cpp b/src/strategy/AiObjectContext.cpp index 92ad0351..fc791244 100644 --- a/src/strategy/AiObjectContext.cpp +++ b/src/strategy/AiObjectContext.cpp @@ -62,7 +62,7 @@ AiObjectContext::AiObjectContext(PlayerbotAI* botAI) : PlayerbotAIAware(botAI) actionContexts.Add(new WotlkDungeonOccActionContext()); actionContexts.Add(new WotlkDungeonUPActionContext()); actionContexts.Add(new WotlkDungeonCoSActionContext()); - actionContexts.Add(new WotlkDungeonFosActionContext()); + actionContexts.Add(new WotlkDungeonFoSActionContext()); triggerContexts.Add(new TriggerContext()); triggerContexts.Add(new ChatTriggerContext()); diff --git a/src/strategy/dungeons/DungeonStrategyContext.h b/src/strategy/dungeons/DungeonStrategyContext.h index 296fc2ff..aa266f66 100644 --- a/src/strategy/dungeons/DungeonStrategyContext.h +++ b/src/strategy/dungeons/DungeonStrategyContext.h @@ -14,7 +14,7 @@ #include "wotlk/oculus/OculusStrategy.h" #include "wotlk/utgardepinnacle/UtgardePinnacleStrategy.h" #include "wotlk/cullingofstratholme/CullingOfStratholmeStrategy.h" -#include "wotlk/forgeofsouls/FosStrategy.h" +#include "wotlk/forgeofsouls/ForgeOfSoulsStrategy.h" /* Full list/TODO: @@ -77,7 +77,7 @@ class DungeonStrategyContext : public NamedObjectContext static Strategy* wotlk_occ(PlayerbotAI* botAI) { return new WotlkDungeonOccStrategy(botAI); } static Strategy* wotlk_up(PlayerbotAI* botAI) { return new WotlkDungeonUPStrategy(botAI); } static Strategy* wotlk_cos(PlayerbotAI* botAI) { return new WotlkDungeonCoSStrategy(botAI); } - static Strategy* wotlk_fos(PlayerbotAI* botAI) { return new WotlkDungeonFosStrategy(botAI); } + static Strategy* wotlk_fos(PlayerbotAI* botAI) { return new WotlkDungeonFoSStrategy(botAI); } // NYI from here down static Strategy* wotlk_toc(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); } static Strategy* wotlk_hor(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); } diff --git a/src/strategy/dungeons/DungeonStrategyUtils.h b/src/strategy/dungeons/DungeonStrategyUtils.h index e5391f4b..3f67f4b4 100644 --- a/src/strategy/dungeons/DungeonStrategyUtils.h +++ b/src/strategy/dungeons/DungeonStrategyUtils.h @@ -1,6 +1,5 @@ #ifndef _PLAYERBOT_DUNGEONUTILS_H #define _PLAYERBOT_DUNGEONUTILS_H -#include "Player.h" template inline const T& DUNGEON_MODE(Player* bot, const T& normal5, const T& heroic10) diff --git a/src/strategy/dungeons/wotlk/WotlkDungeonActionContext.h b/src/strategy/dungeons/wotlk/WotlkDungeonActionContext.h index 06ca0381..75769739 100644 --- a/src/strategy/dungeons/wotlk/WotlkDungeonActionContext.h +++ b/src/strategy/dungeons/wotlk/WotlkDungeonActionContext.h @@ -13,7 +13,7 @@ #include "oculus/OculusActionContext.h" #include "utgardepinnacle/UtgardePinnacleActionContext.h" #include "cullingofstratholme/CullingOfStratholmeActionContext.h" -#include "forgeofsouls/FosActionContext.h" +#include "forgeofsouls/ForgeOfSoulsActionContext.h" // #include "trialofthechampion/TrialOfTheChampionActionContext.h" // #include "hallsofreflection/HallsOfReflectionActionContext.h" // #include "pitofsaron/PitOfSaronActionContext.h" diff --git a/src/strategy/dungeons/wotlk/WotlkDungeonTriggerContext.h b/src/strategy/dungeons/wotlk/WotlkDungeonTriggerContext.h index d7e1e169..8b4e979e 100644 --- a/src/strategy/dungeons/wotlk/WotlkDungeonTriggerContext.h +++ b/src/strategy/dungeons/wotlk/WotlkDungeonTriggerContext.h @@ -13,7 +13,7 @@ #include "oculus/OculusTriggerContext.h" #include "utgardepinnacle/UtgardePinnacleTriggerContext.h" #include "cullingofstratholme/CullingOfStratholmeTriggerContext.h" -#include "forgeofsouls/FosTriggerContext.h" +#include "forgeofsouls/ForgeOfSoulsTriggerContext.h" // #include "trialofthechampion/TrialOfTheChampionTriggerContext.h" // #include "hallsofreflection/HallsOfReflectionTriggerContext.h" // #include "pitofsaron/PitOfSaronTriggerContext.h" diff --git a/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsActionContext.h b/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsActionContext.h new file mode 100644 index 00000000..0ba0b1d2 --- /dev/null +++ b/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsActionContext.h @@ -0,0 +1,23 @@ +#ifndef _PLAYERBOT_WOTLKDUNGEONFOSACTIONCONTEXT_H +#define _PLAYERBOT_WOTLKDUNGEONFOSACTIONCONTEXT_H + +#include "Action.h" +#include "NamedObjectContext.h" +#include "ForgeOfSoulsActions.h" + +class WotlkDungeonFoSActionContext : public NamedObjectContext +{ + public: + WotlkDungeonFoSActionContext() + { + creators["move from bronjahm"] = &WotlkDungeonFoSActionContext::move_from_bronjahm; + creators["attack corrupted soul fragment"] = &WotlkDungeonFoSActionContext::attack_corrupted_soul_fragment; + creators["bronjahm group position"] = &WotlkDungeonFoSActionContext::bronjahm_group_position; + } + private: + static Action* move_from_bronjahm(PlayerbotAI* ai) { return new MoveFromBronjahmAction(ai); } + static Action* attack_corrupted_soul_fragment(PlayerbotAI* ai) { return new AttackCorruptedSoulFragmentAction(ai); } + static Action* bronjahm_group_position(PlayerbotAI* ai) { return new BronjahmGroupPositionAction(ai); } +}; + +#endif diff --git a/src/strategy/dungeons/wotlk/forgeofsouls/FosActions.cpp b/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsActions.cpp similarity index 57% rename from src/strategy/dungeons/wotlk/forgeofsouls/FosActions.cpp rename to src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsActions.cpp index 42270190..31b477ff 100644 --- a/src/strategy/dungeons/wotlk/forgeofsouls/FosActions.cpp +++ b/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsActions.cpp @@ -1,11 +1,10 @@ #include "Playerbots.h" -#include "FosActions.h" -#include "FosStrategy.h" +#include "ForgeOfSoulsActions.h" +#include "ForgeOfSoulsStrategy.h" bool MoveFromBronjahmAction::Execute(Event event) -{ - Unit* boss = nullptr; - boss = AI_VALUE2(Unit*, "find target", "bronjahm"); +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "bronjahm"); if (!boss) return false; @@ -17,7 +16,6 @@ bool MoveFromBronjahmAction::Execute(Event event) return MoveAway(boss, targetDis - distance); } -bool MoveFromBronjahmAction::isUseful() { return bot->HasAura(SPELL_CORRUPT_SOUL); } bool AttackCorruptedSoulFragmentAction::Execute(Event event) { @@ -25,9 +23,9 @@ bool AttackCorruptedSoulFragmentAction::Execute(Event event) GuidVector targets = AI_VALUE(GuidVector, "possible targets no los"); - for (auto i = targets.begin(); i != targets.end(); ++i) + for (auto &target : targets) { - Unit* unit = botAI->GetUnit(*i); + Unit* unit = botAI->GetUnit(target); if (unit && unit->GetEntry() == NPC_CORRUPTED_SOUL_FRAGMENT) { fragment = unit; @@ -35,40 +33,45 @@ bool AttackCorruptedSoulFragmentAction::Execute(Event event) } } - if (!fragment) - return false; - - if (botAI->IsDps(bot)) - { - if (AI_VALUE(Unit*, "current target") == fragment) - return false; - + if (fragment && AI_VALUE(Unit*, "current target") != fragment) return Attack(fragment); - } - else - return false; + + return false; } -bool AttackCorruptedSoulFragmentAction::isUseful() { return botAI->IsDps(bot); } -bool BronjahmTankPositionAction::Execute(Event event) +bool BronjahmGroupPositionAction::Execute(Event event) { - return MoveTo(bot->GetMapId(), BRONJAHM_TANK_POSITION.GetPositionX(), BRONJAHM_TANK_POSITION.GetPositionY(), - BRONJAHM_TANK_POSITION.GetPositionZ(), false, false, false, true, MovementPriority::MOVEMENT_COMBAT); + if (botAI->IsTank(bot)) + if (bot->GetExactDist2d(BRONJAHM_TANK_POSITION) > 5.0f) + return MoveTo(bot->GetMapId(), BRONJAHM_TANK_POSITION.GetPositionX(), BRONJAHM_TANK_POSITION.GetPositionY(), + BRONJAHM_TANK_POSITION.GetPositionZ(), false, false, false, true, + MovementPriority::MOVEMENT_COMBAT); + else + return false; + else + { + Unit* boss = AI_VALUE2(Unit*, "find target", "bronjahm"); + + if (boss) + { + + } + } } -bool BronjahmTankPositionAction::isUseful() { return bot->GetExactDist2d(BRONJAHM_TANK_POSITION) > 5.0f; } +bool BronjahmGroupPositionAction::isUseful() { return bot->GetExactDist2d(BRONJAHM_TANK_POSITION) > 5.0f; } bool BronjahmTankTargetAction::Execute(Event event) { if (botAI->IsTank(bot)) { Unit* boss = AI_VALUE2(Unit*, "find target", "bronjahm"); - if (AI_VALUE(Unit*, "current target") == boss) + if (boss && AI_VALUE(Unit*, "current target") != boss) + return Attack(boss); + else return false; - - return Attack(boss); } else return false; diff --git a/src/strategy/dungeons/wotlk/forgeofsouls/FosActions.h b/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsActions.h similarity index 83% rename from src/strategy/dungeons/wotlk/forgeofsouls/FosActions.h rename to src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsActions.h index e3227019..227a6fbe 100644 --- a/src/strategy/dungeons/wotlk/forgeofsouls/FosActions.h +++ b/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsActions.h @@ -5,7 +5,7 @@ #include "AttackAction.h" #include "PlayerbotAI.h" #include "Playerbots.h" -#include "FosTriggers.h" +#include "ForgeOfSoulsTriggers.h" const Position BRONJAHM_TANK_POSITION = Position(5297.9204f, 2506.698f, 686.06793f); @@ -14,7 +14,6 @@ class MoveFromBronjahmAction : public MovementAction public: MoveFromBronjahmAction(PlayerbotAI* ai) : MovementAction(ai, "move from bronjahm") {} bool Execute(Event event) override; - bool isUseful() override; }; class AttackCorruptedSoulFragmentAction : public AttackAction @@ -22,13 +21,12 @@ class AttackCorruptedSoulFragmentAction : public AttackAction public: AttackCorruptedSoulFragmentAction(PlayerbotAI* ai) : AttackAction(ai, "attack corrupted soul fragment") {} bool Execute(Event event) override; - bool isUseful() override; }; -class BronjahmTankPositionAction : public MovementAction +class BronjahmGroupPositionAction : public MovementAction { public: - BronjahmTankPositionAction(PlayerbotAI* ai) : MovementAction(ai, "bronjahm tank position") {} + BronjahmGroupPositionAction(PlayerbotAI* ai) : MovementAction(ai, "bronjahm group position") {} bool Execute(Event event) override; diff --git a/src/strategy/dungeons/wotlk/forgeofsouls/FosMultipliers.cpp b/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsMultipliers.cpp similarity index 85% rename from src/strategy/dungeons/wotlk/forgeofsouls/FosMultipliers.cpp rename to src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsMultipliers.cpp index 5eadea27..4e41de27 100644 --- a/src/strategy/dungeons/wotlk/forgeofsouls/FosMultipliers.cpp +++ b/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsMultipliers.cpp @@ -1,10 +1,10 @@ -#include "FosMultipliers.h" -#include "FosActions.h" +#include "ForgeOfSoulsMultipliers.h" +#include "ForgeOfSoulsActions.h" #include "GenericSpellActions.h" #include "ChooseTargetActions.h" #include "MovementActions.h" -#include "FosTriggers.h" -#include "FosActions.h" +#include "ForgeOfSoulsTriggers.h" +#include "ForgeOfSoulsActions.h" float BronjahmMultiplier::GetValue(Action* action) { @@ -35,9 +35,9 @@ float AttackFragmentMultiplier::GetValue(Action* action) GuidVector targets = AI_VALUE(GuidVector, "possible targets no los"); - for (auto i = targets.begin(); i != targets.end(); ++i) + for (auto& target : targets) { - Unit* unit = botAI->GetUnit(*i); + Unit* unit = botAI->GetUnit(target); if (unit && unit->GetEntry() == NPC_CORRUPTED_SOUL_FRAGMENT) { fragment = unit; diff --git a/src/strategy/dungeons/wotlk/forgeofsouls/FosMultipliers.h b/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsMultipliers.h similarity index 100% rename from src/strategy/dungeons/wotlk/forgeofsouls/FosMultipliers.h rename to src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsMultipliers.h diff --git a/src/strategy/dungeons/wotlk/forgeofsouls/FosStrategy.cpp b/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsStrategy.cpp similarity index 55% rename from src/strategy/dungeons/wotlk/forgeofsouls/FosStrategy.cpp rename to src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsStrategy.cpp index ba8d591a..1cc522f8 100644 --- a/src/strategy/dungeons/wotlk/forgeofsouls/FosStrategy.cpp +++ b/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsStrategy.cpp @@ -1,20 +1,17 @@ -#include "FosStrategy.h" -#include "FosMultipliers.h" +#include "ForgeOfSoulsStrategy.h" +#include "ForgeOfSoulsMultipliers.h" -void WotlkDungeonFosStrategy::InitTriggers(std::vector& triggers) { +void WotlkDungeonFoSStrategy::InitTriggers(std::vector& triggers) { triggers.push_back( new TriggerNode("move from bronjahm", NextAction::array(0, new NextAction("move from bronjahm", ACTION_MOVE + 5), nullptr))); triggers.push_back(new TriggerNode( "switch to soul fragment", NextAction::array(0, new NextAction("attack corrupted soul fragment", ACTION_RAID + 1), nullptr))); triggers.push_back(new TriggerNode("bronjahm position", - NextAction::array(0, new NextAction("bronjahm tank position", ACTION_RAID + 1), - new NextAction("bronjahm tank target", ACTION_RAID), - new NextAction("bronjahm dps position", ACTION_RAID + 2), - nullptr))); + NextAction::array(0, new NextAction("bronjahm position", ACTION_RAID + 1), nullptr))); } -void WotlkDungeonFosStrategy::InitMultipliers(std::vector& multipliers) +void WotlkDungeonFoSStrategy::InitMultipliers(std::vector& multipliers) { multipliers.push_back(new BronjahmMultiplier(botAI)); multipliers.push_back(new AttackFragmentMultiplier(botAI)); diff --git a/src/strategy/dungeons/wotlk/forgeofsouls/FosStrategy.h b/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsStrategy.h similarity index 65% rename from src/strategy/dungeons/wotlk/forgeofsouls/FosStrategy.h rename to src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsStrategy.h index 5ecf3493..79d58334 100644 --- a/src/strategy/dungeons/wotlk/forgeofsouls/FosStrategy.h +++ b/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsStrategy.h @@ -3,11 +3,11 @@ #include "Multiplier.h" #include "Strategy.h" -class WotlkDungeonFosStrategy : public Strategy +class WotlkDungeonFoSStrategy : public Strategy { public: - WotlkDungeonFosStrategy(PlayerbotAI* ai) : Strategy(ai) {} - std::string const getName() override { return "fos"; } + WotlkDungeonFoSStrategy(PlayerbotAI* ai) : Strategy(ai) {} + std::string const getName() override { return "forge of souls"; } void InitTriggers(std::vector &triggers) override; void InitMultipliers(std::vector &multipliers) override; diff --git a/src/strategy/dungeons/wotlk/forgeofsouls/FosTriggerContext.h b/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsTriggerContext.h similarity index 96% rename from src/strategy/dungeons/wotlk/forgeofsouls/FosTriggerContext.h rename to src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsTriggerContext.h index a310db11..9cef6373 100644 --- a/src/strategy/dungeons/wotlk/forgeofsouls/FosTriggerContext.h +++ b/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsTriggerContext.h @@ -3,7 +3,7 @@ #include "NamedObjectContext.h" #include "AiObjectContext.h" -#include "FosTriggers.h" +#include "ForgeOfSoulsTriggers.h" class WotlkDungeonFosTriggerContext : public NamedObjectContext { diff --git a/src/strategy/dungeons/wotlk/forgeofsouls/FosTriggers.cpp b/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsTriggers.cpp similarity index 66% rename from src/strategy/dungeons/wotlk/forgeofsouls/FosTriggers.cpp rename to src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsTriggers.cpp index 33e2a3fd..a5e4c169 100644 --- a/src/strategy/dungeons/wotlk/forgeofsouls/FosTriggers.cpp +++ b/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsTriggers.cpp @@ -1,15 +1,14 @@ -#include "FosTriggers.h" +#include "ForgeOfSoulsTriggers.h" #include "Playerbots.h" #include "AiObject.h" #include "AiObjectContext.h" bool MoveFromBronjahmTrigger::IsActive() { - Unit* boss = nullptr; - boss = AI_VALUE2(Unit*, "find target", "bronjahm"); + Unit* boss = AI_VALUE2(Unit*, "find target", "bronjahm"); if (boss && boss->HasUnitState(UNIT_STATE_CASTING)) { - if (boss->FindCurrentSpellBySpellId(SPELL_CORRUPT_SOUL)) + if (boss->FindCurrentSpellBySpellId(SPELL_CORRUPT_SOUL) && bot->HasAura(SPELL_CORRUPT_SOUL)) return true; } return false; @@ -20,12 +19,13 @@ bool SwitchToSoulFragment::IsActive() Unit* fragment = nullptr; GuidVector targets = AI_VALUE(GuidVector, "possible targets no los"); - for (auto i = targets.begin(); i != targets.end(); ++i) + for (auto& target : targets) { - Unit* unit = botAI->GetUnit(*i); + Unit* unit = botAI->GetUnit(target); if (unit && unit->GetEntry() == NPC_CORRUPTED_SOUL_FRAGMENT) { - return true; + if (botAI->IsDps(bot)) + return true; } } diff --git a/src/strategy/dungeons/wotlk/forgeofsouls/FosTriggers.h b/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsTriggers.h similarity index 100% rename from src/strategy/dungeons/wotlk/forgeofsouls/FosTriggers.h rename to src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsTriggers.h diff --git a/src/strategy/dungeons/wotlk/forgeofsouls/FosActionContext.h b/src/strategy/dungeons/wotlk/forgeofsouls/FosActionContext.h deleted file mode 100644 index 8d8438c2..00000000 --- a/src/strategy/dungeons/wotlk/forgeofsouls/FosActionContext.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef _PLAYERBOT_WOTLKDUNGEONFOSACTIONCONTEXT_H -#define _PLAYERBOT_WOTLKDUNGEONFOSACTIONCONTEXT_H - -#include "Action.h" -#include "NamedObjectContext.h" -#include "FosActions.h" - -class WotlkDungeonFosActionContext : public NamedObjectContext -{ - public: - WotlkDungeonFosActionContext() { - creators["move from bronjahm"] = &WotlkDungeonFosActionContext::move_from_bronjahm; - creators["attack corrupted soul fragment"] = &WotlkDungeonFosActionContext::attack_corrupted_soul_fragment; - creators["bronjahm tank position"] = &WotlkDungeonFosActionContext::bronjahm_tank_position; - creators["bronjahm tank target"] = &WotlkDungeonFosActionContext::bronjahm_tank_target; - creators["bronjahm dps position"] = &WotlkDungeonFosActionContext::bronjahm_dps_position; - } - private: - static Action* move_from_bronjahm(PlayerbotAI* ai) { return new MoveFromBronjahmAction(ai); } - static Action* attack_corrupted_soul_fragment(PlayerbotAI* ai) { return new AttackCorruptedSoulFragmentAction(ai); } - static Action* bronjahm_tank_position(PlayerbotAI* ai) { return new BronjahmTankPositionAction(ai); } - static Action* bronjahm_tank_target(PlayerbotAI* ai) { return new BronjahmTankTargetAction(ai); } - static Action* bronjahm_dps_position(PlayerbotAI* ai) { return new BronjahmDpsPositionAction(ai); } -}; - -#endif From cb281c7ebdf9e094ea42ba3243408c8b55b53dc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A7=9C=E8=80=80?= Date: Wed, 6 Nov 2024 20:02:05 +0800 Subject: [PATCH 18/19] 2024-11-6 correct problems of forge of souls bronjahm strategy 2024-11-6 --- .../forgeofsouls/ForgeOfSoulsActions.cpp | 35 +++++++++++++------ .../wotlk/forgeofsouls/ForgeOfSoulsActions.h | 4 +-- .../forgeofsouls/ForgeOfSoulsMultipliers.cpp | 10 ++---- .../forgeofsouls/ForgeOfSoulsStrategy.cpp | 2 +- .../forgeofsouls/ForgeOfSoulsTriggers.cpp | 2 +- 5 files changed, 32 insertions(+), 21 deletions(-) diff --git a/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsActions.cpp b/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsActions.cpp index 31b477ff..e0e8425f 100644 --- a/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsActions.cpp +++ b/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsActions.cpp @@ -43,25 +43,40 @@ bool AttackCorruptedSoulFragmentAction::Execute(Event event) bool BronjahmGroupPositionAction::Execute(Event event) { + Unit* boss = AI_VALUE2(Unit*, "find target", "bronjahm"); + if (!boss) + return false; + if (botAI->IsTank(bot)) - if (bot->GetExactDist2d(BRONJAHM_TANK_POSITION) > 5.0f) - return MoveTo(bot->GetMapId(), BRONJAHM_TANK_POSITION.GetPositionX(), BRONJAHM_TANK_POSITION.GetPositionY(), - BRONJAHM_TANK_POSITION.GetPositionZ(), false, false, false, true, - MovementPriority::MOVEMENT_COMBAT); + { + bot->SetTarget(boss->GetGUID()); + if (AI_VALUE2(bool, "has aggro", "current target")) + if (bot->GetExactDist2d(BRONJAHM_TANK_POSITION) > 5.0f) + return MoveTo(bot->GetMapId(), BRONJAHM_TANK_POSITION.GetPositionX(), + BRONJAHM_TANK_POSITION.GetPositionY(), BRONJAHM_TANK_POSITION.GetPositionZ(), false, + false, false, true, MovementPriority::MOVEMENT_NORMAL); + else + return Attack(boss); else - return false; + { + return Attack(boss); + } + } else { - Unit* boss = AI_VALUE2(Unit*, "find target", "bronjahm"); - - if (boss) + float maxMovement = 10.0f; + if (bot->getClass() == CLASS_HUNTER) { - + return Move(bot->GetAngle(boss), fmin(bot->GetExactDist2d(boss) - 6.5f, maxMovement)); + } + else + { + return Move(bot->GetAngle(boss), fmin(bot->GetExactDist2d(boss) - 2.0f, maxMovement)); } } } -bool BronjahmGroupPositionAction::isUseful() { return bot->GetExactDist2d(BRONJAHM_TANK_POSITION) > 5.0f; } +bool BronjahmGroupPositionAction::isUseful() { return true; } bool BronjahmTankTargetAction::Execute(Event event) { diff --git a/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsActions.h b/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsActions.h index 227a6fbe..f4a6521d 100644 --- a/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsActions.h +++ b/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsActions.h @@ -23,10 +23,10 @@ public: bool Execute(Event event) override; }; -class BronjahmGroupPositionAction : public MovementAction +class BronjahmGroupPositionAction : public AttackAction { public: - BronjahmGroupPositionAction(PlayerbotAI* ai) : MovementAction(ai, "bronjahm group position") {} + BronjahmGroupPositionAction(PlayerbotAI* ai) : AttackAction(ai, "bronjahm group position") {} bool Execute(Event event) override; diff --git a/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsMultipliers.cpp b/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsMultipliers.cpp index 4e41de27..6eed3c81 100644 --- a/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsMultipliers.cpp +++ b/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsMultipliers.cpp @@ -16,7 +16,8 @@ float BronjahmMultiplier::GetValue(Action* action) { if (dynamic_cast(action)) return 0.0f; - if (boss && boss->HasUnitState(UNIT_STATE_CASTING) && boss->FindCurrentSpellBySpellId(SPELL_CORRUPT_SOUL)) + if (boss && boss->HasUnitState(UNIT_STATE_CASTING) && boss->FindCurrentSpellBySpellId(SPELL_CORRUPT_SOUL) && + bot->HasAura(SPELL_CORRUPT_SOUL)) { if (dynamic_cast(action) && !dynamic_cast(action)) { @@ -28,8 +29,6 @@ float BronjahmMultiplier::GetValue(Action* action) { float AttackFragmentMultiplier::GetValue(Action* action) { - if (botAI->IsHeal(bot) && dynamic_cast(action)) - return 0.0f; Unit* fragment = nullptr; @@ -45,10 +44,7 @@ float AttackFragmentMultiplier::GetValue(Action* action) } } - if (fragment && dynamic_cast(action)) - return 0.0f; - - if (fragment && dynamic_cast(action)) + if (fragment && botAI->IsDps(bot) && dynamic_cast(action)) return 0.0f; return 1.0f; diff --git a/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsStrategy.cpp b/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsStrategy.cpp index 1cc522f8..68b89157 100644 --- a/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsStrategy.cpp +++ b/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsStrategy.cpp @@ -8,7 +8,7 @@ void WotlkDungeonFoSStrategy::InitTriggers(std::vector& triggers) triggers.push_back(new TriggerNode( "switch to soul fragment", NextAction::array(0, new NextAction("attack corrupted soul fragment", ACTION_RAID + 1), nullptr))); triggers.push_back(new TriggerNode("bronjahm position", - NextAction::array(0, new NextAction("bronjahm position", ACTION_RAID + 1), nullptr))); + NextAction::array(0, new NextAction("bronjahm group position", ACTION_RAID + 1), nullptr))); } void WotlkDungeonFoSStrategy::InitMultipliers(std::vector& multipliers) diff --git a/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsTriggers.cpp b/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsTriggers.cpp index a5e4c169..b2bf096b 100644 --- a/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsTriggers.cpp +++ b/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsTriggers.cpp @@ -1,5 +1,5 @@ -#include "ForgeOfSoulsTriggers.h" #include "Playerbots.h" +#include "ForgeOfSoulsTriggers.h" #include "AiObject.h" #include "AiObjectContext.h" From 7af720f12758cb7fbc4dfdd92d44692fb89eee5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A7=9C=E8=80=80?= Date: Wed, 6 Nov 2024 23:05:32 +0800 Subject: [PATCH 19/19] 2024-11-6 correct problems --- .../forgeofsouls/ForgeOfSoulsActions.cpp | 52 ++++--------------- .../wotlk/forgeofsouls/ForgeOfSoulsActions.h | 18 +------ .../forgeofsouls/ForgeOfSoulsMultipliers.cpp | 11 ++-- .../forgeofsouls/ForgeOfSoulsTriggers.cpp | 15 ++---- .../wotlk/forgeofsouls/ForgeOfSoulsTriggers.h | 2 +- 5 files changed, 23 insertions(+), 75 deletions(-) diff --git a/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsActions.cpp b/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsActions.cpp index e0e8425f..0992bd3b 100644 --- a/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsActions.cpp +++ b/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsActions.cpp @@ -65,53 +65,23 @@ bool BronjahmGroupPositionAction::Execute(Event event) else { float maxMovement = 10.0f; - if (bot->getClass() == CLASS_HUNTER) + + if (bot->GetExactDist2d(boss) > maxMovement) { - return Move(bot->GetAngle(boss), fmin(bot->GetExactDist2d(boss) - 6.5f, maxMovement)); + if (bot->getClass() == CLASS_HUNTER) + { + return Move(bot->GetAngle(boss), fmin(bot->GetExactDist2d(boss) - 6.5f, maxMovement)); + } + else + { + return Move(bot->GetAngle(boss), fmin(bot->GetExactDist2d(boss) - 2.0f, maxMovement)); + } } else - { - return Move(bot->GetAngle(boss), fmin(bot->GetExactDist2d(boss) - 2.0f, maxMovement)); - } + return false; } } bool BronjahmGroupPositionAction::isUseful() { return true; } -bool BronjahmTankTargetAction::Execute(Event event) -{ - if (botAI->IsTank(bot)) - { - Unit* boss = AI_VALUE2(Unit*, "find target", "bronjahm"); - if (boss && AI_VALUE(Unit*, "current target") != boss) - return Attack(boss); - else - return false; - } - else - return false; -} -bool BronjahmDpsPositionAction::Execute(Event event) -{ - Unit* boss = AI_VALUE2(Unit*, "find target", "bronjahm"); - if (!boss) - return false; - - if (bot->getClass() == CLASS_HUNTER) - { - return Move(bot->GetAngle(boss), 8.0f); - } - else - { - return Move(bot->GetAngle(boss), 5.0f); - } -} - -bool BronjahmDpsPositionAction::isUseful() -{ - if (bot->GetExactDist2d(BRONJAHM_TANK_POSITION) <= 10.0f) - return false; - - return botAI->IsDps(bot) || botAI->IsHeal(bot); -} diff --git a/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsActions.h b/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsActions.h index f4a6521d..2388fe50 100644 --- a/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsActions.h +++ b/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsActions.h @@ -7,7 +7,7 @@ #include "Playerbots.h" #include "ForgeOfSoulsTriggers.h" -const Position BRONJAHM_TANK_POSITION = Position(5297.9204f, 2506.698f, 686.06793f); +const Position BRONJAHM_TANK_POSITION = Position(5297.920f, 2506.698f, 686.068f); class MoveFromBronjahmAction : public MovementAction { @@ -33,21 +33,5 @@ public: bool isUseful() override; }; -class BronjahmDpsPositionAction : public MovementAction -{ -public: - BronjahmDpsPositionAction(PlayerbotAI* ai) : MovementAction(ai, "bronjahm dps position") {} - - bool Execute(Event event) override; - - bool isUseful() override; -}; - -class BronjahmTankTargetAction : public AttackAction -{ -public: - BronjahmTankTargetAction(PlayerbotAI* ai) : AttackAction(ai, "bronjahm tank target") {} - bool Execute(Event event) override; -}; #endif diff --git a/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsMultipliers.cpp b/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsMultipliers.cpp index 6eed3c81..36f67fb0 100644 --- a/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsMultipliers.cpp +++ b/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsMultipliers.cpp @@ -8,15 +8,14 @@ float BronjahmMultiplier::GetValue(Action* action) { - Unit* boss = nullptr; - boss = AI_VALUE2(Unit *, "find target", "bronjahm"); + Unit* boss = AI_VALUE2(Unit *, "find target", "bronjahm"); if (!boss) return 1.0f; - if (botAI->IsTank(bot)) - if (dynamic_cast(action)) - return 0.0f; - if (boss && boss->HasUnitState(UNIT_STATE_CASTING) && boss->FindCurrentSpellBySpellId(SPELL_CORRUPT_SOUL) && + if (dynamic_cast(action)) + return 0.0f; + + if (boss->FindCurrentSpellBySpellId(SPELL_CORRUPT_SOUL) && bot->HasAura(SPELL_CORRUPT_SOUL)) { if (dynamic_cast(action) && !dynamic_cast(action)) diff --git a/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsTriggers.cpp b/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsTriggers.cpp index b2bf096b..13256d70 100644 --- a/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsTriggers.cpp +++ b/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsTriggers.cpp @@ -6,11 +6,10 @@ bool MoveFromBronjahmTrigger::IsActive() { Unit* boss = AI_VALUE2(Unit*, "find target", "bronjahm"); - if (boss && boss->HasUnitState(UNIT_STATE_CASTING)) - { - if (boss->FindCurrentSpellBySpellId(SPELL_CORRUPT_SOUL) && bot->HasAura(SPELL_CORRUPT_SOUL)) - return true; - } + + if (boss->FindCurrentSpellBySpellId(SPELL_CORRUPT_SOUL) && bot->HasAura(SPELL_CORRUPT_SOUL)) + return true; + return false; } @@ -36,9 +35,5 @@ bool SwitchToSoulFragment::IsActive() bool BronjahmPositionTrigger::IsActive() { - Unit* boss = AI_VALUE2(Unit*, "find target", "bronjahm"); - if (boss) - return true; - - return false; + return bool(AI_VALUE2(Unit*, "find target", "bronjahm")); } diff --git a/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsTriggers.h b/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsTriggers.h index d52c3f37..3ddf8f66 100644 --- a/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsTriggers.h +++ b/src/strategy/dungeons/wotlk/forgeofsouls/ForgeOfSoulsTriggers.h @@ -6,7 +6,7 @@ #include "GenericTriggers.h" #include "DungeonStrategyUtils.h" -enum FosIDs +enum ForgeOfSoulsBronjahmIDs { // Boss1 NPC_CORRUPTED_SOUL_FRAGMENT = 36535,