Skip to content

Commit

Permalink
Merge pull request liyunfan1223#360 from Bobblybook/master
Browse files Browse the repository at this point in the history
Frost mage implementation
  • Loading branch information
liyunfan1223 authored Jul 23, 2024
2 parents 467633a + b1ffbf2 commit b059efa
Show file tree
Hide file tree
Showing 7 changed files with 259 additions and 15 deletions.
80 changes: 76 additions & 4 deletions src/strategy/mage/FrostMageStrategy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,99 @@
#include "FrostMageStrategy.h"
#include "Playerbots.h"

class FrostMageStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
{
public:
FrostMageStrategyActionNodeFactory()
{
creators["cold snap"] = &cold_snap;
creators["ice barrier"] = &ice_barrier;
creators["summon water elemental"] = &summon_water_elemental;
creators["deep freeze"] = &deep_freeze;
}
private:
static ActionNode* cold_snap([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode ("cold snap",
/*P*/ nullptr,
/*A*/ nullptr,
/*C*/ nullptr);
}

static ActionNode* ice_barrier([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode ("ice barrier",
/*P*/ nullptr,
/*A*/ nullptr,
/*C*/ nullptr);
}

static ActionNode* summon_water_elemental([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode ("summon water elemental",
/*P*/ nullptr,
/*A*/ nullptr,
/*C*/ nullptr);
}

static ActionNode* deep_freeze([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode ("deep freeze",
/*P*/ nullptr,
/*A*/ NextAction::array(0, new NextAction("ice lance"), nullptr),
/*C*/ nullptr);
}
};

FrostMageStrategy::FrostMageStrategy(PlayerbotAI* botAI) : GenericMageStrategy(botAI)
{
actionNodeFactories.Add(new FrostMageStrategyActionNodeFactory());
}

NextAction** FrostMageStrategy::getDefaultActions()
{
return NextAction::array(0,
new NextAction("frostbolt", ACTION_DEFAULT + 0.1f),
new NextAction("shoot", ACTION_DEFAULT),
new NextAction("frostbolt", ACTION_DEFAULT + 0.1f),
new NextAction("shoot", ACTION_DEFAULT),
nullptr);

}

void FrostMageStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
GenericMageStrategy::InitTriggers(triggers);

triggers.push_back(new TriggerNode("icy veins", NextAction::array(0, new NextAction("icy veins", 50.0f), nullptr)));
// No logic currently for cold snap usage.. possibly use right after icy veins drops off?
// triggers.push_back(new TriggerNode("cold snap", NextAction::array(0, new NextAction("cold snap", 50.0f), nullptr)));

triggers.push_back(new TriggerNode("no pet", NextAction::array(0, new NextAction("summon water elemental", ACTION_HIGH), nullptr)));
triggers.push_back(new TriggerNode("has pet", NextAction::array(0, new NextAction("toggle pet spell", ACTION_HIGH + 1), nullptr)));
triggers.push_back(new TriggerNode("ice barrier", NextAction::array(0, new NextAction("ice barrier", ACTION_NORMAL), nullptr)));

triggers.push_back(new TriggerNode("brain freeze", NextAction::array(0, new NextAction("frostfire bolt", ACTION_NORMAL + 3), nullptr)));
// Combo cast the last charge of fingers of frost for double crits.
// Should only do this on the final charge of FoF.
triggers.push_back(new TriggerNode("fingers of frost single", NextAction::array(0,
new NextAction("frostbolt", ACTION_NORMAL + 2),
new NextAction("deep freeze", ACTION_NORMAL + 1),
nullptr)));
// May not need this, frostbolt is the default action so probably don't need to specify.
// Maybe uncomment if you find the mage is prioritising auxillary spells while this buff is up, and wasting the proc.
// triggers.push_back(new TriggerNode("fingers of frost double", NextAction::array(0, new NextAction("frostbolt", ACTION_NORMAL), nullptr)));

// Same 2-spell combo for various freeze procs
triggers.push_back(new TriggerNode("frost nova on target", NextAction::array(0,
new NextAction("frostbolt", ACTION_NORMAL + 2),
new NextAction("deep freeze", ACTION_NORMAL + 1),
nullptr)));
triggers.push_back(new TriggerNode("frostbite on target", NextAction::array(0,
new NextAction("frostbolt", ACTION_NORMAL + 2),
new NextAction("deep freeze", ACTION_NORMAL + 1),
nullptr)));
}

void FrostMageAoeStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(new TriggerNode("light aoe", NextAction::array(0, new NextAction("blizzard", 40.0f), nullptr)));
triggers.push_back(new TriggerNode("medium aoe", NextAction::array(0, new NextAction("blizzard", ACTION_HIGH), nullptr)));
triggers.push_back(new TriggerNode("light aoe", NextAction::array(0, new NextAction("cone of cold", ACTION_HIGH + 1), nullptr)));
}
29 changes: 28 additions & 1 deletion src/strategy/mage/GenericMageStrategy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,12 @@ class GenericMageStrategyActionNodeFactory : public NamedObjectFactory<ActionNod
GenericMageStrategyActionNodeFactory()
{
creators["frostbolt"] = &frostbolt;
creators["frostfire bolt"] = &frostfire_bolt;
creators["ice lance"] = &ice_lance;
creators["fire blast"] = &fire_blast;
creators["scorch"] = &scorch;
creators["frost nova"] = &frost_nova;
creators["cone of cold"] = &cone_of_cold;
creators["icy veins"] = &icy_veins;
creators["combustion"] = &combustion;
creators["evocation"] = &evocation;
Expand All @@ -34,6 +37,22 @@ class GenericMageStrategyActionNodeFactory : public NamedObjectFactory<ActionNod
/*C*/ nullptr);
}

static ActionNode* frostfire_bolt([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode ("frostfire bolt",
/*P*/ nullptr,
/*A*/ NextAction::array(0, new NextAction("fireball"), nullptr),
/*C*/ nullptr);
}

static ActionNode* ice_lance([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode ("ice lance",
/*P*/ nullptr,
/*A*/ nullptr,
/*C*/ nullptr);
}

static ActionNode* fire_blast([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode ("fire blast",
Expand All @@ -55,7 +74,15 @@ class GenericMageStrategyActionNodeFactory : public NamedObjectFactory<ActionNod
return new ActionNode ("frost nova",
/*P*/ nullptr,
/*A*/ nullptr,
/*C*/ nullptr);
/*C*/ nullptr);
}

static ActionNode* cone_of_cold([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode ("cone of cold",
/*P*/ nullptr,
/*A*/ nullptr,
/*C*/ nullptr);
}

static ActionNode* icy_veins([[maybe_unused]] PlayerbotAI* botAI)
Expand Down
7 changes: 7 additions & 0 deletions src/strategy/mage/MageActions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,10 @@ bool CastFrostNovaAction::isUseful()
{
return sServerFacade->IsDistanceLessOrEqualThan(AI_VALUE2(float, "distance", GetTargetName()), 10.f);
}

bool CastConeOfColdAction::isUseful()
{
bool facingTarget = AI_VALUE2(bool, "facing", "current target");
bool targetClose = sServerFacade->IsDistanceLessOrEqualThan(AI_VALUE2(float, "distance", GetTargetName()), 10.f);
return facingTarget && targetClose;
}
47 changes: 43 additions & 4 deletions src/strategy/mage/MageActions.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ class CastArcaneBlastAction : public CastBuffSpellAction
{
public:
CastArcaneBlastAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "arcane blast") { }

std::string const GetTargetName() override { return "current target"; }
};

Expand Down Expand Up @@ -68,7 +67,6 @@ class CastFrostNovaAction : public CastSpellAction
{
public:
CastFrostNovaAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "frost nova") { }

bool isUseful() override;
};

Expand All @@ -78,12 +76,37 @@ class CastFrostboltAction : public CastSpellAction
CastFrostboltAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "frostbolt") { }
};

class CastFrostfireBoltAction : public CastSpellAction
{
public:
CastFrostfireBoltAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "frostfire bolt") { }
};

