Merge pull request #576 from liyunfan1223/assist_dps

Healer attack (healer dps strategy) and healer enhancement
This commit is contained in:
Yunfan Li
2024-10-04 22:20:36 +08:00
committed by GitHub
49 changed files with 553 additions and 187 deletions

View File

@@ -1002,16 +1002,16 @@ AiPlayerbot.PremadeSpecLink.9.2.80 = -03310030003-05203205210331051335230351
AiPlayerbot.PremadeSpecName.11.0 = balance pve
AiPlayerbot.PremadeSpecGlyph.11.0 = 40916,43331,40921,43335,44922,40919
AiPlayerbot.PremadeSpecLink.11.0.60 = 5012203115331003213302301231
AiPlayerbot.PremadeSpecLink.11.0.80 = 5012203125331103213305301231--205003212
AiPlayerbot.PremadeSpecLink.11.0.60 = 5022203105331003213005301231
AiPlayerbot.PremadeSpecLink.11.0.80 = 5032203105331303213305301231--205003012
AiPlayerbot.PremadeSpecName.11.1 = bear pve
AiPlayerbot.PremadeSpecGlyph.11.1 = 40897,43331,46372,43335,43332,40899
AiPlayerbot.PremadeSpecLink.11.1.60 = -500232130322110353100301310501
AiPlayerbot.PremadeSpecLink.11.1.80 = -501232130322110353120303313511-20350001
AiPlayerbot.PremadeSpecName.11.2 = resto pve
AiPlayerbot.PremadeSpecGlyph.11.2 = 40913,43331,40906,43335,44922,45602
AiPlayerbot.PremadeSpecLink.11.2.60 = --230033312031501531050013051
AiPlayerbot.PremadeSpecLink.11.2.80 = 05320001--230033312031512531153313051
AiPlayerbot.PremadeSpecLink.11.2.60 = --230033312031500531050113051
AiPlayerbot.PremadeSpecLink.11.2.80 = 05320031--230033312031501531053313051
AiPlayerbot.PremadeSpecName.11.3 = cat pve
AiPlayerbot.PremadeSpecGlyph.11.3 = 40902,43331,40901,43335,44922,45604
AiPlayerbot.PremadeSpecLink.11.3.60 = -552202032322010053100030310501

View File

@@ -277,10 +277,6 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
{
engine->addStrategiesNoInit("racials", "chat", "default", "cast time", "duel", "boost", nullptr);
}
if (sPlayerbotAIConfig->autoSaveMana)
{
engine->addStrategy("save mana", false);
}
if (sPlayerbotAIConfig->autoAvoidAoe && facade->HasRealPlayerMaster())
{
engine->addStrategy("avoid aoe", false);
@@ -394,7 +390,12 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
if (PlayerbotAI::IsMelee(player, true) && PlayerbotAI::IsDps(player, true)) {
engine->addStrategy("behind", false);
}
if (PlayerbotAI::IsHeal(player, true))
{
if (sPlayerbotAIConfig->autoSaveMana)
engine->addStrategy("save mana", false);
engine->addStrategy("healer dps", false);
}
if (facade->IsRealPlayer() || sRandomPlayerbotMgr->IsRandomBot(player))
{
if (!player->GetGroup())
@@ -483,8 +484,8 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
engine->removeStrategy("threat", false);
engine->addStrategy("boost", false);
if ((player->getClass() == CLASS_DRUID && tab == 2) || (player->getClass() == CLASS_SHAMAN && tab == 2))
engine->addStrategiesNoInit("caster", "caster aoe", nullptr);
// if ((player->getClass() == CLASS_DRUID && tab == 2) || (player->getClass() == CLASS_SHAMAN && tab == 2))
// engine->addStrategiesNoInit("caster", "caster aoe", nullptr);
// if (player->getClass() == CLASS_DRUID && tab == 1)
// engine->addStrategiesNoInit(/*"behind",*/ "dps", nullptr);

View File

@@ -317,13 +317,13 @@ void PlayerbotAI::UpdateAI(uint32 elapsed, bool minimal)
Spell* currentSpell = bot->GetCurrentSpell(CURRENT_GENERIC_SPELL);
if (!currentSpell)
currentSpell = bot->GetCurrentSpell(CURRENT_CHANNELED_SPELL);
if (currentSpell && currentSpell->getState() == SPELL_STATE_PREPARING)
if (currentSpell && currentSpell->GetSpellInfo() && currentSpell->getState() == SPELL_STATE_PREPARING)
{
const SpellInfo* spellInfo = currentSpell->GetSpellInfo();
// interrupt if target is dead
if (currentSpell->m_targets.GetUnitTarget() && !currentSpell->m_targets.GetUnitTarget()->IsAlive() &&
spellInfo && !spellInfo->IsAllowingDeadTarget())
!spellInfo->IsAllowingDeadTarget())
{
InterruptSpell();
SetNextCheckDelay(sPlayerbotAIConfig->reactDelay);
@@ -703,8 +703,7 @@ void PlayerbotAI::HandleTeleportAck()
p << (uint32)0; // supposed to be flags? not used currently
p << (uint32)0; // time - not currently used
bot->GetSession()->HandleMoveTeleportAck(p);
}
SetNextCheckDelay(urand(1000, 3000));
};
}
if (bot->IsBeingTeleportedFar())
{
@@ -712,13 +711,13 @@ void PlayerbotAI::HandleTeleportAck()
{
bot->GetSession()->HandleMoveWorldportAck();
}
SetNextCheckDelay(urand(2000, 5000));
// SetNextCheckDelay(urand(2000, 5000));
if (sPlayerbotAIConfig->applyInstanceStrategies)
ApplyInstanceStrategies(bot->GetMapId(), true);
Reset();
}
SetNextCheckDelay(sPlayerbotAIConfig->globalCoolDown);
Reset();
}
void PlayerbotAI::Reset(bool full)
@@ -1198,7 +1197,7 @@ void PlayerbotAI::HandleBotOutgoingPacket(WorldPacket const& packet)
void PlayerbotAI::SpellInterrupted(uint32 spellid)
{
for (uint8 type = CURRENT_MELEE_SPELL; type < CURRENT_CHANNELED_SPELL; type++)
for (uint8 type = CURRENT_MELEE_SPELL; type <= CURRENT_CHANNELED_SPELL; type++)
{
Spell* spell = bot->GetCurrentSpell((CurrentSpellTypes)type);
if (!spell)
@@ -1206,8 +1205,8 @@ void PlayerbotAI::SpellInterrupted(uint32 spellid)
if (spell->GetSpellInfo()->Id == spellid)
bot->InterruptSpell((CurrentSpellTypes)type);
}
LastSpellCast& lastSpell = aiObjectContext->GetValue<LastSpellCast&>("last spell cast")->Get();
lastSpell.id = 0;
// LastSpellCast& lastSpell = aiObjectContext->GetValue<LastSpellCast&>("last spell cast")->Get();
// lastSpell.id = 0;
}
int32 PlayerbotAI::CalculateGlobalCooldown(uint32 spellid)
@@ -3339,11 +3338,11 @@ bool PlayerbotAI::CastSpell(uint32 spellId, Unit* target, Item* itemTarget)
// }
// }
WaitForSpellCast(spell);
if (spell->GetCastTime())
aiObjectContext->GetValue<LastSpellCast&>("last spell cast")
->Get()
.Set(spellId, target->GetGUID(), time(nullptr));
// WaitForSpellCast(spell);
aiObjectContext->GetValue<LastSpellCast&>("last spell cast")
->Get()
.Set(spellId, target->GetGUID(), time(nullptr));
aiObjectContext->GetValue<PositionMap&>("position")->Get()["random"].Reset();
@@ -3473,7 +3472,7 @@ bool PlayerbotAI::CastSpell(uint32 spellId, float x, float y, float z, Item* ite
}
}
WaitForSpellCast(spell);
// WaitForSpellCast(spell);
aiObjectContext->GetValue<LastSpellCast&>("last spell cast")->Get().Set(spellId, bot->GetGUID(), time(nullptr));
aiObjectContext->GetValue<PositionMap&>("position")->Get()["random"].Reset();
@@ -3688,7 +3687,7 @@ bool PlayerbotAI::CastVehicleSpell(uint32 spellId, Unit* target)
return false;
}
WaitForSpellCast(spell);
// WaitForSpellCast(spell);
// aiObjectContext->GetValue<LastSpellCast&>("last spell cast")->Get().Set(spellId, target->GetGUID(), time(0));
// aiObjectContext->GetValue<botAI::PositionMap&>("position")->Get()["random"].Reset();
@@ -3745,23 +3744,15 @@ bool PlayerbotAI::IsInVehicle(bool canControl, bool canCast, bool canAttack, boo
void PlayerbotAI::WaitForSpellCast(Spell* spell)
{
return;
SpellInfo const* spellInfo = spell->GetSpellInfo();
uint32 castTime = spell->GetCastTime();
// float castTime = spell->GetCastTime();
// if (spellInfo->IsChanneled())
// {
// int32 duration = spellInfo->GetDuration();
// bot->ApplySpellMod(spellInfo->Id, SPELLMOD_DURATION, duration);
// if (duration > 0)
// castTime += duration;
// }
// castTime = ceil(castTime);
// uint32 globalCooldown = CalculateGlobalCooldown(spellInfo->Id);
// if (castTime < globalCooldown)
// castTime = globalCooldown;
if (spellInfo->IsChanneled())
{
int32 duration = spellInfo->GetDuration();
bot->ApplySpellMod(spellInfo->Id, SPELLMOD_DURATION, duration);
if (duration > 0)
castTime += duration;
}
SetNextCheckDelay(castTime + sPlayerbotAIConfig->reactDelay);
}

View File

@@ -10,6 +10,7 @@
#include <string>
#include "Common.h"
#include "DynamicObject.h"
#include "NamedObjectContext.h"
#include "PlayerbotAIAware.h"
#include "Strategy.h"

View File

@@ -202,9 +202,9 @@ bool Engine::DoNextAction(Unit* unit, uint32 depth, bool minimal)
{
LogAction("A:%s - PREREQ", action->getName().c_str());
if (MultiplyAndPush(actionNode->getPrerequisites(), relevance + 0.02, false, event, "prereq"))
if (MultiplyAndPush(actionNode->getPrerequisites(), relevance + 0.002f, false, event, "prereq"))
{
PushAgain(actionNode, relevance + 0.01, event);
PushAgain(actionNode, relevance + 0.001f, event);
continue;
}
}
@@ -226,7 +226,7 @@ bool Engine::DoNextAction(Unit* unit, uint32 depth, bool minimal)
else
{
LogAction("A:%s - FAILED", action->getName().c_str());
MultiplyAndPush(actionNode->getAlternatives(), relevance + 0.03, false, event, "alt");
MultiplyAndPush(actionNode->getAlternatives(), relevance + 0.003f, false, event, "alt");
}
}
else
@@ -246,7 +246,7 @@ bool Engine::DoNextAction(Unit* unit, uint32 depth, bool minimal)
botAI->TellMasterNoFacing(out);
}
LogAction("A:%s - IMPOSSIBLE", action->getName().c_str());
MultiplyAndPush(actionNode->getAlternatives(), relevance + 0.03, false, event, "alt");
MultiplyAndPush(actionNode->getAlternatives(), relevance + 0.003f, false, event, "alt");
}
}
else

