Improve druid cat spec

This commit is contained in:
Yunfan Li
2024-08-31 23:16:14 +08:00
parent e3e0bdde97
commit a63fbb3b5f
14 changed files with 174 additions and 51 deletions

View File

@@ -70,7 +70,7 @@ private:
{
return new ActionNode("mangle (cat)",
/*P*/ nullptr,
/*A*/ NextAction::array(0, new NextAction("claw"), nullptr),
/*A*/ nullptr,
/*C*/ nullptr);
}
@@ -122,38 +122,49 @@ CatDpsDruidStrategy::CatDpsDruidStrategy(PlayerbotAI* botAI) : FeralDruidStrateg
NextAction** CatDpsDruidStrategy::getDefaultActions()
{
return NextAction::array(0, new NextAction("mangle (cat)", ACTION_DEFAULT + 0.1f), nullptr);
return NextAction::array(0, new NextAction("mangle (cat)", ACTION_DEFAULT + 0.3f),
new NextAction("shred", ACTION_DEFAULT + 0.2f), nullptr);
}
void CatDpsDruidStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
FeralDruidStrategy::InitTriggers(triggers);
// Default priority
triggers.push_back(new TriggerNode("high energy available",
NextAction::array(0, new NextAction("claw", ACTION_DEFAULT + 0.1f), nullptr)));
triggers.push_back(
new TriggerNode("cat form", NextAction::array(0, new NextAction("cat form", ACTION_HIGH + 2), nullptr)));
new TriggerNode("faerie fire (feral)",
NextAction::array(0, new NextAction("faerie fire (feral)", ACTION_DEFAULT + 0.0f), nullptr)));
// Main spell
triggers.push_back(
new TriggerNode("rake", NextAction::array(0, new NextAction("rake", ACTION_NORMAL + 5), nullptr)));
new TriggerNode("cat form", NextAction::array(0, new NextAction("cat form", ACTION_HIGH + 8), nullptr)));
triggers.push_back(new TriggerNode("tiger's fury",
NextAction::array(0, new NextAction("tiger's fury", ACTION_HIGH + 7), nullptr)));
triggers.push_back(
new TriggerNode("savage roar", NextAction::array(0, new NextAction("savage roar", ACTION_HIGH + 5), nullptr)));
triggers.push_back(new TriggerNode("combo points available",
NextAction::array(0, new NextAction("rip", ACTION_HIGH + 4), nullptr)));
triggers.push_back(new TriggerNode(
"combo points available", NextAction::array(0, new NextAction("ferocious bite", ACTION_NORMAL + 9), nullptr)));
"combo points available", NextAction::array(0, new NextAction("ferocious bite", ACTION_HIGH + 3), nullptr)));
triggers.push_back(new TriggerNode("target with combo points almost dead",
NextAction::array(0, new NextAction("ferocious bite", ACTION_HIGH + 2), nullptr)));
triggers.push_back(new TriggerNode("rake", NextAction::array(0, new NextAction("rake", ACTION_HIGH + 2), nullptr)));
triggers.push_back(
new TriggerNode("medium threat", NextAction::array(0, new NextAction("cower", ACTION_EMERGENCY + 1), nullptr)));
new TriggerNode("medium threat", NextAction::array(0, new NextAction("cower", ACTION_HIGH + 1), nullptr)));
// AOE
triggers.push_back(
new TriggerNode("medium aoe", NextAction::array(0, new NextAction("swipe (cat)", ACTION_HIGH + 3), nullptr)));
triggers.push_back(new TriggerNode(
"faerie fire (feral)", NextAction::array(0, new NextAction("faerie fire (feral)", ACTION_HIGH), nullptr)));
"light aoe", NextAction::array(0, new NextAction("rake on attacker", ACTION_HIGH + 2), nullptr)));
// Reach target
triggers.push_back(new TriggerNode(
"tiger's fury", NextAction::array(0, new NextAction("tiger's fury", ACTION_EMERGENCY + 1), nullptr)));
"enemy out of melee", NextAction::array(0, new NextAction("feral charge - cat", ACTION_HIGH + 9), nullptr)));
triggers.push_back(
new TriggerNode("behind target", NextAction::array(0, new NextAction("pounce", ACTION_HIGH + 1), nullptr)));
// triggers.push_back(new TriggerNode("player has no flag", NextAction::array(0, new NextAction("prowl",
// ACTION_HIGH), nullptr))); triggers.push_back(new TriggerNode("enemy out of melee", NextAction::array(0, new
// NextAction("prowl", ACTION_INTERRUPT + 1), nullptr)));
triggers.push_back(
new TriggerNode("player has flag", NextAction::array(0, new NextAction("dash", ACTION_EMERGENCY), nullptr)));
triggers.push_back(new TriggerNode("enemy flagcarrier near",
NextAction::array(0, new NextAction("dash", ACTION_EMERGENCY), nullptr)));
new TriggerNode("enemy out of melee", NextAction::array(0, new NextAction("dash", ACTION_HIGH + 8), nullptr)));
}
void CatAoeDruidStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(
new TriggerNode("medium aoe", NextAction::array(0, new NextAction("swipe (cat)", ACTION_HIGH + 2), nullptr)));
}
void CatAoeDruidStrategy::InitTriggers(std::vector<TriggerNode*>& triggers) {}