class CastIceLanceAction : public CastSpellAction
{
public:
CastIceLanceAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "ice lance") { }
};

class CastDeepFreezeAction : public CastSpellAction
{
public:
CastDeepFreezeAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "deep freeze") { }
};

class CastBlizzardAction : public CastSpellAction
{
public:
CastBlizzardAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "blizzard") { }
ActionThreatType getThreatType() override { return ActionThreatType::Aoe; }
};

class CastConeOfColdAction : public CastSpellAction
{
public:
CastConeOfColdAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "cone of cold") { }
ActionThreatType getThreatType() override { return ActionThreatType::Aoe; }
bool isUseful() override;
};

class CastArcaneIntellectAction : public CastBuffSpellAction
Expand Down Expand Up @@ -116,6 +139,24 @@ class CastIcyVeinsAction : public CastBuffSpellAction
CastIcyVeinsAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "icy veins") { }
};

class CastColdSnapAction : public CastBuffSpellAction
{
public:
CastColdSnapAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "cold snap") { }
};

class CastIceBarrierAction : public CastBuffSpellAction
{
public:
CastIceBarrierAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "ice barrier") { }
};

class CastSummonWaterElementalAction : public CastBuffSpellAction
{
public:
CastSummonWaterElementalAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "summon water elemental") { }
};