View File

@@ -38,7 +38,7 @@ bool TogglePetSpellAutoCastAction::Execute(Event event)
bool shouldApply = true;
// imp's spell, felhunte's intelligence, cat stealth
if (spellId == 4511 || spellId == 1742 || spellId == 54424 || spellId == 57564 || spellId == 57565 ||
spellId == 57566 || spellId == 57567 || spellId == 24450 || spellId == 53477)
spellId == 57566 || spellId == 57567 || spellId == 24450)
{
shouldApply = false;
}

View File

@@ -196,8 +196,8 @@ bool CastEnchantItemAction::isPossible()
}
CastHealingSpellAction::CastHealingSpellAction(PlayerbotAI* botAI, std::string const spell, uint8 estAmount,
HealingManaEfficiency manaEfficiency)
: CastAuraSpellAction(botAI, spell, true), estAmount(estAmount), manaEfficiency(manaEfficiency)
HealingManaEfficiency manaEfficiency, bool isOwner)
: CastAuraSpellAction(botAI, spell, isOwner), estAmount(estAmount), manaEfficiency(manaEfficiency)
{
range = botAI->GetRange("heal");
}

View File

@@ -129,7 +129,7 @@ class CastHealingSpellAction : public CastAuraSpellAction
{
public:
CastHealingSpellAction(PlayerbotAI* botAI, std::string const spell, uint8 estAmount = 15.0f,
HealingManaEfficiency manaEfficiency = HealingManaEfficiency::MEDIUM);
HealingManaEfficiency manaEfficiency = HealingManaEfficiency::MEDIUM, bool isOwner = true);
std::string const GetTargetName() override { return "self target"; }
bool isUseful() override;
@@ -177,8 +177,8 @@ class HealPartyMemberAction : public CastHealingSpellAction, public PartyMemberA
{
public:
HealPartyMemberAction(PlayerbotAI* botAI, std::string const spell, uint8 estAmount = 15.0f,
HealingManaEfficiency manaEfficiency = HealingManaEfficiency::MEDIUM)
: CastHealingSpellAction(botAI, spell, estAmount, manaEfficiency), PartyMemberActionNameSupport(spell)
HealingManaEfficiency manaEfficiency = HealingManaEfficiency::MEDIUM, bool isOwner = true)
: CastHealingSpellAction(botAI, spell, estAmount, manaEfficiency, isOwner), PartyMemberActionNameSupport(spell)
{
}

View File

@@ -827,11 +827,12 @@ bool MovementAction::ReachCombatTo(Unit* target, float distance)
float shortenTo = distance;
// Avoid walking too far when moving towards each other
if (bot->GetDistance(tx, ty, tz) >= 10.0f)
shortenTo = std::max(distance, bot->GetDistance(tx, ty, tz) / 2);
float disToGo = bot->GetExactDist(tx, ty, tz) - distance;
if (disToGo >= 10.0f)
shortenTo = disToGo / 2 + distance;
if (bot->GetExactDist(tx, ty, tz) <= shortenTo)
return false;
// if (bot->GetExactDist(tx, ty, tz) <= shortenTo)
// return false;
path.ShortenPathUntilDist(G3D::Vector3(tx, ty, tz), shortenTo);
G3D::Vector3 endPos = path.GetPath().back();
@@ -2313,7 +2314,7 @@ bool TankFaceAction::Execute(Event event)
if (!bot->GetGroup())
return false;
if (!bot->IsWithinMeleeRange(target))
if (!bot->IsWithinMeleeRange(target) || target->isMoving())
return false;
if (!AI_VALUE2(bool, "has aggro", "current target"))
@@ -2513,7 +2514,7 @@ bool SetBehindTargetAction::Execute(Event event)
if (target->GetVictim() == bot)
return false;
if (!bot->IsWithinMeleeRange(target))
if (!bot->IsWithinMeleeRange(target) || target->isMoving())
return false;
float deltaAngle = Position::NormalizeOrientation(target->GetOrientation() - target->GetAngle(bot));

View File

@@ -145,15 +145,12 @@ void CasterDruidStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
new TriggerNode("medium mana", NextAction::array(0, new NextAction("innervate", ACTION_HIGH + 9), NULL)));
triggers.push_back(new TriggerNode("enemy too close for spell",
NextAction::array(0, new NextAction("flee", ACTION_MOVE + 9), nullptr)));
triggers.push_back(
new TriggerNode("party member remove curse",
NextAction::array(0, new NextAction("remove curse on party", ACTION_DISPEL + 7), NULL)));
}
void CasterDruidAoeStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(
new TriggerNode("high aoe", NextAction::array(0, new NextAction("hurricane", ACTION_HIGH + 1), nullptr)));
new TriggerNode("medium aoe", NextAction::array(0, new NextAction("hurricane", ACTION_HIGH + 1), nullptr)));
triggers.push_back(new TriggerNode(
"light aoe", NextAction::array(0, new NextAction("starfall", ACTION_NORMAL + 5),
new NextAction("insect swarm on attacker", ACTION_NORMAL + 3),

View File

@@ -47,4 +47,35 @@ bool CastRebirthAction::isUseful()
{
return CastSpellAction::isUseful() &&
AI_VALUE2(float, "distance", GetTargetName()) <= sPlayerbotAIConfig->spellDistance;
}
Unit* CastRejuvenationOnNotFullAction::GetTarget()
{
Group* group = bot->GetGroup();
MinValueCalculator calc(100);
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
{
Player* player = gref->GetSource();
if (!player)
continue;
if (player->isDead() || player->IsFullHealth())
{
continue;
}
if (player->GetDistance2d(bot) > sPlayerbotAIConfig->spellDistance)
{
continue;
}
if (botAI->HasAura("rejuvenation", player))
{
continue;
}
calc.probe(player->GetHealthPct(), player);
}
return (Unit*)calc.param;
}
bool CastRejuvenationOnNotFullAction::isUseful()
{
return GetTarget();
}

View File

@@ -311,4 +311,16 @@ public:
CastEnrageAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "enrage") {}
};
class CastRejuvenationOnNotFullAction : public HealPartyMemberAction
{
public:
CastRejuvenationOnNotFullAction(PlayerbotAI* ai)
: HealPartyMemberAction(ai, "rejuvenation", 5.0f, HealingManaEfficiency::VERY_HIGH)
{
}
bool isUseful() override;
Unit* GetTarget() override;
};
#endif

View File

@@ -14,6 +14,7 @@
#include "DruidShapeshiftActions.h"
#include "DruidTriggers.h"
#include "GenericDruidNonCombatStrategy.h"
#include "GenericDruidStrategy.h"
#include "HealDruidStrategy.h"
#include "MeleeDruidStrategy.h"
#include "Playerbots.h"
@@ -33,6 +34,7 @@ public:
creators["buff"] = &DruidStrategyFactoryInternal::buff;
creators["boost"] = &DruidStrategyFactoryInternal::boost;
creators["cc"] = &DruidStrategyFactoryInternal::cc;
creators["healer dps"] = &DruidStrategyFactoryInternal::healer_dps;
}
private:
@@ -45,6 +47,7 @@ private:
static Strategy* buff(PlayerbotAI* botAI) { return new GenericDruidBuffStrategy(botAI); }
static Strategy* boost(PlayerbotAI* botAI) { return new DruidBoostStrategy(botAI); }
static Strategy* cc(PlayerbotAI* botAI) { return new DruidCcStrategy(botAI); }
static Strategy* healer_dps(PlayerbotAI* botAI) { return new DruidHealerDpsStrategy(botAI); }
};
class DruidDruidStrategyFactoryInternal : public NamedObjectContext<Strategy>
@@ -161,6 +164,7 @@ public:
creators["travel form"] = &DruidAiObjectContextInternal::travel_form;
creators["aquatic form"] = &DruidAiObjectContextInternal::aquatic_form;
creators["caster form"] = &DruidAiObjectContextInternal::caster_form;
creators["cancel tree form"] = &DruidAiObjectContextInternal::cancel_tree_form;
creators["mangle (bear)"] = &DruidAiObjectContextInternal::mangle_bear;
creators["maul"] = &DruidAiObjectContextInternal::maul;
creators["bash"] = &DruidAiObjectContextInternal::bash;
@@ -205,6 +209,7 @@ public:
creators["healing touch"] = &DruidAiObjectContextInternal::healing_touch;
creators["regrowth on party"] = &DruidAiObjectContextInternal::regrowth_on_party;
creators["rejuvenation on party"] = &DruidAiObjectContextInternal::rejuvenation_on_party;
creators["rejuvenation on not full"] = &DruidAiObjectContextInternal::rejuvenation_on_not_full;
creators["healing touch on party"] = &DruidAiObjectContextInternal::healing_touch_on_party;
creators["rebirth"] = &DruidAiObjectContextInternal::rebirth;
creators["revive"] = &DruidAiObjectContextInternal::revive;
@@ -246,6 +251,7 @@ private:
static Action* travel_form(PlayerbotAI* botAI) { return new CastTravelFormAction(botAI); }
static Action* aquatic_form(PlayerbotAI* botAI) { return new CastAquaticFormAction(botAI); }
static Action* caster_form(PlayerbotAI* botAI) { return new CastCasterFormAction(botAI); }
static Action* cancel_tree_form(PlayerbotAI* botAI) { return new CastCancelTreeFormAction(botAI); }
static Action* mangle_bear(PlayerbotAI* botAI) { return new CastMangleBearAction(botAI); }
static Action* maul(PlayerbotAI* botAI) { return new CastMaulAction(botAI); }
static Action* bash(PlayerbotAI* botAI) { return new CastBashAction(botAI); }
@@ -290,6 +296,7 @@ private:
static Action* healing_touch(PlayerbotAI* botAI) { return new CastHealingTouchAction(botAI); }
static Action* regrowth_on_party(PlayerbotAI* botAI) { return new CastRegrowthOnPartyAction(botAI); }
static Action* rejuvenation_on_party(PlayerbotAI* botAI) { return new CastRejuvenationOnPartyAction(botAI); }
static Action* rejuvenation_on_not_full(PlayerbotAI* botAI) { return new CastRejuvenationOnNotFullAction(botAI); }
static Action* healing_touch_on_party(PlayerbotAI* botAI) { return new CastHealingTouchOnPartyAction(botAI); }
static Action* rebirth(PlayerbotAI* botAI) { return new CastRebirthAction(botAI); }
static Action* revive(PlayerbotAI* botAI) { return new CastReviveAction(botAI); }

