Auto save mana strategy

This commit is contained in:
Yunfan Li
2024-03-23 18:11:46 +08:00
parent 68fdf57c3c
commit 5f31941820
18 changed files with 242 additions and 141 deletions

View File

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

View File

@@ -6,6 +6,7 @@
#include "BattlegroundMgr.h" #include "BattlegroundMgr.h"
#include "Item.h" #include "Item.h"
#include "PlayerbotAI.h" #include "PlayerbotAI.h"
#include "PlayerbotAIConfig.h"
#include "Playerbots.h" #include "Playerbots.h"
#include "Engine.h" #include "Engine.h"
#include "Group.h" #include "Group.h"
@@ -273,8 +274,9 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
{ {
engine->addStrategies("dps", "shadow debuff", "shadow aoe", "threat", nullptr); engine->addStrategies("dps", "shadow debuff", "shadow aoe", "threat", nullptr);
} }
else else {
engine->addStrategies("heal", "threat", nullptr); engine->addStrategies("heal", "threat", nullptr);
}
engine->addStrategies("dps assist", "cure", nullptr); engine->addStrategies("dps assist", "cure", nullptr);
break; break;
@@ -362,6 +364,9 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
engine->addStrategy("boost"); engine->addStrategy("boost");
engine->addStrategy("dps assist"); engine->addStrategy("dps assist");
engine->removeStrategy("threat"); engine->removeStrategy("threat");
if (sPlayerbotAIConfig->autoSaveMana) {
engine->addStrategy("auto save mana");
}
// engine- // engine-
switch (player->getClass()) { switch (player->getClass()) {
case CLASS_PRIEST: { case CLASS_PRIEST: {
@@ -426,7 +431,7 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
engine->addStrategy("arena"); 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("custom::say");
engine->removeStrategy("flee"); engine->removeStrategy("flee");
engine->removeStrategy("threat"); engine->removeStrategy("threat");
@@ -603,6 +608,9 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const
nonCombatEngine->addStrategy("pvp"); nonCombatEngine->addStrategy("pvp");
nonCombatEngine->ChangeStrategy(sPlayerbotAIConfig->nonCombatStrategies); nonCombatEngine->ChangeStrategy(sPlayerbotAIConfig->nonCombatStrategies);
} }
if (sPlayerbotAIConfig->autoSaveMana) {
nonCombatEngine->addStrategy("auto save mana");
}
} }
} }
} }

View File

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

View File

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

View File

@@ -121,7 +121,7 @@ void PlayerbotFactory::Init()
// continue; // continue;
enchantSpellIdCache.push_back(id); 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()); LOG_INFO("playerbots", "Loading {} enchantment spells", enchantSpellIdCache.size());

View File

