Merge pull request #325 from liyunfan1223/dev-20240711

Fix crash caused by dulicate login; Rndbots gear quality configuration
This commit is contained in:
Yunfan Li
2024-07-13 13:42:37 +08:00
committed by GitHub
43 changed files with 195 additions and 110 deletions

View File

@@ -614,11 +614,11 @@ AiPlayerbot.PremadeSpecLink.3.2.80 = -005305101-5000032500033330522135301331
#
AiPlayerbot.PremadeSpecName.4.0 = as pve
AiPlayerbot.PremadeSpecGlyph.4.0 = 45768,43379,45761,43380,43378,45767
AiPlayerbot.PremadeSpecGlyph.4.0 = 45768,43379,45761,43380,43378,45766
AiPlayerbot.PremadeSpecLink.4.0.60 = 005323005350100520103331051
AiPlayerbot.PremadeSpecLink.4.0.80 = 005323005350100520103331051-005005005003-2
AiPlayerbot.PremadeSpecName.4.1 = combat pve
AiPlayerbot.PremadeSpecGlyph.4.1 = 45762,43379,45767,43380,43378,45766
AiPlayerbot.PremadeSpecGlyph.4.1 = 42962,43379,45762,43380,43378,42969
AiPlayerbot.PremadeSpecLink.4.1.60 = -0252051000035015223100501251
AiPlayerbot.PremadeSpecLink.4.1.80 = 00532000523-0252051000035015223100501251
AiPlayerbot.PremadeSpecName.4.2 = subtlety pve
@@ -696,8 +696,8 @@ AiPlayerbot.PremadeSpecLink.7.1.60 = -30205033005001333031131131051
AiPlayerbot.PremadeSpecLink.7.1.80 = 053030052-30205033005021333031131131051
AiPlayerbot.PremadeSpecName.7.2 = resto pve
AiPlayerbot.PremadeSpecGlyph.7.2 = 41517,43385,41527,43386,44923,45775
AiPlayerbot.PremadeSpecLink.7.2.60 = --50005301335310501002331241
AiPlayerbot.PremadeSpecLink.7.2.80 = -00505031-50005331335310501022331251
AiPlayerbot.PremadeSpecLink.7.2.60 = --50005301235310501102321251
AiPlayerbot.PremadeSpecLink.7.2.80 = -00502033-50005331335310501122331251
#
#
@@ -715,8 +715,8 @@ AiPlayerbot.PremadeSpecLink.8.0.60 = 23000503110033014032310150532
AiPlayerbot.PremadeSpecLink.8.0.80 = 23000523310033015032310250532-03-203203001
AiPlayerbot.PremadeSpecName.8.1 = fire pve
AiPlayerbot.PremadeSpecGlyph.8.1 = 42739,43339,45737,43364,44920,42751
AiPlayerbot.PremadeSpecLink.8.1.60 = -0055030012303330053120300351
AiPlayerbot.PremadeSpecLink.8.1.80 = 23000503310003-0055030012303330053120300351
AiPlayerbot.PremadeSpecLink.8.1.60 = -0055030011302231053120321341
AiPlayerbot.PremadeSpecLink.8.1.80 = 23000503110003-0055030011302331053120321351
AiPlayerbot.PremadeSpecName.8.2 = frost pve
AiPlayerbot.PremadeSpecGlyph.8.2 = 42742,43339,50045,43364,43361,42751
AiPlayerbot.PremadeSpecLink.8.2.60 = --3533103310203100232102231151
@@ -891,6 +891,14 @@ AiPlayerbot.AutoPickTalents = 1
#
#
# Equips quality limitation for random bots (1 = normal, 2 = uncommon, 3 = rare, 4 = epic, 5 = legendary)
# default: 3 (rare)
AiPlayerbot.RandomGearQualityLimit = 3
# Equips gear score limitation for random bots (0 = no limit)
# default: 0 (no limit)
AiPlayerbot.RandomGearScoreLimit = 0
# Change random bot has lower gear
AiPlayerbot.RandomGearLoweringChance = 0

View File

@@ -95,7 +95,10 @@ bool PlayerbotAIConfig::Initialize()
autoAvoidAoe = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoAvoidAoe", true);
tellWhenAvoidAoe = sConfigMgr->GetOption<bool>("AiPlayerbot.TellWhenAvoidAoe", true);
randomGearLoweringChance = sConfigMgr->GetOption<float>("AiPlayerbot.RandomGearLoweringChance", 0.15f);
randomGearLoweringChance = sConfigMgr->GetOption<float>("AiPlayerbot.RandomGearLoweringChance", 0.0f);
randomGearQualityLimit = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomGearQualityLimit", 3);
randomGearScoreLimit = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomGearScoreLimit", 0);
randomBotMaxLevelChance = sConfigMgr->GetOption<float>("AiPlayerbot.RandomBotMaxLevelChance", 0.15f);
randomBotRpgChance = sConfigMgr->GetOption<float>("AiPlayerbot.RandomBotRpgChance", 0.20f);

View File

@@ -79,6 +79,8 @@ class PlayerbotAIConfig
std::vector<uint32> randomBotQuestIds;
uint32 randomBotTeleportDistance;
float randomGearLoweringChance;
int32 randomGearQualityLimit;
int32 randomGearScoreLimit;
float randomBotMaxLevelChance;
float randomBotRpgChance;
uint32 minRandomBots, maxRandomBots;

View File