View File

@@ -83,6 +83,8 @@ public:
creators["moonfire"] = &DruidTriggerFactoryInternal::moonfire;
creators["nature's grasp"] = &DruidTriggerFactoryInternal::natures_grasp;
creators["tiger's fury"] = &DruidTriggerFactoryInternal::tigers_fury;
creators["berserk"] = &DruidTriggerFactoryInternal::berserk;
creators["savage roar"] = &DruidTriggerFactoryInternal::savage_roar;
creators["rake"] = &DruidTriggerFactoryInternal::rake;
creators["mark of the wild"] = &DruidTriggerFactoryInternal::mark_of_the_wild;
creators["mark of the wild on party"] = &DruidTriggerFactoryInternal::mark_of_the_wild_on_party;
@@ -117,6 +119,8 @@ private:
static Trigger* faerie_fire(PlayerbotAI* botAI) { return new FaerieFireTrigger(botAI); }
static Trigger* natures_grasp(PlayerbotAI* botAI) { return new NaturesGraspTrigger(botAI); }
static Trigger* tigers_fury(PlayerbotAI* botAI) { return new TigersFuryTrigger(botAI); }
static Trigger* berserk(PlayerbotAI* botAI) { return new BerserkTrigger(botAI); }
static Trigger* savage_roar(PlayerbotAI* botAI) { return new SavageRoarTrigger(botAI); }
static Trigger* rake(PlayerbotAI* botAI) { return new RakeTrigger(botAI); }
static Trigger* mark_of_the_wild(PlayerbotAI* botAI) { return new MarkOfTheWildTrigger(botAI); }
static Trigger* mark_of_the_wild_on_party(PlayerbotAI* botAI) { return new MarkOfTheWildOnPartyTrigger(botAI); }
@@ -174,6 +178,7 @@ public:
creators["mangle (cat)"] = &DruidAiObjectContextInternal::mangle_cat;
creators["swipe (cat)"] = &DruidAiObjectContextInternal::swipe_cat;
creators["rake"] = &DruidAiObjectContextInternal::rake;
creators["rake on attacker"] = &DruidAiObjectContextInternal::rake_on_attacker;
creators["ferocious bite"] = &DruidAiObjectContextInternal::ferocious_bite;
creators["rip"] = &DruidAiObjectContextInternal::rip;
creators["cower"] = &DruidAiObjectContextInternal::cower;
@@ -188,6 +193,7 @@ public:
creators["abolish poison on party"] = &DruidAiObjectContextInternal::abolish_poison_on_party;
creators["berserk"] = &DruidAiObjectContextInternal::berserk;
creators["tiger's fury"] = &DruidAiObjectContextInternal::tigers_fury;
creators["savage roar"] = &DruidAiObjectContextInternal::savage_roar;
creators["mark of the wild"] = &DruidAiObjectContextInternal::mark_of_the_wild;
creators["mark of the wild on party"] = &DruidAiObjectContextInternal::mark_of_the_wild_on_party;
creators["regrowth"] = &DruidAiObjectContextInternal::regrowth;
@@ -257,6 +263,7 @@ private:
static Action* mangle_cat(PlayerbotAI* botAI) { return new CastMangleCatAction(botAI); }
static Action* swipe_cat(PlayerbotAI* botAI) { return new CastSwipeCatAction(botAI); }
static Action* rake(PlayerbotAI* botAI) { return new CastRakeAction(botAI); }
static Action* rake_on_attacker(PlayerbotAI* botAI) { return new CastRakeOnMeleeAttackersAction(botAI); }
static Action* ferocious_bite(PlayerbotAI* botAI) { return new CastFerociousBiteAction(botAI); }
static Action* rip(PlayerbotAI* botAI) { return new CastRipAction(botAI); }
static Action* cower(PlayerbotAI* botAI) { return new CastCowerAction(botAI); }
@@ -271,6 +278,7 @@ private:
static Action* abolish_poison_on_party(PlayerbotAI* botAI) { return new CastAbolishPoisonOnPartyAction(botAI); }
static Action* berserk(PlayerbotAI* botAI) { return new CastBerserkAction(botAI); }
static Action* tigers_fury(PlayerbotAI* botAI) { return new CastTigersFuryAction(botAI); }
static Action* savage_roar(PlayerbotAI* botAI) { return new CastSavageRoarAction(botAI); }
static Action* mark_of_the_wild(PlayerbotAI* botAI) { return new CastMarkOfTheWildAction(botAI); }
static Action* mark_of_the_wild_on_party(PlayerbotAI* botAI) { return new CastMarkOfTheWildOnPartyAction(botAI); }
static Action* regrowth(PlayerbotAI* botAI) { return new CastRegrowthAction(botAI); }