View File

@@ -45,6 +45,17 @@ bool CastCasterFormAction::Execute(Event event)
return true;
}
bool CastCancelTreeFormAction::isUseful()
{
return botAI->HasAura(33891, bot);
}
bool CastCancelTreeFormAction::Execute(Event event)
{
botAI->RemoveAura("tree of life");
return true;
}
bool CastTreeFormAction::isUseful()
{
return GetTarget() && CastSpellAction::isUseful() && !botAI->HasAura(33891, bot);

View File

@@ -70,4 +70,14 @@ public:
bool Execute(Event event) override;
};
class CastCancelTreeFormAction : public CastBuffSpellAction
{
public:
CastCancelTreeFormAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "cancel tree form") {}
bool isUseful() override;
bool isPossible() override { return true; }
bool Execute(Event event) override;
};
#endif

View File

@@ -125,26 +125,34 @@ void GenericDruidNonCombatStrategy::InitTriggers(std::vector<TriggerNode*>& trig
triggers.push_back(
new TriggerNode("party member critical health",
NextAction::array(0, new NextAction("rejuvenation on party", ACTION_MEDIUM_HEAL + 5),
new NextAction("regrowth on party", ACTION_MEDIUM_HEAL + 6), NULL)));
NextAction::array(0,
new NextAction("wild growth on party", ACTION_MEDIUM_HEAL + 7),
new NextAction("regrowth on party", ACTION_MEDIUM_HEAL + 6),
new NextAction("rejuvenation on party", ACTION_MEDIUM_HEAL + 5),
nullptr)));
triggers.push_back(
new TriggerNode("party member low health",
NextAction::array(0, new NextAction("rejuvenation on party", ACTION_MEDIUM_HEAL + 3),
new NextAction("regrowth on party", ACTION_MEDIUM_HEAL + 4), NULL)));
NextAction::array(0,
new NextAction("wild growth on party", ACTION_MEDIUM_HEAL + 5),
new NextAction("regrowth on party", ACTION_MEDIUM_HEAL + 4),
new NextAction("rejuvenation on party", ACTION_MEDIUM_HEAL + 3),
nullptr)));
triggers.push_back(
new TriggerNode("party member medium health",
NextAction::array(0, new NextAction("rejuvenation on party", ACTION_MEDIUM_HEAL + 1),
new NextAction("regrowth on party", ACTION_MEDIUM_HEAL + 2), NULL)));
NextAction::array(0, new NextAction("wild growth on party", ACTION_MEDIUM_HEAL + 3),
new NextAction("regrowth on party", ACTION_MEDIUM_HEAL + 2),
new NextAction("rejuvenation on party", ACTION_MEDIUM_HEAL + 1),
nullptr)));
triggers.push_back(
new TriggerNode("party member almost full health",
NextAction::array(0, new NextAction("rejuvenation on party", ACTION_LIGHT_HEAL + 2), NULL)));
NextAction::array(0, new NextAction("wild growth on party", ACTION_LIGHT_HEAL + 3), new NextAction("rejuvenation on party", ACTION_LIGHT_HEAL + 2), NULL)));
triggers.push_back(
new TriggerNode("party member remove curse",
NextAction::array(0, new NextAction("remove curse on party", ACTION_DISPEL + 7), NULL)));
NextAction::array(0, new NextAction("remove curse on party", ACTION_DISPEL + 7), nullptr)));
}
GenericDruidBuffStrategy::GenericDruidBuffStrategy(PlayerbotAI* botAI) : NonCombatStrategy(botAI)

View File

@@ -130,6 +130,11 @@ void DruidCureStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
triggers.push_back(
new TriggerNode("party member cure poison",
NextAction::array(0, new NextAction("abolish poison on party", ACTION_DISPEL + 1), nullptr)));
triggers.push_back(
new TriggerNode("party member remove curse",
NextAction::array(0, new NextAction("remove curse on party", ACTION_DISPEL + 7), NULL)));
}
void DruidBoostStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
@@ -147,3 +152,22 @@ void DruidCcStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
triggers.push_back(new TriggerNode(
"hibernate", NextAction::array(0, new NextAction("hibernate on cc", ACTION_HIGH + 3), nullptr)));
}
void DruidHealerDpsStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(
new TriggerNode("healer should attack",
NextAction::array(0,
new NextAction("cancel tree form", ACTION_DEFAULT + 0.3f),
new NextAction("moonfire", ACTION_DEFAULT + 0.2f),
new NextAction("wrath", ACTION_DEFAULT + 0.1f),
new NextAction("starfire", ACTION_DEFAULT),
nullptr)));
// long cast time
// triggers.push_back(
// new TriggerNode("medium aoe and healer should attack",
// NextAction::array(0,
// new NextAction("hurricane", ACTION_DEFAULT + 0.7f),
// nullptr)));
}

View File

@@ -46,4 +46,13 @@ public:
std::string const getName() override { return "cc"; }
};
class DruidHealerDpsStrategy : public Strategy
{
public:
DruidHealerDpsStrategy(PlayerbotAI* botAI) : Strategy(botAI) {}
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
std::string const getName() override { return "healer dps"; }
};
#endif

View File