@@ -149,7 +149,10 @@ void PlayerbotFactory::Prepare()
{
if (!itemQuality)
{
itemQuality = ITEM_QUALITY_RARE;
uint32 gs = sPlayerbotAIConfig->randomGearScoreLimit == 0 ? 0 :
PlayerbotFactory::CalcMixedGearScore(sPlayerbotAIConfig->randomGearScoreLimit, sPlayerbotAIConfig->randomGearQualityLimit);
itemQuality = sPlayerbotAIConfig->randomGearQualityLimit;
gearScoreLimit = gs;
}
if (bot->isDead())
@@ -3821,9 +3824,10 @@ float PlayerbotFactory::CalculateItemScore(uint32 item_id, Player* bot)
score += (agility + strength + intellect + spirit + stamina + defense + dodge + parry + block +
resilience + hit + crit + haste + expertise + attack_power + mana_regeneration + spell_power + armor_penetration +
spell_penetration + armor + rangeDps + meleeDps) * 0.001;
// todo: remove duplicate code
if (cls == CLASS_HUNTER) {
// AGILITY only
score += agility * 2.5 + attack_power + armor_penetration * 2 + rangeDps * 5 + hit * 2.5 + crit * 2 + haste * 2.5 + intellect;
score += agility * 2.5 + attack_power + armor_penetration * 2 + rangeDps * 5 + hit * 2 + crit * 2 + haste * 2 + intellect;
} else if (cls == CLASS_WARLOCK ||
cls == CLASS_MAGE ||
(cls == CLASS_PRIEST && tab == 2) || // shadow
@@ -3832,7 +3836,7 @@ float PlayerbotFactory::CalculateItemScore(uint32 item_id, Player* bot)
) {
// SPELL DPS
score += intellect * 0.5 + spirit * 0.5 + spell_power + spell_penetration
+ hit * 1.2 + crit * 0.7 + haste * 1 + rangeDps;
+ hit * 1 + crit * 0.7 + haste * 1 + rangeDps;
} else if ((cls == CLASS_PALADIN && tab == 0) || // holy
(cls == CLASS_PRIEST && tab != 2) || // discipline / holy
(cls == CLASS_SHAMAN && tab == 2) || // heal
@@ -3840,9 +3844,9 @@ float PlayerbotFactory::CalculateItemScore(uint32 item_id, Player* bot)
) {
// HEALER
score += intellect * 0.5 + spirit * 0.5 + spell_power + mana_regeneration * 0.5 + crit * 0.5 + haste * 1 + rangeDps;
} else if (cls == CLASS_ROGUE) {
} else if (cls == CLASS_ROGUE || (cls == CLASS_DRUID && tab == 2 && !PlayerbotAI::IsTank(bot))) {
// AGILITY mainly (STRENGTH also)
score += agility * 2 + strength + attack_power + armor_penetration * 1 + meleeDps * 5 + hit * 2 + crit * 1.5 + haste * 1.5 + expertise * 2.5;
score += agility * 2 + strength + attack_power + armor_penetration * 1 + meleeDps * 5 + hit * 1.5 + crit * 1.5 + haste * 1.5 + expertise * 2.5;
} else if ((cls == CLASS_PALADIN && tab == 2) || // retribution
(cls == CLASS_WARRIOR && tab != 2) || // arm / fury
(cls == CLASS_DEATH_KNIGHT && tab != 0) // ice / unholy
@@ -3852,20 +3856,20 @@ float PlayerbotFactory::CalculateItemScore(uint32 item_id, Player* bot)
} else if ((cls == CLASS_SHAMAN && tab == 1)) { // enhancement
// STRENGTH mainly (AGILITY, INTELLECT also)
score += strength * 1 + agility * 1.5 + intellect * 1.5 + attack_power + spell_power * 1.5 + armor_penetration * 0.5 + meleeDps * 5
+ hit * 2 + crit * 1.5 + haste * 1.5 + expertise * 2;
+ hit * 1.5 + crit * 1.5 + haste * 1.5 + expertise * 2;
} else if ((cls == CLASS_WARRIOR && tab == 2) ||
(cls == CLASS_PALADIN && tab == 1)) {
// TANK WITH SHIELD
score += strength * 1 + agility * 2 + attack_power * 0.2
+ defense * 2.5 + parry * 2 + dodge * 2 + resilience * 2 + block * 2 + armor * 0.3 + stamina * 3
+ hit * 1 + crit * 0.2 + haste * 0.5 + expertise * 3;
+ hit * 0.5 + crit * 0.2 + haste * 0.5 + expertise * 3;
} else if (cls == CLASS_DEATH_KNIGHT && tab == 0){
// BLOOD DK TANK
score += strength * 1 + agility * 2 + attack_power * 0.2
+ defense * 3.5 + parry * 2 + dodge * 2 + resilience * 2 + armor * 0.3 + stamina * 2.5
+ hit * 2 + crit * 0.5 + haste * 0.5 + expertise * 3.5;
+ hit * 0.5 + crit * 0.5 + haste * 0.5 + expertise * 3.5;
} else {
// BEAR DRUID TANK (AND FERAL DRUID...?)
// BEAR DRUID TANK
score += agility * 1.5 + strength * 1 + attack_power * 0.5 + armor_penetration * 0.5 + meleeDps * 2
+ defense * 0.25 + dodge * 0.25 + armor * 0.3 + stamina * 1.5
+ hit * 1 + crit * 1 + haste * 0.5 + expertise * 3;
@@ -4242,9 +4246,10 @@ float PlayerbotFactory::CalculateEnchantScore(uint32 enchant_id, Player* bot)
float score = (agility + strength + intellect + spirit + stamina + defense + dodge + parry + block +
resilience + hit + crit + haste + expertise + attack_power + mana_regeneration + spell_power + armor_penetration +
spell_penetration + armor + dps) * 0.001;
// todo: remove duplicate code
if (cls == CLASS_HUNTER) {
// AGILITY only
score += agility * 2.5 + attack_power + armor_penetration * 2 + dps * 5 + hit * 2.5 + crit * 2 + haste * 2.5 + intellect;
score += agility * 2.5 + attack_power + armor_penetration * 2 + dps * 5 + hit * 2 + crit * 2 + haste * 2.5 + intellect;
} else if (cls == CLASS_WARLOCK ||
cls == CLASS_MAGE ||
(cls == CLASS_PRIEST && tab == 2) || // shadow
@@ -4253,7 +4258,7 @@ float PlayerbotFactory::CalculateEnchantScore(uint32 enchant_id, Player* bot)
) {
// SPELL DPS
score += intellect * 0.5 + spirit * 0.5 + spell_power + spell_penetration
+ hit * 1.2 + crit * 0.7 + haste * 1;
+ hit * 1 + crit * 0.7 + haste * 1;
} else if ((cls == CLASS_PALADIN && tab == 0) || // holy
(cls == CLASS_PRIEST && tab != 2) || // discipline / holy
(cls == CLASS_SHAMAN && tab == 2) || // heal
@@ -4261,9 +4266,9 @@ float PlayerbotFactory::CalculateEnchantScore(uint32 enchant_id, Player* bot)
) {
// HEALER
score += intellect * 0.5 + spirit * 0.5 + spell_power + mana_regeneration * 0.5 + crit * 0.5 + haste * 1;
} else if (cls == CLASS_ROGUE) {
} else if (cls == CLASS_ROGUE || (cls == CLASS_DRUID && tab == 2 && !PlayerbotAI::IsTank(bot))) {
// AGILITY mainly (STRENGTH also)
score += agility * 2 + strength + attack_power + armor_penetration * 1 + dps * 5 + hit * 2 + crit * 1.5 + haste * 1.5 + expertise * 2.5;
score += agility * 2 + strength + attack_power + armor_penetration * 1 + dps * 5 + hit * 1.5 + crit * 1.5 + haste * 1.5 + expertise * 2.5;
} else if ((cls == CLASS_PALADIN && tab == 2) || // retribution
(cls == CLASS_WARRIOR && tab != 2) || // arm / fury
(cls == CLASS_DEATH_KNIGHT && tab != 0) // ice / unholy
@@ -4273,20 +4278,20 @@ float PlayerbotFactory::CalculateEnchantScore(uint32 enchant_id, Player* bot)
} else if ((cls == CLASS_SHAMAN && tab == 1)) { // enhancement
// STRENGTH mainly (AGILITY, INTELLECT also)
score += strength * 1 + agility * 1.5 + intellect * 1.5 + attack_power + spell_power * 1.5 + armor_penetration * 0.5 + dps * 5
+ hit * 2 + crit * 1.5 + haste * 1.5 + expertise * 2;
+ hit * 1.5 + crit * 1.5 + haste * 1.5 + expertise * 2;
} else if ((cls == CLASS_WARRIOR && tab == 2) ||
(cls == CLASS_PALADIN && tab == 1)) {
// TANK WITH SHIELD
score += strength * 1 + agility * 2 + attack_power * 0.2
+ defense * 2.5 + parry * 2 + dodge * 2 + resilience * 2 + block * 2 + armor * 0.3 + stamina * 3
+ hit * 1 + crit * 0.2 + haste * 0.5 + expertise * 3;
+ hit * 0.5 + crit * 0.2 + haste * 0.5 + expertise * 3;
} else if (cls == CLASS_DEATH_KNIGHT && tab == 0){
// BLOOD DK TANK
score += strength * 1 + agility * 2 + attack_power * 0.2
+ defense * 3.5 + parry * 2 + dodge * 2 + resilience * 2 + armor * 0.3 + stamina * 2.5
+ hit * 2 + crit * 0.5 + haste * 0.5 + expertise * 3.5;
+ hit * 0.5 + crit * 0.5 + haste * 0.5 + expertise * 3.5;
} else {
// BEAR DRUID TANK (AND FERAL DRUID...?)
// BEAR DRUID TANK
score += agility * 1.5 + strength * 1 + attack_power * 0.5 + armor_penetration * 0.5 + dps * 2
+ defense * 0.25 + dodge * 0.25 + armor * 0.3 + stamina * 1.5
+ hit * 1 + crit * 1 + haste * 0.5 + expertise * 3;
@@ -4521,9 +4526,10 @@ float PlayerbotFactory::CalculateSpellScore(uint32 spell_id, Player* bot, uint32
}
}
float score = 0;
// todo: remove duplicate code
if (cls == CLASS_HUNTER) {
// AGILITY only
score += agility * 2.5 + attack_power + armor_penetration * 2 + rangeDps * 5 + hit * 2.5 + crit * 2 + haste * 2.5 + intellect;
score += agility * 2.5 + attack_power + armor_penetration * 2 + rangeDps * 5 + hit * 2 + crit * 2 + haste * 2.5 + intellect;
} else if (cls == CLASS_WARLOCK ||
cls == CLASS_MAGE ||
(cls == CLASS_PRIEST && tab == 2) || // shadow
@@ -4532,7 +4538,7 @@ float PlayerbotFactory::CalculateSpellScore(uint32 spell_id, Player* bot, uint32
) {
// SPELL DPS
score += intellect * 0.5 + spirit * 0.5 + spell_power + spell_penetration
+ hit * 1.2 + crit * 0.7 + haste * 1 + rangeDps;
+ hit * 1 + crit * 0.7 + haste * 1 + rangeDps;
} else if ((cls == CLASS_PALADIN && tab == 0) || // holy
(cls == CLASS_PRIEST && tab != 2) || // discipline / holy
(cls == CLASS_SHAMAN && tab == 2) || // heal
@@ -4540,9 +4546,9 @@ float PlayerbotFactory::CalculateSpellScore(uint32 spell_id, Player* bot, uint32
) {
// HEALER
score += intellect * 0.5 + spirit * 0.5 + spell_power + mana_regeneration * 0.5 + crit * 0.5 + haste * 1 + rangeDps;
} else if (cls == CLASS_ROGUE) {
} else if (cls == CLASS_ROGUE || (cls == CLASS_DRUID && tab == 2 && !PlayerbotAI::IsTank(bot))) {
// AGILITY mainly (STRENGTH also)
score += agility * 2 + strength + attack_power + armor_penetration * 1 + meleeDps * 5 + hit * 2 + crit * 1.5 + haste * 1.5 + expertise * 2.5;
score += agility * 2 + strength + attack_power + armor_penetration * 1 + meleeDps * 5 + hit * 1.5 + crit * 1.5 + haste * 1.5 + expertise * 2.5;
} else if ((cls == CLASS_PALADIN && tab == 2) || // retribution
(cls == CLASS_WARRIOR && tab != 2) || // arm / fury
(cls == CLASS_DEATH_KNIGHT && tab != 0) // ice / unholy
@@ -4552,20 +4558,20 @@ float PlayerbotFactory::CalculateSpellScore(uint32 spell_id, Player* bot, uint32
} else if ((cls == CLASS_SHAMAN && tab == 1)) { // enhancement
// STRENGTH mainly (AGILITY, INTELLECT also)
score += strength * 1 + agility * 1.5 + intellect * 1.5 + attack_power + spell_power * 1.5 + armor_penetration * 0.5 + meleeDps * 5
+ hit * 2 + crit * 1.5 + haste * 1.5 + expertise * 2;
+ hit * 1.5 + crit * 1.5 + haste * 1.5 + expertise * 2;
} else if ((cls == CLASS_WARRIOR && tab == 2) ||
(cls == CLASS_PALADIN && tab == 1)) {
// TANK WITH SHIELD
score += strength * 1 + agility * 2 + attack_power * 0.2
+ defense * 2.5 + parry * 2 + dodge * 2 + resilience * 2 + block * 2 + armor * 0.3 + stamina * 3
+ hit * 1 + crit * 0.2 + haste * 0.5 + expertise * 3;
+ hit * 0.5 + crit * 0.2 + haste * 0.5 + expertise * 3;
} else if (cls == CLASS_DEATH_KNIGHT && tab == 0){
// BLOOD DK TANK
score += strength * 1 + agility * 2 + attack_power * 0.2
+ defense * 3.5 + parry * 2 + dodge * 2 + resilience * 2 + armor * 0.3 + stamina * 2.5
+ hit * 2 + crit * 0.5 + haste * 0.5 + expertise * 3.5;
+ hit * 0.5 + crit * 0.5 + haste * 0.5 + expertise * 3.5;
} else {
// BEAR DRUID TANK (AND FERAL DRUID...?)
// BEAR DRUID TANK
score += agility * 1.5 + strength * 1 + attack_power * 0.5 + armor_penetration * 0.5 + meleeDps * 2
+ defense * 0.25 + dodge * 0.25 + armor * 0.3 + stamina * 1.5
+ hit * 1 + crit * 1 + haste * 0.5 + expertise * 3;

View File

@@ -74,6 +74,12 @@ void PlayerbotHolder::AddPlayerBot(ObjectGuid playerGuid, uint32 masterAccountId
void PlayerbotHolder::HandlePlayerBotLoginCallback(PlayerbotLoginQueryHolder const& holder)
{
// has bot already been added?
Player* loginBot = ObjectAccessor::FindConnectedPlayer(holder.GetGuid());
if (loginBot && loginBot->IsInWorld()) {
return;
}
uint32 botAccountId = holder.GetAccountId();
WorldSession* botSession = new WorldSession(botAccountId, "", nullptr, SEC_PLAYER, EXPANSION_WRATH_OF_THE_LICH_KING, time_t(0), LOCALE_enUS, 0, false, false, 0, true);

View File

@@ -152,6 +152,7 @@ class ActionContext : public NamedObjectContext<Action>
creators["auto talents"] = &ActionContext::auto_talents;
creators["auto learn spell"] = &ActionContext::auto_learn_spell;
creators["auto teleport for level"] = &ActionContext::auto_teleport_for_level;
creators["auto upgrade equip"] = &ActionContext::auto_upgrade_equip;
creators["xp gain"] = &ActionContext::xp_gain;
creators["invite nearby"] = &ActionContext::invite_nearby;
creators["invite guild"] = &ActionContext::invite_guild;
@@ -319,6 +320,7 @@ class ActionContext : public NamedObjectContext<Action>
static Action* auto_talents(PlayerbotAI* botAI) { return new AutoSetTalentsAction(botAI); }
static Action* auto_learn_spell(PlayerbotAI* botAI) { return new AutoLearnSpellAction(botAI); }
static Action* auto_teleport_for_level(PlayerbotAI* botAI) { return new AutoTeleportForLevelAction(botAI); }
static Action* auto_upgrade_equip(PlayerbotAI* botAI) { return new AutoUpgradeEquipAction(botAI); }
static Action* xp_gain(PlayerbotAI* botAI) { return new XpGainAction(botAI); }
static Action* invite_nearby(PlayerbotAI* botAI) { return new InviteNearbyToGroupAction(botAI); }
static Action* invite_guild(PlayerbotAI* botAI) { return new InviteGuildToGroupAction(botAI); }

View File

@@ -95,7 +95,7 @@ bool AttackAction::Attack(Unit* target, bool with_pet /*true*/)
return false;
}
if (bot->IsMounted() && bot->IsWithinLOSInMap(target) && sServerFacade->GetDistance2d(bot, target) < 40.0f)
if (bot->IsMounted() && bot->IsWithinLOSInMap(target))
{
WorldPacket emptyPacket;
bot->GetSession()->HandleCancelMountAuraOpcode(emptyPacket);

View File

@@ -24,7 +24,6 @@ bool AutoLearnSpellAction::Execute(Event event)
out << ".";
botAI->TellMaster(out);
}
return true;
}
@@ -181,3 +180,15 @@ void AutoLearnSpellAction::LearnSpell(uint32 spellId, std::ostringstream* out)
}
}
}
bool AutoUpgradeEquipAction::Execute(Event event) {
if (!sPlayerbotAIConfig->autoUpgradeEquip || !sRandomPlayerbotMgr->IsRandomBot(bot)) {
return false;
}
PlayerbotFactory factory(bot, bot->GetLevel(), ITEM_QUALITY_RARE);
if (!sPlayerbotAIConfig->equipmentPersistence || bot->GetLevel() < sPlayerbotAIConfig->equipmentPersistenceLevel) {
factory.InitEquipment(true);
}
factory.InitAmmo();
return true;
}

View File

@@ -23,4 +23,12 @@ class AutoLearnSpellAction : public Action
void LearnSpell(uint32 spellId, std::ostringstream* out);
};
class AutoUpgradeEquipAction : public Action
{
public:
AutoUpgradeEquipAction(PlayerbotAI* botAI, std::string const name = "auto upgrade equip") : Action(botAI, name) { }
bool Execute(Event event);
};
#endif

View File

@@ -6,8 +6,6 @@
#include "SharedDefines.h"
bool AutoTeleportForLevelAction::Execute(Event event) {
AutoUpgradeEquip();
if (!sPlayerbotAIConfig->autoTeleportForLevel || !sRandomPlayerbotMgr->IsRandomBot(bot)) {
return false;
}
@@ -17,14 +15,3 @@ bool AutoTeleportForLevelAction::Execute(Event event) {
sRandomPlayerbotMgr->RandomTeleportForLevel(bot);
return true;
}
void AutoTeleportForLevelAction::AutoUpgradeEquip() {
if (!sPlayerbotAIConfig->autoUpgradeEquip || !sRandomPlayerbotMgr->IsRandomBot(bot)) {
return;
}
PlayerbotFactory factory(bot, bot->GetLevel(), ITEM_QUALITY_RARE);
if (!sPlayerbotAIConfig->equipmentPersistence || bot->GetLevel() < sPlayerbotAIConfig->equipmentPersistenceLevel) {
factory.InitEquipment(true);
}
factory.InitAmmo();
}

View File

@@ -15,8 +15,6 @@ class AutoTeleportForLevelAction : public Action
AutoTeleportForLevelAction(PlayerbotAI* botAI, std::string const name = "auto teleport for level") : Action(botAI, name) { }
bool Execute(Event event);
private:
void AutoUpgradeEquip();
};
#endif

View File

@@ -4115,7 +4115,8 @@ bool BGTactics::selectObjective(bool reset)
}
break;
}
default:
break;
}
return false;
@@ -4503,7 +4504,7 @@ bool BGTactics::atFlag(std::vector<BattleBotPath*> const& vPaths, std::vector<ui
if (f == vFlagIds.end())
continue;
if (!go->isSpawned() || !go->GetGoState() == GO_STATE_READY)
if (!go->isSpawned() || go->GetGoState() != GO_STATE_READY)
continue;
if (!bot->CanUseBattlegroundObject(go) && bgType != BATTLEGROUND_WS)
@@ -4644,6 +4645,8 @@ bool BGTactics::atFlag(std::vector<BattleBotPath*> const& vPaths, std::vector<ui
}
break;
}
default:
break;
}
}

