Merge pull request #163 from liyunfan1223/healer_save_mana

Healer save mana
This commit is contained in:
Yunfan Li
2024-03-26 12:44:27 +08:00
committed by GitHub
20 changed files with 254 additions and 155 deletions

View File

@@ -306,6 +306,16 @@ AiPlayerbot.LowMana = 15
AiPlayerbot.MediumMana = 40
# Random bot default strategies (applied after defaults)
# Enable healer bot save mana
# Default: 1 (enable)
AiPlayerbot.AutoSaveMana = 1
# Healer bot save mana threshold
# Default: 60 (60%)
AiPlayerbot.SaveManaThreshold = 60
AiPlayerbot.RandomBotCombatStrategies = "+dps,+dps assist,-threat"
# AiPlayerbot.RandomBotNonCombatStrategies = "+grind,+loot,+rpg,+custom::say"
AiPlayerbot.RandomBotNonCombatStrategies = ""

View File

@@ -6,6 +6,7 @@
#include "BattlegroundMgr.h"
#include "Item.h"
#include "PlayerbotAI.h"
#include "PlayerbotAIConfig.h"
#include "Playerbots.h"
#include "Engine.h"
#include "Group.h"
@@ -265,7 +266,9 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
{
engine->addStrategies("racials", "chat", "default", "cast time", "duel", "boost", nullptr);
}
if (sPlayerbotAIConfig->autoSaveMana) {
engine->addStrategy("auto save mana");
}
switch (player->getClass())
{
case CLASS_PRIEST:
@@ -273,8 +276,9 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
{
engine->addStrategies("dps", "shadow debuff", "shadow aoe", "threat", nullptr);
}
else
else {
engine->addStrategies("heal", "threat", nullptr);
}
engine->addStrategies("dps assist", "cure", nullptr);
break;
@@ -426,7 +430,7 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
engine->addStrategy("arena");
}
engine->addStrategies("boost", "racials", "chat", "default", "aoe", "potions", "conserve mana", "cast time", "dps assist", nullptr);
engine->addStrategies("boost", "racials", "chat", "default", "aoe", "potions", "cast time", "dps assist", nullptr);
engine->removeStrategy("custom::say");
engine->removeStrategy("flee");
engine->removeStrategy("threat");
@@ -532,7 +536,9 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const
nonCombatEngine->addStrategies("nc", "food", "chat", "follow",
"default", "quest", "loot", "gather", "duel", "buff", "mount", nullptr);
}
if (sPlayerbotAIConfig->autoSaveMana) {
nonCombatEngine->addStrategy("auto save mana");
}
if ((facade->IsRealPlayer() || sRandomPlayerbotMgr->IsRandomBot(player)) && !player->InBattleground())
{
Player* master = facade->GetMaster();

View File

@@ -88,6 +88,8 @@ bool PlayerbotAIConfig::Initialize()
almostFullHealth = sConfigMgr->GetOption<int32>("AiPlayerbot.AlmostFullHealth", 85);
lowMana = sConfigMgr->GetOption<int32>("AiPlayerbot.LowMana", 15);
mediumMana = sConfigMgr->GetOption<int32>("AiPlayerbot.MediumMana", 40);
autoSaveMana = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoSaveMana", true);
saveManaThreshold = sConfigMgr->GetOption<int32>("AiPlayerbot.SaveManaThreshold", 60);
randomGearLoweringChance = sConfigMgr->GetOption<float>("AiPlayerbot.RandomGearLoweringChance", 0.15f);
randomBotMaxLevelChance = sConfigMgr->GetOption<float>("AiPlayerbot.RandomBotMaxLevelChance", 0.15f);

View File

@@ -23,6 +23,16 @@ enum class BotCheatMask : uint32
maxMask = 32
};
enum class HealingManaEfficiency : uint8
{
VERY_LOW = 1,
LOW = 2,
MEDIUM = 4,
HIGH = 8,
VERY_HIGH = 16,
SUPERIOR = 32
};
#define MAX_SPECNO 20
class PlayerbotAIConfig
@@ -51,6 +61,8 @@ class PlayerbotAIConfig
aoeRadius, rpgDistance, targetPosRecalcDistance, farDistance, healDistance, aggroDistance;
uint32 criticalHealth, lowHealth, mediumHealth, almostFullHealth;
uint32 lowMana, mediumMana;
bool autoSaveMana;
uint32 saveManaThreshold;
uint32 openGoSpell;
bool randomBotAutologin;

View File

@@ -121,7 +121,7 @@ void PlayerbotFactory::Init()
// continue;
enchantSpellIdCache.push_back(id);
LOG_INFO("playerbots", "Add {} to enchantment spells", id);
// LOG_INFO("playerbots", "Add {} to enchantment spells", id);
}
}
LOG_INFO("playerbots", "Loading {} enchantment spells", enchantSpellIdCache.size());