@@ -10,7 +10,12 @@
class HealDruidStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
{
public:
HealDruidStrategyActionNodeFactory() { creators["nourish on party"] = &nourtish_on_party; }
HealDruidStrategyActionNodeFactory() {
creators["nourish on party"] = &nourtish_on_party;
// creators["wild growth on party"] = &wild_growth_on_party;
// creators["rejuvenation on party"] = &rejuvenation_on_party;
// creators["regrowth on party"] = &regrowth_on_party;
}
private:
static ActionNode* nourtish_on_party([[maybe_unused]] PlayerbotAI* botAI)
@@ -20,6 +25,27 @@ private:
/*A*/ NextAction::array(0, new NextAction("healing touch on party"), nullptr),
/*C*/ nullptr);
}
// static ActionNode* wild_growth_on_party([[maybe_unused]] PlayerbotAI* botAI)
// {
// return new ActionNode("wild growth on party",
// /*P*/ NextAction::array(0, new NextAction("tree form"), nullptr),
// /*A*/ nullptr,
// /*C*/ nullptr);
// }
// static ActionNode* rejuvenation_on_party([[maybe_unused]] PlayerbotAI* botAI)
// {
// return new ActionNode("rejuvenation on party",
// /*P*/ NextAction::array(0, new NextAction("tree form"), nullptr),
// /*A*/ nullptr,
// /*C*/ nullptr);
// }
// static ActionNode* regrowth_on_party([[maybe_unused]] PlayerbotAI* botAI)
// {
// return new ActionNode("regrowth on party",
// /*P*/ NextAction::array(0, new NextAction("tree form"), nullptr),
// /*A*/ nullptr,
// /*C*/ nullptr);
// }
};
HealDruidStrategy::HealDruidStrategy(PlayerbotAI* botAI) : GenericDruidStrategy(botAI)
@@ -31,61 +57,72 @@ void HealDruidStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
GenericDruidStrategy::InitTriggers(triggers);
// triggers.push_back(new TriggerNode("enemy out of spell", NextAction::array(0, new NextAction("reach spell",
// ACTION_NORMAL + 9), nullptr)));
triggers.push_back(
new TriggerNode("tree form", NextAction::array(0, new NextAction("tree form", ACTION_HIGH + 1), nullptr)));
// triggers.push_back(
// new TriggerNode("tree form", NextAction::array(0, new NextAction("tree form", ACTION_HIGH + 1), nullptr)));
triggers.push_back(new TriggerNode(
"party member to heal out of spell range",
NextAction::array(0, new NextAction("reach party member to heal", ACTION_CRITICAL_HEAL + 9), nullptr)));
triggers.push_back(
new TriggerNode("party member remove curse",
NextAction::array(0, new NextAction("remove curse on party", ACTION_DISPEL + 7), NULL)));
// CRITICAL
triggers.push_back(
new TriggerNode("party member critical health",
NextAction::array(0, new NextAction("swiftmend on party", ACTION_CRITICAL_HEAL + 4),
new NextAction("wild growth", ACTION_CRITICAL_HEAL + 3),
new NextAction("regrowth on party", ACTION_CRITICAL_HEAL + 2),
NextAction::array(0,
new NextAction("tree form", ACTION_CRITICAL_HEAL + 4.1f),
new NextAction("swiftmend on party", ACTION_CRITICAL_HEAL + 4),
new NextAction("regrowth on party", ACTION_CRITICAL_HEAL + 3),
new NextAction("wild growth on party", ACTION_CRITICAL_HEAL + 2),
new NextAction("nourish on party", ACTION_CRITICAL_HEAL + 1),
// new NextAction("healing touch on party", ACTION_CRITICAL_HEAL + 0),
NULL)));
nullptr)));
triggers.push_back(
new TriggerNode("party member critical health",
NextAction::array(0, new NextAction("nature's swiftness", ACTION_CRITICAL_HEAL + 4), NULL)));
NextAction::array(0, new NextAction("nature's swiftness", ACTION_CRITICAL_HEAL + 4), nullptr)));
triggers.push_back(new TriggerNode(
"group heal setting",
NextAction::array(0,
new NextAction("tree form", ACTION_MEDIUM_HEAL + 2.3f),
new NextAction("wild growth on party", ACTION_MEDIUM_HEAL + 2.2f),
new NextAction("rejuvenation on not full", ACTION_MEDIUM_HEAL + 2.1f),
nullptr)));
triggers.push_back(
new TriggerNode("medium group heal occasion",
NextAction::array(0, new NextAction("tranquility", ACTION_CRITICAL_HEAL + 5), NULL)));
new TriggerNode("medium group heal setting",
NextAction::array(0,
new NextAction("tree form", ACTION_CRITICAL_HEAL + 0.6f),
new NextAction("tranquility", ACTION_CRITICAL_HEAL + 0.5f), nullptr)));
// LOW
triggers.push_back(
new TriggerNode("party member low health",
NextAction::array(0, new NextAction("wild growth on party", ACTION_MEDIUM_HEAL + 9),
new NextAction("regrowth on party", ACTION_MEDIUM_HEAL + 8),
new NextAction("swiftmend on party", ACTION_MEDIUM_HEAL + 7),
new NextAction("nourish on party", ACTION_MEDIUM_HEAL + 6),
// new NextAction("healing touch on party", ACTION_MEDIUM_HEAL + 5),
NULL)));
NextAction::array(0, new NextAction("tree form", ACTION_MEDIUM_HEAL + 1.5f),
new NextAction("wild growth on party", ACTION_MEDIUM_HEAL + 1.4f),
new NextAction("regrowth on party", ACTION_MEDIUM_HEAL + 1.3f),
new NextAction("swiftmend on party", ACTION_MEDIUM_HEAL + 1.2),
new NextAction("nourish on party", ACTION_MEDIUM_HEAL + 1.1f),
nullptr)));
// MEDIUM
triggers.push_back(
new TriggerNode("party member medium health",
NextAction::array(0, new NextAction("wild growth on party", ACTION_MEDIUM_HEAL + 4),
new NextAction("rejuvenation on party", ACTION_MEDIUM_HEAL + 3),
new NextAction("regrowth on party", ACTION_MEDIUM_HEAL + 2),
new NextAction("nourish on party", ACTION_MEDIUM_HEAL + 1), NULL)));
NextAction::array(0,
new NextAction("tree form", ACTION_MEDIUM_HEAL + 0.5f),
new NextAction("wild growth on party", ACTION_MEDIUM_HEAL + 0.4f),
new NextAction("rejuvenation on party", ACTION_MEDIUM_HEAL + 0.3f),
new NextAction("regrowth on party", ACTION_MEDIUM_HEAL + 0.2f),
new NextAction("nourish on party", ACTION_MEDIUM_HEAL + 0.1f), nullptr)));
// almost full
triggers.push_back(
new TriggerNode("party member almost full health",
NextAction::array(0, new NextAction("wild growth on party", ACTION_LIGHT_HEAL + 3),
new NextAction("rejuvenation on party", ACTION_LIGHT_HEAL + 2),
new NextAction("regrowth on party", ACTION_LIGHT_HEAL + 1), NULL)));
NextAction::array(0, new NextAction("wild growth on party", ACTION_LIGHT_HEAL + 0.3f),
new NextAction("rejuvenation on party", ACTION_LIGHT_HEAL + 0.2f),
new NextAction("regrowth on party", ACTION_LIGHT_HEAL + 0.1f), nullptr)));
triggers.push_back(
new TriggerNode("medium mana", NextAction::array(0, new NextAction("innervate", ACTION_HIGH + 5), NULL)));
new TriggerNode("medium mana", NextAction::array(0, new NextAction("innervate", ACTION_HIGH + 5), nullptr)));
triggers.push_back(new TriggerNode("enemy too close for spell",
NextAction::array(0, new NextAction("flee", ACTION_MOVE + 9), nullptr)));

View File

@@ -22,7 +22,7 @@ void GenericPaladinNonCombatStrategy::InitTriggers(std::vector<TriggerNode*>& tr
triggers.push_back(new TriggerNode("party member almost full health",
NextAction::array(0, new NextAction("flash of light on party", 25.0f), NULL)));
triggers.push_back(new TriggerNode("party member medium health",
NextAction::array(0, new NextAction("holy light on party", 26.0f), NULL)));
NextAction::array(0, new NextAction("flash of light on party", 26.0f), NULL)));
triggers.push_back(new TriggerNode("party member low health",
NextAction::array(0, new NextAction("holy light on party", 27.0f), NULL)));
triggers.push_back(new TriggerNode("party member critical health",

View File

@@ -71,3 +71,17 @@ void PaladinCcStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
triggers.push_back(
new TriggerNode("turn undead", NextAction::array(0, new NextAction("turn undead", ACTION_HIGH + 1), nullptr)));
}
void PaladinHealerDpsStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(
new TriggerNode("healer should attack",
NextAction::array(0,
new NextAction("hammer of wrath", ACTION_DEFAULT + 0.6f),
new NextAction("holy shock", ACTION_DEFAULT + 0.5f),
new NextAction("shield of righteousness", ACTION_DEFAULT + 0.4f),
new NextAction("judgement of light", ACTION_DEFAULT + 0.3f),
new NextAction("consecration", ACTION_DEFAULT + 0.2f),
new NextAction("exorcism", ACTION_DEFAULT+ 0.1f),
nullptr)));
}

View File

@@ -46,4 +46,13 @@ public:
std::string const getName() override { return "cc"; }
};
class PaladinHealerDpsStrategy : public Strategy
{
public:
PaladinHealerDpsStrategy(PlayerbotAI* botAI) : Strategy(botAI) {}
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
std::string const getName() override { return "healer dps"; }
};
#endif

View File

@@ -22,7 +22,7 @@ public:
creators["cleanse magic"] = &cleanse_magic;
creators["cleanse poison on party"] = &cleanse_poison_on_party;
creators["cleanse disease on party"] = &cleanse_disease_on_party;
// creators["seal of wisdom"] = &seal_of_wisdom;
creators["seal of wisdom"] = &seal_of_wisdom;
creators["seal of justice"] = &seal_of_justice;
creators["hand of reckoning"] = &hand_of_reckoning;
creators["judgement"] = &judgement;
@@ -147,13 +147,13 @@ private:
/*A*/ NextAction::array(0, new NextAction("purify disease on party"), nullptr),
/*C*/ nullptr);
}
// static ActionNode* seal_of_wisdom(PlayerbotAI* ai)
// {
// return new ActionNode ("seal of wisdom",
// /*P*/ NULL,
// /*A*/ NextAction::array(0, new NextAction("seal of justice"), NULL),
// /*C*/ NULL);
// }
static ActionNode* seal_of_wisdom(PlayerbotAI* ai)
{
return new ActionNode ("seal of wisdom",
/*P*/ NULL,
/*A*/ NextAction::array(0, new NextAction("seal of righteousness"), NULL),
/*C*/ NULL);
}
static ActionNode* seal_of_justice(PlayerbotAI* ai)
{
return new ActionNode("seal of justice",

View File

@@ -27,7 +27,7 @@ HealPaladinStrategy::HealPaladinStrategy(PlayerbotAI* botAI) : GenericPaladinStr
NextAction** HealPaladinStrategy::getDefaultActions()
{
return NextAction::array(0, new NextAction("judgement of light", ACTION_DEFAULT + 2), nullptr);
return NextAction::array(0, new NextAction("judgement of light", ACTION_DEFAULT), nullptr);
}
void HealPaladinStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
@@ -49,7 +49,7 @@ void HealPaladinStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
NextAction::array(0, new NextAction("reach party member to heal", ACTION_EMERGENCY + 3), nullptr)));
triggers.push_back(
new TriggerNode("medium group heal occasion",
new TriggerNode("medium group heal setting",
NextAction::array(0, new NextAction("divine sacrifice", ACTION_CRITICAL_HEAL + 5),
new NextAction("avenging wrath", ACTION_HIGH + 4),
nullptr)));

View File

@@ -25,6 +25,7 @@ public:
creators["boost"] = &PaladinStrategyFactoryInternal::boost;
creators["cc"] = &PaladinStrategyFactoryInternal::cc;
creators["bthreat"] = &PaladinStrategyFactoryInternal::bthreat;
creators["healer dps"] = &PaladinStrategyFactoryInternal::healer_dps;
}
private:
@@ -33,6 +34,7 @@ private:
static Strategy* boost(PlayerbotAI* botAI) { return new PaladinBoostStrategy(botAI); }
static Strategy* cc(PlayerbotAI* botAI) { return new PaladinCcStrategy(botAI); }
static Strategy* bthreat(PlayerbotAI* botAI) { return new PaladinBuffThreatStrategy(botAI); }
static Strategy* healer_dps(PlayerbotAI* botAI) { return new PaladinHealerDpsStrategy(botAI); }
};
class PaladinResistanceStrategyFactoryInternal : public NamedObjectContext<Strategy>

