mirror of
https://github.com/mod-playerbots/mod-playerbots.git
synced 2026-01-13 00:58:33 +00:00
Karazhan Refactor + Nightbane Strategy (#1847)
This PR completely refactors the Karazhan raid strategies to clean up the code and polish up/introduce new strategies, including for Nightbane. General changes with respect to the code: - Moved gating checks for action methods to triggers instead of relying on isUseful functions - Got rid of the nonsensical helper class I made and switched to a helper namespace - Broke up some longer action classes into separate methods and/or private members - Deleted/consolidated some excess code - Made greater use of early returns - Renamed methods, multipliers, and triggers to make them easier to understand - Generally made edits to conform with AC code standards Below are the implemented strategies. I’m including all of them, not just new/modified ones, because I don’t think the first set of strategies was ever tested. So each boss could probably use complete testing. ### **Trash** I added strategies for a trash mob that I find particularly annoying: - Mana Warp: These are, IMO, the most annoying trash mobs in Karazhan. They blow up when low on health, and having two blow up in quick succession is enough to take out a decent chunk of your raid. The strategy directs bots to use pretty much every stun in the book on Mana Warps when they’re low on HP, which is the only way to prevent the explosion. ### **Attumen** - During the first phase, bots will focus on Midnight (taking either Midnight or Attumen to 25% starts the next phase). When Attumen spawns, the assist tank will pick him up and move him away so that bots don’t get cleaved. - When Attumen mounts Midnight, starting phase 2, threat is wiped, and bots will pause DPS for a few seconds to allow the main tank to get aggro. All bots, other than the main tank and any bot that pulls aggro, will stack behind Attumen (~6 yards for ranged so Hunters can still attack). ### **Moroes** - As before, bots will mark and prioritize adds and the boss in the recommended kill order: Dorothea, Catriona, Keira, Rafe, Robin, Crispin, and Moroes. In practice, the enemies will probably be stacked up, and the bots will AoE them down in accordance with their typical AoE strategies, but classes without AoE capabilities should still prioritize the skull. - Based on testing feedback, added a method for the main tank to prioritize Moroes ### **Maiden of Virtue** I’ve made only minor changes to Revision’s original strategy here. - The tank with aggro will position Maiden in the middle of the room and move her to a healer when Repentance is cast so that the Holy Ground will break the healer’s stun. - Ranged bots have assigned positions between the columns around the middle of the room (to prevent chain damage from Holy Wrath). ### **The Big Bad Wolf** - The tank with aggro brings the boss to the front left of the stage. - If a bot gets turned into Little Red Riding Hood, it will run around the stage in a counter-clockwise rectangle until the transformation fades. I tweaked this strategy a bit; it's still not perfect, but it works better than before. ### **Romulo and Julianne** There are no substantive changes to this strategy. As before, in phase 3, when both bosses are active, the bots switch back-and-forth between the bosses by alternating the skull icon based on which boss has lower HP (10% differential). ### **The Wizard of Oz** There are no substantive changes to this strategy. As before, bots mark the bosses with a skull icon in their recommended kill order: Dorothee, Tito (assuming he spawns before you kill Dorothee), Roar, Strawman, Tinhead, and the Crone. Additionally, Mages will spam Scorch on Strawman to daze him. ### **The Curator** - The tank will drag the boss to a fixed spot down the hallway. Ranged bots will spread out to avoid chain damage from Arcing Sear, and bots will mark Astral Flares with the skull icon to prioritize them down. - Those strategies already existed, but now I made the assist tank also focus on the boss to try to stay second in aggro and therefore absorb Hateful Bolts. - Added a multiplier to save Bloodlust/Heroism until Evocation. ### **Terestian Illhoof** There are no substantive changes to this strategy. The bots will mark targets with the skull icon in the following order: Demonic Chains, Kil'rek, and Illhoof. ### **Shade of Aran** I redid the strategies a bit, and I think (hope) they work better. - Flame Wreath: Bots will stop moving until the aura fades. There is a bug in which Flame Wreath will sometimes persist long beyond its supposed 20-second duration. If Aran casts Arcane Explosion during this time, you will almost certainly wipe, so that’s frustrating. I made it so that bots will stay in place still and eat the Arcane Explosion because it’s the lesser of two evils, and if you are overgeared, you may be able to survive. In the previous strategy, bots would stop actions entirely, but now they should keep attacking/casting without moving. - Arcane Explosion: No substantive changes here--bots will run out immediately and stay out of range until the cast finishes. - Conjured Elementals: No substantive changes here--they will be marked one-by-one by the skull icon, except that the marking will skip any elemental that is banished. - Ranged Positioning: I redid this strategy. Ranged bots will now maintain a distance between 11 and 15 yards from the boss. This keeps them out of the 10-yard radius in which Aran silences while also keeping them from getting too far away and getting stuck in the alcoves. ### **Netherspite** I significantly refactored the action methods here, but substantively the original strategy remains mostly intact. - Red (Tank) Beam: One tank will be assigned to block the beam for each Portal Phase. The assigned tank will dance in and out of the beam (5 seconds in, 5 seconds out). Tanks intentionally do not avoid Void Zones (it was the lesser of two evils for them to take that damage vs. trying to dynamically avoid them, moving the boss, and possibly getting everybody out of position. - Blue (DPS) Beam: DPS other than Rogues and Warriors are eligible to be assigned (one-by-one) to block this beam. When the assigned blocker reaches 25 stacks of the debuff, they will leave the beam, and the next assigned blocker will take their place. If a Void Zone drops under the assigned blocker, the bot will move along the beam to get out of the Void Zone so that they do not stop blocking. - Green (Healer) Beam: This works the same way as the Blue Beam, except that eligible blockers are healers, Rogues, and DPS Warriors. Healers that are assigned to block will swap in the same way as Blue Beam blockers. If a Rogue or DPS Warrior is the assigned blocker, however, they will stand in the beam for the entire Portal Phase since they do not suffer any adverse effects from the beam. In this PR, I made the strategy prioritize Rogues and DPS Warriors over healers to try to avoid the need for bots to swap (and to avoid the irritating scenario in which a healer would block the beam for the first half of a phase and then tag in a Rogue or DPS Warrior, which would be wasted by blocking only half of a phase). - Non-Blockers: They will stay at least 5 yards away from each beam until called to be an assigned blocker. They will also avoid Void Zones. - Banish Phase: The only strategy I implemented was for bots to avoid residual Void Zones from the Portal Phase. - Phase Transitions: Bots should pause DPS at the beginning of the encounter and whenever Netherspite transitions back from the Banish Phase to the Portal Phase (which is an aggro reset). Note that this doesn't wipe DOTs, and there's not much I can do about that. ### **Prince Malchezaar** The action methods are significantly refactored, but the strategy substantively is not changed very much. - Bots will maintain distance from Infernals. The tank has a larger avoidance radius to give DPS a little bit of margin to work with. Depending on Infernal placement, it is possible for bots to get stuck in some bad positions. In that case, the best solution is to put them on “flee” and lead them to a better position. - Bots that get Enfeebled will run out of Shadow Nova range. They should pick a path that does not cross within any Infernal's Hellfire radius. - Added a multiplier to save Bloodlust/Heroism until Phase 3. ### **Nightbane** **Disclaimer**: Bots are terrible at this encounter, in large part because the map is awful (even before the recent Core changes). So the strategies are not ideal because they need to operate within the bots’ limitations. I STRONGLY suggest you clear the entire Livery Stables (including the upper level) because the mobs in them have a high risk of pulling through the floor of the Master’s Terrace. Ideally, you should clear out the Scullery too. The strategy uses waypoints toward the Northeastern door to the Master’s Terrace. I tried several different locations, and that worked best for me based on where Nightbane lands (note that he has a different landing spot for the encounter start vs. the start subsequent ground phases). - Ground Phase, main tank: The main tank uses two waypoints after it picks up the boss—the movement pattern should be kind of like a reverse checkmark, where the tank moves back along the inner edge of the terrace, then pivots and moves at a bit of an angle to the outer edge. I did this as a way to get the tank to face Nightbane sideways across the terrace, which is how he’s supposed to be tanked. The main tank will not get out of Charred Earth. This is intended. The tank cannot move dynamically enough to avoid it while also not turning the boss and wiping the raid. - Ground phase, ranged: Ranged bots rotate between three waypoints. They start stacked at the same position. If Charred Earth is dropped on that position, the bots will rotate to the second position. If Charred Earth is dropped on that position, they will rotate to the third position. The maximum number of Charred Earths that can be active is two, so if one is dropped on the third position, the ranged bots should rotate back to the first position. - Ground Phase, other melee: Melee bots have no coded Charred Earth avoidance strategy. They do decently enough with the general “avoid aoe” strategy. - Flight Phase: Bots move to Nightbane’s flight position—Nightbane is bugged and cannot be attacked in the air in AC, but all bots still need to stay near him or he will wipe the raid with Fireball Barrage. Bots stack on the same position; when Rain of Bones is cast (one time, snapshotted on the target’s location), all bots will move away to a second nearby position. They will then kill the Restless Skeletons. The Flight Phase lasts for 45 seconds, but Nightbane emotes after 35 seconds and goes to land—during the final 10-second period, bots are freed from all strategies and will follow the master. You need to lead them back to the Northeastern part of the terrace before Nightbane lands so that bots can get immediately positioned when he lands. - Phase Changes: Whenever Nightbane lands, bots should pause DPS for the main tank to get aggro. - Managing bots/pets: During the Flight Phase, bots and pets have a tendency to chase Nightbane outside of the boundaries of the map and pull mobs from other parts of the instance as well as cause Restless Skeletons to spawn out of bounds (and then further cause bots/pets to go out of bounds to attack the skeletons). The strategy should solve for this, but if there are still issues, it should be noted. My resolution was to implement the following: (1) when Nightbane takes flight, bots stop attacking and mark him with the moon icon, and Hunters and Warlocks put pets on passive and recall them (they will put pets on defensive again when Nightbane lands), and (2) all temporary pets are disabled for the duration of the fight (Water Elementals, Shaman wolves, Druid treants, etc.). **Known Issues:** - The approach to getting Nightbane to turn sideways is not always spot on since it’s a workaround to account for what should be dynamic movement. He can end up at a bit of an angle. I’ve tweaked the positions such that if he is at an angle, it should not be a situation in which any ranged position is exposed to Smoldering Breath or Cleave. That does increase the risk that poor positioning may expose a ranged position to Tail Sweep. This is obviously suboptimal, but that attack is much more survivable. - Ranged bots move between the three waypoints by reading the presence of the Charred Earth aura on themselves. Sometimes, a bot may reach the next waypoint with the Charred Earth aura from the previous waypoint still on them (depending on timing of ticks), in which case the bot will keep moving to the next waypoint. This can cause an issue in which the ranged group gets split. So you could have Charred Earth dropped on position 1, and some ranged bots will go to position 2 but others will go to position 3, and then if the second Charred Earth is dropped on position 3, the bots at position 3 will move back to position 1 (which is still in Charred Earth) before then moving to position 2. Balancing spacing between waypoints, positioning with respect to the boss, line of sight, and maximum distance is very difficult to do. I messed with the positioning a lot, and I am not sure if this possibility cannot be entirely avoided without creating other issues. I have at least reached a result in which I have not seen any bots cycle indefinitely (though if testing observes this, it is obviously a problem). Ultimately, I wouldn’t say I’m totally satisfied with the strategy. Wipes are still possible on account of bad RNG. But I think it does make the fight a lot more manageable, as it is a fight that is very difficult with IP nerfs in the absence of any strategy. Previously, I needed to bring 3 healers, and they would still all be out of mana by the first Flight Phase and reliant on MP5 for the remainder of the fight, and I would wipe multiple times before a kill.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
#ifndef _PLAYERBOT_RAIDKARAZHANACTIONS_CONTEXT_H
|
||||
#define _PLAYERBOT_RAIDKARAZHANACTIONS_CONTEXT_H
|
||||
#ifndef _PLAYERBOT_RAIDKARAZHANACTIONCONTEXT_H
|
||||
#define _PLAYERBOT_RAIDKARAZHANACTIONCONTEXT_H
|
||||
|
||||
#include "RaidKarazhanActions.h"
|
||||
#include "NamedObjectContext.h"
|
||||
@@ -9,77 +9,254 @@ class RaidKarazhanActionContext : public NamedObjectContext<Action>
|
||||
public:
|
||||
RaidKarazhanActionContext()
|
||||
{
|
||||
creators["karazhan attumen the huntsman stack behind"] = &RaidKarazhanActionContext::karazhan_attumen_the_huntsman_stack_behind;
|
||||
// Trash
|
||||
creators["mana warp stun creature before warp breach"] =
|
||||
&RaidKarazhanActionContext::mana_warp_stun_creature_before_warp_breach;
|
||||
|
||||
creators["karazhan moroes mark target"] = &RaidKarazhanActionContext::karazhan_moroes_mark_target;
|
||||
// Attumen the Huntsman
|
||||
creators["attumen the huntsman mark target"] =
|
||||
&RaidKarazhanActionContext::attumen_the_huntsman_mark_target;
|
||||
|
||||
creators["karazhan maiden of virtue position boss"] = &RaidKarazhanActionContext::karazhan_maiden_of_virtue_position_boss;
|
||||
creators["karazhan maiden of virtue position ranged"] = &RaidKarazhanActionContext::karazhan_maiden_of_virtue_position_ranged;
|
||||
creators["attumen the huntsman split bosses"] =
|
||||
&RaidKarazhanActionContext::attumen_the_huntsman_split_bosses;
|
||||
|
||||
creators["karazhan big bad wolf position boss"] = &RaidKarazhanActionContext::karazhan_big_bad_wolf_position_boss;
|
||||
creators["karazhan big bad wolf run away"] = &RaidKarazhanActionContext::karazhan_big_bad_wolf_run_away;
|
||||
creators["attumen the huntsman stack behind"] =
|
||||
&RaidKarazhanActionContext::attumen_the_huntsman_stack_behind;
|
||||
|
||||
creators["karazhan romulo and julianne mark target"] = &RaidKarazhanActionContext::karazhan_romulo_and_julianne_mark_target;
|
||||
creators["attumen the huntsman manage dps timer"] =
|
||||
&RaidKarazhanActionContext::attumen_the_huntsman_manage_dps_timer;
|
||||
|
||||
creators["karazhan wizard of oz mark target"] = &RaidKarazhanActionContext::karazhan_wizard_of_oz_mark_target;
|
||||
creators["karazhan wizard of oz scorch strawman"] = &RaidKarazhanActionContext::karazhan_wizard_of_oz_scorch_strawman;
|
||||
// Moroes
|
||||
creators["moroes main tank attack boss"] =
|
||||
&RaidKarazhanActionContext::moroes_main_tank_attack_boss;
|
||||
|
||||
creators["karazhan the curator mark target"] = &RaidKarazhanActionContext::karazhan_the_curator_mark_target;
|
||||
creators["karazhan the curator position boss"] = &RaidKarazhanActionContext::karazhan_the_curator_position_boss;
|
||||
creators["karazhan the curator spread ranged"] = &RaidKarazhanActionContext::karazhan_the_curator_spread_ranged;
|
||||
creators["moroes mark target"] =
|
||||
&RaidKarazhanActionContext::moroes_mark_target;
|
||||
|
||||
creators["karazhan terestian illhoof mark target"] = &RaidKarazhanActionContext::karazhan_terestian_illhoof_mark_target;
|
||||
// Maiden of Virtue
|
||||
creators["maiden of virtue move boss to healer"] =
|
||||
&RaidKarazhanActionContext::maiden_of_virtue_move_boss_to_healer;
|
||||
|
||||
creators["karazhan shade of aran arcane explosion run away"] = &RaidKarazhanActionContext::karazhan_shade_of_aran_arcane_explosion_run_away;
|
||||
creators["karazhan shade of aran flame wreath stop movement"] = &RaidKarazhanActionContext::karazhan_shade_of_aran_flame_wreath_stop_movement;
|
||||
creators["karazhan shade of aran mark conjured elemental"] = &RaidKarazhanActionContext::karazhan_shade_of_aran_mark_conjured_elemental;
|
||||
creators["karazhan shade of aran spread ranged"] = &RaidKarazhanActionContext::karazhan_shade_of_aran_spread_ranged;
|
||||
creators["maiden of virtue position ranged"] =
|
||||
&RaidKarazhanActionContext::maiden_of_virtue_position_ranged;
|
||||
|
||||
creators["karazhan netherspite block red beam"] = &RaidKarazhanActionContext::karazhan_netherspite_block_red_beam;
|
||||
creators["karazhan netherspite block blue beam"] = &RaidKarazhanActionContext::karazhan_netherspite_block_blue_beam;
|
||||
creators["karazhan netherspite block green beam"] = &RaidKarazhanActionContext::karazhan_netherspite_block_green_beam;
|
||||
creators["karazhan netherspite avoid beam and void zone"] = &RaidKarazhanActionContext::karazhan_netherspite_avoid_beam_and_void_zone;
|
||||
creators["karazhan netherspite banish phase avoid void zone"] = &RaidKarazhanActionContext::karazhan_netherspite_banish_phase_avoid_void_zone;
|
||||
// The Big Bad Wolf
|
||||
creators["big bad wolf position boss"] =
|
||||
&RaidKarazhanActionContext::big_bad_wolf_position_boss;
|
||||
|
||||
creators["karazhan prince malchezaar non tank avoid hazard"] = &RaidKarazhanActionContext::karazhan_prince_malchezaar_non_tank_avoid_hazard;
|
||||
creators["karazhan prince malchezaar tank avoid hazard"] = &RaidKarazhanActionContext::karazhan_prince_malchezaar_tank_avoid_hazard;
|
||||
creators["big bad wolf run away from boss"] =
|
||||
&RaidKarazhanActionContext::big_bad_wolf_run_away_from_boss;
|
||||
|
||||
// Romulo and Julianne
|
||||
creators["romulo and julianne mark target"] =
|
||||
&RaidKarazhanActionContext::romulo_and_julianne_mark_target;
|
||||
|
||||
// The Wizard of Oz
|
||||
creators["wizard of oz mark target"] =
|
||||
&RaidKarazhanActionContext::wizard_of_oz_mark_target;
|
||||
creators["wizard of oz scorch strawman"] =
|
||||
&RaidKarazhanActionContext::wizard_of_oz_scorch_strawman;
|
||||
|
||||
// The Curator
|
||||
creators["the curator mark astral flare"] =
|
||||
&RaidKarazhanActionContext::the_curator_mark_astral_flare;
|
||||
|
||||
creators["the curator position boss"] =
|
||||
&RaidKarazhanActionContext::the_curator_position_boss;
|
||||
|
||||
creators["the curator spread ranged"] =
|
||||
&RaidKarazhanActionContext::the_curator_spread_ranged;
|
||||
|
||||
// Terestian Illhoof
|
||||
creators["terestian illhoof mark target"] =
|
||||
&RaidKarazhanActionContext::terestian_illhoof_mark_target;
|
||||
|
||||
// Shade of Aran
|
||||
creators["shade of aran run away from arcane explosion"] =
|
||||
&RaidKarazhanActionContext::shade_of_aran_run_away_from_arcane_explosion;
|
||||
|
||||
creators["shade of aran stop moving during flame wreath"] =
|
||||
&RaidKarazhanActionContext::shade_of_aran_stop_moving_during_flame_wreath;
|
||||
|
||||
creators["shade of aran mark conjured elemental"] =
|
||||
&RaidKarazhanActionContext::shade_of_aran_mark_conjured_elemental;
|
||||
|
||||
creators["shade of aran ranged maintain distance"] =
|
||||
&RaidKarazhanActionContext::shade_of_aran_ranged_maintain_distance;
|
||||
|
||||
// Netherspite
|
||||
creators["netherspite block red beam"] =
|
||||
&RaidKarazhanActionContext::netherspite_block_red_beam;
|
||||
|
||||
creators["netherspite block blue beam"] =
|
||||
&RaidKarazhanActionContext::netherspite_block_blue_beam;
|
||||
|
||||
creators["netherspite block green beam"] =
|
||||
&RaidKarazhanActionContext::netherspite_block_green_beam;
|
||||
|
||||
creators["netherspite avoid beam and void zone"] =
|
||||
&RaidKarazhanActionContext::netherspite_avoid_beam_and_void_zone;
|
||||
|
||||
creators["netherspite banish phase avoid void zone"] =
|
||||
&RaidKarazhanActionContext::netherspite_banish_phase_avoid_void_zone;
|
||||
|
||||
creators["netherspite manage timers and trackers"] =
|
||||
&RaidKarazhanActionContext::netherspite_manage_timers_and_trackers;
|
||||
|
||||
// Prince Malchezaar
|
||||
creators["prince malchezaar enfeebled avoid hazard"] =
|
||||
&RaidKarazhanActionContext::prince_malchezaar_enfeebled_avoid_hazard;
|
||||
|
||||
creators["prince malchezaar non tank avoid infernal"] =
|
||||
&RaidKarazhanActionContext::prince_malchezaar_non_tank_avoid_infernal;
|
||||
|
||||
creators["prince malchezaar main tank movement"] =
|
||||
&RaidKarazhanActionContext::prince_malchezaar_main_tank_movement;
|
||||
|
||||
// Nightbane
|
||||
creators["nightbane ground phase position boss"] =
|
||||
&RaidKarazhanActionContext::nightbane_ground_phase_position_boss;
|
||||
|
||||
creators["nightbane ground phase rotate ranged positions"] =
|
||||
&RaidKarazhanActionContext::nightbane_ground_phase_rotate_ranged_positions;
|
||||
|
||||
creators["nightbane cast fear ward on main tank"] =
|
||||
&RaidKarazhanActionContext::nightbane_cast_fear_ward_on_main_tank;
|
||||
|
||||
creators["nightbane control pet aggression"] =
|
||||
&RaidKarazhanActionContext::nightbane_control_pet_aggression;
|
||||
|
||||
creators["nightbane flight phase movement"] =
|
||||
&RaidKarazhanActionContext::nightbane_flight_phase_movement;
|
||||
|
||||
creators["nightbane manage timers and trackers"] =
|
||||
&RaidKarazhanActionContext::nightbane_manage_timers_and_trackers;
|
||||
}
|
||||
|
||||
private:
|
||||
static Action* karazhan_attumen_the_huntsman_stack_behind(PlayerbotAI* botAI) { return new KarazhanAttumenTheHuntsmanStackBehindAction(botAI); }
|
||||
// Trash
|
||||
static Action* mana_warp_stun_creature_before_warp_breach(
|
||||
PlayerbotAI* botAI) { return new ManaWarpStunCreatureBeforeWarpBreachAction(botAI); }
|
||||
|
||||
static Action* karazhan_moroes_mark_target(PlayerbotAI* botAI) { return new KarazhanMoroesMarkTargetAction(botAI); }
|
||||
// Attumen the Huntsman
|
||||
static Action* attumen_the_huntsman_mark_target(
|
||||
PlayerbotAI* botAI) { return new AttumenTheHuntsmanMarkTargetAction(botAI); }
|
||||
|
||||
static Action* karazhan_maiden_of_virtue_position_boss(PlayerbotAI* botAI) { return new KarazhanMaidenOfVirtuePositionBossAction(botAI); }
|
||||
static Action* karazhan_maiden_of_virtue_position_ranged(PlayerbotAI* botAI) { return new KarazhanMaidenOfVirtuePositionRangedAction(botAI); }
|
||||
static Action* attumen_the_huntsman_split_bosses(
|
||||
PlayerbotAI* botAI) { return new AttumenTheHuntsmanSplitBossesAction(botAI); }
|
||||
|
||||
static Action* karazhan_big_bad_wolf_position_boss(PlayerbotAI* botAI) { return new KarazhanBigBadWolfPositionBossAction(botAI); }
|
||||
static Action* karazhan_big_bad_wolf_run_away(PlayerbotAI* botAI) { return new KarazhanBigBadWolfRunAwayAction(botAI); }
|
||||
static Action* attumen_the_huntsman_stack_behind(
|
||||
PlayerbotAI* botAI) { return new AttumenTheHuntsmanStackBehindAction(botAI); }
|
||||
|
||||
static Action* karazhan_romulo_and_julianne_mark_target(PlayerbotAI* botAI) { return new KarazhanRomuloAndJulianneMarkTargetAction(botAI); }
|
||||
static Action* attumen_the_huntsman_manage_dps_timer(
|
||||
PlayerbotAI* botAI) { return new AttumenTheHuntsmanManageDpsTimerAction(botAI); }
|
||||
|
||||
static Action* karazhan_wizard_of_oz_mark_target(PlayerbotAI* botAI) { return new KarazhanWizardOfOzMarkTargetAction(botAI); }
|
||||
static Action* karazhan_wizard_of_oz_scorch_strawman(PlayerbotAI* botAI) { return new KarazhanWizardOfOzScorchStrawmanAction(botAI); }
|
||||
// Moroes
|
||||
static Action* moroes_main_tank_attack_boss(
|
||||
PlayerbotAI* botAI) { return new MoroesMainTankAttackBossAction(botAI); }
|
||||
|
||||
static Action* karazhan_the_curator_mark_target(PlayerbotAI* botAI) { return new KarazhanTheCuratorMarkTargetAction(botAI); }
|
||||
static Action* karazhan_the_curator_position_boss(PlayerbotAI* botAI) { return new KarazhanTheCuratorPositionBossAction(botAI); }
|
||||
static Action* karazhan_the_curator_spread_ranged(PlayerbotAI* botAI) { return new KarazhanTheCuratorSpreadRangedAction(botAI); }
|
||||
static Action* moroes_mark_target(
|
||||
PlayerbotAI* botAI) { return new MoroesMarkTargetAction(botAI); }
|
||||
|
||||
static Action* karazhan_terestian_illhoof_mark_target(PlayerbotAI* botAI) { return new KarazhanTerestianIllhoofMarkTargetAction(botAI); }
|
||||
// Maiden of Virtue
|
||||
static Action* maiden_of_virtue_move_boss_to_healer(
|
||||
PlayerbotAI* botAI) { return new MaidenOfVirtueMoveBossToHealerAction(botAI); }
|
||||
|
||||
static Action* karazhan_shade_of_aran_arcane_explosion_run_away(PlayerbotAI* botAI) { return new KarazhanShadeOfAranArcaneExplosionRunAwayAction(botAI); }
|
||||
static Action* karazhan_shade_of_aran_flame_wreath_stop_movement(PlayerbotAI* botAI) { return new KarazhanShadeOfAranFlameWreathStopMovementAction(botAI); }
|
||||
static Action* karazhan_shade_of_aran_mark_conjured_elemental(PlayerbotAI* botAI) { return new KarazhanShadeOfAranMarkConjuredElementalAction(botAI); }
|
||||
static Action* karazhan_shade_of_aran_spread_ranged(PlayerbotAI* botAI) { return new KarazhanShadeOfAranSpreadRangedAction(botAI); }
|
||||
static Action* maiden_of_virtue_position_ranged(
|
||||
PlayerbotAI* botAI) { return new MaidenOfVirtuePositionRangedAction(botAI); }
|
||||
|
||||
static Action* karazhan_netherspite_block_red_beam(PlayerbotAI* botAI) { return new KarazhanNetherspiteBlockRedBeamAction(botAI); }
|
||||
static Action* karazhan_netherspite_block_blue_beam(PlayerbotAI* botAI) { return new KarazhanNetherspiteBlockBlueBeamAction(botAI); }
|
||||
static Action* karazhan_netherspite_block_green_beam(PlayerbotAI* botAI) { return new KarazhanNetherspiteBlockGreenBeamAction(botAI); }
|
||||
static Action* karazhan_netherspite_avoid_beam_and_void_zone(PlayerbotAI* botAI) { return new KarazhanNetherspiteAvoidBeamAndVoidZoneAction(botAI); }
|
||||
static Action* karazhan_netherspite_banish_phase_avoid_void_zone(PlayerbotAI* botAI) { return new KarazhanNetherspiteBanishPhaseAvoidVoidZoneAction(botAI); }
|
||||
// The Big Bad Wolf
|
||||
static Action* big_bad_wolf_position_boss(
|
||||
PlayerbotAI* botAI) { return new BigBadWolfPositionBossAction(botAI); }
|
||||
|
||||
static Action* karazhan_prince_malchezaar_non_tank_avoid_hazard(PlayerbotAI* botAI) { return new KarazhanPrinceMalchezaarNonTankAvoidHazardAction(botAI); }
|
||||
static Action* karazhan_prince_malchezaar_tank_avoid_hazard(PlayerbotAI* botAI) { return new KarazhanPrinceMalchezaarTankAvoidHazardAction(botAI); }
|
||||
static Action* big_bad_wolf_run_away_from_boss(
|
||||
PlayerbotAI* botAI) { return new BigBadWolfRunAwayFromBossAction(botAI); }
|
||||
|
||||
// Romulo and Julianne
|
||||
static Action* romulo_and_julianne_mark_target(
|
||||
PlayerbotAI* botAI) { return new RomuloAndJulianneMarkTargetAction(botAI); }
|
||||
|
||||
// The Wizard of Oz
|
||||
static Action* wizard_of_oz_mark_target(
|
||||
PlayerbotAI* botAI) { return new WizardOfOzMarkTargetAction(botAI); }
|
||||
|
||||
static Action* wizard_of_oz_scorch_strawman(
|
||||
PlayerbotAI* botAI) { return new WizardOfOzScorchStrawmanAction(botAI); }
|
||||
|
||||
// The Curator
|
||||
static Action* the_curator_mark_astral_flare(
|
||||
PlayerbotAI* botAI) { return new TheCuratorMarkAstralFlareAction(botAI); }
|
||||
|
||||
static Action* the_curator_position_boss(
|
||||
PlayerbotAI* botAI) { return new TheCuratorPositionBossAction(botAI); }
|
||||
|
||||
static Action* the_curator_spread_ranged(
|
||||
PlayerbotAI* botAI) { return new TheCuratorSpreadRangedAction(botAI); }
|
||||
|
||||
// Terestian Illhoof
|
||||
static Action* terestian_illhoof_mark_target(
|
||||
PlayerbotAI* botAI) { return new TerestianIllhoofMarkTargetAction(botAI); }
|
||||
|
||||
// Shade of Aran
|
||||
static Action* shade_of_aran_run_away_from_arcane_explosion(
|
||||
PlayerbotAI* botAI) { return new ShadeOfAranRunAwayFromArcaneExplosionAction(botAI); }
|
||||
|
||||
static Action* shade_of_aran_stop_moving_during_flame_wreath(
|
||||
PlayerbotAI* botAI) { return new ShadeOfAranStopMovingDuringFlameWreathAction(botAI); }
|
||||
|
||||
static Action* shade_of_aran_mark_conjured_elemental(
|
||||
PlayerbotAI* botAI) { return new ShadeOfAranMarkConjuredElementalAction(botAI); }
|
||||
|
||||
static Action* shade_of_aran_ranged_maintain_distance(
|
||||
PlayerbotAI* botAI) { return new ShadeOfAranRangedMaintainDistanceAction(botAI); }
|
||||
|
||||
// Netherspite
|
||||
static Action* netherspite_block_red_beam(
|
||||
PlayerbotAI* botAI) { return new NetherspiteBlockRedBeamAction(botAI); }
|
||||
|
||||
static Action* netherspite_block_blue_beam(
|
||||
PlayerbotAI* botAI) { return new NetherspiteBlockBlueBeamAction(botAI); }
|
||||
|
||||
static Action* netherspite_block_green_beam(
|
||||
PlayerbotAI* botAI) { return new NetherspiteBlockGreenBeamAction(botAI); }
|
||||
|
||||
static Action* netherspite_avoid_beam_and_void_zone(
|
||||
PlayerbotAI* botAI) { return new NetherspiteAvoidBeamAndVoidZoneAction(botAI); }
|
||||
|
||||
static Action* netherspite_banish_phase_avoid_void_zone(
|
||||
PlayerbotAI* botAI) { return new NetherspiteBanishPhaseAvoidVoidZoneAction(botAI); }
|
||||
|
||||
static Action* netherspite_manage_timers_and_trackers(
|
||||
PlayerbotAI* botAI) { return new NetherspiteManageTimersAndTrackersAction(botAI); }
|
||||
|
||||
// Prince Malchezaar
|
||||
static Action* prince_malchezaar_enfeebled_avoid_hazard(
|
||||
PlayerbotAI* botAI) { return new PrinceMalchezaarEnfeebledAvoidHazardAction(botAI); }
|
||||
|
||||
static Action* prince_malchezaar_non_tank_avoid_infernal(
|
||||
PlayerbotAI* botAI) { return new PrinceMalchezaarNonTankAvoidInfernalAction(botAI); }
|
||||
|
||||
static Action* prince_malchezaar_main_tank_movement(
|
||||
PlayerbotAI* botAI) { return new PrinceMalchezaarMainTankMovementAction(botAI); }
|
||||
|
||||
// Nightbane
|
||||
static Action* nightbane_ground_phase_position_boss(
|
||||
PlayerbotAI* botAI) { return new NightbaneGroundPhasePositionBossAction(botAI); }
|
||||
|
||||
static Action* nightbane_ground_phase_rotate_ranged_positions(
|
||||
PlayerbotAI* botAI) { return new NightbaneGroundPhaseRotateRangedPositionsAction(botAI); }
|
||||
|
||||
static Action* nightbane_cast_fear_ward_on_main_tank(
|
||||
PlayerbotAI* botAI) { return new NightbaneCastFearWardOnMainTankAction(botAI); }
|
||||
|
||||
static Action* nightbane_control_pet_aggression(
|
||||
PlayerbotAI* botAI) { return new NightbaneControlPetAggressionAction(botAI); }
|
||||
|
||||
static Action* nightbane_flight_phase_movement(
|
||||
PlayerbotAI* botAI) { return new NightbaneFlightPhaseMovementAction(botAI); }
|
||||
|
||||
static Action* nightbane_manage_timers_and_trackers(
|
||||
PlayerbotAI* botAI) { return new NightbaneManageTimersAndTrackersAction(botAI); }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,217 +2,322 @@
|
||||
#define _PLAYERBOT_RAIDKARAZHANACTIONS_H
|
||||
|
||||
#include "Action.h"
|
||||
#include "AttackAction.h"
|
||||
#include "MovementActions.h"
|
||||
|
||||
class KarazhanAttumenTheHuntsmanStackBehindAction : public MovementAction
|
||||
class ManaWarpStunCreatureBeforeWarpBreachAction : public AttackAction
|
||||
{
|
||||
public:
|
||||
KarazhanAttumenTheHuntsmanStackBehindAction(PlayerbotAI* botAI, std::string const name = "karazhan attumen the huntsman stack behind") : MovementAction(botAI, name) {}
|
||||
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
class KarazhanMoroesMarkTargetAction : public Action
|
||||
{
|
||||
public:
|
||||
KarazhanMoroesMarkTargetAction(PlayerbotAI* botAI, std::string const name = "karazhan moroes mark target") : Action(botAI, name) {}
|
||||
ManaWarpStunCreatureBeforeWarpBreachAction(
|
||||
PlayerbotAI* botAI, std::string const name = "mana warp stun creature before warp breach") : AttackAction(botAI, name) {}
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class KarazhanMaidenOfVirtuePositionBossAction : public MovementAction
|
||||
class AttumenTheHuntsmanMarkTargetAction : public AttackAction
|
||||
{
|
||||
public:
|
||||
KarazhanMaidenOfVirtuePositionBossAction(PlayerbotAI* botAI, std::string const name = "karazhan maiden of virtue position boss") : MovementAction(botAI, name) {}
|
||||
|
||||
AttumenTheHuntsmanMarkTargetAction(
|
||||
PlayerbotAI* botAI, std::string const name = "attumen the huntsman mark target") : AttackAction(botAI, name) {}
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
class KarazhanMaidenOfVirtuePositionRangedAction : public MovementAction
|
||||
class AttumenTheHuntsmanSplitBossesAction : public AttackAction
|
||||
{
|
||||
public:
|
||||
KarazhanMaidenOfVirtuePositionRangedAction(PlayerbotAI* botAI, std::string const name = "karazhan maiden of virtue position ranged") : MovementAction(botAI, name) {}
|
||||
|
||||
AttumenTheHuntsmanSplitBossesAction(
|
||||
PlayerbotAI* botAI, std::string const name = "attumen the huntsman split bosses") : AttackAction(botAI, name) {}
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
class KarazhanBigBadWolfPositionBossAction : public MovementAction
|
||||
class AttumenTheHuntsmanStackBehindAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
KarazhanBigBadWolfPositionBossAction(PlayerbotAI* botAI, std::string const name = "karazhan big bad wolf position boss") : MovementAction(botAI, name) {}
|
||||
|
||||
AttumenTheHuntsmanStackBehindAction(
|
||||
PlayerbotAI* botAI, std::string const name = "attumen the huntsman stack behind") : MovementAction(botAI, name) {}
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
class KarazhanBigBadWolfRunAwayAction : public MovementAction
|
||||
class AttumenTheHuntsmanManageDpsTimerAction : public Action
|
||||
{
|
||||
public:
|
||||
KarazhanBigBadWolfRunAwayAction(PlayerbotAI* botAI, std::string const name = "karazhan big bad wolf run away") : MovementAction(botAI, name) {}
|
||||
|
||||
AttumenTheHuntsmanManageDpsTimerAction(
|
||||
PlayerbotAI* botAI, std::string const name = "attumen the huntsman manage dps timer") : Action(botAI, name) {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class MoroesMainTankAttackBossAction : public AttackAction
|
||||
{
|
||||
public:
|
||||
MoroesMainTankAttackBossAction(
|
||||
PlayerbotAI* botAI, std::string const name = "moroes main tank attack boss") : AttackAction(botAI, name) {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class MoroesMarkTargetAction : public Action
|
||||
{
|
||||
public:
|
||||
MoroesMarkTargetAction(
|
||||
PlayerbotAI* botAI, std::string const name = "moroes mark target") : Action(botAI, name) {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class MaidenOfVirtueMoveBossToHealerAction : public AttackAction
|
||||
{
|
||||
public:
|
||||
MaidenOfVirtueMoveBossToHealerAction(
|
||||
PlayerbotAI* botAI, std::string const name = "maiden of virtue move boss to healer") : AttackAction(botAI, name) {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class MaidenOfVirtuePositionRangedAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
MaidenOfVirtuePositionRangedAction(
|
||||
PlayerbotAI* botAI, std::string const name = "maiden of virtue position ranged") : MovementAction(botAI, name) {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class BigBadWolfPositionBossAction : public AttackAction
|
||||
{
|
||||
public:
|
||||
BigBadWolfPositionBossAction(
|
||||
PlayerbotAI* botAI, std::string const name = "big bad wolf position boss") : AttackAction(botAI, name) {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class BigBadWolfRunAwayFromBossAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
BigBadWolfRunAwayFromBossAction(
|
||||
PlayerbotAI* botAI, std::string const name = "big bad wolf run away from boss") : MovementAction(botAI, name) {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class RomuloAndJulianneMarkTargetAction : public Action
|
||||
{
|
||||
public:
|
||||
RomuloAndJulianneMarkTargetAction(
|
||||
PlayerbotAI* botAI, std::string const name = "romulo and julianne mark target") : Action(botAI, name) {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class WizardOfOzMarkTargetAction : public Action
|
||||
{
|
||||
public:
|
||||
WizardOfOzMarkTargetAction(
|
||||
PlayerbotAI* botAI, std::string const name = "wizard of oz mark target") : Action(botAI, name) {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class WizardOfOzScorchStrawmanAction : public Action
|
||||
{
|
||||
public:
|
||||
WizardOfOzScorchStrawmanAction(
|
||||
PlayerbotAI* botAI, std::string const name = "wizard of oz scorch strawman") : Action(botAI, name) {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class TheCuratorMarkAstralFlareAction : public Action
|
||||
{
|
||||
public:
|
||||
TheCuratorMarkAstralFlareAction(
|
||||
PlayerbotAI* botAI, std::string const name = "the curator mark astral flare") : Action(botAI, name) {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class TheCuratorPositionBossAction : public AttackAction
|
||||
{
|
||||
public:
|
||||
TheCuratorPositionBossAction(
|
||||
PlayerbotAI* botAI, std::string const name = "the curator position boss") : AttackAction(botAI, name) {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class TheCuratorSpreadRangedAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
TheCuratorSpreadRangedAction(
|
||||
PlayerbotAI* botAI, std::string const name = "the curator spread ranged") : MovementAction(botAI, name) {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class TerestianIllhoofMarkTargetAction : public Action
|
||||
{
|
||||
public:
|
||||
TerestianIllhoofMarkTargetAction(
|
||||
PlayerbotAI* botAI, std::string const name = "terestian illhoof mark target") : Action(botAI, name) {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class ShadeOfAranRunAwayFromArcaneExplosionAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
ShadeOfAranRunAwayFromArcaneExplosionAction(
|
||||
PlayerbotAI* botAI, std::string const name = "shade of aran run away from arcane explosion") : MovementAction(botAI, name) {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class ShadeOfAranStopMovingDuringFlameWreathAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
ShadeOfAranStopMovingDuringFlameWreathAction(
|
||||
PlayerbotAI* botAI, std::string const name = "shade of aran stop moving during flame wreath") : MovementAction(botAI, name) {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class ShadeOfAranMarkConjuredElementalAction : public Action
|
||||
{
|
||||
public:
|
||||
ShadeOfAranMarkConjuredElementalAction(
|
||||
PlayerbotAI* botAI, std::string const name = "shade of aran mark conjured elemental") : Action(botAI, name) {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class ShadeOfAranRangedMaintainDistanceAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
ShadeOfAranRangedMaintainDistanceAction(
|
||||
PlayerbotAI* botAI, std::string const name = "shade of aran ranged maintain distance") : MovementAction(botAI, name) {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class NetherspiteBlockRedBeamAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
NetherspiteBlockRedBeamAction(
|
||||
PlayerbotAI* botAI, std::string const name = "netherspite block red beam") : MovementAction(botAI, name) {}
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
|
||||
private:
|
||||
size_t currentIndex = 0;
|
||||
Position GetPositionOnBeam(Unit* netherspite, Unit* portal, float distanceFromBoss);
|
||||
std::unordered_map<ObjectGuid, bool> _wasBlockingRedBeam;
|
||||
};
|
||||
|
||||
class KarazhanRomuloAndJulianneMarkTargetAction : public Action
|
||||
class NetherspiteBlockBlueBeamAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
KarazhanRomuloAndJulianneMarkTargetAction(PlayerbotAI* botAI, std::string const name = "karazhan romulo and julianne mark target") : Action(botAI, name) {}
|
||||
NetherspiteBlockBlueBeamAction(
|
||||
PlayerbotAI* botAI, std::string const name = "netherspite block blue beam") : MovementAction(botAI, name) {}
|
||||
bool Execute(Event event) override;
|
||||
|
||||
private:
|
||||
std::unordered_map<ObjectGuid, bool> _wasBlockingBlueBeam;
|
||||
};
|
||||
|
||||
class NetherspiteBlockGreenBeamAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
NetherspiteBlockGreenBeamAction(
|
||||
PlayerbotAI* botAI, std::string const name = "netherspite block green beam") : MovementAction(botAI, name) {}
|
||||
bool Execute(Event event) override;
|
||||
|
||||
private:
|
||||
std::unordered_map<ObjectGuid, bool> _wasBlockingGreenBeam;
|
||||
};
|
||||
|
||||
class NetherspiteAvoidBeamAndVoidZoneAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
NetherspiteAvoidBeamAndVoidZoneAction(
|
||||
PlayerbotAI* botAI, std::string const name = "netherspite avoid beam and void zone") : MovementAction(botAI, name) {}
|
||||
bool Execute(Event event) override;
|
||||
|
||||
private:
|
||||
struct BeamAvoid
|
||||
{
|
||||
Unit* portal;
|
||||
float minDist, maxDist;
|
||||
};
|
||||
bool IsAwayFromBeams(float x, float y, const std::vector<BeamAvoid>& beams, Unit* netherspite);
|
||||
};
|
||||
|
||||
class NetherspiteBanishPhaseAvoidVoidZoneAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
NetherspiteBanishPhaseAvoidVoidZoneAction(
|
||||
PlayerbotAI* botAI, std::string const name = "netherspite banish phase avoid void zone") : MovementAction(botAI, name) {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class KarazhanWizardOfOzMarkTargetAction : public Action
|
||||
class NetherspiteManageTimersAndTrackersAction : public Action
|
||||
{
|
||||
public:
|
||||
KarazhanWizardOfOzMarkTargetAction(PlayerbotAI* botAI, std::string const name = "karazhan wizard of oz mark target") : Action(botAI, name) {}
|
||||
|
||||
NetherspiteManageTimersAndTrackersAction(
|
||||
PlayerbotAI* botAI, std::string const name = "netherspite manage timers and trackers") : Action(botAI, name) {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class KarazhanWizardOfOzScorchStrawmanAction : public Action
|
||||
class PrinceMalchezaarEnfeebledAvoidHazardAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
KarazhanWizardOfOzScorchStrawmanAction(PlayerbotAI* botAI, std::string const name = "karazhan wizard of oz scorch strawman") : Action(botAI, name) {}
|
||||
|
||||
PrinceMalchezaarEnfeebledAvoidHazardAction(
|
||||
PlayerbotAI* botAI, std::string const name = "prince malchezaar enfeebled avoid hazard") : MovementAction(botAI, name) {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class KarazhanTheCuratorMarkTargetAction : public Action
|
||||
class PrinceMalchezaarNonTankAvoidInfernalAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
KarazhanTheCuratorMarkTargetAction(PlayerbotAI* botAI, std::string const name = "karazhan the curator mark target") : Action(botAI, name) {}
|
||||
|
||||
PrinceMalchezaarNonTankAvoidInfernalAction(
|
||||
PlayerbotAI* botAI, std::string const name = "prince malchezaar non tank avoid infernal") : MovementAction(botAI, name) {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class KarazhanTheCuratorPositionBossAction : public MovementAction
|
||||
class PrinceMalchezaarMainTankMovementAction : public AttackAction
|
||||
{
|
||||
public:
|
||||
KarazhanTheCuratorPositionBossAction(PlayerbotAI* botAI, std::string const name = "karazhan the curator position boss") : MovementAction(botAI, name) {}
|
||||
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
class KarazhanTheCuratorSpreadRangedAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
KarazhanTheCuratorSpreadRangedAction(PlayerbotAI* botAI, std::string const name = "karazhan the curator spread ranged") : MovementAction(botAI, name) {}
|
||||
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
class KarazhanTerestianIllhoofMarkTargetAction : public Action
|
||||
{
|
||||
public:
|
||||
KarazhanTerestianIllhoofMarkTargetAction(PlayerbotAI* botAI, std::string const name = "karazhan terestian illhoof mark target") : Action(botAI, name) {}
|
||||
|
||||
PrinceMalchezaarMainTankMovementAction(
|
||||
PlayerbotAI* botAI, std::string const name = "prince malchezaar main tank movement") : AttackAction(botAI, name) {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class KarazhanShadeOfAranArcaneExplosionRunAwayAction : public MovementAction
|
||||
class NightbaneGroundPhasePositionBossAction : public AttackAction
|
||||
{
|
||||
public:
|
||||
KarazhanShadeOfAranArcaneExplosionRunAwayAction(PlayerbotAI* botAI, std::string const name = "karazhan shade of aran arcane explosion run away") : MovementAction(botAI, name) {}
|
||||
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
class KarazhanShadeOfAranFlameWreathStopMovementAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
KarazhanShadeOfAranFlameWreathStopMovementAction(PlayerbotAI* botAI, std::string const name = "karazhan shade of aran flame wreath stop bot") : MovementAction(botAI, name) {}
|
||||
|
||||
NightbaneGroundPhasePositionBossAction(
|
||||
PlayerbotAI* botAI, std::string const name = "nightbane ground phase position boss") : AttackAction(botAI, name) {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class KarazhanShadeOfAranMarkConjuredElementalAction : public Action
|
||||
class NightbaneGroundPhaseRotateRangedPositionsAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
KarazhanShadeOfAranMarkConjuredElementalAction(PlayerbotAI* botAI, std::string const name = "karazhan shade of aran mark conjured elemental") : Action(botAI, name) {}
|
||||
|
||||
NightbaneGroundPhaseRotateRangedPositionsAction(
|
||||
PlayerbotAI* botAI, std::string const name = "nightbane ground phase rotate ranged positions") : MovementAction(botAI, name) {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class KarazhanShadeOfAranSpreadRangedAction : public MovementAction
|
||||
class NightbaneCastFearWardOnMainTankAction : public Action
|
||||
{
|
||||
public:
|
||||
KarazhanShadeOfAranSpreadRangedAction(PlayerbotAI* botAI, std::string const name = "karazhan shade of aran spread ranged") : MovementAction(botAI, name) {}
|
||||
|
||||
NightbaneCastFearWardOnMainTankAction(
|
||||
PlayerbotAI* botAI, std::string const name = "nightbane cast fear ward on main tank") : Action(botAI, name) {}
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
class KarazhanNetherspiteBlockRedBeamAction : public MovementAction
|
||||
class NightbaneControlPetAggressionAction : public Action
|
||||
{
|
||||
public:
|
||||
KarazhanNetherspiteBlockRedBeamAction(PlayerbotAI* botAI, std::string const name = "karazhan netherspite block red beam") : MovementAction(botAI, name) {}
|
||||
|
||||
NightbaneControlPetAggressionAction(
|
||||
PlayerbotAI* botAI, std::string const name = "nightbane control pet aggression") : Action(botAI, name) {}
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
class KarazhanNetherspiteBlockBlueBeamAction : public MovementAction
|
||||
class NightbaneFlightPhaseMovementAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
KarazhanNetherspiteBlockBlueBeamAction(PlayerbotAI* botAI, std::string const name = "karazhan netherspite block blue beam") : MovementAction(botAI, name) {}
|
||||
|
||||
NightbaneFlightPhaseMovementAction(
|
||||
PlayerbotAI* botAI, std::string const name = "nightbane flight phase movement") : MovementAction(botAI, name) {}
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
class KarazhanNetherspiteBlockGreenBeamAction : public MovementAction
|
||||
class NightbaneManageTimersAndTrackersAction : public Action
|
||||
{
|
||||
public:
|
||||
KarazhanNetherspiteBlockGreenBeamAction(PlayerbotAI* botAI, std::string const name = "karazhan netherspite block green beam") : MovementAction(botAI, name) {}
|
||||
|
||||
NightbaneManageTimersAndTrackersAction(
|
||||
PlayerbotAI* botAI, std::string const name = "nightbane manage timers and trackers") : Action(botAI, name) {}
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
class KarazhanNetherspiteAvoidBeamAndVoidZoneAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
KarazhanNetherspiteAvoidBeamAndVoidZoneAction(PlayerbotAI* botAI, std::string const name = "karazhan netherspite avoid beam and void zone") : MovementAction(botAI, name) {}
|
||||
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
class KarazhanNetherspiteBanishPhaseAvoidVoidZoneAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
KarazhanNetherspiteBanishPhaseAvoidVoidZoneAction(PlayerbotAI* botAI, std::string const name = "karazhan netherspite banish phase avoid void zone") : MovementAction(botAI, name) {}
|
||||
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
class KarazhanPrinceMalchezaarNonTankAvoidHazardAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
KarazhanPrinceMalchezaarNonTankAvoidHazardAction(PlayerbotAI* botAI, std::string const name = "karazhan prince malchezaar non-tank avoid hazard") : MovementAction(botAI, name) {}
|
||||
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
class KarazhanPrinceMalchezaarTankAvoidHazardAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
KarazhanPrinceMalchezaarTankAvoidHazardAction(PlayerbotAI* botAI, std::string const name = "karazhan prince malchezaar tank avoid hazard") : MovementAction(botAI, name) {}
|
||||
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,28 +1,40 @@
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
|
||||
#include "RaidKarazhanHelpers.h"
|
||||
#include "RaidKarazhanActions.h"
|
||||
#include "AiObjectContext.h"
|
||||
#include "PlayerbotMgr.h"
|
||||
#include "Position.h"
|
||||
#include "Spell.h"
|
||||
#include "Playerbots.h"
|
||||
#include "RtiTargetValue.h"
|
||||
|
||||
const Position KARAZHAN_MAIDEN_OF_VIRTUE_BOSS_POSITION = Position(-10945.881f, -2103.782f, 92.712f);
|
||||
const Position KARAZHAN_MAIDEN_OF_VIRTUE_RANGED_POSITION[8] =
|
||||
namespace KarazhanHelpers
|
||||
{
|
||||
// Attumen the Huntsman
|
||||
std::unordered_map<uint32, time_t> attumenDpsWaitTimer;
|
||||
// Big Bad Wolf
|
||||
std::unordered_map<ObjectGuid, uint8> bigBadWolfRunIndex;
|
||||
// Netherspite
|
||||
std::unordered_map<uint32, time_t> netherspiteDpsWaitTimer;
|
||||
std::unordered_map<ObjectGuid, time_t> redBeamMoveTimer;
|
||||
std::unordered_map<ObjectGuid, bool> lastBeamMoveSideways;
|
||||
// Nightbane
|
||||
std::unordered_map<uint32, time_t> nightbaneDpsWaitTimer;
|
||||
std::unordered_map<ObjectGuid, uint8> nightbaneTankStep;
|
||||
std::unordered_map<ObjectGuid, uint8> nightbaneRangedStep;
|
||||
std::unordered_map<uint32, time_t> nightbaneFlightPhaseStartTimer;
|
||||
std::unordered_map<ObjectGuid, bool> nightbaneRainOfBonesHit;
|
||||
|
||||
const Position MAIDEN_OF_VIRTUE_BOSS_POSITION = { -10945.881f, -2103.782f, 92.712f };
|
||||
const Position MAIDEN_OF_VIRTUE_RANGED_POSITION[8] =
|
||||
{
|
||||
{ -10931.178f, -2116.580f, 92.179f },
|
||||
{ -10925.828f, -2102.425f, 92.180f },
|
||||
{ -10933.089f, -2088.5017f, 92.180f },
|
||||
{ -10947.59f, -2082.8147f, 92.180f },
|
||||
{ -10960.912f, -2090.4368f, 92.179f },
|
||||
{ -10933.089f, -2088.502f, 92.180f },
|
||||
{ -10947.590f, -2082.815f, 92.180f },
|
||||
{ -10960.912f, -2090.437f, 92.179f },
|
||||
{ -10966.017f, -2105.288f, 92.175f },
|
||||
{ -10959.242f, -2119.6172f, 92.180f },
|
||||
{ -10959.242f, -2119.617f, 92.180f },
|
||||
{ -10944.495f, -2123.857f, 92.180f },
|
||||
};
|
||||
|
||||
const Position KARAZHAN_BIG_BAD_WOLF_BOSS_POSITION = Position(-10913.391f, -1773.508f, 90.477f);
|
||||
const Position KARAZHAN_BIG_BAD_WOLF_RUN_POSITION[4] =
|
||||
const Position BIG_BAD_WOLF_BOSS_POSITION = { -10913.391f, -1773.508f, 90.477f };
|
||||
const Position BIG_BAD_WOLF_RUN_POSITION[4] =
|
||||
{
|
||||
{ -10875.456f, -1779.036f, 90.477f },
|
||||
{ -10872.281f, -1751.638f, 90.477f },
|
||||
@@ -30,122 +42,172 @@ const Position KARAZHAN_BIG_BAD_WOLF_RUN_POSITION[4] =
|
||||
{ -10913.391f, -1773.508f, 90.477f },
|
||||
};
|
||||
|
||||
const Position KARAZHAN_THE_CURATOR_BOSS_POSITION = Position(-11139.463f, -1884.645f, 165.765f);
|
||||
const Position THE_CURATOR_BOSS_POSITION = { -11139.463f, -1884.645f, 165.765f };
|
||||
|
||||
void RaidKarazhanHelpers::MarkTargetWithSkull(Unit* target)
|
||||
const Position NIGHTBANE_TRANSITION_BOSS_POSITION = { -11160.646f, -1932.773f, 91.473f }; // near some ribs
|
||||
const Position NIGHTBANE_FINAL_BOSS_POSITION = { -11173.530f, -1940.707f, 91.473f };
|
||||
const Position NIGHTBANE_RANGED_POSITION1 = { -11145.949f, -1970.927f, 91.473f };
|
||||
const Position NIGHTBANE_RANGED_POSITION2 = { -11143.594f, -1954.981f, 91.473f };
|
||||
const Position NIGHTBANE_RANGED_POSITION3 = { -11159.778f, -1961.031f, 91.473f };
|
||||
const Position NIGHTBANE_FLIGHT_STACK_POSITION = { -11159.555f, -1893.526f, 91.473f }; // Broken Barrel
|
||||
const Position NIGHTBANE_RAIN_OF_BONES_POSITION = { -11165.233f, -1911.123f, 91.473f };
|
||||
|
||||
void MarkTargetWithIcon(Player* bot, Unit* target, uint8 iconId)
|
||||
{
|
||||
if (!target)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Group* group = bot->GetGroup())
|
||||
{
|
||||
constexpr uint8_t skullIconId = 7;
|
||||
ObjectGuid skullGuid = group->GetTargetIcon(skullIconId);
|
||||
ObjectGuid currentGuid = group->GetTargetIcon(iconId);
|
||||
if (currentGuid != target->GetGUID())
|
||||
group->SetTargetIcon(iconId, bot->GetGUID(), target->GetGUID());
|
||||
}
|
||||
}
|
||||
|
||||
if (skullGuid != target->GetGUID())
|
||||
void MarkTargetWithSkull(Player* bot, Unit* target)
|
||||
{
|
||||
group->SetTargetIcon(skullIconId, bot->GetGUID(), target->GetGUID());
|
||||
MarkTargetWithIcon(bot, target, RtiTargetValue::skullIndex);
|
||||
}
|
||||
|
||||
void MarkTargetWithSquare(Player* bot, Unit* target)
|
||||
{
|
||||
MarkTargetWithIcon(bot, target, RtiTargetValue::squareIndex);
|
||||
}
|
||||
|
||||
void MarkTargetWithStar(Player* bot, Unit* target)
|
||||
{
|
||||
MarkTargetWithIcon(bot, target, RtiTargetValue::starIndex);
|
||||
}
|
||||
|
||||
void MarkTargetWithCircle(Player* bot, Unit* target)
|
||||
{
|
||||
MarkTargetWithIcon(bot, target, RtiTargetValue::circleIndex);
|
||||
}
|
||||
|
||||
void MarkTargetWithMoon(Player* bot, Unit* target)
|
||||
{
|
||||
MarkTargetWithIcon(bot, target, RtiTargetValue::moonIndex);
|
||||
}
|
||||
|
||||
void SetRtiTarget(PlayerbotAI* botAI, const std::string& rtiName, Unit* target)
|
||||
{
|
||||
if (!target)
|
||||
return;
|
||||
|
||||
std::string currentRti = botAI->GetAiObjectContext()->GetValue<std::string>("rti")->Get();
|
||||
Unit* currentTarget = botAI->GetAiObjectContext()->GetValue<Unit*>("rti target")->Get();
|
||||
|
||||
if (currentRti != rtiName || currentTarget != target)
|
||||
{
|
||||
botAI->GetAiObjectContext()->GetValue<std::string>("rti")->Set(rtiName);
|
||||
botAI->GetAiObjectContext()->GetValue<Unit*>("rti target")->Set(target);
|
||||
}
|
||||
}
|
||||
|
||||
Unit* RaidKarazhanHelpers::GetFirstAliveUnit(const std::vector<Unit*>& units)
|
||||
// Only one bot is needed to set/reset mapwide timers
|
||||
bool IsMapIDTimerManager(PlayerbotAI* botAI, Player* bot)
|
||||
{
|
||||
if (Group* group = bot->GetGroup())
|
||||
{
|
||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||
{
|
||||
Player* member = ref->GetSource();
|
||||
if (member && member->IsAlive() && botAI->IsDps(member) && GET_PLAYERBOT_AI(member))
|
||||
return member == bot;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Unit* GetFirstAliveUnit(const std::vector<Unit*>& units)
|
||||
{
|
||||
for (Unit* unit : units)
|
||||
{
|
||||
if (unit && unit->IsAlive())
|
||||
{
|
||||
return unit;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Unit* RaidKarazhanHelpers::GetFirstAliveUnitByEntry(uint32 entry)
|
||||
Unit* GetFirstAliveUnitByEntry(PlayerbotAI* botAI, uint32 entry)
|
||||
{
|
||||
const GuidVector npcs = AI_VALUE(GuidVector, "nearest hostile npcs");
|
||||
|
||||
const GuidVector npcs = botAI->GetAiObjectContext()->GetValue<GuidVector>("nearest hostile npcs")->Get();
|
||||
for (auto const& npcGuid : npcs)
|
||||
{
|
||||
Unit* unit = botAI->GetUnit(npcGuid);
|
||||
|
||||
if (unit && unit->IsAlive() && unit->GetEntry() == entry)
|
||||
{
|
||||
return unit;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Unit* RaidKarazhanHelpers::GetNearestPlayerInRadius(float radius)
|
||||
Unit* GetNearestPlayerInRadius(Player* bot, float radius)
|
||||
{
|
||||
Unit* nearestPlayer = nullptr;
|
||||
float nearestDistance = radius;
|
||||
|
||||
if (Group* group = bot->GetGroup())
|
||||
{
|
||||
for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
|
||||
for (GroupReference* ref = group->GetFirstMember(); ref != nullptr; ref = ref->next())
|
||||
{
|
||||
Player* member = itr->GetSource();
|
||||
|
||||
Player* member = ref->GetSource();
|
||||
if (!member || !member->IsAlive() || member == bot)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bot->GetExactDist2d(member) < radius)
|
||||
float distance = bot->GetExactDist2d(member);
|
||||
if (distance < nearestDistance)
|
||||
{
|
||||
return member;
|
||||
nearestDistance = distance;
|
||||
nearestPlayer = member;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
return nearestPlayer;
|
||||
}
|
||||
|
||||
bool RaidKarazhanHelpers::IsFlameWreathActive()
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "shade of aran");
|
||||
Spell* currentSpell = boss ? boss->GetCurrentSpell(CURRENT_GENERIC_SPELL) : nullptr;
|
||||
if (currentSpell && currentSpell->m_spellInfo && currentSpell->m_spellInfo->Id == SPELL_FLAME_WREATH)
|
||||
bool IsFlameWreathActive(PlayerbotAI* botAI, Player* bot)
|
||||
{
|
||||
Unit* aran = botAI->GetAiObjectContext()->GetValue<Unit*>("find target", "shade of aran")->Get();
|
||||
Spell* currentSpell = aran ? aran->GetCurrentSpell(CURRENT_GENERIC_SPELL) : nullptr;
|
||||
|
||||
if (currentSpell && currentSpell->m_spellInfo &&
|
||||
currentSpell->m_spellInfo->Id == SPELL_FLAME_WREATH_CAST)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Group* group = bot->GetGroup())
|
||||
{
|
||||
for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
|
||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||
{
|
||||
Player* member = itr->GetSource();
|
||||
Player* member = ref->GetSource();
|
||||
if (!member || !member->IsAlive())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (member->HasAura(SPELL_AURA_FLAME_WREATH))
|
||||
{
|
||||
|
||||
if (member->HasAura(SPELL_FLAME_WREATH_AURA))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Red beam blockers: tank bots, no Nether Exhaustion Red
|
||||
std::vector<Player*> RaidKarazhanHelpers::GetRedBlockers()
|
||||
std::vector<Player*> GetRedBlockers(PlayerbotAI* botAI, Player* bot)
|
||||
{
|
||||
std::vector<Player*> redBlockers;
|
||||
if (Group* group = bot->GetGroup())
|
||||
{
|
||||
for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
|
||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||
{
|
||||
Player* member = itr->GetSource();
|
||||
Player* member = ref->GetSource();
|
||||
if (!member || !member->IsAlive() || !botAI->IsTank(member) || !GET_PLAYERBOT_AI(member) ||
|
||||
member->HasAura(SPELL_NETHER_EXHAUSTION_RED))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
redBlockers.push_back(member);
|
||||
}
|
||||
}
|
||||
@@ -153,94 +215,78 @@ std::vector<Player*> RaidKarazhanHelpers::GetRedBlockers()
|
||||
return redBlockers;
|
||||
}
|
||||
|
||||
// Blue beam blockers: non-Rogue/Warrior DPS bots, no Nether Exhaustion Blue and ≤25 stacks of Blue Beam debuff
|
||||
std::vector<Player*> RaidKarazhanHelpers::GetBlueBlockers()
|
||||
// Blue beam blockers: non-Rogue/Warrior DPS bots, no Nether Exhaustion Blue and <24 stacks of Blue Beam debuff
|
||||
std::vector<Player*> GetBlueBlockers(PlayerbotAI* botAI, Player* bot)
|
||||
{
|
||||
std::vector<Player*> blueBlockers;
|
||||
if (Group* group = bot->GetGroup())
|
||||
{
|
||||
for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
|
||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||
{
|
||||
Player* member = itr->GetSource();
|
||||
Player* member = ref->GetSource();
|
||||
if (!member || !member->IsAlive() || !GET_PLAYERBOT_AI(member))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
bool hasExhaustion = member->HasAura(SPELL_NETHER_EXHAUSTION_BLUE);
|
||||
Aura* blueBuff = member->GetAura(SPELL_BLUE_BEAM_DEBUFF);
|
||||
bool overStack = blueBuff && blueBuff->GetStackAmount() >= 24;
|
||||
|
||||
bool isDps = botAI->IsDps(member);
|
||||
bool isWarrior = member->getClass() == CLASS_WARRIOR;
|
||||
bool isRogue = member->getClass() == CLASS_ROGUE;
|
||||
bool hasExhaustion = member->HasAura(SPELL_NETHER_EXHAUSTION_BLUE);
|
||||
Aura* blueBuff = member->GetAura(SPELL_BLUE_BEAM_DEBUFF);
|
||||
bool overStack = blueBuff && blueBuff->GetStackAmount() >= 26;
|
||||
|
||||
if (isDps && !isWarrior && !isRogue && !hasExhaustion && !overStack)
|
||||
{
|
||||
blueBlockers.push_back(member);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return blueBlockers;
|
||||
}
|
||||
|
||||
// Green beam blockers:
|
||||
// (1) Rogue and non-tank Warrior bots, no Nether Exhaustion Green
|
||||
// (2) Healer bots, no Nether Exhaustion Green and ≤25 stacks of Green Beam debuff
|
||||
std::vector<Player*> RaidKarazhanHelpers::GetGreenBlockers()
|
||||
// (1) Prioritize Rogues and non-tank Warrior bots, no Nether Exhaustion Green
|
||||
// (2) Then assign Healer bots, no Nether Exhaustion Green and <24 stacks of Green Beam debuff
|
||||
std::vector<Player*> GetGreenBlockers(PlayerbotAI* botAI, Player* bot)
|
||||
{
|
||||
std::vector<Player*> greenBlockers;
|
||||
if (Group* group = bot->GetGroup())
|
||||
{
|
||||
for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
|
||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||
{
|
||||
Player* member = itr->GetSource();
|
||||
Player* member = ref->GetSource();
|
||||
if (!member || !member->IsAlive() || !GET_PLAYERBOT_AI(member))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
bool hasExhaustion = member->HasAura(SPELL_NETHER_EXHAUSTION_GREEN);
|
||||
Aura* greenBuff = member->GetAura(SPELL_GREEN_BEAM_DEBUFF);
|
||||
bool overStack = greenBuff && greenBuff->GetStackAmount() >= 26;
|
||||
bool isRogue = member->getClass() == CLASS_ROGUE;
|
||||
bool isDpsWarrior = member->getClass() == CLASS_WARRIOR && botAI->IsDps(member);
|
||||
bool eligibleRogueWarrior = (isRogue || isDpsWarrior) && !hasExhaustion;
|
||||
bool isHealer = botAI->IsHeal(member);
|
||||
bool eligibleHealer = isHealer && !hasExhaustion && !overStack;
|
||||
if (eligibleRogueWarrior || eligibleHealer)
|
||||
{
|
||||
|
||||
if (eligibleRogueWarrior)
|
||||
greenBlockers.push_back(member);
|
||||
}
|
||||
|
||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||
{
|
||||
Player* member = ref->GetSource();
|
||||
if (!member || !member->IsAlive() || !GET_PLAYERBOT_AI(member))
|
||||
continue;
|
||||
|
||||
bool hasExhaustion = member->HasAura(SPELL_NETHER_EXHAUSTION_GREEN);
|
||||
Aura* greenBuff = member->GetAura(SPELL_GREEN_BEAM_DEBUFF);
|
||||
bool overStack = greenBuff && greenBuff->GetStackAmount() >= 24;
|
||||
bool isHealer = botAI->IsHeal(member);
|
||||
bool eligibleHealer = isHealer && !hasExhaustion && !overStack;
|
||||
|
||||
if (eligibleHealer)
|
||||
greenBlockers.push_back(member);
|
||||
}
|
||||
}
|
||||
|
||||
return greenBlockers;
|
||||
}
|
||||
|
||||
Position RaidKarazhanHelpers::GetPositionOnBeam(Unit* boss, Unit* portal, float distanceFromBoss)
|
||||
{
|
||||
float bx = boss->GetPositionX();
|
||||
float by = boss->GetPositionY();
|
||||
float bz = boss->GetPositionZ();
|
||||
float px = portal->GetPositionX();
|
||||
float py = portal->GetPositionY();
|
||||
|
||||
float dx = px - bx;
|
||||
float dy = py - by;
|
||||
float length = sqrt(dx*dx + dy*dy);
|
||||
if (length == 0.0f)
|
||||
{
|
||||
return Position(bx, by, bz);
|
||||
}
|
||||
|
||||
dx /= length;
|
||||
dy /= length;
|
||||
float targetX = bx + dx * distanceFromBoss;
|
||||
float targetY = by + dy * distanceFromBoss;
|
||||
float targetZ = bz;
|
||||
|
||||
return Position(targetX, targetY, targetZ);
|
||||
}
|
||||
|
||||
std::tuple<Player*, Player*, Player*> RaidKarazhanHelpers::GetCurrentBeamBlockers()
|
||||
std::tuple<Player*, Player*, Player*> GetCurrentBeamBlockers(PlayerbotAI* botAI, Player* bot)
|
||||
{
|
||||
static ObjectGuid currentRedBlocker;
|
||||
static ObjectGuid currentGreenBlocker;
|
||||
@@ -250,21 +296,19 @@ std::tuple<Player*, Player*, Player*> RaidKarazhanHelpers::GetCurrentBeamBlocker
|
||||
Player* greenBlocker = nullptr;
|
||||
Player* blueBlocker = nullptr;
|
||||
|
||||
std::vector<Player*> redBlockers = GetRedBlockers();
|
||||
std::vector<Player*> redBlockers = GetRedBlockers(botAI, bot);
|
||||
if (!redBlockers.empty())
|
||||
{
|
||||
auto it = std::find_if(redBlockers.begin(), redBlockers.end(), [](Player* p)
|
||||
auto it = std::find_if(redBlockers.begin(), redBlockers.end(), [](Player* player)
|
||||
{
|
||||
return p && p->GetGUID() == currentRedBlocker;
|
||||
return player && player->GetGUID() == currentRedBlocker;
|
||||
});
|
||||
|
||||
if (it != redBlockers.end())
|
||||
{
|
||||
redBlocker = *it;
|
||||
}
|
||||
else
|
||||
{
|
||||
redBlocker = redBlockers.front();
|
||||
}
|
||||
|
||||
currentRedBlocker = redBlocker ? redBlocker->GetGUID() : ObjectGuid::Empty;
|
||||
}
|
||||
else
|
||||
@@ -273,21 +317,19 @@ std::tuple<Player*, Player*, Player*> RaidKarazhanHelpers::GetCurrentBeamBlocker
|
||||
redBlocker = nullptr;
|
||||
}
|
||||
|
||||
std::vector<Player*> greenBlockers = GetGreenBlockers();
|
||||
std::vector<Player*> greenBlockers = GetGreenBlockers(botAI, bot);
|
||||
if (!greenBlockers.empty())
|
||||
{
|
||||
auto it = std::find_if(greenBlockers.begin(), greenBlockers.end(), [](Player* p)
|
||||
auto it = std::find_if(greenBlockers.begin(), greenBlockers.end(), [](Player* player)
|
||||
{
|
||||
return p && p->GetGUID() == currentGreenBlocker;
|
||||
return player && player->GetGUID() == currentGreenBlocker;
|
||||
});
|
||||
|
||||
if (it != greenBlockers.end())
|
||||
{
|
||||
greenBlocker = *it;
|
||||
}
|
||||
else
|
||||
{
|
||||
greenBlocker = greenBlockers.front();
|
||||
}
|
||||
|
||||
currentGreenBlocker = greenBlocker ? greenBlocker->GetGUID() : ObjectGuid::Empty;
|
||||
}
|
||||
else
|
||||
@@ -296,21 +338,19 @@ std::tuple<Player*, Player*, Player*> RaidKarazhanHelpers::GetCurrentBeamBlocker
|
||||
greenBlocker = nullptr;
|
||||
}
|
||||
|
||||
std::vector<Player*> blueBlockers = GetBlueBlockers();
|
||||
std::vector<Player*> blueBlockers = GetBlueBlockers(botAI, bot);
|
||||
if (!blueBlockers.empty())
|
||||
{
|
||||
auto it = std::find_if(blueBlockers.begin(), blueBlockers.end(), [](Player* p)
|
||||
auto it = std::find_if(blueBlockers.begin(), blueBlockers.end(), [](Player* player)
|
||||
{
|
||||
return p && p->GetGUID() == currentBlueBlocker;
|
||||
return player && player->GetGUID() == currentBlueBlocker;
|
||||
});
|
||||
|
||||
if (it != blueBlockers.end())
|
||||
{
|
||||
blueBlocker = *it;
|
||||
}
|
||||
else
|
||||
{
|
||||
blueBlocker = blueBlockers.front();
|
||||
}
|
||||
|
||||
currentBlueBlocker = blueBlocker ? blueBlocker->GetGUID() : ObjectGuid::Empty;
|
||||
}
|
||||
else
|
||||
@@ -322,7 +362,7 @@ std::tuple<Player*, Player*, Player*> RaidKarazhanHelpers::GetCurrentBeamBlocker
|
||||
return std::make_tuple(redBlocker, greenBlocker, blueBlocker);
|
||||
}
|
||||
|
||||
std::vector<Unit*> RaidKarazhanHelpers::GetAllVoidZones()
|
||||
std::vector<Unit*> GetAllVoidZones(PlayerbotAI* botAI, Player* bot)
|
||||
{
|
||||
std::vector<Unit*> voidZones;
|
||||
const float radius = 30.0f;
|
||||
@@ -331,35 +371,29 @@ std::vector<Unit*> RaidKarazhanHelpers::GetAllVoidZones()
|
||||
{
|
||||
Unit* unit = botAI->GetUnit(npcGuid);
|
||||
if (!unit || unit->GetEntry() != NPC_VOID_ZONE)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
float dist = bot->GetExactDist2d(unit);
|
||||
if (dist < radius)
|
||||
{
|
||||
voidZones.push_back(unit);
|
||||
}
|
||||
}
|
||||
|
||||
return voidZones;
|
||||
}
|
||||
|
||||
bool RaidKarazhanHelpers::IsSafePosition(float x, float y, float z,
|
||||
const std::vector<Unit*>& hazards, float hazardRadius)
|
||||
bool IsSafePosition(float x, float y, float z, const std::vector<Unit*>& hazards, float hazardRadius)
|
||||
{
|
||||
for (Unit* hazard : hazards)
|
||||
{
|
||||
float dist = std::sqrt(std::pow(x - hazard->GetPositionX(), 2) + std::pow(y - hazard->GetPositionY(), 2));
|
||||
float dist = hazard->GetExactDist2d(x, y);
|
||||
if (dist < hazardRadius)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<Unit*> RaidKarazhanHelpers::GetSpawnedInfernals() const
|
||||
std::vector<Unit*> GetSpawnedInfernals(PlayerbotAI* botAI)
|
||||
{
|
||||
std::vector<Unit*> infernals;
|
||||
const GuidVector npcs = botAI->GetAiObjectContext()->GetValue<GuidVector>("nearest npcs")->Get();
|
||||
@@ -367,15 +401,14 @@ std::vector<Unit*> RaidKarazhanHelpers::GetSpawnedInfernals() const
|
||||
{
|
||||
Unit* unit = botAI->GetUnit(npcGuid);
|
||||
if (unit && unit->GetEntry() == NPC_NETHERSPITE_INFERNAL)
|
||||
{
|
||||
infernals.push_back(unit);
|
||||
}
|
||||
}
|
||||
|
||||
return infernals;
|
||||
}
|
||||
|
||||
bool RaidKarazhanHelpers::IsStraightPathSafe(const Position& start, const Position& target, const std::vector<Unit*>& hazards, float hazardRadius, float stepSize)
|
||||
bool IsStraightPathSafe(const Position& start, const Position& target, const std::vector<Unit*>& hazards,
|
||||
float hazardRadius, float stepSize)
|
||||
{
|
||||
float sx = start.GetPositionX();
|
||||
float sy = start.GetPositionY();
|
||||
@@ -383,11 +416,10 @@ bool RaidKarazhanHelpers::IsStraightPathSafe(const Position& start, const Positi
|
||||
float tx = target.GetPositionX();
|
||||
float ty = target.GetPositionY();
|
||||
float tz = target.GetPositionZ();
|
||||
float totalDist = std::sqrt(std::pow(tx - sx, 2) + std::pow(ty - sy, 2));
|
||||
|
||||
const float totalDist = start.GetExactDist2d(target.GetPositionX(), target.GetPositionY());
|
||||
if (totalDist == 0.0f)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
for (float checkDist = 0.0f; checkDist <= totalDist; checkDist += stepSize)
|
||||
{
|
||||
@@ -397,13 +429,62 @@ bool RaidKarazhanHelpers::IsStraightPathSafe(const Position& start, const Positi
|
||||
float checkZ = sz + (tz - sz) * t;
|
||||
for (Unit* hazard : hazards)
|
||||
{
|
||||
float hazardDist = std::sqrt(std::pow(checkX - hazard->GetPositionX(), 2) + std::pow(checkY - hazard->GetPositionY(), 2));
|
||||
if (hazardDist < hazardRadius)
|
||||
{
|
||||
const float hx = checkX - hazard->GetPositionX();
|
||||
const float hy = checkY - hazard->GetPositionY();
|
||||
if ((hx*hx + hy*hy) < hazardRadius * hazardRadius)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TryFindSafePositionWithSafePath(
|
||||
Player* bot, float originX, float originY, float originZ, float centerX, float centerY, float centerZ,
|
||||
const std::vector<Unit*>& hazards, float safeDistance, float stepSize, uint8 numAngles,
|
||||
float maxSampleDist, bool requireSafePath, float& bestDestX, float& bestDestY, float& bestDestZ)
|
||||
{
|
||||
float bestMoveDist = std::numeric_limits<float>::max();
|
||||
bool found = false;
|
||||
|
||||
for (int i = 0; i < numAngles; ++i)
|
||||
{
|
||||
float angle = (2.0f * M_PI * i) / numAngles;
|
||||
float dx = cos(angle);
|
||||
float dy = sin(angle);
|
||||
|
||||
for (float dist = stepSize; dist <= maxSampleDist; dist += stepSize)
|
||||
{
|
||||
float x = centerX + dx * dist;
|
||||
float y = centerY + dy * dist;
|
||||
float z = centerZ;
|
||||
float destX = x, destY = y, destZ = z;
|
||||
if (!bot->GetMap()->CheckCollisionAndGetValidCoords(bot, centerX, centerY, centerZ,
|
||||
destX, destY, destZ, true))
|
||||
continue;
|
||||
|
||||
if (!IsSafePosition(destX, destY, destZ, hazards, safeDistance))
|
||||
continue;
|
||||
|
||||
if (requireSafePath)
|
||||
{
|
||||
if (!IsStraightPathSafe(Position(originX, originY, originZ), Position(destX, destY, destZ),
|
||||
hazards, safeDistance, stepSize))
|
||||
continue;
|
||||
}
|
||||
|
||||
const float moveDist = Position(originX, originY, originZ).GetExactDist2d(destX, destY);
|
||||
if (moveDist < bestMoveDist)
|
||||
{
|
||||
bestMoveDist = moveDist;
|
||||
bestDestX = destX;
|
||||
bestDestY = destY;
|
||||
bestDestZ = destZ;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
#ifndef _PLAYERBOT_RAIDKARAZHANHELPERS_H_
|
||||
#define _PLAYERBOT_RAIDKARAZHANHELPERS_H_
|
||||
|
||||
#include "AiObject.h"
|
||||
#include "Playerbots.h"
|
||||
#include "Position.h"
|
||||
#include <ctime>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "AiObject.h"
|
||||
#include "Position.h"
|
||||
#include "Unit.h"
|
||||
|
||||
namespace KarazhanHelpers
|
||||
{
|
||||
enum KarazhanSpells
|
||||
{
|
||||
// Maiden of Virtue
|
||||
@@ -13,73 +18,119 @@ enum KarazhanSpells
|
||||
// Opera Event
|
||||
SPELL_LITTLE_RED_RIDING_HOOD = 30756,
|
||||
|
||||
// The Curator
|
||||
SPELL_CURATOR_EVOCATION = 30254,
|
||||
|
||||
// Shade of Aran
|
||||
SPELL_FLAME_WREATH = 30004,
|
||||
SPELL_AURA_FLAME_WREATH = 29946,
|
||||
SPELL_FLAME_WREATH_CAST = 30004,
|
||||
SPELL_FLAME_WREATH_AURA = 29946,
|
||||
SPELL_ARCANE_EXPLOSION = 29973,
|
||||
SPELL_WARLOCK_BANISH = 18647, // Rank 2
|
||||
|
||||
// Netherspite
|
||||
SPELL_GREEN_BEAM_DEBUFF = 30422,
|
||||
SPELL_BLUE_BEAM_DEBUFF = 30423,
|
||||
SPELL_RED_BEAM_DEBUFF = 30421, // "Nether Portal - Perseverance" (player aura)
|
||||
SPELL_GREEN_BEAM_DEBUFF = 30422, // "Nether Portal - Serenity" (player aura)
|
||||
SPELL_BLUE_BEAM_DEBUFF = 30423, // "Nether Portal - Dominance" (player aura)
|
||||
SPELL_GREEN_BEAM_HEAL = 30467, // "Nether Portal - Serenity" (Netherspite aura)
|
||||
SPELL_NETHER_EXHAUSTION_RED = 38637,
|
||||
SPELL_NETHER_EXHAUSTION_GREEN = 38638,
|
||||
SPELL_NETHER_EXHAUSTION_BLUE = 38639,
|
||||
SPELL_NETHERSPITE_BANISHED = 39833,
|
||||
SPELL_NETHERSPITE_BANISHED = 39833, // "Vortex Shade Black"
|
||||
|
||||
// Prince Malchezaar
|
||||
SPELL_ENFEEBLE = 30843,
|
||||
|
||||
// Nightbane
|
||||
SPELL_CHARRED_EARTH = 30129,
|
||||
SPELL_BELLOWING_ROAR = 36922,
|
||||
SPELL_RAIN_OF_BONES = 37091,
|
||||
|
||||
// Warlock
|
||||
SPELL_WARLOCK_BANISH = 18647,
|
||||
|
||||
// Priest
|
||||
SPELL_FEAR_WARD = 6346,
|
||||
};
|
||||
|
||||
enum KarazhanNpcs
|
||||
enum KarazhanNPCs
|
||||
{
|
||||
// Attumen the Huntsman
|
||||
NPC_ATTUMEN_THE_HUNTSMAN_MOUNTED = 16152,
|
||||
// Trash
|
||||
NPC_SPECTRAL_RETAINER = 16410,
|
||||
NPC_MANA_WARP = 16530,
|
||||
|
||||
// Terestian Illhoof
|
||||
NPC_KILREK = 17229,
|
||||
NPC_DEMON_CHAINS = 17248,
|
||||
// Attumen the Huntsman
|
||||
NPC_ATTUMEN_THE_HUNTSMAN = 15550,
|
||||
NPC_ATTUMEN_THE_HUNTSMAN_MOUNTED = 16152,
|
||||
|
||||
// Shade of Aran
|
||||
NPC_CONJURED_ELEMENTAL = 17167,
|
||||
|
||||
// Netherspite
|
||||
NPC_VOID_ZONE = 16697,
|
||||
NPC_RED_PORTAL = 17369,
|
||||
NPC_BLUE_PORTAL = 17368,
|
||||
NPC_GREEN_PORTAL = 17367,
|
||||
NPC_GREEN_PORTAL = 17367, // "Nether Portal - Serenity <Healing Portal>"
|
||||
NPC_BLUE_PORTAL = 17368, // "Nether Portal - Dominance <Damage Portal>"
|
||||
NPC_RED_PORTAL = 17369, // "Nether Portal - Perseverance <Tanking Portal>"
|
||||
|
||||
// Prince Malchezaar
|
||||
NPC_NETHERSPITE_INFERNAL = 17646,
|
||||
};
|
||||
|
||||
extern const Position KARAZHAN_MAIDEN_OF_VIRTUE_BOSS_POSITION;
|
||||
extern const Position KARAZHAN_MAIDEN_OF_VIRTUE_RANGED_POSITION[8];
|
||||
extern const Position KARAZHAN_BIG_BAD_WOLF_BOSS_POSITION;
|
||||
extern const Position KARAZHAN_BIG_BAD_WOLF_RUN_POSITION[4];
|
||||
extern const Position KARAZHAN_THE_CURATOR_BOSS_POSITION;
|
||||
const uint32 KARAZHAN_MAP_ID = 532;
|
||||
const float NIGHTBANE_FLIGHT_Z = 95.0f;
|
||||
|
||||
class RaidKarazhanHelpers : public AiObject
|
||||
{
|
||||
public:
|
||||
explicit RaidKarazhanHelpers(PlayerbotAI* botAI) : AiObject(botAI) {}
|
||||
// Attumen the Huntsman
|
||||
extern std::unordered_map<uint32, time_t> attumenDpsWaitTimer;
|
||||
// Big Bad Wolf
|
||||
extern std::unordered_map<ObjectGuid, uint8> bigBadWolfRunIndex;
|
||||
// Netherspite
|
||||
extern std::unordered_map<uint32, time_t> netherspiteDpsWaitTimer;
|
||||
extern std::unordered_map<ObjectGuid, time_t> redBeamMoveTimer;
|
||||
extern std::unordered_map<ObjectGuid, bool> lastBeamMoveSideways;
|
||||
// Nightbane
|
||||
extern std::unordered_map<uint32, time_t> nightbaneDpsWaitTimer;
|
||||
extern std::unordered_map<ObjectGuid, uint8> nightbaneTankStep;
|
||||
extern std::unordered_map<ObjectGuid, uint8> nightbaneRangedStep;
|
||||
extern std::unordered_map<uint32, time_t> nightbaneFlightPhaseStartTimer;
|
||||
extern std::unordered_map<ObjectGuid, bool> nightbaneRainOfBonesHit;
|
||||
|
||||
void MarkTargetWithSkull(Unit* /*target*/);
|
||||
Unit* GetFirstAliveUnit(const std::vector<Unit*>& /*units*/);
|
||||
Unit* GetFirstAliveUnitByEntry(uint32 /*entry*/);
|
||||
Unit* GetNearestPlayerInRadius(float /*radius*/ = 5.0f);
|
||||
bool IsFlameWreathActive();
|
||||
Position GetPositionOnBeam(Unit* boss, Unit* portal, float distanceFromBoss);
|
||||
std::vector<Player*> GetRedBlockers();
|
||||
std::vector<Player*> GetBlueBlockers();
|
||||
std::vector<Player*> GetGreenBlockers();
|
||||
std::tuple<Player*, Player*, Player*> GetCurrentBeamBlockers();
|
||||
std::vector<Unit*> GetAllVoidZones();
|
||||
bool IsSafePosition (float x, float y, float z,
|
||||
const std::vector<Unit*>& hazards, float hazardRadius);
|
||||
std::vector<Unit*> GetSpawnedInfernals() const;
|
||||
bool IsStraightPathSafe(const Position& start, const Position& target,
|
||||
extern const Position MAIDEN_OF_VIRTUE_BOSS_POSITION;
|
||||
extern const Position MAIDEN_OF_VIRTUE_RANGED_POSITION[8];
|
||||
extern const Position BIG_BAD_WOLF_BOSS_POSITION;
|
||||
extern const Position BIG_BAD_WOLF_RUN_POSITION[4];
|
||||
extern const Position THE_CURATOR_BOSS_POSITION;
|
||||
extern const Position NIGHTBANE_TRANSITION_BOSS_POSITION;
|
||||
extern const Position NIGHTBANE_FINAL_BOSS_POSITION;
|
||||
extern const Position NIGHTBANE_RANGED_POSITION1;
|
||||
extern const Position NIGHTBANE_RANGED_POSITION2;
|
||||
extern const Position NIGHTBANE_RANGED_POSITION3;
|
||||
extern const Position NIGHTBANE_FLIGHT_STACK_POSITION;
|
||||
extern const Position NIGHTBANE_RAIN_OF_BONES_POSITION;
|
||||
|
||||
void MarkTargetWithIcon(Player* bot, Unit* target, uint8 iconId);
|
||||
void MarkTargetWithSkull(Player* bot, Unit* target);
|
||||
void MarkTargetWithSquare(Player* bot, Unit* target);
|
||||
void MarkTargetWithStar(Player* bot, Unit* target);
|
||||
void MarkTargetWithCircle(Player* bot, Unit* target);
|
||||
void MarkTargetWithMoon(Player* bot, Unit* target);
|
||||
void SetRtiTarget(PlayerbotAI* botAI, const std::string& rtiName, Unit* target);
|
||||
bool IsMapIDTimerManager(PlayerbotAI* botAI, Player* bot);
|
||||
Unit* GetFirstAliveUnit(const std::vector<Unit*>& units);
|
||||
Unit* GetFirstAliveUnitByEntry(PlayerbotAI* botAI, uint32 entry);
|
||||
Unit* GetNearestPlayerInRadius(Player* bot, float radius);
|
||||
bool IsFlameWreathActive(PlayerbotAI* botAI, Player* bot);
|
||||
std::vector<Player*> GetRedBlockers(PlayerbotAI* botAI, Player* bot);
|
||||
std::vector<Player*> GetBlueBlockers(PlayerbotAI* botAI, Player* bot);
|
||||
std::vector<Player*> GetGreenBlockers(PlayerbotAI* botAI, Player* bot);
|
||||
std::tuple<Player*, Player*, Player*> GetCurrentBeamBlockers(PlayerbotAI* botAI, Player* bot);
|
||||
std::vector<Unit*> GetAllVoidZones(PlayerbotAI *botAI, Player* bot);
|
||||
bool IsSafePosition (float x, float y, float z, const std::vector<Unit*>& hazards, float hazardRadius);
|
||||
std::vector<Unit*> GetSpawnedInfernals(PlayerbotAI* botAI);
|
||||
bool IsStraightPathSafe(
|
||||
const Position& start, const Position& target,
|
||||
const std::vector<Unit*>& hazards, float hazardRadius, float stepSize);
|
||||
};
|
||||
bool TryFindSafePositionWithSafePath(
|
||||
Player* bot, float originX, float originY, float originZ, float centerX, float centerY, float centerZ,
|
||||
const std::vector<Unit*>& hazards, float safeDistance, float stepSize, uint8 numAngles,
|
||||
float maxSampleDist, bool requireSafePath, float& bestDestX, float& bestDestY, float& bestDestZ);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,48 +1,76 @@
|
||||
#include "RaidKarazhanMultipliers.h"
|
||||
#include "RaidKarazhanActions.h"
|
||||
#include "RaidKarazhanHelpers.h"
|
||||
#include "AiObjectContext.h"
|
||||
#include "AttackAction.h"
|
||||
#include "DruidBearActions.h"
|
||||
#include "DruidCatActions.h"
|
||||
#include "ChooseTargetActions.h"
|
||||
#include "DruidActions.h"
|
||||
#include "FollowActions.h"
|
||||
#include "GenericActions.h"
|
||||
#include "HunterActions.h"
|
||||
#include "MageActions.h"
|
||||
#include "Playerbots.h"
|
||||
#include "PriestActions.h"
|
||||
#include "ReachTargetActions.h"
|
||||
#include "RogueActions.h"
|
||||
#include "WarriorActions.h"
|
||||
#include "ShamanActions.h"
|
||||
|
||||
static bool IsChargeAction(Action* action)
|
||||
using namespace KarazhanHelpers;
|
||||
|
||||
// Keep tanks from jumping back and forth between Attumen and Midnight
|
||||
float AttumenTheHuntsmanDisableTankAssistMultiplier::GetValue(Action* action)
|
||||
{
|
||||
return dynamic_cast<CastChargeAction*>(action) ||
|
||||
dynamic_cast<CastInterceptAction*>(action) ||
|
||||
dynamic_cast<CastFeralChargeBearAction*>(action) ||
|
||||
dynamic_cast<CastFeralChargeCatAction*>(action);
|
||||
Unit* midnight = AI_VALUE2(Unit*, "find target", "midnight");
|
||||
if (!midnight)
|
||||
return 1.0f;
|
||||
|
||||
Unit* attumen = AI_VALUE2(Unit*, "find target", "attumen the huntsman");
|
||||
if (!attumen)
|
||||
return 1.0f;
|
||||
|
||||
if (bot->GetVictim() != nullptr && dynamic_cast<TankAssistAction*>(action))
|
||||
return 0.0f;
|
||||
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
float KarazhanAttumenTheHuntsmanMultiplier::GetValue(Action* action)
|
||||
// Try to get rid of jittering when bots are stacked behind Attumen
|
||||
float AttumenTheHuntsmanStayStackedMultiplier::GetValue(Action* action)
|
||||
{
|
||||
RaidKarazhanHelpers karazhanHelper(botAI);
|
||||
Unit* boss = karazhanHelper.GetFirstAliveUnitByEntry(NPC_ATTUMEN_THE_HUNTSMAN_MOUNTED);
|
||||
if (boss && !(botAI->IsTank(bot) && botAI->HasAggro(boss) && boss->GetVictim() == bot) &&
|
||||
(dynamic_cast<MovementAction*>(action) &&
|
||||
!dynamic_cast<KarazhanAttumenTheHuntsmanStackBehindAction*>(action)))
|
||||
Unit* attumenMounted = GetFirstAliveUnitByEntry(botAI, NPC_ATTUMEN_THE_HUNTSMAN_MOUNTED);
|
||||
if (!attumenMounted)
|
||||
return 1.0f;
|
||||
|
||||
if (!botAI->IsMainTank(bot) && attumenMounted->GetVictim() != bot)
|
||||
{
|
||||
if (dynamic_cast<CombatFormationMoveAction*>(action) ||
|
||||
dynamic_cast<FleeAction*>(action) ||
|
||||
dynamic_cast<CastBlinkBackAction*>(action) ||
|
||||
dynamic_cast<CastDisengageAction*>(action) ||
|
||||
dynamic_cast<CastReachTargetSpellAction*>(action))
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
float KarazhanBigBadWolfMultiplier::GetValue(Action* action)
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "the big bad wolf");
|
||||
if (!boss)
|
||||
// Give the main tank 8 seconds to grab aggro when Attumen mounts Midnight
|
||||
// In reality it's shorter because it takes Attumen a few seconds to aggro after mounting
|
||||
float AttumenTheHuntsmanWaitForDpsMultiplier::GetValue(Action* action)
|
||||
{
|
||||
Unit* attumenMounted = GetFirstAliveUnitByEntry(botAI, NPC_ATTUMEN_THE_HUNTSMAN_MOUNTED);
|
||||
if (!attumenMounted)
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
if (bot->HasAura(SPELL_LITTLE_RED_RIDING_HOOD))
|
||||
const time_t now = std::time(nullptr);
|
||||
const uint8 dpsWaitSeconds = 8;
|
||||
|
||||
auto it = attumenDpsWaitTimer.find(KARAZHAN_MAP_ID);
|
||||
if (it == attumenDpsWaitTimer.end() || (now - it->second) < dpsWaitSeconds)
|
||||
{
|
||||
if ((dynamic_cast<MovementAction*>(action) && !dynamic_cast<KarazhanBigBadWolfRunAwayAction*>(action)) ||
|
||||
(dynamic_cast<AttackAction*>(action)))
|
||||
if (!botAI->IsMainTank(bot))
|
||||
{
|
||||
if (dynamic_cast<AttackAction*>(action) || (dynamic_cast<CastSpellAction*>(action) &&
|
||||
!dynamic_cast<CastHealingSpellAction*>(action)))
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
@@ -50,48 +78,56 @@ float KarazhanBigBadWolfMultiplier::GetValue(Action* action)
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
float KarazhanShadeOfAranMultiplier::GetValue(Action* action)
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "shade of aran");
|
||||
if (!boss)
|
||||
// The assist tank should stay on the boss to be 2nd on aggro and tank Hateful Bolts
|
||||
float TheCuratorDisableTankAssistMultiplier::GetValue(Action* action)
|
||||
{
|
||||
Unit* curator = AI_VALUE2(Unit*, "find target", "the curator");
|
||||
if (!curator)
|
||||
return 1.0f;
|
||||
|
||||
if (bot->GetVictim() != nullptr && dynamic_cast<TankAssistAction*>(action))
|
||||
return 0.0f;
|
||||
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
if (boss->HasUnitState(UNIT_STATE_CASTING) && boss->FindCurrentSpellBySpellId(SPELL_ARCANE_EXPLOSION))
|
||||
// Save Bloodlust/Heroism for Evocation (100% increased damage)
|
||||
float TheCuratorDelayBloodlustAndHeroismMultiplier::GetValue(Action* action)
|
||||
{
|
||||
if (IsChargeAction(action))
|
||||
Unit* curator = AI_VALUE2(Unit*, "find target", "the curator");
|
||||
if (!curator)
|
||||
return 1.0f;
|
||||
|
||||
if (!curator->HasAura(SPELL_CURATOR_EVOCATION))
|
||||
{
|
||||
if (dynamic_cast<CastBloodlustAction*>(action) ||
|
||||
dynamic_cast<CastHeroismAction*>(action))
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
if (dynamic_cast<MovementAction*>(action))
|
||||
{
|
||||
const float safeDistance = 20.0f;
|
||||
if (bot->GetDistance2d(boss) >= safeDistance)
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
bool flameWreathActive = boss->HasAura(SPELL_FLAME_WREATH);
|
||||
if (!flameWreathActive && bot->GetGroup())
|
||||
// Don't charge back in when running from Arcane Explosion
|
||||
float ShadeOfAranArcaneExplosionDisableChargeMultiplier::GetValue(Action* action)
|
||||
{
|
||||
for (GroupReference* itr = bot->GetGroup()->GetFirstMember(); itr != nullptr; itr = itr->next())
|
||||
Unit* aran = AI_VALUE2(Unit*, "find target", "shade of aran");
|
||||
if (!aran)
|
||||
return 1.0f;
|
||||
|
||||
if (aran->HasUnitState(UNIT_STATE_CASTING) &&
|
||||
aran->FindCurrentSpellBySpellId(SPELL_ARCANE_EXPLOSION))
|
||||
{
|
||||
Player* member = itr->GetSource();
|
||||
if (member && member->HasAura(SPELL_AURA_FLAME_WREATH))
|
||||
{
|
||||
flameWreathActive = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (flameWreathActive)
|
||||
{
|
||||
if (dynamic_cast<MovementAction*>(action) || IsChargeAction(action))
|
||||
if (dynamic_cast<CastReachTargetSpellAction*>(action))
|
||||
return 0.0f;
|
||||
|
||||
if (bot->GetDistance2d(aran) >= 20.0f)
|
||||
{
|
||||
if (dynamic_cast<CombatFormationMoveAction*>(action) ||
|
||||
dynamic_cast<FleeAction*>(action) ||
|
||||
dynamic_cast<FollowAction*>(action) ||
|
||||
dynamic_cast<ReachTargetAction*>(action) ||
|
||||
dynamic_cast<AvoidAoeAction*>(action))
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
@@ -99,166 +135,224 @@ float KarazhanShadeOfAranMultiplier::GetValue(Action* action)
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
float KarazhanNetherspiteBlueAndGreenBeamMultiplier::GetValue(Action* action)
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "netherspite");
|
||||
if (!boss || !boss->IsAlive())
|
||||
// I will not move when Flame Wreath is cast or the raid blows up
|
||||
float ShadeOfAranFlameWreathDisableMovementMultiplier::GetValue(Action* action)
|
||||
{
|
||||
Unit* aran = AI_VALUE2(Unit*, "find target", "shade of aran");
|
||||
if (!aran)
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
if (dynamic_cast<AvoidAoeAction*>(action) || dynamic_cast<CastKillingSpreeAction*>(action))
|
||||
if (IsFlameWreathActive(botAI, bot))
|
||||
{
|
||||
if (dynamic_cast<CombatFormationMoveAction*>(action) ||
|
||||
dynamic_cast<FleeAction*>(action) ||
|
||||
dynamic_cast<FollowAction*>(action) ||
|
||||
dynamic_cast<ReachTargetAction*>(action) ||
|
||||
dynamic_cast<AvoidAoeAction*>(action) ||
|
||||
dynamic_cast<CastKillingSpreeAction*>(action) ||
|
||||
dynamic_cast<CastBlinkBackAction*>(action) ||
|
||||
dynamic_cast<CastDisengageAction*>(action) ||
|
||||
dynamic_cast<CastReachTargetSpellAction*>(action))
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
RaidKarazhanHelpers karazhanHelper(botAI);
|
||||
auto [redBlocker /*unused*/, greenBlocker, blueBlocker] = karazhanHelper.GetCurrentBeamBlockers();
|
||||
bool isBlocker = (bot == greenBlocker || bot == blueBlocker);
|
||||
if (isBlocker)
|
||||
{
|
||||
Unit* bluePortal = bot->FindNearestCreature(NPC_BLUE_PORTAL, 150.0f);
|
||||
Unit* greenPortal = bot->FindNearestCreature(NPC_GREEN_PORTAL, 150.0f);
|
||||
bool inBeam = false;
|
||||
for (Unit* portal : {bluePortal, greenPortal})
|
||||
{
|
||||
if (!portal)
|
||||
{
|
||||
continue;
|
||||
return 1.0f;
|
||||
}
|
||||
float bx = boss->GetPositionX(), by = boss->GetPositionY();
|
||||
float px = portal->GetPositionX(), py = portal->GetPositionY();
|
||||
float dx = px - bx, dy = py - by;
|
||||
float length = sqrt(dx*dx + dy*dy);
|
||||
if (length == 0.0f)
|
||||
|
||||
// Try to rid of the jittering when blocking beams
|
||||
float NetherspiteKeepBlockingBeamMultiplier::GetValue(Action* action)
|
||||
{
|
||||
continue;
|
||||
Unit* netherspite = AI_VALUE2(Unit*, "find target", "netherspite");
|
||||
if (!netherspite || netherspite->HasAura(SPELL_NETHERSPITE_BANISHED))
|
||||
return 1.0f;
|
||||
|
||||
auto [redBlocker, greenBlocker, blueBlocker] = GetCurrentBeamBlockers(botAI, bot);
|
||||
|
||||
if (bot == redBlocker)
|
||||
{
|
||||
if (dynamic_cast<CombatFormationMoveAction*>(action))
|
||||
return 0.0f;
|
||||
}
|
||||
dx /= length; dy /= length;
|
||||
float botdx = bot->GetPositionX() - bx, botdy = bot->GetPositionY() - by;
|
||||
float t = (botdx * dx + botdy * dy);
|
||||
float beamX = bx + dx * t, beamY = by + dy * t;
|
||||
float distToBeam = sqrt(pow(bot->GetPositionX() - beamX, 2) + pow(bot->GetPositionY() - beamY, 2));
|
||||
if (distToBeam < 0.3f && t > 0.0f && t < length)
|
||||
|
||||
if (bot == blueBlocker)
|
||||
{
|
||||
inBeam = true;
|
||||
break;
|
||||
if (dynamic_cast<CombatFormationMoveAction*>(action) ||
|
||||
dynamic_cast<ReachTargetAction*>(action))
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
if (bot == greenBlocker)
|
||||
{
|
||||
if (dynamic_cast<CombatFormationMoveAction*>(action) ||
|
||||
dynamic_cast<ReachTargetAction*>(action) ||
|
||||
dynamic_cast<FleeAction*>(action) ||
|
||||
dynamic_cast<CastKillingSpreeAction*>(action) ||
|
||||
dynamic_cast<CastReachTargetSpellAction*>(action))
|
||||
return 0.0f;
|
||||
}
|
||||
if (inBeam)
|
||||
{
|
||||
std::vector<Unit*> voidZones = karazhanHelper.GetAllVoidZones();
|
||||
bool inVoidZone = false;
|
||||
for (Unit* vz : voidZones)
|
||||
{
|
||||
if (bot->GetExactDist2d(vz) < 4.0f)
|
||||
{
|
||||
inVoidZone = true;
|
||||
break;
|
||||
|
||||
return 1.0f;
|
||||
}
|
||||
}
|
||||
if (!inVoidZone)
|
||||
|
||||
// Give tanks 5 seconds to get aggro during phase transitions
|
||||
float NetherspiteWaitForDpsMultiplier::GetValue(Action* action)
|
||||
{
|
||||
if (dynamic_cast<MovementAction*>(action) || IsChargeAction(action))
|
||||
Unit* netherspite = AI_VALUE2(Unit*, "find target", "netherspite");
|
||||
if (!netherspite || netherspite->HasAura(SPELL_NETHERSPITE_BANISHED))
|
||||
return 1.0f;
|
||||
|
||||
const time_t now = std::time(nullptr);
|
||||
const uint8 dpsWaitSeconds = 5;
|
||||
|
||||
auto it = netherspiteDpsWaitTimer.find(KARAZHAN_MAP_ID);
|
||||
if (it == netherspiteDpsWaitTimer.end() || (now - it->second) < dpsWaitSeconds)
|
||||
{
|
||||
if (!botAI->IsTank(bot))
|
||||
{
|
||||
if (dynamic_cast<AttackAction*>(action) || (dynamic_cast<CastSpellAction*>(action) &&
|
||||
!dynamic_cast<CastHealingSpellAction*>(action)))
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
float KarazhanNetherspiteRedBeamMultiplier::GetValue(Action* action)
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "netherspite");
|
||||
if (!boss || !boss->IsAlive())
|
||||
// Disable standard "avoid aoe" strategy, which may interfere with scripted avoidance
|
||||
float PrinceMalchezaarDisableAvoidAoeMultiplier::GetValue(Action* action)
|
||||
{
|
||||
Unit* malchezaar = AI_VALUE2(Unit*, "find target", "prince malchezaar");
|
||||
if (!malchezaar)
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
if (dynamic_cast<AvoidAoeAction*>(action))
|
||||
return 0.0f;
|
||||
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
// Don't run back into Shadow Nova when Enfeebled
|
||||
float PrinceMalchezaarEnfeebleKeepDistanceMultiplier::GetValue(Action* action)
|
||||
{
|
||||
Unit* malchezaar = AI_VALUE2(Unit*, "find target", "prince malchezaar");
|
||||
if (!malchezaar)
|
||||
return 1.0f;
|
||||
|
||||
if (bot->HasAura(SPELL_ENFEEBLE))
|
||||
{
|
||||
if (dynamic_cast<MovementAction*>(action) &&
|
||||
!dynamic_cast<PrinceMalchezaarEnfeebledAvoidHazardAction*>(action))
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
RaidKarazhanHelpers karazhanHelper(botAI);
|
||||
auto [redBlocker, greenBlocker /*unused*/, blueBlocker /*unused*/] = karazhanHelper.GetCurrentBeamBlockers();
|
||||
static std::map<ObjectGuid, uint32> beamMoveTimes;
|
||||
static std::map<ObjectGuid, bool> lastBeamMoveSideways;
|
||||
ObjectGuid botGuid = bot->GetGUID();
|
||||
Unit* redPortal = bot->FindNearestCreature(NPC_RED_PORTAL, 150.0f);
|
||||
if (bot == redBlocker && boss && redPortal)
|
||||
{
|
||||
Position blockingPos = karazhanHelper.GetPositionOnBeam(boss, redPortal, 18.0f);
|
||||
float bx = boss->GetPositionX();
|
||||
float by = boss->GetPositionY();
|
||||
float px = redPortal->GetPositionX();
|
||||
float py = redPortal->GetPositionY();
|
||||
float dx = px - bx;
|
||||
float dy = py - by;
|
||||
float length = sqrt(dx*dx + dy*dy);
|
||||
if (length != 0.0f)
|
||||
{
|
||||
dx /= length;
|
||||
dy /= length;
|
||||
float perpDx = -dy;
|
||||
float perpDy = dx;
|
||||
Position sidewaysPos(blockingPos.GetPositionX() + perpDx * 3.0f,
|
||||
blockingPos.GetPositionY() + perpDy * 3.0f,
|
||||
blockingPos.GetPositionZ());
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
uint32 intervalSecs = 5;
|
||||
if (beamMoveTimes[botGuid] == 0)
|
||||
// Wait until Phase 3 to use Bloodlust/Heroism
|
||||
float PrinceMalchezaarDelayBloodlustAndHeroismMultiplier::GetValue(Action* action)
|
||||
{
|
||||
beamMoveTimes[botGuid] = time(nullptr);
|
||||
lastBeamMoveSideways[botGuid] = false;
|
||||
}
|
||||
if (time(nullptr) - beamMoveTimes[botGuid] >= intervalSecs)
|
||||
{
|
||||
lastBeamMoveSideways[botGuid] = !lastBeamMoveSideways[botGuid];
|
||||
beamMoveTimes[botGuid] = time(nullptr);
|
||||
}
|
||||
Position targetPos = lastBeamMoveSideways[botGuid] ? sidewaysPos : blockingPos;
|
||||
float distToTarget = bot->GetExactDist2d(targetPos.GetPositionX(), targetPos.GetPositionY());
|
||||
const float positionTolerance = 1.5f;
|
||||
if (distToTarget < positionTolerance)
|
||||
{
|
||||
if (dynamic_cast<MovementAction*>(action) || IsChargeAction(action))
|
||||
Unit* malchezaar = AI_VALUE2(Unit*, "find target", "prince malchezaar");
|
||||
if (!malchezaar)
|
||||
return 1.0f;
|
||||
|
||||
if (malchezaar->GetHealthPct() > 30.0f)
|
||||
{
|
||||
if (dynamic_cast<CastBloodlustAction*>(action) ||
|
||||
dynamic_cast<CastHeroismAction*>(action))
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
// Pets tend to run out of bounds and cause skeletons to spawn off the map
|
||||
// Pets also tend to pull adds from inside of the tower through the floor
|
||||
// This multiplier DOES NOT impact Hunter and Warlock pets
|
||||
// Hunter and Warlock pets are addressed in ControlPetAggressionAction
|
||||
float NightbaneDisablePetsMultiplier::GetValue(Action* action)
|
||||
{
|
||||
Unit* nightbane = AI_VALUE2(Unit*, "find target", "nightbane");
|
||||
if (!nightbane)
|
||||
return 1.0f;
|
||||
|
||||
if (dynamic_cast<CastForceOfNatureAction*>(action) ||
|
||||
dynamic_cast<CastFeralSpiritAction*>(action) ||
|
||||
dynamic_cast<CastFireElementalTotemAction*>(action) ||
|
||||
dynamic_cast<CastFireElementalTotemMeleeAction*>(action) ||
|
||||
dynamic_cast<CastSummonWaterElementalAction*>(action) ||
|
||||
dynamic_cast<CastShadowfiendAction*>(action))
|
||||
return 0.0f;
|
||||
|
||||
if (nightbane->GetPositionZ() > NIGHTBANE_FLIGHT_Z)
|
||||
{
|
||||
if (dynamic_cast<PetAttackAction*>(action))
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
// Give the main tank 8 seconds to get aggro during phase transitions
|
||||
float NightbaneWaitForDpsMultiplier::GetValue(Action* action)
|
||||
{
|
||||
Unit* nightbane = AI_VALUE2(Unit*, "find target", "nightbane");
|
||||
if (!nightbane || nightbane->GetPositionZ() > NIGHTBANE_FLIGHT_Z)
|
||||
return 1.0f;
|
||||
|
||||
const time_t now = std::time(nullptr);
|
||||
const uint8 dpsWaitSeconds = 8;
|
||||
|
||||
auto it = nightbaneDpsWaitTimer.find(KARAZHAN_MAP_ID);
|
||||
if (it == nightbaneDpsWaitTimer.end() || (now - it->second) < dpsWaitSeconds)
|
||||
{
|
||||
if (!botAI->IsMainTank(bot))
|
||||
{
|
||||
if (dynamic_cast<AttackAction*>(action) || (dynamic_cast<CastSpellAction*>(action) &&
|
||||
!dynamic_cast<CastHealingSpellAction*>(action)))
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
float KarazhanPrinceMalchezaarMultiplier::GetValue(Action* action)
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "prince malchezaar");
|
||||
if (!boss || !boss->IsAlive())
|
||||
// The "avoid aoe" strategy must be disabled for the main tank
|
||||
// Otherwise, the main tank will spin Nightbane to avoid Charred Earth and wipe the raid
|
||||
// It is also disabled for all bots during the flight phase
|
||||
float NightbaneDisableAvoidAoeMultiplier::GetValue(Action* action)
|
||||
{
|
||||
Unit* nightbane = AI_VALUE2(Unit*, "find target", "nightbane");
|
||||
if (!nightbane)
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
if (nightbane->GetPositionZ() > NIGHTBANE_FLIGHT_Z || botAI->IsMainTank(bot))
|
||||
{
|
||||
if (dynamic_cast<AvoidAoeAction*>(action))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
if (botAI->IsMelee(bot) && bot->HasAura(SPELL_ENFEEBLE) &&
|
||||
!dynamic_cast<KarazhanPrinceMalchezaarNonTankAvoidHazardAction*>(action))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
if (botAI->IsRanged(bot) && bot->HasAura(SPELL_ENFEEBLE) &&
|
||||
(dynamic_cast<MovementAction*>(action) &&
|
||||
!dynamic_cast<KarazhanPrinceMalchezaarNonTankAvoidHazardAction*>(action)))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
// Disable some movement actions that conflict with the strategies
|
||||
float NightbaneDisableMovementMultiplier::GetValue(Action* action)
|
||||
{
|
||||
Unit* nightbane = AI_VALUE2(Unit*, "find target", "nightbane");
|
||||
if (!nightbane)
|
||||
return 1.0f;
|
||||
|
||||
if (dynamic_cast<CastBlinkBackAction*>(action) ||
|
||||
dynamic_cast<CastDisengageAction*>(action) ||
|
||||
dynamic_cast<FleeAction*>(action))
|
||||
return 0.0f;
|
||||
|
||||
// Disable CombatFormationMoveAction for all bots except:
|
||||
// (1) main tank and (2) only during the ground phase, other melee
|
||||
if (botAI->IsRanged(bot) ||
|
||||
(botAI->IsMelee(bot) && !botAI->IsMainTank(bot) &&
|
||||
nightbane->GetPositionZ() > NIGHTBANE_FLIGHT_Z))
|
||||
{
|
||||
if (dynamic_cast<CombatFormationMoveAction*>(action))
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,45 +3,131 @@
|
||||
|
||||
#include "Multiplier.h"
|
||||
|
||||
class KarazhanAttumenTheHuntsmanMultiplier : public Multiplier
|
||||
class AttumenTheHuntsmanDisableTankAssistMultiplier : public Multiplier
|
||||
{
|
||||
public:
|
||||
KarazhanAttumenTheHuntsmanMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "karazhan attumen the huntsman multiplier") {}
|
||||
AttumenTheHuntsmanDisableTankAssistMultiplier(
|
||||
PlayerbotAI* botAI) : Multiplier(botAI, "attumen the huntsman disable tank assist multiplier") {}
|
||||
virtual float GetValue(Action* action);
|
||||
};
|
||||
|
||||
class KarazhanBigBadWolfMultiplier : public Multiplier
|
||||
class AttumenTheHuntsmanStayStackedMultiplier : public Multiplier
|
||||
{
|
||||
public:
|
||||
KarazhanBigBadWolfMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "karazhan big bad wolf multiplier") {}
|
||||
AttumenTheHuntsmanStayStackedMultiplier(
|
||||
PlayerbotAI* botAI) : Multiplier(botAI, "attumen the huntsman stay stacked multiplier") {}
|
||||
virtual float GetValue(Action* action);
|
||||
};
|
||||
|
||||
class KarazhanShadeOfAranMultiplier : public Multiplier
|
||||
class AttumenTheHuntsmanWaitForDpsMultiplier : public Multiplier
|
||||
{
|
||||
public:
|
||||
KarazhanShadeOfAranMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "karazhan shade of aran multiplier") {}
|
||||
AttumenTheHuntsmanWaitForDpsMultiplier(
|
||||
PlayerbotAI* botAI) : Multiplier(botAI, "attumen the huntsman wait for dps multiplier") {}
|
||||
virtual float GetValue(Action* action);
|
||||
};
|
||||
|
||||
class KarazhanNetherspiteBlueAndGreenBeamMultiplier : public Multiplier
|
||||
class TheCuratorDisableTankAssistMultiplier : public Multiplier
|
||||
{
|
||||
public:
|
||||
KarazhanNetherspiteBlueAndGreenBeamMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "karazhan netherspite blue and green beam multiplier") {}
|
||||
TheCuratorDisableTankAssistMultiplier(
|
||||
PlayerbotAI* botAI) : Multiplier(botAI, "the curator disable tank assist multiplier") {}
|
||||
virtual float GetValue(Action* action);
|
||||
};
|
||||
|
||||
class KarazhanNetherspiteRedBeamMultiplier : public Multiplier
|
||||
class TheCuratorDelayBloodlustAndHeroismMultiplier : public Multiplier
|
||||
{
|
||||
public:
|
||||
KarazhanNetherspiteRedBeamMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "karazhan netherspite red beam multiplier") {}
|
||||
TheCuratorDelayBloodlustAndHeroismMultiplier(
|
||||
PlayerbotAI* botAI) : Multiplier(botAI, "the curator delay bloodlust and heroism multiplier") {}
|
||||
virtual float GetValue(Action* action);
|
||||
};
|
||||
|
||||
class KarazhanPrinceMalchezaarMultiplier : public Multiplier
|
||||
class ShadeOfAranArcaneExplosionDisableChargeMultiplier : public Multiplier
|
||||
{
|
||||
public:
|
||||
KarazhanPrinceMalchezaarMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "karazhan prince malchezaar multiplier") {}
|
||||
ShadeOfAranArcaneExplosionDisableChargeMultiplier(
|
||||
PlayerbotAI* botAI) : Multiplier(botAI, "shade of aran arcane explosion disable charge multiplier") {}
|
||||
virtual float GetValue(Action* action);
|
||||
};
|
||||
|
||||
class ShadeOfAranFlameWreathDisableMovementMultiplier : public Multiplier
|
||||
{
|
||||
public:
|
||||
ShadeOfAranFlameWreathDisableMovementMultiplier(
|
||||
PlayerbotAI* botAI) : Multiplier(botAI, "shade of aran flame wreath disable movement multiplier") {}
|
||||
virtual float GetValue(Action* action);
|
||||
};
|
||||
|
||||
class NetherspiteKeepBlockingBeamMultiplier : public Multiplier
|
||||
{
|
||||
public:
|
||||
NetherspiteKeepBlockingBeamMultiplier(
|
||||
PlayerbotAI* botAI) : Multiplier(botAI, "netherspite keep blocking beam multiplier") {}
|
||||
virtual float GetValue(Action* action);
|
||||
};
|
||||
|
||||
class NetherspiteWaitForDpsMultiplier : public Multiplier
|
||||
{
|
||||
public:
|
||||
NetherspiteWaitForDpsMultiplier(
|
||||
PlayerbotAI* botAI) : Multiplier(botAI, "netherspite wait for dps multiplier") {}
|
||||
virtual float GetValue(Action* action);
|
||||
};
|
||||
|
||||
class PrinceMalchezaarDisableAvoidAoeMultiplier : public Multiplier
|
||||
{
|
||||
public:
|
||||
PrinceMalchezaarDisableAvoidAoeMultiplier(
|
||||
PlayerbotAI* botAI) : Multiplier(botAI, "prince malchezaar disable avoid aoe multiplier") {}
|
||||
virtual float GetValue(Action* action);
|
||||
};
|
||||
|
||||
class PrinceMalchezaarEnfeebleKeepDistanceMultiplier : public Multiplier
|
||||
{
|
||||
public:
|
||||
PrinceMalchezaarEnfeebleKeepDistanceMultiplier(
|
||||
PlayerbotAI* botAI) : Multiplier(botAI, "prince malchezaar enfeeble keep distance multiplier") {}
|
||||
virtual float GetValue(Action* action);
|
||||
};
|
||||
|
||||
class PrinceMalchezaarDelayBloodlustAndHeroismMultiplier : public Multiplier
|
||||
{
|
||||
public:
|
||||
PrinceMalchezaarDelayBloodlustAndHeroismMultiplier(
|
||||
PlayerbotAI* botAI) : Multiplier(botAI, "prince malchezaar delay bloodlust and heroism multiplier") {}
|
||||
virtual float GetValue(Action* action);
|
||||
};
|
||||
|
||||
class NightbaneDisablePetsMultiplier : public Multiplier
|
||||
{
|
||||
public:
|
||||
NightbaneDisablePetsMultiplier(
|
||||
PlayerbotAI* botAI) : Multiplier(botAI, "nightbane disable pets multiplier") {}
|
||||
virtual float GetValue(Action* action);
|
||||
};
|
||||
|
||||
class NightbaneWaitForDpsMultiplier : public Multiplier
|
||||
{
|
||||
public:
|
||||
NightbaneWaitForDpsMultiplier(
|
||||
PlayerbotAI* botAI) : Multiplier(botAI, "nightbane wait for dps multiplier") {}
|
||||
virtual float GetValue(Action* action);
|
||||
};
|
||||
|
||||
class NightbaneDisableAvoidAoeMultiplier : public Multiplier
|
||||
{
|
||||
public:
|
||||
NightbaneDisableAvoidAoeMultiplier(
|
||||
PlayerbotAI* botAI) : Multiplier(botAI, "nightbane disable avoid aoe multiplier") {}
|
||||
virtual float GetValue(Action* action);
|
||||
};
|
||||
|
||||
class NightbaneDisableMovementMultiplier : public Multiplier
|
||||
{
|
||||
public:
|
||||
NightbaneDisableMovementMultiplier(
|
||||
PlayerbotAI* botAI) : Multiplier(botAI, "nightbane disable movement multiplier") {}
|
||||
virtual float GetValue(Action* action);
|
||||
};
|
||||
|
||||
|
||||
@@ -3,79 +3,160 @@
|
||||
|
||||
void RaidKarazhanStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(new TriggerNode(
|
||||
"karazhan attumen the huntsman", NextAction::array(0,
|
||||
new NextAction("karazhan attumen the huntsman stack behind", ACTION_RAID + 1),
|
||||
nullptr)));
|
||||
// Trash
|
||||
triggers.push_back(new TriggerNode("mana warp is about to explode",
|
||||
NextAction::array(0, new NextAction("mana warp stun creature before warp breach", ACTION_EMERGENCY + 6), nullptr)
|
||||
));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"karazhan moroes", NextAction::array(0,
|
||||
new NextAction("karazhan moroes mark target", ACTION_RAID + 1),
|
||||
nullptr)));
|
||||
// Attumen the Huntsman
|
||||
triggers.push_back(new TriggerNode("attumen the huntsman need target priority",
|
||||
NextAction::array(0, new NextAction("attumen the huntsman mark target", ACTION_RAID + 1), nullptr)
|
||||
));
|
||||
triggers.push_back(new TriggerNode("attumen the huntsman attumen spawned",
|
||||
NextAction::array(0, new NextAction("attumen the huntsman split bosses", ACTION_RAID + 2), nullptr)
|
||||
));
|
||||
triggers.push_back(new TriggerNode("attumen the huntsman attumen is mounted",
|
||||
NextAction::array(0, new NextAction("attumen the huntsman stack behind", ACTION_RAID + 1), nullptr)
|
||||
));
|
||||
triggers.push_back(new TriggerNode("attumen the huntsman boss wipes aggro when mounting",
|
||||
NextAction::array(0, new NextAction("attumen the huntsman manage dps timer", ACTION_RAID + 2), nullptr)
|
||||
));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"karazhan maiden of virtue", NextAction::array(0,
|
||||
new NextAction("karazhan maiden of virtue position ranged", ACTION_RAID + 1),
|
||||
new NextAction("karazhan maiden of virtue position boss", ACTION_RAID + 1),
|
||||
nullptr)));
|
||||
// Moroes
|
||||
triggers.push_back(new TriggerNode("moroes boss engaged by main tank",
|
||||
NextAction::array(0, new NextAction("moroes main tank attack boss", ACTION_RAID + 1), nullptr)
|
||||
));
|
||||
triggers.push_back(new TriggerNode("moroes need target priority",
|
||||
NextAction::array(0, new NextAction("moroes mark target", ACTION_RAID + 1), nullptr)
|
||||
));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"karazhan big bad wolf", NextAction::array(0,
|
||||
new NextAction("karazhan big bad wolf run away", ACTION_EMERGENCY + 6),
|
||||
new NextAction("karazhan big bad wolf position boss", ACTION_RAID + 1),
|
||||
nullptr)));
|
||||
// Maiden of Virtue
|
||||
triggers.push_back(new TriggerNode("maiden of virtue healers are stunned by repentance",
|
||||
NextAction::array(0, new NextAction("maiden of virtue move boss to healer", ACTION_RAID + 1), nullptr)
|
||||
));
|
||||
triggers.push_back(new TriggerNode("maiden of virtue holy wrath deals chain damage",
|
||||
NextAction::array(0, new NextAction("maiden of virtue position ranged", ACTION_RAID + 1), nullptr)
|
||||
));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"karazhan romulo and julianne", NextAction::array(0,
|
||||
new NextAction("karazhan romulo and julianne mark target", ACTION_RAID + 1),
|
||||
nullptr)));
|
||||
// The Big Bad Wolf
|
||||
triggers.push_back(new TriggerNode("big bad wolf boss is chasing little red riding hood",
|
||||
NextAction::array(0, new NextAction("big bad wolf run away from boss", ACTION_EMERGENCY + 6), nullptr)
|
||||
));
|
||||
triggers.push_back(new TriggerNode("big bad wolf boss engaged by tank",
|
||||
NextAction::array(0, new NextAction("big bad wolf position boss", ACTION_RAID + 1), nullptr)
|
||||
));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"karazhan wizard of oz", NextAction::array(0,
|
||||
new NextAction("karazhan wizard of oz scorch strawman", ACTION_RAID + 2),
|
||||
new NextAction("karazhan wizard of oz mark target", ACTION_RAID + 1),
|
||||
nullptr)));
|
||||
// Romulo and Julianne
|
||||
triggers.push_back(new TriggerNode("romulo and julianne both bosses revived",
|
||||
NextAction::array(0, new NextAction("romulo and julianne mark target", ACTION_RAID + 1), nullptr)
|
||||
));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"karazhan the curator", NextAction::array(0,
|
||||
new NextAction("karazhan the curator spread ranged", ACTION_RAID + 2),
|
||||
new NextAction("karazhan the curator position boss", ACTION_RAID + 2),
|
||||
new NextAction("karazhan the curator mark target", ACTION_RAID + 1),
|
||||
nullptr)));
|
||||
// The Wizard of Oz
|
||||
triggers.push_back(new TriggerNode("wizard of oz need target priority",
|
||||
NextAction::array(0, new NextAction("wizard of oz mark target", ACTION_RAID + 1), nullptr)
|
||||
));
|
||||
triggers.push_back(new TriggerNode("wizard of oz strawman is vulnerable to fire",
|
||||
NextAction::array(0, new NextAction("wizard of oz scorch strawman", ACTION_RAID + 2), nullptr)
|
||||
));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"karazhan terestian illhoof", NextAction::array(0,
|
||||
new NextAction("karazhan terestian illhoof mark target", ACTION_RAID + 1),
|
||||
nullptr)));
|
||||
// The Curator
|
||||
triggers.push_back(new TriggerNode("the curator astral flare spawned",
|
||||
NextAction::array(0, new NextAction("the curator mark astral flare", ACTION_RAID + 1), nullptr)
|
||||
));
|
||||
triggers.push_back(new TriggerNode("the curator boss engaged by tanks",
|
||||
NextAction::array(0, new NextAction("the curator position boss", ACTION_RAID + 2), nullptr)
|
||||
));
|
||||
triggers.push_back(new TriggerNode("the curator astral flares cast arcing sear",
|
||||
NextAction::array(0, new NextAction("the curator spread ranged", ACTION_RAID + 2), nullptr)
|
||||
));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"karazhan shade of aran", NextAction::array(0,
|
||||
new NextAction("karazhan shade of aran flame wreath stop movement", ACTION_EMERGENCY + 7),
|
||||
new NextAction("karazhan shade of aran arcane explosion run away", ACTION_EMERGENCY + 6),
|
||||
new NextAction("karazhan shade of aran spread ranged", ACTION_RAID + 2),
|
||||
new NextAction("karazhan shade of aran mark conjured elemental", ACTION_RAID + 1),
|
||||
nullptr)));
|
||||
// Terestian Illhoof
|
||||
triggers.push_back(new TriggerNode("terestian illhoof need target priority",
|
||||
NextAction::array(0, new NextAction("terestian illhoof mark target", ACTION_RAID + 1), nullptr)
|
||||
));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"karazhan netherspite", NextAction::array(0,
|
||||
new NextAction("karazhan netherspite block red beam", ACTION_EMERGENCY + 8),
|
||||
new NextAction("karazhan netherspite block blue beam", ACTION_EMERGENCY + 8),
|
||||
new NextAction("karazhan netherspite block green beam", ACTION_EMERGENCY + 8),
|
||||
new NextAction("karazhan netherspite avoid beam and void zone", ACTION_EMERGENCY + 7),
|
||||
new NextAction("karazhan netherspite banish phase avoid void zone", ACTION_RAID + 1),
|
||||
nullptr)));
|
||||
// Shade of Aran
|
||||
triggers.push_back(new TriggerNode("shade of aran arcane explosion is casting",
|
||||
NextAction::array(0, new NextAction("shade of aran run away from arcane explosion", ACTION_EMERGENCY + 6), nullptr)
|
||||
));
|
||||
triggers.push_back(new TriggerNode("shade of aran flame wreath is active",
|
||||
NextAction::array(0, new NextAction("shade of aran stop moving during flame wreath", ACTION_EMERGENCY + 7), nullptr)
|
||||
));
|
||||
triggers.push_back(new TriggerNode("shade of aran conjured elementals summoned",
|
||||
NextAction::array(0, new NextAction("shade of aran mark conjured elemental", ACTION_RAID + 1), nullptr)
|
||||
));
|
||||
triggers.push_back(new TriggerNode("shade of aran boss uses counterspell and blizzard",
|
||||
NextAction::array(0, new NextAction("shade of aran ranged maintain distance", ACTION_RAID + 2), nullptr)
|
||||
));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"karazhan prince malchezaar", NextAction::array(0,
|
||||
new NextAction("karazhan prince malchezaar non tank avoid hazard", ACTION_EMERGENCY + 6),
|
||||
new NextAction("karazhan prince malchezaar tank avoid hazard", ACTION_EMERGENCY + 6),
|
||||
nullptr)));
|
||||
// Netherspite
|
||||
triggers.push_back(new TriggerNode("netherspite red beam is active",
|
||||
NextAction::array(0, new NextAction("netherspite block red beam", ACTION_EMERGENCY + 8), nullptr)
|
||||
));
|
||||
triggers.push_back(new TriggerNode("netherspite blue beam is active",
|
||||
NextAction::array(0, new NextAction("netherspite block blue beam", ACTION_EMERGENCY + 8), nullptr)
|
||||
));
|
||||
triggers.push_back(new TriggerNode("netherspite green beam is active",
|
||||
NextAction::array(0, new NextAction("netherspite block green beam", ACTION_EMERGENCY + 8), nullptr)
|
||||
));
|
||||
triggers.push_back(new TriggerNode("netherspite bot is not beam blocker",
|
||||
NextAction::array(0, new NextAction("netherspite avoid beam and void zone", ACTION_EMERGENCY + 7), nullptr)
|
||||
));
|
||||
triggers.push_back(new TriggerNode("netherspite boss is banished",
|
||||
NextAction::array(0, new NextAction("netherspite banish phase avoid void zone", ACTION_RAID + 1), nullptr)
|
||||
));
|
||||
triggers.push_back(new TriggerNode("netherspite need to manage timers and trackers",
|
||||
NextAction::array(0, new NextAction("netherspite manage timers and trackers", ACTION_EMERGENCY + 10), nullptr)
|
||||
));
|
||||
|
||||
// Prince Malchezaar
|
||||
triggers.push_back(new TriggerNode("prince malchezaar bot is enfeebled",
|
||||
NextAction::array(0, new NextAction("prince malchezaar enfeebled avoid hazard", ACTION_EMERGENCY + 6), nullptr)
|
||||
));
|
||||
triggers.push_back(new TriggerNode("prince malchezaar infernals are spawned",
|
||||
NextAction::array(0, new NextAction("prince malchezaar non tank avoid infernal", ACTION_EMERGENCY + 1), nullptr)
|
||||
));
|
||||
triggers.push_back(new TriggerNode("prince malchezaar boss engaged by main tank",
|
||||
NextAction::array(0, new NextAction("prince malchezaar main tank movement", ACTION_EMERGENCY + 6), nullptr)
|
||||
));
|
||||
|
||||
// Nightbane
|
||||
triggers.push_back(new TriggerNode("nightbane boss engaged by main tank",
|
||||
NextAction::array(0, new NextAction("nightbane ground phase position boss", ACTION_RAID + 1), nullptr)
|
||||
));
|
||||
triggers.push_back(new TriggerNode("nightbane ranged bots are in charred earth",
|
||||
NextAction::array(0, new NextAction("nightbane ground phase rotate ranged positions", ACTION_EMERGENCY + 1), nullptr)
|
||||
));
|
||||
triggers.push_back(new TriggerNode("nightbane main tank is susceptible to fear",
|
||||
NextAction::array(0, new NextAction("nightbane cast fear ward on main tank", ACTION_RAID + 2), nullptr)
|
||||
));
|
||||
triggers.push_back(new TriggerNode("nightbane pets ignore collision to chase flying boss",
|
||||
NextAction::array(0, new NextAction("nightbane control pet aggression", ACTION_RAID + 2), nullptr)
|
||||
));
|
||||
triggers.push_back(new TriggerNode("nightbane boss is flying",
|
||||
NextAction::array(0, new NextAction("nightbane flight phase movement", ACTION_RAID + 1), nullptr)
|
||||
));
|
||||
triggers.push_back(new TriggerNode("nightbane need to manage timers and trackers",
|
||||
NextAction::array(0, new NextAction("nightbane manage timers and trackers", ACTION_EMERGENCY + 10), nullptr)
|
||||
));
|
||||
}
|
||||
|
||||
void RaidKarazhanStrategy::InitMultipliers(std::vector<Multiplier*>& multipliers)
|
||||
{
|
||||
multipliers.push_back(new KarazhanShadeOfAranMultiplier(botAI));
|
||||
multipliers.push_back(new KarazhanNetherspiteBlueAndGreenBeamMultiplier(botAI));
|
||||
multipliers.push_back(new KarazhanNetherspiteRedBeamMultiplier(botAI));
|
||||
multipliers.push_back(new KarazhanPrinceMalchezaarMultiplier(botAI));
|
||||
multipliers.push_back(new AttumenTheHuntsmanDisableTankAssistMultiplier(botAI));
|
||||
multipliers.push_back(new AttumenTheHuntsmanStayStackedMultiplier(botAI));
|
||||
multipliers.push_back(new AttumenTheHuntsmanWaitForDpsMultiplier(botAI));
|
||||
multipliers.push_back(new TheCuratorDisableTankAssistMultiplier(botAI));
|
||||
multipliers.push_back(new TheCuratorDelayBloodlustAndHeroismMultiplier(botAI));
|
||||
multipliers.push_back(new ShadeOfAranArcaneExplosionDisableChargeMultiplier(botAI));
|
||||
multipliers.push_back(new ShadeOfAranFlameWreathDisableMovementMultiplier(botAI));
|
||||
multipliers.push_back(new NetherspiteKeepBlockingBeamMultiplier(botAI));
|
||||
multipliers.push_back(new NetherspiteWaitForDpsMultiplier(botAI));
|
||||
multipliers.push_back(new PrinceMalchezaarDisableAvoidAoeMultiplier(botAI));
|
||||
multipliers.push_back(new PrinceMalchezaarEnfeebleKeepDistanceMultiplier(botAI));
|
||||
multipliers.push_back(new PrinceMalchezaarDelayBloodlustAndHeroismMultiplier(botAI));
|
||||
multipliers.push_back(new NightbaneDisablePetsMultiplier(botAI));
|
||||
multipliers.push_back(new NightbaneWaitForDpsMultiplier(botAI));
|
||||
multipliers.push_back(new NightbaneDisableAvoidAoeMultiplier(botAI));
|
||||
multipliers.push_back(new NightbaneDisableMovementMultiplier(botAI));
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
class RaidKarazhanStrategy : public Strategy
|
||||
{
|
||||
public:
|
||||
RaidKarazhanStrategy(PlayerbotAI* ai) : Strategy(ai) {}
|
||||
RaidKarazhanStrategy(PlayerbotAI* botAI) : Strategy(botAI) {}
|
||||
|
||||
std::string const getName() override { return "karazhan"; }
|
||||
|
||||
|
||||
@@ -9,31 +9,255 @@ class RaidKarazhanTriggerContext : public NamedObjectContext<Trigger>
|
||||
public:
|
||||
RaidKarazhanTriggerContext()
|
||||
{
|
||||
creators["karazhan attumen the huntsman"] = &RaidKarazhanTriggerContext::karazhan_attumen_the_huntsman;
|
||||
creators["karazhan moroes"] = &RaidKarazhanTriggerContext::karazhan_moroes;
|
||||
creators["karazhan maiden of virtue"] = &RaidKarazhanTriggerContext::karazhan_maiden_of_virtue;
|
||||
creators["karazhan big bad wolf"] = &RaidKarazhanTriggerContext::karazhan_big_bad_wolf;
|
||||
creators["karazhan romulo and julianne"] = &RaidKarazhanTriggerContext::karazhan_romulo_and_julianne;
|
||||
creators["karazhan wizard of oz"] = &RaidKarazhanTriggerContext::karazhan_wizard_of_oz;
|
||||
creators["karazhan the curator"] = &RaidKarazhanTriggerContext::karazhan_the_curator;
|
||||
creators["karazhan terestian illhoof"] = &RaidKarazhanTriggerContext::karazhan_terestian_illhoof;
|
||||
creators["karazhan shade of aran"] = &RaidKarazhanTriggerContext::karazhan_shade_of_aran;
|
||||
creators["karazhan netherspite"] = &RaidKarazhanTriggerContext::karazhan_netherspite;
|
||||
creators["karazhan prince malchezaar"] = &RaidKarazhanTriggerContext::karazhan_prince_malchezaar;
|
||||
// Trash
|
||||
creators["mana warp is about to explode"] =
|
||||
&RaidKarazhanTriggerContext::mana_warp_is_about_to_explode;
|
||||
|
||||
// Attumen the Huntsman
|
||||
creators["attumen the huntsman need target priority"] =
|
||||
&RaidKarazhanTriggerContext::attumen_the_huntsman_need_target_priority;
|
||||
|
||||
creators["attumen the huntsman attumen spawned"] =
|
||||
&RaidKarazhanTriggerContext::attumen_the_huntsman_attumen_spawned;
|
||||
|
||||
creators["attumen the huntsman attumen is mounted"] =
|
||||
&RaidKarazhanTriggerContext::attumen_the_huntsman_attumen_is_mounted;
|
||||
|
||||
creators["attumen the huntsman boss wipes aggro when mounting"] =
|
||||
&RaidKarazhanTriggerContext::attumen_the_huntsman_boss_wipes_aggro_when_mounting;
|
||||
|
||||
// Moroes
|
||||
creators["moroes boss engaged by main tank"] =
|
||||
&RaidKarazhanTriggerContext::moroes_boss_engaged_by_main_tank;
|
||||
|
||||
creators["moroes need target priority"] =
|
||||
&RaidKarazhanTriggerContext::moroes_need_target_priority;
|
||||
|
||||
// Maiden of Virtue
|
||||
creators["maiden of virtue healers are stunned by repentance"] =
|
||||
&RaidKarazhanTriggerContext::maiden_of_virtue_healers_are_stunned_by_repentance;
|
||||
|
||||
creators["maiden of virtue holy wrath deals chain damage"] =
|
||||
&RaidKarazhanTriggerContext::maiden_of_virtue_holy_wrath_deals_chain_damage;
|
||||
|
||||
// The Big Bad Wolf
|
||||
creators["big bad wolf boss engaged by tank"] =
|
||||
&RaidKarazhanTriggerContext::big_bad_wolf_boss_engaged_by_tank;
|
||||
|
||||
creators["big bad wolf boss is chasing little red riding hood"] =
|
||||
&RaidKarazhanTriggerContext::big_bad_wolf_boss_is_chasing_little_red_riding_hood;
|
||||
|
||||
// Romulo and Julianne
|
||||
creators["romulo and julianne both bosses revived"] =
|
||||
&RaidKarazhanTriggerContext::romulo_and_julianne_both_bosses_revived;
|
||||
|
||||
// The Wizard of Oz
|
||||
creators["wizard of oz need target priority"] =
|
||||
&RaidKarazhanTriggerContext::wizard_of_oz_need_target_priority;
|
||||
|
||||
creators["wizard of oz strawman is vulnerable to fire"] =
|
||||
&RaidKarazhanTriggerContext::wizard_of_oz_strawman_is_vulnerable_to_fire;
|
||||
|
||||
// The Curator
|
||||
creators["the curator astral flare spawned"] =
|
||||
&RaidKarazhanTriggerContext::the_curator_astral_flare_spawned;
|
||||
|
||||
creators["the curator boss engaged by tanks"] =
|
||||
&RaidKarazhanTriggerContext::the_curator_boss_engaged_by_tanks;
|
||||
|
||||
creators["the curator astral flares cast arcing sear"] =
|
||||
&RaidKarazhanTriggerContext::the_curator_astral_flares_cast_arcing_sear;
|
||||
|
||||
// Terestian Illhoof
|
||||
creators["terestian illhoof need target priority"] =
|
||||
&RaidKarazhanTriggerContext::terestian_illhoof_need_target_priority;
|
||||
|
||||
// Shade of Aran
|
||||
creators["shade of aran arcane explosion is casting"] =
|
||||
&RaidKarazhanTriggerContext::shade_of_aran_arcane_explosion_is_casting;
|
||||
|
||||
creators["shade of aran flame wreath is active"] =
|
||||
&RaidKarazhanTriggerContext::shade_of_aran_flame_wreath_is_active;
|
||||
|
||||
creators["shade of aran conjured elementals summoned"] =
|
||||
&RaidKarazhanTriggerContext::shade_of_aran_conjured_elementals_summoned;
|
||||
|
||||
creators["shade of aran boss uses counterspell and blizzard"] =
|
||||
&RaidKarazhanTriggerContext::shade_of_aran_boss_uses_counterspell_and_blizzard;
|
||||
|
||||
// Netherspite
|
||||
creators["netherspite red beam is active"] =
|
||||
&RaidKarazhanTriggerContext::netherspite_red_beam_is_active;
|
||||
|
||||
creators["netherspite blue beam is active"] =
|
||||
&RaidKarazhanTriggerContext::netherspite_blue_beam_is_active;
|
||||
|
||||
creators["netherspite green beam is active"] =
|
||||
&RaidKarazhanTriggerContext::netherspite_green_beam_is_active;
|
||||
|
||||
creators["netherspite bot is not beam blocker"] =
|
||||
&RaidKarazhanTriggerContext::netherspite_bot_is_not_beam_blocker;
|
||||
|
||||
creators["netherspite boss is banished"] =
|
||||
&RaidKarazhanTriggerContext::netherspite_boss_is_banished;
|
||||
|
||||
creators["netherspite need to manage timers and trackers"] =
|
||||
&RaidKarazhanTriggerContext::netherspite_need_to_manage_timers_and_trackers;
|
||||
|
||||
// Prince Malchezaar
|
||||
creators["prince malchezaar bot is enfeebled"] =
|
||||
&RaidKarazhanTriggerContext::prince_malchezaar_bot_is_enfeebled;
|
||||
|
||||
creators["prince malchezaar infernals are spawned"] =
|
||||
&RaidKarazhanTriggerContext::prince_malchezaar_infernals_are_spawned;
|
||||
|
||||
creators["prince malchezaar boss engaged by main tank"] =
|
||||
&RaidKarazhanTriggerContext::prince_malchezaar_boss_engaged_by_main_tank;
|
||||
|
||||
// Nightbane
|
||||
creators["nightbane boss engaged by main tank"] =
|
||||
&RaidKarazhanTriggerContext::nightbane_boss_engaged_by_main_tank;
|
||||
|
||||
creators["nightbane ranged bots are in charred earth"] =
|
||||
&RaidKarazhanTriggerContext::nightbane_ranged_bots_are_in_charred_earth;
|
||||
|
||||
creators["nightbane main tank is susceptible to fear"] =
|
||||
&RaidKarazhanTriggerContext::nightbane_main_tank_is_susceptible_to_fear;
|
||||
|
||||
creators["nightbane pets ignore collision to chase flying boss"] =
|
||||
&RaidKarazhanTriggerContext::nightbane_pets_ignore_collision_to_chase_flying_boss;
|
||||
|
||||
creators["nightbane boss is flying"] =
|
||||
&RaidKarazhanTriggerContext::nightbane_boss_is_flying;
|
||||
|
||||
creators["nightbane need to manage timers and trackers"] =
|
||||
&RaidKarazhanTriggerContext::nightbane_need_to_manage_timers_and_trackers;
|
||||
}
|
||||
|
||||
private:
|
||||
static Trigger* karazhan_attumen_the_huntsman(PlayerbotAI* botAI) { return new KarazhanAttumenTheHuntsmanTrigger(botAI); }
|
||||
static Trigger* karazhan_moroes(PlayerbotAI* botAI) { return new KarazhanMoroesTrigger(botAI); }
|
||||
static Trigger* karazhan_maiden_of_virtue(PlayerbotAI* botAI) { return new KarazhanMaidenOfVirtueTrigger(botAI); }
|
||||
static Trigger* karazhan_big_bad_wolf(PlayerbotAI* botAI) { return new KarazhanBigBadWolfTrigger(botAI); }
|
||||
static Trigger* karazhan_romulo_and_julianne(PlayerbotAI* botAI) { return new KarazhanRomuloAndJulianneTrigger(botAI); }
|
||||
static Trigger* karazhan_wizard_of_oz(PlayerbotAI* botAI) { return new KarazhanWizardOfOzTrigger(botAI); }
|
||||
static Trigger* karazhan_the_curator(PlayerbotAI* botAI) { return new KarazhanTheCuratorTrigger(botAI); }
|
||||
static Trigger* karazhan_terestian_illhoof(PlayerbotAI* botAI) { return new KarazhanTerestianIllhoofTrigger(botAI); }
|
||||
static Trigger* karazhan_shade_of_aran(PlayerbotAI* botAI) { return new KarazhanShadeOfAranTrigger(botAI); }
|
||||
static Trigger* karazhan_netherspite(PlayerbotAI* botAI) { return new KarazhanNetherspiteTrigger(botAI); }
|
||||
static Trigger* karazhan_prince_malchezaar(PlayerbotAI* botAI) { return new KarazhanPrinceMalchezaarTrigger(botAI); }
|
||||
// Trash
|
||||
static Trigger* mana_warp_is_about_to_explode(
|
||||
PlayerbotAI* botAI) { return new ManaWarpIsAboutToExplodeTrigger(botAI); }
|
||||
|
||||
// Attumen the Huntsman
|
||||
static Trigger* attumen_the_huntsman_need_target_priority(
|
||||
PlayerbotAI* botAI) { return new AttumenTheHuntsmanNeedTargetPriorityTrigger(botAI); }
|
||||
|
||||
static Trigger* attumen_the_huntsman_attumen_spawned(
|
||||
PlayerbotAI* botAI) { return new AttumenTheHuntsmanAttumenSpawnedTrigger(botAI); }
|
||||
|
||||
static Trigger* attumen_the_huntsman_attumen_is_mounted(
|
||||
PlayerbotAI* botAI) { return new AttumenTheHuntsmanAttumenIsMountedTrigger(botAI); }
|
||||
|
||||
static Trigger* attumen_the_huntsman_boss_wipes_aggro_when_mounting(
|
||||
PlayerbotAI* botAI) { return new AttumenTheHuntsmanBossWipesAggroWhenMountingTrigger(botAI); }
|
||||
|
||||
// Moroes
|
||||
static Trigger* moroes_boss_engaged_by_main_tank(
|
||||
PlayerbotAI* botAI) { return new MoroesBossEngagedByMainTankTrigger(botAI); }
|
||||
|
||||
static Trigger* moroes_need_target_priority(
|
||||
PlayerbotAI* botAI) { return new MoroesNeedTargetPriorityTrigger(botAI); }
|
||||
|
||||
// Maiden of Virtue
|
||||
static Trigger* maiden_of_virtue_healers_are_stunned_by_repentance(
|
||||
PlayerbotAI* botAI) { return new MaidenOfVirtueHealersAreStunnedByRepentanceTrigger(botAI); }
|
||||
|
||||
static Trigger* maiden_of_virtue_holy_wrath_deals_chain_damage(
|
||||
PlayerbotAI* botAI) { return new MaidenOfVirtueHolyWrathDealsChainDamageTrigger(botAI); }
|
||||
|
||||
// The Big Bad Wolf
|
||||
static Trigger* big_bad_wolf_boss_engaged_by_tank(
|
||||
PlayerbotAI* botAI) { return new BigBadWolfBossEngagedByTankTrigger(botAI); }
|
||||
|
||||
static Trigger* big_bad_wolf_boss_is_chasing_little_red_riding_hood(
|
||||
PlayerbotAI* botAI) { return new BigBadWolfBossIsChasingLittleRedRidingHoodTrigger(botAI); }
|
||||
|
||||
// Romulo and Julianne
|
||||
static Trigger* romulo_and_julianne_both_bosses_revived(
|
||||
PlayerbotAI* botAI) { return new RomuloAndJulianneBothBossesRevivedTrigger(botAI); }
|
||||
|
||||
// The Wizard of Oz
|
||||
static Trigger* wizard_of_oz_need_target_priority(
|
||||
PlayerbotAI* botAI) { return new WizardOfOzNeedTargetPriorityTrigger(botAI); }
|
||||
|
||||
static Trigger* wizard_of_oz_strawman_is_vulnerable_to_fire(
|
||||
PlayerbotAI* botAI) { return new WizardOfOzStrawmanIsVulnerableToFireTrigger(botAI); }
|
||||
|
||||
// The Curator
|
||||
static Trigger* the_curator_astral_flare_spawned(
|
||||
PlayerbotAI* botAI) { return new TheCuratorAstralFlareSpawnedTrigger(botAI); }
|
||||
|
||||
static Trigger* the_curator_boss_engaged_by_tanks(
|
||||
PlayerbotAI* botAI) { return new TheCuratorBossEngagedByTanksTrigger(botAI); }
|
||||
|
||||
static Trigger* the_curator_astral_flares_cast_arcing_sear(
|
||||
PlayerbotAI* botAI) { return new TheCuratorBossAstralFlaresCastArcingSearTrigger(botAI); }
|
||||
|
||||
// Terestian Illhoof
|
||||
static Trigger* terestian_illhoof_need_target_priority(
|
||||
PlayerbotAI* botAI) { return new TerestianIllhoofNeedTargetPriorityTrigger(botAI); }
|
||||
|
||||
// Shade of Aran
|
||||
static Trigger* shade_of_aran_arcane_explosion_is_casting(
|
||||
PlayerbotAI* botAI) { return new ShadeOfAranArcaneExplosionIsCastingTrigger(botAI); }
|
||||
|
||||
static Trigger* shade_of_aran_flame_wreath_is_active(
|
||||
PlayerbotAI* botAI) { return new ShadeOfAranFlameWreathIsActiveTrigger(botAI); }
|
||||
|
||||
static Trigger* shade_of_aran_conjured_elementals_summoned(
|
||||
PlayerbotAI* botAI) { return new ShadeOfAranConjuredElementalsSummonedTrigger(botAI); }
|
||||
|
||||
static Trigger* shade_of_aran_boss_uses_counterspell_and_blizzard(
|
||||
PlayerbotAI* botAI) { return new ShadeOfAranBossUsesCounterspellAndBlizzardTrigger(botAI); }
|
||||
|
||||
// Netherspite
|
||||
static Trigger* netherspite_red_beam_is_active(
|
||||
PlayerbotAI* botAI) { return new NetherspiteRedBeamIsActiveTrigger(botAI); }
|
||||
|
||||
static Trigger* netherspite_blue_beam_is_active(
|
||||
PlayerbotAI* botAI) { return new NetherspiteBlueBeamIsActiveTrigger(botAI); }
|
||||
|
||||
static Trigger* netherspite_green_beam_is_active(
|
||||
PlayerbotAI* botAI) { return new NetherspiteGreenBeamIsActiveTrigger(botAI); }
|
||||
|
||||
static Trigger* netherspite_bot_is_not_beam_blocker(
|
||||
PlayerbotAI* botAI) { return new NetherspiteBotIsNotBeamBlockerTrigger(botAI); }
|
||||
|
||||
static Trigger* netherspite_boss_is_banished(
|
||||
PlayerbotAI* botAI) { return new NetherspiteBossIsBanishedTrigger(botAI); }
|
||||
|
||||
static Trigger* netherspite_need_to_manage_timers_and_trackers(
|
||||
PlayerbotAI* botAI) { return new NetherspiteNeedToManageTimersAndTrackersTrigger(botAI); }
|
||||
|
||||
// Prince Malchezaar
|
||||
static Trigger* prince_malchezaar_bot_is_enfeebled(
|
||||
PlayerbotAI* botAI) { return new PrinceMalchezaarBotIsEnfeebledTrigger(botAI); }
|
||||
|
||||
static Trigger* prince_malchezaar_infernals_are_spawned(
|
||||
PlayerbotAI* botAI) { return new PrinceMalchezaarInfernalsAreSpawnedTrigger(botAI); }
|
||||
|
||||
static Trigger* prince_malchezaar_boss_engaged_by_main_tank(
|
||||
PlayerbotAI* botAI) { return new PrinceMalchezaarBossEngagedByMainTankTrigger(botAI); }
|
||||
|
||||
// Nightbane
|
||||
static Trigger* nightbane_boss_engaged_by_main_tank(
|
||||
PlayerbotAI* botAI) { return new NightbaneBossEngagedByMainTankTrigger(botAI); }
|
||||
|
||||
static Trigger* nightbane_ranged_bots_are_in_charred_earth(
|
||||
PlayerbotAI* botAI) { return new NightbaneRangedBotsAreInCharredEarthTrigger(botAI); }
|
||||
|
||||
static Trigger* nightbane_main_tank_is_susceptible_to_fear(
|
||||
PlayerbotAI* botAI) { return new NightbaneMainTankIsSusceptibleToFearTrigger(botAI); }
|
||||
|
||||
static Trigger* nightbane_pets_ignore_collision_to_chase_flying_boss(
|
||||
PlayerbotAI* botAI) { return new NightbanePetsIgnoreCollisionToChaseFlyingBossTrigger(botAI); }
|
||||
|
||||
static Trigger* nightbane_boss_is_flying(
|
||||
PlayerbotAI* botAI) { return new NightbaneBossIsFlyingTrigger(botAI); }
|
||||
|
||||
static Trigger* nightbane_need_to_manage_timers_and_trackers(
|
||||
PlayerbotAI* botAI) { return new NightbaneNeedToManageTimersAndTrackersTrigger(botAI); }
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -3,17 +3,64 @@
|
||||
#include "RaidKarazhanActions.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
bool KarazhanAttumenTheHuntsmanTrigger::IsActive()
|
||||
{
|
||||
RaidKarazhanHelpers helpers(botAI);
|
||||
Unit* boss = helpers.GetFirstAliveUnitByEntry(NPC_ATTUMEN_THE_HUNTSMAN_MOUNTED);
|
||||
using namespace KarazhanHelpers;
|
||||
|
||||
return boss && boss->IsAlive();
|
||||
bool ManaWarpIsAboutToExplodeTrigger::IsActive()
|
||||
{
|
||||
Unit* manaWarp = AI_VALUE2(Unit*, "find target", "mana warp");
|
||||
return manaWarp && manaWarp->GetHealthPct() < 15;
|
||||
}
|
||||
|
||||
bool KarazhanMoroesTrigger::IsActive()
|
||||
bool AttumenTheHuntsmanNeedTargetPriorityTrigger::IsActive()
|
||||
{
|
||||
if (botAI->IsHeal(bot))
|
||||
return false;
|
||||
|
||||
Unit* midnight = AI_VALUE2(Unit*, "find target", "midnight");
|
||||
return midnight != nullptr;
|
||||
}
|
||||
|
||||
bool AttumenTheHuntsmanAttumenSpawnedTrigger::IsActive()
|
||||
{
|
||||
if (!botAI->IsAssistTankOfIndex(bot, 0))
|
||||
return false;
|
||||
|
||||
Unit* attumen = GetFirstAliveUnitByEntry(botAI, NPC_ATTUMEN_THE_HUNTSMAN);
|
||||
return attumen != nullptr;
|
||||
}
|
||||
|
||||
bool AttumenTheHuntsmanAttumenIsMountedTrigger::IsActive()
|
||||
{
|
||||
if (botAI->IsMainTank(bot))
|
||||
return false;
|
||||
|
||||
Unit* attumenMounted = GetFirstAliveUnitByEntry(botAI, NPC_ATTUMEN_THE_HUNTSMAN_MOUNTED);
|
||||
return attumenMounted && attumenMounted->GetVictim() != bot;
|
||||
}
|
||||
|
||||
bool AttumenTheHuntsmanBossWipesAggroWhenMountingTrigger::IsActive()
|
||||
{
|
||||
if (!IsMapIDTimerManager(botAI, bot))
|
||||
return false;
|
||||
|
||||
Unit* midnight = AI_VALUE2(Unit*, "find target", "midnight");
|
||||
return midnight != nullptr;
|
||||
}
|
||||
|
||||
bool MoroesBossEngagedByMainTankTrigger::IsActive()
|
||||
{
|
||||
if (!botAI->IsMainTank(bot))
|
||||
return false;
|
||||
|
||||
Unit* moroes = AI_VALUE2(Unit*, "find target", "moroes");
|
||||
return moroes != nullptr;
|
||||
}
|
||||
|
||||
bool MoroesNeedTargetPriorityTrigger::IsActive()
|
||||
{
|
||||
if (!botAI->IsDps(bot))
|
||||
return false;
|
||||
|
||||
Unit* dorothea = AI_VALUE2(Unit*, "find target", "baroness dorothea millstipe");
|
||||
Unit* catriona = AI_VALUE2(Unit*, "find target", "lady catriona von'indi");
|
||||
Unit* keira = AI_VALUE2(Unit*, "find target", "lady keira berrybuck");
|
||||
@@ -21,39 +68,67 @@ bool KarazhanMoroesTrigger::IsActive()
|
||||
Unit* robin = AI_VALUE2(Unit*, "find target", "lord robin daris");
|
||||
Unit* crispin = AI_VALUE2(Unit*, "find target", "lord crispin ference");
|
||||
|
||||
return ((moroes && moroes->IsAlive()) ||
|
||||
(dorothea && dorothea->IsAlive()) ||
|
||||
(catriona && catriona->IsAlive()) ||
|
||||
(keira && keira->IsAlive()) ||
|
||||
(rafe && rafe->IsAlive()) ||
|
||||
(robin && robin->IsAlive()) ||
|
||||
(crispin && crispin->IsAlive()));
|
||||
Unit* target = GetFirstAliveUnit({ dorothea, catriona, keira, rafe, robin, crispin });
|
||||
return target != nullptr;
|
||||
}
|
||||
|
||||
bool KarazhanMaidenOfVirtueTrigger::IsActive()
|
||||
bool MaidenOfVirtueHealersAreStunnedByRepentanceTrigger::IsActive()
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "maiden of virtue");
|
||||
if (!botAI->IsTank(bot))
|
||||
return false;
|
||||
|
||||
return boss && boss->IsAlive();
|
||||
Unit* maiden = AI_VALUE2(Unit*, "find target", "maiden of virtue");
|
||||
return maiden && maiden->GetVictim() == bot;
|
||||
}
|
||||
|
||||
bool KarazhanBigBadWolfTrigger::IsActive()
|
||||
bool MaidenOfVirtueHolyWrathDealsChainDamageTrigger::IsActive()
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "the big bad wolf");
|
||||
if (!botAI->IsRanged(bot))
|
||||
return false;
|
||||
|
||||
return boss && boss->IsAlive();
|
||||
Unit* maiden = AI_VALUE2(Unit*, "find target", "maiden of virtue");
|
||||
return maiden != nullptr;
|
||||
}
|
||||
|
||||
bool KarazhanRomuloAndJulianneTrigger::IsActive()
|
||||
bool BigBadWolfBossEngagedByTankTrigger::IsActive()
|
||||
{
|
||||
Unit* julianne = AI_VALUE2(Unit*, "find target", "julianne");
|
||||
if (!botAI->IsTank(bot) || bot->HasAura(SPELL_LITTLE_RED_RIDING_HOOD))
|
||||
return false;
|
||||
|
||||
Unit* wolf = AI_VALUE2(Unit*, "find target", "the big bad wolf");
|
||||
return wolf != nullptr;
|
||||
}
|
||||
|
||||
bool BigBadWolfBossIsChasingLittleRedRidingHoodTrigger::IsActive()
|
||||
{
|
||||
if (!bot->HasAura(SPELL_LITTLE_RED_RIDING_HOOD))
|
||||
return false;
|
||||
|
||||
Unit* wolf = AI_VALUE2(Unit*, "find target", "the big bad wolf");
|
||||
return wolf != nullptr;
|
||||
}
|
||||
|
||||
bool RomuloAndJulianneBothBossesRevivedTrigger::IsActive()
|
||||
{
|
||||
if (!IsMapIDTimerManager(botAI, bot))
|
||||
return false;
|
||||
|
||||
Unit* romulo = AI_VALUE2(Unit*, "find target", "romulo");
|
||||
if (!romulo)
|
||||
return false;
|
||||
|
||||
return julianne && julianne->IsAlive() && romulo && romulo->IsAlive();
|
||||
Unit* julianne = AI_VALUE2(Unit*, "find target", "julianne");
|
||||
if (!julianne)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool KarazhanWizardOfOzTrigger::IsActive()
|
||||
bool WizardOfOzNeedTargetPriorityTrigger::IsActive()
|
||||
{
|
||||
if (!IsMapIDTimerManager(botAI, bot))
|
||||
return false;
|
||||
|
||||
Unit* dorothee = AI_VALUE2(Unit*, "find target", "dorothee");
|
||||
Unit* tito = AI_VALUE2(Unit*, "find target", "tito");
|
||||
Unit* roar = AI_VALUE2(Unit*, "find target", "roar");
|
||||
@@ -61,45 +136,249 @@ bool KarazhanWizardOfOzTrigger::IsActive()
|
||||
Unit* tinhead = AI_VALUE2(Unit*, "find target", "tinhead");
|
||||
Unit* crone = AI_VALUE2(Unit*, "find target", "the crone");
|
||||
|
||||
return ((dorothee && dorothee->IsAlive()) ||
|
||||
(tito && tito->IsAlive()) ||
|
||||
(roar && roar->IsAlive()) ||
|
||||
(strawman && strawman->IsAlive()) ||
|
||||
(tinhead && tinhead->IsAlive()) ||
|
||||
(crone && crone->IsAlive()));
|
||||
Unit* target = GetFirstAliveUnit({ dorothee, tito, roar, strawman, tinhead, crone });
|
||||
return target != nullptr;
|
||||
}
|
||||
|
||||
bool KarazhanTheCuratorTrigger::IsActive()
|
||||
bool WizardOfOzStrawmanIsVulnerableToFireTrigger::IsActive()
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "the curator");
|
||||
if (bot->getClass() != CLASS_MAGE)
|
||||
return false;
|
||||
|
||||
return boss && boss->IsAlive();
|
||||
Unit* strawman = AI_VALUE2(Unit*, "find target", "strawman");
|
||||
return strawman && strawman->IsAlive();
|
||||
}
|
||||
|
||||
bool KarazhanTerestianIllhoofTrigger::IsActive()
|
||||
bool TheCuratorAstralFlareSpawnedTrigger::IsActive()
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "terestian illhoof");
|
||||
if (!botAI->IsDps(bot))
|
||||
return false;
|
||||
|
||||
return boss && boss->IsAlive();
|
||||
Unit* flare = AI_VALUE2(Unit*, "find target", "astral flare");
|
||||
return flare != nullptr;
|
||||
}
|
||||
|
||||
bool KarazhanShadeOfAranTrigger::IsActive()
|
||||
bool TheCuratorBossEngagedByTanksTrigger::IsActive()
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "shade of aran");
|
||||
if (!botAI->IsMainTank(bot) && !botAI->IsAssistTankOfIndex(bot, 0))
|
||||
return false;
|
||||
|
||||
return boss && boss->IsAlive();
|
||||
Unit* curator = AI_VALUE2(Unit*, "find target", "the curator");
|
||||
return curator != nullptr;
|
||||
}
|
||||
|
||||
bool KarazhanNetherspiteTrigger::IsActive()
|
||||
bool TheCuratorBossAstralFlaresCastArcingSearTrigger::IsActive()
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "netherspite");
|
||||
if (!botAI->IsRanged(bot))
|
||||
return false;
|
||||
|
||||
return boss && boss->IsAlive();
|
||||
Unit* curator = AI_VALUE2(Unit*, "find target", "the curator");
|
||||
return curator != nullptr;
|
||||
}
|
||||
|
||||
bool KarazhanPrinceMalchezaarTrigger::IsActive()
|
||||
bool TerestianIllhoofNeedTargetPriorityTrigger::IsActive()
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "prince malchezaar");
|
||||
if (!IsMapIDTimerManager(botAI, bot))
|
||||
return false;
|
||||
|
||||
return boss && boss->IsAlive();
|
||||
Unit* illhoof = AI_VALUE2(Unit*, "find target", "terestian illhoof");
|
||||
return illhoof != nullptr;
|
||||
}
|
||||
|
||||
bool ShadeOfAranArcaneExplosionIsCastingTrigger::IsActive()
|
||||
{
|
||||
Unit* aran = AI_VALUE2(Unit*, "find target", "shade of aran");
|
||||
return aran && aran->HasUnitState(UNIT_STATE_CASTING) &&
|
||||
aran->FindCurrentSpellBySpellId(SPELL_ARCANE_EXPLOSION) &&
|
||||
!IsFlameWreathActive(botAI, bot);
|
||||
}
|
||||
|
||||
bool ShadeOfAranFlameWreathIsActiveTrigger::IsActive()
|
||||
{
|
||||
Unit* aran = AI_VALUE2(Unit*, "find target", "shade of aran");
|
||||
return aran && IsFlameWreathActive(botAI, bot);
|
||||
}
|
||||
|
||||
// Exclusion of Banish is so the player may Banish elementals if they wish
|
||||
bool ShadeOfAranConjuredElementalsSummonedTrigger::IsActive()
|
||||
{
|
||||
if (!IsMapIDTimerManager(botAI, bot))
|
||||
return false;
|
||||
|
||||
Unit* elemental = AI_VALUE2(Unit*, "find target", "conjured elemental");
|
||||
return elemental && elemental->IsAlive() &&
|
||||
!elemental->HasAura(SPELL_WARLOCK_BANISH);
|
||||
}
|
||||
|
||||
bool ShadeOfAranBossUsesCounterspellAndBlizzardTrigger::IsActive()
|
||||
{
|
||||
if (!botAI->IsRanged(bot))
|
||||
return false;
|
||||
|
||||
Unit* aran = AI_VALUE2(Unit*, "find target", "shade of aran");
|
||||
return aran && !(aran->HasUnitState(UNIT_STATE_CASTING) &&
|
||||
aran->FindCurrentSpellBySpellId(SPELL_ARCANE_EXPLOSION)) &&
|
||||
!IsFlameWreathActive(botAI, bot);
|
||||
}
|
||||
|
||||
bool NetherspiteRedBeamIsActiveTrigger::IsActive()
|
||||
{
|
||||
Unit* netherspite = AI_VALUE2(Unit*, "find target", "netherspite");
|
||||
if (!netherspite || netherspite->HasAura(SPELL_NETHERSPITE_BANISHED))
|
||||
return false;
|
||||
|
||||
Unit* redPortal = bot->FindNearestCreature(NPC_RED_PORTAL, 150.0f);
|
||||
return redPortal != nullptr;
|
||||
}
|
||||
|
||||
bool NetherspiteBlueBeamIsActiveTrigger::IsActive()
|
||||
{
|
||||
Unit* netherspite = AI_VALUE2(Unit*, "find target", "netherspite");
|
||||
if (!netherspite || netherspite->HasAura(SPELL_NETHERSPITE_BANISHED))
|
||||
return false;
|
||||
|
||||
Unit* bluePortal = bot->FindNearestCreature(NPC_BLUE_PORTAL, 150.0f);
|
||||
return bluePortal != nullptr;
|
||||
}
|
||||
|
||||
bool NetherspiteGreenBeamIsActiveTrigger::IsActive()
|
||||
{
|
||||
Unit* netherspite = AI_VALUE2(Unit*, "find target", "netherspite");
|
||||
if (!netherspite || netherspite->HasAura(SPELL_NETHERSPITE_BANISHED))
|
||||
return false;
|
||||
|
||||
Unit* greenPortal = bot->FindNearestCreature(NPC_GREEN_PORTAL, 150.0f);
|
||||
return greenPortal != nullptr;
|
||||
}
|
||||
|
||||
bool NetherspiteBotIsNotBeamBlockerTrigger::IsActive()
|
||||
{
|
||||
Unit* netherspite = AI_VALUE2(Unit*, "find target", "netherspite");
|
||||
if (!netherspite || netherspite->HasAura(SPELL_NETHERSPITE_BANISHED))
|
||||
return false;
|
||||
|
||||
auto [redBlocker, greenBlocker, blueBlocker] = GetCurrentBeamBlockers(botAI, bot);
|
||||
return bot != redBlocker && bot != blueBlocker && bot != greenBlocker;
|
||||
}
|
||||
|
||||
bool NetherspiteBossIsBanishedTrigger::IsActive()
|
||||
{
|
||||
Unit* netherspite = AI_VALUE2(Unit*, "find target", "netherspite");
|
||||
if (!netherspite || !netherspite->HasAura(SPELL_NETHERSPITE_BANISHED))
|
||||
return false;
|
||||
|
||||
std::vector<Unit*> voidZones = GetAllVoidZones(botAI, bot);
|
||||
for (Unit* vz : voidZones)
|
||||
{
|
||||
if (bot->GetExactDist2d(vz) < 4.0f)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NetherspiteNeedToManageTimersAndTrackersTrigger::IsActive()
|
||||
{
|
||||
if (!botAI->IsTank(bot) && !IsMapIDTimerManager(botAI, bot))
|
||||
return false;
|
||||
|
||||
Unit* netherspite = AI_VALUE2(Unit*, "find target", "netherspite");
|
||||
return netherspite != nullptr;
|
||||
}
|
||||
|
||||
bool PrinceMalchezaarBotIsEnfeebledTrigger::IsActive()
|
||||
{
|
||||
return bot->HasAura(SPELL_ENFEEBLE);
|
||||
}
|
||||
|
||||
bool PrinceMalchezaarInfernalsAreSpawnedTrigger::IsActive()
|
||||
{
|
||||
if (botAI->IsMainTank(bot) || bot->HasAura(SPELL_ENFEEBLE))
|
||||
return false;
|
||||
|
||||
Unit* malchezaar = AI_VALUE2(Unit*, "find target", "prince malchezaar");
|
||||
return malchezaar != nullptr;
|
||||
}
|
||||
|
||||
bool PrinceMalchezaarBossEngagedByMainTankTrigger::IsActive()
|
||||
{
|
||||
if (!botAI->IsMainTank(bot))
|
||||
return false;
|
||||
|
||||
Unit* malchezaar = AI_VALUE2(Unit*, "find target", "prince malchezaar");
|
||||
return malchezaar != nullptr;
|
||||
}
|
||||
|
||||
bool NightbaneBossEngagedByMainTankTrigger::IsActive()
|
||||
{
|
||||
if (!botAI->IsMainTank(bot))
|
||||
return false;
|
||||
|
||||
Unit* nightbane = AI_VALUE2(Unit*, "find target", "nightbane");
|
||||
return nightbane && nightbane->GetPositionZ() <= NIGHTBANE_FLIGHT_Z;
|
||||
}
|
||||
|
||||
bool NightbaneRangedBotsAreInCharredEarthTrigger::IsActive()
|
||||
{
|
||||
if (!botAI->IsRanged(bot))
|
||||
return false;
|
||||
|
||||
Unit* nightbane = AI_VALUE2(Unit*, "find target", "nightbane");
|
||||
return nightbane && nightbane->GetPositionZ() <= NIGHTBANE_FLIGHT_Z;
|
||||
}
|
||||
|
||||
bool NightbaneMainTankIsSusceptibleToFearTrigger::IsActive()
|
||||
{
|
||||
if (bot->getClass() != CLASS_PRIEST)
|
||||
return false;
|
||||
|
||||
Unit* nightbane = AI_VALUE2(Unit*, "find target", "nightbane");
|
||||
if (!nightbane)
|
||||
return false;
|
||||
|
||||
Player* mainTank = nullptr;
|
||||
if (Group* group = bot->GetGroup())
|
||||
{
|
||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||
{
|
||||
Player* member = ref->GetSource();
|
||||
if (member && botAI->IsMainTank(member))
|
||||
{
|
||||
mainTank = member;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mainTank && !mainTank->HasAura(SPELL_FEAR_WARD) &&
|
||||
botAI->CanCastSpell("fear ward", mainTank);
|
||||
}
|
||||
|
||||
bool NightbanePetsIgnoreCollisionToChaseFlyingBossTrigger::IsActive()
|
||||
{
|
||||
Unit* nightbane = AI_VALUE2(Unit*, "find target", "nightbane");
|
||||
if (!nightbane)
|
||||
return false;
|
||||
|
||||
Pet* pet = bot->GetPet();
|
||||
return pet && pet->IsAlive();
|
||||
}
|
||||
|
||||
bool NightbaneBossIsFlyingTrigger::IsActive()
|
||||
{
|
||||
Unit* nightbane = AI_VALUE2(Unit*, "find target", "nightbane");
|
||||
if (!nightbane || nightbane->GetPositionZ() <= NIGHTBANE_FLIGHT_Z)
|
||||
return false;
|
||||
|
||||
const time_t now = std::time(nullptr);
|
||||
const uint8 flightPhaseDurationSeconds = 35;
|
||||
|
||||
return nightbaneFlightPhaseStartTimer.find(KARAZHAN_MAP_ID) != nightbaneFlightPhaseStartTimer.end() &&
|
||||
(now - nightbaneFlightPhaseStartTimer[KARAZHAN_MAP_ID] < flightPhaseDurationSeconds);
|
||||
}
|
||||
|
||||
bool NightbaneNeedToManageTimersAndTrackersTrigger::IsActive()
|
||||
{
|
||||
Unit* nightbane = AI_VALUE2(Unit*, "find target", "nightbane");
|
||||
return nightbane != nullptr;
|
||||
}
|
||||
|
||||
@@ -3,80 +3,298 @@
|
||||
|
||||
#include "Trigger.h"
|
||||
|
||||
class KarazhanAttumenTheHuntsmanTrigger : public Trigger
|
||||
class ManaWarpIsAboutToExplodeTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
KarazhanAttumenTheHuntsmanTrigger(PlayerbotAI* botAI) : Trigger(botAI, "karazhan attumen the huntsman") {}
|
||||
ManaWarpIsAboutToExplodeTrigger(
|
||||
PlayerbotAI* botAI) : Trigger(botAI, "mana warp is about to explode") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class KarazhanMoroesTrigger : public Trigger
|
||||
class AttumenTheHuntsmanNeedTargetPriorityTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
KarazhanMoroesTrigger(PlayerbotAI* botAI) : Trigger(botAI, "karazhan moroes") {}
|
||||
AttumenTheHuntsmanNeedTargetPriorityTrigger(
|
||||
PlayerbotAI* botAI) : Trigger(botAI, "attumen the huntsman need target priority") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class KarazhanMaidenOfVirtueTrigger : public Trigger
|
||||
class AttumenTheHuntsmanAttumenSpawnedTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
KarazhanMaidenOfVirtueTrigger(PlayerbotAI* botAI) : Trigger(botAI, "karazhan maiden of virtue") {}
|
||||
AttumenTheHuntsmanAttumenSpawnedTrigger(
|
||||
PlayerbotAI* botAI) : Trigger(botAI, "attumen the huntsman attumen spawned") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class KarazhanBigBadWolfTrigger : public Trigger
|
||||
class AttumenTheHuntsmanAttumenIsMountedTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
KarazhanBigBadWolfTrigger(PlayerbotAI* botAI) : Trigger(botAI, "karazhan big bad wolf") {}
|
||||
AttumenTheHuntsmanAttumenIsMountedTrigger(
|
||||
PlayerbotAI* botAI) : Trigger(botAI, "attumen the huntsman attumen is mounted") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class KarazhanRomuloAndJulianneTrigger : public Trigger
|
||||
class AttumenTheHuntsmanBossWipesAggroWhenMountingTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
KarazhanRomuloAndJulianneTrigger(PlayerbotAI* botAI) : Trigger(botAI, "karazhan romulo and julianne") {}
|
||||
AttumenTheHuntsmanBossWipesAggroWhenMountingTrigger(
|
||||
PlayerbotAI* botAI) : Trigger(botAI, "attumen the huntsman boss wipes aggro when mounting") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class KarazhanWizardOfOzTrigger : public Trigger
|
||||
class MoroesBossEngagedByMainTankTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
KarazhanWizardOfOzTrigger(PlayerbotAI* botAI) : Trigger(botAI, "karazhan wizard of oz") {}
|
||||
MoroesBossEngagedByMainTankTrigger(
|
||||
PlayerbotAI* botAI) : Trigger(botAI, "moroes boss engaged by main tank") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class KarazhanTheCuratorTrigger : public Trigger
|
||||
class MoroesNeedTargetPriorityTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
KarazhanTheCuratorTrigger(PlayerbotAI* botAI) : Trigger(botAI, "karazhan the curator") {}
|
||||
MoroesNeedTargetPriorityTrigger(
|
||||
PlayerbotAI* botAI) : Trigger(botAI, "moroes need target priority") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class KarazhanTerestianIllhoofTrigger : public Trigger
|
||||
class MaidenOfVirtueHealersAreStunnedByRepentanceTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
KarazhanTerestianIllhoofTrigger(PlayerbotAI* botAI) : Trigger(botAI, "karazhan terestian illhoof") {}
|
||||
MaidenOfVirtueHealersAreStunnedByRepentanceTrigger(
|
||||
PlayerbotAI* botAI) : Trigger(botAI, "maiden of virtue healers are stunned by repentance") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class KarazhanShadeOfAranTrigger : public Trigger
|
||||
class MaidenOfVirtueHolyWrathDealsChainDamageTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
KarazhanShadeOfAranTrigger(PlayerbotAI* botAI) : Trigger(botAI, "karazhan shade of aran") {}
|
||||
MaidenOfVirtueHolyWrathDealsChainDamageTrigger(
|
||||
PlayerbotAI* botAI) : Trigger(botAI, "maiden of virtue holy wrath deals chain damage") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class KarazhanNetherspiteTrigger : public Trigger
|
||||
class BigBadWolfBossEngagedByTankTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
KarazhanNetherspiteTrigger(PlayerbotAI* botAI) : Trigger(botAI, "karazhan netherspite") {}
|
||||
BigBadWolfBossEngagedByTankTrigger(
|
||||
PlayerbotAI* botAI) : Trigger(botAI, "big bad wolf boss engaged by tank") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class KarazhanPrinceMalchezaarTrigger : public Trigger
|
||||
class BigBadWolfBossIsChasingLittleRedRidingHoodTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
KarazhanPrinceMalchezaarTrigger(PlayerbotAI* botAI) : Trigger(botAI, "karazhan prince malchezaar") {}
|
||||
BigBadWolfBossIsChasingLittleRedRidingHoodTrigger(
|
||||
PlayerbotAI* botAI) : Trigger(botAI, "big bad wolf boss is chasing little red riding hood") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class RomuloAndJulianneBothBossesRevivedTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
RomuloAndJulianneBothBossesRevivedTrigger(
|
||||
PlayerbotAI* botAI) : Trigger(botAI, "romulo and julianne both bosses revived") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class WizardOfOzNeedTargetPriorityTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
WizardOfOzNeedTargetPriorityTrigger(
|
||||
PlayerbotAI* botAI) : Trigger(botAI, "wizard of oz need target priority") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class WizardOfOzStrawmanIsVulnerableToFireTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
WizardOfOzStrawmanIsVulnerableToFireTrigger(
|
||||
PlayerbotAI* botAI) : Trigger(botAI, "wizard of oz strawman is vulnerable to fire") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
class TheCuratorAstralFlareSpawnedTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
TheCuratorAstralFlareSpawnedTrigger(
|
||||
PlayerbotAI* botAI) : Trigger(botAI, "the curator astral flare spawned") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class TheCuratorBossEngagedByTanksTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
TheCuratorBossEngagedByTanksTrigger(
|
||||
PlayerbotAI* botAI) : Trigger(botAI, "the curator boss engaged by tanks") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class TheCuratorBossAstralFlaresCastArcingSearTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
TheCuratorBossAstralFlaresCastArcingSearTrigger(
|
||||
PlayerbotAI* botAI) : Trigger(botAI, "the curator astral flares cast arcing sear") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class TerestianIllhoofNeedTargetPriorityTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
TerestianIllhoofNeedTargetPriorityTrigger(
|
||||
PlayerbotAI* botAI) : Trigger(botAI, "terestian illhoof need target priority") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class ShadeOfAranArcaneExplosionIsCastingTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
ShadeOfAranArcaneExplosionIsCastingTrigger(
|
||||
PlayerbotAI* botAI) : Trigger(botAI, "shade of aran arcane explosion is casting") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class ShadeOfAranFlameWreathIsActiveTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
ShadeOfAranFlameWreathIsActiveTrigger(
|
||||
PlayerbotAI* botAI) : Trigger(botAI, "shade of aran flame wreath is active") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class ShadeOfAranConjuredElementalsSummonedTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
ShadeOfAranConjuredElementalsSummonedTrigger(
|
||||
PlayerbotAI* botAI) : Trigger(botAI, "shade of aran conjured elementals summoned") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class ShadeOfAranBossUsesCounterspellAndBlizzardTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
ShadeOfAranBossUsesCounterspellAndBlizzardTrigger(
|
||||
PlayerbotAI* botAI) : Trigger(botAI, "shade of aran boss uses counterspell and blizzard") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class NetherspiteRedBeamIsActiveTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
NetherspiteRedBeamIsActiveTrigger(
|
||||
PlayerbotAI* botAI) : Trigger(botAI, "netherspite red beam is active") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class NetherspiteBlueBeamIsActiveTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
NetherspiteBlueBeamIsActiveTrigger(
|
||||
PlayerbotAI* botAI) : Trigger(botAI, "netherspite blue beam is active") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class NetherspiteGreenBeamIsActiveTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
NetherspiteGreenBeamIsActiveTrigger(
|
||||
PlayerbotAI* botAI) : Trigger(botAI, "netherspite green beam is active") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class NetherspiteBotIsNotBeamBlockerTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
NetherspiteBotIsNotBeamBlockerTrigger(
|
||||
PlayerbotAI* botAI) : Trigger(botAI, "netherspite bot is not beam blocker") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class NetherspiteBossIsBanishedTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
NetherspiteBossIsBanishedTrigger(
|
||||
PlayerbotAI* botAI) : Trigger(botAI, "netherspite boss is banished") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class NetherspiteNeedToManageTimersAndTrackersTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
NetherspiteNeedToManageTimersAndTrackersTrigger(
|
||||
PlayerbotAI* botAI) : Trigger(botAI, "netherspite need to manage timers and trackers") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class PrinceMalchezaarBotIsEnfeebledTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
PrinceMalchezaarBotIsEnfeebledTrigger(
|
||||
PlayerbotAI* botAI) : Trigger(botAI, "prince malchezaar bot is enfeebled") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class PrinceMalchezaarInfernalsAreSpawnedTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
PrinceMalchezaarInfernalsAreSpawnedTrigger(
|
||||
PlayerbotAI* botAI) : Trigger(botAI, "prince malchezaar infernals are spawned") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class PrinceMalchezaarBossEngagedByMainTankTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
PrinceMalchezaarBossEngagedByMainTankTrigger(
|
||||
PlayerbotAI* botAI) : Trigger(botAI, "prince malchezaar boss engaged by main tank") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class NightbaneBossEngagedByMainTankTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
NightbaneBossEngagedByMainTankTrigger(
|
||||
PlayerbotAI* botAI) : Trigger(botAI, "nightbane boss engaged by main tank") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class NightbaneRangedBotsAreInCharredEarthTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
NightbaneRangedBotsAreInCharredEarthTrigger(
|
||||
PlayerbotAI* botAI) : Trigger(botAI, "nightbane ranged bots are in charred earth") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class NightbaneMainTankIsSusceptibleToFearTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
NightbaneMainTankIsSusceptibleToFearTrigger(
|
||||
PlayerbotAI* botAI) : Trigger(botAI, "nightbane main tank is susceptible to fear") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class NightbanePetsIgnoreCollisionToChaseFlyingBossTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
NightbanePetsIgnoreCollisionToChaseFlyingBossTrigger(
|
||||
PlayerbotAI* botAI) : Trigger(botAI, "nightbane pets ignore collision to chase flying boss") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class NightbaneBossIsFlyingTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
NightbaneBossIsFlyingTrigger(
|
||||
PlayerbotAI* botAI) : Trigger(botAI, "nightbane boss is flying") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class NightbaneNeedToManageTimersAndTrackersTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
NightbaneNeedToManageTimersAndTrackersTrigger(
|
||||
PlayerbotAI* botAI) : Trigger(botAI, "nightbane need to manage timers and trackers") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user