View File

@@ -91,6 +91,8 @@ bool BuyAction::Execute(Event event)
case ITEM_USAGE_SKILL:
needMoneyFor = NeedMoneyFor::tradeskill;
break;
default:
break;
}
if (needMoneyFor == NeedMoneyFor::none)

View File

@@ -11,7 +11,7 @@
uint32 FindLastSeparator(std::string const text, std::string const sep)
{
uint32 pos = text.rfind(sep);
size_t pos = text.rfind(sep);
if (pos == std::string::npos)
return pos;
@@ -64,7 +64,7 @@ bool CastCustomSpellAction::Execute(Event event)
Item* itemTarget = nullptr;
uint32 pos = FindLastSeparator(text, " ");
size_t pos = FindLastSeparator(text, " ");
uint32 castCount = 1;
if (pos != std::string::npos)
{

View File

@@ -46,19 +46,19 @@ void ChooseTravelTargetAction::getNewTarget(TravelTarget* newTarget, TravelTarge
foundTarget = SetNpcFlagTarget(newTarget, { UNIT_NPC_FLAG_BANKER,UNIT_NPC_FLAG_BATTLEMASTER,UNIT_NPC_FLAG_AUCTIONEER });
//Grind for money
if (!foundTarget && AI_VALUE(bool, "should get money"))
if (!foundTarget && AI_VALUE(bool, "should get money")) {
if (urand(1, 100) > 66)
{
foundTarget = SetQuestTarget(newTarget, true); //Turn in quests for money.
if (!foundTarget)
foundTarget = SetQuestTarget(newTarget); //Do low level quests
}
else if (urand(1, 100) > 50)
} else if (urand(1, 100) > 50) {
foundTarget = SetGrindTarget(newTarget); //Go grind mobs for money
else
} else {
foundTarget = SetNewQuestTarget(newTarget); //Find a low level quest to do
}
}
//Continue
if (!foundTarget && urand(1, 100) > 10) //90% chance

View File

@@ -10,7 +10,7 @@
bool CustomStrategyEditAction::Execute(Event event)
{
std::string text = event.getParam();
uint32 pos = text.find(" ");
size_t pos = text.find(" ");
if (pos == std::string::npos)
return PrintHelp();

View File

@@ -147,6 +147,8 @@ RollVote LootRollAction::CalculateRollVote(ItemTemplate const* proto)
case ITEM_USAGE_VENDOR:
needVote = GREED;
break;
default:
break;
}
return StoreLootAction::IsLootAllowed(proto->ItemId, GET_PLAYERBOT_AI(bot)) ? needVote : PASS;

View File

@@ -17,7 +17,7 @@ bool RangeAction::Execute(Event event)
PrintRange("flee");
}
uint32 pos = param.find(" ");
size_t pos = param.find(" ");
if (pos == std::string::npos)
return false;

View File

@@ -53,6 +53,8 @@ void TalkToQuestGiverAction::ProcessQuest(Quest const* quest, Object* questGiver
case QUEST_STATUS_FAILED:
out << "|cffff0000Failed|r";
break;
default:
break;
}
out << ": " << chat->FormatQuest(quest);
@@ -257,6 +259,8 @@ bool TurnInQueryQuestAction::Execute(Event event)
case QUEST_STATUS_REWARDED:
out << "|cffff0000Rewarded|r";
break;
default:
break;
}
out << ": " << chat->FormatQuest(quest);