View File

@@ -302,14 +302,14 @@ class clazz : public CastHealingSpellAction \
bool isUseful() override { return useful; } \
}
#define HEAL_PARTY_ACTION(clazz, spell) \
#define HEAL_PARTY_ACTION(clazz, spell, estAmount, manaEfficiency) \
class clazz : public HealPartyMemberAction \
{ \
public: \
clazz(PlayerbotAI* botAI) : HealPartyMemberAction(botAI, spell) { } \
clazz(PlayerbotAI* botAI) : HealPartyMemberAction(botAI, spell, estAmount, manaEfficiency) { } \
}
#define AOE_HEAL_ACTION(clazz, spell) \
#define AOE_HEAL_ACTION(clazz, spell, estAmount, manaEfficiency) \
class clazz : public CastAoeHealSpellAction \
{ \
public: \

View File

@@ -58,7 +58,8 @@ class StrategyContext : public NamedObjectContext<Strategy>
creators["gather"] = &StrategyContext::gather;
creators["emote"] = &StrategyContext::emote;
creators["passive"] = &StrategyContext::passive;
creators["conserve mana"] = &StrategyContext::conserve_mana;
// creators["conserve mana"] = &StrategyContext::conserve_mana;
creators["auto save mana"] = &StrategyContext::auto_save_mana;
creators["food"] = &StrategyContext::food;
creators["chat"] = &StrategyContext::chat;
creators["default"] = &StrategyContext::world_packet;
@@ -131,7 +132,8 @@ class StrategyContext : public NamedObjectContext<Strategy>
static Strategy* gather(PlayerbotAI* botAI) { return new GatherStrategy(botAI); }
static Strategy* emote(PlayerbotAI* botAI) { return new EmoteStrategy(botAI); }
static Strategy* passive(PlayerbotAI* botAI) { return new PassiveStrategy(botAI); }
static Strategy* conserve_mana(PlayerbotAI* botAI) { return new ConserveManaStrategy(botAI); }
// static Strategy* conserve_mana(PlayerbotAI* botAI) { return new ConserveManaStrategy(botAI); }
static Strategy* auto_save_mana(PlayerbotAI* botAI) { return new HealerAutoSaveManaStrategy(botAI); }
static Strategy* food(PlayerbotAI* botAI) { return new UseFoodStrategy(botAI); }
static Strategy* chat(PlayerbotAI* botAI) { return new ChatCommandHandlerStrategy(botAI); }
static Strategy* world_packet(PlayerbotAI* botAI) { return new WorldPacketHandlerStrategy(botAI); }

View File

@@ -151,7 +151,8 @@ bool CastEnchantItemAction::isPossible()
return spellId && AI_VALUE2(Item*, "item for spell", spellId);
}
CastHealingSpellAction::CastHealingSpellAction(PlayerbotAI* botAI, std::string const spell, uint8 estAmount) : CastAuraSpellAction(botAI, spell, true), estAmount(estAmount)
CastHealingSpellAction::CastHealingSpellAction(PlayerbotAI* botAI, std::string const spell, uint8 estAmount, HealingManaEfficiency manaEfficiency)
: CastAuraSpellAction(botAI, spell, true), estAmount(estAmount), manaEfficiency(manaEfficiency)
{
range = botAI->GetRange("heal");
}

View File