View File

@@ -73,7 +73,7 @@ void TankPaladinStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
GenericPaladinStrategy::InitTriggers(triggers);
triggers.push_back(
new TriggerNode("seal", NextAction::array(0, new NextAction("seal of command", ACTION_HIGH), nullptr)));
new TriggerNode("seal", NextAction::array(0, new NextAction("seal of corruption", ACTION_HIGH), nullptr)));
triggers.push_back(
new TriggerNode("low mana", NextAction::array(0, new NextAction("seal of wisdom", ACTION_HIGH + 9), nullptr)));
// triggers.push_back(new TriggerNode("devotion aura", NextAction::array(0, new NextAction("devotion aura", 90.0f),
@@ -106,7 +106,7 @@ void TankPaladinStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
triggers.push_back(new TriggerNode(
"righteous fury", NextAction::array(0, new NextAction("righteous fury", ACTION_HIGH + 8), nullptr)));
triggers.push_back(
new TriggerNode("medium group heal occasion",
new TriggerNode("medium group heal setting",
NextAction::array(0, new NextAction("divine sacrifice", ACTION_HIGH + 5), nullptr)));
triggers.push_back(new TriggerNode(
"enough mana", NextAction::array(0, new NextAction("consecration", ACTION_HIGH + 4), nullptr)));

View File

@@ -87,3 +87,23 @@ void PriestCcStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
triggers.push_back(
new TriggerNode("shackle undead", NextAction::array(0, new NextAction("shackle undead", 31.0f), nullptr)));
}
void PriestHealerDpsStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(
new TriggerNode("healer should attack",
NextAction::array(0,
new NextAction("shadow word: pain", ACTION_DEFAULT + 0.5f),
new NextAction("holy fire", ACTION_DEFAULT + 0.4f),
new NextAction("smite", ACTION_DEFAULT + 0.3f),
new NextAction("mind blast", ACTION_DEFAULT + 0.2f),
new NextAction("shoot", ACTION_DEFAULT),
nullptr)));
triggers.push_back(
new TriggerNode("medium aoe and healer should attack",
NextAction::array(0,
new NextAction("mind sear", ACTION_DEFAULT + 0.5f),
nullptr)));
}

View File

@@ -46,4 +46,13 @@ public:
std::string const getName() override { return "cc"; }
};
class PriestHealerDpsStrategy : public Strategy
{
public:
PriestHealerDpsStrategy(PlayerbotAI* botAI) : Strategy(botAI) {}
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
std::string const getName() override { return "healer dps"; }
};
#endif

View File

@@ -29,51 +29,56 @@ void HealPriestStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
// triggers.push_back(new TriggerNode(
// "medium aoe heal",
// NextAction::array(0,
// new NextAction("circle of healing", ACTION_MEDIUM_HEAL + 8),
// new NextAction("circle of healing on party", ACTION_MEDIUM_HEAL + 8),
// // new NextAction("power word: shield on almost full health below", ACTION_MEDIUM_HEAL + 7),
// NULL)));
triggers.push_back(new TriggerNode(
"group heal occasion",
NextAction::array(0, new NextAction("circle of healing", ACTION_MEDIUM_HEAL + 8),
new NextAction("power word: shield on almost full health below", ACTION_MEDIUM_HEAL + 7),
NULL)));
"group heal setting",
NextAction::array(0,
new NextAction("prayer of mending on party", ACTION_MEDIUM_HEAL + 8),
new NextAction("power word: shield on not full", ACTION_MEDIUM_HEAL + 7),
nullptr)));
triggers.push_back(new TriggerNode(
"medium group heal occasion",
NextAction::array(0, new NextAction("divine hymn", ACTION_CRITICAL_HEAL + 6),
new NextAction("prayer of healing on party", ACTION_CRITICAL_HEAL + 5), nullptr)));
"medium group heal setting",
NextAction::array(0, new NextAction("divine hymn", ACTION_CRITICAL_HEAL + 7),
new NextAction("prayer of mending on party", ACTION_CRITICAL_HEAL + 6),
new NextAction("power word: shield on not full", ACTION_CRITICAL_HEAL + 5),
new NextAction("prayer of healing on party", ACTION_CRITICAL_HEAL + 4),
nullptr)));
triggers.push_back(new TriggerNode(
"party member critical health",
NextAction::array(0, new NextAction("power word: shield on party", ACTION_CRITICAL_HEAL + 6),
NextAction::array(0, new NextAction("power word: shield on party", ACTION_CRITICAL_HEAL + 5),
new NextAction("penance on party", ACTION_CRITICAL_HEAL + 4),
new NextAction("flash heal on party", ACTION_CRITICAL_HEAL + 3),
new NextAction("prayer of mending on party", ACTION_CRITICAL_HEAL + 2), NULL)));
new NextAction("prayer of mending on party", ACTION_CRITICAL_HEAL + 3),
new NextAction("flash heal on party", ACTION_CRITICAL_HEAL + 2),
nullptr)));
triggers.push_back(
new TriggerNode("party member low health",
NextAction::array(0, new NextAction("power word: shield on party", ACTION_MEDIUM_HEAL + 4),
new NextAction("prayer of mending on party", ACTION_MEDIUM_HEAL + 3),
new NextAction("penance on party", ACTION_MEDIUM_HEAL + 2),
new NextAction("circle of healing", ACTION_MEDIUM_HEAL + 2),
new NextAction("prayer of mending on party", ACTION_MEDIUM_HEAL + 1),
new NextAction("flash heal on party", ACTION_MEDIUM_HEAL + 0), NULL)));
new NextAction("flash heal on party", ACTION_MEDIUM_HEAL + 0), nullptr)));
triggers.push_back(
new TriggerNode("party member medium health",
NextAction::array(0, new NextAction("power word: shield on party", ACTION_LIGHT_HEAL + 9),
new NextAction("penance on party", ACTION_LIGHT_HEAL + 7),
new NextAction("circle of healing", ACTION_LIGHT_HEAL + 7),
new NextAction("prayer of mending on party", ACTION_LIGHT_HEAL + 6),
new NextAction("prayer of mending on party", ACTION_LIGHT_HEAL + 7),
new NextAction("penance on party", ACTION_LIGHT_HEAL + 6),
new NextAction("flash heal on party", ACTION_LIGHT_HEAL + 5),
// new NextAction("renew on party", ACTION_LIGHT_HEAL + 8),
NULL)));
nullptr)));
triggers.push_back(
new TriggerNode("party member almost full health",
NextAction::array(0,
// new NextAction("penance on party", ACTION_LIGHT_HEAL + 3),
new NextAction("renew on party", ACTION_LIGHT_HEAL + 2), NULL)));
new NextAction("prayer of mending on party", ACTION_LIGHT_HEAL + 2),
new NextAction("renew on party", ACTION_LIGHT_HEAL + 1),
nullptr)));
// triggers.push_back(new TriggerNode("almost full health", NextAction::array(0, new NextAction("renew", 43.f),
// nullptr))); triggers.push_back(new TriggerNode("party member almost full health", NextAction::array(0, new
@@ -86,7 +91,7 @@ void HealPriestStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
NextAction::array(0, new NextAction("reach party member to heal", ACTION_CRITICAL_HEAL + 10), nullptr)));
// triggers.push_back(new TriggerNode("medium aoe heal", NextAction::array(0, new NextAction("prayer of
// mending", 49.0f), nullptr))); triggers.push_back(new TriggerNode("medium aoe heal", NextAction::array(0, new
// NextAction("circle of healing", 48.0f), nullptr))); triggers.push_back(new TriggerNode("binding heal",
// NextAction("circle of healing on party", 48.0f), nullptr))); triggers.push_back(new TriggerNode("binding heal",
// NextAction::array(0, new NextAction("binding heal", 52.0f), nullptr))); triggers.push_back(new TriggerNode("low
// mana", NextAction::array(0, new NextAction("shadowfiend", ACTION_HIGH), nullptr)));

View File