View File

@@ -11,8 +11,8 @@
#ifndef WIN32
inline int strcmpi(char const* s1, char const* s2)
{
for (; *s1 && *s2 && (toupper(*s1) == toupper(*s2)); ++s1, ++s2);
return *s1 - *s2;
for (; *s1 && *s2 && (toupper(*s1) == toupper(*s2)); ++s1, ++s2) {}
return *s1 - *s2;
}
#endif

View File

@@ -67,7 +67,7 @@ class DeathKnightTriggerFactoryInternal : public NamedObjectContext<Trigger>
DeathKnightTriggerFactoryInternal()
{
creators["bone shield"] = &DeathKnightTriggerFactoryInternal::bone_shield;
creators["pestilence"] = &DeathKnightTriggerFactoryInternal::pestilence;
creators["pestilence glyph"] = &DeathKnightTriggerFactoryInternal::pestilence_glyph;
creators["blood strike"] = &DeathKnightTriggerFactoryInternal::blood_strike;
creators["plague strike"] = &DeathKnightTriggerFactoryInternal::plague_strike;
creators["plague strike on attacker"] = &DeathKnightTriggerFactoryInternal::plague_strike_on_attacker;
@@ -94,7 +94,7 @@ class DeathKnightTriggerFactoryInternal : public NamedObjectContext<Trigger>
private:
static Trigger* bone_shield(PlayerbotAI* botAI) { return new BoneShieldTrigger(botAI); }
static Trigger* pestilence(PlayerbotAI* botAI) { return new PestilenceTrigger(botAI); }
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_on_attacker(PlayerbotAI* botAI) { return new PlagueStrikeDebuffOnAttackerTrigger(botAI); }

View File

@@ -14,7 +14,7 @@ bool DKPresenceTrigger::IsActive()
return !botAI->HasAura("blood presence", target) && !botAI->HasAura("unholy presence", target) && !botAI->HasAura("frost presence", target);
}
bool PestilenceTrigger::IsActive() {
bool PestilenceGlyphTrigger::IsActive() {
if (!SpellTrigger::IsActive()) {
return false;
}

View File

@@ -71,10 +71,10 @@ class DeathCoilTrigger : public SpellCanBeCastTrigger
DeathCoilTrigger(PlayerbotAI* botAI) : SpellCanBeCastTrigger(botAI, "death coil") { }
};
class PestilenceTrigger : public DebuffTrigger
class PestilenceGlyphTrigger : public SpellTrigger
{
public:
PestilenceTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "pestilence") { }
PestilenceGlyphTrigger(PlayerbotAI* botAI) : SpellTrigger(botAI, "pestilence") { }
virtual bool IsActive() override;
};

