Mage Overhaul

Hello everyone,

Back again with another class overhaul. Here is a list of what changes have been made:
1. Consolidated the AoE strategies into "aoe". For light aoe (2+ enemies) the mage will use Cone of Cold (frost)/Arcane Explosion (Arcane)/Multi-Dot with Living Bomb (Fire/Frostfire). For medium aoe (3+ enemies) they will use Flamestrike -> Blizzard. Also, the mage will automatically cancel channeling their blizzard if there is less than 2 enemies around. This is huge, since the mage would often stand there and finish their entire channel during a boss fight after the adds died.
2. Organized actions, triggers, and the aiobjectcontext
3. Enabled Deep Freeze to be casted on bosses regardless of their immune status. Big benefit for frost dps on boss fights.
4. Slight tweaks in the conf so Arcane gets Arcane Barrage and Frostfire gets 2/2 Firestarter
5. Streamlined Arcane DPS to use Missile Barrage proc when at 4 stacks of Arcane Blast
5. Streamlined Fire/Frostfire DPS to keep Improved Scorch active (5% spell crit) unless there is a debuff of equal type
6. Added "firestarter" strategy, that utilizes the Fire talent Firestarter better. The mage will multi-dot Living Bomb while running towards melee, and cast Dragon's Breath -> instant cast Flamestrike -> Blast Wave -> instant cast Flamestrike -> Blizzard for bonkers damage. Disabled by default - not everyone wants their mages running into melee. Enable by typing "co +firestarter" on fire and frostfire mages.
7. Streamlined Frost DPS by finally adding support for Cold Snap for mages. It will proc when both Icy Veins and Deep Freeze are on cooldown. There is an exception to this - if the mage is level 30-59, it will not check for Deep Freeze - only Icy Veins.
8. Added Conjure Mana Gem support in the generic non-combat strategy and Use Mana Gem support in the generic combat strategy. This might be the biggest benefit of the overhaul - the gem has a 90 second cooldown, not shared with mana potions. It really prevents the mage from gassing out in longer fights. And the mana gem has 3 charges!
9. Added Mana Shield ability, which triggers on low health.
10. Changed Mirror Image from a boost ability to an anti-threat tool. Not many people know this, but it's best use in PvE is it's anti-threat modifier: "Mod Total Threat - Temporary Value: -90000000". It also doesn't do good damage, and is essentially used best as a pre-pull spell. But until the mages know how to react to a pull-timer, it's going to be used to reduce threat.

Let me know what y'all think!
This commit is contained in:
ThePenguinMan96
2025-07-26 01:49:49 -07:00
parent b65646170c
commit ee245f73b5
19 changed files with 985 additions and 547 deletions

View File

