better shaman totem strategy

This commit is contained in:
Yunfan Li
2023-10-29 00:16:31 +08:00
parent 8b42ea3e89
commit a76290a149
10 changed files with 108 additions and 32 deletions

View File

@@ -118,9 +118,9 @@ bool CastSpellAction::isUseful()
CastMeleeSpellAction::CastMeleeSpellAction(PlayerbotAI* botAI, std::string const spell) : CastSpellAction(botAI, spell)
{
range = ATTACK_DISTANCE;
Unit* target = AI_VALUE(Unit*, "current target");
if (target)
range = bot->GetMeleeRange(target);
// Unit* target = AI_VALUE(Unit*, "current target");
// if (target)
// range = bot->GetMeleeRange(target);
// range = target->GetCombinedCombatReach();
}

View File

@@ -39,7 +39,8 @@ CasterShamanStrategy::CasterShamanStrategy(PlayerbotAI* botAI) : GenericShamanSt
NextAction** CasterShamanStrategy::getDefaultActions()
{
return NextAction::array(0,
new NextAction("lava burst", ACTION_DEFAULT + 0.1f),
new NextAction("lava burst", ACTION_DEFAULT + 0.2f),
new NextAction("thunderstorm", ACTION_DEFAULT + 0.1f),
new NextAction("lightning bolt", ACTION_DEFAULT),
NULL);
}
@@ -55,7 +56,9 @@ void CasterShamanStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
// triggers.push_back(new TriggerNode("frost shock snare", NextAction::array(0, new NextAction("frost shock", 21.0f), nullptr)));
triggers.push_back(new TriggerNode(
"no fire totem",
NextAction::array(0, new NextAction("totem of wrath", 15.0f), NULL)));
NextAction::array(0,
// new NextAction("fire elemental totem", 16.0f),
new NextAction("totem of wrath", 15.0f), NULL)));
triggers.push_back(new TriggerNode("enemy too close for spell", NextAction::array(0, new NextAction("flee", ACTION_HIGH), nullptr)));
}

View File

@@ -81,9 +81,9 @@ void HealShamanStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
"party member cleanse spirit curse",
NextAction::array(0, new NextAction("cleanse spirit curse on party", ACTION_DISPEL + 2), NULL)));
triggers.push_back(new TriggerNode(
"no fire totem",
NextAction::array(0, new NextAction("fire elemental totem", 11.0f), new NextAction("flametongue totem", 10.0f), NULL)));
// triggers.push_back(new TriggerNode(
// "no fire totem",
// NextAction::array(0, new NextAction("flametongue totem", 10.0f), NULL)));
triggers.push_back(new TriggerNode(
"no water totem",

View File

@@ -50,9 +50,10 @@ MeleeShamanStrategy::MeleeShamanStrategy(PlayerbotAI* botAI) : GenericShamanStra
NextAction** MeleeShamanStrategy::getDefaultActions()
{
return NextAction::array(0,
new NextAction("stormstrike", ACTION_DEFAULT + 0.4f),
new NextAction("earth shock", ACTION_DEFAULT + 0.3f),
new NextAction("fire nova", ACTION_DEFAULT + 0.2f),
new NextAction("stormstrike", ACTION_DEFAULT + 0.5f),
new NextAction("earth shock", ACTION_DEFAULT + 0.4f),
new NextAction("feral spirit", ACTION_DEFAULT + 0.3f),
new NextAction("fire nova", ACTION_DEFAULT + 0.2f),
new NextAction("lava lash", ACTION_DEFAULT + 0.1f),
new NextAction("melee", ACTION_DEFAULT),
NULL);
@@ -72,9 +73,23 @@ void MeleeShamanStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
// triggers.push_back(new TriggerNode("enemy too close for melee", NextAction::array(0, new NextAction("move out of enemy contact", ACTION_NORMAL + 8), nullptr)));
triggers.push_back(new TriggerNode("medium aoe", NextAction::array(0, new NextAction("strength of earth totem", ACTION_LIGHT_HEAL), nullptr)));
triggers.push_back(new TriggerNode("enemy out of melee", NextAction::array(0, new NextAction("reach melee", ACTION_NORMAL + 8), nullptr)));
triggers.push_back(new TriggerNode(
"no fire totem",
NextAction::array(0, new NextAction("reach melee", 23.0f), new NextAction("magma totem", 22.0f), nullptr)));
NextAction::array(0,
new NextAction("reach melee", 23.0f),
new NextAction("magma totem", 22.0f), nullptr)));
triggers.push_back(new TriggerNode("fire elemental totem",
NextAction::array(0,
new NextAction("reach melee", 33.0f),
new NextAction("fire elemental totem", 32.0f),
nullptr)));
triggers.push_back(new TriggerNode(
"no air totem",
NextAction::array(0, new NextAction("windfury totem", 20.0f), nullptr)));
triggers.push_back(new TriggerNode(
"medium mana",
NextAction::array(0, new NextAction("shamanistic rage", 23.0f), nullptr)));
@@ -83,6 +98,6 @@ void MeleeShamanStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
void MeleeAoeShamanStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(new TriggerNode("magma totem", NextAction::array(0, new NextAction("magma totem", 26.0f), nullptr)));
// triggers.push_back(new TriggerNode("magma totem", NextAction::array(0, new NextAction("magma totem", 26.0f), nullptr)));
triggers.push_back(new TriggerNode("medium aoe", NextAction::array(0, new NextAction("fire nova", 25.0f), nullptr)));
}