View File

@@ -192,5 +192,5 @@ void GenericDKStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
// triggers.push_back(new TriggerNode("light aoe", NextAction::array(0,
// new NextAction("pestilence", ACTION_NORMAL + 4),
// nullptr)));
triggers.push_back(new TriggerNode("pestilence", NextAction::array(0, new NextAction("pestilence", ACTION_HIGH + 9), NULL)));
triggers.push_back(new TriggerNode("pestilence glyph", NextAction::array(0, new NextAction("pestilence", ACTION_HIGH + 9), NULL)));
}

View File

@@ -8,7 +8,7 @@
void CombatStrategy::InitTriggers(std::vector<TriggerNode*> &triggers)
{
triggers.push_back(new TriggerNode("enemy out of spell", NextAction::array(0, new NextAction("reach spell", ACTION_MOVE + 11), nullptr)));
triggers.push_back(new TriggerNode("enemy out of spell", NextAction::array(0, new NextAction("reach spell", ACTION_HIGH), nullptr)));
triggers.push_back(new TriggerNode("invalid target", NextAction::array(0, new NextAction("drop target", 100), nullptr)));
triggers.push_back(new TriggerNode("mounted", NextAction::array(0, new NextAction("check mount state", 54), nullptr)));
// triggers.push_back(new TriggerNode("out of react range", NextAction::array(0, new NextAction("flee to master", 55), nullptr)));
@@ -24,44 +24,44 @@ AvoidAoeStrategy::AvoidAoeStrategy(PlayerbotAI* botAI) : Strategy(botAI)
}
class AvoidAoeStrategyMultiplier : public Multiplier
{
public:
AvoidAoeStrategyMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "run away on area debuff") {}
// class AvoidAoeStrategyMultiplier : public Multiplier
// {
// public:
// AvoidAoeStrategyMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "run away on area debuff") {}
public:
virtual float GetValue(Action* action);
// public:
// virtual float GetValue(Action* action);
private:
};
// private:
// };
float AvoidAoeStrategyMultiplier::GetValue(Action* action)
{
if (!action)
return 1.0f;
// float AvoidAoeStrategyMultiplier::GetValue(Action* action)
// {
// if (!action)
// return 1.0f;
std::string name = action->getName();
if (name == "follow" || name == "co" || name == "nc" || name == "drop target")
return 1.0f;
// std::string name = action->getName();
// if (name == "follow" || name == "co" || name == "nc" || name == "drop target")
// return 1.0f;
uint32 spellId = AI_VALUE2(uint32, "spell id", name);
const SpellInfo* const pSpellInfo = sSpellMgr->GetSpellInfo(spellId);
if (!pSpellInfo) return 1.0f;
// uint32 spellId = AI_VALUE2(uint32, "spell id", name);
// const SpellInfo* const pSpellInfo = sSpellMgr->GetSpellInfo(spellId);
// if (!pSpellInfo) return 1.0f;
if (spellId && pSpellInfo->Targets & TARGET_FLAG_DEST_LOCATION)
return 1.0f;
else if (spellId && pSpellInfo->Targets & TARGET_FLAG_SOURCE_LOCATION)
return 1.0f;
// if (spellId && pSpellInfo->Targets & TARGET_FLAG_DEST_LOCATION)
// return 1.0f;
// else if (spellId && pSpellInfo->Targets & TARGET_FLAG_SOURCE_LOCATION)
// return 1.0f;
uint32 castTime = pSpellInfo->CalcCastTime(bot);
// uint32 castTime = pSpellInfo->CalcCastTime(bot);
if (AI_VALUE2(bool, "has area debuff", "self target") && spellId && castTime > 0)
{
return 0.0f;
}
// if (AI_VALUE2(bool, "has area debuff", "self target") && spellId && castTime > 0)
// {
// return 0.0f;
// }
return 1.0f;
}
// return 1.0f;
// }
NextAction** AvoidAoeStrategy::getDefaultActions()
{
@@ -86,6 +86,6 @@ void AvoidAoeStrategy::InitMultipliers(std::vector<Multiplier*>& multipliers)
NextAction** CombatFormationStrategy::getDefaultActions()
{
return NextAction::array(0,
new NextAction("combat formation move", ACTION_EMERGENCY),
new NextAction("combat formation move", ACTION_NORMAL),
nullptr);
}

View File

@@ -37,9 +37,10 @@ void WorldPacketHandlerStrategy::InitTriggers(std::vector<TriggerNode*>& trigger
triggers.push_back(new TriggerNode("bg status", NextAction::array(0, new NextAction("bg status", relevance), nullptr)));
triggers.push_back(new TriggerNode("xpgain", NextAction::array(0, new NextAction("xp gain", relevance), nullptr)));
triggers.push_back(new TriggerNode("levelup", NextAction::array(0,
new NextAction("auto talents", relevance),
new NextAction("auto learn spell", relevance),
new NextAction("auto teleport for level", relevance),
new NextAction("auto teleport for level", relevance + 3),
new NextAction("auto talents", relevance + 2),
new NextAction("auto learn spell", relevance + 1),
new NextAction("auto upgrade equip", relevance),
nullptr)));
// triggers.push_back(new TriggerNode("group destroyed", NextAction::array(0, new NextAction("reset botAI", relevance), nullptr)));
triggers.push_back(new TriggerNode("questgiver quest details", NextAction::array(0, new NextAction("turn in query quest", relevance), nullptr)));

View File

@@ -153,7 +153,7 @@ bool CastMeleeConsecrationAction::isUseful()
{
Unit* target = GetTarget();
// float dis = distance + CONTACT_DISTANCE;
return target && bot->IsWithinCombatRange(target, sPlayerbotAIConfig->meleeDistance); // sServerFacade->IsDistanceGreaterThan(AI_VALUE2(float, "distance", GetTargetName()), distance);
return target && bot->IsWithinMeleeRange(target); // sServerFacade->IsDistanceGreaterThan(AI_VALUE2(float, "distance", GetTargetName()), distance);
}
bool CastDivineSacrificeAction::isUseful()

View File

@@ -94,6 +94,9 @@ void TankPaladinStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
triggers.push_back(new TriggerNode(
"medium group heal occasion",
NextAction::array(0, new NextAction("divine sacrifice", ACTION_HIGH + 5), nullptr)));
triggers.push_back(new TriggerNode(
"enough mana",
NextAction::array(0, new NextAction("melee consecration", ACTION_HIGH + 4), nullptr)));
triggers.push_back(new TriggerNode(
"not facing target",
NextAction::array(0, new NextAction("set facing", ACTION_NORMAL + 7), nullptr)));

View File

@@ -52,6 +52,7 @@ void CasterShamanStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
triggers.push_back(new TriggerNode("shaman weapon", NextAction::array(0, new NextAction("flametongue weapon", 23.0f), nullptr)));
// triggers.push_back(new TriggerNode("searing totem", NextAction::array(0, new NextAction("searing totem", 19.0f), nullptr)));
triggers.push_back(new TriggerNode("flame shock", NextAction::array(0, new NextAction("flame shock", 20.0f), nullptr)));
triggers.push_back(new TriggerNode("elemental mastery", NextAction::array(0, new NextAction("elemental mastery", 27.0f), nullptr)));
// triggers.push_back(new TriggerNode("frost shock snare", NextAction::array(0, new NextAction("frost shock", 21.0f), nullptr)));
triggers.push_back(new TriggerNode(
"no fire totem",

View File

@@ -350,6 +350,12 @@ class CastBloodlustAction : public CastBuffSpellAction
CastBloodlustAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "bloodlust") { }
};
class CastElementalMasteryAction : public CastBuffSpellAction
{
public:
CastElementalMasteryAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "elemental mastery") { }
};
class CastWindShearOnEnemyHealerAction : public CastSpellOnEnemyHealerAction
{
public:

View File

@@ -96,6 +96,7 @@ class ShamanATriggerFactoryInternal : public NamedObjectContext<Trigger>
creators["frost shock snare"] = &ShamanATriggerFactoryInternal::frost_shock_snare;
creators["heroism"] = &ShamanATriggerFactoryInternal::heroism;
creators["bloodlust"] = &ShamanATriggerFactoryInternal::bloodlust;
creators["elemental mastery"] = &ShamanATriggerFactoryInternal::elemental_mastery;
creators["wind shear on enemy healer"] = &ShamanATriggerFactoryInternal::wind_shear_on_enemy_healer;
creators["cure poison"] = &ShamanATriggerFactoryInternal::cure_poison;
creators["party member cure poison"] = &ShamanATriggerFactoryInternal::party_member_cure_poison;
@@ -114,6 +115,7 @@ class ShamanATriggerFactoryInternal : public NamedObjectContext<Trigger>
static Trigger* maelstrom_weapon(PlayerbotAI* botAI) { return new MaelstromWeaponTrigger(botAI); }
static Trigger* heroism(PlayerbotAI* botAI) { return new HeroismTrigger(botAI); }
static Trigger* bloodlust(PlayerbotAI* botAI) { return new BloodlustTrigger(botAI); }
static Trigger* elemental_mastery(PlayerbotAI* botAI) { return new ElementalMasteryTrigger(botAI); }
static Trigger* party_member_cleanse_disease(PlayerbotAI* botAI) { return new PartyMemberCleanseSpiritDiseaseTrigger(botAI); }
static Trigger* party_member_cleanse_curse(PlayerbotAI* botAI) { return new PartyMemberCleanseSpiritCurseTrigger(botAI); }
static Trigger* party_member_cleanse_poison(PlayerbotAI* botAI) { return new PartyMemberCleanseSpiritPoisonTrigger(botAI); }
@@ -206,6 +208,7 @@ class ShamanAiObjectContextInternal : public NamedObjectContext<Action>
creators["thunderstorm"] = &ShamanAiObjectContextInternal::thunderstorm;
creators["heroism"] = &ShamanAiObjectContextInternal::heroism;
creators["bloodlust"] = &ShamanAiObjectContextInternal::bloodlust;
creators["elemental mastery"] = &ShamanAiObjectContextInternal::elemental_mastery;
// creators["cure disease"] = &ShamanAiObjectContextInternal::cure_disease;
// creators["cure disease on party"] = &ShamanAiObjectContextInternal::cure_disease_on_party;
// creators["cure poison"] = &ShamanAiObjectContextInternal::cure_poison;
@@ -222,6 +225,7 @@ class ShamanAiObjectContextInternal : public NamedObjectContext<Action>
private:
static Action* heroism(PlayerbotAI* botAI) { return new CastHeroismAction(botAI); }
static Action* bloodlust(PlayerbotAI* botAI) { return new CastBloodlustAction(botAI); }
static Action* elemental_mastery(PlayerbotAI* botAI) { return new CastElementalMasteryAction(botAI); }
static Action* thunderstorm(PlayerbotAI* botAI) { return new CastThunderstormAction(botAI); }
static Action* lightning_bolt(PlayerbotAI* botAI) { return new CastLightningBoltAction(botAI); }
static Action* chain_lightning(PlayerbotAI* botAI) { return new CastChainLightningAction(botAI); }

View File

@@ -201,6 +201,12 @@ class BloodlustTrigger : public BoostTrigger
BloodlustTrigger(PlayerbotAI* botAI) : BoostTrigger(botAI, "bloodlust") { }
};
class ElementalMasteryTrigger : public BoostTrigger
{
public:
ElementalMasteryTrigger(PlayerbotAI* botAI) : BoostTrigger(botAI, "elemental mastery") { }
};
class MaelstromWeaponTrigger : public HasAuraStackTrigger
{
public:

View File

@@ -64,6 +64,11 @@ bool AlmostFullManaTrigger::IsActive()
return AI_VALUE2(bool, "has mana", "self target") && AI_VALUE2(uint8, "mana", "self target") > 85;
}
bool EnoughManaTrigger::IsActive()
{
return AI_VALUE2(bool, "has mana", "self target") && AI_VALUE2(uint8, "mana", "self target") > 65;
}
bool RageAvailable::IsActive()
{
return AI_VALUE2(uint8, "rage", "self target") >= amount;

View File

@@ -30,6 +30,14 @@ class HighManaTrigger : public Trigger
bool IsActive() override;
};
class EnoughManaTrigger : public Trigger
{
public:
EnoughManaTrigger(PlayerbotAI* botAI) : Trigger(botAI, "enough mana") { }
bool IsActive() override;
};
class AlmostFullManaTrigger : public Trigger
{
public:

View File

@@ -45,6 +45,7 @@ class TriggerContext : public NamedObjectContext<Trigger>
creators["medium mana"] = &TriggerContext::MediumMana;
creators["high mana"] = &TriggerContext::HighMana;
creators["almost full mana"] = &TriggerContext::AlmostFullMana;
creators["enough mana"] = &TriggerContext::EnoughMana;
creators["party member critical health"] = &TriggerContext::PartyMemberCriticalHealth;
creators["party member low health"] = &TriggerContext::PartyMemberLowHealth;
@@ -253,6 +254,7 @@ class TriggerContext : public NamedObjectContext<Trigger>
static Trigger* MediumMana(PlayerbotAI* botAI) { return new MediumManaTrigger(botAI); }
static Trigger* HighMana(PlayerbotAI* botAI) { return new HighManaTrigger(botAI); }
static Trigger* AlmostFullMana(PlayerbotAI* botAI) { return new AlmostFullManaTrigger(botAI); }
static Trigger* EnoughMana(PlayerbotAI* botAI) { return new EnoughManaTrigger(botAI); }
static Trigger* LightRageAvailable(PlayerbotAI* botAI) { return new LightRageAvailableTrigger(botAI); }
static Trigger* MediumRageAvailable(PlayerbotAI* botAI) { return new MediumRageAvailableTrigger(botAI); }
static Trigger* HighRageAvailable(PlayerbotAI* botAI) { return new HighRageAvailableTrigger(botAI); }

View File

@@ -172,7 +172,7 @@ bool AttackersValue::IsPossibleTarget(Unit* attacker, Player* bot, float range)
// (inCannon || !attacker->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE)) && attacker->CanSeeOrDetect(bot) &&
// !(attacker->HasUnitState(UNIT_STATE_STUNNED) && botAI->HasAura("shackle undead", attacker)) && !((attacker->IsPolymorphed() || botAI->HasAura("sap", attacker) || /*attacker->IsCharmed() ||*/ attacker->isFeared()) && !rti) &&
/*!sServerFacade->IsInRoots(attacker) &&*/
!attacker->IsFriendlyTo(bot) && bot->IsWithinDistInMap(attacker, range) &&
!attacker->IsFriendlyTo(bot) &&
!attacker->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION) &&
// !(attacker->GetGUID().IsPet() && enemy) &&
!(attacker->GetCreatureType() == CREATURE_TYPE_CRITTER && !attacker->IsInCombat()) &&

View File

@@ -180,6 +180,8 @@ uint32 MoneyNeededForValue::Calculate()
case NeedMoneyFor::tradeskill:
moneyWanted = (level * level * level); //Or level^3 (10s @ lvl10, 3g @ lvl30, 20g @ lvl60, 50g @ lvl80): Todo replace (Should be buyable reagents that combined allow crafting of usefull items)
break;
default:
break;
}
return moneyWanted;