class CastCombustionAction : public CastBuffSpellAction
{
public:
Expand Down Expand Up @@ -183,7 +224,6 @@ class CastPolymorphAction : public CastBuffSpellAction
{
public:
CastPolymorphAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "polymorph") { }

Value<Unit*>* GetTargetValue() override;
};

Expand Down Expand Up @@ -223,7 +263,6 @@ class CastEvocationAction : public CastSpellAction
{
public:
CastEvocationAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "evocation") { }

std::string const GetTargetName() override { return "self target"; }
};

Expand Down
28 changes: 28 additions & 0 deletions src/strategy/mage/MageAiObjectContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,12 @@ class MageTriggerFactoryInternal : public NamedObjectContext<Trigger>
creators["fireball"] = &MageTriggerFactoryInternal::fireball;
creators["pyroblast"] = &MageTriggerFactoryInternal::pyroblast;
creators["combustion"] = &MageTriggerFactoryInternal::combustion;
creators["fingers of frost single"] = &MageTriggerFactoryInternal::fingers_of_frost_single;
creators["fingers of frost double"] = &MageTriggerFactoryInternal::fingers_of_frost_double;
creators["brain freeze"] = &MageTriggerFactoryInternal::brain_freeze;
creators["icy veins"] = &MageTriggerFactoryInternal::icy_veins;
creators["cold snap"] = &MageTriggerFactoryInternal::cold_snap;
creators["ice barrier"] = &MageTriggerFactoryInternal::ice_barrier;
creators["arcane intellect"] = &MageTriggerFactoryInternal::arcane_intellect;
creators["arcane intellect on party"] = &MageTriggerFactoryInternal::arcane_intellect_on_party;
creators["mage armor"] = &MageTriggerFactoryInternal::mage_armor;
Expand All @@ -99,6 +104,8 @@ class MageTriggerFactoryInternal : public NamedObjectContext<Trigger>
creators["frost ward"] = &MageTriggerFactoryInternal::frost_ward;
creators["arcane blast stack"] = &MageTriggerFactoryInternal::arcane_blast_stack;
creators["mirror image"] = &MageTriggerFactoryInternal::mirror_image;
creators["frost nova on target"] = &MageTriggerFactoryInternal::frost_nova_on_target;
creators["frostbite on target"] = &MageTriggerFactoryInternal::frostbite_on_target;
}