@@ -9,11 +9,15 @@
#include "CureTriggers.h"
#include "GenericTriggers.h"
#include "SharedDefines.h"
#include "Trigger.h"
#include "Playerbots.h"
#include "PlayerbotAI.h"
#include <set>
#include <unordered_set>
class PlayerbotAI;
DEFLECT_TRIGGER(FireWardTrigger, "fire ward");
DEFLECT_TRIGGER(FrostWardTrigger, "frost ward");
// Buff and Out of Combat Triggers
class ArcaneIntellectOnPartyTrigger : public BuffOnPartyTrigger
{
@@ -37,30 +41,53 @@ public:
bool IsActive() override;
};
class LivingBombTrigger : public DebuffTrigger
class NoFocusMagicTrigger : public Trigger
{
public:
LivingBombTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "living bomb", 1, true) {}
NoFocusMagicTrigger(PlayerbotAI* botAI) : Trigger(botAI, "no focus magic") {}
bool IsActive() override;
};
class FireballTrigger : public DebuffTrigger
class IceBarrierTrigger : public BuffTrigger
{
public:
FireballTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "fireball", 1, true) {}
IceBarrierTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "ice barrier") {}
};
class PyroblastTrigger : public DebuffTrigger
class NoManaGemTrigger : public Trigger
{
public:
PyroblastTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "pyroblast", 1, true) {}
NoManaGemTrigger(PlayerbotAI* botAI) : Trigger(botAI, "no mana gem") {}
bool IsActive() override;
};
class FireWardTrigger : public DeflectSpellTrigger
{
public:
FireWardTrigger(PlayerbotAI* botAI) : DeflectSpellTrigger(botAI, "fire ward") {}
};
class FrostWardTrigger : public DeflectSpellTrigger
{
public:
FrostWardTrigger(PlayerbotAI* botAI) : DeflectSpellTrigger(botAI, "frost ward") {}
};
// Proc and Boost Triggers
class HotStreakTrigger : public HasAuraTrigger
{
public:
HotStreakTrigger(PlayerbotAI* botAI) : HasAuraTrigger(botAI, "hot streak") {}
};
class FirestarterTrigger : public HasAuraTrigger
{
public:
FirestarterTrigger(PlayerbotAI* botAI) : HasAuraTrigger(botAI, "firestarter") {}
};
class MissileBarrageTrigger : public HasAuraTrigger
{
public:
@@ -73,55 +100,71 @@ public:
ArcaneBlastTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "arcane blast") {}
};
class FingersOfFrostSingleTrigger : public HasAuraStackTrigger
class ArcaneBlastStackTrigger : public HasAuraStackTrigger
{
public:
FingersOfFrostSingleTrigger(PlayerbotAI* ai) : HasAuraStackTrigger(ai, "fingers of frost", 1, 1) {}
ArcaneBlastStackTrigger(PlayerbotAI* botAI) : HasAuraStackTrigger(botAI, "arcane blast", 4, 1) {}
};
class ArcaneBlast4StacksAndMissileBarrageTrigger : public TwoTriggers
{
public:
ArcaneBlast4StacksAndMissileBarrageTrigger(PlayerbotAI* ai)
: TwoTriggers(ai, "arcane blast stack", "missile barrage")
{
}
};
class CombustionTrigger : public BuffTrigger
{
public:
CombustionTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "combustion") {}
};
class IcyVeinsCooldownTrigger : public SpellCooldownTrigger
{
public:
IcyVeinsCooldownTrigger(PlayerbotAI* botAI) : SpellCooldownTrigger(botAI, "icy veins") {}
};
class DeepFreezeCooldownTrigger : public SpellCooldownTrigger
{
public:
DeepFreezeCooldownTrigger(PlayerbotAI* botAI) : SpellCooldownTrigger(botAI, "deep freeze") {}
bool IsActive() override;
};
class FingersOfFrostDoubleTrigger : public HasAuraStackTrigger
class ColdSnapTrigger : public TwoTriggers
{
public:
FingersOfFrostDoubleTrigger(PlayerbotAI* ai) : HasAuraStackTrigger(ai, "fingers of frost", 2, 1) {}
// bool IsActive() override;
ColdSnapTrigger(PlayerbotAI* ai) : TwoTriggers(ai, "icy veins on cd", "deep freeze on cd") {}
};
class BrainFreezeTrigger : public HasAuraTrigger
class MirrorImageTrigger : public BuffTrigger
{
public:
BrainFreezeTrigger(PlayerbotAI* botAI) : HasAuraTrigger(botAI, "fireball!") {}
MirrorImageTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "mirror image") {}
};
class CounterspellInterruptSpellTrigger : public InterruptSpellTrigger
class IcyVeinsTrigger : public BuffTrigger
{
public:
CounterspellInterruptSpellTrigger(PlayerbotAI* botAI) : InterruptSpellTrigger(botAI, "counterspell") {}
IcyVeinsTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "icy veins") {}
};
class CombustionTrigger : public BoostTrigger
class ArcanePowerTrigger : public BuffTrigger
{
public:
CombustionTrigger(PlayerbotAI* botAI) : BoostTrigger(botAI, "combustion") {}
ArcanePowerTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "arcane power") {}
};
class PresenceOfMindTrigger : public BuffTrigger
{
public:
PresenceOfMindTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "presence of mind") {}
};
class IcyVeinsTrigger : public BoostTrigger
{
public:
IcyVeinsTrigger(PlayerbotAI* botAI) : BoostTrigger(botAI, "icy veins") {}
};
class ColdSnapTrigger : public BoostTrigger
{
public:
ColdSnapTrigger(PlayerbotAI* botAI) : BoostTrigger(botAI, "cold snap") {}
};
class IceBarrierTrigger : public BuffTrigger
{
public:
IceBarrierTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "ice barrier") {}
};
// CC, Interrupt, and Dispel Triggers
class PolymorphTrigger : public HasCcTargetTrigger
{
@@ -155,29 +198,63 @@ public:
CounterspellEnemyHealerTrigger(PlayerbotAI* botAI) : InterruptEnemyHealerTrigger(botAI, "counterspell") {}
};
class ArcanePowerTrigger : public BuffTrigger
class CounterspellInterruptSpellTrigger : public InterruptSpellTrigger
{
public:
ArcanePowerTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "arcane power") {}
CounterspellInterruptSpellTrigger(PlayerbotAI* botAI) : InterruptSpellTrigger(botAI, "counterspell") {}
};
class PresenceOfMindTrigger : public BuffTrigger
// Damage and Debuff Triggers
class LivingBombTrigger : public DebuffTrigger
{
public:
PresenceOfMindTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "presence of mind") {}
LivingBombTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "living bomb", 1, true) {}
bool IsActive() override { return BuffTrigger::IsActive(); }
};
class ArcaneBlastStackTrigger : public HasAuraStackTrigger
class LivingBombOnAttackersTrigger : public DebuffOnAttackerTrigger
{
public:
ArcaneBlastStackTrigger(PlayerbotAI* botAI) : HasAuraStackTrigger(botAI, "arcane blast", 3, 1) {}
LivingBombOnAttackersTrigger(PlayerbotAI* ai) : DebuffOnAttackerTrigger(ai, "living bomb", true) {}
bool IsActive() override { return BuffTrigger::IsActive(); }
};
class FireballTrigger : public DebuffTrigger
{
public:
FireballTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "fireball", 1, true) {}
};
class ImprovedScorchTrigger : public DebuffTrigger
{
public:
ImprovedScorchTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "improved scorch", 1, true, 0.5f) {}
bool IsActive() override;
};
class MirrorImageTrigger : public BoostTrigger
class PyroblastTrigger : public DebuffTrigger
{
public:
MirrorImageTrigger(PlayerbotAI* botAI) : BoostTrigger(botAI, "mirror image") {}
PyroblastTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "pyroblast", 1, true) {}
};
class FrostfireBoltTrigger : public DebuffTrigger
{
public:
FrostfireBoltTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "frostfire bolt", 1, true) {}
};
class FingersOfFrostTrigger : public HasAuraTrigger
{
public:
FingersOfFrostTrigger(PlayerbotAI* botAI) : HasAuraTrigger(botAI, "fingers of frost") {}
};
class BrainFreezeTrigger : public HasAuraTrigger
{
public:
BrainFreezeTrigger(PlayerbotAI* botAI) : HasAuraTrigger(botAI, "fireball!") {}
};
class FrostNovaOnTargetTrigger : public DebuffTrigger
@@ -194,17 +271,74 @@ public:
bool IsActive() override;
};
class NoFocusMagicTrigger : public Trigger
class FlamestrikeNearbyTrigger : public Trigger
{
public:
NoFocusMagicTrigger(PlayerbotAI* botAI) : Trigger(botAI, "no focus magic") {}
FlamestrikeNearbyTrigger(PlayerbotAI* botAI, float radius = 30.0f)
: Trigger(botAI, "flamestrike nearby"), radius(radius)
{
}
bool IsActive() override;
protected:
float radius;
static const std::set<uint32> FLAMESTRIKE_SPELL_IDS;
};
class FrostfireBoltTrigger : public DebuffTrigger
class FlamestrikeBlizzardTrigger : public TwoTriggers
{
public:
FrostfireBoltTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "frostfire bolt", 1, true) {}
FlamestrikeBlizzardTrigger(PlayerbotAI* ai) : TwoTriggers(ai, "flamestrike nearby", "medium aoe") {}
};
class BlizzardChannelCheckTrigger : public Trigger
{
public:
BlizzardChannelCheckTrigger(PlayerbotAI* botAI, uint32 minEnemies = 2)
: Trigger(botAI, "blizzard channel check"), minEnemies(minEnemies) {}
bool IsActive() override;
protected:
uint32 minEnemies;
static const std::set<uint32> BLIZZARD_SPELL_IDS;
};
class BlastWaveOffCdTrigger : public SpellNoCooldownTrigger
{
public:
BlastWaveOffCdTrigger(PlayerbotAI* botAI) : SpellNoCooldownTrigger(botAI, "blast wave") {}
};
class BlastWaveOffCdTriggerAndMediumAoeTrigger : public TwoTriggers
{
public:
BlastWaveOffCdTriggerAndMediumAoeTrigger(PlayerbotAI* ai) : TwoTriggers(ai, "blast wave off cd", "medium aoe") {}
};
class NoFirestarterStrategyTrigger : public Trigger
{
public:
NoFirestarterStrategyTrigger(PlayerbotAI* botAI) : Trigger(botAI, "no firestarter strategy") {}
bool IsActive() override
{
return !botAI->HasStrategy("firestarter", BOT_STATE_COMBAT);
}
};
class EnemyIsCloseAndNoFirestarterStrategyTrigger : public TwoTriggers
{
public:
EnemyIsCloseAndNoFirestarterStrategyTrigger(PlayerbotAI* botAI)
: TwoTriggers(botAI, "enemy is close", "no firestarter strategy") {}
};
class EnemyTooCloseForSpellAndNoFirestarterStrategyTrigger : public TwoTriggers
{
public:
EnemyTooCloseForSpellAndNoFirestarterStrategyTrigger(PlayerbotAI* botAI)
: TwoTriggers(botAI, "enemy too close for spell", "no firestarter strategy") {}
};
#endif