View File

@@ -8,8 +8,8 @@
#ifndef WIN32
inline int strcmpi(char const* s1, char const* s2)
{
for (; *s1 && *s2 && (toupper(*s1) == toupper(*s2)); ++s1, ++s2);
return *s1 - *s2;
for (; *s1 && *s2 && (toupper(*s1) == toupper(*s2)); ++s1, ++s2) {}
return *s1 - *s2;
}
#endif

View File

@@ -14,7 +14,7 @@ class Unit;
class PartyMemberToDispel : public PartyMemberValue, public Qualified
{
public:
PartyMemberToDispel(PlayerbotAI* botAI, std::string const name = "party member to dispel") : PartyMemberValue(botAI, name, 2 * 1000), Qualified() { }
PartyMemberToDispel(PlayerbotAI* botAI, std::string const name = "party member to dispel") : PartyMemberValue(botAI, name, 1000), Qualified() { }
protected:
Unit* Calculate() override;

View File

@@ -32,7 +32,9 @@ ArmsWarriorStrategy::ArmsWarriorStrategy(PlayerbotAI* botAI) : GenericWarriorStr
NextAction** ArmsWarriorStrategy::getDefaultActions()
{
return NextAction::array(0, new NextAction("heroic strike", ACTION_DEFAULT), nullptr);
return NextAction::array(0,
new NextAction("bladestorm", ACTION_DEFAULT + 0.1f),
new NextAction("melee", ACTION_DEFAULT), nullptr);
}
void ArmsWarriorStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
@@ -56,4 +58,5 @@ void ArmsWarriorStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
triggers.push_back(new TriggerNode("rend", NextAction::array(0, new NextAction("rend", ACTION_HIGH + 5), nullptr)));
triggers.push_back(new TriggerNode("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", NextAction::array(0, new NextAction("thunder clap", ACTION_HIGH + 1), nullptr)));
}