private:
Expand All @@ -110,7 +117,12 @@ class MageTriggerFactoryInternal : public NamedObjectContext<Trigger>
static Trigger* fireball(PlayerbotAI* botAI) { return new FireballTrigger(botAI); }
static Trigger* pyroblast(PlayerbotAI* botAI) { return new PyroblastTrigger(botAI); }
static Trigger* combustion(PlayerbotAI* botAI) { return new CombustionTrigger(botAI); }
static Trigger* fingers_of_frost_single(PlayerbotAI* botAI) { return new FingersOfFrostSingleTrigger(botAI); }
static Trigger* fingers_of_frost_double(PlayerbotAI* botAI) { return new FingersOfFrostDoubleTrigger(botAI); }
static Trigger* brain_freeze(PlayerbotAI* botAI) { return new BrainFreezeTrigger(botAI); }
static Trigger* icy_veins(PlayerbotAI* botAI) { return new IcyVeinsTrigger(botAI); }
static Trigger* cold_snap(PlayerbotAI* botAI) { return new ColdSnapTrigger(botAI); }
static Trigger* ice_barrier(PlayerbotAI* botAI) { return new IceBarrierTrigger(botAI); }
static Trigger* arcane_intellect(PlayerbotAI* botAI) { return new ArcaneIntellectTrigger(botAI); }
static Trigger* arcane_intellect_on_party(PlayerbotAI* botAI) { return new ArcaneIntellectOnPartyTrigger(botAI); }
static Trigger* mage_armor(PlayerbotAI* botAI) { return new MageArmorTrigger(botAI); }
Expand All @@ -125,6 +137,8 @@ class MageTriggerFactoryInternal : public NamedObjectContext<Trigger>
static Trigger* counterspell_enemy_healer(PlayerbotAI* botAI) { return new CounterspellEnemyHealerTrigger(botAI); }
static Trigger* arcane_blast_stack(PlayerbotAI* botAI) { return new ArcaneBlastStackTrigger(botAI); }
static Trigger* mirror_image(PlayerbotAI* botAI) { return new MirrorImageTrigger(botAI); }
static Trigger* frost_nova_on_target(PlayerbotAI* botAI) { return new FrostNovaOnTargetTrigger(botAI); }
static Trigger* frostbite_on_target(PlayerbotAI* botAI) { return new FrostbiteOnTargetTrigger(botAI); }
};