View File

@@ -0,0 +1,6 @@
#include "DruidCatActions.h"
bool CastMangleCatAction::isUseful()
{
return CastMeleeDebuffSpellAction::isUseful() && !botAI->HasAura("mangle (bear)", GetTarget(), false, isOwner);
}

View File

@@ -35,10 +35,23 @@ public:
CastTigersFuryAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "tiger's fury") {}
};
class CastSavageRoarAction : public CastBuffSpellAction
{
public:
CastSavageRoarAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "savage roar") {}
std::string const GetTargetName() override { return "current target"; }
};
class CastRakeAction : public CastDebuffSpellAction
{
public:
CastRakeAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "rake") {}
CastRakeAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "rake", true, 6.0f) {}
};
class CastRakeOnMeleeAttackersAction : public CastDebuffSpellOnMeleeAttackerAction
{
public:
CastRakeOnMeleeAttackersAction(PlayerbotAI* botAI) : CastDebuffSpellOnMeleeAttackerAction(botAI, "rake", true, 6.0f) {}
};
class CastClawAction : public CastMeleeSpellAction
@@ -47,10 +60,11 @@ public:
CastClawAction(PlayerbotAI* botAI) : CastMeleeSpellAction(botAI, "claw") {}
};
class CastMangleCatAction : public CastMeleeSpellAction
class CastMangleCatAction : public CastMeleeDebuffSpellAction
{
public:
CastMangleCatAction(PlayerbotAI* botAI) : CastMeleeSpellAction(botAI, "mangle (cat)") {}
CastMangleCatAction(PlayerbotAI* botAI) : CastMeleeDebuffSpellAction(botAI, "mangle (cat)", false, 0.0f) {}
bool isUseful() override;
};
class CastSwipeCatAction : public CastMeleeSpellAction
@@ -65,10 +79,10 @@ public:
CastFerociousBiteAction(PlayerbotAI* botAI) : CastMeleeSpellAction(botAI, "ferocious bite") {}
};
class CastRipAction : public CastMeleeSpellAction
class CastRipAction : public CastMeleeDebuffSpellAction
{
public:
CastRipAction(PlayerbotAI* botAI) : CastMeleeSpellAction(botAI, "rip") {}
CastRipAction(PlayerbotAI* botAI) : CastMeleeDebuffSpellAction(botAI, "rip", true, 12.0f) {}
};
class CastShredAction : public CastMeleeSpellAction