View File

@@ -61,7 +61,7 @@ void FuryWarriorStrategy::InitTriggers(std::vector<TriggerNode*> &triggers)
triggers.push_back(new TriggerNode("bloodthirst", NextAction::array(0, new NextAction("bloodthirst", ACTION_HIGH + 7), nullptr)));
triggers.push_back(new TriggerNode("instant slam", NextAction::array(0, new NextAction("slam", ACTION_HIGH + 5), nullptr)));
triggers.push_back(new TriggerNode("bloodrage", NextAction::array(0, new NextAction("bloodrage", ACTION_HIGH + 2), nullptr)));
triggers.push_back(new TriggerNode("high rage available", NextAction::array(0, new NextAction("heroic strike", ACTION_HIGH + 1), NULL)));
triggers.push_back(new TriggerNode("medium rage available", NextAction::array(0, new NextAction("heroic strike", ACTION_HIGH + 1), NULL)));
// triggers.push_back(new TriggerNode("berserker rage", NextAction::array(0, new NextAction("berserker rage", ACTION_HIGH + 2), nullptr)));
// triggers.push_back(new TriggerNode("light aoe", NextAction::array(0,
// new NextAction("whirlwind", ACTION_HIGH + 2),

View File

@@ -88,4 +88,6 @@ void TankWarriorStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
triggers.push_back(new TriggerNode("rend", NextAction::array(0, new NextAction("rend", ACTION_NORMAL + 1), nullptr)));
triggers.push_back(new TriggerNode("rend on attacker", NextAction::array(0, new NextAction("rend on attacker", ACTION_NORMAL + 1), nullptr)));
triggers.push_back(new TriggerNode("protect party member", NextAction::array(0, new NextAction("intervene", ACTION_EMERGENCY), nullptr)));
triggers.push_back(new TriggerNode("high rage available", NextAction::array(0, new NextAction("heroic strike", ACTION_HIGH + 1), nullptr)));
triggers.push_back(new TriggerNode("medium rage available", NextAction::array(0, new NextAction("thunder clap", ACTION_HIGH + 1), nullptr)));
}

View File

@@ -117,7 +117,7 @@ class WarriorTriggerFactoryInternal : public NamedObjectContext<Trigger>
static Trigger* SwordAndBoard(PlayerbotAI* botAI) { return new SwordAndBoardTrigger(botAI); }
static Trigger* shield_bash_on_enemy_healer(PlayerbotAI* botAI) { return new ShieldBashInterruptEnemyHealerSpellTrigger(botAI); }
static Trigger* thunderclap_and_rage(PlayerbotAI* botAI) { return new TwoTriggers(botAI, "thunderclap", "light rage available"); }
static Trigger* thunderclap_and_rage(PlayerbotAI* botAI) { return new TwoTriggers(botAI, "thunder clap", "light rage available"); }
static Trigger* intercept_can_cast(PlayerbotAI* botAI) { return new InterceptCanCastTrigger(botAI); }
static Trigger* intercept_and_far_enemy(PlayerbotAI* botAI) { return new TwoTriggers(botAI, "enemy is out of melee", "intercept can cast"); }
static Trigger* intercept_and_rage(PlayerbotAI* botAI) { return new TwoTriggers(botAI, "intercept and far enemy", "light rage available"); }