@@ -98,20 +98,23 @@ class CastEnchantItemAction : public CastSpellAction
class CastHealingSpellAction : public CastAuraSpellAction
{
public:
CastHealingSpellAction(PlayerbotAI* botAI, std::string const spell, uint8 estAmount = 15.0f);
CastHealingSpellAction(PlayerbotAI* botAI, std::string const spell, uint8 estAmount = 15.0f, HealingManaEfficiency manaEfficiency = HealingManaEfficiency::MEDIUM);
std::string const GetTargetName() override { return "self target"; }
bool isUseful() override;
ActionThreatType getThreatType() override { return ActionThreatType::Aoe; }
protected:
// Yunfan: Mana efficiency tell the bot how to save mana. The higher the better.
HealingManaEfficiency manaEfficiency;
uint8 estAmount;
// protected:
};
class CastAoeHealSpellAction : public CastHealingSpellAction
{
public:
CastAoeHealSpellAction(PlayerbotAI* botAI, std::string const spell, uint8 estAmount = 15.0f) : CastHealingSpellAction(botAI, spell, estAmount) { }
CastAoeHealSpellAction(PlayerbotAI* botAI, std::string const spell, uint8 estAmount = 15.0f, HealingManaEfficiency manaEfficiency = HealingManaEfficiency::MEDIUM)
: CastHealingSpellAction(botAI, spell, estAmount, manaEfficiency) { }
std::string const GetTargetName() override { return "party member to heal"; }
bool isUseful() override;
@@ -142,8 +145,8 @@ class PartyMemberActionNameSupport
class HealPartyMemberAction : public CastHealingSpellAction, public PartyMemberActionNameSupport
{
public:
HealPartyMemberAction(PlayerbotAI* botAI, std::string const spell, uint8 estAmount = 15.0f) :
CastHealingSpellAction(botAI, spell, estAmount), PartyMemberActionNameSupport(spell) { }
HealPartyMemberAction(PlayerbotAI* botAI, std::string const spell, uint8 estAmount = 15.0f, HealingManaEfficiency manaEfficiency = HealingManaEfficiency::MEDIUM) :
CastHealingSpellAction(botAI, spell, estAmount, manaEfficiency), PartyMemberActionNameSupport(spell) { }
std::string const GetTargetName() override { return "party member to heal"; }
std::string const getName() override { return PartyMemberActionNameSupport::getName(); }

View File

@@ -46,19 +46,19 @@ class CastHealingTouchAction : public CastHealingSpellAction
class CastRejuvenationOnPartyAction : public HealPartyMemberAction
{
public:
CastRejuvenationOnPartyAction(PlayerbotAI* botAI) : HealPartyMemberAction(botAI, "rejuvenation") { }
CastRejuvenationOnPartyAction(PlayerbotAI* botAI) : HealPartyMemberAction(botAI, "rejuvenation", 15.0f, HealingManaEfficiency::VERY_HIGH) { }
};
class CastRegrowthOnPartyAction : public HealPartyMemberAction
{
public:
CastRegrowthOnPartyAction(PlayerbotAI* botAI) : HealPartyMemberAction(botAI, "regrowth") { }
CastRegrowthOnPartyAction(PlayerbotAI* botAI) : HealPartyMemberAction(botAI, "regrowth", 35.0f, HealingManaEfficiency::HIGH) { }
};
class CastHealingTouchOnPartyAction : public HealPartyMemberAction
{
public:
CastHealingTouchOnPartyAction(PlayerbotAI* botAI) : HealPartyMemberAction(botAI, "healing touch") { }
CastHealingTouchOnPartyAction(PlayerbotAI* botAI) : HealPartyMemberAction(botAI, "healing touch", 50.0f, HealingManaEfficiency::LOW) { }
};
class CastReviveAction : public ResurrectPartyMemberAction
@@ -242,7 +242,7 @@ class CastInnervateAction : public CastSpellAction
class CastTranquilityAction : public CastAoeHealSpellAction
{
public:
CastTranquilityAction(PlayerbotAI* botAI) : CastAoeHealSpellAction(botAI, "tranquility") { }
CastTranquilityAction(PlayerbotAI* botAI) : CastAoeHealSpellAction(botAI, "tranquility", 15.0f, HealingManaEfficiency::MEDIUM) { }
};
class CastNaturesSwiftnessAction : public CastBuffSpellAction
@@ -254,19 +254,19 @@ class CastNaturesSwiftnessAction : public CastBuffSpellAction
class CastWildGrowthOnPartyAction : public HealPartyMemberAction
{
public:
CastWildGrowthOnPartyAction(PlayerbotAI* ai) : HealPartyMemberAction(ai, "wild growth") {}
CastWildGrowthOnPartyAction(PlayerbotAI* ai) : HealPartyMemberAction(ai, "wild growth", 15.0f, HealingManaEfficiency::VERY_HIGH) {}
};
class CastPartySwiftmendAction : public HealPartyMemberAction
{
public:
CastPartySwiftmendAction(PlayerbotAI* ai) : HealPartyMemberAction(ai, "swiftmend") {}
CastPartySwiftmendAction(PlayerbotAI* ai) : HealPartyMemberAction(ai, "swiftmend", 15.0f, HealingManaEfficiency::MEDIUM) {}
};
class CastPartyNourishAction : public HealPartyMemberAction
{
public:
CastPartyNourishAction(PlayerbotAI* ai) : HealPartyMemberAction(ai, "nourish") {}
CastPartyNourishAction(PlayerbotAI* ai) : HealPartyMemberAction(ai, "nourish", 25.0f, HealingManaEfficiency::LOW) {}
};
class CastDruidRemoveCurseOnPartyAction : public CurePartyMemberAction

View File

@@ -5,83 +5,122 @@
#include "ConserveManaStrategy.h"
#include "GenericSpellActions.h"
#include "LastSpellCastValue.h"
#include "PlayerbotAIConfig.h"
#include "Playerbots.h"
float ConserveManaMultiplier::GetValue(Action* action)
// float ConserveManaMultiplier::GetValue(Action* action)
// {
// if (!action)
// return 1.0f;
// uint8 health = AI_VALUE2(uint8, "health", "self target");
// uint8 targetHealth = AI_VALUE2(uint8, "health", "current target");
// uint8 mana = AI_VALUE2(uint8, "mana", "self target");
// bool hasMana = AI_VALUE2(bool, "has mana", "self target");
// bool mediumMana = hasMana && mana < sPlayerbotAIConfig->mediumMana;
// if (health < sPlayerbotAIConfig->lowHealth)
// return 1.0f;
// Unit* target = AI_VALUE(Unit*, "current target");
// if (action->GetTarget() != target)
// return 1.0f;
// CastSpellAction* spellAction = dynamic_cast<CastSpellAction*>(action);
// if (!spellAction)
// return 1.0f;
// std::string const spell = spellAction->getName();
// uint32 spellId = AI_VALUE2(uint32, "spell id", spell);
// SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
// if (!spellInfo || spellInfo->PowerType != POWER_MANA)
// return 1.0f;
// if (mediumMana && dynamic_cast<CastBuffSpellAction*>(action))
// return 0.0f;
// if (target && ((int)target->getLevel() - (int)bot->getLevel()) >= 0)
// return 1.0f;
// return 1.0f;
// }
// float SaveManaMultiplier::GetValue(Action* action)
// {
// if (!action)
// return 1.0f;
// if (action->GetTarget() != AI_VALUE(Unit*, "current target"))
// return 1.0f;
// double saveLevel = AI_VALUE(double, "mana save level");
// if (saveLevel <= 1.0)
// return 1.0f;
// CastSpellAction* spellAction = dynamic_cast<CastSpellAction*>(action);
// if (!spellAction)
// return 1.0f;
// std::string const spell = spellAction->getName();
// uint32 spellId = AI_VALUE2(uint32, "spell id", spell);
// SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
// if (!spellInfo || spellInfo->PowerType != POWER_MANA)
// return 1.0f;
// int32 cost = spellInfo->ManaCost;
// if (!cost)
// return 1.0f;
// time_t lastCastTime = AI_VALUE2(time_t, "last spell cast time", spell);
// if (!lastCastTime)
// return 1.0f;
// time_t elapsed = time(nullptr) - lastCastTime;
// if ((double)elapsed < 10 * saveLevel)
// return 0.0f;
// return 1.0f;
// }
// void ConserveManaStrategy::InitMultipliers(std::vector<Multiplier*>& multipliers)
// {
// multipliers.push_back(new ConserveManaMultiplier(botAI));
// }
float HealerAutoSaveManaMultiplier::GetValue(Action* action)
{
if (!action)
uint8 mana = bot->GetPowerPct(Powers::POWER_MANA);
if (mana > sPlayerbotAIConfig->saveManaThreshold)
return 1.0f;
CastHealingSpellAction* healingAction = dynamic_cast<CastHealingSpellAction*>(action);
if (!healingAction)
return 1.0f;
uint8 health = AI_VALUE2(uint8, "health", "self target");
uint8 targetHealth = AI_VALUE2(uint8, "health", "current target");
uint8 mana = AI_VALUE2(uint8, "mana", "self target");
bool hasMana = AI_VALUE2(bool, "has mana", "self target");
bool mediumMana = hasMana && mana < sPlayerbotAIConfig->mediumMana;
if (health < sPlayerbotAIConfig->lowHealth)
Unit* target = healingAction->GetTarget();
if (!target)
return 1.0f;
Unit* target = AI_VALUE(Unit*, "current target");
if (action->GetTarget() != target)
return 1.0f;
CastSpellAction* spellAction = dynamic_cast<CastSpellAction*>(action);
if (!spellAction)
return 1.0f;
std::string const spell = spellAction->getName();
uint32 spellId = AI_VALUE2(uint32, "spell id", spell);
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
if (!spellInfo || spellInfo->PowerType != POWER_MANA)
return 1.0f;
if (mediumMana && dynamic_cast<CastBuffSpellAction*>(action))
bool isTank = target->ToPlayer() ? botAI->IsTank(target->ToPlayer()) : false;
uint8 health = target->GetHealthPct();
HealingManaEfficiency manaEfficiency = healingAction->manaEfficiency;
uint8 estAmount = healingAction->estAmount;
uint8 lossAmount = 100 - health;
if (isTank) {
estAmount /= 1.5; // tanks have more health
if (health >= sPlayerbotAIConfig->mediumHealth && (lossAmount < estAmount || manaEfficiency <= HealingManaEfficiency::MEDIUM))
return 0.0f;
if (target && ((int)target->getLevel() - (int)bot->getLevel()) >= 0)
return 1.0f;
return 1.0f;
}
float SaveManaMultiplier::GetValue(Action* action)
{
if (!action)
return 1.0f;
if (action->GetTarget() != AI_VALUE(Unit*, "current target"))
return 1.0f;
double saveLevel = AI_VALUE(double, "mana save level");
if (saveLevel <= 1.0)
return 1.0f;
CastSpellAction* spellAction = dynamic_cast<CastSpellAction*>(action);
if (!spellAction)
return 1.0f;
std::string const spell = spellAction->getName();
uint32 spellId = AI_VALUE2(uint32, "spell id", spell);
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
if (!spellInfo || spellInfo->PowerType != POWER_MANA)
return 1.0f;
int32 cost = spellInfo->ManaCost;
if (!cost)
return 1.0f;
time_t lastCastTime = AI_VALUE2(time_t, "last spell cast time", spell);
if (!lastCastTime)
return 1.0f;
time_t elapsed = time(nullptr) - lastCastTime;
if ((double)elapsed < 10 * saveLevel)
if (health >= sPlayerbotAIConfig->lowHealth && (lossAmount < estAmount || manaEfficiency <= HealingManaEfficiency::LOW))
return 0.0f;
} else {
if (health >= sPlayerbotAIConfig->mediumHealth && (lossAmount < estAmount || manaEfficiency <= HealingManaEfficiency::MEDIUM))
return 0.0f;
if (lossAmount < estAmount || manaEfficiency <= HealingManaEfficiency::LOW)
return 0.0f;
}
return 1.0f;
}
void ConserveManaStrategy::InitMultipliers(std::vector<Multiplier*>& multipliers)
void HealerAutoSaveManaStrategy::InitMultipliers(std::vector<Multiplier*>& multipliers)
{
multipliers.push_back(new ConserveManaMultiplier(botAI));
multipliers.push_back(new HealerAutoSaveManaMultiplier(botAI));
}

View File

@@ -9,29 +9,57 @@
class PlayerbotAI;
class ConserveManaMultiplier : public Multiplier
// Yunfan: deprecate old save mana method.
// class ConserveManaMultiplier : public Multiplier
// {
// public:
// ConserveManaMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "conserve mana") { }
// float GetValue(Action* action) override;
// };
// class SaveManaMultiplier : public Multiplier
// {
// public:
// SaveManaMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "save mana") { }
// float GetValue(Action* action) override;
// };
// class ConserveManaStrategy : public Strategy
// {
// public:
// ConserveManaStrategy(PlayerbotAI* botAI) : Strategy(botAI) { }
// void InitMultipliers(std::vector<Multiplier*>& multipliers) override;
// std::string const getName() override { return "conserve mana"; }
// };
// class HealerSaveManaStrategy : public Strategy
// {
// public:
// HealerSaveManaStrategy(PlayerbotAI* botAI) : Strategy(botAI) { }
// void InitMultipliers(std::vector<Multiplier*>& multipliers) override;
// std::string const getName() override { return "healer save mana"; }
// };
class HealerAutoSaveManaMultiplier : public Multiplier
{
public:
ConserveManaMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "conserve mana") { }
HealerAutoSaveManaMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "auto save mana") { }
float GetValue(Action* action) override;
};
class SaveManaMultiplier : public Multiplier
class HealerAutoSaveManaStrategy : public Strategy
{
public:
SaveManaMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "save mana") { }
float GetValue(Action* action) override;
};
class ConserveManaStrategy : public Strategy
{
public:
ConserveManaStrategy(PlayerbotAI* botAI) : Strategy(botAI) { }
HealerAutoSaveManaStrategy(PlayerbotAI* botAI) : Strategy(botAI) { }
void InitMultipliers(std::vector<Multiplier*>& multipliers) override;
std::string const getName() override { return "conserve mana"; }
std::string const getName() override { return "auto save mana"; }
};
#endif