@@ -63,42 +63,50 @@ void HolyHealPriestStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
GenericPriestStrategy::InitTriggers(triggers);
triggers.push_back(
new TriggerNode("group heal occasion",
NextAction::array(0, new NextAction("circle of healing", ACTION_MEDIUM_HEAL + 8), NULL)));
new TriggerNode("group heal setting",
NextAction::array(0,
new NextAction("prayer of mending on party", ACTION_MEDIUM_HEAL + 9),
new NextAction("circle of healing on party", ACTION_MEDIUM_HEAL + 8), nullptr)));
triggers.push_back(new TriggerNode(
"medium group heal occasion",
NextAction::array(0, new NextAction("divine hymn", ACTION_CRITICAL_HEAL + 6),
new NextAction("prayer of healing on party", ACTION_CRITICAL_HEAL + 5), nullptr)));
"medium group heal setting",
NextAction::array(0, new NextAction("divine hymn", ACTION_CRITICAL_HEAL + 7),
new NextAction("prayer of mending on party", ACTION_CRITICAL_HEAL + 6),
new NextAction("circle of healing on party", ACTION_CRITICAL_HEAL + 5),
new NextAction("prayer of healing on party", ACTION_CRITICAL_HEAL + 4), nullptr)));
triggers.push_back(new TriggerNode(
"party member critical health",
NextAction::array(0,
new NextAction("guardian spirit on party", ACTION_CRITICAL_HEAL + 6),
new NextAction("power word: shield on party", ACTION_CRITICAL_HEAL + 5),
new NextAction("flash heal on party", ACTION_CRITICAL_HEAL + 3),
new NextAction("prayer of mending on party", ACTION_CRITICAL_HEAL + 2), NULL)));
new NextAction("prayer of mending on party", ACTION_CRITICAL_HEAL + 3),
new NextAction("greater heal on party", ACTION_MEDIUM_HEAL + 2),
new NextAction("flash heal on party", ACTION_CRITICAL_HEAL + 1),
nullptr)));
triggers.push_back(
new TriggerNode("party member low health",
NextAction::array(0, new NextAction("circle of healing", ACTION_MEDIUM_HEAL + 4),
new NextAction("greater heal on party", ACTION_MEDIUM_HEAL + 3),
new NextAction("prayer of mending on party", ACTION_MEDIUM_HEAL + 2),
new NextAction("flash heal on party", ACTION_MEDIUM_HEAL + 1), NULL)));
NextAction::array(0, new NextAction("circle of healing on party", ACTION_MEDIUM_HEAL + 4),
new NextAction("prayer of mending on party", ACTION_MEDIUM_HEAL + 3),
new NextAction("greater heal on party", ACTION_MEDIUM_HEAL + 2),
new NextAction("flash heal on party", ACTION_MEDIUM_HEAL + 1), nullptr)));
triggers.push_back(
new TriggerNode("party member medium health",
NextAction::array(0, new NextAction("circle of healing", ACTION_LIGHT_HEAL + 7),
NextAction::array(0, new NextAction("circle of healing on party", ACTION_LIGHT_HEAL + 7),
new NextAction("prayer of mending on party", ACTION_LIGHT_HEAL + 6),
new NextAction("flash heal on party", ACTION_LIGHT_HEAL + 5),
new NextAction("greater heal on party", ACTION_MEDIUM_HEAL + 5),
new NextAction("flash heal on party", ACTION_LIGHT_HEAL + 4),
// new NextAction("renew on party", ACTION_LIGHT_HEAL + 8),
NULL)));
nullptr)));
triggers.push_back(
new TriggerNode("party member almost full health",
NextAction::array(0, new NextAction("renew on party", ACTION_LIGHT_HEAL + 2),
// new NextAction("flash heal on party", ACTION_LIGHT_HEAL + 1),
NULL)));
NextAction::array(0,
new NextAction("renew on party", ACTION_LIGHT_HEAL + 2),
new NextAction("prayer of mending on party", ACTION_LIGHT_HEAL + 1),
nullptr)));
triggers.push_back(new TriggerNode(
"party member to heal out of spell range",

View File

@@ -18,7 +18,7 @@ bool CastRemoveShadowformAction::Execute(Event event)
return true;
}
Unit* CastPowerWordShieldOnAlmostFullHealthBelow::GetTarget()
Unit* CastPowerWordShieldOnAlmostFullHealthBelowAction::GetTarget()
{
Group* group = bot->GetGroup();
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
@@ -47,7 +47,7 @@ Unit* CastPowerWordShieldOnAlmostFullHealthBelow::GetTarget()
return nullptr;
}
bool CastPowerWordShieldOnAlmostFullHealthBelow::isUseful()
bool CastPowerWordShieldOnAlmostFullHealthBelowAction::isUseful()
{
Group* group = bot->GetGroup();
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
@@ -74,4 +74,35 @@ bool CastPowerWordShieldOnAlmostFullHealthBelow::isUseful()
return true;
}
return false;
}
Unit* CastPowerWordShieldOnNotFullAction::GetTarget()
{
Group* group = bot->GetGroup();
MinValueCalculator calc(100);
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
{
Player* player = gref->GetSource();
if (!player)
continue;
if (player->isDead() || player->IsFullHealth())
{
continue;
}
if (player->GetDistance2d(bot) > sPlayerbotAIConfig->spellDistance)
{
continue;
}
if (botAI->HasAnyAuraOf(player, "weakened soul", "power word: shield", nullptr))
{
continue;
}
calc.probe(player->GetHealthPct(), player);
}
return (Unit*)calc.param;
}
bool CastPowerWordShieldOnNotFullAction::isUseful()
{
return GetTarget();
}

View File

@@ -52,10 +52,23 @@ HEAL_PARTY_ACTION(CastGreaterHealOnPartyAction, "greater heal", 50.0f, HealingMa
HEAL_PARTY_ACTION(CastPowerWordShieldOnPartyAction, "power word: shield", 15.0f, HealingManaEfficiency::VERY_HIGH);
HEAL_PARTY_ACTION(CastFlashHealOnPartyAction, "flash heal", 15.0f, HealingManaEfficiency::LOW);
HEAL_PARTY_ACTION(CastRenewOnPartyAction, "renew", 15.0f, HealingManaEfficiency::VERY_HIGH);
HEAL_PARTY_ACTION(CastPrayerOfMendingAction, "prayer of mending", 15.0f, HealingManaEfficiency::MEDIUM);
// HEAL_PARTY_ACTION(CastPrayerOfMendingAction, "prayer of mending", 10.0f, HealingManaEfficiency::HIGH);
class CastPrayerOfMendingAction : public HealPartyMemberAction
{
public:
CastPrayerOfMendingAction(PlayerbotAI* botAI) : HealPartyMemberAction(botAI, "prayer of mending", 10.0f, HealingManaEfficiency::HIGH, false) {}
};
HEAL_PARTY_ACTION(CastBindingHealAction, "binding heal", 15.0f, HealingManaEfficiency::MEDIUM);
HEAL_PARTY_ACTION(CastPrayerOfHealingAction, "prayer of healing", 15.0f, HealingManaEfficiency::MEDIUM);
AOE_HEAL_ACTION(CastCircleOfHealingAction, "circle of healing", 15.0f, HealingManaEfficiency::HIGH);
// AOE_HEAL_ACTION(CastCircleOfHealingAction, "circle of healing", 15.0f, HealingManaEfficiency::HIGH);
class CastCircleOfHealingAction : public HealPartyMemberAction
{
public:
CastCircleOfHealingAction(PlayerbotAI* ai) : HealPartyMemberAction(ai, "circle of healing", 15.0f, HealingManaEfficiency::HIGH)
{
}
};
AOE_HEAL_ACTION(CastLightwellAction, "lightwell", 15.0f, HealingManaEfficiency::MEDIUM);
SPELL_ACTION(CastSmiteAction, "smite");
@@ -68,7 +81,13 @@ CURE_PARTY_ACTION(CastCureDiseaseOnPartyAction, "cure disease", DISPEL_DISEASE);
CURE_ACTION(CastAbolishDiseaseAction, "abolish disease");
CURE_PARTY_ACTION(CastAbolishDiseaseOnPartyAction, "abolish disease", DISPEL_DISEASE);
DEBUFF_CHECKISOWNER_ACTION(CastHolyFireAction, "holy fire");
// DEBUFF_CHECKISOWNER_ACTION(CastHolyFireAction, "holy fire");
class CastHolyFireAction : public CastDebuffSpellAction
{
public:
CastHolyFireAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "holy fire", true, 0.0f) {}
};
// shadow 2.4.3
// BUFF_ACTION(CastShadowfiendAction, "shadowfiend");
SPELL_ACTION(CastShadowWordDeathAction, "shadow word: death");
@@ -156,10 +175,10 @@ public:
virtual std::string const GetTargetName() { return "current target"; }
};
class CastPowerWordShieldOnAlmostFullHealthBelow : public HealPartyMemberAction
class CastPowerWordShieldOnAlmostFullHealthBelowAction : public HealPartyMemberAction
{
public:
CastPowerWordShieldOnAlmostFullHealthBelow(PlayerbotAI* ai)
CastPowerWordShieldOnAlmostFullHealthBelowAction(PlayerbotAI* ai)
: HealPartyMemberAction(ai, "power word: shield", 15.0f, HealingManaEfficiency::HIGH)
{
}
@@ -167,6 +186,17 @@ public:
Unit* GetTarget() override;
};
class CastPowerWordShieldOnNotFullAction : public HealPartyMemberAction
{
public:
CastPowerWordShieldOnNotFullAction(PlayerbotAI* ai)
: HealPartyMemberAction(ai, "power word: shield", 5.0f, HealingManaEfficiency::HIGH)
{
}
bool isUseful() override;
Unit* GetTarget() override;
};
class CastMindSearAction : public CastSpellAction
{
public:

View File

@@ -5,6 +5,7 @@
#include "PriestAiObjectContext.h"
#include "GenericPriestStrategy.h"
#include "HolyPriestStrategy.h"
#include "NamedObjectContext.h"
#include "Playerbots.h"
@@ -30,6 +31,7 @@ public:
creators["boost"] = &PriestStrategyFactoryInternal::boost;
creators["rshadow"] = &PriestStrategyFactoryInternal::rshadow;
creators["cc"] = &PriestStrategyFactoryInternal::cc;
creators["healer dps"] = &PriestStrategyFactoryInternal::healer_dps;
}
private:
@@ -42,6 +44,7 @@ private:
static Strategy* pull(PlayerbotAI* botAI) { return new PullStrategy(botAI, "shoot"); }
static Strategy* shadow_debuff(PlayerbotAI* botAI) { return new ShadowPriestDebuffStrategy(botAI); }
static Strategy* cure(PlayerbotAI* botAI) { return new PriestCureStrategy(botAI); }
static Strategy* healer_dps(PlayerbotAI* botAI) { return new PriestHealerDpsStrategy(botAI); }
};
class PriestCombatStrategyFactoryInternal : public NamedObjectContext<Strategy>
@@ -172,6 +175,8 @@ public:
creators["power word: shield on party"] = &PriestAiObjectContextInternal::power_word_shield_on_party;
creators["power word: shield on almost full health below"] =
&PriestAiObjectContextInternal::power_word_shield_on_almost_full_health_below;
creators["power word: shield on not full"] =
&PriestAiObjectContextInternal::power_word_shield_on_not_full;
creators["renew"] = &PriestAiObjectContextInternal::renew;
creators["renew on party"] = &PriestAiObjectContextInternal::renew_on_party;
creators["greater heal"] = &PriestAiObjectContextInternal::greater_heal;
@@ -192,7 +197,7 @@ public:
creators["fade"] = &PriestAiObjectContextInternal::fade;
creators["inner fire"] = &PriestAiObjectContextInternal::inner_fire;
creators["resurrection"] = &PriestAiObjectContextInternal::resurrection;
creators["circle of healing"] = &PriestAiObjectContextInternal::circle_of_healing;
creators["circle of healing on party"] = &PriestAiObjectContextInternal::circle_of_healing;
creators["psychic scream"] = &PriestAiObjectContextInternal::psychic_scream;
creators["vampiric touch"] = &PriestAiObjectContextInternal::vampiric_touch;
creators["vampiric touch on attacker"] = &PriestAiObjectContextInternal::vampiric_touch_on_attacker;
@@ -282,7 +287,11 @@ private:
}
static Action* power_word_shield_on_almost_full_health_below(PlayerbotAI* ai)
{
return new CastPowerWordShieldOnAlmostFullHealthBelow(ai);
return new CastPowerWordShieldOnAlmostFullHealthBelowAction(ai);
}
static Action* power_word_shield_on_not_full(PlayerbotAI* ai)
{
return new CastPowerWordShieldOnNotFullAction(ai);
}
static Action* renew(PlayerbotAI* botAI) { return new CastRenewAction(botAI); }
static Action* renew_on_party(PlayerbotAI* botAI) { return new CastRenewOnPartyAction(botAI); }