View File

@@ -7,7 +7,14 @@
bool CastTotemAction::isUseful()
{
return CastBuffSpellAction::isUseful() && !AI_VALUE2(bool, "has totem", name);
if (needLifeTime > 0.1f) {
Unit* target = AI_VALUE(Unit*, "current target");
float dps = AI_VALUE(float, "expected group dps");
if (target->GetHealth() / dps < needLifeTime) {
return false;
}
}
return CastBuffSpellAction::isUseful() && !AI_VALUE2(bool, "has totem", name) && !botAI->HasAura(buff, bot);
}
bool CastManaSpringTotemAction::isUseful()
@@ -27,7 +34,7 @@ bool CastSearingTotemAction::isUseful()
bool CastMagmaTotemAction::isUseful()
{
return CastMeleeSpellAction::isUseful() && !AI_VALUE2(bool, "has totem", name);
return CastTotemAction::isUseful() && !AI_VALUE2(bool, "has totem", name);
}
bool CastCleansingTotemAction::isUseful()

View File

@@ -5,7 +5,9 @@
#ifndef _PLAYERBOT_SHAMANACTIONS_H
#define _PLAYERBOT_SHAMANACTIONS_H
#include "Define.h"
#include "GenericSpellActions.h"
#include "Playerbots.h"
#include "SharedDefines.h"
class PlayerbotAI;
@@ -109,9 +111,19 @@ class CastWindfuryWeaponAction : public CastEnchantItemAction
class CastTotemAction : public CastBuffSpellAction
{
public:
CastTotemAction(PlayerbotAI* botAI, std::string const spell) : CastBuffSpellAction(botAI, spell) { }
CastTotemAction(PlayerbotAI* botAI, std::string const spell, std::string const buffName = "", float needLifeTime = 8.0f)
: CastBuffSpellAction(botAI, spell), needLifeTime(needLifeTime) {
if (buffName == "") {
buff = spell;
} else {
buff = buffName;
}
}
bool isUseful() override;
protected:
float needLifeTime;
std::string buff;
};
class CastStoneskinTotemAction : public CastTotemAction
@@ -129,13 +141,13 @@ class CastEarthbindTotemAction : public CastTotemAction
class CastStrengthOfEarthTotemAction : public CastTotemAction
{
public:
CastStrengthOfEarthTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "strength of earth totem") { }
CastStrengthOfEarthTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "strength of earth totem", "strength of earth", 20.0f) { }
};
class CastManaSpringTotemAction : public CastTotemAction
{
public:
CastManaSpringTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "mana spring totem") { }
CastManaSpringTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "mana spring totem", "mana spring", 20.0f) { }
bool isUseful() override;
};
@@ -164,7 +176,7 @@ class CastCleansingTotemAction : public CastTotemAction
class CastFlametongueTotemAction : public CastTotemAction
{
public:
CastFlametongueTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "flametongue totem") { }
CastFlametongueTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "flametongue totem", "", 20.0f) { }
bool isUseful() override;
};
@@ -184,16 +196,16 @@ class CastGraceOfAirTotemAction : public CastTotemAction
class CastSearingTotemAction : public CastTotemAction
{
public:
CastSearingTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "searing totem") { }
CastSearingTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "searing totem", "", 0.0f) { }
std::string const GetTargetName() override { return "self target"; }
bool isUseful() override;
};
class CastMagmaTotemAction : public CastMeleeSpellAction
class CastMagmaTotemAction : public CastTotemAction
{
public:
CastMagmaTotemAction(PlayerbotAI* botAI) : CastMeleeSpellAction(botAI, "magma totem") { }
CastMagmaTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "magma totem", "", 0.0f) { }
std::string const GetTargetName() override { return "self target"; }
bool isUseful() override;
@@ -392,7 +404,7 @@ class CastTotemOfWrathAction : public CastTotemAction
class CastFireElementalTotemAction : public CastTotemAction
{
public:
CastFireElementalTotemAction(PlayerbotAI* ai) : CastTotemAction(ai, "fire elemental totem") {}
CastFireElementalTotemAction(PlayerbotAI* ai) : CastTotemAction(ai, "fire elemental totem", "", 0.0f) {}
virtual std::string const GetTargetName() override { return "self target"; }
virtual bool isUseful() override { return CastTotemAction::isUseful(); }
};
@@ -400,7 +412,7 @@ class CastFireElementalTotemAction : public CastTotemAction
class CastWrathOfAirTotemAction : public CastTotemAction
{
public:
CastWrathOfAirTotemAction(PlayerbotAI* ai) : CastTotemAction(ai, "wrath of air totem") {}
CastWrathOfAirTotemAction(PlayerbotAI* ai) : CastTotemAction(ai, "wrath of air totem", "wrath of air totem") {}
};
class CastShamanisticRageAction : public CastBuffSpellAction
@@ -408,4 +420,10 @@ class CastShamanisticRageAction : public CastBuffSpellAction
public:
CastShamanisticRageAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "shamanistic rage") {}
};
class CastFeralSpiritAction : public CastSpellAction
{
public:
CastFeralSpiritAction(PlayerbotAI* ai) : CastSpellAction(ai, "feral spirit") {}
};
#endif