View File

@@ -39,7 +39,6 @@ BUFF_ACTION(CastCrusaderAuraAction, "crusader aura");
BUFF_ACTION(CastSanctityAuraAction, "sanctity aura");
SPELL_ACTION(CastHolyShockAction, "holy shock");
HEAL_PARTY_ACTION(CastHolyShockOnPartyAction, "holy shock");
// consecration
MELEE_ACTION(CastConsecrationAction, "consecration");
@@ -168,10 +167,16 @@ class CastHolyLightAction : public CastHealingSpellAction
CastHolyLightAction(PlayerbotAI* botAI) : CastHealingSpellAction(botAI, "holy light") { }
};
class CastHolyShockOnPartyAction : public HealPartyMemberAction
{
public:
CastHolyShockOnPartyAction(PlayerbotAI* botAI) : HealPartyMemberAction(botAI, "holy shock", 25.0f, HealingManaEfficiency::MEDIUM) { }
};
class CastHolyLightOnPartyAction : public HealPartyMemberAction
{
public:
CastHolyLightOnPartyAction(PlayerbotAI* botAI) : HealPartyMemberAction(botAI, "holy light") { }
CastHolyLightOnPartyAction(PlayerbotAI* botAI) : HealPartyMemberAction(botAI, "holy light", 50.0f, HealingManaEfficiency::HIGH) { }
};
class CastFlashOfLightAction : public CastHealingSpellAction
@@ -183,7 +188,7 @@ class CastFlashOfLightAction : public CastHealingSpellAction
class CastFlashOfLightOnPartyAction : public HealPartyMemberAction
{
public:
CastFlashOfLightOnPartyAction(PlayerbotAI* botAI) : HealPartyMemberAction(botAI, "flash of light") { }
CastFlashOfLightOnPartyAction(PlayerbotAI* botAI) : HealPartyMemberAction(botAI, "flash of light", 15.0f, HealingManaEfficiency::LOW) { }
};
class CastLayOnHandsAction : public CastHealingSpellAction