@@ -302,14 +302,14 @@ class clazz : public CastHealingSpellAction \
bool isUseful() override { return useful; } \ bool isUseful() override { return useful; } \
} }
#define HEAL_PARTY_ACTION(clazz, spell) \ #define HEAL_PARTY_ACTION(clazz, spell, estAmount, manaEfficiency) \
class clazz : public HealPartyMemberAction \ class clazz : public HealPartyMemberAction \
{ \ { \
public: \ 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 \ class clazz : public CastAoeHealSpellAction \
{ \ { \
public: \ public: \

View File

@@ -58,7 +58,8 @@ class StrategyContext : public NamedObjectContext<Strategy>
creators["gather"] = &StrategyContext::gather; creators["gather"] = &StrategyContext::gather;
creators["emote"] = &StrategyContext::emote; creators["emote"] = &StrategyContext::emote;
creators["passive"] = &StrategyContext::passive; 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["food"] = &StrategyContext::food;
creators["chat"] = &StrategyContext::chat; creators["chat"] = &StrategyContext::chat;
creators["default"] = &StrategyContext::world_packet; 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* gather(PlayerbotAI* botAI) { return new GatherStrategy(botAI); }
static Strategy* emote(PlayerbotAI* botAI) { return new EmoteStrategy(botAI); } static Strategy* emote(PlayerbotAI* botAI) { return new EmoteStrategy(botAI); }
static Strategy* passive(PlayerbotAI* botAI) { return new PassiveStrategy(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* food(PlayerbotAI* botAI) { return new UseFoodStrategy(botAI); }
static Strategy* chat(PlayerbotAI* botAI) { return new ChatCommandHandlerStrategy(botAI); } static Strategy* chat(PlayerbotAI* botAI) { return new ChatCommandHandlerStrategy(botAI); }
static Strategy* world_packet(PlayerbotAI* botAI) { return new WorldPacketHandlerStrategy(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); 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"); range = botAI->GetRange("heal");
} }

View File

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

View File

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

View File

@@ -5,83 +5,122 @@
#include "ConserveManaStrategy.h" #include "ConserveManaStrategy.h"
#include "GenericSpellActions.h" #include "GenericSpellActions.h"
#include "LastSpellCastValue.h" #include "LastSpellCastValue.h"
#include "PlayerbotAIConfig.h"
#include "Playerbots.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; return 1.0f;
uint8 health = AI_VALUE2(uint8, "health", "self target"); Unit* target = healingAction->GetTarget();
uint8 targetHealth = AI_VALUE2(uint8, "health", "current target"); if (!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; return 1.0f;
bool isTank = target->ToPlayer() ? botAI->IsTank(target->ToPlayer()) : false;
Unit* target = AI_VALUE(Unit*, "current target"); uint8 health = target->GetHealthPct();
if (action->GetTarget() != target) HealingManaEfficiency manaEfficiency = healingAction->manaEfficiency;
return 1.0f; uint8 estAmount = healingAction->estAmount;
uint8 lossAmount = 100 - health;
CastSpellAction* spellAction = dynamic_cast<CastSpellAction*>(action); if (isTank) {
if (!spellAction) estAmount /= 1.5; // tanks have more health
return 1.0f; if (health >= sPlayerbotAIConfig->mediumHealth && (lossAmount < estAmount || manaEfficiency <= HealingManaEfficiency::MEDIUM))
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; return 0.0f;
if (health >= sPlayerbotAIConfig->lowHealth && (lossAmount < estAmount || manaEfficiency <= HealingManaEfficiency::LOW))
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 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; 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 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: public:
ConserveManaMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "conserve mana") { } HealerAutoSaveManaMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "auto save mana") { }
float GetValue(Action* action) override; float GetValue(Action* action) override;
}; };
class SaveManaMultiplier : public Multiplier class HealerAutoSaveManaStrategy : public Strategy
{ {
public: public:
SaveManaMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "save mana") { } HealerAutoSaveManaStrategy(PlayerbotAI* botAI) : Strategy(botAI) { }
float GetValue(Action* action) override;
};
class ConserveManaStrategy : public Strategy
{
public:
ConserveManaStrategy(PlayerbotAI* botAI) : Strategy(botAI) { }
void InitMultipliers(std::vector<Multiplier*>& multipliers) override; 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 #endif

View File

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

View File

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

View File

@@ -6,6 +6,7 @@
#define _PLAYERBOT_PRIESTACTIONS_H #define _PLAYERBOT_PRIESTACTIONS_H
#include "GenericSpellActions.h" #include "GenericSpellActions.h"
#include "PlayerbotAIConfig.h"
#include "Playerbots.h" #include "Playerbots.h"
class PlayerbotAI; class PlayerbotAI;
@@ -15,7 +16,7 @@ BUFF_ACTION(CastPowerWordFortitudeAction, "power word: fortitude");
BUFF_PARTY_ACTION(CastPowerWordFortitudeOnPartyAction, "power word: fortitude"); BUFF_PARTY_ACTION(CastPowerWordFortitudeOnPartyAction, "power word: fortitude");
BUFF_PARTY_ACTION(CastPrayerOfFortitudeOnPartyAction, "prayer of fortitude"); BUFF_PARTY_ACTION(CastPrayerOfFortitudeOnPartyAction, "prayer of fortitude");
BUFF_ACTION(CastPowerWordShieldAction, "power word: shield"); BUFF_ACTION(CastPowerWordShieldAction, "power word: shield");
HEAL_PARTY_ACTION(CastPowerWordShieldOnPartyAction, "power word: shield");
BUFF_ACTION(CastInnerFireAction, "inner fire"); BUFF_ACTION(CastInnerFireAction, "inner fire");
CURE_ACTION(CastDispelMagicAction, "dispel magic"); CURE_ACTION(CastDispelMagicAction, "dispel magic");
CURE_PARTY_ACTION(CastDispelMagicOnPartyAction, "dispel magic", DISPEL_MAGIC); CURE_PARTY_ACTION(CastDispelMagicOnPartyAction, "dispel magic", DISPEL_MAGIC);
@@ -39,22 +40,21 @@ PROTECT_ACTION(CastPainSuppressionProtectAction, "pain suppression");
// holy // holy
HEAL_ACTION(CastLesserHealAction, "lesser heal"); HEAL_ACTION(CastLesserHealAction, "lesser heal");
HEAL_PARTY_ACTION(CastLesserHealOnPartyAction, "lesser heal");
HEAL_ACTION(CastHealAction, "heal"); HEAL_ACTION(CastHealAction, "heal");
HEAL_PARTY_ACTION(CastHealOnPartyAction, "heal");
HEAL_ACTION(CastGreaterHealAction, "greater heal"); HEAL_ACTION(CastGreaterHealAction, "greater heal");
HEAL_PARTY_ACTION(CastGreaterHealOnPartyAction, "greater heal");
HEAL_ACTION(CastFlashHealAction, "flash heal"); HEAL_ACTION(CastFlashHealAction, "flash heal");
HEAL_PARTY_ACTION(CastFlashHealOnPartyAction, "flash heal");
HEAL_ACTION(CastRenewAction, "renew"); HEAL_ACTION(CastRenewAction, "renew");
HEAL_PARTY_ACTION(CastRenewOnPartyAction, "renew"); HEAL_PARTY_ACTION(CastLesserHealOnPartyAction, "lesser heal", 50.0f, HealingManaEfficiency::MEDIUM);
// holy 2.4.3 HEAL_PARTY_ACTION(CastHealOnPartyAction, "heal", 50.0f, HealingManaEfficiency::MEDIUM);
HEAL_PARTY_ACTION(CastPrayerOfMendingAction, "prayer of mending"); HEAL_PARTY_ACTION(CastGreaterHealOnPartyAction, "greater heal", 50.0f, HealingManaEfficiency::MEDIUM);
HEAL_PARTY_ACTION(CastBindingHealAction, "binding heal"); 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(CastPrayerOfHealingAction, "prayer of healing"); HEAL_PARTY_ACTION(CastRenewOnPartyAction, "renew", 15.0f, HealingManaEfficiency::VERY_HIGH);
AOE_HEAL_ACTION(CastLightwellAction, "lightwell"); HEAL_PARTY_ACTION(CastPrayerOfMendingAction, "prayer of mending", 15.0f, HealingManaEfficiency::MEDIUM);
AOE_HEAL_ACTION(CastCircleOfHealingAction, "circle of healing"); 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(CastSmiteAction, "smite");
SPELL_ACTION(CastHolyNovaAction, "holy nova"); SPELL_ACTION(CastHolyNovaAction, "holy nova");
@@ -126,7 +126,7 @@ public:
class CastPenanceOnPartyAction : public HealPartyMemberAction class CastPenanceOnPartyAction : public HealPartyMemberAction
{ {
public: public:
CastPenanceOnPartyAction(PlayerbotAI* ai) : HealPartyMemberAction(ai, "penance") {} CastPenanceOnPartyAction(PlayerbotAI* ai) : HealPartyMemberAction(ai, "penance", 25.0f, HealingManaEfficiency::HIGH) {}
}; };
class CastHymnOfHopeAction : public CastSpellAction class CastHymnOfHopeAction : public CastSpellAction
@@ -152,7 +152,7 @@ public:
class CastPowerWordShieldOnAlmostFullHealthBelow : public HealPartyMemberAction { class CastPowerWordShieldOnAlmostFullHealthBelow : public HealPartyMemberAction {
public: public:
CastPowerWordShieldOnAlmostFullHealthBelow(PlayerbotAI* ai) : HealPartyMemberAction(ai, "power word: shield") {} CastPowerWordShieldOnAlmostFullHealthBelow(PlayerbotAI* ai) : HealPartyMemberAction(ai, "power word: shield", 15.0f, HealingManaEfficiency::HIGH) {}
bool isUseful() override; bool isUseful() override;
Unit* GetTarget() 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["lesser healing wave on party"] = &lesser_healing_wave_on_party;
creators["chain heal"] = &chain_heal; creators["chain heal"] = &chain_heal;
creators["riptide"] = &riptide; creators["riptide"] = &riptide;
creators["chain heal on party"] = &chain_heal_on_party;
creators["riptide on party"] = &riptide_on_party; creators["riptide on party"] = &riptide_on_party;
creators["earth shock"] = &earth_shock; creators["earth shock"] = &earth_shock;
} }
@@ -88,14 +87,6 @@ class GenericShamanStrategyActionNodeFactory : public NamedObjectFactory<ActionN
/*C*/ nullptr); /*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) static ActionNode* riptide_on_party([[maybe_unused]] PlayerbotAI* botAI)
{ {
return new ActionNode ("riptide on party", return new ActionNode ("riptide on party",

View File

@@ -21,7 +21,7 @@ class CastLesserHealingWaveAction : public CastHealingSpellAction
class CastLesserHealingWaveOnPartyAction : public HealPartyMemberAction class CastLesserHealingWaveOnPartyAction : public HealPartyMemberAction
{ {
public: 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 class CastHealingWaveAction : public CastHealingSpellAction
@@ -33,13 +33,13 @@ class CastHealingWaveAction : public CastHealingSpellAction
class CastHealingWaveOnPartyAction : public HealPartyMemberAction class CastHealingWaveOnPartyAction : public HealPartyMemberAction
{ {
public: public:
CastHealingWaveOnPartyAction(PlayerbotAI* botAI) : HealPartyMemberAction(botAI, "healing wave") { } CastHealingWaveOnPartyAction(PlayerbotAI* botAI) : HealPartyMemberAction(botAI, "healing wave", 50.0f, HealingManaEfficiency::MEDIUM) { }
}; };
class CastChainHealAction : public CastAoeHealSpellAction class CastChainHealAction : public CastAoeHealSpellAction
{ {
public: public:
CastChainHealAction(PlayerbotAI* botAI) : CastAoeHealSpellAction(botAI, "chain heal") { } CastChainHealAction(PlayerbotAI* botAI) : CastAoeHealSpellAction(botAI, "chain heal", 15.0f, HealingManaEfficiency::HIGH) { }
}; };
class CastRiptideAction : public CastHealingSpellAction class CastRiptideAction : public CastHealingSpellAction
@@ -51,7 +51,7 @@ class CastRiptideAction : public CastHealingSpellAction
class CastRiptideOnPartyAction : public HealPartyMemberAction class CastRiptideOnPartyAction : public HealPartyMemberAction
{ {
public: public:
CastRiptideOnPartyAction(PlayerbotAI* botAI) : HealPartyMemberAction(botAI, "riptide") { } CastRiptideOnPartyAction(PlayerbotAI* botAI) : HealPartyMemberAction(botAI, "riptide", 15.0f, HealingManaEfficiency::VERY_HIGH) { }
}; };
class CastEarthShieldAction : public CastBuffSpellAction class CastEarthShieldAction : public CastBuffSpellAction

View File

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