View File

@@ -55,7 +55,7 @@ void PriestNonCombatStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
NextAction::array(0, new NextAction("renew on party", ACTION_LIGHT_HEAL + 3), NULL)));
triggers.push_back(
new TriggerNode("medium aoe heal", NextAction::array(0, new NextAction("circle of healing", 27.0f), NULL)));
new TriggerNode("group heal setting", NextAction::array(0, new NextAction("circle of healing on party", 27.0f), NULL)));
}
void PriestBuffStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)

View File

@@ -29,7 +29,7 @@ public:
creators["lesser heal on party"] = &lesser_heal_on_party;
creators["flash heal"] = &flash_heal;
creators["flash heal on party"] = &flash_heal_on_party;
creators["circle of healing"] = &circle_of_healing;
creators["circle of healing on party"] = &circle_of_healing;
creators["prayer of fortitude on party"] = &prayer_of_fortitude_on_party;
creators["prayer of spirit on party"] = &prayer_of_spirit_on_party;
}
@@ -128,7 +128,7 @@ private:
}
static ActionNode* circle_of_healing(PlayerbotAI* ai)
{
return new ActionNode("circle of healing",
return new ActionNode("circle of healing on party",
/*P*/ NextAction::array(0, new NextAction("remove shadowform"), NULL),
// /*A*/ NextAction::array(0, new NextAction("flash heal on party"), NULL),
/*A*/ NULL,

View File

@@ -51,8 +51,8 @@ void CasterShamanStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
// triggers.push_back(new TriggerNode("enemy out of spell", NextAction::array(0, new NextAction("reach spell",
// ACTION_NORMAL + 9), nullptr))); triggers.push_back(new TriggerNode("shaman weapon", NextAction::array(0, new
// NextAction("flametongue weapon", 23.0f), nullptr)));
// triggers.push_back(new TriggerNode(
// "enough mana", NextAction::array(0, new NextAction("chain lightning", ACTION_DEFAULT + 0.1f), nullptr)));
triggers.push_back(new TriggerNode(
"enough mana", NextAction::array(0, new NextAction("chain lightning", ACTION_DEFAULT + 0.1f), nullptr)));
triggers.push_back(new TriggerNode("main hand weapon no imbue",
NextAction::array(0, new NextAction("flametongue weapon", 22.0f), nullptr)));

View File

@@ -3,6 +3,7 @@
* and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#include "GenericShamanStrategy.h"
#include "HealShamanStrategy.h"
#include "Playerbots.h"
#include "Strategy.h"
@@ -17,7 +18,7 @@ public:
creators["windfury weapon"] = &windfury_weapon;
creators["lesser healing wave"] = &lesser_healing_wave;
creators["lesser healing wave on party"] = &lesser_healing_wave_on_party;
creators["chain heal"] = &chain_heal;
creators["chain heal on party"] = &chain_heal;
creators["riptide"] = &riptide;
creators["riptide on party"] = &riptide_on_party;
creators["earth shock"] = &earth_shock;
@@ -74,9 +75,9 @@ private:
static ActionNode* chain_heal([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode("chain heal",
return new ActionNode("chain heal on party",
/*P*/ nullptr,
/*A*/ NextAction::array(0, new NextAction("lesser healing wave"), nullptr),
/*A*/ NextAction::array(0, new NextAction("lesser healing wave on party"), nullptr),
/*C*/ nullptr);
}
@@ -116,7 +117,7 @@ void GenericShamanStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
// triggers.push_back(new TriggerNode("party member medium health", NextAction::array(0, new NextAction("lesser
// healing wave on party", 25.0f), nullptr))); triggers.push_back(new TriggerNode("party member low health",
// NextAction::array(0, new NextAction("riptide on party", 25.0f), nullptr))); triggers.push_back(new
// TriggerNode("medium aoe heal", NextAction::array(0, new NextAction("chain heal", 27.0f), nullptr)));
// TriggerNode("medium aoe heal", NextAction::array(0, new NextAction("chain heal on party", 27.0f), nullptr)));
// triggers.push_back(new TriggerNode("medium health", NextAction::array(0, new NextAction("lesser healing
// wave", 26.0f), nullptr))); triggers.push_back(new TriggerNode("low health", NextAction::array(0, new
// NextAction("riptide", 26.0f), nullptr)));
@@ -162,3 +163,18 @@ void ShamanCureStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
new TriggerNode("party member cleanse spirit curse",
NextAction::array(0, new NextAction("cleanse spirit curse on party", 23.0f), nullptr)));
}
void ShamanHealerDpsStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(
new TriggerNode("healer should attack",
NextAction::array(0,
new NextAction("flame shock", ACTION_DEFAULT + 0.2f),
new NextAction("lava burst", ACTION_DEFAULT + 0.1f),
new NextAction("lightning bolt", ACTION_DEFAULT), nullptr)));
triggers.push_back(
new TriggerNode("medium aoe and healer should attack",
NextAction::array(0,
new NextAction("chain lightning", ACTION_DEFAULT + 0.3f), nullptr)));
}

View File

@@ -45,4 +45,13 @@ public:
std::string const getName() override { return "cure"; }
};
class ShamanHealerDpsStrategy : public Strategy
{
public:
ShamanHealerDpsStrategy(PlayerbotAI* botAI) : Strategy(botAI) {}
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
std::string const getName() override { return "healer dps"; }
};
#endif

View File

@@ -49,8 +49,8 @@ void HealShamanStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
triggers.push_back(new TriggerNode("main hand weapon no imbue",
NextAction::array(0, new NextAction("earthliving weapon", 22.0f), nullptr)));
triggers.push_back(new TriggerNode(
"group heal occasion",
NextAction::array(0, new NextAction("riptide on party", 23.0f), new NextAction("chain heal", 22.0f), NULL)));
"group heal setting",
NextAction::array(0, new NextAction("riptide on party", 23.0f), new NextAction("chain heal on party", 22.0f), NULL)));
triggers.push_back(new TriggerNode(
"party member critical health",

View File

@@ -42,11 +42,11 @@ public:
}
};
class CastChainHealAction : public CastAoeHealSpellAction
class CastChainHealAction : public HealPartyMemberAction
{
public:
CastChainHealAction(PlayerbotAI* botAI)
: CastAoeHealSpellAction(botAI, "chain heal", 15.0f, HealingManaEfficiency::HIGH)
: HealPartyMemberAction(botAI, "chain heal", 15.0f, HealingManaEfficiency::HIGH)
{
}
};
@@ -335,7 +335,7 @@ public:
class CastFlameShockAction : public CastDebuffSpellAction
{
public:
CastFlameShockAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "flame shock", true) {}
CastFlameShockAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "flame shock", true, 6.0f) {}
};
class CastEarthShockAction : public CastSpellAction

View File