View File

@@ -74,6 +74,7 @@ class ShamanATriggerFactoryInternal : public NamedObjectContext<Trigger>
creators["mana spring totem"] = &ShamanATriggerFactoryInternal::mana_spring_totem;
creators["flametongue totem"] = &ShamanATriggerFactoryInternal::flametongue_totem;
creators["strength of earth totem"] = &ShamanATriggerFactoryInternal::strength_of_earth_totem;
creators["fire elemental totem"] = &ShamanATriggerFactoryInternal::fire_elemental_totem;
creators["magma totem"] = &ShamanATriggerFactoryInternal::magma_totem;
creators["searing totem"] = &ShamanATriggerFactoryInternal::searing_totem;
creators["wind shear"] = &ShamanATriggerFactoryInternal::wind_shear;
@@ -102,6 +103,7 @@ class ShamanATriggerFactoryInternal : public NamedObjectContext<Trigger>
creators["party member cure disease"] = &ShamanATriggerFactoryInternal::party_member_cure_disease;
creators["no fire totem"] = &ShamanATriggerFactoryInternal::no_fire_totem;
creators["no water totem"] = &ShamanATriggerFactoryInternal::no_water_totem;
creators["no air totem"] = &ShamanATriggerFactoryInternal::no_air_totem;
creators["earth shield on main tank"] = &ShamanATriggerFactoryInternal::earth_shield_on_main_tank;
creators["maelstrom weapon"] = &ShamanATriggerFactoryInternal::maelstrom_weapon;
creators["flame shock"] = &ShamanATriggerFactoryInternal::flame_shock;
@@ -127,6 +129,7 @@ class ShamanATriggerFactoryInternal : public NamedObjectContext<Trigger>
static Trigger* mana_spring_totem(PlayerbotAI* botAI) { return new ManaSpringTotemTrigger(botAI); }
static Trigger* flametongue_totem(PlayerbotAI* botAI) { return new FlametongueTotemTrigger(botAI); }
static Trigger* strength_of_earth_totem(PlayerbotAI* botAI) { return new StrengthOfEarthTotemTrigger(botAI); }
static Trigger* fire_elemental_totem(PlayerbotAI* botAI) { return new FireElementalTotemTrigger(botAI); }
static Trigger* magma_totem(PlayerbotAI* botAI) { return new MagmaTotemTrigger(botAI); }
static Trigger* searing_totem(PlayerbotAI* botAI) { return new SearingTotemTrigger(botAI); }
static Trigger* wind_shear(PlayerbotAI* botAI) { return new WindShearInterruptSpellTrigger(botAI); }
@@ -143,6 +146,7 @@ class ShamanATriggerFactoryInternal : public NamedObjectContext<Trigger>
static Trigger* party_member_cure_disease(PlayerbotAI* botAI) { return new PartyMemberCureDiseaseTrigger(botAI); }
static Trigger* no_fire_totem(PlayerbotAI* ai) { return new NoFireTotemTrigger(ai); }
static Trigger* no_water_totem(PlayerbotAI* ai) { return new NoWaterTotemTrigger(ai); }
static Trigger* no_air_totem(PlayerbotAI* ai) { return new NoAirTotemTrigger(ai); }
static Trigger* earth_shield_on_main_tank(PlayerbotAI* ai) { return new EarthShieldOnMainTankTrigger(ai); }
static Trigger* flame_shock(PlayerbotAI* ai) { return new FlameShockTrigger(ai); }
static Trigger* wrath_of_air_totem(PlayerbotAI* ai) { return new WrathOfAirTotemTrigger(ai); }
@@ -210,9 +214,9 @@ class ShamanAiObjectContextInternal : public NamedObjectContext<Action>
creators["earth shield on main tank"] = &ShamanAiObjectContextInternal::earth_shield_on_main_tank;
creators["fire elemental totem"] = &ShamanAiObjectContextInternal::fire_elemental_totem;
creators["totem of wrath"] = &ShamanAiObjectContextInternal::totem_of_wrath;
creators["fire elemental totem"] = &ShamanAiObjectContextInternal::fire_elemental_totem;
creators["wrath of air totem"] = &ShamanAiObjectContextInternal::wrath_of_air_totem;
creators["shamanistic rage"] = &ShamanAiObjectContextInternal::shamanistic_rage;
creators["feral spirit"] = &ShamanAiObjectContextInternal::feral_spirit;
}
private:
@@ -275,6 +279,7 @@ class ShamanAiObjectContextInternal : public NamedObjectContext<Action>
static Action* fire_elemental_totem(PlayerbotAI* ai) { return new CastFireElementalTotemAction(ai); }
static Action* wrath_of_air_totem(PlayerbotAI* ai) { return new CastWrathOfAirTotemAction(ai); }
static Action* shamanistic_rage(PlayerbotAI* ai) { return new CastShamanisticRageAction(ai); }
static Action* feral_spirit(PlayerbotAI* ai) { return new CastFeralSpiritAction(ai); }
};

