mirror of
https://github.com/mod-playerbots/mod-playerbots
synced 2025-11-29 15:58:20 +08:00
Merge pull request #509 from liyunfan1223/spell_interruption
Spell interruption
This commit is contained in:
@@ -774,12 +774,12 @@ AiPlayerbot.RandomBotInWorldWithRotationDisabled = 31104000
|
||||
|
||||
AiPlayerbot.PremadeSpecName.1.0 = arms pve
|
||||
AiPlayerbot.PremadeSpecGlyph.1.0 = 43418,43395,43423,43399,49084,43421
|
||||
AiPlayerbot.PremadeSpecLink.1.0.60 = 3022032023335100202012013031241
|
||||
AiPlayerbot.PremadeSpecLink.1.0.80 = 3022032123335100202012013031251-32505010002
|
||||
AiPlayerbot.PremadeSpecLink.1.0.60 = 3022032023335100002012211231241
|
||||
AiPlayerbot.PremadeSpecLink.1.0.80 = 3022032023335100102012213231251-305-2033
|
||||
AiPlayerbot.PremadeSpecName.1.1 = fury pve
|
||||
AiPlayerbot.PremadeSpecGlyph.1.1 = 43418,43395,43414,43399,49084,43432
|
||||
AiPlayerbot.PremadeSpecLink.1.1.60 = -305053000500310053120501351
|
||||
AiPlayerbot.PremadeSpecLink.1.1.80 = 30202300233-305053000500310153120511351
|
||||
AiPlayerbot.PremadeSpecLink.1.1.80 = 32002300233-305053000500310153120511351
|
||||
AiPlayerbot.PremadeSpecName.1.2 = prot pve
|
||||
AiPlayerbot.PremadeSpecGlyph.1.2 = 43424,43395,43425,43399,49084,45793
|
||||
AiPlayerbot.PremadeSpecLink.1.2.60 = --053351225000210521030113321
|
||||
@@ -825,8 +825,8 @@ AiPlayerbot.PremadeSpecLink.3.0.60 = 51200201505112243100511351
|
||||
AiPlayerbot.PremadeSpecLink.3.0.80 = 51200201505112253100531351-015305021
|
||||
AiPlayerbot.PremadeSpecName.3.1 = mm pve
|
||||
AiPlayerbot.PremadeSpecGlyph.3.1 = 42912,43350,42914,43351,43338,45732
|
||||
AiPlayerbot.PremadeSpecLink.3.1.60 = -015305101230013233125031051
|
||||
AiPlayerbot.PremadeSpecLink.3.1.80 = 502-035305101230013233135031351-5000002
|
||||
AiPlayerbot.PremadeSpecLink.3.1.60 = -025315101030013233125031051
|
||||
AiPlayerbot.PremadeSpecLink.3.1.80 = 502-025335101030013233135031351-5000002
|
||||
AiPlayerbot.PremadeSpecName.3.2 = surv pve
|
||||
AiPlayerbot.PremadeSpecGlyph.3.2 = 42912,43350,45731,43351,43338,45732
|
||||
AiPlayerbot.PremadeSpecLink.3.2.60 = --5000032500033330502135201311
|
||||
@@ -910,8 +910,8 @@ AiPlayerbot.PremadeSpecLink.6.1.60 = -32003350332203012300023101351
|
||||
AiPlayerbot.PremadeSpecLink.6.1.80 = -32002350352203012300033101351-230200305003
|
||||
AiPlayerbot.PremadeSpecName.6.2 = unholy pve
|
||||
AiPlayerbot.PremadeSpecGlyph.6.2 = 43542,43673,45804,43544,43672,43549
|
||||
AiPlayerbot.PremadeSpecLink.6.2.60 = --2300303050032152000150213130051
|
||||
AiPlayerbot.PremadeSpecLink.6.2.80 = -320053500002-2300303050032152000150213130051
|
||||
AiPlayerbot.PremadeSpecLink.6.2.60 = --2301303050032151000150013131151
|
||||
AiPlayerbot.PremadeSpecLink.6.2.80 = -320033500002-2301303050032151000150013133151
|
||||
AiPlayerbot.PremadeSpecName.6.3 = double aura blood pve
|
||||
AiPlayerbot.PremadeSpecGlyph.6.3 = 45805,43673,43827,43544,43672,43554
|
||||
AiPlayerbot.PremadeSpecLink.6.3.60 = 005512153330030320102013-305
|
||||
|
||||
@@ -310,24 +310,22 @@ void PlayerbotAI::UpdateAI(uint32 elapsed, bool minimal)
|
||||
bot->SetPower(bot->getPowerType(), bot->GetMaxPower(bot->getPowerType()));
|
||||
}
|
||||
|
||||
if (!CanUpdateAI())
|
||||
return;
|
||||
|
||||
// check activity
|
||||
AllowActivity();
|
||||
|
||||
// if (bot->GetCurrentSpell(CURRENT_CHANNELED_SPELL)) {
|
||||
// return;
|
||||
// }
|
||||
Spell* currentSpell = bot->GetCurrentSpell(CURRENT_GENERIC_SPELL);
|
||||
if (currentSpell && currentSpell->getState() == SPELL_STATE_CASTING && currentSpell->GetCastTime())
|
||||
if (currentSpell && currentSpell->getState() == SPELL_STATE_PREPARING)
|
||||
{
|
||||
nextAICheckDelay = currentSpell->GetCastTime() + sPlayerbotAIConfig->reactDelay;
|
||||
SetNextCheckDelay(nextAICheckDelay);
|
||||
if (!CanUpdateAI())
|
||||
return;
|
||||
if (currentSpell->m_targets.GetUnitTarget() && !currentSpell->m_targets.GetUnitTarget()->IsAlive())
|
||||
{
|
||||
bot->InterruptSpell(CURRENT_GENERIC_SPELL);
|
||||
SetNextCheckDelay(sPlayerbotAIConfig->reactDelay);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!CanUpdateAI())
|
||||
return;
|
||||
|
||||
if (!bot->InBattleground() && !bot->inRandomLfgDungeon() && bot->GetGroup())
|
||||
{
|
||||
Player* leader = bot->GetGroup()->GetLeader();
|
||||
@@ -898,9 +896,9 @@ void PlayerbotAI::HandleBotOutgoingPacket(WorldPacket const& packet)
|
||||
p >> casterGuid.ReadAsPacked();
|
||||
if (casterGuid != bot->GetGUID())
|
||||
return;
|
||||
|
||||
uint8 count, result;
|
||||
uint32 spellId;
|
||||
p >> spellId;
|
||||
p >> count >> spellId >> result;
|
||||
SpellInterrupted(spellId);
|
||||
return;
|
||||
}
|
||||
@@ -1134,21 +1132,15 @@ void PlayerbotAI::HandleBotOutgoingPacket(WorldPacket const& packet)
|
||||
|
||||
void PlayerbotAI::SpellInterrupted(uint32 spellid)
|
||||
{
|
||||
for (uint8 type = CURRENT_MELEE_SPELL; type < CURRENT_CHANNELED_SPELL; type++)
|
||||
{
|
||||
Spell* spell = bot->GetCurrentSpell((CurrentSpellTypes)type);
|
||||
if (!spell)
|
||||
continue;
|
||||
if (spell->GetSpellInfo()->Id == spellid)
|
||||
bot->InterruptSpell((CurrentSpellTypes)type);
|
||||
}
|
||||
LastSpellCast& lastSpell = aiObjectContext->GetValue<LastSpellCast&>("last spell cast")->Get();
|
||||
if (!spellid || lastSpell.id != spellid)
|
||||
return;
|
||||
|
||||
time_t now = time(nullptr);
|
||||
if (now <= lastSpell.timer)
|
||||
return;
|
||||
|
||||
uint32 castTimeSpent = 1000 * (now - lastSpell.timer);
|
||||
int32 globalCooldown = CalculateGlobalCooldown(lastSpell.id);
|
||||
if (static_cast<int32>(castTimeSpent) < globalCooldown)
|
||||
SetNextCheckDelay(globalCooldown - castTimeSpent);
|
||||
else
|
||||
SetNextCheckDelay(sPlayerbotAIConfig->reactDelay);
|
||||
|
||||
lastSpell.id = 0;
|
||||
}
|
||||
|
||||
@@ -1512,14 +1504,15 @@ void PlayerbotAI::ApplyInstanceStrategies(uint32 mapId, bool tellMaster)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (strategyName.empty())
|
||||
return;
|
||||
engines[BOT_STATE_COMBAT]->addStrategy(strategyName);
|
||||
engines[BOT_STATE_NON_COMBAT]->addStrategy(strategyName);
|
||||
if (tellMaster && !strategyName.empty())
|
||||
{
|
||||
std::ostringstream out;
|
||||
out << "Add " << strategyName << " instance strategy";
|
||||
TellMaster(out.str());
|
||||
TellMasterNoFacing(out.str());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3616,6 +3609,7 @@ bool PlayerbotAI::IsInVehicle(bool canControl, bool canCast, bool canAttack, boo
|
||||
|
||||
void PlayerbotAI::WaitForSpellCast(Spell* spell)
|
||||
{
|
||||
return;
|
||||
SpellInfo const* spellInfo = spell->GetSpellInfo();
|
||||
uint32 castTime = spell->GetCastTime();
|
||||
// float castTime = spell->GetCastTime();
|
||||
|
||||
@@ -128,6 +128,7 @@ void PlayerbotHolder::HandlePlayerBotLoginCallback(PlayerbotLoginQueryHolder con
|
||||
allowed = false;
|
||||
out << "Failure: You are not allowed to control bot " << bot->GetName().c_str();
|
||||
}
|
||||
|
||||
if (allowed && masterSession)
|
||||
{
|
||||
Player* player = masterSession->GetPlayer();
|
||||
@@ -145,6 +146,7 @@ void PlayerbotHolder::HandlePlayerBotLoginCallback(PlayerbotLoginQueryHolder con
|
||||
out << "Failure: You have added too many bots for this class";
|
||||
}
|
||||
}
|
||||
|
||||
if (allowed)
|
||||
{
|
||||
sRandomPlayerbotMgr->OnPlayerLogin(bot);
|
||||
@@ -1305,7 +1307,7 @@ uint32 PlayerbotHolder::GetPlayerbotsCountByClass(uint32 cls)
|
||||
for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it)
|
||||
{
|
||||
Player* const bot = it->second;
|
||||
if (bot->getClass() == cls)
|
||||
if (bot && bot->IsInWorld() && bot->getClass() == cls)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
|
||||
@@ -207,7 +207,8 @@ void PlayerbotFactory::Randomize(bool incremental)
|
||||
{
|
||||
ClearAllItems();
|
||||
}
|
||||
// bot->SaveToDB(false, false);
|
||||
bot->RemoveAllSpellCooldown();
|
||||
UnbindInstance();
|
||||
|
||||
bot->GiveLevel(level);
|
||||
bot->InitStatsForLevel();
|
||||
@@ -3880,7 +3881,7 @@ void PlayerbotFactory::ApplyEnchantAndGemsNew(bool destoryOld)
|
||||
}
|
||||
availableGems.push_back(enchantGem);
|
||||
}
|
||||
|
||||
StatsWeightCalculator calculator(bot);
|
||||
for (uint8 slot = 0; slot < EQUIPMENT_SLOT_END; ++slot)
|
||||
{
|
||||
if (slot == EQUIPMENT_SLOT_TABARD || slot == EQUIPMENT_SLOT_BODY)
|
||||
@@ -3940,7 +3941,6 @@ void PlayerbotFactory::ApplyEnchantAndGemsNew(bool destoryOld)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
StatsWeightCalculator calculator(bot);
|
||||
float score = calculator.CalculateEnchant(enchant_id);
|
||||
if (score >= bestScore)
|
||||
{
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include "SpellMgr.h"
|
||||
#include "UpdateFields.h"
|
||||
|
||||
StatsCollector::StatsCollector(CollectorType type) : type_(type) { Reset(); }
|
||||
StatsCollector::StatsCollector(CollectorType type, int32 cls) : type_(type), cls_(cls) { Reset(); }
|
||||
|
||||
void StatsCollector::Reset()
|
||||
{
|
||||
@@ -243,6 +243,18 @@ bool StatsCollector::SpecialSpellFilter(uint32 spellId) {
|
||||
case 67771: // Death's Verdict (heroic)
|
||||
stats[STATS_TYPE_ATTACK_POWER] += 260;
|
||||
return true;
|
||||
case 71406: // Tiny Abomination in a Jar
|
||||
if (cls_ == CLASS_PALADIN)
|
||||
stats[STATS_TYPE_ATTACK_POWER] += 600;
|
||||
else
|
||||
stats[STATS_TYPE_ATTACK_POWER] += 150;
|
||||
return true;
|
||||
case 71545: // Tiny Abomination in a Jar (heroic)
|
||||
if (cls_ == CLASS_PALADIN)
|
||||
stats[STATS_TYPE_ATTACK_POWER] += 800;
|
||||
else
|
||||
stats[STATS_TYPE_ATTACK_POWER] += 200;
|
||||
return true;
|
||||
case 71519: // Deathbringer's Will
|
||||
stats[STATS_TYPE_ATTACK_POWER] += 350;
|
||||
return true;
|
||||
|
||||
@@ -57,7 +57,7 @@ enum CollectorType : uint8
|
||||
class StatsCollector
|
||||
{
|
||||
public:
|
||||
StatsCollector(CollectorType type);
|
||||
StatsCollector(CollectorType type, int32 cls = -1);
|
||||
StatsCollector(StatsCollector& stats) = default;
|
||||
void Reset();
|
||||
void CollectItemStats(ItemTemplate const* proto);
|
||||
@@ -78,6 +78,7 @@ private:
|
||||
|
||||
private:
|
||||
CollectorType type_;
|
||||
uint32 cls_;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -27,10 +27,10 @@ StatsWeightCalculator::StatsWeightCalculator(Player* player) : player_(player)
|
||||
type_ = CollectorType::MELEE;
|
||||
else
|
||||
type_ = CollectorType::RANGED;
|
||||
collector_ = std::make_unique<StatsCollector>(type_);
|
||||
|
||||
cls = player->getClass();
|
||||
tab = AiFactory::GetPlayerSpecTab(player);
|
||||
collector_ = std::make_unique<StatsCollector>(type_, cls);
|
||||
|
||||
|
||||
if (cls == CLASS_DEATH_KNIGHT && tab == DEATHKNIGHT_TAB_UNHOLY)
|
||||
hitOverflowType_ = CollectorType::SPELL;
|
||||
@@ -128,58 +128,58 @@ void StatsWeightCalculator::GenerateBasicWeights(Player* player)
|
||||
|
||||
if (cls == CLASS_HUNTER && (tab == HUNTER_TAB_BEASTMASTER || tab == HUNTER_TAB_SURVIVAL))
|
||||
{
|
||||
stats_weights_[STATS_TYPE_AGILITY] += 2.4f;
|
||||
stats_weights_[STATS_TYPE_AGILITY] += 2.5f;
|
||||
stats_weights_[STATS_TYPE_ATTACK_POWER] += 1.0f;
|
||||
stats_weights_[STATS_TYPE_ARMOR_PENETRATION] += 1.3f;
|
||||
stats_weights_[STATS_TYPE_HIT] += 1.6f;
|
||||
stats_weights_[STATS_TYPE_CRIT] += 1.5f;
|
||||
stats_weights_[STATS_TYPE_HASTE] += 1.4f;
|
||||
stats_weights_[STATS_TYPE_RANGED_DPS] += 5.0f;
|
||||
stats_weights_[STATS_TYPE_ARMOR_PENETRATION] += 1.5f;
|
||||
stats_weights_[STATS_TYPE_HIT] += 1.7f;
|
||||
stats_weights_[STATS_TYPE_CRIT] += 1.4f;
|
||||
stats_weights_[STATS_TYPE_HASTE] += 1.6f;
|
||||
stats_weights_[STATS_TYPE_RANGED_DPS] += 7.5f;
|
||||
}
|
||||
else if (cls == CLASS_HUNTER && tab == HUNTER_TAB_MARKSMANSHIP)
|
||||
{
|
||||
stats_weights_[STATS_TYPE_AGILITY] += 2.2f;
|
||||
stats_weights_[STATS_TYPE_AGILITY] += 2.3f;
|
||||
stats_weights_[STATS_TYPE_ATTACK_POWER] += 1.0f;
|
||||
stats_weights_[STATS_TYPE_ARMOR_PENETRATION] += 2.2f;
|
||||
stats_weights_[STATS_TYPE_ARMOR_PENETRATION] += 2.25f;
|
||||
stats_weights_[STATS_TYPE_HIT] += 2.1f;
|
||||
stats_weights_[STATS_TYPE_CRIT] += 2.0f;
|
||||
stats_weights_[STATS_TYPE_HASTE] += 1.8f;
|
||||
stats_weights_[STATS_TYPE_RANGED_DPS] += 5.0f;
|
||||
stats_weights_[STATS_TYPE_RANGED_DPS] += 10.0f;
|
||||
}
|
||||
else if (cls == CLASS_ROGUE && tab == ROGUE_TAB_COMBAT)
|
||||
{
|
||||
stats_weights_[STATS_TYPE_AGILITY] += 1.8f;
|
||||
stats_weights_[STATS_TYPE_AGILITY] += 1.9f;
|
||||
stats_weights_[STATS_TYPE_STRENGTH] += 1.1f;
|
||||
stats_weights_[STATS_TYPE_ATTACK_POWER] += 1.0f;
|
||||
stats_weights_[STATS_TYPE_ARMOR_PENETRATION] += 1.2f;
|
||||
stats_weights_[STATS_TYPE_HIT] += 2.0f;
|
||||
stats_weights_[STATS_TYPE_CRIT] += 1.6f;
|
||||
stats_weights_[STATS_TYPE_HASTE] += 1.4f;
|
||||
stats_weights_[STATS_TYPE_ARMOR_PENETRATION] += 1.8f;
|
||||
stats_weights_[STATS_TYPE_HIT] += 2.1f;
|
||||
stats_weights_[STATS_TYPE_CRIT] += 1.4f;
|
||||
stats_weights_[STATS_TYPE_HASTE] += 1.7f;
|
||||
stats_weights_[STATS_TYPE_EXPERTISE] += 2.0f;
|
||||
stats_weights_[STATS_TYPE_MELEE_DPS] += 5.0f;
|
||||
stats_weights_[STATS_TYPE_MELEE_DPS] += 7.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_AGILITY] += 2.2f;
|
||||
stats_weights_[STATS_TYPE_STRENGTH] += 2.4f;
|
||||
stats_weights_[STATS_TYPE_ATTACK_POWER] += 1.0f;
|
||||
stats_weights_[STATS_TYPE_ARMOR_PENETRATION] += 2.1f;
|
||||
stats_weights_[STATS_TYPE_ARMOR_PENETRATION] += 2.3f;
|
||||
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;
|
||||
stats_weights_[STATS_TYPE_CRIT] += 1.5f;
|
||||
stats_weights_[STATS_TYPE_HASTE] += 2.1f;
|
||||
stats_weights_[STATS_TYPE_EXPERTISE] += 2.1f;
|
||||
stats_weights_[STATS_TYPE_MELEE_DPS] += 15.0f;
|
||||
}
|
||||
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.5f;
|
||||
stats_weights_[STATS_TYPE_STRENGTH] += 1.1f;
|
||||
stats_weights_[STATS_TYPE_ATTACK_POWER] += 1.0f;
|
||||
stats_weights_[STATS_TYPE_ARMOR_PENETRATION] += 1.0f;
|
||||
stats_weights_[STATS_TYPE_HIT] += 1.6f;
|
||||
stats_weights_[STATS_TYPE_CRIT] += 1.3f;
|
||||
stats_weights_[STATS_TYPE_HASTE] += 1.5f;
|
||||
stats_weights_[STATS_TYPE_EXPERTISE] += 2.0f;
|
||||
stats_weights_[STATS_TYPE_ARMOR_PENETRATION] += 1.2f;
|
||||
stats_weights_[STATS_TYPE_HIT] += 2.1f;
|
||||
stats_weights_[STATS_TYPE_CRIT] += 1.1f;
|
||||
stats_weights_[STATS_TYPE_HASTE] += 1.8f;
|
||||
stats_weights_[STATS_TYPE_EXPERTISE] += 2.1f;
|
||||
stats_weights_[STATS_TYPE_MELEE_DPS] += 5.0f;
|
||||
}
|
||||
else if (cls == CLASS_WARRIOR && tab == WARRIOR_TAB_FURY) // fury
|
||||
@@ -208,70 +208,86 @@ void StatsWeightCalculator::GenerateBasicWeights(Player* player)
|
||||
}
|
||||
else if (cls == CLASS_DEATH_KNIGHT && tab == DEATHKNIGHT_TAB_FROST) // frost dk
|
||||
{
|
||||
stats_weights_[STATS_TYPE_AGILITY] += 1.8f;
|
||||
stats_weights_[STATS_TYPE_STRENGTH] += 2.6f;
|
||||
stats_weights_[STATS_TYPE_AGILITY] += 1.7f;
|
||||
stats_weights_[STATS_TYPE_STRENGTH] += 2.8f;
|
||||
stats_weights_[STATS_TYPE_ATTACK_POWER] += 1.0f;
|
||||
stats_weights_[STATS_TYPE_ARMOR_PENETRATION] += 2.1f;
|
||||
stats_weights_[STATS_TYPE_ARMOR_PENETRATION] += 2.7f;
|
||||
stats_weights_[STATS_TYPE_HIT] += 2.3f;
|
||||
stats_weights_[STATS_TYPE_CRIT] += 2.2f;
|
||||
stats_weights_[STATS_TYPE_HASTE] += 1.8f;
|
||||
stats_weights_[STATS_TYPE_HASTE] += 2.1f;
|
||||
stats_weights_[STATS_TYPE_EXPERTISE] += 2.5f;
|
||||
stats_weights_[STATS_TYPE_MELEE_DPS] += 7.0f;
|
||||
}
|
||||
else if (cls == CLASS_DEATH_KNIGHT && tab == DEATHKNIGHT_TAB_UNHOLY)
|
||||
{
|
||||
stats_weights_[STATS_TYPE_AGILITY] += 0.5f;
|
||||
stats_weights_[STATS_TYPE_AGILITY] += 0.9f;
|
||||
stats_weights_[STATS_TYPE_STRENGTH] += 2.5f;
|
||||
stats_weights_[STATS_TYPE_ATTACK_POWER] += 1.0f;
|
||||
stats_weights_[STATS_TYPE_ARMOR_PENETRATION] += 1.0f;
|
||||
stats_weights_[STATS_TYPE_HIT] += 1.8f;
|
||||
stats_weights_[STATS_TYPE_CRIT] += 1.0f;
|
||||
stats_weights_[STATS_TYPE_HASTE] += 1.7f;
|
||||
stats_weights_[STATS_TYPE_EXPERTISE] += 1.0f;
|
||||
stats_weights_[STATS_TYPE_ARMOR_PENETRATION] += 1.3f;
|
||||
stats_weights_[STATS_TYPE_HIT] += 2.2f;
|
||||
stats_weights_[STATS_TYPE_CRIT] += 1.7f;
|
||||
stats_weights_[STATS_TYPE_HASTE] += 1.8f;
|
||||
stats_weights_[STATS_TYPE_EXPERTISE] += 1.5f;
|
||||
stats_weights_[STATS_TYPE_MELEE_DPS] += 5.0f;
|
||||
}
|
||||
else if (cls == CLASS_PALADIN && tab == PALADIN_TAB_RETRIBUTION) // retribution
|
||||
{
|
||||
stats_weights_[STATS_TYPE_AGILITY] += 1.3f;
|
||||
stats_weights_[STATS_TYPE_AGILITY] += 1.6f;
|
||||
stats_weights_[STATS_TYPE_STRENGTH] += 2.5f;
|
||||
stats_weights_[STATS_TYPE_INTELLECT] += 0.15f;
|
||||
stats_weights_[STATS_TYPE_INTELLECT] += 0.1f;
|
||||
stats_weights_[STATS_TYPE_ATTACK_POWER] += 1.0f;
|
||||
stats_weights_[STATS_TYPE_SPELL_POWER] += 0.3f;
|
||||
stats_weights_[STATS_TYPE_ARMOR_PENETRATION] += 0.7f;
|
||||
stats_weights_[STATS_TYPE_ARMOR_PENETRATION] += 1.5f;
|
||||
stats_weights_[STATS_TYPE_HIT] += 1.9f;
|
||||
stats_weights_[STATS_TYPE_CRIT] += 1.3f;
|
||||
stats_weights_[STATS_TYPE_HASTE] += 1.2f;
|
||||
stats_weights_[STATS_TYPE_CRIT] += 1.7f;
|
||||
stats_weights_[STATS_TYPE_HASTE] += 1.6f;
|
||||
stats_weights_[STATS_TYPE_EXPERTISE] += 2.0f;
|
||||
stats_weights_[STATS_TYPE_MELEE_DPS] += 7.0f;
|
||||
stats_weights_[STATS_TYPE_MELEE_DPS] += 9.0f;
|
||||
}
|
||||
else if ((cls == CLASS_SHAMAN && tab == SHAMAN_TAB_ENHANCEMENT)) // enhancement
|
||||
{
|
||||
stats_weights_[STATS_TYPE_AGILITY] += 1.6f;
|
||||
stats_weights_[STATS_TYPE_AGILITY] += 1.4f;
|
||||
stats_weights_[STATS_TYPE_STRENGTH] += 1.1f;
|
||||
stats_weights_[STATS_TYPE_INTELLECT] += 0.5f;
|
||||
stats_weights_[STATS_TYPE_INTELLECT] += 0.3f;
|
||||
stats_weights_[STATS_TYPE_ATTACK_POWER] += 1.0f;
|
||||
stats_weights_[STATS_TYPE_SPELL_POWER] += 0.9f;
|
||||
stats_weights_[STATS_TYPE_ARMOR_PENETRATION] += 1.2f;
|
||||
stats_weights_[STATS_TYPE_HIT] += 1.7f;
|
||||
stats_weights_[STATS_TYPE_CRIT] += 1.4f;
|
||||
stats_weights_[STATS_TYPE_SPELL_POWER] += 0.95f;
|
||||
stats_weights_[STATS_TYPE_ARMOR_PENETRATION] += 0.9f;
|
||||
stats_weights_[STATS_TYPE_HIT] += 2.1f;
|
||||
stats_weights_[STATS_TYPE_CRIT] += 1.5f;
|
||||
stats_weights_[STATS_TYPE_HASTE] += 1.8f;
|
||||
stats_weights_[STATS_TYPE_EXPERTISE] += 2.0f;
|
||||
stats_weights_[STATS_TYPE_MELEE_DPS] += 8.5f;
|
||||
}
|
||||
else if (cls == CLASS_WARLOCK || cls == CLASS_MAGE ||
|
||||
else if (cls == CLASS_WARLOCK || (cls == CLASS_MAGE && tab != MAGE_TAB_FIRE) ||
|
||||
(cls == CLASS_PRIEST && tab == PRIEST_TAB_SHADOW) || // shadow
|
||||
(cls == CLASS_SHAMAN && tab == SHAMAN_TAB_ELEMENTAL) || // element
|
||||
(cls == CLASS_DRUID && tab == DRUID_TAB_BALANCE)) // balance
|
||||
{
|
||||
stats_weights_[STATS_TYPE_INTELLECT] += 0.5f;
|
||||
stats_weights_[STATS_TYPE_SPIRIT] += 0.4f;
|
||||
stats_weights_[STATS_TYPE_INTELLECT] += 0.3f;
|
||||
stats_weights_[STATS_TYPE_SPIRIT] += 0.6f;
|
||||
stats_weights_[STATS_TYPE_SPELL_POWER] += 1.0f;
|
||||
stats_weights_[STATS_TYPE_SPELL_PENETRATION] += 1.0f;
|
||||
stats_weights_[STATS_TYPE_HIT] += 1.1f;
|
||||
stats_weights_[STATS_TYPE_CRIT] += 0.8f;
|
||||
stats_weights_[STATS_TYPE_HASTE] += 1.0f;
|
||||
stats_weights_[STATS_TYPE_RANGED_DPS] += 1.0f;
|
||||
}
|
||||
else if (cls == CLASS_MAGE && tab == MAGE_TAB_FIRE)
|
||||
{
|
||||
stats_weights_[STATS_TYPE_INTELLECT] += 0.3f;
|
||||
stats_weights_[STATS_TYPE_SPIRIT] += 0.7f;
|
||||
stats_weights_[STATS_TYPE_SPELL_POWER] += 1.0f;
|
||||
stats_weights_[STATS_TYPE_HIT] += 1.2f;
|
||||
stats_weights_[STATS_TYPE_CRIT] += 1.1f;
|
||||
stats_weights_[STATS_TYPE_HASTE] += 0.8f;
|
||||
stats_weights_[STATS_TYPE_RANGED_DPS] += 1.0f;
|
||||
}
|
||||
else if (cls == CLASS_SHAMAN && tab == SHAMAN_TAB_ELEMENTAL)
|
||||
{
|
||||
stats_weights_[STATS_TYPE_INTELLECT] += 0.25f;
|
||||
stats_weights_[STATS_TYPE_SPELL_POWER] += 1.0f;
|
||||
stats_weights_[STATS_TYPE_HIT] += 1.1f;
|
||||
stats_weights_[STATS_TYPE_CRIT] += 0.8f;
|
||||
stats_weights_[STATS_TYPE_HASTE] += 1.0f;
|
||||
}
|
||||
else if ((cls == CLASS_PALADIN && tab == PALADIN_TAB_HOLY) || // holy
|
||||
(cls == CLASS_PRIEST && tab != PRIEST_TAB_SHADOW) || // discipline / holy
|
||||
(cls == CLASS_SHAMAN && tab == SHAMAN_TAB_RESTORATION) || // heal
|
||||
@@ -349,6 +365,8 @@ void StatsWeightCalculator::GenerateAdditionalWeights(Player* player)
|
||||
{
|
||||
if (player->HasAura(34484))
|
||||
stats_weights_[STATS_TYPE_INTELLECT] += 1.1f;
|
||||
if (player->HasAura(56341))
|
||||
stats_weights_[STATS_TYPE_STAMINA] += 0.3f;
|
||||
}
|
||||
else if (cls == CLASS_WARRIOR)
|
||||
{
|
||||
|
||||
@@ -311,7 +311,7 @@ bool ChooseRpgTargetAction::isFollowValid(Player* bot, WorldObject* target)
|
||||
bool ChooseRpgTargetAction::isFollowValid(Player* bot, WorldPosition pos)
|
||||
{
|
||||
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
|
||||
Player* master = botAI->GetGroupMaster();
|
||||
Player* gmaster = botAI->GetGroupMaster();
|
||||
Player* realMaster = botAI->GetMaster();
|
||||
AiObjectContext* context = botAI->GetAiObjectContext();
|
||||
|
||||
@@ -327,30 +327,30 @@ bool ChooseRpgTargetAction::isFollowValid(Player* bot, WorldPosition pos)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!master || bot == master)
|
||||
if (!gmaster || bot == gmaster)
|
||||
return true;
|
||||
|
||||
if (!botAI->HasStrategy("follow", BOT_STATE_NON_COMBAT))
|
||||
return true;
|
||||
|
||||
if (bot->GetDistance(master) > sPlayerbotAIConfig->rpgDistance * 2)
|
||||
if (bot->GetDistance(gmaster) > sPlayerbotAIConfig->rpgDistance * 2)
|
||||
return false;
|
||||
|
||||
Formation* formation = AI_VALUE(Formation*, "formation");
|
||||
float distance = master->GetDistance2d(pos.getX(), pos.getY());
|
||||
float distance = gmaster->GetDistance2d(pos.getX(), pos.getY());
|
||||
|
||||
if (!botAI->HasActivePlayerMaster() && distance < 50.0f)
|
||||
{
|
||||
Player* player = master;
|
||||
if (!master->isMoving() ||
|
||||
Player* player = gmaster;
|
||||
if (gmaster && !gmaster->isMoving() ||
|
||||
PAI_VALUE(WorldPosition, "last long move").distance(pos) < sPlayerbotAIConfig->reactDistance)
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((inDungeon || !master->HasPlayerFlag(PLAYER_FLAGS_RESTING)) && realMaster == master && distance > 5.0f)
|
||||
if ((inDungeon || !gmaster->HasPlayerFlag(PLAYER_FLAGS_RESTING)) && realMaster == gmaster && distance > 5.0f)
|
||||
return false;
|
||||
|
||||
if (!master->isMoving() && distance < 25.0f)
|
||||
if (!gmaster->isMoving() && distance < 25.0f)
|
||||
return true;
|
||||
|
||||
if (distance < formation->GetMaxDistance())
|
||||
|
||||
@@ -162,8 +162,14 @@ bool CastMeleeDebuffSpellAction::isUseful()
|
||||
|
||||
bool CastAuraSpellAction::isUseful()
|
||||
{
|
||||
return GetTarget() && (GetTarget() != nullptr) && CastSpellAction::isUseful() &&
|
||||
!botAI->HasAura(spell, GetTarget(), false, isOwner);
|
||||
if (!GetTarget() || !CastSpellAction::isUseful())
|
||||
return false;
|
||||
Aura* aura = botAI->GetAura(spell, GetTarget(), isOwner, checkDuration);
|
||||
if (!aura)
|
||||
return true;
|
||||
if (beforeDuration && aura->GetDuration() < beforeDuration)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
CastEnchantItemAction::CastEnchantItemAction(PlayerbotAI* botAI, std::string const spell)
|
||||
@@ -251,8 +257,8 @@ Value<Unit*>* CastDebuffSpellOnMeleeAttackerAction::GetTargetValue()
|
||||
return context->GetValue<Unit*>("melee attacker without aura", spell);
|
||||
}
|
||||
|
||||
CastBuffSpellAction::CastBuffSpellAction(PlayerbotAI* botAI, std::string const spell, bool checkIsOwner)
|
||||
: CastAuraSpellAction(botAI, spell, checkIsOwner)
|
||||
CastBuffSpellAction::CastBuffSpellAction(PlayerbotAI* botAI, std::string const spell, bool checkIsOwner, uint32 beforeDuration)
|
||||
: CastAuraSpellAction(botAI, spell, checkIsOwner, false, beforeDuration)
|
||||
{
|
||||
range = botAI->GetRange("spell");
|
||||
}
|
||||
|
||||
@@ -37,16 +37,20 @@ protected:
|
||||
class CastAuraSpellAction : public CastSpellAction
|
||||
{
|
||||
public:
|
||||
CastAuraSpellAction(PlayerbotAI* botAI, std::string const spell, bool isOwner = false)
|
||||
CastAuraSpellAction(PlayerbotAI* botAI, std::string const spell, bool isOwner = false, bool checkDuration = false, uint32 beforeDuration = 0)
|
||||
: CastSpellAction(botAI, spell)
|
||||
{
|
||||
this->isOwner = isOwner;
|
||||
this->beforeDuration = beforeDuration;
|
||||
this->checkDuration = checkDuration;
|
||||
}
|
||||
|
||||
bool isUseful() override;
|
||||
|
||||
protected:
|
||||
bool isOwner;
|
||||
bool checkDuration;
|
||||
uint32 beforeDuration;
|
||||
};
|
||||
|
||||
class CastMeleeSpellAction : public CastSpellAction
|
||||
@@ -107,7 +111,7 @@ public:
|
||||
class CastBuffSpellAction : public CastAuraSpellAction
|
||||
{
|
||||
public:
|
||||
CastBuffSpellAction(PlayerbotAI* botAI, std::string const spell, bool checkIsOwner = false);
|
||||
CastBuffSpellAction(PlayerbotAI* botAI, std::string const spell, bool checkIsOwner = false, uint32 beforeDuration = 0);
|
||||
|
||||
std::string const GetTargetName() override { return "self target"; }
|
||||
};
|
||||
|
||||
@@ -814,39 +814,25 @@ bool MovementAction::ReachCombatTo(Unit* target, float distance)
|
||||
float combatDistance = bot->GetCombatReach() + target->GetCombatReach();
|
||||
distance += combatDistance;
|
||||
|
||||
if (target->HasUnitMovementFlag(MOVEMENTFLAG_FORWARD)) // target is moving forward, predict the position
|
||||
{
|
||||
float needToGo = bot->GetExactDist(target) - distance;
|
||||
float timeToGo = MoveDelay(abs(needToGo)) + sPlayerbotAIConfig->reactDelay / 1000.0f;
|
||||
float targetMoveDist = timeToGo * target->GetSpeed(MOVE_RUN);
|
||||
targetMoveDist = std::min(5.0f, targetMoveDist);
|
||||
tx += targetMoveDist * cos(target->GetOrientation());
|
||||
ty += targetMoveDist * sin(target->GetOrientation());
|
||||
if (!target->GetMap()->CheckCollisionAndGetValidCoords(target, target->GetPositionX(), target->GetPositionY(),
|
||||
target->GetPositionZ(), tx, ty, tz))
|
||||
{
|
||||
// disable prediction if position is invalid
|
||||
tx = target->GetPositionX();
|
||||
ty = target->GetPositionY();
|
||||
tz = target->GetPositionZ();
|
||||
}
|
||||
// Prediction may cause this, which makes ShortenPathUntilDist fail
|
||||
if (bot->GetExactDist(tx, ty, tz) <= distance)
|
||||
{
|
||||
tx = target->GetPositionX();
|
||||
ty = target->GetPositionY();
|
||||
tz = target->GetPositionZ();
|
||||
}
|
||||
}
|
||||
if (bot->GetExactDist(tx, ty, tz) <= distance)
|
||||
return false;
|
||||
|
||||
PathGenerator path(bot);
|
||||
path.CalculatePath(tx, ty, tz, false);
|
||||
PathType type = path.GetPathType();
|
||||
int typeOk = PATHFIND_NORMAL | PATHFIND_INCOMPLETE;
|
||||
if (!(type & typeOk))
|
||||
return false;
|
||||
path.ShortenPathUntilDist(G3D::Vector3(tx, ty, tz), distance);
|
||||
float shortenTo = distance;
|
||||
|
||||
// Avoid walking too far when moving towards each other
|
||||
if (bot->GetDistance(tx, ty, tz) >= 10.0f)
|
||||
shortenTo = std::max(distance, bot->GetDistance(tx, ty, tz) / 2);
|
||||
|
||||
if (bot->GetExactDist(tx, ty, tz) <= shortenTo)
|
||||
return false;
|
||||
|
||||
path.ShortenPathUntilDist(G3D::Vector3(tx, ty, tz), shortenTo);
|
||||
G3D::Vector3 endPos = path.GetPath().back();
|
||||
return MoveTo(target->GetMapId(), endPos.x, endPos.y, endPos.z, false, false, false, false,
|
||||
MovementPriority::MOVEMENT_COMBAT);
|
||||
|
||||
@@ -29,13 +29,14 @@ bool TellAttackersAction::Execute(Event event)
|
||||
botAI->TellMaster("--- Attackers ---");
|
||||
|
||||
GuidVector attackers = context->GetValue<GuidVector>("attackers")->Get();
|
||||
int32 count = 0;
|
||||
for (ObjectGuid const guid : attackers)
|
||||
{
|
||||
Unit* unit = botAI->GetUnit(guid);
|
||||
if (!unit || !unit->IsAlive())
|
||||
continue;
|
||||
|
||||
botAI->TellMaster(unit->GetName());
|
||||
botAI->TellMaster(std::to_string(++count) + std::string(".") + unit->GetName());
|
||||
}
|
||||
|
||||
botAI->TellMaster("--- Threat ---");
|
||||
|
||||
@@ -165,16 +165,10 @@ bool SummonAction::SummonUsingNpcs(Player* summoner, Player* player)
|
||||
|
||||
bool SummonAction::Teleport(Player* summoner, Player* player)
|
||||
{
|
||||
Player* master = GetMaster();
|
||||
// if (master->GetMap() && master->GetMap()->IsDungeon()) {
|
||||
// InstanceMap* map = master->GetMap()->ToInstanceMap();
|
||||
// if (map) {
|
||||
// if (map->CannotEnter(player, true) == Map::CANNOT_ENTER_MAX_PLAYERS) {
|
||||
// botAI->TellError("I can not enter this dungeon");
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// Player* master = GetMaster();
|
||||
if (!summoner)
|
||||
return false;
|
||||
|
||||
if (player->GetVehicle())
|
||||
{
|
||||
botAI->TellError("You cannot summon me while I'm on a vehicle");
|
||||
@@ -197,13 +191,13 @@ bool SummonAction::Teleport(Player* summoner, Player* player)
|
||||
->botRepairWhenSummon) // .conf option to repair bot gear when summoned 0 = off, 1 = on
|
||||
bot->DurabilityRepairAll(false, 1.0f, false);
|
||||
|
||||
if (master->IsInCombat() && !sPlayerbotAIConfig->allowSummonInCombat)
|
||||
if (summoner->IsInCombat() && !sPlayerbotAIConfig->allowSummonInCombat)
|
||||
{
|
||||
botAI->TellError("You cannot summon me while you're in combat");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!master->IsAlive() && !sPlayerbotAIConfig->allowSummonWhenMasterIsDead)
|
||||
if (!summoner->IsAlive() && !sPlayerbotAIConfig->allowSummonWhenMasterIsDead)
|
||||
{
|
||||
botAI->TellError("You cannot summon me while you're dead");
|
||||
return false;
|
||||
@@ -218,7 +212,7 @@ bool SummonAction::Teleport(Player* summoner, Player* player)
|
||||
|
||||
bool revive =
|
||||
sPlayerbotAIConfig->reviveBotWhenSummoned == 2 ||
|
||||
(sPlayerbotAIConfig->reviveBotWhenSummoned == 1 && !master->IsInCombat() && master->IsAlive());
|
||||
(sPlayerbotAIConfig->reviveBotWhenSummoned == 1 && !summoner->IsInCombat() && summoner->IsAlive());
|
||||
|
||||
if (bot->isDead() && revive)
|
||||
{
|
||||
|
||||
@@ -100,9 +100,12 @@ void BloodDKStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
triggers.push_back(
|
||||
new TriggerNode("lose aggro", NextAction::array(0, new NextAction("dark command", ACTION_HIGH + 3), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("low health", NextAction::array(0, new NextAction("army of the dead", ACTION_HIGH + 5),
|
||||
new NextAction("vampiric blood", ACTION_HIGH + 4),
|
||||
new TriggerNode("low health", NextAction::array(0, new NextAction("army of the dead", ACTION_HIGH + 4),
|
||||
new NextAction("death strike", ACTION_HIGH + 3), nullptr)));
|
||||
// triggers.push_back(new TriggerNode("army of the dead", NextAction::array(0, new NextAction("army of the dead",
|
||||
// ACTION_HIGH + 6), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("critical health", NextAction::array(0, new NextAction("vampiric blood", ACTION_HIGH + 5), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("icy touch", NextAction::array(0, new NextAction("icy touch", ACTION_HIGH + 2), nullptr)));
|
||||
triggers.push_back(new TriggerNode(
|
||||
"plague strike", NextAction::array(0, new NextAction("plague strike", ACTION_HIGH + 2), nullptr)));
|
||||
}
|
||||
|
||||
@@ -165,7 +165,7 @@ public:
|
||||
class CastGhoulFrenzyAction : public CastBuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastGhoulFrenzyAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "ghoul frenzy") {}
|
||||
CastGhoulFrenzyAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "ghoul frenzy", false, 5000) {}
|
||||
std::string const GetTargetName() override { return "pet target"; }
|
||||
};
|
||||
|
||||
@@ -242,7 +242,7 @@ class CastDeathAndDecayAction : public CastSpellAction
|
||||
{
|
||||
public:
|
||||
CastDeathAndDecayAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "death and decay") {}
|
||||
ActionThreatType getThreatType() override { return ActionThreatType::Aoe; }
|
||||
// ActionThreatType getThreatType() override { return ActionThreatType::Aoe; }
|
||||
};
|
||||
|
||||
class CastHornOfWinterAction : public CastSpellAction
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "DKTriggers.h"
|
||||
#include "FrostDKStrategy.h"
|
||||
#include "GenericDKNonCombatStrategy.h"
|
||||
#include "GenericTriggers.h"
|
||||
#include "Playerbots.h"
|
||||
#include "PullStrategy.h"
|
||||
#include "UnholyDKStrategy.h"
|
||||
@@ -73,10 +74,14 @@ public:
|
||||
creators["plague strike"] = &DeathKnightTriggerFactoryInternal::plague_strike;
|
||||
creators["plague strike on attacker"] = &DeathKnightTriggerFactoryInternal::plague_strike_on_attacker;
|
||||
creators["icy touch"] = &DeathKnightTriggerFactoryInternal::icy_touch;
|
||||
creators["icy touch 8s"] = &DeathKnightTriggerFactoryInternal::icy_touch_8s;
|
||||
creators["dd cd and icy touch 8s"] = &DeathKnightTriggerFactoryInternal::dd_cd_and_icy_touch_8s;
|
||||
creators["death coil"] = &DeathKnightTriggerFactoryInternal::death_coil;
|
||||
creators["icy touch on attacker"] = &DeathKnightTriggerFactoryInternal::icy_touch_on_attacker;
|
||||
creators["improved icy talons"] = &DeathKnightTriggerFactoryInternal::improved_icy_talons;
|
||||
creators["plague strike"] = &DeathKnightTriggerFactoryInternal::plague_strike;
|
||||
creators["plague strike 8s"] = &DeathKnightTriggerFactoryInternal::plague_strike_8s;
|
||||
creators["dd cd and plague strike 8s"] = &DeathKnightTriggerFactoryInternal::dd_cd_and_plague_strike_8s;
|
||||
creators["horn of winter"] = &DeathKnightTriggerFactoryInternal::horn_of_winter;
|
||||
creators["mind freeze"] = &DeathKnightTriggerFactoryInternal::mind_freeze;
|
||||
creators["mind freeze on enemy healer"] = &DeathKnightTriggerFactoryInternal::mind_freeze_on_enemy_healer;
|
||||
@@ -87,8 +92,11 @@ public:
|
||||
creators["chains of ice"] = &DeathKnightTriggerFactoryInternal::chains_of_ice;
|
||||
creators["unbreakable armor"] = &DeathKnightTriggerFactoryInternal::unbreakable_armor;
|
||||
creators["high blood rune"] = &DeathKnightTriggerFactoryInternal::high_blood_rune;
|
||||
creators["high frost rune"] = &DeathKnightTriggerFactoryInternal::high_frost_rune;
|
||||
creators["high unholy rune"] = &DeathKnightTriggerFactoryInternal::high_unholy_rune;
|
||||
creators["freezing fog"] = &DeathKnightTriggerFactoryInternal::freezing_fog;
|
||||
creators["no desolation"] = &DeathKnightTriggerFactoryInternal::no_desolation;
|
||||
creators["dd cd and no desolation"] = &DeathKnightTriggerFactoryInternal::dd_cd_and_no_desolation;
|
||||
creators["death and decay cooldown"] = &DeathKnightTriggerFactoryInternal::death_and_decay_cooldown;
|
||||
creators["army of the dead"] = &DeathKnightTriggerFactoryInternal::army_of_the_dead;
|
||||
}
|
||||
@@ -98,11 +106,15 @@ private:
|
||||
static Trigger* pestilence_glyph(PlayerbotAI* botAI) { return new PestilenceGlyphTrigger(botAI); }
|
||||
static Trigger* blood_strike(PlayerbotAI* botAI) { return new BloodStrikeTrigger(botAI); }
|
||||
static Trigger* plague_strike(PlayerbotAI* botAI) { return new PlagueStrikeDebuffTrigger(botAI); }
|
||||
static Trigger* plague_strike_8s(PlayerbotAI* botAI) { return new PlagueStrike8sDebuffTrigger(botAI); }
|
||||
static Trigger* dd_cd_and_plague_strike_8s(PlayerbotAI* botAI) { return new TwoTriggers(botAI, "death and decay cooldown", "plague strike 8s"); }
|
||||
static Trigger* plague_strike_on_attacker(PlayerbotAI* botAI)
|
||||
{
|
||||
return new PlagueStrikeDebuffOnAttackerTrigger(botAI);
|
||||
}
|
||||
static Trigger* icy_touch(PlayerbotAI* botAI) { return new IcyTouchDebuffTrigger(botAI); }
|
||||
static Trigger* icy_touch_8s(PlayerbotAI* botAI) { return new IcyTouch8sDebuffTrigger(botAI); }
|
||||
static Trigger* dd_cd_and_icy_touch_8s(PlayerbotAI* botAI) { return new TwoTriggers(botAI, "death and decay cooldown", "icy touch 8s"); }
|
||||
static Trigger* death_coil(PlayerbotAI* botAI) { return new DeathCoilTrigger(botAI); }
|
||||
static Trigger* icy_touch_on_attacker(PlayerbotAI* botAI) { return new IcyTouchDebuffOnAttackerTrigger(botAI); }
|
||||
static Trigger* improved_icy_talons(PlayerbotAI* botAI) { return new ImprovedIcyTalonsTrigger(botAI); }
|
||||
@@ -122,8 +134,11 @@ private:
|
||||
static Trigger* chains_of_ice(PlayerbotAI* botAI) { return new ChainsOfIceSnareTrigger(botAI); }
|
||||
static Trigger* unbreakable_armor(PlayerbotAI* botAI) { return new UnbreakableArmorTrigger(botAI); }
|
||||
static Trigger* high_blood_rune(PlayerbotAI* botAI) { return new HighBloodRuneTrigger(botAI); }
|
||||
static Trigger* high_frost_rune(PlayerbotAI* botAI) { return new HighFrostRuneTrigger(botAI); }
|
||||
static Trigger* high_unholy_rune(PlayerbotAI* botAI) { return new HighUnholyRuneTrigger(botAI); }
|
||||
static Trigger* freezing_fog(PlayerbotAI* botAI) { return new FreezingFogTrigger(botAI); }
|
||||
static Trigger* no_desolation(PlayerbotAI* botAI) { return new DesolationTrigger(botAI); }
|
||||
static Trigger* dd_cd_and_no_desolation(PlayerbotAI* botAI) { return new TwoTriggers(botAI, "death and decay cooldown", "no desolation"); }
|
||||
static Trigger* death_and_decay_cooldown(PlayerbotAI* botAI) { return new DeathAndDecayCooldownTrigger(botAI); }
|
||||
static Trigger* army_of_the_dead(PlayerbotAI* botAI) { return new ArmyOfTheDeadTrigger(botAI); }
|
||||
};
|
||||
|
||||
@@ -39,14 +39,21 @@ bool PestilenceGlyphTrigger::IsActive()
|
||||
|
||||
bool HighBloodRuneTrigger::IsActive()
|
||||
{
|
||||
// bot->Say(std::to_string(bot->GetBaseRune(0)) + "_" + std::to_string(bot->GetRuneCooldown(0)) + " " +
|
||||
// std::to_string(bot->GetBaseRune(1)) + "_" + std::to_string(bot->GetRuneCooldown(1)), LANG_UNIVERSAL);
|
||||
return !bot->GetRuneCooldown(0) && !bot->GetRuneCooldown(1);
|
||||
}
|
||||
|
||||
bool HighFrostRuneTrigger::IsActive()
|
||||
{
|
||||
return !bot->GetRuneCooldown(2) && !bot->GetRuneCooldown(3);
|
||||
}
|
||||
|
||||
bool HighUnholyRuneTrigger::IsActive()
|
||||
{
|
||||
return !bot->GetRuneCooldown(4) && !bot->GetRuneCooldown(5);
|
||||
}
|
||||
bool DesolationTrigger::IsActive()
|
||||
{
|
||||
return bot->HasAura(66817) && !botAI->HasAura("desolation", GetTarget(), false, true, -1, true);
|
||||
return bot->HasAura(66817) && BuffTrigger::IsActive();
|
||||
}
|
||||
|
||||
bool DeathAndDecayCooldownTrigger::IsActive()
|
||||
@@ -55,5 +62,5 @@ bool DeathAndDecayCooldownTrigger::IsActive()
|
||||
if (!spellId)
|
||||
return true;
|
||||
|
||||
return bot->HasSpellCooldown(spellId);
|
||||
return bot->GetSpellCooldownDelay(spellId) >= 3000;
|
||||
}
|
||||
@@ -17,14 +17,26 @@ BUFF_TRIGGER(ImprovedIcyTalonsTrigger, "improved icy talons");
|
||||
class PlagueStrikeDebuffTrigger : public DebuffTrigger
|
||||
{
|
||||
public:
|
||||
PlagueStrikeDebuffTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "blood plague", true, .0f) {}
|
||||
PlagueStrikeDebuffTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "blood plague", 1, true, .0f) {}
|
||||
};
|
||||
|
||||
class PlagueStrike8sDebuffTrigger : public DebuffTrigger
|
||||
{
|
||||
public:
|
||||
PlagueStrike8sDebuffTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "blood plague", 1, true, .0f, 3000) {}
|
||||
};
|
||||
|
||||
// DEBUFF_CHECKISOWNER_TRIGGER(IcyTouchDebuffTrigger, "frost fever");
|
||||
class IcyTouchDebuffTrigger : public DebuffTrigger
|
||||
{
|
||||
public:
|
||||
IcyTouchDebuffTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "frost fever", true, .0f) {}
|
||||
IcyTouchDebuffTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "frost fever", 1, true, .0f) {}
|
||||
};
|
||||
|
||||
class IcyTouch8sDebuffTrigger : public DebuffTrigger
|
||||
{
|
||||
public:
|
||||
IcyTouch8sDebuffTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "frost fever", 1, true, .0f, 3000) {}
|
||||
};
|
||||
|
||||
BUFF_TRIGGER(UnbreakableArmorTrigger, "unbreakable armor");
|
||||
@@ -139,6 +151,20 @@ public:
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class HighFrostRuneTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
HighFrostRuneTrigger(PlayerbotAI* botAI) : Trigger(botAI, "high frost rune") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class HighUnholyRuneTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
HighUnholyRuneTrigger(PlayerbotAI* botAI) : Trigger(botAI, "high unholy rune") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class FreezingFogTrigger : public HasAuraTrigger
|
||||
{
|
||||
public:
|
||||
@@ -148,7 +174,7 @@ public:
|
||||
class DesolationTrigger : public BuffTrigger
|
||||
{
|
||||
public:
|
||||
DesolationTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "desolation") {}
|
||||
DesolationTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "desolation", 1, false, true, 10000) {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ public:
|
||||
// creators["icebound fortitude"] = &icebound_fortitude;
|
||||
// creators["mind freeze"] = &mind_freeze;
|
||||
// creators["hungering cold"] = &hungering_cold;
|
||||
// creators["unbreakable armor"] = &unbreakable_armor;
|
||||
creators["unbreakable armor"] = &unbreakable_armor;
|
||||
// creators["improved icy talons"] = &improved_icy_talons;
|
||||
}
|
||||
|
||||
@@ -70,6 +70,13 @@ private:
|
||||
/*A*/ nullptr,
|
||||
/*C*/ nullptr);
|
||||
}
|
||||
static ActionNode* unbreakable_armor([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("unbreakable armor",
|
||||
/*P*/ NextAction::array(0, new NextAction("blood tap"), nullptr),
|
||||
/*A*/ nullptr,
|
||||
/*C*/ nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
FrostDKStrategy::FrostDKStrategy(PlayerbotAI* botAI) : GenericDKStrategy(botAI)
|
||||
@@ -80,24 +87,32 @@ FrostDKStrategy::FrostDKStrategy(PlayerbotAI* botAI) : GenericDKStrategy(botAI)
|
||||
NextAction** FrostDKStrategy::getDefaultActions()
|
||||
{
|
||||
return NextAction::array(
|
||||
0, new NextAction("obliterate", ACTION_DEFAULT + 0.5f), new NextAction("frost strike", ACTION_DEFAULT + 0.4f),
|
||||
// new NextAction("death strike", ACTION_NORMAL + 3),
|
||||
new NextAction("empower rune weapon", ACTION_DEFAULT + 0.2f),
|
||||
0, new NextAction("obliterate", ACTION_DEFAULT + 0.7f),
|
||||
new NextAction("frost strike", ACTION_DEFAULT + 0.4f),
|
||||
new NextAction("empower rune weapon", ACTION_DEFAULT + 0.3f),
|
||||
new NextAction("horn of winter", ACTION_DEFAULT + 0.1f), new NextAction("melee", ACTION_DEFAULT), NULL);
|
||||
}
|
||||
|
||||
void FrostDKStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
GenericDKStrategy::InitTriggers(triggers);
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"unbreakable armor", NextAction::array(0, new NextAction("unbreakable armor", ACTION_DEFAULT + 0.6f), nullptr)));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"freezing fog", NextAction::array(0, new NextAction("howling blast", ACTION_DEFAULT + 0.5f), nullptr)));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"high blood rune", NextAction::array(0, new NextAction("blood strike", ACTION_DEFAULT + 0.2f), nullptr)));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"army of the dead", NextAction::array(0, new NextAction("army of the dead", ACTION_HIGH + 6), nullptr)));
|
||||
triggers.push_back(new TriggerNode(
|
||||
"unbreakable armor", NextAction::array(0, new NextAction("unbreakable armor", ACTION_NORMAL + 4), nullptr)));
|
||||
triggers.push_back(new TriggerNode(
|
||||
"high blood rune", NextAction::array(0, new NextAction("blood strike", ACTION_NORMAL + 1), nullptr)));
|
||||
triggers.push_back(new TriggerNode(
|
||||
"freezing fog", NextAction::array(0, new NextAction("howling blast", ACTION_HIGH + 1), nullptr)));
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("icy touch", NextAction::array(0, new NextAction("icy touch", ACTION_HIGH + 2), nullptr)));
|
||||
triggers.push_back(new TriggerNode(
|
||||
"plague strike", NextAction::array(0, new NextAction("plague strike", ACTION_HIGH + 2), nullptr)));
|
||||
// triggers.push_back(new TriggerNode("empower rune weapon", NextAction::array(0, new NextAction("empower rune
|
||||
// weapon", ACTION_NORMAL + 4), nullptr)));
|
||||
}
|
||||
|
||||
@@ -135,7 +135,7 @@ private:
|
||||
{
|
||||
return new ActionNode("death and decay",
|
||||
/*P*/ nullptr,
|
||||
/*A*/ NextAction::array(0, new NextAction("blood tap"), nullptr),
|
||||
/*A*/ nullptr,
|
||||
/*C*/ nullptr);
|
||||
}
|
||||
|
||||
@@ -176,33 +176,14 @@ void GenericDKStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
triggers.push_back(
|
||||
new TriggerNode("mind freeze on enemy healer",
|
||||
NextAction::array(0, new NextAction("mind freeze on enemy healer", ACTION_HIGH + 1), nullptr)));
|
||||
triggers.push_back(new TriggerNode(
|
||||
"bone shield", NextAction::array(0, new NextAction("bone shield", ACTION_NORMAL + 1), nullptr)));
|
||||
triggers.push_back(new TriggerNode(
|
||||
"horn of winter", NextAction::array(0, new NextAction("horn of winter", ACTION_NORMAL + 1), nullptr)));
|
||||
// triggers.push_back(new TriggerNode("enemy out of melee", NextAction::array(0, new NextAction("reach melee",
|
||||
// ACTION_NORMAL + 8), nullptr)));
|
||||
triggers.push_back(new TriggerNode("critical health",
|
||||
NextAction::array(0, new NextAction("death pact", ACTION_HIGH + 5), nullptr)));
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("low health", NextAction::array(0, new NextAction("icebound fortitude", ACTION_HIGH + 5),
|
||||
new NextAction("rune tap", ACTION_HIGH + 4), nullptr)));
|
||||
triggers.push_back(new TriggerNode("medium health",
|
||||
NextAction::array(0, new NextAction("rune tap", ACTION_NORMAL + 4),
|
||||
new NextAction("death strike", ACTION_NORMAL + 3), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("icy touch", NextAction::array(0, new NextAction("icy touch", ACTION_HIGH + 2), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("icy touch on attacker",
|
||||
NextAction::array(0, new NextAction("icy touch on attacker", ACTION_HIGH + 1), nullptr)));
|
||||
triggers.push_back(new TriggerNode(
|
||||
"plague strike", NextAction::array(0, new NextAction("plague strike", ACTION_HIGH + 2), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("plague strike on attacker",
|
||||
NextAction::array(0, new NextAction("plague strike on attacker", ACTION_HIGH + 1), nullptr)));
|
||||
// triggers.push_back(new TriggerNode("high aoe",
|
||||
// NextAction::array(0,
|
||||
// new NextAction("death and decay", ACTION_NORMAL + 5),
|
||||
// new NextAction("pestilence", ACTION_NORMAL + 4),
|
||||
// new NextAction("blood boil", ACTION_NORMAL + 3), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("medium aoe", NextAction::array(0, new NextAction("death and decay", ACTION_HIGH + 9),
|
||||
new NextAction("pestilence", ACTION_NORMAL + 4),
|
||||
|
||||
@@ -26,7 +26,7 @@ public:
|
||||
// creators["summon gargoyle"] = &army of the dead;
|
||||
// creators["anti magic shell"] = &anti_magic_shell;
|
||||
// creators["anti magic zone"] = &anti_magic_zone;
|
||||
// creators["ghoul frenzy"] = &ghoul_frenzy;
|
||||
creators["ghoul frenzy"] = &ghoul_frenzy;
|
||||
creators["corpse explosion"] = &corpse_explosion;
|
||||
creators["icy touch"] = &icy_touch;
|
||||
}
|
||||
@@ -35,15 +35,21 @@ private:
|
||||
static ActionNode* death_strike([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("death strike",
|
||||
/*P*/ NextAction::array(0, new NextAction("unholy presence"), nullptr),
|
||||
/*P*/ NextAction::array(0, new NextAction("blood presence"), nullptr),
|
||||
/*A*/ nullptr,
|
||||
/*C*/ nullptr);
|
||||
}
|
||||
static ActionNode* ghoul_frenzy([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("ghoul frenzy",
|
||||
/*P*/ NextAction::array(0, new NextAction("blood presence"), nullptr),
|
||||
/*A*/ nullptr,
|
||||
/*C*/ nullptr);
|
||||
}
|
||||
|
||||
static ActionNode* corpse_explosion([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("corpse explosion",
|
||||
/*P*/ NextAction::array(0, new NextAction("unholy presence"), nullptr),
|
||||
/*P*/ NextAction::array(0, new NextAction("blood presence"), nullptr),
|
||||
/*A*/ nullptr,
|
||||
/*C*/ nullptr);
|
||||
}
|
||||
@@ -51,14 +57,14 @@ private:
|
||||
static ActionNode* scourge_strike([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("scourge strike",
|
||||
/*P*/ NextAction::array(0, new NextAction("unholy presence"), nullptr),
|
||||
/*P*/ NextAction::array(0, new NextAction("blood presence"), nullptr),
|
||||
/*A*/ nullptr,
|
||||
/*C*/ nullptr);
|
||||
}
|
||||
static ActionNode* icy_touch([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("icy touch",
|
||||
/*P*/ NextAction::array(0, new NextAction("unholy presence"), nullptr),
|
||||
/*P*/ NextAction::array(0, new NextAction("blood presence"), nullptr),
|
||||
/*A*/ nullptr,
|
||||
/*C*/ nullptr);
|
||||
}
|
||||
@@ -72,29 +78,57 @@ UnholyDKStrategy::UnholyDKStrategy(PlayerbotAI* botAI) : GenericDKStrategy(botAI
|
||||
NextAction** UnholyDKStrategy::getDefaultActions()
|
||||
{
|
||||
return NextAction::array(
|
||||
0, new NextAction("death and decay", ACTION_DEFAULT + 0.5f),
|
||||
new NextAction("horn of winter", ACTION_DEFAULT + 0.4f),
|
||||
new NextAction("summon gargoyle", ACTION_DEFAULT + 0.3f), new NextAction("death coil", ACTION_DEFAULT + 0.2f),
|
||||
new NextAction("scourge strike", ACTION_NORMAL + 0.1f), new NextAction("melee", ACTION_DEFAULT), nullptr);
|
||||
0, new NextAction("death and decay", ACTION_HIGH + 5),
|
||||
new NextAction("summon gargoyle", ACTION_DEFAULT + 0.4f),
|
||||
new NextAction("empower rune weapon", ACTION_DEFAULT + 0.3f),
|
||||
new NextAction("horn of winter", ACTION_DEFAULT + 0.2f),
|
||||
new NextAction("death coil", ACTION_DEFAULT + 0.1f),
|
||||
new NextAction("melee", ACTION_DEFAULT), nullptr);
|
||||
}
|
||||
|
||||
void UnholyDKStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
GenericDKStrategy::InitTriggers(triggers);
|
||||
triggers.push_back(new TriggerNode(
|
||||
"death and decay cooldown", NextAction::array(0,
|
||||
new NextAction("ghoul frenzy", ACTION_DEFAULT + 0.9f),
|
||||
new NextAction("scourge strike", ACTION_DEFAULT + 0.8f),
|
||||
new NextAction("blood boil", ACTION_DEFAULT + 0.7f),
|
||||
new NextAction("icy touch", ACTION_DEFAULT + 0.6f),
|
||||
new NextAction("plague strike", ACTION_DEFAULT + 0.5f),
|
||||
nullptr)));
|
||||
|
||||
triggers.push_back(new TriggerNode("dd cd and no desolation",
|
||||
NextAction::array(0, new NextAction("blood strike", ACTION_DEFAULT + 0.75f), nullptr)));
|
||||
|
||||
// triggers.push_back(
|
||||
// new TriggerNode("icy touch", NextAction::array(0, new NextAction("icy touch", ACTION_HIGH + 2), nullptr)));
|
||||
// triggers.push_back(new TriggerNode(
|
||||
// "plague strike", NextAction::array(0, new NextAction("plague strike", ACTION_HIGH + 1), nullptr)));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"high frost rune", NextAction::array(0,
|
||||
new NextAction("icy touch", ACTION_NORMAL + 3), nullptr)));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"high unholy rune", NextAction::array(0,
|
||||
new NextAction("plague strike", ACTION_NORMAL + 2), nullptr)));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"high blood rune", NextAction::array(0, new NextAction("blood strike", ACTION_NORMAL + 1), nullptr)));
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("dd cd and plague strike 8s", NextAction::array(0, new NextAction("plague strike", ACTION_HIGH + 2), nullptr)));
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("dd cd and icy touch 8s", NextAction::array(0, new NextAction("icy touch", ACTION_HIGH + 1), nullptr)));
|
||||
|
||||
|
||||
// triggers.push_back(new TriggerNode("often", NextAction::array(0, new NextAction(, ACTION_NORMAL + 2), nullptr)));
|
||||
triggers.push_back(new TriggerNode(
|
||||
"army of the dead", NextAction::array(0, new NextAction("army of the dead", ACTION_HIGH + 6), nullptr)));
|
||||
triggers.push_back(new TriggerNode("critical health",
|
||||
NextAction::array(0, new NextAction("death pact", ACTION_HIGH + 5), nullptr)));
|
||||
triggers.push_back(new TriggerNode("no desolation",
|
||||
NextAction::array(0, new NextAction("blood strike", ACTION_HIGH + 4), nullptr)));
|
||||
triggers.push_back(new TriggerNode(
|
||||
"death and decay cooldown", NextAction::array(0, new NextAction("ghoul frenzy", ACTION_NORMAL + 5.0f),
|
||||
new NextAction("scourge strike", ACTION_NORMAL + 4.0f),
|
||||
new NextAction("blood boil", ACTION_NORMAL + 3.0f),
|
||||
new NextAction("icy touch", ACTION_NORMAL + 2.0f),
|
||||
new NextAction("plague strike", ACTION_NORMAL + 1.0f), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("bone shield", NextAction::array(0, new NextAction("bone shield", ACTION_HIGH + 1), nullptr)));
|
||||
}
|
||||
|
||||
void UnholyDKAoeStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
|
||||
@@ -152,7 +152,16 @@ bool OutNumberedTrigger::IsActive()
|
||||
bool BuffTrigger::IsActive()
|
||||
{
|
||||
Unit* target = GetTarget();
|
||||
return SpellTrigger::IsActive() && !botAI->HasAura(spell, target, false, checkIsOwner);
|
||||
if (!target)
|
||||
return false;
|
||||
if (!SpellTrigger::IsActive())
|
||||
return false;
|
||||
Aura* aura = botAI->GetAura(spell, target, checkIsOwner, checkDuration);
|
||||
if (!aura)
|
||||
return true;
|
||||
if (beforeDuration && aura->GetDuration() < beforeDuration)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
Value<Unit*>* BuffOnPartyTrigger::GetTargetValue()
|
||||
|
||||
@@ -308,10 +308,12 @@ public:
|
||||
class BuffTrigger : public SpellTrigger
|
||||
{
|
||||
public:
|
||||
BuffTrigger(PlayerbotAI* botAI, std::string const spell, int32 checkInterval = 1, bool checkIsOwner = false)
|
||||
BuffTrigger(PlayerbotAI* botAI, std::string const spell, int32 checkInterval = 1, bool checkIsOwner = false, bool checkDuration = false, uint32 beforeDuration = 0)
|
||||
: SpellTrigger(botAI, spell, checkInterval)
|
||||
{
|
||||
this->checkIsOwner = checkIsOwner;
|
||||
this->checkDuration = checkDuration;
|
||||
this->beforeDuration = beforeDuration;
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -320,6 +322,8 @@ public:
|
||||
|
||||
protected:
|
||||
bool checkIsOwner;
|
||||
bool checkDuration;
|
||||
uint32 beforeDuration;
|
||||
};
|
||||
|
||||
class BuffOnPartyTrigger : public BuffTrigger
|
||||
@@ -379,8 +383,8 @@ class DebuffTrigger : public BuffTrigger
|
||||
{
|
||||
public:
|
||||
DebuffTrigger(PlayerbotAI* botAI, std::string const spell, int32 checkInterval = 1, bool checkIsOwner = false,
|
||||
float needLifeTime = 8.0f)
|
||||
: BuffTrigger(botAI, spell, checkInterval, checkIsOwner), needLifeTime(needLifeTime)
|
||||
float needLifeTime = 8.0f, uint32 beforeDuration = 0)
|
||||
: BuffTrigger(botAI, spell, checkInterval, checkIsOwner, false, beforeDuration), needLifeTime(needLifeTime)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -46,14 +46,14 @@ WorldLocation ArrowFormation::GetLocationInternal()
|
||||
|
||||
float x = master->GetPositionX() - masterUnit->GetX() + botUnit->GetX();
|
||||
float y = master->GetPositionY() - masterUnit->GetY() + botUnit->GetY();
|
||||
float z = master->GetPositionZ();
|
||||
float z = master->GetPositionZ() + master->GetHoverHeight();
|
||||
if (!master->GetMap()->CheckCollisionAndGetValidCoords(master, master->GetPositionX(), master->GetPositionY(),
|
||||
master->GetPositionZ(), x, y, z))
|
||||
{
|
||||
x = master->GetPositionX() - masterUnit->GetX() + botUnit->GetX();
|
||||
y = master->GetPositionY() - masterUnit->GetY() + botUnit->GetY();
|
||||
z = master->GetPositionZ() + master->GetHoverHeight();
|
||||
z = master->GetMapHeight(x, y, z);
|
||||
master->UpdateAllowedPositionZ(x, y, z);
|
||||
}
|
||||
return WorldLocation(master->GetMapId(), x, y, z);
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ public:
|
||||
CasterFindTargetSmartStrategy(PlayerbotAI* botAI, float dps)
|
||||
: FindTargetStrategy(botAI), dps_(dps), targetExpectedLifeTime(1000000)
|
||||
{
|
||||
result = nullptr;
|
||||
}
|
||||
|
||||
void CheckAttacker(Unit* attacker, ThreatMgr* threatMgr) override
|
||||
@@ -86,13 +87,15 @@ public:
|
||||
{
|
||||
float new_time = new_unit->GetHealth() / dps_;
|
||||
float old_time = old_unit->GetHealth() / dps_;
|
||||
// [5-20] > (5-0] > (20-inf)
|
||||
if (GetIntervalLevel(new_unit) > GetIntervalLevel(old_unit))
|
||||
// [5-30] > (5-0] > (20-inf)
|
||||
int new_level = GetIntervalLevel(new_unit);
|
||||
int old_level = GetIntervalLevel(old_unit);
|
||||
if (new_level != old_level)
|
||||
{
|
||||
return true;
|
||||
return new_level > old_level;
|
||||
}
|
||||
int32_t level = GetIntervalLevel(new_unit);
|
||||
if (level % 10 == 2 || level % 10 == 1)
|
||||
int32_t level = new_level;
|
||||
if (level % 10 == 2 || level % 10 == 0)
|
||||
{
|
||||
return new_time < old_time;
|
||||
}
|
||||
@@ -116,15 +119,15 @@ public:
|
||||
botAI->IsRanged(botAI->GetBot()) ? sPlayerbotAIConfig->spellDistance : sPlayerbotAIConfig->meleeDistance;
|
||||
attackRange += 5.0f;
|
||||
int level = dis < attackRange ? 10 : 0;
|
||||
if (time >= 3 && time <= 20)
|
||||
if (time >= 5 && time <= 30)
|
||||
{
|
||||
return level + 2;
|
||||
}
|
||||
if (time > 20)
|
||||
if (time > 30)
|
||||
{
|
||||
return level + 1;
|
||||
return level;
|
||||
}
|
||||
return level;
|
||||
return level + 1;
|
||||
}
|
||||
|
||||
protected:
|
||||
@@ -176,12 +179,14 @@ public:
|
||||
float new_time = new_unit->GetHealth() / dps_;
|
||||
float old_time = old_unit->GetHealth() / dps_;
|
||||
// [5-20] > (5-0] > (20-inf)
|
||||
if (GetIntervalLevel(new_unit) > GetIntervalLevel(old_unit))
|
||||
int new_level = GetIntervalLevel(new_unit);
|
||||
int old_level = GetIntervalLevel(old_unit);
|
||||
if (new_level != old_level)
|
||||
{
|
||||
return true;
|
||||
return new_level > old_level;
|
||||
}
|
||||
// attack enemy in range and with lowest health
|
||||
int level = GetIntervalLevel(new_unit);
|
||||
int level = new_level;
|
||||
if (level == 10)
|
||||
{
|
||||
return new_time < old_time;
|
||||
@@ -249,12 +254,14 @@ public:
|
||||
float new_time = new_unit->GetHealth() / dps_;
|
||||
float old_time = old_unit->GetHealth() / dps_;
|
||||
// [5-20] > (5-0] > (20-inf)
|
||||
if (GetIntervalLevel(new_unit) > GetIntervalLevel(old_unit))
|
||||
int new_level = GetIntervalLevel(new_unit);
|
||||
int old_level = GetIntervalLevel(old_unit);
|
||||
if (new_level != old_level)
|
||||
{
|
||||
return true;
|
||||
return new_level > old_level;
|
||||
}
|
||||
// attack enemy in range and with lowest health
|
||||
int level = GetIntervalLevel(new_unit);
|
||||
int level = new_level;
|
||||
Player* bot = botAI->GetBot();
|
||||
if (level == 10)
|
||||
{
|
||||
|
||||
@@ -88,7 +88,7 @@ public:
|
||||
float angle = GetFollowAngle();
|
||||
float x = master->GetPositionX() + cos(angle) * range;
|
||||
float y = master->GetPositionY() + sin(angle) * range;
|
||||
float z = master->GetPositionZ();
|
||||
float z = master->GetPositionZ() + master->GetHoverHeight();
|
||||
if (!master->GetMap()->CheckCollisionAndGetValidCoords(master, master->GetPositionX(), master->GetPositionY(),
|
||||
master->GetPositionZ(), x, y, z))
|
||||
{
|
||||
@@ -138,15 +138,14 @@ public:
|
||||
|
||||
float x = master->GetPositionX() + cos(angle) * range + dx;
|
||||
float y = master->GetPositionY() + sin(angle) * range + dy;
|
||||
float z = master->GetPositionZ();
|
||||
z = bot->GetMapHeight(x, y, z + 5.0f);
|
||||
float z = master->GetPositionZ() + master->GetHoverHeight();
|
||||
if (!master->GetMap()->CheckCollisionAndGetValidCoords(
|
||||
master, master->GetPositionX(), master->GetPositionY(), master->GetPositionZ(), x, y, z))
|
||||
{
|
||||
x = master->GetPositionX() + cos(angle) * range + dx;
|
||||
y = master->GetPositionY() + sin(angle) * range + dy;
|
||||
z = master->GetPositionZ() + master->GetHoverHeight();
|
||||
z = master->GetMapHeight(x, y, z);
|
||||
master->UpdateAllowedPositionZ(x, y, z);
|
||||
}
|
||||
// bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bot->GetPositionX(), bot->GetPositionY(),
|
||||
// bot->GetPositionZ(), x, y, z);
|
||||
@@ -155,15 +154,14 @@ public:
|
||||
|
||||
float x = master->GetPositionX() + cos(angle) * range + dx;
|
||||
float y = master->GetPositionY() + sin(angle) * range + dy;
|
||||
float z = master->GetPositionZ();
|
||||
z = bot->GetMapHeight(x, y, z + 5.0f);
|
||||
float z = master->GetPositionZ() + master->GetHoverHeight();
|
||||
if (!master->GetMap()->CheckCollisionAndGetValidCoords(master, master->GetPositionX(), master->GetPositionY(),
|
||||
master->GetPositionZ(), x, y, z))
|
||||
{
|
||||
x = master->GetPositionX() + cos(angle) * range + dx;
|
||||
y = master->GetPositionY() + sin(angle) * range + dy;
|
||||
z = master->GetPositionZ() + master->GetHoverHeight();
|
||||
z = master->GetMapHeight(x, y, z);
|
||||
master->UpdateAllowedPositionZ(x, y, z);
|
||||
}
|
||||
return WorldLocation(master->GetMapId(), x, y, z);
|
||||
}
|
||||
@@ -221,8 +219,8 @@ public:
|
||||
{
|
||||
x = target->GetPositionX() + cos(angle) * range;
|
||||
y = target->GetPositionY() + sin(angle) * range;
|
||||
z = target->GetPositionZ() + target->GetHoverHeight();
|
||||
z = target->GetMapHeight(x, y, z);
|
||||
z = target->GetPositionZ();
|
||||
target->UpdateAllowedPositionZ(x, y, z);
|
||||
}
|
||||
return WorldLocation(bot->GetMapId(), x, y, z);
|
||||
}
|
||||
@@ -389,7 +387,7 @@ public:
|
||||
x = master->GetPositionX() + cos(angle) * range + cos(followAngle) * followRange;
|
||||
y = master->GetPositionY() + sin(angle) * range + sin(followAngle) * followRange;
|
||||
z = master->GetPositionZ() + master->GetHoverHeight();
|
||||
z = master->GetMapHeight(x, y, z);
|
||||
master->UpdateAllowedPositionZ(x, y, z);
|
||||
}
|
||||
return WorldLocation(bot->GetMapId(), minX, minY, z);
|
||||
}
|
||||
@@ -403,7 +401,7 @@ public:
|
||||
x = master->GetPositionX() + cos(angle) * range + cos(followAngle) * followRange;
|
||||
y = master->GetPositionY() + sin(angle) * range + sin(followAngle) * followRange;
|
||||
z = master->GetPositionZ() + master->GetHoverHeight();
|
||||
z = master->GetMapHeight(x, y, z);
|
||||
master->UpdateAllowedPositionZ(x, y, z);
|
||||
}
|
||||
return WorldLocation(bot->GetMapId(), x, y, z);
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ GuidVector NearestTrapWithDamageValue::Calculate()
|
||||
continue;
|
||||
}
|
||||
const SpellInfo* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
||||
if (spellInfo->IsPositive())
|
||||
if (!spellInfo || spellInfo->IsPositive())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -34,8 +34,9 @@ ArmsWarriorStrategy::ArmsWarriorStrategy(PlayerbotAI* botAI) : GenericWarriorStr
|
||||
|
||||
NextAction** ArmsWarriorStrategy::getDefaultActions()
|
||||
{
|
||||
return NextAction::array(0, new NextAction("bladestorm", ACTION_DEFAULT + 0.1f),
|
||||
new NextAction("melee", ACTION_DEFAULT), nullptr);
|
||||
return NextAction::array(0, new NextAction("bladestorm", ACTION_DEFAULT + 0.2f),
|
||||
new NextAction("mortal strike", ACTION_DEFAULT + 0.1f),
|
||||
new NextAction("melee", ACTION_DEFAULT), nullptr);
|
||||
}
|
||||
|
||||
void ArmsWarriorStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
@@ -63,9 +64,8 @@ void ArmsWarriorStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
triggers.push_back(new TriggerNode(
|
||||
"victory rush", NextAction::array(0, new NextAction("victory rush", ACTION_INTERRUPT), nullptr)));
|
||||
triggers.push_back(new TriggerNode(
|
||||
"medium rage available", NextAction::array(0, new NextAction("heroic strike", ACTION_HIGH + 10), nullptr)));
|
||||
/*triggers.push_back(new TriggerNode("high rage available", NextAction::array(0, new NextAction("slam", ACTION_HIGH
|
||||
* + 1), nullptr)));*/
|
||||
"high rage available", NextAction::array(0, new NextAction("heroic strike", ACTION_HIGH + 10), nullptr)));
|
||||
triggers.push_back(new TriggerNode("medium rage available", NextAction::array(0, new NextAction("slam", ACTION_HIGH + 1), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("bloodrage", NextAction::array(0, new NextAction("bloodrage", ACTION_HIGH + 2), nullptr)));
|
||||
triggers.push_back(
|
||||
@@ -75,6 +75,6 @@ void ArmsWarriorStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
"rend on attacker", NextAction::array(0, new NextAction("rend on attacker", ACTION_HIGH + 5), nullptr)));
|
||||
triggers.push_back(new TriggerNode(
|
||||
"critical health", NextAction::array(0, new NextAction("intimidating shout", ACTION_EMERGENCY), nullptr)));
|
||||
triggers.push_back(new TriggerNode("medium rage available",
|
||||
triggers.push_back(new TriggerNode("medium aoe",
|
||||
NextAction::array(0, new NextAction("thunder clap", ACTION_HIGH + 1), nullptr)));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user