mirror of
https://github.com/mod-playerbots/mod-playerbots.git
synced 2026-03-15 21:35:09 +00:00
# Pull Request Most of the changes are not functional but are to modify style based on comments received to the TK PR (e.g., eliminate nesting of if statements) and leverage general boss helpers. There is some reordering of returns and other changes to try to consolidate or clean-up the code (such as removing unnecessary parameters). The strategies themselves have only minor changes. - Main tank no longer uses tangential movement for Lurker Spout, unlike other bots. The MT will just call moves directly to a position behind Lurker. This is because I found tangential movement was taking too long for the MT to get in place since it starts right in front of Lurker. - Vashj MT group Shaman will now use Grounding Totem without actually switching to the Grounding Totem strategy. I have now eliminated all strategy swaps, which I dislike because they persist after the encounter, and it's better not to mess with player strategies since presumably people are generally using Windfury or Wrath of Air for the Air Totem. - I made a ton of changes to Vashj core passing as I noticed the existing logic is nonfunctional in several ways. It generally works fine ingame, but the changes should make things much smoother. For example, the storing of the nearest trigger NPC for generators in the existing strategy is useless because it relies on insert_or_assign for an unordered map that will continue to run during the course of the core passing logic, and a similar issue exists with respect to the map to store the last time a bot held a core. The result is that there is slight movement of bots when the core is flying through the air and not held by any bot because the trigger for core passing does not fire during that period. In practice, the time is brief enough that the sequence works OK, but it looks stupid because the bots should not be moving at all. So that should be fixed. There is a known issue re: core passing that would take extreme effort to fix and I am not going to do it because it is a fringe situation. There are a couple of spots where the Tainted Elemental can rarely spawn that can result in a straight-line passing sequence to the nearest generator that is blocked by LoS. Fixing this would be extremely difficult and niche, so what you will need to do if this happens is to just command your bots to destroy the core and try again with the next spawn. --- ## Design Philosophy We prioritize **stability, performance, and predictability** over behavioral realism. Complex player-mimicking logic is intentionally limited due to its negative impact on scalability, maintainability, and long-term robustness. Excessive processing overhead can lead to server hiccups, increased CPU usage, and degraded performance for all participants. Because every action and decision tree is executed **per bot and per trigger**, even small increases in logic complexity can scale poorly and negatively affect both players and world (random) bots. Bots are not expected to behave perfectly, and perfect simulation of human decision-making is not a project goal. Increased behavioral realism often introduces disproportionate cost, reduced predictability, and significantly higher maintenance overhead. Every additional branch of logic increases long-term responsibility. All decision paths must be tested, validated, and maintained continuously as the system evolves. If advanced or AI-intensive behavior is introduced, the **default configuration must remain the lightweight decision model**. More complex behavior should only be available as an **explicit opt-in option**, clearly documented as having a measurable performance cost. Principles: - **Stability before intelligence** A stable system is always preferred over a smarter one. - **Performance is a shared resource** Any increase in bot cost affects all players and all bots. - **Simple logic scales better than smart logic** Predictable behavior under load is more valuable than perfect decisions. - **Complexity must justify itself** If a feature cannot clearly explain its cost, it should not exist. - **Defaults must be cheap** Expensive behavior must always be optional and clearly communicated. - **Bots should look reasonable, not perfect** The goal is believable behavior, not human simulation. Before submitting, confirm that this change aligns with those principles. --- ## Feature Evaluation Please answer the following: - Describe the **minimum logic** required to achieve the intended behavior? - Describe the **cheapest implementation** that produces an acceptable result? - Describe the **runtime cost** when this logic executes across many bots? I have attempted to streamline methods and even remove some. The strategy is admittedly somewhat performance heavy due to the need for function calls such as iterating over inventory items. However, the new version should be less performance intensive than the merged strategy--for example, there were places where all members of the raid would have their inventory checked, but I've now limited the check to only the 5 core handler bots. I've run the instance with pmon on, and there are no methods that stand out as particularly resource intensive when not in a boss encounter, and I view that as the most important thing (though I make effort to reduce performance impact during encounters also). Expensive checks that are unavoidable for the strategy to work such as grid searches are gated behind cheaper checks. --- ## How to Test the Changes - Step-by-step instructions to test the change - Any required setup (e.g. multiple players, bots, specific configuration) - Expected behavior and how to verify it Enter SSC with a raid group and run the instance, including all bosses. Every boss should be killable, and every major mechanic should be addressed by bots. I will work with Dreathean to get the Wiki up soon so that should be a reference for testing strategies. ## Complexity & Impact Does this change add new decision branches? - - [ ] No - - [x] Yes (**explain below**) Only within the context of strategies, which are basically all new decision branches, and there are some tweaks here to what is currently merged. Does this change increase per-bot or per-tick processing? - - [x] No - - [ ] Yes (**describe and justify impact**) Could this logic scale poorly under load? - - [ ] No - - [x] Yes (**explain why**) I'm sure if you have a large server, with multiple raid groups running the instance at the same time, the performance impact could be significant. But I have done my best to limit it, and I think some notable performance impact is unavoidable with the current framework for raid strategies. --- ## Defaults & Configuration Does this change modify default bot behavior? - - [ ] No - - [x] Yes (**explain why**) Only for strategies in the instance. If this introduces more advanced or AI-heavy logic: - - [ ] Lightweight mode remains the default - - [x] More complex behavior is optional and thereby configurable There should be no impact if co +ssc and nc +ssc are not added to bots. Because raid strategies are currently not removed after leaving an instance, players should manually remove them (or reset botAI). This is a general issue that needs to be addressed with the module. --- ## AI Assistance Was AI assistance (e.g. ChatGPT or similar tools) used while working on this change? - - [ ] No - - [x] Yes (**explain below**) If yes, please specify: - AI tool or model used (e.g. ChatGPT, GPT-4, Claude, etc.) - Purpose of usage (e.g. brainstorming, refactoring, documentation, code generation) - Which parts of the change were influenced or generated - Whether the result was manually reviewed and adapted AI assistance is allowed, but all submitted code must be fully understood, reviewed, and owned by the contributor. Any AI-influenced changes must be verified against existing CORE and PB logic. We expect contributors to be honest about what they do and do not understand. GPT-4 because I don't like to use up my premium requests in CoPilot and I generally like it better than GPT-5 =P I use LLMs to draft code snippets but do review everything and have become less-and-less reliant over time. I don't use agent mode, only ask. For this PR, I had it do the updated version of AnyRecentCoreInInventory(), which is more complicated than before and uses indexing for each bot to consider status of only prior bots in the passing chain. Everything else either I wrote or could have written but had the AI help and just edited afterward to save time. --- ## Final Checklist - - [x] Stability is not compromised - - [x] Performance impact is understood, tested, and acceptable - - [x] Added logic complexity is justified and explained - - [x] Documentation updated if needed --- ## Notes for Reviewers Anything that significantly improves realism at the cost of stability or performance should be carefully discussed before merging. --------- Co-authored-by: Keleborn <22352763+Celandriel@users.noreply.github.com> Co-authored-by: bash <hermensb@gmail.com> Co-authored-by: Revision <tkn963@gmail.com> Co-authored-by: kadeshar <kadeshar@gmail.com>
210 lines
12 KiB
C++
210 lines
12 KiB
C++
/*
|
|
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
|
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
|
*/
|
|
|
|
#include "RaidSSCStrategy.h"
|
|
#include "RaidSSCMultipliers.h"
|
|
|
|
void RaidSSCStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
{
|
|
// General
|
|
triggers.push_back(new TriggerNode("serpent shrine cavern bot is not in combat", {
|
|
NextAction("serpent shrine cavern erase timers and trackers", ACTION_EMERGENCY + 11) }));
|
|
|
|
// Trash Mobs
|
|
triggers.push_back(new TriggerNode("underbog colossus spawned toxic pool after death", {
|
|
NextAction("underbog colossus escape toxic pool", ACTION_EMERGENCY + 10) }));
|
|
|
|
triggers.push_back(new TriggerNode("greyheart tidecaller water elemental totem spawned", {
|
|
NextAction("greyheart tidecaller mark water elemental totem", ACTION_RAID + 1) }));
|
|
|
|
// Hydross the Unstable <Duke of Currents>
|
|
triggers.push_back(new TriggerNode("hydross the unstable bot is frost tank", {
|
|
NextAction("hydross the unstable position frost tank", ACTION_RAID + 1) }));
|
|
|
|
triggers.push_back(new TriggerNode("hydross the unstable bot is nature tank", {
|
|
NextAction("hydross the unstable position nature tank", ACTION_RAID + 1) }));
|
|
|
|
triggers.push_back(new TriggerNode("hydross the unstable elementals spawned", {
|
|
NextAction("hydross the unstable prioritize elemental adds", ACTION_RAID + 1) }));
|
|
|
|
triggers.push_back(new TriggerNode("hydross the unstable danger from water tombs", {
|
|
NextAction("hydross the unstable frost phase spread out", ACTION_EMERGENCY + 1) }));
|
|
|
|
triggers.push_back(new TriggerNode("hydross the unstable tank needs aggro upon phase change", {
|
|
NextAction("hydross the unstable misdirect boss to tank", ACTION_EMERGENCY + 6) }));
|
|
|
|
triggers.push_back(new TriggerNode("hydross the unstable aggro resets upon phase change", {
|
|
NextAction("hydross the unstable stop dps upon phase change", ACTION_EMERGENCY + 9) }));
|
|
|
|
triggers.push_back(new TriggerNode("hydross the unstable need to manage timers", {
|
|
NextAction("hydross the unstable manage timers", ACTION_EMERGENCY + 10) }));
|
|
|
|
// The Lurker Below
|
|
triggers.push_back(new TriggerNode("the lurker below spout is active", {
|
|
NextAction("the lurker below run around behind boss", ACTION_EMERGENCY + 6) }));
|
|
|
|
triggers.push_back(new TriggerNode("the lurker below boss is active for main tank", {
|
|
NextAction("the lurker below position main tank", ACTION_RAID + 1) }));
|
|
|
|
triggers.push_back(new TriggerNode("the lurker below boss casts geyser", {
|
|
NextAction("the lurker below spread ranged in arc", ACTION_RAID + 1) }));
|
|
|
|
triggers.push_back(new TriggerNode("the lurker below boss is submerged", {
|
|
NextAction("the lurker below tanks pick up adds", ACTION_EMERGENCY + 1) }));
|
|
|
|
triggers.push_back(new TriggerNode("the lurker below need to prepare timer for spout", {
|
|
NextAction("the lurker below manage spout timer", ACTION_EMERGENCY + 10) }));
|
|
|
|
// Leotheras the Blind
|
|
triggers.push_back(new TriggerNode("leotheras the blind boss is inactive", {
|
|
NextAction("leotheras the blind target spellbinders", ACTION_RAID + 1) }));
|
|
|
|
triggers.push_back(new TriggerNode("leotheras the blind boss transformed into demon form", {
|
|
NextAction("leotheras the blind demon form tank attack boss", ACTION_RAID + 1) }));
|
|
|
|
triggers.push_back(new TriggerNode("leotheras the blind only warlock should tank demon form", {
|
|
NextAction("leotheras the blind melee tanks don't attack demon form", ACTION_RAID + 1) }));
|
|
|
|
triggers.push_back(new TriggerNode("leotheras the blind boss engaged by ranged", {
|
|
NextAction("leotheras the blind position ranged", ACTION_RAID + 1) }));
|
|
|
|
triggers.push_back(new TriggerNode("leotheras the blind boss channeling whirlwind", {
|
|
NextAction("leotheras the blind run away from whirlwind", ACTION_EMERGENCY + 1) }));
|
|
|
|
triggers.push_back(new TriggerNode("leotheras the blind bot has too many chaos blast stacks", {
|
|
NextAction("leotheras the blind melee dps run away from boss", ACTION_EMERGENCY + 6) }));
|
|
|
|
triggers.push_back(new TriggerNode("leotheras the blind inner demon has awakened", {
|
|
NextAction("leotheras the blind destroy inner demon", ACTION_EMERGENCY + 7) }));
|
|
|
|
triggers.push_back(new TriggerNode("leotheras the blind entered final phase", {
|
|
NextAction("leotheras the blind final phase assign dps priority", ACTION_RAID + 1) }));
|
|
|
|
triggers.push_back(new TriggerNode("leotheras the blind demon form tank needs aggro", {
|
|
NextAction("leotheras the blind misdirect boss to demon form tank", ACTION_RAID + 2) }));
|
|
|
|
triggers.push_back(new TriggerNode("leotheras the blind boss wipes aggro upon phase change", {
|
|
NextAction("leotheras the blind manage dps wait timers", ACTION_EMERGENCY + 10) }));
|
|
|
|
// Fathom-Lord Karathress
|
|
triggers.push_back(new TriggerNode("fathom-lord karathress boss engaged by main tank", {
|
|
NextAction("fathom-lord karathress main tank position boss", ACTION_RAID + 1) }));
|
|
|
|
triggers.push_back(new TriggerNode("fathom-lord karathress caribdis engaged by first assist tank", {
|
|
NextAction("fathom-lord karathress first assist tank position caribdis", ACTION_RAID + 1) }));
|
|
|
|
triggers.push_back(new TriggerNode("fathom-lord karathress sharkkis engaged by second assist tank", {
|
|
NextAction("fathom-lord karathress second assist tank position sharkkis", ACTION_RAID + 1) }));
|
|
|
|
triggers.push_back(new TriggerNode("fathom-lord karathress tidalvess engaged by third assist tank", {
|
|
NextAction("fathom-lord karathress third assist tank position tidalvess", ACTION_RAID + 1) }));
|
|
|
|
triggers.push_back(new TriggerNode("fathom-lord karathress caribdis tank needs dedicated healer", {
|
|
NextAction("fathom-lord karathress position caribdis tank healer", ACTION_RAID + 1) }));
|
|
|
|
triggers.push_back(new TriggerNode("fathom-lord karathress pulling bosses", {
|
|
NextAction("fathom-lord karathress misdirect bosses to tanks", ACTION_RAID + 2) }));
|
|
|
|
triggers.push_back(new TriggerNode("fathom-lord karathress determining kill order", {
|
|
NextAction("fathom-lord karathress assign dps priority", ACTION_RAID + 1) }));
|
|
|
|
triggers.push_back(new TriggerNode("fathom-lord karathress tanks need to establish aggro", {
|
|
NextAction("fathom-lord karathress manage dps timer", ACTION_EMERGENCY + 10) }));
|
|
|
|
// Morogrim Tidewalker
|
|
triggers.push_back(new TriggerNode("morogrim tidewalker boss engaged by main tank", {
|
|
NextAction("morogrim tidewalker move boss to tank position", ACTION_RAID + 1) }));
|
|
|
|
triggers.push_back(new TriggerNode("morogrim tidewalker water globules are incoming", {
|
|
NextAction("morogrim tidewalker phase 2 reposition ranged", ACTION_RAID + 1) }));
|
|
|
|
triggers.push_back(new TriggerNode("morogrim tidewalker pulling boss", {
|
|
NextAction("morogrim tidewalker misdirect boss to main tank", ACTION_RAID + 1) }));
|
|
|
|
// Lady Vashj <Coilfang Matron>
|
|
triggers.push_back(new TriggerNode("lady vashj boss engaged by main tank", {
|
|
NextAction("lady vashj main tank position boss", ACTION_RAID + 1) }));
|
|
|
|
triggers.push_back(new TriggerNode("lady vashj boss engaged by ranged in phase 1", {
|
|
NextAction("lady vashj phase 1 spread ranged in arc", ACTION_RAID + 1) }));
|
|
|
|
triggers.push_back(new TriggerNode("lady vashj casts shock blast on highest aggro", {
|
|
NextAction("lady vashj set grounding totem in main tank group", ACTION_EMERGENCY + 1) }));
|
|
|
|
triggers.push_back(new TriggerNode("lady vashj bot has static charge", {
|
|
NextAction("lady vashj static charge move away from group", ACTION_EMERGENCY + 7) }));
|
|
|
|
triggers.push_back(new TriggerNode("lady vashj pulling boss in phase 1 and phase 3", {
|
|
NextAction("lady vashj misdirect boss to main tank", ACTION_RAID + 2) }));
|
|
|
|
triggers.push_back(new TriggerNode("lady vashj tainted elemental cheat", {
|
|
NextAction("lady vashj teleport to tainted elemental", ACTION_EMERGENCY + 10),
|
|
NextAction("lady vashj loot tainted core", ACTION_EMERGENCY + 10) }));
|
|
|
|
triggers.push_back(new TriggerNode("lady vashj tainted core was looted", {
|
|
NextAction("lady vashj pass the tainted core", ACTION_EMERGENCY + 10) }));
|
|
|
|
triggers.push_back(new TriggerNode("lady vashj tainted core is unusable", {
|
|
NextAction("lady vashj destroy tainted core", ACTION_EMERGENCY + 1) }));
|
|
|
|
triggers.push_back(new TriggerNode("lady vashj adds spawn in phase 2 and phase 3", {
|
|
NextAction("lady vashj assign phase 2 and phase 3 dps priority", ACTION_RAID + 1) }));
|
|
|
|
triggers.push_back(new TriggerNode("lady vashj coilfang strider is approaching", {
|
|
NextAction("lady vashj misdirect strider to first assist tank", ACTION_EMERGENCY + 2),
|
|
NextAction("lady vashj tank attack and move away strider", ACTION_EMERGENCY + 1) }));
|
|
|
|
triggers.push_back(new TriggerNode("lady vashj toxic sporebats are spewing poison clouds", {
|
|
NextAction("lady vashj avoid toxic spores", ACTION_EMERGENCY + 6) }));
|
|
|
|
triggers.push_back(new TriggerNode("lady vashj bot is entangled in toxic spores or static charge", {
|
|
NextAction("lady vashj use free action abilities", ACTION_EMERGENCY + 7) }));
|
|
}
|
|
|
|
void RaidSSCStrategy::InitMultipliers(std::vector<Multiplier*>& multipliers)
|
|
{
|
|
// Trash Mobs
|
|
multipliers.push_back(new UnderbogColossusEscapeToxicPoolMultiplier(botAI));
|
|
|
|
// Hydross the Unstable <Duke of Currents>
|
|
multipliers.push_back(new HydrossTheUnstableDisableTankActionsMultiplier(botAI));
|
|
multipliers.push_back(new HydrossTheUnstableWaitForDpsMultiplier(botAI));
|
|
multipliers.push_back(new HydrossTheUnstableControlMisdirectionMultiplier(botAI));
|
|
|
|
// The Lurker Below
|
|
multipliers.push_back(new TheLurkerBelowStayAwayFromSpoutMultiplier(botAI));
|
|
multipliers.push_back(new TheLurkerBelowMaintainRangedSpreadMultiplier(botAI));
|
|
multipliers.push_back(new TheLurkerBelowDisableTankAssistMultiplier(botAI));
|
|
|
|
// Leotheras the Blind
|
|
multipliers.push_back(new LeotherasTheBlindAvoidWhirlwindMultiplier(botAI));
|
|
multipliers.push_back(new LeotherasTheBlindDisableTankActionsMultiplier(botAI));
|
|
multipliers.push_back(new LeotherasTheBlindMeleeDpsAvoidChaosBlastMultiplier(botAI));
|
|
multipliers.push_back(new LeotherasTheBlindFocusOnInnerDemonMultiplier(botAI));
|
|
multipliers.push_back(new LeotherasTheBlindWaitForDpsMultiplier(botAI));
|
|
multipliers.push_back(new LeotherasTheBlindDelayBloodlustAndHeroismMultiplier(botAI));
|
|
|
|
// Fathom-Lord Karathress
|
|
multipliers.push_back(new FathomLordKarathressDisableTankActionsMultiplier(botAI));
|
|
multipliers.push_back(new FathomLordKarathressDisableAoeMultiplier(botAI));
|
|
multipliers.push_back(new FathomLordKarathressControlMisdirectionMultiplier(botAI));
|
|
multipliers.push_back(new FathomLordKarathressWaitForDpsMultiplier(botAI));
|
|
multipliers.push_back(new FathomLordKarathressCaribdisTankHealerMaintainPositionMultiplier(botAI));
|
|
|
|
// Morogrim Tidewalker
|
|
multipliers.push_back(new MorogrimTidewalkerDelayBloodlustAndHeroismMultiplier(botAI));
|
|
multipliers.push_back(new MorogrimTidewalkerDisableTankActionsMultiplier(botAI));
|
|
multipliers.push_back(new MorogrimTidewalkerMaintainPhase2StackingMultiplier(botAI));
|
|
|
|
// Lady Vashj <Coilfang Matron>
|
|
multipliers.push_back(new LadyVashjDelayCooldownsMultiplier(botAI));
|
|
multipliers.push_back(new LadyVashjMainTankGroupShamanUseGroundingTotemMultiplier(botAI));
|
|
multipliers.push_back(new LadyVashjMaintainPhase1RangedSpreadMultiplier(botAI));
|
|
multipliers.push_back(new LadyVashjStaticChargeStayAwayFromGroupMultiplier(botAI));
|
|
multipliers.push_back(new LadyVashjDoNotLootTheTaintedCoreMultiplier(botAI));
|
|
multipliers.push_back(new LadyVashjCorePassersPrioritizePositioningMultiplier(botAI));
|
|
multipliers.push_back(new LadyVashjDisableAutomaticTargetingAndMovementModifier(botAI));
|
|
}
|