View File

@@ -84,4 +84,10 @@ bool NoWaterTotemTrigger::IsActive()
!AI_VALUE2(bool, "has totem", "cleansing totem") &&
!AI_VALUE2(bool, "has totem", "mana spring totem") &&
!AI_VALUE2(bool, "has totem", "healing stream totem");
}
bool NoAirTotemTrigger::IsActive()
{
return !AI_VALUE2(bool, "has totem", "wrath of air totem") &&
!AI_VALUE2(bool, "has totem", "windfury totem");
}

View File

@@ -65,6 +65,12 @@ class StrengthOfEarthTotemTrigger : public TotemTrigger
StrengthOfEarthTotemTrigger(PlayerbotAI* botAI) : TotemTrigger(botAI, "strength of earth totem") { }
};
class FireElementalTotemTrigger : public BoostTrigger
{
public:
FireElementalTotemTrigger(PlayerbotAI* botAI) : BoostTrigger(botAI, "fire elemental totem") { }
};
class MagmaTotemTrigger : public TotemTrigger
{
public:
@@ -234,13 +240,13 @@ class PartyMemberCureDiseaseTrigger : public PartyMemberNeedCureTrigger
class NoFireTotemTrigger : public Trigger {
public:
NoFireTotemTrigger(PlayerbotAI* ai) : Trigger(ai, "no fire totem") {}
virtual bool IsActive() override;
bool IsActive() override;
};
class NoWaterTotemTrigger : public Trigger {
public:
NoWaterTotemTrigger(PlayerbotAI* ai) : Trigger(ai, "no water totem") {}
virtual bool IsActive() override;
bool IsActive() override;
};
class EarthShieldOnMainTankTrigger : public BuffOnMainTankTrigger
@@ -259,4 +265,11 @@ class WrathOfAirTotemTrigger : public TotemTrigger
public:
WrathOfAirTotemTrigger(PlayerbotAI* ai) : TotemTrigger(ai, "wrath of air totem") {}
};
class NoAirTotemTrigger : public TotemTrigger
{
public:
NoAirTotemTrigger(PlayerbotAI* ai) : TotemTrigger(ai, "no air totem") {}
bool IsActive() override;
};
#endif

View File

@@ -13,19 +13,28 @@ void TotemsShamanStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
GenericShamanStrategy::InitTriggers(triggers);
triggers.push_back(new TriggerNode("fire elemental totem", NextAction::array(0, new NextAction("fire elemental totem", 32.0f), nullptr)));
triggers.push_back(new TriggerNode(
"wrath of air totem",
"no air totem",
NextAction::array(0, new NextAction("wrath of air totem", 8.0f), NULL)));
triggers.push_back(new TriggerNode(
"no water totem",
NextAction::array(0, new NextAction("mana spring totem", 7.0f), NULL)));
NextAction::array(0,
new NextAction("mana spring totem", 7.0f),
new NextAction("healing stream totem", 6.0f),
nullptr)));
triggers.push_back(new TriggerNode(
"no fire totem",
NextAction::array(0,
new NextAction("flametongue totem", 7.0f),
new NextAction("searing totem", 6.0f),
nullptr)));
triggers.push_back(new TriggerNode(
"strength of earth totem",
NextAction::array(0, new NextAction("strength of earth totem", 6.0f), NULL)));
triggers.push_back(new TriggerNode(
"no fire totem",
NextAction::array(0, new NextAction("flametongue totem", 5.0f), NULL)));
}