mirror of
https://github.com/mod-playerbots/mod-playerbots.git
synced 2026-01-13 09:07:19 +00:00
Merge pull request #502 from liyunfan1223/druid-cat
Improve druid cat spec
This commit is contained in:
@@ -916,7 +916,7 @@ AiPlayerbot.PremadeSpecGlyph.7.0 = 41536,43385,41532,43386,44923,45776
|
|||||||
AiPlayerbot.PremadeSpecLink.7.0.60 = 4530001520213351102301351
|
AiPlayerbot.PremadeSpecLink.7.0.60 = 4530001520213351102301351
|
||||||
AiPlayerbot.PremadeSpecLink.7.0.80 = 3530001523213351322301351-005050031
|
AiPlayerbot.PremadeSpecLink.7.0.80 = 3530001523213351322301351-005050031
|
||||||
AiPlayerbot.PremadeSpecName.7.1 = enh pve
|
AiPlayerbot.PremadeSpecName.7.1 = enh pve
|
||||||
AiPlayerbot.PremadeSpecGlyph.7.1 = 41530,43385,41539,43386,44923,41540
|
AiPlayerbot.PremadeSpecGlyph.7.1 = 41542,43385,41539,43386,44923,45771
|
||||||
AiPlayerbot.PremadeSpecLink.7.1.60 = -30205033005001333031131131051
|
AiPlayerbot.PremadeSpecLink.7.1.60 = -30205033005001333031131131051
|
||||||
AiPlayerbot.PremadeSpecLink.7.1.80 = 053030052-30205033005021333031131131051
|
AiPlayerbot.PremadeSpecLink.7.1.80 = 053030052-30205033005021333031131131051
|
||||||
AiPlayerbot.PremadeSpecName.7.2 = resto pve
|
AiPlayerbot.PremadeSpecName.7.2 = resto pve
|
||||||
@@ -996,7 +996,7 @@ AiPlayerbot.PremadeSpecLink.11.2.60 = --230033312031501531050013051
|
|||||||
AiPlayerbot.PremadeSpecLink.11.2.80 = 05320001--230033312031512531153313051
|
AiPlayerbot.PremadeSpecLink.11.2.80 = 05320001--230033312031512531153313051
|
||||||
AiPlayerbot.PremadeSpecName.11.3 = cat pve
|
AiPlayerbot.PremadeSpecName.11.3 = cat pve
|
||||||
AiPlayerbot.PremadeSpecGlyph.11.3 = 40902,43331,40901,43335,44922,45604
|
AiPlayerbot.PremadeSpecGlyph.11.3 = 40902,43331,40901,43335,44922,45604
|
||||||
AiPlayerbot.PremadeSpecLink.11.3.60 = -553202032322010052100030310501
|
AiPlayerbot.PremadeSpecLink.11.3.60 = -552202032322010053100030310501
|
||||||
AiPlayerbot.PremadeSpecLink.11.3.80 = -553202032322010053100030310511-205503012
|
AiPlayerbot.PremadeSpecLink.11.3.80 = -553202032322010053100030310511-205503012
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -1183,11 +1183,12 @@ AiPlayerbot.RandomClassSpecIndex.9.2 = 2
|
|||||||
|
|
||||||
AiPlayerbot.RandomClassSpecProb.11.0 = 20
|
AiPlayerbot.RandomClassSpecProb.11.0 = 20
|
||||||
AiPlayerbot.RandomClassSpecIndex.11.0 = 0
|
AiPlayerbot.RandomClassSpecIndex.11.0 = 0
|
||||||
AiPlayerbot.RandomClassSpecProb.11.1 = 40
|
AiPlayerbot.RandomClassSpecProb.11.1 = 25
|
||||||
AiPlayerbot.RandomClassSpecIndex.11.1 = 1
|
AiPlayerbot.RandomClassSpecIndex.11.1 = 1
|
||||||
AiPlayerbot.RandomClassSpecProb.11.2 = 40
|
AiPlayerbot.RandomClassSpecProb.11.2 = 35
|
||||||
AiPlayerbot.RandomClassSpecIndex.11.2 = 2
|
AiPlayerbot.RandomClassSpecIndex.11.2 = 2
|
||||||
|
AiPlayerbot.RandomClassSpecProb.11.3 = 20
|
||||||
|
AiPlayerbot.RandomClassSpecIndex.11.3 = 3
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -71,7 +71,6 @@ uint8 AiFactory::GetPlayerSpecTab(Player* bot)
|
|||||||
max = tabs[i];
|
max = tabs[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return tab;
|
return tab;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -481,11 +480,11 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
|
|||||||
if ((player->getClass() == CLASS_DRUID && tab == 2) || (player->getClass() == CLASS_SHAMAN && tab == 2))
|
if ((player->getClass() == CLASS_DRUID && tab == 2) || (player->getClass() == CLASS_SHAMAN && tab == 2))
|
||||||
engine->addStrategiesNoInit("caster", "caster aoe", nullptr);
|
engine->addStrategiesNoInit("caster", "caster aoe", nullptr);
|
||||||
|
|
||||||
if (player->getClass() == CLASS_DRUID && tab == 1)
|
// if (player->getClass() == CLASS_DRUID && tab == 1)
|
||||||
engine->addStrategiesNoInit(/*"behind",*/ "dps", nullptr);
|
// engine->addStrategiesNoInit(/*"behind",*/ "dps", nullptr);
|
||||||
|
|
||||||
if (player->getClass() == CLASS_ROGUE)
|
// if (player->getClass() == CLASS_ROGUE)
|
||||||
engine->addStrategiesNoInit(/*"behind",*/ "stealth", nullptr);
|
// engine->addStrategiesNoInit(/*"behind",*/ "stealth", nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2001,6 +2001,10 @@ bool PlayerbotAI::IsDps(Player* player)
|
|||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (tab == DRUID_TAB_FERAL && !IsTank(player))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case CLASS_SHAMAN:
|
case CLASS_SHAMAN:
|
||||||
if (tab != SHAMAN_TAB_RESTORATION)
|
if (tab != SHAMAN_TAB_RESTORATION)
|
||||||
@@ -2795,8 +2799,8 @@ bool PlayerbotAI::CanCastSpell(uint32 spellid, Unit* target, bool checkHasSpell,
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint32 CastingTime = !spellInfo->IsChanneled() ? spellInfo->CalcCastTime(bot) : spellInfo->GetDuration();
|
uint32 CastingTime = !spellInfo->IsChanneled() ? spellInfo->CalcCastTime(bot) : spellInfo->GetDuration();
|
||||||
bool interruptOnMove = spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_MOVEMENT;
|
// bool interruptOnMove = spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_MOVEMENT;
|
||||||
if ((CastingTime || interruptOnMove) && bot->isMoving())
|
if ((CastingTime || spellInfo->IsAutoRepeatRangedSpell()) && bot->isMoving())
|
||||||
{
|
{
|
||||||
if (!sPlayerbotAIConfig->logInGroupOnly || (bot->GetGroup() && HasRealPlayerMaster()))
|
if (!sPlayerbotAIConfig->logInGroupOnly || (bot->GetGroup() && HasRealPlayerMaster()))
|
||||||
{
|
{
|
||||||
@@ -5177,6 +5181,32 @@ uint32 PlayerbotAI::GetBuffedCount(Player* player, std::string const spellname)
|
|||||||
return bcount;
|
return bcount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32 PlayerbotAI::GetNearGroupMemberCount(float dis)
|
||||||
|
{
|
||||||
|
int count = 1; // yourself
|
||||||
|
if (Group* group = bot->GetGroup())
|
||||||
|
{
|
||||||
|
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
|
||||||
|
{
|
||||||
|
Player* member = gref->GetSource();
|
||||||
|
if (member == bot) // calculated
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!member || !member->IsInWorld())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (member->GetMapId() != bot->GetMapId())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (member->GetExactDist(bot) > dis)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
bool PlayerbotAI::CanMove()
|
bool PlayerbotAI::CanMove()
|
||||||
{
|
{
|
||||||
// do not allow if not vehicle driver
|
// do not allow if not vehicle driver
|
||||||
|
|||||||
@@ -469,6 +469,7 @@ public:
|
|||||||
void ImbueItem(Item* item);
|
void ImbueItem(Item* item);
|
||||||
void EnchantItemT(uint32 spellid, uint8 slot);
|
void EnchantItemT(uint32 spellid, uint8 slot);
|
||||||
uint32 GetBuffedCount(Player* player, std::string const spellname);
|
uint32 GetBuffedCount(Player* player, std::string const spellname);
|
||||||
|
int32 GetNearGroupMemberCount(float dis = sPlayerbotAIConfig->sightDistance);
|
||||||
|
|
||||||
virtual bool CanCastSpell(std::string const name, Unit* target, Item* itemTarget = nullptr);
|
virtual bool CanCastSpell(std::string const name, Unit* target, Item* itemTarget = nullptr);
|
||||||
virtual bool CastSpell(std::string const name, Unit* target, Item* itemTarget = nullptr);
|
virtual bool CastSpell(std::string const name, Unit* target, Item* itemTarget = nullptr);
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
#include "RandomItemMgr.h"
|
#include "RandomItemMgr.h"
|
||||||
#include "RandomPlayerbotFactory.h"
|
#include "RandomPlayerbotFactory.h"
|
||||||
|
#include "RandomPlayerbotMgr.h"
|
||||||
#include "Talentspec.h"
|
#include "Talentspec.h"
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
@@ -329,15 +330,22 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
parsedSpecLinkOrder[cls][spec][level] = ParseTempTalentsOrder(cls, premadeSpecLink[cls][spec][level]);
|
parsedSpecLinkOrder[cls][spec][level] = ParseTempTalentsOrder(cls, premadeSpecLink[cls][spec][level]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (uint32 spec = 0; spec < 3; ++spec)
|
for (uint32 spec = 0; spec < MAX_SPECNO; ++spec)
|
||||||
{
|
{
|
||||||
std::ostringstream os;
|
std::ostringstream os;
|
||||||
os << "AiPlayerbot.RandomClassSpecProb." << cls << "." << spec;
|
os << "AiPlayerbot.RandomClassSpecProb." << cls << "." << spec;
|
||||||
randomClassSpecProb[cls][spec] = sConfigMgr->GetOption<uint32>(os.str().c_str(), 33);
|
uint32 def;
|
||||||
|
if (spec <= 1)
|
||||||
|
def = 33;
|
||||||
|
else if (spec == 2)
|
||||||
|
def = 34;
|
||||||
|
else
|
||||||
|
def = 0;
|
||||||
|
randomClassSpecProb[cls][spec] = sConfigMgr->GetOption<uint32>(os.str().c_str(), def, false);
|
||||||
os.str("");
|
os.str("");
|
||||||
os.clear();
|
os.clear();
|
||||||
os << "AiPlayerbot.RandomClassSpecIndex." << cls << "." << spec;
|
os << "AiPlayerbot.RandomClassSpecIndex." << cls << "." << spec;
|
||||||
randomClassSpecIndex[cls][spec] = sConfigMgr->GetOption<uint32>(os.str().c_str(), spec + 1);
|
randomClassSpecIndex[cls][spec] = sConfigMgr->GetOption<uint32>(os.str().c_str(), spec, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -475,6 +483,9 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
selfBotLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.SelfBotLevel", 1);
|
selfBotLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.SelfBotLevel", 1);
|
||||||
|
|
||||||
RandomPlayerbotFactory::CreateRandomBots();
|
RandomPlayerbotFactory::CreateRandomBots();
|
||||||
|
if (sPlayerbotAIConfig->addClassCommand)
|
||||||
|
sRandomPlayerbotMgr->PrepareAddclassCache();
|
||||||
|
|
||||||
if (World::IsStopped())
|
if (World::IsStopped())
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -162,8 +162,6 @@ RandomPlayerbotMgr::RandomPlayerbotMgr() : PlayerbotHolder(), processTicks(0)
|
|||||||
{
|
{
|
||||||
sPlayerbotCommandServer->Start();
|
sPlayerbotCommandServer->Start();
|
||||||
PrepareTeleportCache();
|
PrepareTeleportCache();
|
||||||
if (sPlayerbotAIConfig->addClassCommand)
|
|
||||||
PrepareAddclassCache();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BattlegroundData.clear();
|
BattlegroundData.clear();
|
||||||
|
|||||||
@@ -169,6 +169,7 @@ public:
|
|||||||
void setActivityPercentage(float percentage) { activityMod = percentage / 100.0f; }
|
void setActivityPercentage(float percentage) { activityMod = percentage / 100.0f; }
|
||||||
static uint8 GetTeamClassIdx(bool isAlliance, uint8 claz) { return isAlliance * 20 + claz; }
|
static uint8 GetTeamClassIdx(bool isAlliance, uint8 claz) { return isAlliance * 20 + claz; }
|
||||||
|
|
||||||
|
void PrepareAddclassCache();
|
||||||
std::map<uint8, std::vector<ObjectGuid>> addclassCache;
|
std::map<uint8, std::vector<ObjectGuid>> addclassCache;
|
||||||
protected:
|
protected:
|
||||||
void OnBotLoginInternal(Player* const bot) override;
|
void OnBotLoginInternal(Player* const bot) override;
|
||||||
@@ -193,7 +194,6 @@ private:
|
|||||||
void RandomTeleport(Player* bot, std::vector<WorldLocation>& locs, bool hearth = false);
|
void RandomTeleport(Player* bot, std::vector<WorldLocation>& locs, bool hearth = false);
|
||||||
uint32 GetZoneLevel(uint16 mapId, float teleX, float teleY, float teleZ);
|
uint32 GetZoneLevel(uint16 mapId, float teleX, float teleY, float teleZ);
|
||||||
void PrepareTeleportCache();
|
void PrepareTeleportCache();
|
||||||
void PrepareAddclassCache();
|
|
||||||
typedef void (RandomPlayerbotMgr::*ConsoleCommandHandler)(Player*);
|
typedef void (RandomPlayerbotMgr::*ConsoleCommandHandler)(Player*);
|
||||||
|
|
||||||
std::vector<Player*> players;
|
std::vector<Player*> players;
|
||||||
|
|||||||
@@ -878,14 +878,31 @@ void PlayerbotFactory::InitTalentsTree(bool increment /*false*/, bool use_templa
|
|||||||
uint32 total_tabs = tabs[0] + tabs[1] + tabs[2];
|
uint32 total_tabs = tabs[0] + tabs[1] + tabs[2];
|
||||||
if (increment && total_tabs != 0)
|
if (increment && total_tabs != 0)
|
||||||
{
|
{
|
||||||
|
/// @todo: match current talent with template
|
||||||
specTab = AiFactory::GetPlayerSpecTab(bot);
|
specTab = AiFactory::GetPlayerSpecTab(bot);
|
||||||
}
|
/// @todo: fix cat druid hardcode
|
||||||
|
if (bot->getClass() == CLASS_DRUID && specTab == DRUID_TAB_FERAL && bot->GetLevel() >= 20 && !bot->HasAura(16931))
|
||||||
|
specTab = 3;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
uint32 point = urand(0, 100);
|
uint32 point = urand(1, 100);
|
||||||
uint32 p1 = sPlayerbotAIConfig->randomClassSpecProb[cls][0];
|
uint32 currentP = 0;
|
||||||
uint32 p2 = p1 + sPlayerbotAIConfig->randomClassSpecProb[cls][1];
|
int i;
|
||||||
specTab = point < p1 ? 0 : (point < p2 ? 1 : 2);
|
for (i = 0; i < MAX_SPECNO; i++)
|
||||||
|
{
|
||||||
|
currentP += sPlayerbotAIConfig->randomClassSpecProb[cls][i];
|
||||||
|
if (point <= currentP)
|
||||||
|
{
|
||||||
|
specTab = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i == MAX_SPECNO)
|
||||||
|
{
|
||||||
|
specTab = 0;
|
||||||
|
LOG_ERROR("playerbots", "Fail to select spec num for bot {}! Set to 0.", bot->GetName());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (reset)
|
if (reset)
|
||||||
{
|
{
|
||||||
@@ -896,12 +913,13 @@ void PlayerbotFactory::InitTalentsTree(bool increment /*false*/, bool use_templa
|
|||||||
{
|
{
|
||||||
InitTalentsByTemplate(specTab);
|
InitTalentsByTemplate(specTab);
|
||||||
}
|
}
|
||||||
else
|
// always use template now
|
||||||
{
|
// else
|
||||||
InitTalents(specTab);
|
// {
|
||||||
if (bot->GetFreeTalentPoints())
|
// InitTalents(specTab);
|
||||||
InitTalents((specTab + 1) % 3);
|
// if (bot->GetFreeTalentPoints())
|
||||||
}
|
// InitTalents((specTab + 1) % 3);
|
||||||
|
// }
|
||||||
bot->SendTalentsInfoData(false);
|
bot->SendTalentsInfoData(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1433,7 +1451,7 @@ void Shuffle(std::vector<uint32>& items)
|
|||||||
void PlayerbotFactory::InitEquipment(bool incremental)
|
void PlayerbotFactory::InitEquipment(bool incremental)
|
||||||
{
|
{
|
||||||
std::unordered_map<uint8, std::vector<uint32>> items;
|
std::unordered_map<uint8, std::vector<uint32>> items;
|
||||||
int tab = AiFactory::GetPlayerSpecTab(bot);
|
// int tab = AiFactory::GetPlayerSpecTab(bot);
|
||||||
|
|
||||||
uint32 blevel = bot->GetLevel();
|
uint32 blevel = bot->GetLevel();
|
||||||
int32 delta = 2;
|
int32 delta = 2;
|
||||||
@@ -3062,6 +3080,9 @@ void PlayerbotFactory::InitGlyphs(bool increment)
|
|||||||
|
|
||||||
uint8 cls = bot->getClass();
|
uint8 cls = bot->getClass();
|
||||||
uint8 tab = AiFactory::GetPlayerSpecTab(bot);
|
uint8 tab = AiFactory::GetPlayerSpecTab(bot);
|
||||||
|
/// @todo: fix cat druid hardcode
|
||||||
|
if (bot->getClass() == CLASS_DRUID && tab == DRUID_TAB_FERAL && bot->GetLevel() >= 20 && !bot->HasAura(16931))
|
||||||
|
tab = 3;
|
||||||
std::list<uint32> glyphs;
|
std::list<uint32> glyphs;
|
||||||
ItemTemplateContainer const* itemTemplates = sObjectMgr->GetItemTemplateStore();
|
ItemTemplateContainer const* itemTemplates = sObjectMgr->GetItemTemplateStore();
|
||||||
for (ItemTemplateContainer::const_iterator i = itemTemplates->begin(); i != itemTemplates->end(); ++i)
|
for (ItemTemplateContainer::const_iterator i = itemTemplates->begin(); i != itemTemplates->end(); ++i)
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ void StatsWeightCalculator::GenerateBasicWeights(Player* player)
|
|||||||
stats_weights_[STATS_TYPE_HASTE] += 1.8f;
|
stats_weights_[STATS_TYPE_HASTE] += 1.8f;
|
||||||
stats_weights_[STATS_TYPE_RANGED_DPS] += 5.0f;
|
stats_weights_[STATS_TYPE_RANGED_DPS] += 5.0f;
|
||||||
}
|
}
|
||||||
else if ((cls == CLASS_ROGUE && tab == ROGUE_TAB_COMBAT) || (cls == CLASS_DRUID && tab == DRUID_TAB_FERAL && !PlayerbotAI::IsTank(player)))
|
else if (cls == CLASS_ROGUE && tab == ROGUE_TAB_COMBAT)
|
||||||
{
|
{
|
||||||
stats_weights_[STATS_TYPE_AGILITY] += 1.8f;
|
stats_weights_[STATS_TYPE_AGILITY] += 1.8f;
|
||||||
stats_weights_[STATS_TYPE_STRENGTH] += 1.1f;
|
stats_weights_[STATS_TYPE_STRENGTH] += 1.1f;
|
||||||
@@ -143,7 +143,19 @@ void StatsWeightCalculator::GenerateBasicWeights(Player* player)
|
|||||||
stats_weights_[STATS_TYPE_HASTE] += 1.4f;
|
stats_weights_[STATS_TYPE_HASTE] += 1.4f;
|
||||||
stats_weights_[STATS_TYPE_EXPERTISE] += 2.0f;
|
stats_weights_[STATS_TYPE_EXPERTISE] += 2.0f;
|
||||||
stats_weights_[STATS_TYPE_MELEE_DPS] += 5.0f;
|
stats_weights_[STATS_TYPE_MELEE_DPS] += 5.0f;
|
||||||
}
|
}
|
||||||
|
else if (cls == CLASS_DRUID && tab == DRUID_TAB_FERAL && !PlayerbotAI::IsTank(player))
|
||||||
|
{
|
||||||
|
stats_weights_[STATS_TYPE_AGILITY] += 2.4f;
|
||||||
|
stats_weights_[STATS_TYPE_STRENGTH] += 2.3f;
|
||||||
|
stats_weights_[STATS_TYPE_ATTACK_POWER] += 1.0f;
|
||||||
|
stats_weights_[STATS_TYPE_ARMOR_PENETRATION] += 2.1f;
|
||||||
|
stats_weights_[STATS_TYPE_HIT] += 1.9f;
|
||||||
|
stats_weights_[STATS_TYPE_CRIT] += 1.8f;
|
||||||
|
stats_weights_[STATS_TYPE_HASTE] += 1.4f;
|
||||||
|
stats_weights_[STATS_TYPE_EXPERTISE] += 2.0f;
|
||||||
|
stats_weights_[STATS_TYPE_MELEE_DPS] += 5.0f;
|
||||||
|
}
|
||||||
else if (cls == CLASS_ROGUE && (tab == ROGUE_TAB_ASSASSINATION || tab == ROGUE_TAB_SUBTLETY))
|
else if (cls == CLASS_ROGUE && (tab == ROGUE_TAB_ASSASSINATION || tab == ROGUE_TAB_SUBTLETY))
|
||||||
{
|
{
|
||||||
stats_weights_[STATS_TYPE_AGILITY] += 1.7f;
|
stats_weights_[STATS_TYPE_AGILITY] += 1.7f;
|
||||||
@@ -224,13 +236,13 @@ void StatsWeightCalculator::GenerateBasicWeights(Player* player)
|
|||||||
stats_weights_[STATS_TYPE_STRENGTH] += 1.1f;
|
stats_weights_[STATS_TYPE_STRENGTH] += 1.1f;
|
||||||
stats_weights_[STATS_TYPE_INTELLECT] += 0.5f;
|
stats_weights_[STATS_TYPE_INTELLECT] += 0.5f;
|
||||||
stats_weights_[STATS_TYPE_ATTACK_POWER] += 1.0f;
|
stats_weights_[STATS_TYPE_ATTACK_POWER] += 1.0f;
|
||||||
stats_weights_[STATS_TYPE_SPELL_POWER] += 1.0f;
|
stats_weights_[STATS_TYPE_SPELL_POWER] += 0.9f;
|
||||||
stats_weights_[STATS_TYPE_ARMOR_PENETRATION] += 1.2f;
|
stats_weights_[STATS_TYPE_ARMOR_PENETRATION] += 1.2f;
|
||||||
stats_weights_[STATS_TYPE_HIT] += 1.7f;
|
stats_weights_[STATS_TYPE_HIT] += 1.7f;
|
||||||
stats_weights_[STATS_TYPE_CRIT] += 1.4f;
|
stats_weights_[STATS_TYPE_CRIT] += 1.4f;
|
||||||
stats_weights_[STATS_TYPE_HASTE] += 1.8f;
|
stats_weights_[STATS_TYPE_HASTE] += 1.8f;
|
||||||
stats_weights_[STATS_TYPE_EXPERTISE] += 2.0f;
|
stats_weights_[STATS_TYPE_EXPERTISE] += 2.0f;
|
||||||
stats_weights_[STATS_TYPE_MELEE_DPS] += 5.2f;
|
stats_weights_[STATS_TYPE_MELEE_DPS] += 8.5f;
|
||||||
}
|
}
|
||||||
else if (cls == CLASS_WARLOCK ||
|
else if (cls == CLASS_WARLOCK ||
|
||||||
cls == CLASS_MAGE ||
|
cls == CLASS_MAGE ||
|
||||||
|
|||||||
@@ -172,7 +172,7 @@ public:
|
|||||||
creators["rtsc"] = &ChatActionContext::rtsc;
|
creators["rtsc"] = &ChatActionContext::rtsc;
|
||||||
creators["naxx chat shortcut"] = &ChatActionContext::naxx_chat_shortcut;
|
creators["naxx chat shortcut"] = &ChatActionContext::naxx_chat_shortcut;
|
||||||
creators["bwl chat shortcut"] = &ChatActionContext::bwl_chat_shortcut;
|
creators["bwl chat shortcut"] = &ChatActionContext::bwl_chat_shortcut;
|
||||||
creators["tell expected dps"] = &ChatActionContext::tell_expected_dps;
|
creators["tell estimated dps"] = &ChatActionContext::tell_estimated_dps;
|
||||||
creators["join"] = &ChatActionContext::join;
|
creators["join"] = &ChatActionContext::join;
|
||||||
creators["calc"] = &ChatActionContext::calc;
|
creators["calc"] = &ChatActionContext::calc;
|
||||||
}
|
}
|
||||||
@@ -271,7 +271,7 @@ private:
|
|||||||
static Action* rtsc(PlayerbotAI* botAI) { return new RTSCAction(botAI); }
|
static Action* rtsc(PlayerbotAI* botAI) { return new RTSCAction(botAI); }
|
||||||
static Action* naxx_chat_shortcut(PlayerbotAI* ai) { return new NaxxChatShortcutAction(ai); }
|
static Action* naxx_chat_shortcut(PlayerbotAI* ai) { return new NaxxChatShortcutAction(ai); }
|
||||||
static Action* bwl_chat_shortcut(PlayerbotAI* ai) { return new BwlChatShortcutAction(ai); }
|
static Action* bwl_chat_shortcut(PlayerbotAI* ai) { return new BwlChatShortcutAction(ai); }
|
||||||
static Action* tell_expected_dps(PlayerbotAI* ai) { return new TellExpectedDpsAction(ai); }
|
static Action* tell_estimated_dps(PlayerbotAI* ai) { return new TellEstimatedDpsAction(ai); }
|
||||||
static Action* join(PlayerbotAI* ai) { return new JoinGroupAction(ai); }
|
static Action* join(PlayerbotAI* ai) { return new JoinGroupAction(ai); }
|
||||||
static Action* calc(PlayerbotAI* ai) { return new TellCalculateItemAction(ai); }
|
static Action* calc(PlayerbotAI* ai) { return new TellCalculateItemAction(ai); }
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -364,5 +364,5 @@ bool CastDebuffSpellAction::isUseful()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return CastAuraSpellAction::isUseful() &&
|
return CastAuraSpellAction::isUseful() &&
|
||||||
(target->GetHealth() / AI_VALUE(float, "expected group dps")) >= needLifeTime;
|
(target->GetHealth() / AI_VALUE(float, "estimated group dps")) >= needLifeTime;
|
||||||
}
|
}
|
||||||
@@ -130,10 +130,10 @@ bool TellAuraAction::Execute(Event event)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TellExpectedDpsAction::Execute(Event event)
|
bool TellEstimatedDpsAction::Execute(Event event)
|
||||||
{
|
{
|
||||||
float dps = AI_VALUE(float, "expected group dps");
|
float dps = AI_VALUE(float, "estimated group dps");
|
||||||
botAI->TellMaster("Expected Group DPS: " + std::to_string(dps));
|
botAI->TellMaster("Estimated Group DPS: " + std::to_string(dps));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,10 +30,10 @@ public:
|
|||||||
virtual bool Execute(Event event);
|
virtual bool Execute(Event event);
|
||||||
};
|
};
|
||||||
|
|
||||||
class TellExpectedDpsAction : public Action
|
class TellEstimatedDpsAction : public Action
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TellExpectedDpsAction(PlayerbotAI* ai) : Action(ai, "tell expected dps") {}
|
TellEstimatedDpsAction(PlayerbotAI* ai) : Action(ai, "tell estimated dps") {}
|
||||||
|
|
||||||
virtual bool Execute(Event event);
|
virtual bool Execute(Event event);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ private:
|
|||||||
{
|
{
|
||||||
return new ActionNode("mangle (cat)",
|
return new ActionNode("mangle (cat)",
|
||||||
/*P*/ nullptr,
|
/*P*/ nullptr,
|
||||||
/*A*/ NextAction::array(0, new NextAction("claw"), nullptr),
|
/*A*/ nullptr,
|
||||||
/*C*/ nullptr);
|
/*C*/ nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,38 +122,51 @@ CatDpsDruidStrategy::CatDpsDruidStrategy(PlayerbotAI* botAI) : FeralDruidStrateg
|
|||||||
|
|
||||||
NextAction** CatDpsDruidStrategy::getDefaultActions()
|
NextAction** CatDpsDruidStrategy::getDefaultActions()
|
||||||
{
|
{
|
||||||
return NextAction::array(0, new NextAction("mangle (cat)", ACTION_DEFAULT + 0.1f), nullptr);
|
return NextAction::array(0, new NextAction("shred", ACTION_DEFAULT + 0.4f),
|
||||||
|
new NextAction("tiger's fury", ACTION_DEFAULT + 0.1f), nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CatDpsDruidStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
void CatDpsDruidStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||||
{
|
{
|
||||||
FeralDruidStrategy::InitTriggers(triggers);
|
FeralDruidStrategy::InitTriggers(triggers);
|
||||||
|
|
||||||
|
// Default priority
|
||||||
|
triggers.push_back(new TriggerNode("high energy available",
|
||||||
|
NextAction::array(0, new NextAction("mangle (cat)", ACTION_DEFAULT + 0.3f), nullptr)));
|
||||||
|
triggers.push_back(new TriggerNode("high energy available",
|
||||||
|
NextAction::array(0, new NextAction("claw", ACTION_DEFAULT + 0.2f), nullptr)));
|
||||||
triggers.push_back(
|
triggers.push_back(
|
||||||
new TriggerNode("cat form", NextAction::array(0, new NextAction("cat form", ACTION_HIGH + 2), nullptr)));
|
new TriggerNode("faerie fire (feral)",
|
||||||
|
NextAction::array(0, new NextAction("faerie fire (feral)", ACTION_DEFAULT + 0.0f), nullptr)));
|
||||||
|
|
||||||
|
// Main spell
|
||||||
triggers.push_back(
|
triggers.push_back(
|
||||||
new TriggerNode("rake", NextAction::array(0, new NextAction("rake", ACTION_NORMAL + 5), nullptr)));
|
new TriggerNode("cat form", NextAction::array(0, new NextAction("cat form", ACTION_HIGH + 8), nullptr)));
|
||||||
|
triggers.push_back(
|
||||||
|
new TriggerNode("savage roar", NextAction::array(0, new NextAction("savage roar", ACTION_HIGH + 7), nullptr)));
|
||||||
|
triggers.push_back(new TriggerNode("combo points available",
|
||||||
|
NextAction::array(0, new NextAction("rip", ACTION_HIGH + 6), nullptr)));
|
||||||
triggers.push_back(new TriggerNode(
|
triggers.push_back(new TriggerNode(
|
||||||
"combo points available", NextAction::array(0, new NextAction("ferocious bite", ACTION_NORMAL + 9), nullptr)));
|
"ferocious bite time", NextAction::array(0, new NextAction("ferocious bite", ACTION_HIGH + 5), nullptr)));
|
||||||
triggers.push_back(
|
triggers.push_back(
|
||||||
new TriggerNode("medium threat", NextAction::array(0, new NextAction("cower", ACTION_EMERGENCY + 1), nullptr)));
|
new TriggerNode("target with combo points almost dead",
|
||||||
|
NextAction::array(0, new NextAction("ferocious bite", ACTION_HIGH + 4), nullptr)));
|
||||||
|
triggers.push_back(new TriggerNode("mangle (cat)",
|
||||||
|
NextAction::array(0, new NextAction("mangle (cat)", ACTION_HIGH + 3), nullptr)));
|
||||||
|
triggers.push_back(new TriggerNode("rake", NextAction::array(0, new NextAction("rake", ACTION_HIGH + 2), nullptr)));
|
||||||
|
triggers.push_back(
|
||||||
|
new TriggerNode("medium threat", NextAction::array(0, new NextAction("cower", ACTION_HIGH + 1), nullptr)));
|
||||||
|
|
||||||
|
// AOE
|
||||||
|
triggers.push_back(
|
||||||
|
new TriggerNode("medium aoe", NextAction::array(0, new NextAction("swipe (cat)", ACTION_HIGH + 3), nullptr)));
|
||||||
triggers.push_back(new TriggerNode(
|
triggers.push_back(new TriggerNode(
|
||||||
"faerie fire (feral)", NextAction::array(0, new NextAction("faerie fire (feral)", ACTION_HIGH), nullptr)));
|
"light aoe", NextAction::array(0, new NextAction("rake on attacker", ACTION_HIGH + 2), nullptr)));
|
||||||
|
// Reach target
|
||||||
triggers.push_back(new TriggerNode(
|
triggers.push_back(new TriggerNode(
|
||||||
"tiger's fury", NextAction::array(0, new NextAction("tiger's fury", ACTION_EMERGENCY + 1), nullptr)));
|
"enemy out of melee", NextAction::array(0, new NextAction("feral charge - cat", ACTION_HIGH + 9), nullptr)));
|
||||||
triggers.push_back(
|
triggers.push_back(
|
||||||
new TriggerNode("behind target", NextAction::array(0, new NextAction("pounce", ACTION_HIGH + 1), nullptr)));
|
new TriggerNode("enemy out of melee", NextAction::array(0, new NextAction("dash", ACTION_HIGH + 8), nullptr)));
|
||||||
// triggers.push_back(new TriggerNode("player has no flag", NextAction::array(0, new NextAction("prowl",
|
|
||||||
// ACTION_HIGH), nullptr))); triggers.push_back(new TriggerNode("enemy out of melee", NextAction::array(0, new
|
|
||||||
// NextAction("prowl", ACTION_INTERRUPT + 1), nullptr)));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("player has flag", NextAction::array(0, new NextAction("dash", ACTION_EMERGENCY), nullptr)));
|
|
||||||
triggers.push_back(new TriggerNode("enemy flagcarrier near",
|
|
||||||
NextAction::array(0, new NextAction("dash", ACTION_EMERGENCY), nullptr)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CatAoeDruidStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
void CatAoeDruidStrategy::InitTriggers(std::vector<TriggerNode*>& triggers) {}
|
||||||
{
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("medium aoe", NextAction::array(0, new NextAction("swipe (cat)", ACTION_HIGH + 2), nullptr)));
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -83,6 +83,8 @@ public:
|
|||||||
creators["moonfire"] = &DruidTriggerFactoryInternal::moonfire;
|
creators["moonfire"] = &DruidTriggerFactoryInternal::moonfire;
|
||||||
creators["nature's grasp"] = &DruidTriggerFactoryInternal::natures_grasp;
|
creators["nature's grasp"] = &DruidTriggerFactoryInternal::natures_grasp;
|
||||||
creators["tiger's fury"] = &DruidTriggerFactoryInternal::tigers_fury;
|
creators["tiger's fury"] = &DruidTriggerFactoryInternal::tigers_fury;
|
||||||
|
creators["berserk"] = &DruidTriggerFactoryInternal::berserk;
|
||||||
|
creators["savage roar"] = &DruidTriggerFactoryInternal::savage_roar;
|
||||||
creators["rake"] = &DruidTriggerFactoryInternal::rake;
|
creators["rake"] = &DruidTriggerFactoryInternal::rake;
|
||||||
creators["mark of the wild"] = &DruidTriggerFactoryInternal::mark_of_the_wild;
|
creators["mark of the wild"] = &DruidTriggerFactoryInternal::mark_of_the_wild;
|
||||||
creators["mark of the wild on party"] = &DruidTriggerFactoryInternal::mark_of_the_wild_on_party;
|
creators["mark of the wild on party"] = &DruidTriggerFactoryInternal::mark_of_the_wild_on_party;
|
||||||
@@ -101,6 +103,8 @@ public:
|
|||||||
creators["party member remove curse"] = &DruidTriggerFactoryInternal::party_member_remove_curse;
|
creators["party member remove curse"] = &DruidTriggerFactoryInternal::party_member_remove_curse;
|
||||||
creators["eclipse (solar) cooldown"] = &DruidTriggerFactoryInternal::eclipse_solar_cooldown;
|
creators["eclipse (solar) cooldown"] = &DruidTriggerFactoryInternal::eclipse_solar_cooldown;
|
||||||
creators["eclipse (lunar) cooldown"] = &DruidTriggerFactoryInternal::eclipse_lunar_cooldown;
|
creators["eclipse (lunar) cooldown"] = &DruidTriggerFactoryInternal::eclipse_lunar_cooldown;
|
||||||
|
creators["mangle (cat)"] = &DruidTriggerFactoryInternal::mangle_cat;
|
||||||
|
creators["ferocious bite time"] = &DruidTriggerFactoryInternal::ferocious_bite_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -117,6 +121,8 @@ private:
|
|||||||
static Trigger* faerie_fire(PlayerbotAI* botAI) { return new FaerieFireTrigger(botAI); }
|
static Trigger* faerie_fire(PlayerbotAI* botAI) { return new FaerieFireTrigger(botAI); }
|
||||||
static Trigger* natures_grasp(PlayerbotAI* botAI) { return new NaturesGraspTrigger(botAI); }
|
static Trigger* natures_grasp(PlayerbotAI* botAI) { return new NaturesGraspTrigger(botAI); }
|
||||||
static Trigger* tigers_fury(PlayerbotAI* botAI) { return new TigersFuryTrigger(botAI); }
|
static Trigger* tigers_fury(PlayerbotAI* botAI) { return new TigersFuryTrigger(botAI); }
|
||||||
|
static Trigger* berserk(PlayerbotAI* botAI) { return new BerserkTrigger(botAI); }
|
||||||
|
static Trigger* savage_roar(PlayerbotAI* botAI) { return new SavageRoarTrigger(botAI); }
|
||||||
static Trigger* rake(PlayerbotAI* botAI) { return new RakeTrigger(botAI); }
|
static Trigger* rake(PlayerbotAI* botAI) { return new RakeTrigger(botAI); }
|
||||||
static Trigger* mark_of_the_wild(PlayerbotAI* botAI) { return new MarkOfTheWildTrigger(botAI); }
|
static Trigger* mark_of_the_wild(PlayerbotAI* botAI) { return new MarkOfTheWildTrigger(botAI); }
|
||||||
static Trigger* mark_of_the_wild_on_party(PlayerbotAI* botAI) { return new MarkOfTheWildOnPartyTrigger(botAI); }
|
static Trigger* mark_of_the_wild_on_party(PlayerbotAI* botAI) { return new MarkOfTheWildOnPartyTrigger(botAI); }
|
||||||
@@ -133,6 +139,8 @@ private:
|
|||||||
static Trigger* party_member_remove_curse(PlayerbotAI* ai) { return new DruidPartyMemberRemoveCurseTrigger(ai); }
|
static Trigger* party_member_remove_curse(PlayerbotAI* ai) { return new DruidPartyMemberRemoveCurseTrigger(ai); }
|
||||||
static Trigger* eclipse_solar_cooldown(PlayerbotAI* ai) { return new EclipseSolarCooldownTrigger(ai); }
|
static Trigger* eclipse_solar_cooldown(PlayerbotAI* ai) { return new EclipseSolarCooldownTrigger(ai); }
|
||||||
static Trigger* eclipse_lunar_cooldown(PlayerbotAI* ai) { return new EclipseLunarCooldownTrigger(ai); }
|
static Trigger* eclipse_lunar_cooldown(PlayerbotAI* ai) { return new EclipseLunarCooldownTrigger(ai); }
|
||||||
|
static Trigger* mangle_cat(PlayerbotAI* ai) { return new MangleCatTrigger(ai); }
|
||||||
|
static Trigger* ferocious_bite_time(PlayerbotAI* ai) { return new FerociousBiteTimeTrigger(ai); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class DruidAiObjectContextInternal : public NamedObjectContext<Action>
|
class DruidAiObjectContextInternal : public NamedObjectContext<Action>
|
||||||
@@ -174,6 +182,7 @@ public:
|
|||||||
creators["mangle (cat)"] = &DruidAiObjectContextInternal::mangle_cat;
|
creators["mangle (cat)"] = &DruidAiObjectContextInternal::mangle_cat;
|
||||||
creators["swipe (cat)"] = &DruidAiObjectContextInternal::swipe_cat;
|
creators["swipe (cat)"] = &DruidAiObjectContextInternal::swipe_cat;
|
||||||
creators["rake"] = &DruidAiObjectContextInternal::rake;
|
creators["rake"] = &DruidAiObjectContextInternal::rake;
|
||||||
|
creators["rake on attacker"] = &DruidAiObjectContextInternal::rake_on_attacker;
|
||||||
creators["ferocious bite"] = &DruidAiObjectContextInternal::ferocious_bite;
|
creators["ferocious bite"] = &DruidAiObjectContextInternal::ferocious_bite;
|
||||||
creators["rip"] = &DruidAiObjectContextInternal::rip;
|
creators["rip"] = &DruidAiObjectContextInternal::rip;
|
||||||
creators["cower"] = &DruidAiObjectContextInternal::cower;
|
creators["cower"] = &DruidAiObjectContextInternal::cower;
|
||||||
@@ -188,6 +197,7 @@ public:
|
|||||||
creators["abolish poison on party"] = &DruidAiObjectContextInternal::abolish_poison_on_party;
|
creators["abolish poison on party"] = &DruidAiObjectContextInternal::abolish_poison_on_party;
|
||||||
creators["berserk"] = &DruidAiObjectContextInternal::berserk;
|
creators["berserk"] = &DruidAiObjectContextInternal::berserk;
|
||||||
creators["tiger's fury"] = &DruidAiObjectContextInternal::tigers_fury;
|
creators["tiger's fury"] = &DruidAiObjectContextInternal::tigers_fury;
|
||||||
|
creators["savage roar"] = &DruidAiObjectContextInternal::savage_roar;
|
||||||
creators["mark of the wild"] = &DruidAiObjectContextInternal::mark_of_the_wild;
|
creators["mark of the wild"] = &DruidAiObjectContextInternal::mark_of_the_wild;
|
||||||
creators["mark of the wild on party"] = &DruidAiObjectContextInternal::mark_of_the_wild_on_party;
|
creators["mark of the wild on party"] = &DruidAiObjectContextInternal::mark_of_the_wild_on_party;
|
||||||
creators["regrowth"] = &DruidAiObjectContextInternal::regrowth;
|
creators["regrowth"] = &DruidAiObjectContextInternal::regrowth;
|
||||||
@@ -257,6 +267,7 @@ private:
|
|||||||
static Action* mangle_cat(PlayerbotAI* botAI) { return new CastMangleCatAction(botAI); }
|
static Action* mangle_cat(PlayerbotAI* botAI) { return new CastMangleCatAction(botAI); }
|
||||||
static Action* swipe_cat(PlayerbotAI* botAI) { return new CastSwipeCatAction(botAI); }
|
static Action* swipe_cat(PlayerbotAI* botAI) { return new CastSwipeCatAction(botAI); }
|
||||||
static Action* rake(PlayerbotAI* botAI) { return new CastRakeAction(botAI); }
|
static Action* rake(PlayerbotAI* botAI) { return new CastRakeAction(botAI); }
|
||||||
|
static Action* rake_on_attacker(PlayerbotAI* botAI) { return new CastRakeOnMeleeAttackersAction(botAI); }
|
||||||
static Action* ferocious_bite(PlayerbotAI* botAI) { return new CastFerociousBiteAction(botAI); }
|
static Action* ferocious_bite(PlayerbotAI* botAI) { return new CastFerociousBiteAction(botAI); }
|
||||||
static Action* rip(PlayerbotAI* botAI) { return new CastRipAction(botAI); }
|
static Action* rip(PlayerbotAI* botAI) { return new CastRipAction(botAI); }
|
||||||
static Action* cower(PlayerbotAI* botAI) { return new CastCowerAction(botAI); }
|
static Action* cower(PlayerbotAI* botAI) { return new CastCowerAction(botAI); }
|
||||||
@@ -271,6 +282,7 @@ private:
|
|||||||
static Action* abolish_poison_on_party(PlayerbotAI* botAI) { return new CastAbolishPoisonOnPartyAction(botAI); }
|
static Action* abolish_poison_on_party(PlayerbotAI* botAI) { return new CastAbolishPoisonOnPartyAction(botAI); }
|
||||||
static Action* berserk(PlayerbotAI* botAI) { return new CastBerserkAction(botAI); }
|
static Action* berserk(PlayerbotAI* botAI) { return new CastBerserkAction(botAI); }
|
||||||
static Action* tigers_fury(PlayerbotAI* botAI) { return new CastTigersFuryAction(botAI); }
|
static Action* tigers_fury(PlayerbotAI* botAI) { return new CastTigersFuryAction(botAI); }
|
||||||
|
static Action* savage_roar(PlayerbotAI* botAI) { return new CastSavageRoarAction(botAI); }
|
||||||
static Action* mark_of_the_wild(PlayerbotAI* botAI) { return new CastMarkOfTheWildAction(botAI); }
|
static Action* mark_of_the_wild(PlayerbotAI* botAI) { return new CastMarkOfTheWildAction(botAI); }
|
||||||
static Action* mark_of_the_wild_on_party(PlayerbotAI* botAI) { return new CastMarkOfTheWildOnPartyAction(botAI); }
|
static Action* mark_of_the_wild_on_party(PlayerbotAI* botAI) { return new CastMarkOfTheWildOnPartyAction(botAI); }
|
||||||
static Action* regrowth(PlayerbotAI* botAI) { return new CastRegrowthAction(botAI); }
|
static Action* regrowth(PlayerbotAI* botAI) { return new CastRegrowthAction(botAI); }
|
||||||
|
|||||||
1
src/strategy/druid/DruidCatActions.cpp
Normal file
1
src/strategy/druid/DruidCatActions.cpp
Normal file
@@ -0,0 +1 @@
|
|||||||
|
#include "DruidCatActions.h"
|
||||||
@@ -35,10 +35,23 @@ public:
|
|||||||
CastTigersFuryAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "tiger's fury") {}
|
CastTigersFuryAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "tiger's fury") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class CastSavageRoarAction : public CastBuffSpellAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CastSavageRoarAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "savage roar") {}
|
||||||
|
std::string const GetTargetName() override { return "current target"; }
|
||||||
|
};
|
||||||
|
|
||||||
class CastRakeAction : public CastDebuffSpellAction
|
class CastRakeAction : public CastDebuffSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastRakeAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "rake") {}
|
CastRakeAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "rake", true, 6.0f) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class CastRakeOnMeleeAttackersAction : public CastDebuffSpellOnMeleeAttackerAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CastRakeOnMeleeAttackersAction(PlayerbotAI* botAI) : CastDebuffSpellOnMeleeAttackerAction(botAI, "rake", true, 6.0f) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastClawAction : public CastMeleeSpellAction
|
class CastClawAction : public CastMeleeSpellAction
|
||||||
@@ -65,10 +78,10 @@ public:
|
|||||||
CastFerociousBiteAction(PlayerbotAI* botAI) : CastMeleeSpellAction(botAI, "ferocious bite") {}
|
CastFerociousBiteAction(PlayerbotAI* botAI) : CastMeleeSpellAction(botAI, "ferocious bite") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastRipAction : public CastMeleeSpellAction
|
class CastRipAction : public CastMeleeDebuffSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastRipAction(PlayerbotAI* botAI) : CastMeleeSpellAction(botAI, "rip") {}
|
CastRipAction(PlayerbotAI* botAI) : CastMeleeDebuffSpellAction(botAI, "rip", true, 12.0f) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastShredAction : public CastMeleeSpellAction
|
class CastShredAction : public CastMeleeSpellAction
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
#include "CureTriggers.h"
|
#include "CureTriggers.h"
|
||||||
#include "GenericTriggers.h"
|
#include "GenericTriggers.h"
|
||||||
#include "Player.h"
|
#include "Player.h"
|
||||||
|
#include "PlayerbotAI.h"
|
||||||
|
#include "Playerbots.h"
|
||||||
#include "SharedDefines.h"
|
#include "SharedDefines.h"
|
||||||
|
|
||||||
class PlayerbotAI;
|
class PlayerbotAI;
|
||||||
@@ -95,10 +97,22 @@ public:
|
|||||||
BashInterruptSpellTrigger(PlayerbotAI* botAI) : InterruptSpellTrigger(botAI, "bash") {}
|
BashInterruptSpellTrigger(PlayerbotAI* botAI) : InterruptSpellTrigger(botAI, "bash") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class TigersFuryTrigger : public BoostTrigger
|
class TigersFuryTrigger : public BuffTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TigersFuryTrigger(PlayerbotAI* botAI) : BoostTrigger(botAI, "tiger's fury") {}
|
TigersFuryTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "tiger's fury") {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class BerserkTrigger : public BoostTrigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BerserkTrigger(PlayerbotAI* botAI) : BoostTrigger(botAI, "berserk") {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SavageRoarTrigger : public BuffTrigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SavageRoarTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "savage roar") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class NaturesGraspTrigger : public BoostTrigger
|
class NaturesGraspTrigger : public BoostTrigger
|
||||||
@@ -212,4 +226,43 @@ public:
|
|||||||
bool IsActive() override { return bot->HasSpellCooldown(48518); }
|
bool IsActive() override { return bot->HasSpellCooldown(48518); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class MangleCatTrigger : public DebuffTrigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MangleCatTrigger(PlayerbotAI* ai) : DebuffTrigger(ai, "mangle (cat)", 1, false, 0.0f) {}
|
||||||
|
bool IsActive() override
|
||||||
|
{
|
||||||
|
return DebuffTrigger::IsActive() && !botAI->HasAura("mangle (bear)", GetTarget(), false, false, -1, true)
|
||||||
|
&& !botAI->HasAura("trauma", GetTarget(), false, false, -1, true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class FerociousBiteTimeTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FerociousBiteTimeTrigger(PlayerbotAI* ai) : Trigger(ai, "ferocious bite time") {}
|
||||||
|
bool IsActive() override
|
||||||
|
{
|
||||||
|
Unit* target = AI_VALUE(Unit*, "current target");
|
||||||
|
if (!target)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
uint8 cp = AI_VALUE2(uint8, "combo", "current target");
|
||||||
|
if (cp < 5)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Aura* roar = botAI->GetAura("savage roar", bot);
|
||||||
|
bool roarCheck = !roar || roar->GetDuration() > 8000;
|
||||||
|
if (!roarCheck)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Aura* rip = botAI->GetAura("rip", target, true);
|
||||||
|
bool ripCheck = !rip || rip->GetDuration() > 8000;
|
||||||
|
if (!ripCheck)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -112,4 +112,6 @@ void FeralDruidStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
NextAction::array(0, new NextAction("dash", ACTION_EMERGENCY + 2), nullptr)));
|
NextAction::array(0, new NextAction("dash", ACTION_EMERGENCY + 2), nullptr)));
|
||||||
triggers.push_back(new TriggerNode("enemy flagcarrier near",
|
triggers.push_back(new TriggerNode("enemy flagcarrier near",
|
||||||
NextAction::array(0, new NextAction("dash", ACTION_EMERGENCY + 2), nullptr)));
|
NextAction::array(0, new NextAction("dash", ACTION_EMERGENCY + 2), nullptr)));
|
||||||
|
triggers.push_back(
|
||||||
|
new TriggerNode("berserk", NextAction::array(0, new NextAction("berserk", ACTION_HIGH + 6), nullptr)));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ float CastTimeMultiplier::GetValue(Action* action)
|
|||||||
return 1.0f;
|
return 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (castTime > (1000 * target->GetHealth() / AI_VALUE(float, "expected group dps")))
|
if (castTime > (1000 * target->GetHealth() / AI_VALUE(float, "estimated group dps")))
|
||||||
{
|
{
|
||||||
return 0.1f;
|
return 0.1f;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ void ChatCommandHandlerStrategy::InitTriggers(std::vector<TriggerNode*>& trigger
|
|||||||
triggers.push_back(
|
triggers.push_back(
|
||||||
new TriggerNode("bwl", NextAction::array(0, new NextAction("bwl chat shortcut", relevance), NULL)));
|
new TriggerNode("bwl", NextAction::array(0, new NextAction("bwl chat shortcut", relevance), NULL)));
|
||||||
triggers.push_back(
|
triggers.push_back(
|
||||||
new TriggerNode("dps", NextAction::array(0, new NextAction("tell expected dps", relevance), NULL)));
|
new TriggerNode("dps", NextAction::array(0, new NextAction("tell estimated dps", relevance), NULL)));
|
||||||
triggers.push_back(
|
triggers.push_back(
|
||||||
new TriggerNode("disperse", NextAction::array(0, new NextAction("disperse set", relevance), NULL)));
|
new TriggerNode("disperse", NextAction::array(0, new NextAction("disperse set", relevance), NULL)));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,8 +77,6 @@ public:
|
|||||||
creators["tricks of the trade on main tank"] = &RogueTriggerFactoryInternal::tricks_of_the_trade_on_main_tank;
|
creators["tricks of the trade on main tank"] = &RogueTriggerFactoryInternal::tricks_of_the_trade_on_main_tank;
|
||||||
creators["adrenaline rush"] = &RogueTriggerFactoryInternal::adrenaline_rush;
|
creators["adrenaline rush"] = &RogueTriggerFactoryInternal::adrenaline_rush;
|
||||||
creators["blade fury"] = &RogueTriggerFactoryInternal::blade_fury;
|
creators["blade fury"] = &RogueTriggerFactoryInternal::blade_fury;
|
||||||
creators["target with combo points almost dead"] =
|
|
||||||
&RogueTriggerFactoryInternal::target_with_combo_points_almost_dead;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -102,10 +100,6 @@ private:
|
|||||||
{
|
{
|
||||||
return new TricksOfTheTradeOnMainTankTrigger(ai);
|
return new TricksOfTheTradeOnMainTankTrigger(ai);
|
||||||
}
|
}
|
||||||
static Trigger* target_with_combo_points_almost_dead(PlayerbotAI* ai)
|
|
||||||
{
|
|
||||||
return new TargetWithComboPointsLowerHealTrigger(ai, 3, 3.0f);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class RogueAiObjectContextInternal : public NamedObjectContext<Action>
|
class RogueAiObjectContextInternal : public NamedObjectContext<Action>
|
||||||
|
|||||||
@@ -124,14 +124,3 @@ bool OffHandWeaponNoEnchantTrigger::IsActive()
|
|||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TargetWithComboPointsLowerHealTrigger::IsActive()
|
|
||||||
{
|
|
||||||
Unit* target = AI_VALUE(Unit*, "current target");
|
|
||||||
if (!target || !target->IsAlive() || !target->IsInWorld())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return ComboPointsAvailableTrigger::IsActive() &&
|
|
||||||
(target->GetHealth() / AI_VALUE(float, "expected group dps")) <= lifeTime;
|
|
||||||
}
|
|
||||||
@@ -127,17 +127,6 @@ public:
|
|||||||
TricksOfTheTradeOnMainTankTrigger(PlayerbotAI* ai) : BuffOnMainTankTrigger(ai, "tricks of the trade", true) {}
|
TricksOfTheTradeOnMainTankTrigger(PlayerbotAI* ai) : BuffOnMainTankTrigger(ai, "tricks of the trade", true) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class TargetWithComboPointsLowerHealTrigger : public ComboPointsAvailableTrigger
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
TargetWithComboPointsLowerHealTrigger(PlayerbotAI* ai, int32 combo_point = 5, float lifeTime = 8.0f)
|
|
||||||
: ComboPointsAvailableTrigger(ai, combo_point), lifeTime(lifeTime)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
bool IsActive() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
float lifeTime;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -66,7 +66,9 @@ void CasterShamanStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
// shock", 21.0f), nullptr)));
|
// shock", 21.0f), nullptr)));
|
||||||
triggers.push_back(
|
triggers.push_back(
|
||||||
new TriggerNode("no fire totem", NextAction::array(0, new NextAction("totem of wrath", 15.0f), NULL)));
|
new TriggerNode("no fire totem", NextAction::array(0, new NextAction("totem of wrath", 15.0f), NULL)));
|
||||||
|
triggers.push_back(new TriggerNode("fire elemental totem",
|
||||||
|
NextAction::array(0, new NextAction("fire elemental totem", 32.0f), nullptr)));
|
||||||
|
|
||||||
triggers.push_back(
|
triggers.push_back(
|
||||||
new TriggerNode("medium mana", NextAction::array(0, new NextAction("thunderstorm", ACTION_HIGH + 1), nullptr)));
|
new TriggerNode("medium mana", NextAction::array(0, new NextAction("thunderstorm", ACTION_HIGH + 1), nullptr)));
|
||||||
|
|
||||||
|
|||||||
@@ -104,6 +104,11 @@ void HealShamanStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
triggers.push_back(
|
triggers.push_back(
|
||||||
new TriggerNode("medium mana", NextAction::array(0, new NextAction("mana tide totem", ACTION_HIGH + 5), NULL)));
|
new TriggerNode("medium mana", NextAction::array(0, new NextAction("mana tide totem", ACTION_HIGH + 5), NULL)));
|
||||||
|
|
||||||
|
triggers.push_back(
|
||||||
|
new TriggerNode("no fire totem", NextAction::array(0, new NextAction("flametongue totem", 7.0f),
|
||||||
|
new NextAction("searing totem", 6.0f), nullptr)));
|
||||||
|
triggers.push_back(new TriggerNode("fire elemental totem",
|
||||||
|
NextAction::array(0, new NextAction("fire elemental totem", 32.0f), nullptr)));
|
||||||
triggers.push_back(new TriggerNode(
|
triggers.push_back(new TriggerNode(
|
||||||
"party member to heal out of spell range",
|
"party member to heal out of spell range",
|
||||||
NextAction::array(0, new NextAction("reach party member to heal", ACTION_CRITICAL_HEAL + 1), nullptr)));
|
NextAction::array(0, new NextAction("reach party member to heal", ACTION_CRITICAL_HEAL + 1), nullptr)));
|
||||||
|
|||||||
@@ -72,11 +72,8 @@ void MeleeShamanStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
triggers.push_back(
|
triggers.push_back(
|
||||||
new TriggerNode("flame shock", NextAction::array(0, new NextAction("flame shock", 20.0f), nullptr)));
|
new TriggerNode("flame shock", NextAction::array(0, new NextAction("flame shock", 20.0f), nullptr)));
|
||||||
triggers.push_back(
|
triggers.push_back(
|
||||||
new TriggerNode("maelstrom weapon", NextAction::array(0, new NextAction("lightning bolt", 25.0f), nullptr)));
|
new TriggerNode("maelstrom weapon 4", NextAction::array(0, new NextAction("lightning bolt", 25.0f), nullptr)));
|
||||||
triggers.push_back(new TriggerNode("not facing target",
|
|
||||||
NextAction::array(0, new NextAction("set facing", ACTION_NORMAL + 7), nullptr)));
|
|
||||||
// triggers.push_back(new TriggerNode("enemy too close for melee", NextAction::array(0, new NextAction("move out of
|
|
||||||
// enemy contact", ACTION_NORMAL + 8), nullptr)));
|
|
||||||
triggers.push_back(new TriggerNode(
|
triggers.push_back(new TriggerNode(
|
||||||
"medium aoe", NextAction::array(0, new NextAction("strength of earth totem", ACTION_LIGHT_HEAL), nullptr)));
|
"medium aoe", NextAction::array(0, new NextAction("strength of earth totem", ACTION_LIGHT_HEAL), nullptr)));
|
||||||
triggers.push_back(new TriggerNode(
|
triggers.push_back(new TriggerNode(
|
||||||
@@ -86,9 +83,8 @@ void MeleeShamanStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
"no fire totem",
|
"no fire totem",
|
||||||
NextAction::array(0, new NextAction("reach melee", 23.0f), new NextAction("magma totem", 22.0f), nullptr)));
|
NextAction::array(0, new NextAction("reach melee", 23.0f), new NextAction("magma totem", 22.0f), nullptr)));
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("fire elemental totem",
|
triggers.push_back(new TriggerNode(
|
||||||
NextAction::array(0, new NextAction("reach melee", 33.0f),
|
"fire elemental totem", NextAction::array(0, new NextAction("fire elemental totem melee", 32.0f), nullptr)));
|
||||||
new NextAction("fire elemental totem", 32.0f), nullptr)));
|
|
||||||
|
|
||||||
triggers.push_back(
|
triggers.push_back(
|
||||||
new TriggerNode("no air totem", NextAction::array(0, new NextAction("windfury totem", 20.0f), nullptr)));
|
new TriggerNode("no air totem", NextAction::array(0, new NextAction("windfury totem", 20.0f), nullptr)));
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ bool CastTotemAction::isUseful()
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
float dps = AI_VALUE(float, "expected group dps");
|
float dps = AI_VALUE(float, "estimated group dps");
|
||||||
if (target->GetHealth() / dps < needLifeTime)
|
if (target->GetHealth() / dps < needLifeTime)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@@ -51,11 +51,14 @@ bool CastMagmaTotemAction::isUseful() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool CastFireNovaAction::isUseful() {
|
bool CastFireNovaAction::isUseful() {
|
||||||
|
Unit* target = AI_VALUE(Unit*, "current target");
|
||||||
|
if (!target)
|
||||||
|
return false;
|
||||||
Creature* fireTotem = bot->GetMap()->GetCreature(bot->m_SummonSlot[1]);
|
Creature* fireTotem = bot->GetMap()->GetCreature(bot->m_SummonSlot[1]);
|
||||||
if (!fireTotem)
|
if (!fireTotem)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (bot->GetDistance(fireTotem) > 8.0f)
|
if (target->GetDistance(fireTotem) > 8.0f)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return CastMeleeSpellAction::isUseful();
|
return CastMeleeSpellAction::isUseful();
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#define _PLAYERBOT_SHAMANACTIONS_H
|
#define _PLAYERBOT_SHAMANACTIONS_H
|
||||||
|
|
||||||
#include "GenericSpellActions.h"
|
#include "GenericSpellActions.h"
|
||||||
|
#include "Playerbots.h"
|
||||||
#include "SharedDefines.h"
|
#include "SharedDefines.h"
|
||||||
|
|
||||||
class PlayerbotAI;
|
class PlayerbotAI;
|
||||||
@@ -426,6 +427,20 @@ public:
|
|||||||
virtual bool isUseful() override { return CastTotemAction::isUseful(); }
|
virtual bool isUseful() override { return CastTotemAction::isUseful(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class CastFireElementalTotemMeleeAction : public CastTotemAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CastFireElementalTotemMeleeAction(PlayerbotAI* ai) : CastTotemAction(ai, "fire elemental totem", "", 0.0f) {}
|
||||||
|
virtual std::string const GetTargetName() override { return "self target"; }
|
||||||
|
virtual bool isUseful() override
|
||||||
|
{
|
||||||
|
Unit* target = AI_VALUE(Unit*, "current target");
|
||||||
|
if (!target || !bot->IsWithinMeleeRange(target))
|
||||||
|
return false;
|
||||||
|
return CastTotemAction::isUseful();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class CastWrathOfAirTotemAction : public CastTotemAction
|
class CastWrathOfAirTotemAction : public CastTotemAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -110,13 +110,17 @@ public:
|
|||||||
creators["no water totem"] = &ShamanATriggerFactoryInternal::no_water_totem;
|
creators["no water totem"] = &ShamanATriggerFactoryInternal::no_water_totem;
|
||||||
creators["no air totem"] = &ShamanATriggerFactoryInternal::no_air_totem;
|
creators["no air totem"] = &ShamanATriggerFactoryInternal::no_air_totem;
|
||||||
creators["earth shield on main tank"] = &ShamanATriggerFactoryInternal::earth_shield_on_main_tank;
|
creators["earth shield on main tank"] = &ShamanATriggerFactoryInternal::earth_shield_on_main_tank;
|
||||||
creators["maelstrom weapon"] = &ShamanATriggerFactoryInternal::maelstrom_weapon;
|
creators["maelstrom weapon 3"] = &ShamanATriggerFactoryInternal::maelstrom_weapon_3;
|
||||||
|
creators["maelstrom weapon 4"] = &ShamanATriggerFactoryInternal::maelstrom_weapon_4;
|
||||||
|
creators["maelstrom weapon 5"] = &ShamanATriggerFactoryInternal::maelstrom_weapon_5;
|
||||||
creators["flame shock"] = &ShamanATriggerFactoryInternal::flame_shock;
|
creators["flame shock"] = &ShamanATriggerFactoryInternal::flame_shock;
|
||||||
creators["wrath of air totem"] = &ShamanATriggerFactoryInternal::wrath_of_air_totem;
|
creators["wrath of air totem"] = &ShamanATriggerFactoryInternal::wrath_of_air_totem;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static Trigger* maelstrom_weapon(PlayerbotAI* botAI) { return new MaelstromWeaponTrigger(botAI); }
|
static Trigger* maelstrom_weapon_3(PlayerbotAI* botAI) { return new MaelstromWeaponTrigger(botAI, 3); }
|
||||||
|
static Trigger* maelstrom_weapon_4(PlayerbotAI* botAI) { return new MaelstromWeaponTrigger(botAI, 4); }
|
||||||
|
static Trigger* maelstrom_weapon_5(PlayerbotAI* botAI) { return new MaelstromWeaponTrigger(botAI, 5); }
|
||||||
static Trigger* heroism(PlayerbotAI* botAI) { return new HeroismTrigger(botAI); }
|
static Trigger* heroism(PlayerbotAI* botAI) { return new HeroismTrigger(botAI); }
|
||||||
static Trigger* bloodlust(PlayerbotAI* botAI) { return new BloodlustTrigger(botAI); }
|
static Trigger* bloodlust(PlayerbotAI* botAI) { return new BloodlustTrigger(botAI); }
|
||||||
static Trigger* elemental_mastery(PlayerbotAI* botAI) { return new ElementalMasteryTrigger(botAI); }
|
static Trigger* elemental_mastery(PlayerbotAI* botAI) { return new ElementalMasteryTrigger(botAI); }
|
||||||
@@ -234,6 +238,7 @@ public:
|
|||||||
creators["lava burst"] = &ShamanAiObjectContextInternal::lava_burst;
|
creators["lava burst"] = &ShamanAiObjectContextInternal::lava_burst;
|
||||||
creators["earth shield on main tank"] = &ShamanAiObjectContextInternal::earth_shield_on_main_tank;
|
creators["earth shield on main tank"] = &ShamanAiObjectContextInternal::earth_shield_on_main_tank;
|
||||||
creators["fire elemental totem"] = &ShamanAiObjectContextInternal::fire_elemental_totem;
|
creators["fire elemental totem"] = &ShamanAiObjectContextInternal::fire_elemental_totem;
|
||||||
|
creators["fire elemental totem melee"] = &ShamanAiObjectContextInternal::fire_elemental_totem_melee;
|
||||||
creators["totem of wrath"] = &ShamanAiObjectContextInternal::totem_of_wrath;
|
creators["totem of wrath"] = &ShamanAiObjectContextInternal::totem_of_wrath;
|
||||||
creators["wrath of air totem"] = &ShamanAiObjectContextInternal::wrath_of_air_totem;
|
creators["wrath of air totem"] = &ShamanAiObjectContextInternal::wrath_of_air_totem;
|
||||||
creators["shamanistic rage"] = &ShamanAiObjectContextInternal::shamanistic_rage;
|
creators["shamanistic rage"] = &ShamanAiObjectContextInternal::shamanistic_rage;
|
||||||
@@ -314,6 +319,7 @@ private:
|
|||||||
static Action* earth_shield_on_main_tank(PlayerbotAI* ai) { return new CastEarthShieldOnMainTankAction(ai); }
|
static Action* earth_shield_on_main_tank(PlayerbotAI* ai) { return new CastEarthShieldOnMainTankAction(ai); }
|
||||||
static Action* totem_of_wrath(PlayerbotAI* ai) { return new CastTotemOfWrathAction(ai); }
|
static Action* totem_of_wrath(PlayerbotAI* ai) { return new CastTotemOfWrathAction(ai); }
|
||||||
static Action* fire_elemental_totem(PlayerbotAI* ai) { return new CastFireElementalTotemAction(ai); }
|
static Action* fire_elemental_totem(PlayerbotAI* ai) { return new CastFireElementalTotemAction(ai); }
|
||||||
|
static Action* fire_elemental_totem_melee(PlayerbotAI* ai) { return new CastFireElementalTotemMeleeAction(ai); }
|
||||||
static Action* wrath_of_air_totem(PlayerbotAI* ai) { return new CastWrathOfAirTotemAction(ai); }
|
static Action* wrath_of_air_totem(PlayerbotAI* ai) { return new CastWrathOfAirTotemAction(ai); }
|
||||||
static Action* shamanistic_rage(PlayerbotAI* ai) { return new CastShamanisticRageAction(ai); }
|
static Action* shamanistic_rage(PlayerbotAI* ai) { return new CastShamanisticRageAction(ai); }
|
||||||
static Action* feral_spirit(PlayerbotAI* ai) { return new CastFeralSpiritAction(ai); }
|
static Action* feral_spirit(PlayerbotAI* ai) { return new CastFeralSpiritAction(ai); }
|
||||||
|
|||||||
@@ -241,7 +241,7 @@ public:
|
|||||||
class MaelstromWeaponTrigger : public HasAuraStackTrigger
|
class MaelstromWeaponTrigger : public HasAuraStackTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MaelstromWeaponTrigger(PlayerbotAI* botAI) : HasAuraStackTrigger(botAI, "maelstrom weapon", 5) {}
|
MaelstromWeaponTrigger(PlayerbotAI* botAI, int stack = 5) : HasAuraStackTrigger(botAI, "maelstrom weapon", stack) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class WindShearInterruptEnemyHealerSpellTrigger : public InterruptEnemyHealerTrigger
|
class WindShearInterruptEnemyHealerSpellTrigger : public InterruptEnemyHealerTrigger
|
||||||
|
|||||||
@@ -13,20 +13,13 @@ void TotemsShamanStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
{
|
{
|
||||||
GenericShamanStrategy::InitTriggers(triggers);
|
GenericShamanStrategy::InitTriggers(triggers);
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("fire elemental totem",
|
|
||||||
NextAction::array(0, new NextAction("fire elemental totem", 32.0f), nullptr)));
|
|
||||||
|
|
||||||
triggers.push_back(
|
triggers.push_back(
|
||||||
new TriggerNode("no air totem", NextAction::array(0, new NextAction("wrath of air totem", 8.0f), NULL)));
|
new TriggerNode("no air totem", NextAction::array(0, new NextAction("wrath of air totem", 8.0f), nullptr)));
|
||||||
|
|
||||||
triggers.push_back(
|
triggers.push_back(
|
||||||
new TriggerNode("no water totem", NextAction::array(0, new NextAction("mana spring totem", 7.0f),
|
new TriggerNode("no water totem", NextAction::array(0, new NextAction("mana spring totem", 7.0f),
|
||||||
new NextAction("healing stream totem", 6.0f), nullptr)));
|
new NextAction("healing stream totem", 6.0f), nullptr)));
|
||||||
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("no fire totem", NextAction::array(0, new NextAction("flametongue totem", 7.0f),
|
|
||||||
new NextAction("searing totem", 6.0f), nullptr)));
|
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("strength of earth totem",
|
triggers.push_back(new TriggerNode("strength of earth totem",
|
||||||
NextAction::array(0, new NextAction("strength of earth totem", 6.0f), NULL)));
|
NextAction::array(0, new NextAction("strength of earth totem", 6.0f), nullptr)));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,6 +83,17 @@ bool EnergyAvailable::IsActive() { return AI_VALUE2(uint8, "energy", "self targe
|
|||||||
|
|
||||||
bool ComboPointsAvailableTrigger::IsActive() { return AI_VALUE2(uint8, "combo", "current target") >= amount; }
|
bool ComboPointsAvailableTrigger::IsActive() { return AI_VALUE2(uint8, "combo", "current target") >= amount; }
|
||||||
|
|
||||||
|
bool TargetWithComboPointsLowerHealTrigger::IsActive()
|
||||||
|
{
|
||||||
|
Unit* target = AI_VALUE(Unit*, "current target");
|
||||||
|
if (!target || !target->IsAlive() || !target->IsInWorld())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return ComboPointsAvailableTrigger::IsActive() &&
|
||||||
|
(target->GetHealth() / AI_VALUE(float, "estimated group dps")) <= lifeTime;
|
||||||
|
}
|
||||||
|
|
||||||
bool LoseAggroTrigger::IsActive() { return !AI_VALUE2(bool, "has aggro", "current target"); }
|
bool LoseAggroTrigger::IsActive() { return !AI_VALUE2(bool, "has aggro", "current target"); }
|
||||||
|
|
||||||
bool HasAggroTrigger::IsActive() { return AI_VALUE2(bool, "has aggro", "current target"); }
|
bool HasAggroTrigger::IsActive() { return AI_VALUE2(bool, "has aggro", "current target"); }
|
||||||
@@ -221,7 +232,7 @@ bool DebuffTrigger::IsActive()
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return BuffTrigger::IsActive() && (target->GetHealth() / AI_VALUE(float, "expected group dps")) >= needLifeTime;
|
return BuffTrigger::IsActive() && (target->GetHealth() / AI_VALUE(float, "estimated group dps")) >= needLifeTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DebuffOnBossTrigger::IsActive()
|
bool DebuffOnBossTrigger::IsActive()
|
||||||
|
|||||||
@@ -113,6 +113,19 @@ public:
|
|||||||
bool IsActive() override;
|
bool IsActive() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class TargetWithComboPointsLowerHealTrigger : public ComboPointsAvailableTrigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TargetWithComboPointsLowerHealTrigger(PlayerbotAI* ai, int32 combo_point = 5, float lifeTime = 8.0f)
|
||||||
|
: ComboPointsAvailableTrigger(ai, combo_point), lifeTime(lifeTime)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
bool IsActive() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
float lifeTime;
|
||||||
|
};
|
||||||
|
|
||||||
class LoseAggroTrigger : public Trigger
|
class LoseAggroTrigger : public Trigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ public:
|
|||||||
|
|
||||||
creators["combo points available"] = &TriggerContext::ComboPointsAvailable;
|
creators["combo points available"] = &TriggerContext::ComboPointsAvailable;
|
||||||
creators["combo points 3 available"] = &TriggerContext::ComboPoints3Available;
|
creators["combo points 3 available"] = &TriggerContext::ComboPoints3Available;
|
||||||
|
creators["target with combo points almost dead"] = &TriggerContext::target_with_combo_points_almost_dead;
|
||||||
|
|
||||||
creators["medium threat"] = &TriggerContext::MediumThreat;
|
creators["medium threat"] = &TriggerContext::MediumThreat;
|
||||||
|
|
||||||
@@ -309,6 +310,10 @@ private:
|
|||||||
}
|
}
|
||||||
static Trigger* ComboPointsAvailable(PlayerbotAI* botAI) { return new ComboPointsAvailableTrigger(botAI); }
|
static Trigger* ComboPointsAvailable(PlayerbotAI* botAI) { return new ComboPointsAvailableTrigger(botAI); }
|
||||||
static Trigger* ComboPoints3Available(PlayerbotAI* botAI) { return new ComboPointsAvailableTrigger(botAI, 3); }
|
static Trigger* ComboPoints3Available(PlayerbotAI* botAI) { return new ComboPointsAvailableTrigger(botAI, 3); }
|
||||||
|
static Trigger* target_with_combo_points_almost_dead(PlayerbotAI* ai)
|
||||||
|
{
|
||||||
|
return new TargetWithComboPointsLowerHealTrigger(ai, 3, 3.0f);
|
||||||
|
}
|
||||||
static Trigger* MediumThreat(PlayerbotAI* botAI) { return new MediumThreatTrigger(botAI); }
|
static Trigger* MediumThreat(PlayerbotAI* botAI) { return new MediumThreatTrigger(botAI); }
|
||||||
static Trigger* Dead(PlayerbotAI* botAI) { return new DeadTrigger(botAI); }
|
static Trigger* Dead(PlayerbotAI* botAI) { return new DeadTrigger(botAI); }
|
||||||
static Trigger* corpse_near(PlayerbotAI* botAI) { return new CorpseNearTrigger(botAI); }
|
static Trigger* corpse_near(PlayerbotAI* botAI) { return new CorpseNearTrigger(botAI); }
|
||||||
|
|||||||
@@ -36,3 +36,36 @@ Unit* AttackerWithoutAuraTargetValue::Calculate()
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Unit* MeleeAttackerWithoutAuraTargetValue::Calculate()
|
||||||
|
{
|
||||||
|
GuidVector attackers = botAI->GetAiObjectContext()->GetValue<GuidVector>("attackers")->Get();
|
||||||
|
// Unit* target = botAI->GetAiObjectContext()->GetValue<Unit*>("current target")->Get();
|
||||||
|
uint32 max_health = 0;
|
||||||
|
Unit* result = nullptr;
|
||||||
|
for (ObjectGuid const guid : attackers)
|
||||||
|
{
|
||||||
|
Unit* unit = botAI->GetUnit(guid);
|
||||||
|
if (!unit || !unit->IsAlive())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!bot->IsWithinMeleeRange(unit))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (checkArc && !bot->HasInArc(CAST_ANGLE_IN_FRONT, unit))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (unit->GetHealth() < max_health)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!botAI->HasAura(qualifier, unit, false, true))
|
||||||
|
{
|
||||||
|
max_health = unit->GetHealth();
|
||||||
|
result = unit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|||||||
@@ -28,7 +28,9 @@ protected:
|
|||||||
class MeleeAttackerWithoutAuraTargetValue : public AttackerWithoutAuraTargetValue
|
class MeleeAttackerWithoutAuraTargetValue : public AttackerWithoutAuraTargetValue
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MeleeAttackerWithoutAuraTargetValue(PlayerbotAI* botAI) : AttackerWithoutAuraTargetValue(botAI, "melee") {}
|
MeleeAttackerWithoutAuraTargetValue(PlayerbotAI* botAI, bool checkArc = true) : AttackerWithoutAuraTargetValue(botAI, "melee"), checkArc(checkArc) {}
|
||||||
|
Unit* Calculate() override;
|
||||||
|
bool checkArc;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -291,7 +291,7 @@ Unit* DpsTargetValue::Calculate()
|
|||||||
return rti;
|
return rti;
|
||||||
|
|
||||||
// FindLeastHpTargetStrategy strategy(botAI);
|
// FindLeastHpTargetStrategy strategy(botAI);
|
||||||
float dps = AI_VALUE(float, "expected group dps");
|
float dps = AI_VALUE(float, "estimated group dps");
|
||||||
if (botAI->IsCaster(bot))
|
if (botAI->IsCaster(bot))
|
||||||
{
|
{
|
||||||
CasterFindTargetSmartStrategy strategy(botAI, dps);
|
CasterFindTargetSmartStrategy strategy(botAI, dps);
|
||||||
|
|||||||
135
src/strategy/values/EstimatedLifetimeValue.cpp
Normal file
135
src/strategy/values/EstimatedLifetimeValue.cpp
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
#include "EstimatedLifetimeValue.h"
|
||||||
|
|
||||||
|
#include "AiFactory.h"
|
||||||
|
#include "PlayerbotAI.h"
|
||||||
|
#include "PlayerbotAIConfig.h"
|
||||||
|
#include "Playerbots.h"
|
||||||
|
#include "SharedDefines.h"
|
||||||
|
|
||||||
|
float EstimatedLifetimeValue::Calculate()
|
||||||
|
{
|
||||||
|
Unit* target = AI_VALUE(Unit*, qualifier);
|
||||||
|
if (!target || !target->IsAlive())
|
||||||
|
{
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
float dps = AI_VALUE(float, "estimated group dps");
|
||||||
|
bool aoePenalty = AI_VALUE(uint8, "attacker count") >= 3;
|
||||||
|
if (aoePenalty)
|
||||||
|
dps *= 0.75;
|
||||||
|
float res = target->GetHealth() / dps;
|
||||||
|
// bot->Say(target->GetName() + " lifetime: " + std::to_string(res), LANG_UNIVERSAL);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
float EstimatedGroupDpsValue::Calculate()
|
||||||
|
{
|
||||||
|
float totalDps;
|
||||||
|
|
||||||
|
std::vector<Player*> groupPlayer={bot};
|
||||||
|
if (Group* group = bot->GetGroup())
|
||||||
|
{
|
||||||
|
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
|
||||||
|
{
|
||||||
|
Player* member = gref->GetSource();
|
||||||
|
if (member == bot) // calculated
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!member || !member->IsInWorld())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (member->GetMapId() != bot->GetMapId())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (member->GetExactDist(bot) > sPlayerbotAIConfig->sightDistance)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
groupPlayer.push_back(member);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (Player* player : groupPlayer)
|
||||||
|
{
|
||||||
|
float roleMultiplier;
|
||||||
|
if (botAI->IsTank(player))
|
||||||
|
roleMultiplier = 0.3f;
|
||||||
|
else if (botAI->IsHeal(player))
|
||||||
|
roleMultiplier = 0.1f;
|
||||||
|
else
|
||||||
|
roleMultiplier = 1.0f;
|
||||||
|
float basicDps = GetBasicDps(player->GetLevel());
|
||||||
|
float basicGs = GetBasicGs(player->GetLevel());
|
||||||
|
uint32 mixedGearScore = PlayerbotAI::GetMixedGearScore(player, true, false, 12);
|
||||||
|
|
||||||
|
float gap = (float)mixedGearScore / basicGs - 1;
|
||||||
|
float gs_modifier = gap * 3 + 1;
|
||||||
|
if (gs_modifier < 0.75)
|
||||||
|
gs_modifier = 0.75;
|
||||||
|
if (gs_modifier > 4)
|
||||||
|
gs_modifier = 4;
|
||||||
|
totalDps += basicDps * roleMultiplier * gs_modifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
return totalDps;
|
||||||
|
}
|
||||||
|
|
||||||
|
float EstimatedGroupDpsValue::GetBasicDps(uint32 level)
|
||||||
|
{
|
||||||
|
float basic_dps;
|
||||||
|
|
||||||
|
if (level <= 15)
|
||||||
|
{
|
||||||
|
basic_dps = 5 + level * 1;
|
||||||
|
}
|
||||||
|
else if (level <= 25)
|
||||||
|
{
|
||||||
|
basic_dps = 20 + (level - 15) * 2;
|
||||||
|
}
|
||||||
|
else if (level <= 45)
|
||||||
|
{
|
||||||
|
basic_dps = 40 + (level - 25) * 3;
|
||||||
|
}
|
||||||
|
else if (level <= 55)
|
||||||
|
{
|
||||||
|
basic_dps = 100 + (level - 45) * 20;
|
||||||
|
}
|
||||||
|
else if (level <= 60)
|
||||||
|
{
|
||||||
|
basic_dps = 300 + (level - 55) * 50;
|
||||||
|
}
|
||||||
|
else if (level <= 70)
|
||||||
|
{
|
||||||
|
basic_dps = 450 + (level - 60) * 40;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
basic_dps = 750 + (level - 70) * 175;
|
||||||
|
}
|
||||||
|
return basic_dps;
|
||||||
|
}
|
||||||
|
|
||||||
|
float EstimatedGroupDpsValue::GetBasicGs(uint32 level)
|
||||||
|
{
|
||||||
|
float basic_gs;
|
||||||
|
|
||||||
|
if (level <= 8)
|
||||||
|
{
|
||||||
|
basic_gs = (level + 5) * 2;
|
||||||
|
}
|
||||||
|
else if (level <= 15)
|
||||||
|
{
|
||||||
|
basic_gs = (level + 5) * 3;
|
||||||
|
}
|
||||||
|
else if (level <= 60)
|
||||||
|
{
|
||||||
|
basic_gs = (level + 5) * 4;
|
||||||
|
}
|
||||||
|
else if (level <= 70)
|
||||||
|
{
|
||||||
|
basic_gs = (85 + (level - 60) * 3) * 4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
basic_gs = (155 + (level - 70) * 4) * 4;
|
||||||
|
}
|
||||||
|
return basic_gs;
|
||||||
|
}
|
||||||
@@ -3,8 +3,8 @@
|
|||||||
* and/or modify it under version 2 of the License, or (at your option), any later version.
|
* and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _PLAYERBOT_EXPECTEDLIFETIMEVALUE_H
|
#ifndef _PLAYERBOT_EstimatedLifetimeValue_H
|
||||||
#define _PLAYERBOT_EXPECTEDLIFETIMEVALUE_H
|
#define _PLAYERBOT_EstimatedLifetimeValue_H
|
||||||
|
|
||||||
#include "NamedObjectContext.h"
|
#include "NamedObjectContext.h"
|
||||||
#include "PossibleTargetsValue.h"
|
#include "PossibleTargetsValue.h"
|
||||||
@@ -15,22 +15,26 @@ class PlayerbotAI;
|
|||||||
class Unit;
|
class Unit;
|
||||||
|
|
||||||
// [target health] / [expected group single target dps] = [expected lifetime]
|
// [target health] / [expected group single target dps] = [expected lifetime]
|
||||||
class ExpectedLifetimeValue : public FloatCalculatedValue, public Qualified
|
class EstimatedLifetimeValue : public FloatCalculatedValue, public Qualified
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ExpectedLifetimeValue(PlayerbotAI* botAI) : FloatCalculatedValue(botAI, "expected lifetime") {}
|
EstimatedLifetimeValue(PlayerbotAI* botAI) : FloatCalculatedValue(botAI, "estimated lifetime") {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
float Calculate() override;
|
float Calculate() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ExpectedGroupDpsValue : public FloatCalculatedValue
|
class EstimatedGroupDpsValue : public FloatCalculatedValue
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ExpectedGroupDpsValue(PlayerbotAI* botAI) : FloatCalculatedValue(botAI, "expected group dps", 20 * 1000) {}
|
EstimatedGroupDpsValue(PlayerbotAI* botAI) : FloatCalculatedValue(botAI, "estimated group dps", 20 * 1000) {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
float Calculate() override;
|
float Calculate() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
float GetBasicDps(uint32 level);
|
||||||
|
float GetBasicGs(uint32 level);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
#include "ExpectedLifetimeValue.h"
|
|
||||||
|
|
||||||
#include "AiFactory.h"
|
|
||||||
#include "PlayerbotAI.h"
|
|
||||||
#include "Playerbots.h"
|
|
||||||
#include "SharedDefines.h"
|
|
||||||
|
|
||||||
float ExpectedLifetimeValue::Calculate()
|
|
||||||
{
|
|
||||||
Unit* target = AI_VALUE(Unit*, qualifier);
|
|
||||||
if (!target || !target->IsAlive())
|
|
||||||
{
|
|
||||||
return 0.0f;
|
|
||||||
}
|
|
||||||
float dps = AI_VALUE(float, "expected group dps");
|
|
||||||
float res = target->GetHealth() / dps;
|
|
||||||
// bot->Say(target->GetName() + " lifetime: " + std::to_string(res), LANG_UNIVERSAL);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
float ExpectedGroupDpsValue::Calculate()
|
|
||||||
{
|
|
||||||
float dps_num;
|
|
||||||
Group* group = bot->GetGroup();
|
|
||||||
if (!group)
|
|
||||||
{
|
|
||||||
dps_num = 0.7;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dps_num = group->GetMembersCount() * 0.7;
|
|
||||||
}
|
|
||||||
uint32 mixedGearScore = PlayerbotAI::GetMixedGearScore(bot, true, false, 12);
|
|
||||||
// efficiency record based on rare gear level, is there better calculation method?
|
|
||||||
// float dps_efficiency = 1;
|
|
||||||
float basic_dps;
|
|
||||||
int32 basic_gs;
|
|
||||||
int32 level = bot->GetLevel();
|
|
||||||
|
|
||||||
if (level <= 15)
|
|
||||||
{
|
|
||||||
basic_dps = 5 + level * 1;
|
|
||||||
}
|
|
||||||
else if (level <= 25)
|
|
||||||
{
|
|
||||||
basic_dps = 20 + (level - 15) * 2;
|
|
||||||
}
|
|
||||||
else if (level <= 40)
|
|
||||||
{
|
|
||||||
basic_dps = 40 + (level - 30) * 4;
|
|
||||||
}
|
|
||||||
else if (level <= 55)
|
|
||||||
{
|
|
||||||
basic_dps = 100 + (level - 45) * 20;
|
|
||||||
}
|
|
||||||
else if (level <= 60)
|
|
||||||
{
|
|
||||||
basic_dps = 300 + (level - 55) * 50;
|
|
||||||
}
|
|
||||||
else if (level <= 70)
|
|
||||||
{
|
|
||||||
basic_dps = 450 + (level - 60) * 40;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
basic_dps = 750 + (level - 70) * 175;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (level <= 8)
|
|
||||||
{
|
|
||||||
basic_gs = (level + 5) * 2;
|
|
||||||
}
|
|
||||||
else if (level <= 15)
|
|
||||||
{
|
|
||||||
basic_gs = (level + 5) * 3;
|
|
||||||
}
|
|
||||||
else if (level <= 60)
|
|
||||||
{
|
|
||||||
basic_gs = (level + 5) * 4;
|
|
||||||
}
|
|
||||||
else if (level <= 70)
|
|
||||||
{
|
|
||||||
basic_gs = (85 + (level - 60) * 3) * 4;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
basic_gs = (155 + (level - 70) * 4) * 4;
|
|
||||||
}
|
|
||||||
float gap = mixedGearScore - basic_gs;
|
|
||||||
float gs_modifier = (float)mixedGearScore / basic_gs - 1;
|
|
||||||
gs_modifier = gs_modifier * 3 + 1;
|
|
||||||
|
|
||||||
if (gs_modifier < 0.75)
|
|
||||||
gs_modifier = 0.75;
|
|
||||||
if (gs_modifier > 4)
|
|
||||||
gs_modifier = 4;
|
|
||||||
|
|
||||||
return dps_num * basic_dps * gs_modifier;
|
|
||||||
}
|
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
#include "DuelTargetValue.h"
|
#include "DuelTargetValue.h"
|
||||||
#include "EnemyHealerTargetValue.h"
|
#include "EnemyHealerTargetValue.h"
|
||||||
#include "EnemyPlayerValue.h"
|
#include "EnemyPlayerValue.h"
|
||||||
#include "ExpectedLifetimeValue.h"
|
#include "EstimatedLifetimeValue.h"
|
||||||
#include "Formations.h"
|
#include "Formations.h"
|
||||||
#include "GrindTargetValue.h"
|
#include "GrindTargetValue.h"
|
||||||
#include "GroupValues.h"
|
#include "GroupValues.h"
|
||||||
@@ -299,8 +299,8 @@ public:
|
|||||||
creators["boss target"] = &ValueContext::boss_target;
|
creators["boss target"] = &ValueContext::boss_target;
|
||||||
creators["nearest triggers"] = &ValueContext::nearest_triggers;
|
creators["nearest triggers"] = &ValueContext::nearest_triggers;
|
||||||
creators["neglect threat"] = &ValueContext::neglect_threat;
|
creators["neglect threat"] = &ValueContext::neglect_threat;
|
||||||
creators["expected lifetime"] = &ValueContext::expected_lifetime;
|
creators["estimated lifetime"] = &ValueContext::expected_lifetime;
|
||||||
creators["expected group dps"] = &ValueContext::expected_group_dps;
|
creators["estimated group dps"] = &ValueContext::expected_group_dps;
|
||||||
creators["area debuff"] = &ValueContext::area_debuff;
|
creators["area debuff"] = &ValueContext::area_debuff;
|
||||||
creators["nearest trap with damage"] = &ValueContext::nearest_trap_with_damange;
|
creators["nearest trap with damage"] = &ValueContext::nearest_trap_with_damange;
|
||||||
creators["disperse distance"] = &ValueContext::disperse_distance;
|
creators["disperse distance"] = &ValueContext::disperse_distance;
|
||||||
@@ -538,8 +538,8 @@ private:
|
|||||||
static UntypedValue* boss_target(PlayerbotAI* ai) { return new BossTargetValue(ai); }
|
static UntypedValue* boss_target(PlayerbotAI* ai) { return new BossTargetValue(ai); }
|
||||||
static UntypedValue* nearest_triggers(PlayerbotAI* ai) { return new NearestTriggersValue(ai); }
|
static UntypedValue* nearest_triggers(PlayerbotAI* ai) { return new NearestTriggersValue(ai); }
|
||||||
static UntypedValue* neglect_threat(PlayerbotAI* ai) { return new NeglectThreatResetValue(ai); }
|
static UntypedValue* neglect_threat(PlayerbotAI* ai) { return new NeglectThreatResetValue(ai); }
|
||||||
static UntypedValue* expected_lifetime(PlayerbotAI* ai) { return new ExpectedLifetimeValue(ai); }
|
static UntypedValue* expected_lifetime(PlayerbotAI* ai) { return new EstimatedLifetimeValue(ai); }
|
||||||
static UntypedValue* expected_group_dps(PlayerbotAI* ai) { return new ExpectedGroupDpsValue(ai); }
|
static UntypedValue* expected_group_dps(PlayerbotAI* ai) { return new EstimatedGroupDpsValue(ai); }
|
||||||
static UntypedValue* area_debuff(PlayerbotAI* ai) { return new AreaDebuffValue(ai); }
|
static UntypedValue* area_debuff(PlayerbotAI* ai) { return new AreaDebuffValue(ai); }
|
||||||
static UntypedValue* nearest_trap_with_damange(PlayerbotAI* ai) { return new NearestTrapWithDamageValue(ai); }
|
static UntypedValue* nearest_trap_with_damange(PlayerbotAI* ai) { return new NearestTrapWithDamageValue(ai); }
|
||||||
static UntypedValue* disperse_distance(PlayerbotAI* ai) { return new DisperseDistanceValue(ai); }
|
static UntypedValue* disperse_distance(PlayerbotAI* ai) { return new DisperseDistanceValue(ai); }
|
||||||
|
|||||||
Reference in New Issue
Block a user