View File

@@ -39,12 +39,12 @@ Unit* CastPowerWordShieldOnAlmostFullHealthBelow::GetTarget()
if (player->GetDistance2d(bot) > sPlayerbotAIConfig->spellDistance) {
continue;
}
if (botAI->HasAnyAuraOf(player, "weakened soul", "power word: shield", NULL)) {
if (botAI->HasAnyAuraOf(player, "weakened soul", "power word: shield", nullptr)) {
continue;
}
return player;
}
return NULL;
return nullptr;
}
bool CastPowerWordShieldOnAlmostFullHealthBelow::isUseful()
@@ -64,7 +64,7 @@ bool CastPowerWordShieldOnAlmostFullHealthBelow::isUseful()
if (player->GetDistance2d(bot) > sPlayerbotAIConfig->spellDistance) {
continue;
}
if (botAI->HasAnyAuraOf(player, "weakened soul", "power word: shield", NULL)) {
if (botAI->HasAnyAuraOf(player, "weakened soul", "power word: shield", nullptr)) {
continue;
}
return true;

View File

@@ -6,6 +6,7 @@
#define _PLAYERBOT_PRIESTACTIONS_H
#include "GenericSpellActions.h"
#include "PlayerbotAIConfig.h"
#include "Playerbots.h"
class PlayerbotAI;
@@ -15,7 +16,7 @@ BUFF_ACTION(CastPowerWordFortitudeAction, "power word: fortitude");
BUFF_PARTY_ACTION(CastPowerWordFortitudeOnPartyAction, "power word: fortitude");
BUFF_PARTY_ACTION(CastPrayerOfFortitudeOnPartyAction, "prayer of fortitude");
BUFF_ACTION(CastPowerWordShieldAction, "power word: shield");
HEAL_PARTY_ACTION(CastPowerWordShieldOnPartyAction, "power word: shield");
BUFF_ACTION(CastInnerFireAction, "inner fire");
CURE_ACTION(CastDispelMagicAction, "dispel magic");
CURE_PARTY_ACTION(CastDispelMagicOnPartyAction, "dispel magic", DISPEL_MAGIC);
@@ -39,22 +40,21 @@ PROTECT_ACTION(CastPainSuppressionProtectAction, "pain suppression");
// holy
HEAL_ACTION(CastLesserHealAction, "lesser heal");
HEAL_PARTY_ACTION(CastLesserHealOnPartyAction, "lesser heal");
HEAL_ACTION(CastHealAction, "heal");
HEAL_PARTY_ACTION(CastHealOnPartyAction, "heal");
HEAL_ACTION(CastGreaterHealAction, "greater heal");
HEAL_PARTY_ACTION(CastGreaterHealOnPartyAction, "greater heal");
HEAL_ACTION(CastFlashHealAction, "flash heal");
HEAL_PARTY_ACTION(CastFlashHealOnPartyAction, "flash heal");
HEAL_ACTION(CastRenewAction, "renew");
HEAL_PARTY_ACTION(CastRenewOnPartyAction, "renew");
// holy 2.4.3
HEAL_PARTY_ACTION(CastPrayerOfMendingAction, "prayer of mending");
HEAL_PARTY_ACTION(CastBindingHealAction, "binding heal");
HEAL_PARTY_ACTION(CastPrayerOfHealingAction, "prayer of healing");
AOE_HEAL_ACTION(CastLightwellAction, "lightwell");
AOE_HEAL_ACTION(CastCircleOfHealingAction, "circle of healing");
HEAL_PARTY_ACTION(CastLesserHealOnPartyAction, "lesser heal", 50.0f, HealingManaEfficiency::MEDIUM);
HEAL_PARTY_ACTION(CastHealOnPartyAction, "heal", 50.0f, HealingManaEfficiency::MEDIUM);
HEAL_PARTY_ACTION(CastGreaterHealOnPartyAction, "greater heal", 50.0f, HealingManaEfficiency::MEDIUM);
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(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(CastLightwellAction, "lightwell", 15.0f, HealingManaEfficiency::MEDIUM);
SPELL_ACTION(CastSmiteAction, "smite");
SPELL_ACTION(CastHolyNovaAction, "holy nova");
@@ -126,7 +126,7 @@ public:
class CastPenanceOnPartyAction : public HealPartyMemberAction
{
public:
CastPenanceOnPartyAction(PlayerbotAI* ai) : HealPartyMemberAction(ai, "penance") {}
CastPenanceOnPartyAction(PlayerbotAI* ai) : HealPartyMemberAction(ai, "penance", 25.0f, HealingManaEfficiency::HIGH) {}
};
class CastHymnOfHopeAction : public CastSpellAction
@@ -152,7 +152,7 @@ public:
class CastPowerWordShieldOnAlmostFullHealthBelow : public HealPartyMemberAction {
public:
CastPowerWordShieldOnAlmostFullHealthBelow(PlayerbotAI* ai) : HealPartyMemberAction(ai, "power word: shield") {}
CastPowerWordShieldOnAlmostFullHealthBelow(PlayerbotAI* ai) : HealPartyMemberAction(ai, "power word: shield", 15.0f, HealingManaEfficiency::HIGH) {}
bool isUseful() override;
Unit* GetTarget() override;
};

View File

@@ -18,7 +18,6 @@ class GenericShamanStrategyActionNodeFactory : public NamedObjectFactory<ActionN
creators["lesser healing wave on party"] = &lesser_healing_wave_on_party;
creators["chain heal"] = &chain_heal;
creators["riptide"] = &riptide;
creators["chain heal on party"] = &chain_heal_on_party;
creators["riptide on party"] = &riptide_on_party;
creators["earth shock"] = &earth_shock;
}
@@ -88,14 +87,6 @@ class GenericShamanStrategyActionNodeFactory : public NamedObjectFactory<ActionN
/*C*/ nullptr);
}
static ActionNode* chain_heal_on_party([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode ("chain heal on party",
/*P*/ nullptr,
/*A*/ NextAction::array(0, new NextAction("lesser healing wave on party"), nullptr),
/*C*/ nullptr);
}
static ActionNode* riptide_on_party([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode ("riptide on party",

View File

@@ -49,19 +49,19 @@ void HealShamanStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
triggers.push_back(new TriggerNode(
"party member critical health",
NextAction::array(0, new NextAction("riptide on party", 24.0f), new NextAction("healing wave on party", 23.0f), NULL)));
NextAction::array(0, new NextAction("riptide on party", 24.0f), new NextAction("lesser healing wave on party", 23.0f), nullptr)));
triggers.push_back(new TriggerNode(
"party member low health",
NextAction::array(0, new NextAction("riptide on party", 18.0f), new NextAction("healing wave on party", 17.0f), NULL)));
NextAction::array(0, new NextAction("riptide on party", 18.0f), new NextAction("lesser healing wave on party", 17.0f), nullptr)));
triggers.push_back(new TriggerNode(
"party member medium health",
NextAction::array(0, new NextAction("riptide on party", 15.0f), new NextAction("lesser healing wave on party", 14.0f), NULL)));
NextAction::array(0, new NextAction("riptide on party", 15.0f), new NextAction("lesser healing wave on party", 14.0f), nullptr)));
triggers.push_back(new TriggerNode(
"party member almost full health",
NextAction::array(0, new NextAction("riptide on party", 12.0f), new NextAction("lesser healing wave on party", 11.0f), NULL)));
NextAction::array(0, new NextAction("riptide on party", 12.0f), nullptr)));
triggers.push_back(new TriggerNode(
"party member cleanse spirit poison",
@@ -85,9 +85,9 @@ void HealShamanStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
// "no fire totem",
// NextAction::array(0, new NextAction("flametongue totem", 10.0f), NULL)));
triggers.push_back(new TriggerNode(
"no water totem",
NextAction::array(0, new NextAction("healing stream totem", 13.0f), NULL)));
// triggers.push_back(new TriggerNode(
// "no water totem",
// NextAction::array(0, new NextAction("healing stream totem", 13.0f), NULL)));
triggers.push_back(new TriggerNode(
"earth shield on main tank",

View File

@@ -21,7 +21,7 @@ class CastLesserHealingWaveAction : public CastHealingSpellAction
class CastLesserHealingWaveOnPartyAction : public HealPartyMemberAction
{
public:
CastLesserHealingWaveOnPartyAction(PlayerbotAI* botAI) : HealPartyMemberAction(botAI, "lesser healing wave") { }
CastLesserHealingWaveOnPartyAction(PlayerbotAI* botAI) : HealPartyMemberAction(botAI, "lesser healing wave", 25.0f, HealingManaEfficiency::LOW) { }
};
class CastHealingWaveAction : public CastHealingSpellAction
@@ -33,13 +33,13 @@ class CastHealingWaveAction : public CastHealingSpellAction
class CastHealingWaveOnPartyAction : public HealPartyMemberAction
{
public:
CastHealingWaveOnPartyAction(PlayerbotAI* botAI) : HealPartyMemberAction(botAI, "healing wave") { }
CastHealingWaveOnPartyAction(PlayerbotAI* botAI) : HealPartyMemberAction(botAI, "healing wave", 50.0f, HealingManaEfficiency::MEDIUM) { }
};
class CastChainHealAction : public CastAoeHealSpellAction
{
public:
CastChainHealAction(PlayerbotAI* botAI) : CastAoeHealSpellAction(botAI, "chain heal") { }
CastChainHealAction(PlayerbotAI* botAI) : CastAoeHealSpellAction(botAI, "chain heal", 15.0f, HealingManaEfficiency::HIGH) { }
};
class CastRiptideAction : public CastHealingSpellAction
@@ -51,7 +51,7 @@ class CastRiptideAction : public CastHealingSpellAction
class CastRiptideOnPartyAction : public HealPartyMemberAction
{
public:
CastRiptideOnPartyAction(PlayerbotAI* botAI) : HealPartyMemberAction(botAI, "riptide") { }
CastRiptideOnPartyAction(PlayerbotAI* botAI) : HealPartyMemberAction(botAI, "riptide", 15.0f, HealingManaEfficiency::VERY_HIGH) { }
};
class CastEarthShieldAction : public CastBuffSpellAction
@@ -147,7 +147,7 @@ class CastStrengthOfEarthTotemAction : public CastTotemAction
class CastManaSpringTotemAction : public CastTotemAction
{
public:
CastManaSpringTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "mana spring totem", "mana spring", 20.0f) { }
CastManaSpringTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "mana spring totem", "mana spring", 0.0f) { }
bool isUseful() override;
};

View File

@@ -16,19 +16,19 @@ void ShamanNonCombatStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
triggers.push_back(new TriggerNode("water walking on party", NextAction::array(0, new NextAction("water walking on party", 11.0f), nullptr)));
triggers.push_back(new TriggerNode(
"party member critical health",
NextAction::array(0, new NextAction("healing wave on party", 27.0f), NULL)));
NextAction::array(0, new NextAction("riptide on party", 31.0f), new NextAction("healing wave on party", 30.0f), NULL)));
triggers.push_back(new TriggerNode(
"party member low health",
NextAction::array(0, new NextAction("healing wave on party", 26.0f), NULL)));
NextAction::array(0, new NextAction("riptide on party", 29.0f), new NextAction("healing wave on party", 28.0f), NULL)));
triggers.push_back(new TriggerNode(
"party member medium health",
NextAction::array(0, new NextAction("healing wave on party", 25.0f), NULL)));
NextAction::array(0, new NextAction("riptide on party", 27.0f), new NextAction("healing wave on party", 26.0f), NULL)));
triggers.push_back(new TriggerNode(
"party member almost full health",
NextAction::array(0, new NextAction("lesser healing wave on party", 24.0f), NULL)));
NextAction::array(0, new NextAction("riptide on party", 25.0f), new NextAction("lesser healing wave on party", 24.0f), NULL)));
triggers.push_back(new TriggerNode(
"medium aoe heal",

View File

@@ -91,7 +91,7 @@ class CasterFindTargetSmartStrategy : public FindTargetStrategy
return true;
}
int32_t level = GetIntervalLevel(new_unit);
if (level % 10 == 2 || level % 10 == 0) {
if (level % 10 == 2 || level % 10 == 1) {
return new_time < old_time;
}
// dont switch targets when all of them with low health
@@ -110,10 +110,10 @@ class CasterFindTargetSmartStrategy : public FindTargetStrategy
float attackRange = botAI->IsRanged(botAI->GetBot()) ? sPlayerbotAIConfig->spellDistance : sPlayerbotAIConfig->meleeDistance;
attackRange += 5.0f;
int level = dis < attackRange ? 10 : 0;
if (time >= 5 && time <= 20) {
if (time >= 3 && time <= 20) {
return level + 2;
}
if (time < 5) {
if (time > 20) {
return level + 1;
}
return level;