class MageAiObjectContextInternal : public NamedObjectContext<Action>
Expand All @@ -135,7 +149,11 @@ class MageAiObjectContextInternal : public NamedObjectContext<Action>
creators["arcane power"] = &MageAiObjectContextInternal::arcane_power;
creators["presence of mind"] = &MageAiObjectContextInternal::presence_of_mind;
creators["frostbolt"] = &MageAiObjectContextInternal::frostbolt;
creators["frostfire bolt"] = &MageAiObjectContextInternal::frostfire_bolt;
creators["ice lance"] = &MageAiObjectContextInternal::ice_lance;
creators["deep freeze"] = &MageAiObjectContextInternal::deep_freeze;
creators["blizzard"] = &MageAiObjectContextInternal::blizzard;
creators["cone of cold"] = &MageAiObjectContextInternal::cone_of_cold;
creators["frost nova"] = &MageAiObjectContextInternal::frost_nova;
creators["arcane intellect"] = &MageAiObjectContextInternal::arcane_intellect;
creators["arcane intellect on party"] = &MageAiObjectContextInternal::arcane_intellect_on_party;
Expand All @@ -156,6 +174,9 @@ class MageAiObjectContextInternal : public NamedObjectContext<Action>
creators["remove lesser curse"] = &MageAiObjectContextInternal::remove_lesser_curse;
creators["remove lesser curse on party"] = &MageAiObjectContextInternal::remove_lesser_curse_on_party;
creators["icy veins"] = &MageAiObjectContextInternal::icy_veins;
creators["cold snap"] = &MageAiObjectContextInternal::cold_snap;
creators["ice barrier"] = &MageAiObjectContextInternal::ice_barrier;
creators["summon water elemental"] = &MageAiObjectContextInternal::summon_water_elemental;
creators["combustion"] = &MageAiObjectContextInternal::combustion;
creators["ice block"] = &MageAiObjectContextInternal::ice_block;
creators["polymorph"] = &MageAiObjectContextInternal::polymorph;
Expand Down Expand Up @@ -183,7 +204,11 @@ class MageAiObjectContextInternal : public NamedObjectContext<Action>
static Action* arcane_barrage(PlayerbotAI* botAI) { return new CastArcaneBarrageAction(botAI); }
static Action* arcane_blast(PlayerbotAI* botAI) { return new CastArcaneBlastAction(botAI); }
static Action* frostbolt(PlayerbotAI* botAI) { return new CastFrostboltAction(botAI); }
static Action* frostfire_bolt(PlayerbotAI* botAI) { return new CastFrostfireBoltAction(botAI); }
static Action* ice_lance(PlayerbotAI* botAI) { return new CastIceLanceAction(botAI); }
static Action* deep_freeze(PlayerbotAI* botAI) { return new CastDeepFreezeAction(botAI); }
static Action* blizzard(PlayerbotAI* botAI) { return new CastBlizzardAction(botAI); }
static Action* cone_of_cold(PlayerbotAI* botAI) { return new CastConeOfColdAction(botAI); }
static Action* frost_nova(PlayerbotAI* botAI) { return new CastFrostNovaAction(botAI); }
static Action* arcane_intellect(PlayerbotAI* botAI) { return new CastArcaneIntellectAction(botAI); }
static Action* arcane_intellect_on_party(PlayerbotAI* botAI) { return new CastArcaneIntellectOnPartyAction(botAI); }
Expand All @@ -204,6 +229,9 @@ class MageAiObjectContextInternal : public NamedObjectContext<Action>
static Action* remove_lesser_curse(PlayerbotAI* botAI) { return new CastRemoveLesserCurseAction(botAI); }
static Action* remove_lesser_curse_on_party(PlayerbotAI* botAI) { return new CastRemoveLesserCurseOnPartyAction(botAI); }
static Action* icy_veins(PlayerbotAI* botAI) { return new CastIcyVeinsAction(botAI); }
static Action* cold_snap(PlayerbotAI* botAI) { return new CastColdSnapAction(botAI); }
static Action* ice_barrier(PlayerbotAI* botAI) { return new CastIceBarrierAction(botAI); }
static Action* summon_water_elemental(PlayerbotAI* botAI) { return new CastSummonWaterElementalAction(botAI); }
static Action* combustion(PlayerbotAI* botAI) { return new CastCombustionAction(botAI); }
static Action* ice_block(PlayerbotAI* botAI) { return new CastIceBlockAction(botAI); }
static Action* polymorph(PlayerbotAI* botAI) { return new CastPolymorphAction(botAI); }
Expand Down
26 changes: 26 additions & 0 deletions src/strategy/mage/MageTriggers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,29 @@ bool MageArmorTrigger::IsActive()
Unit* target = GetTarget();
return !botAI->HasAura("ice armor", target) && !botAI->HasAura("frost armor", target) && !botAI->HasAura("molten armor", target) && !botAI->HasAura("mage armor", target);
}

bool FingersOfFrostSingleTrigger::IsActive()
{
// Fingers of Frost "stack" count is always 1.
// The value is instead stored in the charges.
Aura *aura = botAI->GetAura(getName(), GetTarget(), false, true, -1);
return (aura && aura->GetCharges() == 1);
}

bool FrostNovaOnTargetTrigger::IsActive()
{
Unit* target = GetTarget();
if (!target || !target->IsAlive() || !target->IsInWorld()) {
return false;
}
return botAI->HasAura(spell, target);
}

bool FrostbiteOnTargetTrigger::IsActive()
{
Unit* target = GetTarget();
if (!target || !target->IsAlive() || !target->IsInWorld()) {
return false;
}
return botAI->HasAura(spell, target);
}
Loading

0 comments on commit b059efa

Please sign in to comment.