View File

@@ -95,10 +95,22 @@ public:
BashInterruptSpellTrigger(PlayerbotAI* botAI) : InterruptSpellTrigger(botAI, "bash") {}
};
class TigersFuryTrigger : public BoostTrigger
class TigersFuryTrigger : public BuffTrigger
{
public:
TigersFuryTrigger(PlayerbotAI* botAI) : BoostTrigger(botAI, "tiger's fury") {}
TigersFuryTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "tiger's fury") {}
};
class BerserkTrigger : public BoostTrigger
{
public:
BerserkTrigger(PlayerbotAI* botAI) : BoostTrigger(botAI, "berserk") {}
};
class SavageRoarTrigger : public BuffTrigger
{
public:
SavageRoarTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "savage roar") {}
};
class NaturesGraspTrigger : public BoostTrigger

View File

@@ -112,4 +112,6 @@ void FeralDruidStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
NextAction::array(0, new NextAction("dash", ACTION_EMERGENCY + 2), nullptr)));
triggers.push_back(new TriggerNode("enemy flagcarrier near",
NextAction::array(0, new NextAction("dash", ACTION_EMERGENCY + 2), nullptr)));
triggers.push_back(
new TriggerNode("berserk", NextAction::array(0, new NextAction("berserk", ACTION_HIGH + 6), nullptr)));
}

View File

@@ -36,3 +36,36 @@ Unit* AttackerWithoutAuraTargetValue::Calculate()
return result;
}
Unit* MeleeAttackerWithoutAuraTargetValue::Calculate()
{
GuidVector attackers = botAI->GetAiObjectContext()->GetValue<GuidVector>("attackers")->Get();
// Unit* target = botAI->GetAiObjectContext()->GetValue<Unit*>("current target")->Get();
uint32 max_health = 0;
Unit* result = nullptr;
for (ObjectGuid const guid : attackers)
{
Unit* unit = botAI->GetUnit(guid);
if (!unit || !unit->IsAlive())
continue;
if (!bot->IsWithinMeleeRange(unit))
continue;
if (checkArc && !bot->HasInArc(CAST_ANGLE_IN_FRONT, unit))
continue;
if (unit->GetHealth() < max_health)
{
continue;
}
if (!botAI->HasAura(qualifier, unit, false, true))
{
max_health = unit->GetHealth();
result = unit;
}
}
return result;
}

View File

@@ -28,7 +28,9 @@ protected:
class MeleeAttackerWithoutAuraTargetValue : public AttackerWithoutAuraTargetValue
{
public:
MeleeAttackerWithoutAuraTargetValue(PlayerbotAI* botAI) : AttackerWithoutAuraTargetValue(botAI, "melee") {}
MeleeAttackerWithoutAuraTargetValue(PlayerbotAI* botAI, bool checkArc = true) : AttackerWithoutAuraTargetValue(botAI, "melee"), checkArc(checkArc) {}
Unit* Calculate() override;
bool checkArc;
};
#endif

View File

@@ -13,6 +13,9 @@ float ExpectedLifetimeValue::Calculate()
return 0.0f;
}
float dps = AI_VALUE(float, "expected group dps");
bool aoePenalty = AI_VALUE(uint8, "attacker count") >= 3;
if (aoePenalty)
dps *= 0.75;
float res = target->GetHealth() / dps;
// bot->Say(target->GetName() + " lifetime: " + std::to_string(res), LANG_UNIVERSAL);
return res;