@@ -6,6 +6,7 @@
#include "ShamanAiObjectContext.h"
#include "CasterShamanStrategy.h"
#include "GenericShamanStrategy.h"
#include "HealShamanStrategy.h"
#include "MeleeShamanStrategy.h"
#include "NamedObjectContext.h"
@@ -25,6 +26,7 @@ public:
creators["melee aoe"] = &ShamanStrategyFactoryInternal::melee_aoe;
creators["caster aoe"] = &ShamanStrategyFactoryInternal::caster_aoe;
creators["cure"] = &ShamanStrategyFactoryInternal::cure;
creators["healer dps"] = &ShamanStrategyFactoryInternal::healer_dps;
}
private:
@@ -33,6 +35,7 @@ private:
static Strategy* melee_aoe(PlayerbotAI* botAI) { return new MeleeAoeShamanStrategy(botAI); }
static Strategy* caster_aoe(PlayerbotAI* botAI) { return new CasterAoeShamanStrategy(botAI); }
static Strategy* cure(PlayerbotAI* botAI) { return new ShamanCureStrategy(botAI); }
static Strategy* healer_dps(PlayerbotAI* botAI) { return new ShamanHealerDpsStrategy(botAI); }
};
class ShamanBuffStrategyFactoryInternal : public NamedObjectContext<Strategy>
@@ -207,7 +210,7 @@ public:
creators["lesser healing wave on party"] = &ShamanAiObjectContextInternal::lesser_healing_wave_on_party;
creators["earth shield"] = &ShamanAiObjectContextInternal::earth_shield;
creators["earth shield on party"] = &ShamanAiObjectContextInternal::earth_shield_on_party;
creators["chain heal"] = &ShamanAiObjectContextInternal::chain_heal;
creators["chain heal on party"] = &ShamanAiObjectContextInternal::chain_heal;
creators["riptide"] = &ShamanAiObjectContextInternal::riptide;
creators["riptide on party"] = &ShamanAiObjectContextInternal::riptide_on_party;
creators["stormstrike"] = &ShamanAiObjectContextInternal::stormstrike;

View File

@@ -39,7 +39,7 @@ void ShamanNonCombatStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
new NextAction("lesser healing wave on party", 24.0f), NULL)));
triggers.push_back(
new TriggerNode("medium aoe heal", NextAction::array(0, new NextAction("chain heal", 27.0f), NULL)));
new TriggerNode("group heal setting", NextAction::array(0, new NextAction("chain heal on party", 27.0f), NULL)));
triggers.push_back(
new TriggerNode("cure poison", NextAction::array(0, new NextAction("cure poison", 21.0f), nullptr)));

View File

@@ -9,6 +9,8 @@
#include "BattlegroundWS.h"
#include "CreatureAI.h"
#include "GameTime.h"
#include "LastSpellCastValue.h"
#include "ObjectGuid.h"
#include "PlayerbotAIConfig.h"
#include "Playerbots.h"
@@ -76,7 +78,7 @@ bool AlmostFullManaTrigger::IsActive()
bool EnoughManaTrigger::IsActive()
{
return AI_VALUE2(bool, "has mana", "self target") && AI_VALUE2(uint8, "mana", "self target") > 65;
return AI_VALUE2(bool, "has mana", "self target") && AI_VALUE2(uint8, "mana", "self target") > sPlayerbotAIConfig->highMana;
}
bool RageAvailable::IsActive() { return AI_VALUE2(uint8, "rage", "self target") >= amount; }
@@ -366,6 +368,39 @@ bool GenericBoostTrigger::IsActive()
return AI_VALUE(uint8, "balance") <= balance;
}
bool HealerShouldAttackTrigger::IsActive()
{
// nobody can help me
if (botAI->GetNearGroupMemberCount(sPlayerbotAIConfig->sightDistance) <= 1)
return true;
if (AI_VALUE2(uint8, "health", "party member to heal") < sPlayerbotAIConfig->almostFullHealth)
return false;
// special check for resto druid (dont remove tree of life frequently)
if (bot->GetAura(33891))
{
LastSpellCast& lastSpell = botAI->GetAiObjectContext()->GetValue<LastSpellCast&>("last spell cast")->Get();
if (lastSpell.timer + 5 > time(nullptr))
return false;
}
int manaThreshold;
int balance = AI_VALUE(uint8, "balance");
// higher threshold in higher pressure
if (balance <= 50)
manaThreshold = 85;
else if (balance <= 100)
manaThreshold = sPlayerbotAIConfig->highMana;
else
manaThreshold = sPlayerbotAIConfig->mediumMana;
if (AI_VALUE2(bool, "has mana", "self target") && AI_VALUE2(uint8, "mana", "self target") < manaThreshold)
return false;
return true;
}
bool ItemCountTrigger::IsActive() { return AI_VALUE2(uint32, "item count", item) < count; }
bool InterruptSpellTrigger::IsActive()

View File

@@ -459,6 +459,16 @@ protected:
float balance;
};
class HealerShouldAttackTrigger : public Trigger
{
public:
HealerShouldAttackTrigger(PlayerbotAI* botAI)
: Trigger(botAI, "healer should attack", 1)
{
}
bool IsActive() override;
};
class RandomTrigger : public Trigger
{

View File

@@ -24,7 +24,18 @@ bool AoeHealTrigger::IsActive() { return AI_VALUE2(uint8, "aoe heal", type) >= c
bool AoeInGroupTrigger::IsActive()
{
Group* group = bot->GetGroup();
return group && group->GetMembersCount() >= 5 &&
AI_VALUE2(uint8, "aoe heal", type) >= (group->GetMembersCount() * ratio);
int32 member = botAI->GetNearGroupMemberCount();
if (member < 5)
return false;
int threshold = member * 0.5;
if (member <= 5)
threshold = 3;
else if (member <= 10)
threshold = std::min(threshold, 5);
else if (member <= 25)
threshold = std::min(threshold, 10);
else
threshold = std::min(threshold, 15);
return AI_VALUE2(uint8, "aoe heal", type) >= threshold;
}

View File

@@ -186,14 +186,13 @@ protected:
class AoeInGroupTrigger : public Trigger
{
public:
AoeInGroupTrigger(PlayerbotAI* ai, std::string name, std::string type, float ratio)
: Trigger(ai, name), ratio(ratio), type(type)
AoeInGroupTrigger(PlayerbotAI* ai, std::string name, std::string type)
: Trigger(ai, name), type(type)
{
}
bool IsActive() override;
protected:
float ratio;
std::string type;
};

View File

@@ -48,6 +48,7 @@ public:
creators["almost full mana"] = &TriggerContext::AlmostFullMana;
creators["enough mana"] = &TriggerContext::EnoughMana;
creators["party member critical health"] = &TriggerContext::PartyMemberCriticalHealth;
creators["party member low health"] = &TriggerContext::PartyMemberLowHealth;
creators["party member medium health"] = &TriggerContext::PartyMemberMediumHealth;
@@ -83,6 +84,9 @@ public:
creators["medium aoe"] = &TriggerContext::MediumAoe;
creators["high aoe"] = &TriggerContext::HighAoe;
creators["healer should attack"] = &TriggerContext::healer_should_attack;
creators["medium aoe and healer should attack"] = &TriggerContext::medium_aoe_and_healer_should_attack;
creators["has area debuff"] = &TriggerContext::HasAreaDebuff;
creators["enemy out of melee"] = &TriggerContext::EnemyOutOfMelee;
@@ -135,8 +139,8 @@ public:
creators["medium aoe heal"] = &TriggerContext::medium_aoe_heal;
creators["almost full aoe heal"] = &TriggerContext::almost_full_aoe_heal;
creators["group heal occasion"] = &TriggerContext::group_heal_occasion;
creators["medium group heal occasion"] = &TriggerContext::medium_group_heal_occasion;
creators["group heal setting"] = &TriggerContext::group_heal_occasion;
creators["medium group heal setting"] = &TriggerContext::medium_group_heal_occasion;
creators["invalid target"] = &TriggerContext::invalid_target;
creators["lfg proposal active"] = &TriggerContext::lfg_proposal_active;
@@ -242,11 +246,11 @@ private:
}
static Trigger* group_heal_occasion(PlayerbotAI* ai)
{
return new AoeInGroupTrigger(ai, "group heal occasion", "almost full", 0.6);
return new AoeInGroupTrigger(ai, "group heal setting", "almost full");
}
static Trigger* medium_group_heal_occasion(PlayerbotAI* ai)
{
return new AoeInGroupTrigger(ai, "group heal occasion", "medium", 0.6);
return new AoeInGroupTrigger(ai, "medium group heal setting", "medium");
}
static Trigger* target_changed(PlayerbotAI* botAI) { return new TargetChangedTrigger(botAI); }
static Trigger* swimming(PlayerbotAI* botAI) { return new IsSwimmingTrigger(botAI); }
@@ -265,6 +269,8 @@ private:
static Trigger* LightAoe(PlayerbotAI* botAI) { return new LightAoeTrigger(botAI); }
static Trigger* MediumAoe(PlayerbotAI* botAI) { return new MediumAoeTrigger(botAI); }
static Trigger* HighAoe(PlayerbotAI* botAI) { return new HighAoeTrigger(botAI); }
static Trigger* healer_should_attack(PlayerbotAI* botAI) { return new HealerShouldAttackTrigger(botAI); }
static Trigger* medium_aoe_and_healer_should_attack(PlayerbotAI* botAI) { return new TwoTriggers(botAI, "medium aoe", "healer should attack"); }
static Trigger* HasAreaDebuff(PlayerbotAI* botAI) { return new HasAreaDebuffTrigger(botAI); }
static Trigger* LoseAggro(PlayerbotAI* botAI) { return new LoseAggroTrigger(botAI); }
static Trigger* HasAggro(PlayerbotAI* botAI) { return new HasAggroTrigger(botAI); }

View File

@@ -94,7 +94,7 @@ uint8 BalancePercentValue::Calculate()
level *= 3;
break;
case CREATURE_ELITE_WORLDBOSS:
level *= 30;
level *= 20;
break;
}

View File

@@ -55,7 +55,7 @@ private:
{
return new ActionNode("summon felhunter",
/*P*/ nullptr,
/*A*/ NextAction::array(0, new NextAction("summon voidwalker"), nullptr),
/*A*/ NextAction::array(0, new NextAction("summon succubus"), nullptr),
/*C*/ nullptr);
}
static ActionNode* summon_felguard([[maybe_unused]] PlayerbotAI* botAI)