Merge pull request #2332 from mod-playerbots/test-staging

Test staging
This commit is contained in:
Keleborn 2026-05-01 13:09:54 -07:00 committed by GitHub
commit da3237fa78
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
104 changed files with 821 additions and 352 deletions

View File

@ -806,6 +806,27 @@ AiPlayerbot.RandomGearQualityLimit = 3
# Default: 0 (no limit) # Default: 0 (no limit)
AiPlayerbot.RandomGearScoreLimit = 0 AiPlayerbot.RandomGearScoreLimit = 0
# Prefer armor of the class's ideal type: apply 3x score multiplier to class-appropriate armor.
# When enabled, Warriors strongly prefer plate, Shamans prefer mail, etc.
# A truly superior item can still win (no hard filtering), but same-quality
# armor of the preferred type will score 3x higher and be equipped instead.
#
# ARMOR TYPE PREFERENCES:
# Plate: Warriors, Paladins, Death Knights
# Mail: Hunters, Shamans
# Leather: Rogues, Druids
# Cloth: Priests, Mages, Warlocks
#
# Default: 0 (disabled)
AiPlayerbot.PreferClassArmorType = 0
# When enabled, bots prefer spec-appropriate weapons based on speed and weapon type during autogear.
# Examples: Arms Warriors favor slow 2H axes/polearms (Axe Specialization), Combat Rogues
# favor a slow MH with a fast OH, and Enhancement Shamans favor synchronized slow 1H weapons.
# Default: 0 (disabled)
AiPlayerbot.PreferredSpecWeapons = 0
# If disabled, random bots can only upgrade equipment through looting and quests # If disabled, random bots can only upgrade equipment through looting and quests
# Default: 1 (enabled) # Default: 1 (enabled)
AiPlayerbot.IncrementalGearInit = 1 AiPlayerbot.IncrementalGearInit = 1
@ -1836,12 +1857,24 @@ AiPlayerbot.WorldBuffMatrix = # WARRIOR ARMS 1:0,1,0,80,80:53760,57358; # WARRIO
# #
# #
# arms pve
AiPlayerbot.RandomClassSpecProb.1.0 = 20 AiPlayerbot.RandomClassSpecProb.1.0 = 20
AiPlayerbot.RandomClassSpecIndex.1.0 = 0 AiPlayerbot.RandomClassSpecIndex.1.0 = 0
# fury pve
AiPlayerbot.RandomClassSpecProb.1.1 = 40 AiPlayerbot.RandomClassSpecProb.1.1 = 40
AiPlayerbot.RandomClassSpecIndex.1.1 = 1 AiPlayerbot.RandomClassSpecIndex.1.1 = 1
# prot pve
AiPlayerbot.RandomClassSpecProb.1.2 = 40 AiPlayerbot.RandomClassSpecProb.1.2 = 40
AiPlayerbot.RandomClassSpecIndex.1.2 = 2 AiPlayerbot.RandomClassSpecIndex.1.2 = 2
# arms pvp
AiPlayerbot.RandomClassSpecProb.1.3 = 0
AiPlayerbot.RandomClassSpecIndex.1.3 = 3
# fury pvp
AiPlayerbot.RandomClassSpecProb.1.4 = 0
AiPlayerbot.RandomClassSpecIndex.1.4 = 4
# prot pvp
AiPlayerbot.RandomClassSpecProb.1.5 = 0
AiPlayerbot.RandomClassSpecIndex.1.5 = 5
# #
# #
@ -1853,12 +1886,24 @@ AiPlayerbot.RandomClassSpecIndex.1.2 = 2
# #
# #
# holy pve
AiPlayerbot.RandomClassSpecProb.2.0 = 30 AiPlayerbot.RandomClassSpecProb.2.0 = 30
AiPlayerbot.RandomClassSpecIndex.2.0 = 0 AiPlayerbot.RandomClassSpecIndex.2.0 = 0
# prot pve
AiPlayerbot.RandomClassSpecProb.2.1 = 40 AiPlayerbot.RandomClassSpecProb.2.1 = 40
AiPlayerbot.RandomClassSpecIndex.2.1 = 1 AiPlayerbot.RandomClassSpecIndex.2.1 = 1
# ret pve
AiPlayerbot.RandomClassSpecProb.2.2 = 30 AiPlayerbot.RandomClassSpecProb.2.2 = 30
AiPlayerbot.RandomClassSpecIndex.2.2 = 2 AiPlayerbot.RandomClassSpecIndex.2.2 = 2
# holy pvp
AiPlayerbot.RandomClassSpecProb.2.3 = 0
AiPlayerbot.RandomClassSpecIndex.2.3 = 3
# prot pvp
AiPlayerbot.RandomClassSpecProb.2.4 = 0
AiPlayerbot.RandomClassSpecIndex.2.4 = 4
# ret pvp
AiPlayerbot.RandomClassSpecProb.2.5 = 0
AiPlayerbot.RandomClassSpecIndex.2.5 = 5
# #
# #
@ -1870,12 +1915,24 @@ AiPlayerbot.RandomClassSpecIndex.2.2 = 2
# #
# #
# bm pve
AiPlayerbot.RandomClassSpecProb.3.0 = 33 AiPlayerbot.RandomClassSpecProb.3.0 = 33
AiPlayerbot.RandomClassSpecIndex.3.0 = 0 AiPlayerbot.RandomClassSpecIndex.3.0 = 0
# mm pve
AiPlayerbot.RandomClassSpecProb.3.1 = 33 AiPlayerbot.RandomClassSpecProb.3.1 = 33
AiPlayerbot.RandomClassSpecIndex.3.1 = 1 AiPlayerbot.RandomClassSpecIndex.3.1 = 1
# surv pve
AiPlayerbot.RandomClassSpecProb.3.2 = 33 AiPlayerbot.RandomClassSpecProb.3.2 = 33
AiPlayerbot.RandomClassSpecIndex.3.2 = 2 AiPlayerbot.RandomClassSpecIndex.3.2 = 2
# bm pvp
AiPlayerbot.RandomClassSpecProb.3.3 = 0
AiPlayerbot.RandomClassSpecIndex.3.3 = 3
# mm pvp
AiPlayerbot.RandomClassSpecProb.3.4 = 0
AiPlayerbot.RandomClassSpecIndex.3.4 = 4
# surv pvp
AiPlayerbot.RandomClassSpecProb.3.5 = 0
AiPlayerbot.RandomClassSpecIndex.3.5 = 5
# #
# #
@ -1887,12 +1944,24 @@ AiPlayerbot.RandomClassSpecIndex.3.2 = 2
# #
# #
# as pve
AiPlayerbot.RandomClassSpecProb.4.0 = 45 AiPlayerbot.RandomClassSpecProb.4.0 = 45
AiPlayerbot.RandomClassSpecIndex.4.0 = 0 AiPlayerbot.RandomClassSpecIndex.4.0 = 0
# combat pve
AiPlayerbot.RandomClassSpecProb.4.1 = 45 AiPlayerbot.RandomClassSpecProb.4.1 = 45
AiPlayerbot.RandomClassSpecIndex.4.1 = 1 AiPlayerbot.RandomClassSpecIndex.4.1 = 1
# subtlety pve
AiPlayerbot.RandomClassSpecProb.4.2 = 10 AiPlayerbot.RandomClassSpecProb.4.2 = 10
AiPlayerbot.RandomClassSpecIndex.4.2 = 2 AiPlayerbot.RandomClassSpecIndex.4.2 = 2
# as pvp
AiPlayerbot.RandomClassSpecProb.4.3 = 0
AiPlayerbot.RandomClassSpecIndex.4.3 = 3
# combat pvp
AiPlayerbot.RandomClassSpecProb.4.4 = 0
AiPlayerbot.RandomClassSpecIndex.4.4 = 4
# subtlety pvp
AiPlayerbot.RandomClassSpecProb.4.5 = 0
AiPlayerbot.RandomClassSpecIndex.4.5 = 5
# #
# #
@ -1904,12 +1973,24 @@ AiPlayerbot.RandomClassSpecIndex.4.2 = 2
# #
# #
# disc pve
AiPlayerbot.RandomClassSpecProb.5.0 = 40 AiPlayerbot.RandomClassSpecProb.5.0 = 40
AiPlayerbot.RandomClassSpecIndex.5.0 = 0 AiPlayerbot.RandomClassSpecIndex.5.0 = 0
# holy pve
AiPlayerbot.RandomClassSpecProb.5.1 = 35 AiPlayerbot.RandomClassSpecProb.5.1 = 35
AiPlayerbot.RandomClassSpecIndex.5.1 = 1 AiPlayerbot.RandomClassSpecIndex.5.1 = 1
# shadow pve
AiPlayerbot.RandomClassSpecProb.5.2 = 25 AiPlayerbot.RandomClassSpecProb.5.2 = 25
AiPlayerbot.RandomClassSpecIndex.5.2 = 2 AiPlayerbot.RandomClassSpecIndex.5.2 = 2
# disc pvp
AiPlayerbot.RandomClassSpecProb.5.3 = 0
AiPlayerbot.RandomClassSpecIndex.5.3 = 3
# holy pvp
AiPlayerbot.RandomClassSpecProb.5.4 = 0
AiPlayerbot.RandomClassSpecIndex.5.4 = 4
# shadow pvp
AiPlayerbot.RandomClassSpecProb.5.5 = 0
AiPlayerbot.RandomClassSpecIndex.5.5 = 5
# #
# #
@ -1921,12 +2002,27 @@ AiPlayerbot.RandomClassSpecIndex.5.2 = 2
# #
# #
# blood pve
AiPlayerbot.RandomClassSpecProb.6.0 = 30 AiPlayerbot.RandomClassSpecProb.6.0 = 30
AiPlayerbot.RandomClassSpecIndex.6.0 = 0 AiPlayerbot.RandomClassSpecIndex.6.0 = 0
# frost pve
AiPlayerbot.RandomClassSpecProb.6.1 = 40 AiPlayerbot.RandomClassSpecProb.6.1 = 40
AiPlayerbot.RandomClassSpecIndex.6.1 = 1 AiPlayerbot.RandomClassSpecIndex.6.1 = 1
# unholy pve
AiPlayerbot.RandomClassSpecProb.6.2 = 30 AiPlayerbot.RandomClassSpecProb.6.2 = 30
AiPlayerbot.RandomClassSpecIndex.6.2 = 2 AiPlayerbot.RandomClassSpecIndex.6.2 = 2
# double aura blood pve
AiPlayerbot.RandomClassSpecProb.6.3 = 0
AiPlayerbot.RandomClassSpecIndex.6.3 = 3
# blood pvp
AiPlayerbot.RandomClassSpecProb.6.4 = 0
AiPlayerbot.RandomClassSpecIndex.6.4 = 4
# frost pvp
AiPlayerbot.RandomClassSpecProb.6.5 = 0
AiPlayerbot.RandomClassSpecIndex.6.5 = 5
# unholy pvp
AiPlayerbot.RandomClassSpecProb.6.6 = 0
AiPlayerbot.RandomClassSpecIndex.6.6 = 6
# #
# #
@ -1938,12 +2034,24 @@ AiPlayerbot.RandomClassSpecIndex.6.2 = 2
# #
# #
# ele pve
AiPlayerbot.RandomClassSpecProb.7.0 = 33 AiPlayerbot.RandomClassSpecProb.7.0 = 33
AiPlayerbot.RandomClassSpecIndex.7.0 = 0 AiPlayerbot.RandomClassSpecIndex.7.0 = 0
# enh pve
AiPlayerbot.RandomClassSpecProb.7.1 = 33 AiPlayerbot.RandomClassSpecProb.7.1 = 33
AiPlayerbot.RandomClassSpecIndex.7.1 = 1 AiPlayerbot.RandomClassSpecIndex.7.1 = 1
# resto pve
AiPlayerbot.RandomClassSpecProb.7.2 = 33 AiPlayerbot.RandomClassSpecProb.7.2 = 33
AiPlayerbot.RandomClassSpecIndex.7.2 = 2 AiPlayerbot.RandomClassSpecIndex.7.2 = 2
# ele pvp
AiPlayerbot.RandomClassSpecProb.7.3 = 0
AiPlayerbot.RandomClassSpecIndex.7.3 = 3
# enh pvp
AiPlayerbot.RandomClassSpecProb.7.4 = 0
AiPlayerbot.RandomClassSpecIndex.7.4 = 4
# resto pvp
AiPlayerbot.RandomClassSpecProb.7.5 = 0
AiPlayerbot.RandomClassSpecIndex.7.5 = 5
# #
# #
@ -1955,12 +2063,27 @@ AiPlayerbot.RandomClassSpecIndex.7.2 = 2
# #
# #
# arcane pve
AiPlayerbot.RandomClassSpecProb.8.0 = 30 AiPlayerbot.RandomClassSpecProb.8.0 = 30
AiPlayerbot.RandomClassSpecIndex.8.0 = 0 AiPlayerbot.RandomClassSpecIndex.8.0 = 0
# fire pve
AiPlayerbot.RandomClassSpecProb.8.1 = 30 AiPlayerbot.RandomClassSpecProb.8.1 = 30
AiPlayerbot.RandomClassSpecIndex.8.1 = 1 AiPlayerbot.RandomClassSpecIndex.8.1 = 1
# frost pve
AiPlayerbot.RandomClassSpecProb.8.2 = 40 AiPlayerbot.RandomClassSpecProb.8.2 = 40
AiPlayerbot.RandomClassSpecIndex.8.2 = 2 AiPlayerbot.RandomClassSpecIndex.8.2 = 2
# frostfire pve
AiPlayerbot.RandomClassSpecProb.8.3 = 0
AiPlayerbot.RandomClassSpecIndex.8.3 = 3
# arcane pvp
AiPlayerbot.RandomClassSpecProb.8.4 = 0
AiPlayerbot.RandomClassSpecIndex.8.4 = 4
# fire pvp
AiPlayerbot.RandomClassSpecProb.8.5 = 0
AiPlayerbot.RandomClassSpecIndex.8.5 = 5
# frost pvp
AiPlayerbot.RandomClassSpecProb.8.6 = 0
AiPlayerbot.RandomClassSpecIndex.8.6 = 6
# #
# #
@ -1972,12 +2095,24 @@ AiPlayerbot.RandomClassSpecIndex.8.2 = 2
# #
# #
# affli pve
AiPlayerbot.RandomClassSpecProb.9.0 = 33 AiPlayerbot.RandomClassSpecProb.9.0 = 33
AiPlayerbot.RandomClassSpecIndex.9.0 = 0 AiPlayerbot.RandomClassSpecIndex.9.0 = 0
# demo pve
AiPlayerbot.RandomClassSpecProb.9.1 = 34 AiPlayerbot.RandomClassSpecProb.9.1 = 34
AiPlayerbot.RandomClassSpecIndex.9.1 = 1 AiPlayerbot.RandomClassSpecIndex.9.1 = 1
# destro pve
AiPlayerbot.RandomClassSpecProb.9.2 = 33 AiPlayerbot.RandomClassSpecProb.9.2 = 33
AiPlayerbot.RandomClassSpecIndex.9.2 = 2 AiPlayerbot.RandomClassSpecIndex.9.2 = 2
# affli pvp
AiPlayerbot.RandomClassSpecProb.9.3 = 0
AiPlayerbot.RandomClassSpecIndex.9.3 = 3
# demo pvp
AiPlayerbot.RandomClassSpecProb.9.4 = 0
AiPlayerbot.RandomClassSpecIndex.9.4 = 4
# destro pvp
AiPlayerbot.RandomClassSpecProb.9.5 = 0
AiPlayerbot.RandomClassSpecIndex.9.5 = 5
# #
# #
@ -1989,14 +2124,27 @@ AiPlayerbot.RandomClassSpecIndex.9.2 = 2
# #
# #
# balance pve
AiPlayerbot.RandomClassSpecProb.11.0 = 20 AiPlayerbot.RandomClassSpecProb.11.0 = 20
AiPlayerbot.RandomClassSpecIndex.11.0 = 0 AiPlayerbot.RandomClassSpecIndex.11.0 = 0
# bear pve
AiPlayerbot.RandomClassSpecProb.11.1 = 25 AiPlayerbot.RandomClassSpecProb.11.1 = 25
AiPlayerbot.RandomClassSpecIndex.11.1 = 1 AiPlayerbot.RandomClassSpecIndex.11.1 = 1
# resto pve
AiPlayerbot.RandomClassSpecProb.11.2 = 35 AiPlayerbot.RandomClassSpecProb.11.2 = 35
AiPlayerbot.RandomClassSpecIndex.11.2 = 2 AiPlayerbot.RandomClassSpecIndex.11.2 = 2
# cat pve
AiPlayerbot.RandomClassSpecProb.11.3 = 20 AiPlayerbot.RandomClassSpecProb.11.3 = 20
AiPlayerbot.RandomClassSpecIndex.11.3 = 3 AiPlayerbot.RandomClassSpecIndex.11.3 = 3
# balance pvp
AiPlayerbot.RandomClassSpecProb.11.4 = 0
AiPlayerbot.RandomClassSpecIndex.11.4 = 4
# cat pvp
AiPlayerbot.RandomClassSpecProb.11.5 = 0
AiPlayerbot.RandomClassSpecIndex.11.5 = 5
# resto pvp
AiPlayerbot.RandomClassSpecProb.11.6 = 0
AiPlayerbot.RandomClassSpecIndex.11.6 = 6
# #
# #

View File

@ -114,6 +114,11 @@ bool AttackAction::Attack(Unit* target, bool /*with_pet*/ /*true*/)
return false; return false;
} }
// Infantry attacks are not allowed from vehicles drivers.
// Check is needed to stop some auto-attack situations.
if (botAI->IsInVehicle() && !botAI->IsInVehicle(false, false, true))
return false;
Unit* oldTarget = context->GetValue<Unit*>("current target")->Get(); Unit* oldTarget = context->GetValue<Unit*>("current target")->Get();
bool shouldMelee = bot->IsWithinMeleeRange(target) || botAI->IsMelee(bot); bool shouldMelee = bot->IsWithinMeleeRange(target) || botAI->IsMelee(bot);

View File

@ -73,7 +73,7 @@ void AutoMaintenanceOnLevelupAction::LearnSpells(std::ostringstream* out)
LearnQuestSpells(out); LearnQuestSpells(out);
} }
void AutoMaintenanceOnLevelupAction::LearnTrainerSpells(std::ostringstream* out) void AutoMaintenanceOnLevelupAction::LearnTrainerSpells(std::ostringstream* /*out*/)
{ {
PlayerbotFactory factory(bot, bot->GetLevel()); PlayerbotFactory factory(bot, bot->GetLevel());
factory.InitSkills(); factory.InitSkills();

View File

@ -27,7 +27,7 @@ bool BankAction::Execute(Event event)
return false; return false;
} }
bool BankAction::ExecuteBank(std::string const text, Unit* bank) bool BankAction::ExecuteBank(std::string const text, Unit* /*bank*/)
{ {
if (text.empty() || text == "?") if (text.empty() || text == "?")
{ {

View File

@ -534,21 +534,18 @@ bool BGJoinAction::JoinQueue(uint32 type)
botAI->GetAiObjectContext()->GetValue<uint32>("bg type")->Set(0); botAI->GetAiObjectContext()->GetValue<uint32>("bg type")->Set(0);
WorldPacket* packet = nullptr;
if (!isArena) if (!isArena)
{ {
WorldPacket* packet = new WorldPacket(CMSG_BATTLEMASTER_JOIN, 20); packet = new WorldPacket(CMSG_BATTLEMASTER_JOIN, 20);
*packet << bot->GetGUID() << bgTypeId_ << instanceId << joinAsGroup; *packet << bot->GetGUID() << bgTypeId_ << instanceId << joinAsGroup;
/// FIX race condition
// bot->GetSession()->HandleBattlemasterJoinOpcode(packet);
bot->GetSession()->QueuePacket(packet);
} }
else else
{ {
WorldPacket arena_packet(CMSG_BATTLEMASTER_JOIN_ARENA, 20); packet = new WorldPacket(CMSG_BATTLEMASTER_JOIN_ARENA, 20);
arena_packet << unit->GetGUID() << arenaslot << asGroup << uint8(isRated); *packet << unit->GetGUID() << arenaslot << asGroup << uint8(isRated);
bot->GetSession()->HandleBattlemasterJoinArena(arena_packet);
} }
bot->GetSession()->QueuePacket(packet);
return true; return true;
} }

View File

@ -21,7 +21,7 @@ public:
} }
bool Execute(Event event) override; bool Execute(Event event) override;
virtual std::string const castString(WorldObject* target) { return "cast"; } virtual std::string const castString(WorldObject* /*target*/) { return "cast"; }
protected: protected:
bool ncCast = false; bool ncCast = false;
@ -49,7 +49,7 @@ public:
bool isUseful() override { return false; } bool isUseful() override { return false; }
virtual bool AcceptSpell(SpellInfo const* spellInfo); virtual bool AcceptSpell(SpellInfo const* spellInfo);
virtual uint32 GetSpellPriority(SpellInfo const* spellInfo) { return 1; } virtual uint32 GetSpellPriority(SpellInfo const* /*spellInfo*/) { return 1; }
virtual bool castSpell(uint32 spellId, WorldObject* wo); virtual bool castSpell(uint32 spellId, WorldObject* wo);
bool Execute(Event event) override; bool Execute(Event event) override;

View File

@ -80,7 +80,7 @@ bool FollowChatShortcutAction::Execute(Event /*event*/)
true, priority); true, priority);
} }
if (Pet* pet = bot->GetPet()) if (bot->GetPet())
botAI->PetFollow(); botAI->PetFollow();
if (moved) if (moved)

View File

@ -116,6 +116,7 @@ bool ChooseRpgTargetAction::Execute(Event /*event*/)
GuidPosition masterRpgTarget; GuidPosition masterRpgTarget;
if (master && master != bot && GET_PLAYERBOT_AI(master) && master->GetMapId() == bot->GetMapId() && !master->IsBeingTeleported()) if (master && master != bot && GET_PLAYERBOT_AI(master) && master->GetMapId() == bot->GetMapId() && !master->IsBeingTeleported())
{ {
//TODO Implement
Player* player = botAI->GetMaster(); Player* player = botAI->GetMaster();
//GuidPosition masterRpgTarget = PAI_VALUE(GuidPosition, "rpg target"); //not used, line marked for removal. //GuidPosition masterRpgTarget = PAI_VALUE(GuidPosition, "rpg target"); //not used, line marked for removal.
} }

View File

@ -62,31 +62,16 @@ bool CleanQuestLogAction::Execute(Event event)
{ {
Player* requester = event.getOwner() ? event.getOwner() : GetMaster(); Player* requester = event.getOwner() ? event.getOwner() : GetMaster();
if (!requester) if (!requester)
{
botAI->TellMaster("No event owner detected");
return false; return false;
}
if (!sPlayerbotAIConfig.dropObsoleteQuests) if (!sPlayerbotAIConfig.dropObsoleteQuests)
{
return false; return false;
}
// Only output this message if "debug rpg" strategy is enabled // Only output this message if "debug rpg" strategy is enabled
if (botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT)) if (botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT))
{
botAI->TellMaster("Clean Quest Log command received, removing grey/trivial quests..."); botAI->TellMaster("Clean Quest Log command received, removing grey/trivial quests...");
}
uint8 botLevel = bot->GetLevel(); // Get bot's level uint8 botLevel = bot->GetLevel(); // Get bot's level
uint8 numQuest = 0;
for (uint8 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot)
{
if (bot->GetQuestSlotQuestId(slot))
{
numQuest++;
}
}
for (uint8 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot) for (uint8 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot)
{ {
@ -101,34 +86,24 @@ bool CleanQuestLogAction::Execute(Event event)
// Determine if quest is trivial by comparing levels // Determine if quest is trivial by comparing levels
int32 questLevel = quest->GetQuestLevel(); int32 questLevel = quest->GetQuestLevel();
if (questLevel == -1) // For scaling quests, default to bot level if (questLevel == -1) // For scaling quests, default to bot level
{
questLevel = botLevel; questLevel = botLevel;
}
// Set the level difference for when a quest becomes trivial // Set the level difference for when a quest becomes trivial
// This was determined by using the Lua code the client uses // This was determined by using the Lua code the client uses
int32 trivialLevel = 5; int32 trivialLevel = 5;
if (botLevel >= 40) if (botLevel >= 40)
{
trivialLevel = 8; trivialLevel = 8;
}
else if (botLevel >= 30) else if (botLevel >= 30)
{
trivialLevel = 7; trivialLevel = 7;
}
else if (botLevel >= 20) else if (botLevel >= 20)
{
trivialLevel = 6; trivialLevel = 6;
}
// Check if the quest is trivial (grey) for the bot // Check if the quest is trivial (grey) for the bot
if ((botLevel - questLevel) > trivialLevel) if ((botLevel - questLevel) > trivialLevel)
{ {
// Output only if "debug rpg" strategy is enabled // Output only if "debug rpg" strategy is enabled
if (botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT)) if (botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT))
{
botAI->TellMaster("Quest [ " + quest->GetTitle() + " ] will be removed because it is trivial (grey)."); botAI->TellMaster("Quest [ " + quest->GetTitle() + " ] will be removed because it is trivial (grey).");
}
// Remove quest // Remove quest
botAI->rpgStatistic.questDropped++; botAI->rpgStatistic.questDropped++;
@ -137,8 +112,6 @@ bool CleanQuestLogAction::Execute(Event event)
bot->SetQuestStatus(questId, QUEST_STATUS_NONE); bot->SetQuestStatus(questId, QUEST_STATUS_NONE);
bot->RemoveRewardedQuest(questId); bot->RemoveRewardedQuest(questId);
numQuest--;
if (botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT)) if (botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT))
{ {
const std::string text_quest = ChatHelper::FormatQuest(quest); const std::string text_quest = ChatHelper::FormatQuest(quest);
@ -147,17 +120,13 @@ bool CleanQuestLogAction::Execute(Event event)
} }
if (botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT)) if (botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT))
{
botAI->TellMaster("Quest [ " + quest->GetTitle() + " ] has been removed."); botAI->TellMaster("Quest [ " + quest->GetTitle() + " ] has been removed.");
}
} }
else else
{ {
// Only output if "debug rpg" strategy is enabled // Only output if "debug rpg" strategy is enabled
if (botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT)) if (botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT))
{
botAI->TellMaster("Quest [ " + quest->GetTitle() + " ] is not trivial and will be kept."); botAI->TellMaster("Quest [ " + quest->GetTitle() + " ] is not trivial and will be kept.");
}
} }
} }
@ -174,7 +143,6 @@ void CleanQuestLogAction::DropQuestType(uint8& numQuest, uint8 wantNum, bool isG
{ {
std::random_device rd; std::random_device rd;
std::mt19937 g(rd()); std::mt19937 g(rd());
std::shuffle(slots.begin(), slots.end(), g); std::shuffle(slots.begin(), slots.end(), g);
} }
@ -200,8 +168,10 @@ void CleanQuestLogAction::DropQuestType(uint8& numQuest, uint8 wantNum, bool isG
bot->GetLevel() <= bot->GetQuestLevel(quest) + uint32(lowLevelDiff)) // Quest is not gray bot->GetLevel() <= bot->GetQuestLevel(quest) + uint32(lowLevelDiff)) // Quest is not gray
{ {
if (bot->GetLevel() + 5 > bot->GetQuestLevel(quest)) // Quest is not red if (bot->GetLevel() + 5 > bot->GetQuestLevel(quest)) // Quest is not red
{
if (!isGreen) if (!isGreen)
continue; continue;
}
} }
else // Quest is gray else // Quest is gray
{ {

View File

@ -168,8 +168,8 @@ bool FollowAction::Execute(Event /*event*/)
? MovementPriority::MOVEMENT_COMBAT ? MovementPriority::MOVEMENT_COMBAT
: MovementPriority::MOVEMENT_NORMAL; : MovementPriority::MOVEMENT_NORMAL;
bool const movingAllowed = IsMovingAllowed(mapId, destX, destY, destZ); bool const movingAllowed = IsMovingAllowed();
bool const dupMove = IsDuplicateMove(mapId, destX, destY, destZ); bool const dupMove = IsDuplicateMove(destX, destY, destZ);
bool const waiting = IsWaitingForLastMove(priority); bool const waiting = IsWaitingForLastMove(priority);
if (movingAllowed && !dupMove && !waiting) if (movingAllowed && !dupMove && !waiting)

View File

@ -53,7 +53,7 @@ bool GuildBankAction::Execute(std::string const text, GameObject* bank)
return result; return result;
} }
bool GuildBankAction::MoveFromCharToBank(Item* item, GameObject* bank) bool GuildBankAction::MoveFromCharToBank(Item* item, GameObject* /*bank*/)
{ {
uint32 playerSlot = item->GetSlot(); uint32 playerSlot = item->GetSlot();
uint32 playerBag = item->GetBagSlot(); uint32 playerBag = item->GetBagSlot();

View File

@ -78,7 +78,7 @@ private:
class TakeMailProcessor : public MailProcessor class TakeMailProcessor : public MailProcessor
{ {
public: public:
bool Process(uint32 index, Mail* mail, PlayerbotAI* botAI) override bool Process(uint32 /*index*/, Mail* mail, PlayerbotAI* botAI) override
{ {
Player* bot = botAI->GetBot(); Player* bot = botAI->GetBot();
if (!CheckBagSpace(bot)) if (!CheckBagSpace(bot))
@ -104,7 +104,7 @@ public:
{ {
std::vector<uint32> guids; std::vector<uint32> guids;
for (MailItemInfoVec::iterator i = mail->items.begin(); i != mail->items.end(); ++i) for (MailItemInfoVec::iterator i = mail->items.begin(); i != mail->items.end(); ++i)
if (ItemTemplate const* proto = sObjectMgr->GetItemTemplate(i->item_template)) if (sObjectMgr->GetItemTemplate(i->item_template))
guids.push_back(i->item_guid); guids.push_back(i->item_guid);
for (std::vector<uint32>::iterator i = guids.begin(); i != guids.end(); ++i) for (std::vector<uint32>::iterator i = guids.begin(); i != guids.end(); ++i)
@ -157,7 +157,7 @@ private:
class DeleteMailProcessor : public MailProcessor class DeleteMailProcessor : public MailProcessor
{ {
public: public:
bool Process(uint32 index, Mail* mail, PlayerbotAI* botAI) override bool Process(uint32 /*index*/, Mail* mail, PlayerbotAI* botAI) override
{ {
std::ostringstream out; std::ostringstream out;
out << "|cffffffff" << mail->subject << "|cffff0000 deleted"; out << "|cffffffff" << mail->subject << "|cffff0000 deleted";
@ -172,7 +172,7 @@ public:
class ReadMailProcessor : public MailProcessor class ReadMailProcessor : public MailProcessor
{ {
public: public:
bool Process(uint32 index, Mail* mail, PlayerbotAI* botAI) override bool Process(uint32 /*index*/, Mail* mail, PlayerbotAI* botAI) override
{ {
std::ostringstream out, body; std::ostringstream out, body;
out << "|cffffffff" << mail->subject; out << "|cffffffff" << mail->subject;

View File

@ -63,10 +63,10 @@ void MovementAction::CreateWp(Player* wpOwner, float x, float y, float z, float
bool MovementAction::JumpTo(uint32 mapId, float x, float y, float z, MovementPriority priority) bool MovementAction::JumpTo(uint32 mapId, float x, float y, float z, MovementPriority priority)
{ {
UpdateMovementState(); UpdateMovementState();
if (!IsMovingAllowed(mapId, x, y, z)) if (!IsMovingAllowed())
return false; return false;
if (IsDuplicateMove(mapId, x, y, z)) if (IsDuplicateMove(x, y, z))
return false; return false;
if (IsWaitingForLastMove(priority)) if (IsWaitingForLastMove(priority))
@ -171,11 +171,11 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle,
bool exact_waypoint, MovementPriority priority, bool lessDelay, bool backwards) bool exact_waypoint, MovementPriority priority, bool lessDelay, bool backwards)
{ {
UpdateMovementState(); UpdateMovementState();
if (!IsMovingAllowed(mapId, x, y, z)) if (!IsMovingAllowed())
{ {
return false; return false;
} }
if (IsDuplicateMove(mapId, x, y, z)) if (IsDuplicateMove(x, y, z))
{ {
return false; return false;
} }
@ -897,20 +897,7 @@ bool MovementAction::IsMovingAllowed(WorldObject* target)
return IsMovingAllowed(); return IsMovingAllowed();
} }
bool MovementAction::IsMovingAllowed(uint32 mapId, float x, float y, float z) bool MovementAction::IsDuplicateMove(float x, float y, float z)
{
// removed sqrt as means distance limit was effectively 22500 (ReactDistance<63>)
// leaving it commented incase we find ReactDistance limit causes problems
// float distance = sqrt(bot->GetDistance(x, y, z));
// Remove react distance limit
// if (!bot->InBattleground())
// return false;
return IsMovingAllowed();
}
bool MovementAction::IsDuplicateMove(uint32 mapId, float x, float y, float z)
{ {
LastMovement& lastMove = *context->GetValue<LastMovement&>("last movement"); LastMovement& lastMove = *context->GetValue<LastMovement&>("last movement");
@ -1286,7 +1273,7 @@ bool MovementAction::Follow(Unit* target, float distance, float angle)
return true; return true;
} }
bool MovementAction::ChaseTo(WorldObject* obj, float distance, float angle) bool MovementAction::ChaseTo(WorldObject* obj, float distance)
{ {
if (!IsMovingAllowed()) if (!IsMovingAllowed())
{ {
@ -1859,7 +1846,7 @@ bool FleeAction::isUseful()
bool FleeWithPetAction::Execute(Event /*event*/) bool FleeWithPetAction::Execute(Event /*event*/)
{ {
if (Pet* pet = bot->GetPet()) if (bot->GetPet())
botAI->PetFollow(); botAI->PetFollow();
return Flee(AI_VALUE(Unit*, "current target")); return Flee(AI_VALUE(Unit*, "current target"));

View File

@ -43,14 +43,13 @@ protected:
float GetFollowAngle(); float GetFollowAngle();
bool Follow(Unit* target, float distance = sPlayerbotAIConfig.followDistance); bool Follow(Unit* target, float distance = sPlayerbotAIConfig.followDistance);
bool Follow(Unit* target, float distance, float angle); bool Follow(Unit* target, float distance, float angle);
bool ChaseTo(WorldObject* obj, float distance = 0.0f, float angle = 0.0f); bool ChaseTo(WorldObject* obj, float distance = 0.0f);
bool ReachCombatTo(Unit* target, float distance = 0.0f); bool ReachCombatTo(Unit* target, float distance = 0.0f);
float MoveDelay(float distance, bool backwards = false); float MoveDelay(float distance, bool backwards = false);
void WaitForReach(float distance); void WaitForReach(float distance);
void SetNextMovementDelay(float delayMillis); void SetNextMovementDelay(float delayMillis);
bool IsMovingAllowed(WorldObject* target); bool IsMovingAllowed(WorldObject* target);
bool IsMovingAllowed(uint32 mapId, float x, float y, float z); bool IsDuplicateMove(float x, float y, float z);
bool IsDuplicateMove(uint32 mapId, float x, float y, float z);
bool IsWaitingForLastMove(MovementPriority priority); bool IsWaitingForLastMove(MovementPriority priority);
bool IsMovingAllowed(); bool IsMovingAllowed();
bool Flee(Unit* target); bool Flee(Unit* target);

View File

@ -45,7 +45,7 @@ std::once_flag ReadyChecker::initFlag;
class HealthChecker : public ReadyChecker class HealthChecker : public ReadyChecker
{ {
public: public:
bool Check(PlayerbotAI* botAI, AiObjectContext* context) override bool Check(PlayerbotAI* /*botAI*/, AiObjectContext* context) override
{ {
return AI_VALUE2(uint8, "health", "self target") > sPlayerbotAIConfig.almostFullHealth; return AI_VALUE2(uint8, "health", "self target") > sPlayerbotAIConfig.almostFullHealth;
} }
@ -56,7 +56,7 @@ public:
class ManaChecker : public ReadyChecker class ManaChecker : public ReadyChecker
{ {
public: public:
bool Check(PlayerbotAI* botAI, AiObjectContext* context) override bool Check(PlayerbotAI* /*botAI*/, AiObjectContext* context) override
{ {
return !AI_VALUE2(bool, "has mana", "self target") || return !AI_VALUE2(bool, "has mana", "self target") ||
AI_VALUE2(uint8, "mana", "self target") > sPlayerbotAIConfig.mediumHealth; AI_VALUE2(uint8, "mana", "self target") > sPlayerbotAIConfig.mediumHealth;
@ -68,7 +68,7 @@ public:
class DistanceChecker : public ReadyChecker class DistanceChecker : public ReadyChecker
{ {
public: public:
bool Check(PlayerbotAI* botAI, AiObjectContext* context) override bool Check(PlayerbotAI* botAI, AiObjectContext* /*context*/) override
{ {
Player* bot = botAI->GetBot(); Player* bot = botAI->GetBot();
if (Player* master = botAI->GetMaster()) if (Player* master = botAI->GetMaster())
@ -90,7 +90,7 @@ public:
class HunterChecker : public ReadyChecker class HunterChecker : public ReadyChecker
{ {
public: public:
bool Check(PlayerbotAI* botAI, AiObjectContext* context) override bool Check(PlayerbotAI* botAI, AiObjectContext* /*context*/) override
{ {
Player* bot = botAI->GetBot(); Player* bot = botAI->GetBot();
if (bot->getClass() == CLASS_HUNTER) if (bot->getClass() == CLASS_HUNTER)
@ -126,7 +126,7 @@ class ItemCountChecker : public ReadyChecker
public: public:
ItemCountChecker(std::string const item, std::string const name) : item(item), name(name) {} ItemCountChecker(std::string const item, std::string const name) : item(item), name(name) {}
bool Check(PlayerbotAI* botAI, AiObjectContext* context) override bool Check(PlayerbotAI* /*botAI*/, AiObjectContext* context) override
{ {
return AI_VALUE2(uint32, "item count", item) > 0; return AI_VALUE2(uint32, "item count", item) > 0;
} }
@ -225,4 +225,4 @@ bool ReadyCheckAction::ReadyCheck()
return true; return true;
} }
bool FinishReadyCheckAction::Execute(Event event) { return ReadyCheck(); } bool FinishReadyCheckAction::Execute(Event /*event*/) { return ReadyCheck(); }

View File

@ -65,7 +65,7 @@ void ReleaseSpiritAction::IncrementDeathCount() const
} }
} }
void ReleaseSpiritAction::LogRelease(const std::string& releaseMsg, bool isAutoRelease) const void ReleaseSpiritAction::LogRelease(const std::string& releaseMsg) const
{ {
const std::string teamPrefix = bot->GetTeamId() == TEAM_ALLIANCE ? "A" : "H"; const std::string teamPrefix = bot->GetTeamId() == TEAM_ALLIANCE ? "A" : "H";
@ -82,13 +82,13 @@ bool AutoReleaseSpiritAction::Execute(Event /*event*/)
{ {
IncrementDeathCount(); IncrementDeathCount();
bot->DurabilityRepairAll(false, 1.0f, false); bot->DurabilityRepairAll(false, 1.0f, false);
LogRelease("auto released", true); LogRelease("auto released");
WorldPacket packet(CMSG_REPOP_REQUEST); WorldPacket packet(CMSG_REPOP_REQUEST);
packet << uint8(0); packet << uint8(0);
bot->GetSession()->HandleRepopRequestOpcode(packet); bot->GetSession()->HandleRepopRequestOpcode(packet);
LogRelease("releases spirit", true); LogRelease("releases spirit");
if (bot->InBattleground()) if (bot->InBattleground())
{ {

View File

@ -18,7 +18,7 @@ public:
: Action(botAI, name) {} : Action(botAI, name) {}
bool Execute(Event event) override; bool Execute(Event event) override;
void LogRelease(const std::string& releaseType, bool isAutoRelease = false) const; void LogRelease(const std::string& releaseType) const;
protected: protected:
void IncrementDeathCount() const; void IncrementDeathCount() const;

View File

@ -251,9 +251,9 @@ GraveyardStruct const* SpiritHealerAction::GetGrave(bool startZone)
std::vector<uint32> races; std::vector<uint32> races;
if (bot->GetTeamId() == TEAM_ALLIANCE) if (bot->GetTeamId() == TEAM_ALLIANCE)
races = {RACE_HUMAN, RACE_DWARF, RACE_GNOME, RACE_NIGHTELF}; races = {RACE_HUMAN, RACE_DWARF, RACE_GNOME, RACE_NIGHTELF, RACE_DRAENEI};
else else
races = {RACE_ORC, RACE_TROLL, RACE_TAUREN, RACE_UNDEAD_PLAYER}; races = {RACE_ORC, RACE_TROLL, RACE_TAUREN, RACE_UNDEAD_PLAYER, RACE_BLOODELF};
float graveDistance = -1; float graveDistance = -1;

View File

@ -154,7 +154,7 @@ bool SayAction::isUseful()
return (time(nullptr) - lastSaid) > 30; return (time(nullptr) - lastSaid) > 30;
} }
void ChatReplyAction::ChatReplyDo(Player* bot, uint32& type, uint32& guid1, uint32& guid2, std::string& msg, std::string& chanName, std::string& name) void ChatReplyAction::ChatReplyDo(Player* bot, uint32& type, uint32& guid1, std::string& msg, std::string& chanName, std::string& name)
{ {
std::string respondsText = ""; std::string respondsText = "";
@ -205,14 +205,14 @@ void ChatReplyAction::ChatReplyDo(Player* bot, uint32& type, uint32& guid1, uint
if (msg.starts_with(sPlayerbotAIConfig.toxicLinksPrefix) if (msg.starts_with(sPlayerbotAIConfig.toxicLinksPrefix)
&& (GET_PLAYERBOT_AI(bot)->GetChatHelper()->ExtractAllItemIds(msg).size() > 0 || GET_PLAYERBOT_AI(bot)->GetChatHelper()->ExtractAllQuestIds(msg).size() > 0)) && (GET_PLAYERBOT_AI(bot)->GetChatHelper()->ExtractAllItemIds(msg).size() > 0 || GET_PLAYERBOT_AI(bot)->GetChatHelper()->ExtractAllQuestIds(msg).size() > 0))
{ {
HandleToxicLinksReply(bot, chatChannelSource, msg, name); HandleToxicLinksReply(bot, chatChannelSource);
return; return;
} }
//thunderfury //thunderfury
if (GET_PLAYERBOT_AI(bot)->GetChatHelper()->ExtractAllItemIds(msg).count(19019)) if (GET_PLAYERBOT_AI(bot)->GetChatHelper()->ExtractAllItemIds(msg).count(19019))
{ {
HandleThunderfuryReply(bot, chatChannelSource, msg, name); HandleThunderfuryReply(bot, chatChannelSource);
return; return;
} }
@ -220,7 +220,7 @@ void ChatReplyAction::ChatReplyDo(Player* bot, uint32& type, uint32& guid1, uint
SendGeneralResponse(bot, chatChannelSource, messageRepy, name); SendGeneralResponse(bot, chatChannelSource, messageRepy, name);
} }
bool ChatReplyAction::HandleThunderfuryReply(Player* bot, ChatChannelSource chatChannelSource, std::string& msg, std::string& name) bool ChatReplyAction::HandleThunderfuryReply(Player* bot, ChatChannelSource chatChannelSource)
{ {
std::map<std::string, std::string> placeholders; std::map<std::string, std::string> placeholders;
const auto thunderfury = sObjectMgr->GetItemTemplate(19019); const auto thunderfury = sObjectMgr->GetItemTemplate(19019);
@ -248,7 +248,7 @@ bool ChatReplyAction::HandleThunderfuryReply(Player* bot, ChatChannelSource chat
return true; return true;
} }
bool ChatReplyAction::HandleToxicLinksReply(Player* bot, ChatChannelSource chatChannelSource, std::string& msg, std::string& name) bool ChatReplyAction::HandleToxicLinksReply(Player* bot, ChatChannelSource chatChannelSource)
{ {
//quests //quests
std::vector<uint32> incompleteQuests; std::vector<uint32> incompleteQuests;

View File

@ -29,12 +29,12 @@ class ChatReplyAction : public Action
{ {
public: public:
ChatReplyAction(PlayerbotAI* ai) : Action(ai, "chat message") {} ChatReplyAction(PlayerbotAI* ai) : Action(ai, "chat message") {}
virtual bool Execute(Event event) { return true; } virtual bool Execute(Event /*event*/) { return true; }
bool isUseful() { return true; } bool isUseful() { return true; }
static void ChatReplyDo(Player* bot, uint32& type, uint32& guid1, uint32& guid2, std::string& msg, std::string& chanName, std::string& name); static void ChatReplyDo(Player* bot, uint32& type, uint32& guid1, std::string& msg, std::string& chanName, std::string& name);
static bool HandleThunderfuryReply(Player* bot, ChatChannelSource chatChannelSource, std::string& msg, std::string& name); static bool HandleThunderfuryReply(Player* bot, ChatChannelSource chatChannelSource);
static bool HandleToxicLinksReply(Player* bot, ChatChannelSource chatChannelSource, std::string& msg, std::string& name); static bool HandleToxicLinksReply(Player* bot, ChatChannelSource chatChannelSource);
static bool HandleWTBItemsReply(Player* bot, ChatChannelSource chatChannelSource, std::string& msg, std::string& name); static bool HandleWTBItemsReply(Player* bot, ChatChannelSource chatChannelSource, std::string& msg, std::string& name);
static bool HandleLFGQuestsReply(Player* bot, ChatChannelSource chatChannelSource, std::string& msg, std::string& name); static bool HandleLFGQuestsReply(Player* bot, ChatChannelSource chatChannelSource, std::string& msg, std::string& name);
static bool SendGeneralResponse(Player* bot, ChatChannelSource chatChannelSource, std::string& responseMessage, std::string& name); static bool SendGeneralResponse(Player* bot, ChatChannelSource chatChannelSource, std::string& responseMessage, std::string& name);

View File

@ -15,7 +15,7 @@
std::set<uint32> const FISHING_SPELLS = {7620, 7731, 7732, 18248, 33095, 51294}; std::set<uint32> const FISHING_SPELLS = {7620, 7731, 7732, 18248, 33095, 51294};
Creature* SeeSpellAction::CreateWps(Player* wpOwner, float x, float y, float z, float o, uint32 entry, Creature* lastWp, Creature* SeeSpellAction::CreateWps(Player* wpOwner, float x, float y, float z, float o, uint32 entry, Creature* /*lastWp*/,
bool important) bool important)
{ {
float dist = wpOwner->GetDistance(x, y, z); float dist = wpOwner->GetDistance(x, y, z);

View File

@ -61,7 +61,7 @@ bool SummonAction::Execute(Event /*event*/)
if (!master) if (!master)
return false; return false;
if (Pet* pet = bot->GetPet()) if (bot->GetPet())
botAI->PetFollow(); botAI->PetFollow();
if (master->GetSession()->GetSecurity() >= SEC_PLAYER) if (master->GetSession()->GetSecurity() >= SEC_PLAYER)

View File

@ -11,7 +11,7 @@ public:
ChatCommandActionNodeFactoryInternal() { creators["tank attack chat shortcut"] = &tank_attack_chat_shortcut; } ChatCommandActionNodeFactoryInternal() { creators["tank attack chat shortcut"] = &tank_attack_chat_shortcut; }
private: private:
static ActionNode* tank_attack_chat_shortcut(PlayerbotAI* botAI) static ActionNode* tank_attack_chat_shortcut(PlayerbotAI* /*botAI*/)
{ {
return new ActionNode("tank attack chat shortcut", return new ActionNode("tank attack chat shortcut",
/*P*/ {}, /*P*/ {},

View File

@ -64,11 +64,11 @@ std::vector<NextAction> AvoidAoeStrategy::getDefaultActions()
}; };
} }
void AvoidAoeStrategy::InitTriggers(std::vector<TriggerNode*>& triggers) void AvoidAoeStrategy::InitTriggers(std::vector<TriggerNode*>& /*triggers*/)
{ {
} }
void AvoidAoeStrategy::InitMultipliers(std::vector<Multiplier*>& multipliers) void AvoidAoeStrategy::InitMultipliers(std::vector<Multiplier*>& /*multipliers*/)
{ {
} }
@ -81,7 +81,7 @@ std::vector<NextAction> TankFaceStrategy::getDefaultActions()
}; };
} }
void TankFaceStrategy::InitTriggers(std::vector<TriggerNode*>& triggers) void TankFaceStrategy::InitTriggers(std::vector<TriggerNode*>& /*triggers*/)
{ {
} }

View File

@ -17,6 +17,6 @@ void DuelStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
DuelStrategy::DuelStrategy(PlayerbotAI* botAI) : PassTroughStrategy(botAI) {} DuelStrategy::DuelStrategy(PlayerbotAI* botAI) : PassTroughStrategy(botAI) {}
void StartDuelStrategy::InitTriggers(std::vector<TriggerNode*>& triggers) {} void StartDuelStrategy::InitTriggers(std::vector<TriggerNode*>& /*triggers*/) {}
StartDuelStrategy::StartDuelStrategy(PlayerbotAI* botAI) : Strategy(botAI) {} StartDuelStrategy::StartDuelStrategy(PlayerbotAI* botAI) : Strategy(botAI) {}

View File

@ -12,6 +12,6 @@ std::vector<NextAction> FollowMasterStrategy::getDefaultActions()
}; };
} }
void FollowMasterStrategy::InitTriggers(std::vector<TriggerNode*>& triggers) void FollowMasterStrategy::InitTriggers(std::vector<TriggerNode*>& /*triggers*/)
{ {
} }

View File

@ -12,4 +12,4 @@ std::vector<NextAction> GuardStrategy::getDefaultActions()
}; };
} }
void GuardStrategy::InitTriggers(std::vector<TriggerNode*>& triggers) {} void GuardStrategy::InitTriggers(std::vector<TriggerNode*>& /*triggers*/) {}

View File

@ -13,7 +13,7 @@ void MaintenanceStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{ {
triggers.push_back( triggers.push_back(
new TriggerNode( new TriggerNode(
"random", "seldom",
{ {
NextAction("clean quest log", 6.0f) NextAction("clean quest log", 6.0f)
} }

View File

@ -17,7 +17,7 @@ void CollisionStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
new TriggerNode("collision", { NextAction("move out of collision", 2.0f) })); new TriggerNode("collision", { NextAction("move out of collision", 2.0f) }));
} }
void MountStrategy::InitTriggers(std::vector<TriggerNode*>& triggers) void MountStrategy::InitTriggers(std::vector<TriggerNode*>& /*triggers*/)
{ {
} }

View File

@ -49,7 +49,7 @@ PullStrategy* PullStrategy::Get(PlayerbotAI* botAI)
Unit* PullStrategy::GetTarget() const Unit* PullStrategy::GetTarget() const
{ {
ObjectGuid const guid = botAI->GetAiObjectContext()->GetValue<ObjectGuid>("pull target")->Get(); ObjectGuid const guid = botAI->GetAiObjectContext()->GetValue<ObjectGuid>("pull strategy target")->Get();
if (guid.IsEmpty()) if (guid.IsEmpty())
return nullptr; return nullptr;
@ -66,7 +66,7 @@ bool PullStrategy::HasTarget() const { return GetTarget() != nullptr; }
void PullStrategy::SetTarget(Unit* target) void PullStrategy::SetTarget(Unit* target)
{ {
botAI->GetAiObjectContext()->GetValue<ObjectGuid>("pull target")->Set(target ? target->GetGUID() : ObjectGuid::Empty); botAI->GetAiObjectContext()->GetValue<ObjectGuid>("pull strategy target")->Set(target ? target->GetGUID() : ObjectGuid::Empty);
} }
std::string PullStrategy::GetPullActionName() const std::string PullStrategy::GetPullActionName() const

View File

@ -7,4 +7,4 @@
RTSCStrategy::RTSCStrategy(PlayerbotAI* botAI) : Strategy(botAI) {} RTSCStrategy::RTSCStrategy(PlayerbotAI* botAI) : Strategy(botAI) {}
void RTSCStrategy::InitTriggers(std::vector<TriggerNode*>& triggers) {} void RTSCStrategy::InitTriggers(std::vector<TriggerNode*>& /*triggers*/) {}

View File

@ -11,7 +11,7 @@ public:
RacialsStrategyActionNodeFactory() { creators["lifeblood"] = &lifeblood; } RacialsStrategyActionNodeFactory() { creators["lifeblood"] = &lifeblood; }
private: private:
static ActionNode* lifeblood(PlayerbotAI* botAI) static ActionNode* lifeblood(PlayerbotAI* /*botAI*/)
{ {
return new ActionNode("lifeblood", return new ActionNode("lifeblood",
/*P*/ {}, /*P*/ {},

View File

@ -11,7 +11,7 @@ public:
UsePotionsStrategyActionNodeFactory() { creators["healthstone"] = &healthstone; } UsePotionsStrategyActionNodeFactory() { creators["healthstone"] = &healthstone; }
private: private:
static ActionNode* healthstone(PlayerbotAI* botAI) static ActionNode* healthstone(PlayerbotAI* /*botAI*/)
{ {
return new ActionNode("healthstone", return new ActionNode("healthstone",
/*P*/ {}, /*P*/ {},

View File

@ -19,6 +19,7 @@ WorldLocation ArrowFormation::GetLocationInternal()
uint32 tankLines = 1 + tanks.Size() / 6; uint32 tankLines = 1 + tanks.Size() / 6;
uint32 meleeLines = 1 + melee.Size() / 6; uint32 meleeLines = 1 + melee.Size() / 6;
uint32 rangedLines = 1 + ranged.Size() / 6; uint32 rangedLines = 1 + ranged.Size() / 6;
//TODO Implement Healer Lines
uint32 healerLines = 1 + healers.Size() / 6; uint32 healerLines = 1 + healers.Size() / 6;
float offset = 0.f; float offset = 0.f;
@ -147,7 +148,7 @@ UnitPosition MultiLineUnitPlacer::Place(FormationUnit* unit, uint32 index, uint3
return placer.Place(unit, indexInLine, lineSize); return placer.Place(unit, indexInLine, lineSize);
} }
UnitPosition SingleLineUnitPlacer::Place(FormationUnit* unit, uint32 index, uint32 count) UnitPosition SingleLineUnitPlacer::Place(FormationUnit* /*unit*/, uint32 index, uint32 count)
{ {
float angle = orientation - M_PI / 2.0f; float angle = orientation - M_PI / 2.0f;
float x = cos(angle) * sPlayerbotAIConfig.followDistance * ((float)index - (float)count / 2); float x = cos(angle) * sPlayerbotAIConfig.followDistance * ((float)index - (float)count / 2);

View File

@ -20,7 +20,7 @@ public:
} }
public: public:
void CheckAttacker(Unit* creature, ThreatManager* threatMgr) override void CheckAttacker(Unit* creature, ThreatManager* /*threatMgr*/) override
{ {
Player* bot = botAI->GetBot(); Player* bot = botAI->GetBot();
if (!botAI->CanCastSpell(spell, creature)) if (!botAI->CanCastSpell(spell, creature))

View File

@ -13,7 +13,7 @@ public:
{ {
} }
void CheckAttacker(Unit* attacker, ThreatManager* threatMgr) override void CheckAttacker(Unit* attacker, ThreatManager* /*threatMgr*/) override
{ {
if (botAI->HasAura(spell, attacker)) if (botAI->HasAura(spell, attacker))
result = attacker; result = attacker;

View File

@ -50,7 +50,7 @@ public:
result = nullptr; result = nullptr;
} }
void CheckAttacker(Unit* attacker, ThreatManager* threatMgr) override void CheckAttacker(Unit* attacker, ThreatManager* /*threatMgr*/) override
{ {
if (Group* group = botAI->GetBot()->GetGroup()) if (Group* group = botAI->GetBot()->GetGroup())
{ {

View File

@ -11,8 +11,6 @@ std::vector<Item*> InventoryItemValueBase::Find(std::string const qualifier)
{ {
std::vector<Item*> result; std::vector<Item*> result;
Player* bot = InventoryAction::botAI->GetBot();
std::vector<Item*> items = InventoryAction::parseItems(qualifier); std::vector<Item*> items = InventoryAction::parseItems(qualifier);
for (Item* item : items) for (Item* item : items)
result.push_back(item); result.push_back(item);

View File

@ -17,7 +17,7 @@ class InventoryItemValueBase : public InventoryAction
public: public:
InventoryItemValueBase(PlayerbotAI* botAI) : InventoryAction(botAI, "empty") {} InventoryItemValueBase(PlayerbotAI* botAI) : InventoryAction(botAI, "empty") {}
bool Execute(Event event) override { return false; } bool Execute(Event /*event*/) override { return false; }
protected: protected:
std::vector<Item*> Find(std::string const qualifier); std::vector<Item*> Find(std::string const qualifier);

View File

@ -48,23 +48,6 @@ Item* ItemForSpellValue::Calculate()
} }
} }
// Workaround as some spells have no item mask (e.g. shaman weapon enhancements)
if (!strcmpi(spellInfo->SpellName[0], "rockbiter weapon") ||
!strcmpi(spellInfo->SpellName[0], "flametongue weapon") ||
!strcmpi(spellInfo->SpellName[0], "earthliving weapon") ||
!strcmpi(spellInfo->SpellName[0], "frostbrand weapon") || !strcmpi(spellInfo->SpellName[0], "windfury weapon"))
{
itemForSpell = GetItemFitsToSpellRequirements(EQUIPMENT_SLOT_MAINHAND, spellInfo);
if (itemForSpell && itemForSpell->GetTemplate()->Class == ITEM_CLASS_WEAPON)
return itemForSpell;
itemForSpell = GetItemFitsToSpellRequirements(EQUIPMENT_SLOT_OFFHAND, spellInfo);
if (itemForSpell && itemForSpell->GetTemplate()->Class == ITEM_CLASS_WEAPON)
return itemForSpell;
return nullptr;
}
if (!(spellInfo->Targets & TARGET_FLAG_ITEM)) if (!(spellInfo->Targets & TARGET_FLAG_ITEM))
return nullptr; return nullptr;

View File

@ -234,6 +234,11 @@ ItemUsage ItemUsageValue::QueryItemUsageForEquip(ItemTemplate const* itemProto,
calculator.SetItemSetBonus(false); calculator.SetItemSetBonus(false);
calculator.SetOverflowPenalty(false); calculator.SetOverflowPenalty(false);
// Apply PvP weights if the bot is specced for PvP
bool isPvp = sRandomPlayerbotMgr.IsSpecPvp(bot->GetGUID().GetCounter(), bot->getClass());
if (isPvp)
calculator.SetPvpSpec(true);
float itemScore = calculator.CalculateItem(itemProto->ItemId, randomPropertyId); float itemScore = calculator.CalculateItem(itemProto->ItemId, randomPropertyId);
if (itemScore) if (itemScore)
@ -864,8 +869,6 @@ bool ItemUsageValue::SpellGivesSkillUp(uint32 spellId, Player* bot)
{ {
uint32 SkillValue = bot->GetPureSkillValue(skill->SkillLine); uint32 SkillValue = bot->GetPureSkillValue(skill->SkillLine);
uint32 craft_skill_gain = sWorld->getIntConfig(CONFIG_SKILL_GAIN_CRAFTING);
if (SkillGainChance(SkillValue, skill->TrivialSkillLineRankHigh, if (SkillGainChance(SkillValue, skill->TrivialSkillLineRankHigh,
(skill->TrivialSkillLineRankHigh + skill->TrivialSkillLineRankLow) / 2, (skill->TrivialSkillLineRankHigh + skill->TrivialSkillLineRankLow) / 2,
skill->TrivialSkillLineRankLow) > 0) skill->TrivialSkillLineRankLow) > 0)

View File

@ -13,7 +13,7 @@ class FindLeastHpTargetStrategy : public FindNonCcTargetStrategy
public: public:
FindLeastHpTargetStrategy(PlayerbotAI* botAI) : FindNonCcTargetStrategy(botAI), minHealth(0) {} FindLeastHpTargetStrategy(PlayerbotAI* botAI) : FindNonCcTargetStrategy(botAI), minHealth(0) {}
void CheckAttacker(Unit* attacker, ThreatManager* threatMgr) override void CheckAttacker(Unit* attacker, ThreatManager* /*threatMgr*/) override
{ {
if (IsCcTarget(attacker)) if (IsCcTarget(attacker))
return; return;

View File

@ -60,7 +60,7 @@ public:
class AllLootStrategy : public LootStrategy class AllLootStrategy : public LootStrategy
{ {
public: public:
bool CanLoot(ItemTemplate const* proto, AiObjectContext* context) override { return true; } bool CanLoot(ItemTemplate const* /*proto*/, AiObjectContext* /*context*/) override { return true; }
std::string const GetName() override { return "all"; } std::string const GetName() override { return "all"; }
}; };

View File

@ -28,4 +28,4 @@ void NearestCorpsesValue::FindUnits(std::list<Unit*>& targets)
Cell::VisitObjects(bot, searcher, range); Cell::VisitObjects(bot, searcher, range);
} }
bool NearestCorpsesValue::AcceptUnit(Unit* unit) { return true; } bool NearestCorpsesValue::AcceptUnit(Unit* /*unit*/) { return true; }

View File

@ -27,7 +27,7 @@ Unit* PartyMemberValue::FindPartyMember(std::vector<Player*>* party, FindPlayerP
return nullptr; return nullptr;
} }
Unit* PartyMemberValue::FindPartyMember(FindPlayerPredicate& predicate, bool ignoreOutOfGroup) Unit* PartyMemberValue::FindPartyMember(FindPlayerPredicate& predicate, bool /*ignoreOutOfGroup*/)
{ {
Player* master = GetMaster(); Player* master = GetMaster();
// GuidVector nearestPlayers; // GuidVector nearestPlayers;

View File

@ -40,13 +40,13 @@ bool SpellCastUsefulValue::Calculate()
return false; return false;
} }
// TODO: workaround if (qualifier == "windfury weapon" || qualifier == "flametongue weapon" ||
if (qualifier == "windfury weapon" || qualifier == "flametongue weapon" || qualifier == "frostbrand weapon" || qualifier == "frostbrand weapon" || qualifier == "rockbiter weapon" ||
qualifier == "rockbiter weapon" || qualifier == "earthliving weapon" || qualifier == "spellstone") qualifier == "earthliving weapon" || qualifier == "spellstone")
{ {
if (Item* item = AI_VALUE2(Item*, "item for spell", spellid)) if (Item* item = AI_VALUE2(Item*, "item for spell", spellid);
if (item->IsInWorld() && item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT)) item && item->IsInWorld() && item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT))
return false; return false;
} }
std::set<uint32>& skipSpells = AI_VALUE(std::set<uint32>&, "skip spells list"); std::set<uint32>& skipSpells = AI_VALUE(std::set<uint32>&, "skip spells list");

View File

@ -49,7 +49,7 @@ class FindTankTargetSmartStrategy : public FindTargetStrategy
public: public:
FindTankTargetSmartStrategy(PlayerbotAI* botAI) : FindTargetStrategy(botAI) {} FindTankTargetSmartStrategy(PlayerbotAI* botAI) : FindTargetStrategy(botAI) {}
void CheckAttacker(Unit* attacker, ThreatManager* threatMgr) override void CheckAttacker(Unit* attacker, ThreatManager* /*threatMgr*/) override
{ {
if (Group* group = botAI->GetBot()->GetGroup()) if (Group* group = botAI->GetBot()->GetGroup())
{ {

View File

@ -161,7 +161,7 @@ Unit* FindTargetValue::Calculate()
return nullptr; return nullptr;
} }
void FindBossTargetStrategy::CheckAttacker(Unit* attacker, ThreatManager* threatManager) void FindBossTargetStrategy::CheckAttacker(Unit* attacker, ThreatManager* /*threatManager*/)
{ {
UnitAI* unitAI = attacker->GetAI(); UnitAI* unitAI = attacker->GetAI();
BossAI* bossAI = dynamic_cast<BossAI*>(unitAI); BossAI* bossAI = dynamic_cast<BossAI*>(unitAI);

View File

@ -116,6 +116,15 @@ public:
} }
}; };
class PullStrategyTargetValue : public ManualSetValue<ObjectGuid>
{
public:
PullStrategyTargetValue(PlayerbotAI* botAI, std::string const name = "pull strategy target")
: ManualSetValue<ObjectGuid>(botAI, ObjectGuid::Empty, name)
{
}
};
class FindTargetValue : public UnitCalculatedValue, public Qualified class FindTargetValue : public UnitCalculatedValue, public Qualified
{ {
public: public:

View File

@ -241,6 +241,7 @@ public:
creators["travel target"] = &ValueContext::travel_target; creators["travel target"] = &ValueContext::travel_target;
creators["talk target"] = &ValueContext::talk_target; creators["talk target"] = &ValueContext::talk_target;
creators["pull target"] = &ValueContext::pull_target; creators["pull target"] = &ValueContext::pull_target;
creators["pull strategy target"] = &ValueContext::pull_strategy_target;
creators["focus heal targets"] = &ValueContext::focus_heal_targets; creators["focus heal targets"] = &ValueContext::focus_heal_targets;
creators["group"] = &ValueContext::group; creators["group"] = &ValueContext::group;
creators["range"] = &ValueContext::range; creators["range"] = &ValueContext::range;
@ -498,6 +499,7 @@ private:
static UntypedValue* next_rpg_action(PlayerbotAI* botAI) { return new NextRpgActionValue(botAI); } static UntypedValue* next_rpg_action(PlayerbotAI* botAI) { return new NextRpgActionValue(botAI); }
static UntypedValue* travel_target(PlayerbotAI* botAI) { return new TravelTargetValue(botAI); } static UntypedValue* travel_target(PlayerbotAI* botAI) { return new TravelTargetValue(botAI); }
static UntypedValue* pull_target(PlayerbotAI* botAI) { return new PullTargetValue(botAI); } static UntypedValue* pull_target(PlayerbotAI* botAI) { return new PullTargetValue(botAI); }
static UntypedValue* pull_strategy_target(PlayerbotAI* botAI) { return new PullStrategyTargetValue(botAI); }
static UntypedValue* focus_heal_targets(PlayerbotAI* botAI) { return new FocusHealTargetValue(botAI); } static UntypedValue* focus_heal_targets(PlayerbotAI* botAI) { return new FocusHealTargetValue(botAI); }
static UntypedValue* bg_master(PlayerbotAI* botAI) { return new BgMasterValue(botAI); } static UntypedValue* bg_master(PlayerbotAI* botAI) { return new BgMasterValue(botAI); }

View File

@ -47,7 +47,7 @@ void GenericDKNonCombatStrategy::InitTriggers(std::vector<TriggerNode*>& trigger
new TriggerNode("bone shield", { NextAction("bone shield", 21.0f) })); new TriggerNode("bone shield", { NextAction("bone shield", 21.0f) }));
} }
void DKBuffDpsStrategy::InitTriggers(std::vector<TriggerNode*>& triggers) void DKBuffDpsStrategy::InitTriggers(std::vector<TriggerNode*>& /*triggers*/)
{ {
} }

View File

@ -311,4 +311,4 @@ void CatDpsDruidStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
); );
} }
void CatAoeDruidStrategy::InitTriggers(std::vector<TriggerNode*>& triggers) {} void CatAoeDruidStrategy::InitTriggers(std::vector<TriggerNode*>& /*triggers*/) {}

View File

@ -392,7 +392,7 @@ class CastExplosiveShotRank4Action : public CastExplosiveShotBaseAction
public: public:
CastExplosiveShotRank4Action(PlayerbotAI* botAI) : CastExplosiveShotRank4Action(PlayerbotAI* botAI) :
CastExplosiveShotBaseAction(botAI) {} CastExplosiveShotBaseAction(botAI) {}
bool Execute(Event event) override bool Execute(Event /*event*/) override
{ {
return botAI->CastSpell(60053, GetTarget()); return botAI->CastSpell(60053, GetTarget());
} }
@ -412,7 +412,7 @@ class CastExplosiveShotRank3Action : public CastExplosiveShotBaseAction
public: public:
CastExplosiveShotRank3Action(PlayerbotAI* botAI) : CastExplosiveShotRank3Action(PlayerbotAI* botAI) :
CastExplosiveShotBaseAction(botAI) {} CastExplosiveShotBaseAction(botAI) {}
bool Execute(Event event) override bool Execute(Event /*event*/) override
{ {
return botAI->CastSpell(60052, GetTarget()); return botAI->CastSpell(60052, GetTarget());
} }
@ -432,7 +432,7 @@ class CastExplosiveShotRank2Action : public CastExplosiveShotBaseAction
public: public:
CastExplosiveShotRank2Action(PlayerbotAI* botAI) : CastExplosiveShotRank2Action(PlayerbotAI* botAI) :
CastExplosiveShotBaseAction(botAI) {} CastExplosiveShotBaseAction(botAI) {}
bool Execute(Event event) override bool Execute(Event /*event*/) override
{ {
return botAI->CastSpell(60051, GetTarget()); return botAI->CastSpell(60051, GetTarget());
} }
@ -452,7 +452,7 @@ class CastExplosiveShotRank1Action : public CastExplosiveShotBaseAction
public: public:
CastExplosiveShotRank1Action(PlayerbotAI* botAI) : CastExplosiveShotRank1Action(PlayerbotAI* botAI) :
CastExplosiveShotBaseAction(botAI) {} CastExplosiveShotBaseAction(botAI) {}
bool Execute(Event event) override bool Execute(Event /*event*/) override
{ {
return botAI->CastSpell(53301, GetTarget()); return botAI->CastSpell(53301, GetTarget());
} }

View File

@ -54,7 +54,7 @@ void PaladinCureStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{ NextAction("cleanse magic on party", ACTION_DISPEL + 1) })); { NextAction("cleanse magic on party", ACTION_DISPEL + 1) }));
} }
void PaladinBoostStrategy::InitTriggers(std::vector<TriggerNode*>& triggers) void PaladinBoostStrategy::InitTriggers(std::vector<TriggerNode*>& /*triggers*/)
{ {
// triggers.push_back(new TriggerNode("divine favor", { NextAction("divine favor", // triggers.push_back(new TriggerNode("divine favor", { NextAction("divine favor",

View File

@ -124,12 +124,12 @@ void AoEWarlockStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
); );
} }
void WarlockBoostStrategy::InitTriggers(std::vector<TriggerNode*>& triggers) void WarlockBoostStrategy::InitTriggers(std::vector<TriggerNode*>& /*triggers*/)
{ {
// Placeholder for future boost triggers // Placeholder for future boost triggers
} }
void WarlockPetStrategy::InitTriggers(std::vector<TriggerNode*>& triggers) void WarlockPetStrategy::InitTriggers(std::vector<TriggerNode*>& /*triggers*/)
{ {
// Placeholder for future pet triggers // Placeholder for future pet triggers
} }

View File

@ -41,6 +41,6 @@ std::vector<NextAction> TankWarlockStrategy::getDefaultActions()
}; };
} }
void TankWarlockStrategy::InitTriggers(std::vector<TriggerNode*>& triggers) void TankWarlockStrategy::InitTriggers(std::vector<TriggerNode*>& /*triggers*/)
{ {
} }

View File

@ -21,7 +21,7 @@ public:
} }
private: private:
static ActionNode* charge(PlayerbotAI* botAI) static ActionNode* charge(PlayerbotAI* /*botAI*/)
{ {
return new ActionNode( return new ActionNode(
"charge", "charge",
@ -31,7 +31,7 @@ private:
); );
} }
static ActionNode* death_wish(PlayerbotAI* botAI) static ActionNode* death_wish(PlayerbotAI* /*botAI*/)
{ {
return new ActionNode( return new ActionNode(
"death wish", "death wish",
@ -41,7 +41,7 @@ private:
); );
} }
static ActionNode* piercing_howl(PlayerbotAI* botAI) static ActionNode* piercing_howl(PlayerbotAI* /*botAI*/)
{ {
return new ActionNode( return new ActionNode(
"piercing howl", "piercing howl",
@ -51,7 +51,7 @@ private:
); );
} }
static ActionNode* mocking_blow(PlayerbotAI* botAI) static ActionNode* mocking_blow(PlayerbotAI* /*botAI*/)
{ {
return new ActionNode( return new ActionNode(
"mocking blow", "mocking blow",
@ -61,7 +61,7 @@ private:
); );
} }
static ActionNode* heroic_strike(PlayerbotAI* botAI) static ActionNode* heroic_strike(PlayerbotAI* /*botAI*/)
{ {
return new ActionNode( return new ActionNode(
"heroic strike", "heroic strike",
@ -71,7 +71,7 @@ private:
); );
} }
static ActionNode* enraged_regeneration(PlayerbotAI* botAI) static ActionNode* enraged_regeneration(PlayerbotAI* /*botAI*/)
{ {
return new ActionNode( return new ActionNode(
"enraged regeneration", "enraged regeneration",
@ -81,7 +81,7 @@ private:
); );
} }
static ActionNode* retaliation(PlayerbotAI* botAI) static ActionNode* retaliation(PlayerbotAI* /*botAI*/)
{ {
return new ActionNode( return new ActionNode(
"retaliation", "retaliation",
@ -91,7 +91,7 @@ private:
); );
} }
static ActionNode* shattering_throw(PlayerbotAI* botAI) static ActionNode* shattering_throw(PlayerbotAI* /*botAI*/)
{ {
return new ActionNode( return new ActionNode(
"shattering throw", "shattering throw",

View File

@ -18,7 +18,7 @@ public:
} }
private: private:
static ActionNode* charge(PlayerbotAI* botAI) static ActionNode* charge(PlayerbotAI* /*botAI*/)
{ {
return new ActionNode( return new ActionNode(
"charge", "charge",
@ -28,7 +28,7 @@ private:
); );
} }
static ActionNode* intercept(PlayerbotAI* botAI) static ActionNode* intercept(PlayerbotAI* /*botAI*/)
{ {
return new ActionNode( return new ActionNode(
"intercept", "intercept",
@ -38,7 +38,7 @@ private:
); );
} }
static ActionNode* piercing_howl(PlayerbotAI* botAI) static ActionNode* piercing_howl(PlayerbotAI* /*botAI*/)
{ {
return new ActionNode( return new ActionNode(
"piercing howl", "piercing howl",
@ -48,7 +48,7 @@ private:
); );
} }
static ActionNode* pummel(PlayerbotAI* botAI) static ActionNode* pummel(PlayerbotAI* /*botAI*/)
{ {
return new ActionNode( return new ActionNode(
"pummel", "pummel",
@ -58,7 +58,7 @@ private:
); );
} }
static ActionNode* enraged_regeneration(PlayerbotAI* botAI) static ActionNode* enraged_regeneration(PlayerbotAI* /*botAI*/)
{ {
return new ActionNode( return new ActionNode(
"enraged regeneration", "enraged regeneration",

View File

@ -24,7 +24,7 @@ public:
} }
private: private:
static ActionNode* heroic_throw_taunt(PlayerbotAI* botAI) static ActionNode* heroic_throw_taunt(PlayerbotAI* /*botAI*/)
{ {
return new ActionNode( return new ActionNode(
"heroic throw", "heroic throw",
@ -34,7 +34,7 @@ private:
); );
} }
static ActionNode* heroic_throw_on_snare_target(PlayerbotAI* botAI) static ActionNode* heroic_throw_on_snare_target(PlayerbotAI* /*botAI*/)
{ {
return new ActionNode( return new ActionNode(
"heroic throw on snare target", "heroic throw on snare target",
@ -44,7 +44,7 @@ private:
); );
} }
static ActionNode* last_stand(PlayerbotAI* botAI) static ActionNode* last_stand(PlayerbotAI* /*botAI*/)
{ {
return new ActionNode( return new ActionNode(
"last stand", "last stand",
@ -54,7 +54,7 @@ private:
); );
} }
static ActionNode* devastate(PlayerbotAI* botAI) static ActionNode* devastate(PlayerbotAI* /*botAI*/)
{ {
return new ActionNode( return new ActionNode(
"devastate", "devastate",
@ -64,7 +64,7 @@ private:
); );
} }
static ActionNode* commanding_shout(PlayerbotAI* botAI) static ActionNode* commanding_shout(PlayerbotAI* /*botAI*/)
{ {
return new ActionNode( return new ActionNode(
"commanding shout", "commanding shout",
@ -74,7 +74,7 @@ private:
); );
} }
static ActionNode* sunder_armor(PlayerbotAI* botAI) static ActionNode* sunder_armor(PlayerbotAI* /*botAI*/)
{ {
return new ActionNode( return new ActionNode(
"sunder armor", "sunder armor",
@ -84,7 +84,7 @@ private:
); );
} }
static ActionNode* charge(PlayerbotAI* botAI) static ActionNode* charge(PlayerbotAI* /*botAI*/)
{ {
return new ActionNode( return new ActionNode(
"charge", "charge",
@ -94,7 +94,7 @@ private:
); );
} }
static ActionNode* taunt(PlayerbotAI* botAI) static ActionNode* taunt(PlayerbotAI* /*botAI*/)
{ {
return new ActionNode( return new ActionNode(
"taunt", "taunt",
@ -104,7 +104,7 @@ private:
); );
} }
static ActionNode* vigilance(PlayerbotAI* botAI) static ActionNode* vigilance(PlayerbotAI* /*botAI*/)
{ {
return new ActionNode( return new ActionNode(
"vigilance", "vigilance",
@ -114,7 +114,7 @@ private:
); );
} }
static ActionNode* enraged_regeneration(PlayerbotAI* botAI) static ActionNode* enraged_regeneration(PlayerbotAI* /*botAI*/)
{ {
return new ActionNode( return new ActionNode(
"enraged regeneration", "enraged regeneration",

View File

@ -134,7 +134,7 @@ bool IckAndKrickAction::PoisonNova(bool poisonNova, Unit* boss)
return false; return false;
} }
bool IckAndKrickAction::ExplosiveBarrage(bool explosiveBarrage, Unit* boss) bool IckAndKrickAction::ExplosiveBarrage(bool /*explosiveBarrage*/, Unit* boss)
{ {
std::vector<Unit*> orbs; std::vector<Unit*> orbs;
Unit* closestOrb = nullptr; Unit* closestOrb = nullptr;

View File

@ -27,7 +27,7 @@ float IckAndKrickMultiplier::GetValue(Action* action)
return 1.0f; return 1.0f;
} }
float GarfrostMultiplier::GetValue(Action* action) float GarfrostMultiplier::GetValue(Action* /*action*/)
{ {
Unit* boss = AI_VALUE2(Unit*, "find target", "garfrost"); Unit* boss = AI_VALUE2(Unit*, "find target", "garfrost");
if (!boss) if (!boss)

View File

@ -15,6 +15,6 @@ void WotlkDungeonToCStrategy::InitTriggers(std::vector<TriggerNode*> &triggers)
} }
void WotlkDungeonToCStrategy::InitMultipliers(std::vector<Multiplier*> &multipliers) void WotlkDungeonToCStrategy::InitMultipliers(std::vector<Multiplier*> &/*multipliers*/)
{ {
} }

View File

@ -57,7 +57,7 @@ float HighKingMaulgarDisableArcaneShotOnKroshMultiplier::GetValue(Action* action
float HighKingMaulgarDisableMageTankAOEMultiplier::GetValue(Action* action) float HighKingMaulgarDisableMageTankAOEMultiplier::GetValue(Action* action)
{ {
if (IsKroshMageTank(botAI, bot) && if (IsKroshMageTank(bot) &&
(dynamic_cast<CastFrostNovaAction*>(action) || dynamic_cast<CastBlizzardAction*>(action) || (dynamic_cast<CastFrostNovaAction*>(action) || dynamic_cast<CastBlizzardAction*>(action) ||
dynamic_cast<CastConeOfColdAction*>(action) || dynamic_cast<CastFlamestrikeAction*>(action) || dynamic_cast<CastConeOfColdAction*>(action) || dynamic_cast<CastFlamestrikeAction*>(action) ||
dynamic_cast<CastDragonsBreathAction*>(action) || dynamic_cast<CastBlastWaveAction*>(action))) dynamic_cast<CastDragonsBreathAction*>(action) || dynamic_cast<CastBlastWaveAction*>(action)))

View File

@ -31,14 +31,14 @@ bool HighKingMaulgarIsMageTankTrigger::IsActive()
{ {
Unit* krosh = AI_VALUE2(Unit*, "find target", "krosh firehand"); Unit* krosh = AI_VALUE2(Unit*, "find target", "krosh firehand");
return IsKroshMageTank(botAI, bot) && krosh; return IsKroshMageTank(bot) && krosh;
} }
bool HighKingMaulgarIsMoonkinTankTrigger::IsActive() bool HighKingMaulgarIsMoonkinTankTrigger::IsActive()
{ {
Unit* kiggler = AI_VALUE2(Unit*, "find target", "kiggler the crazed"); Unit* kiggler = AI_VALUE2(Unit*, "find target", "kiggler the crazed");
return IsKigglerMoonkinTank(botAI, bot) && kiggler; return IsKigglerMoonkinTank(bot) && kiggler;
} }
bool HighKingMaulgarDeterminingKillOrderTrigger::IsActive() bool HighKingMaulgarDeterminingKillOrderTrigger::IsActive()
@ -53,8 +53,8 @@ bool HighKingMaulgarDeterminingKillOrderTrigger::IsActive()
!(botAI->IsMainTank(bot) && maulgar) && !(botAI->IsMainTank(bot) && maulgar) &&
!(botAI->IsAssistTankOfIndex(bot, 0, false) && olm) && !(botAI->IsAssistTankOfIndex(bot, 0, false) && olm) &&
!(botAI->IsAssistTankOfIndex(bot, 1, false) && blindeye) && !(botAI->IsAssistTankOfIndex(bot, 1, false) && blindeye) &&
!(IsKroshMageTank(botAI, bot) && krosh) && !(IsKroshMageTank(bot) && krosh) &&
!(IsKigglerMoonkinTank(botAI, bot) && kiggler); !(IsKigglerMoonkinTank(bot) && kiggler);
} }
bool HighKingMaulgarHealerInDangerTrigger::IsActive() bool HighKingMaulgarHealerInDangerTrigger::IsActive()

View File

@ -39,7 +39,7 @@ namespace GruulsLairHelpers
return false; return false;
} }
bool IsKroshMageTank(PlayerbotAI* botAI, Player* bot) bool IsKroshMageTank(Player* bot)
{ {
Group* group = bot->GetGroup(); Group* group = bot->GetGroup();
if (!group) if (!group)
@ -79,7 +79,7 @@ namespace GruulsLairHelpers
return highestHpMage == bot; return highestHpMage == bot;
} }
bool IsKigglerMoonkinTank(PlayerbotAI* botAI, Player* bot) bool IsKigglerMoonkinTank(Player* bot)
{ {
Group* group = bot->GetGroup(); Group* group = bot->GetGroup();
if (!group) if (!group)

View File

@ -29,8 +29,8 @@ namespace GruulsLairHelpers
constexpr uint32 GRUULS_LAIR_MAP_ID = 565; constexpr uint32 GRUULS_LAIR_MAP_ID = 565;
bool IsAnyOgreBossAlive(PlayerbotAI* botAI); bool IsAnyOgreBossAlive(PlayerbotAI* botAI);
bool IsKroshMageTank(PlayerbotAI* botAI, Player* bot); bool IsKroshMageTank(Player* bot);
bool IsKigglerMoonkinTank(PlayerbotAI* botAI, Player* bot); bool IsKigglerMoonkinTank(Player* bot);
bool IsPositionSafe(PlayerbotAI* botAI, Player* bot, Position pos); bool IsPositionSafe(PlayerbotAI* botAI, Player* bot, Position pos);
bool TryGetNewSafePosition(PlayerbotAI* botAI, Player* bot, Position& outPos); bool TryGetNewSafePosition(PlayerbotAI* botAI, Player* bot, Position& outPos);

View File

@ -1998,10 +1998,10 @@ bool IccRotfaceGroupPositionAction::PositionRangedAndHealers(Unit* boss,Unit *sm
if (!isHeroic) if (!isHeroic)
return false; return false;
return FindAndMoveFromClosestMember(boss, smallOoze); return FindAndMoveFromClosestMember(smallOoze);
} }
bool IccRotfaceGroupPositionAction::FindAndMoveFromClosestMember(Unit* boss, Unit* smallOoze) bool IccRotfaceGroupPositionAction::FindAndMoveFromClosestMember(Unit* smallOoze)
{ {
const GuidVector npcs = AI_VALUE(GuidVector, "nearest hostile npcs"); const GuidVector npcs = AI_VALUE(GuidVector, "nearest hostile npcs");
@ -6925,7 +6925,7 @@ bool IccLichKingWinterAction::Execute(Event /*event*/)
isVictim = true; isVictim = true;
// First priority: Get out of Defile if we're in one // First priority: Get out of Defile if we're in one
if (!IsPositionSafeFromDefile(bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(), 3.0f)) if (!IsPositionSafeFromDefile(bot->GetPositionX(), bot->GetPositionY(), 3.0f))
{ {
// Find nearest safe position (use tank position as fallback) // Find nearest safe position (use tank position as fallback)
const Position* safePos = botAI->IsTank(bot) ? GetMainTankPosition() : GetMainTankRangedPosition(); const Position* safePos = botAI->IsTank(bot) ? GetMainTankPosition() : GetMainTankRangedPosition();
@ -7124,7 +7124,7 @@ const Position* IccLichKingWinterAction::GetMainTankRangedPosition()
return &ICC_LK_FROSTR3_POSITION; return &ICC_LK_FROSTR3_POSITION;
} }
bool IccLichKingWinterAction::IsPositionSafeFromDefile(float x, float y, float z, float minSafeDistance) bool IccLichKingWinterAction::IsPositionSafeFromDefile(float x, float y, float minSafeDistance)
{ {
Unit* boss = AI_VALUE2(Unit*, "find target", "the lich king"); Unit* boss = AI_VALUE2(Unit*, "find target", "the lich king");
if (!boss) if (!boss)
@ -7190,7 +7190,7 @@ bool IccLichKingWinterAction::TryMoveToPosition(float targetX, float targetY, fl
dy /= distance; dy /= distance;
// First check if direct path is safe // First check if direct path is safe
if (bot->IsWithinLOS(targetX, targetY, targetZ) && IsPositionSafeFromDefile(targetX, targetY, targetZ, 3.0f)) if (bot->IsWithinLOS(targetX, targetY, targetZ) && IsPositionSafeFromDefile(targetX, targetY, 3.0f))
{ {
if (isForced) if (isForced)
botAI->Reset(); botAI->Reset();
@ -7221,7 +7221,7 @@ bool IccLichKingWinterAction::TryMoveToPosition(float targetX, float targetY, fl
float testY = currentY + dy * attemptDistance + offsetY * direction; float testY = currentY + dy * attemptDistance + offsetY * direction;
float testZ = targetZ; float testZ = targetZ;
if (bot->IsWithinLOS(testX, testY, testZ) && IsPositionSafeFromDefile(testX, testY, testZ, 3.0f)) if (bot->IsWithinLOS(testX, testY, testZ) && IsPositionSafeFromDefile(testX, testY, 3.0f))
{ {
if (isForced) if (isForced)
botAI->Reset(); botAI->Reset();
@ -7271,7 +7271,7 @@ void IccLichKingWinterAction::HandleTankPositioning()
const Position* targetPos = GetMainTankPosition(); const Position* targetPos = GetMainTankPosition();
// First check if current position is safe // First check if current position is safe
if (!IsPositionSafeFromDefile(bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(), 3.0f)) if (!IsPositionSafeFromDefile(bot->GetPositionX(), bot->GetPositionY(), 3.0f))
{ {
// If in defile, prioritize getting out // If in defile, prioritize getting out
TryMoveToPosition(targetPos->GetPositionX(), targetPos->GetPositionY(), 840.857f, true); TryMoveToPosition(targetPos->GetPositionX(), targetPos->GetPositionY(), 840.857f, true);
@ -7295,7 +7295,7 @@ void IccLichKingWinterAction::HandleTankPositioning()
} }
// Once in position, handle add management from tank position // Once in position, handle add management from tank position
HandleMainTankAddManagement(boss, targetPos); HandleMainTankAddManagement(targetPos);
} }
// ASSIST TANK: More flexible positioning based on add collection // ASSIST TANK: More flexible positioning based on add collection
else if (botAI->IsAssistTank(bot)) else if (botAI->IsAssistTank(bot))
@ -7312,7 +7312,7 @@ void IccLichKingWinterAction::HandleTankPositioning()
} }
// Handle assist tank add collection and positioning // Handle assist tank add collection and positioning
HandleAssistTankAddManagement(boss, targetPos); HandleAssistTankAddManagement(targetPos);
} }
} }
@ -7405,7 +7405,7 @@ void IccLichKingWinterAction::HandleRangedPositioning()
const Position* targetPos = GetMainTankRangedPosition(); const Position* targetPos = GetMainTankRangedPosition();
// First check if current position is safe // First check if current position is safe
if (!IsPositionSafeFromDefile(bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(), 3.0f)) if (!IsPositionSafeFromDefile(bot->GetPositionX(), bot->GetPositionY(), 3.0f))
{ {
// If in defile, prioritize getting out // If in defile, prioritize getting out
TryMoveToPosition(targetPos->GetPositionX(), targetPos->GetPositionY(), 840.857f, true); TryMoveToPosition(targetPos->GetPositionX(), targetPos->GetPositionY(), 840.857f, true);
@ -7484,7 +7484,7 @@ void IccLichKingWinterAction::HandleRangedPositioning()
} }
} }
void IccLichKingWinterAction::HandleMainTankAddManagement(Unit* boss, const Position* tankPos) void IccLichKingWinterAction::HandleMainTankAddManagement(const Position* tankPos)
{ {
if (!botAI->IsMainTank(bot)) if (!botAI->IsMainTank(bot))
return; return;
@ -7607,7 +7607,7 @@ void IccLichKingWinterAction::HandleMainTankAddManagement(Unit* boss, const Posi
} }
} }
void IccLichKingWinterAction::HandleAssistTankAddManagement(Unit* boss, const Position* tankPos) void IccLichKingWinterAction::HandleAssistTankAddManagement(const Position* tankPos)
{ {
if (!botAI->IsAssistTank(bot)) if (!botAI->IsAssistTank(bot))
return; return;
@ -7812,7 +7812,7 @@ bool IccLichKingAddsAction::Execute(Event /*event*/)
return true; return true;
// Handle shambling horror interactions // Handle shambling horror interactions
HandleShamblingHorrors(boss, hasPlague); HandleShamblingHorrors();
// Handle assist tank add management // Handle assist tank add management
if (HandleAssistTankAddManagement(boss, diff)) if (HandleAssistTankAddManagement(boss, diff))
@ -8251,7 +8251,7 @@ bool IccLichKingAddsAction::HandleQuakeMechanics(Unit* boss)
return false; return false;
} }
void IccLichKingAddsAction::HandleShamblingHorrors(Unit* boss, bool hasPlague) void IccLichKingAddsAction::HandleShamblingHorrors()
{ {
// Find closest shambling horror // Find closest shambling horror
GuidVector npcs2 = AI_VALUE(GuidVector, "nearest hostile npcs"); GuidVector npcs2 = AI_VALUE(GuidVector, "nearest hostile npcs");

View File

@ -286,7 +286,7 @@ public:
bool HandleOozeTargeting(); bool HandleOozeTargeting();
bool HandleOozeMemberPositioning(); bool HandleOozeMemberPositioning();
bool PositionRangedAndHealers(Unit* boss,Unit* smallOoze); bool PositionRangedAndHealers(Unit* boss,Unit* smallOoze);
bool FindAndMoveFromClosestMember(Unit* boss, Unit* smallOoze); bool FindAndMoveFromClosestMember(Unit* smallOoze);
}; };
class IccRotfaceMoveAwayFromExplosionAction : public MovementAction class IccRotfaceMoveAwayFromExplosionAction : public MovementAction
@ -623,12 +623,12 @@ class IccLichKingWinterAction : public AttackAction
void HandlePositionCorrection(); void HandlePositionCorrection();
bool IsValidCollectibleAdd(Unit* unit); bool IsValidCollectibleAdd(Unit* unit);
bool IsPositionSafeFromDefile(float x, float y, float z, float minSafeDistance); bool IsPositionSafeFromDefile(float x, float y, float minSafeDistance);
void HandleTankPositioning(); void HandleTankPositioning();
void HandleMeleePositioning(); void HandleMeleePositioning();
void HandleRangedPositioning(); void HandleRangedPositioning();
void HandleMainTankAddManagement(Unit* boss, const Position* tankPos); void HandleMainTankAddManagement(const Position* tankPos);
void HandleAssistTankAddManagement(Unit* boss, const Position* tankPos); void HandleAssistTankAddManagement(const Position* tankPos);
private: private:
const Position* GetMainTankPosition(); const Position* GetMainTankPosition();
@ -648,7 +648,7 @@ class IccLichKingAddsAction : public AttackAction
void HandleHeroicNonTankPositioning(Difficulty diff, Unit* terenasMenethilHC); void HandleHeroicNonTankPositioning(Difficulty diff, Unit* terenasMenethilHC);
void HandleSpiritMarkingAndTargeting(Difficulty diff, Unit* terenasMenethilHC); void HandleSpiritMarkingAndTargeting(Difficulty diff, Unit* terenasMenethilHC);
bool HandleQuakeMechanics(Unit* boss); bool HandleQuakeMechanics(Unit* boss);
void HandleShamblingHorrors(Unit* boss, bool hasPlague); void HandleShamblingHorrors();
bool HandleAssistTankAddManagement(Unit* boss, Difficulty diff); bool HandleAssistTankAddManagement(Unit* boss, Difficulty diff);
void HandleMeleePositioning(Unit* boss, bool hasPlague, Difficulty diff); void HandleMeleePositioning(Unit* boss, bool hasPlague, Difficulty diff);
void HandleMainTankTargeting(Unit* boss, Difficulty diff); void HandleMainTankTargeting(Unit* boss, Difficulty diff);

View File

@ -559,7 +559,7 @@ bool IccBqlVampiricBiteTrigger::IsActive()
bool IccValkyreSpearTrigger::IsActive() bool IccValkyreSpearTrigger::IsActive()
{ {
// Check if there's a spear nearby // Check if there's a spear nearby
if (Creature* spear = bot->FindNearestCreature(NPC_SPEAR, 100.0f)) if (bot->FindNearestCreature(NPC_SPEAR, 100.0f))
return true; return true;
return false; return false;

View File

@ -744,7 +744,7 @@ bool NetherspiteBlockBlueBeamAction::Execute(Event /*event*/)
float candidateX = bx + dx * dist; float candidateX = bx + dx * dist;
float candidateY = by + dy * dist; float candidateY = by + dy * dist;
float candidateZ = bz; float candidateZ = bz;
if (!IsSafePosition(candidateX, candidateY, candidateZ, voidZones, 4.0f)) if (!IsSafePosition(candidateX, candidateY, voidZones, 4.0f))
continue; continue;
float distToIdeal = fabs(dist - idealDistance); float distToIdeal = fabs(dist - idealDistance);
@ -836,7 +836,7 @@ bool NetherspiteBlockGreenBeamAction::Execute(Event /*event*/)
float candidateX = bx + dx * dist; float candidateX = bx + dx * dist;
float candidateY = by + dy * dist; float candidateY = by + dy * dist;
float candidateZ = bz; float candidateZ = bz;
if (!IsSafePosition(candidateX, candidateY, candidateZ, voidZones, 4.0f)) if (!IsSafePosition(candidateX, candidateY, voidZones, 4.0f))
continue; continue;
float distToIdeal = fabs(dist - 18.0f); float distToIdeal = fabs(dist - 18.0f);
@ -873,7 +873,7 @@ bool NetherspiteAvoidBeamAndVoidZoneAction::Execute(Event /*event*/)
std::vector<Unit*> voidZones = GetAllVoidZones(botAI, bot); std::vector<Unit*> voidZones = GetAllVoidZones(botAI, bot);
bool nearVoidZone = !IsSafePosition(bot->GetPositionX(), bot->GetPositionY(), bool nearVoidZone = !IsSafePosition(bot->GetPositionX(), bot->GetPositionY(),
bot->GetPositionZ(), voidZones, 4.0f); voidZones, 4.0f);
std::vector<BeamAvoid> beams; std::vector<BeamAvoid> beams;
Unit* redPortal = bot->FindNearestCreature(NPC_RED_PORTAL, 150.0f); Unit* redPortal = bot->FindNearestCreature(NPC_RED_PORTAL, 150.0f);
@ -922,7 +922,7 @@ bool NetherspiteAvoidBeamAndVoidZoneAction::Execute(Event /*event*/)
float cy = botY + std::sin(angle) * dist; float cy = botY + std::sin(angle) * dist;
float cz = netherspiteZ; float cz = netherspiteZ;
if (!IsSafePosition(cx, cy, cz, voidZones, 4.0f) || if (!IsSafePosition(cx, cy, voidZones, 4.0f) ||
!IsAwayFromBeams(cx, cy, beams, netherspite)) !IsAwayFromBeams(cx, cy, beams, netherspite))
continue; continue;

View File

@ -272,7 +272,7 @@ namespace KarazhanHelpers
return voidZones; return voidZones;
} }
bool IsSafePosition(float x, float y, float z, const std::vector<Unit*>& hazards, float hazardRadius) bool IsSafePosition(float x, float y, const std::vector<Unit*>& hazards, float hazardRadius)
{ {
for (Unit* hazard : hazards) for (Unit* hazard : hazards)
{ {
@ -351,7 +351,7 @@ namespace KarazhanHelpers
destX, destY, destZ, true)) destX, destY, destZ, true))
continue; continue;
if (!IsSafePosition(destX, destY, destZ, hazards, safeDistance)) if (!IsSafePosition(destX, destY, hazards, safeDistance))
continue; continue;
if (requireSafePath) if (requireSafePath)

View File

@ -116,7 +116,7 @@ namespace KarazhanHelpers
std::vector<Player*> GetGreenBlockers(PlayerbotAI* botAI, Player* bot); std::vector<Player*> GetGreenBlockers(PlayerbotAI* botAI, Player* bot);
std::tuple<Player*, Player*, Player*> GetCurrentBeamBlockers(PlayerbotAI* botAI, Player* bot); std::tuple<Player*, Player*, Player*> GetCurrentBeamBlockers(PlayerbotAI* botAI, Player* bot);
std::vector<Unit*> GetAllVoidZones(PlayerbotAI *botAI, Player* bot); std::vector<Unit*> GetAllVoidZones(PlayerbotAI *botAI, Player* bot);
bool IsSafePosition (float x, float y, float z, const std::vector<Unit*>& hazards, float hazardRadius); bool IsSafePosition (float x, float y, const std::vector<Unit*>& hazards, float hazardRadius);
std::vector<Unit*> GetSpawnedInfernals(PlayerbotAI* botAI); std::vector<Unit*> GetSpawnedInfernals(PlayerbotAI* botAI);
bool IsStraightPathSafe( bool IsStraightPathSafe(
const Position& start, const Position& target, const Position& start, const Position& target,

View File

@ -499,7 +499,7 @@ bool MagtheridonUseManticronCubeAction::Execute(Event /*event*/)
return false; return false;
// Release cubes after Blast Nova is interrupted // Release cubes after Blast Nova is interrupted
if (HandleCubeRelease(magtheridon, cube)) if (HandleCubeRelease(magtheridon))
return true; return true;
// Check if cube logic should be active (49+ second rule) // Check if cube logic should be active (49+ second rule)
@ -520,7 +520,7 @@ bool MagtheridonUseManticronCubeAction::Execute(Event /*event*/)
return false; return false;
} }
bool MagtheridonUseManticronCubeAction::HandleCubeRelease(Unit* magtheridon, GameObject* cube) bool MagtheridonUseManticronCubeAction::HandleCubeRelease(Unit* magtheridon)
{ {
if (bot->HasAura(SPELL_SHADOW_GRASP) && if (bot->HasAura(SPELL_SHADOW_GRASP) &&
!(magtheridon->HasUnitState(UNIT_STATE_CASTING) && !(magtheridon->HasUnitState(UNIT_STATE_CASTING) &&

View File

@ -81,7 +81,7 @@ public:
bool Execute(Event event) override; bool Execute(Event event) override;
private: private:
bool HandleCubeRelease(Unit* magtheridon, GameObject* cube); bool HandleCubeRelease(Unit* magtheridon);
bool ShouldActivateCubeLogic(Unit* magtheridon); bool ShouldActivateCubeLogic(Unit* magtheridon);
bool HandleWaitingPhase(const MagtheridonHelpers::CubeInfo& cubeInfo); bool HandleWaitingPhase(const MagtheridonHelpers::CubeInfo& cubeInfo);
bool HandleCubeInteraction(const MagtheridonHelpers::CubeInfo& cubeInfo, GameObject* cube); bool HandleCubeInteraction(const MagtheridonHelpers::CubeInfo& cubeInfo, GameObject* cube);

View File

@ -118,7 +118,7 @@ namespace MagtheridonHelpers
std::unordered_map<uint32, time_t> spreadWaitTimer; std::unordered_map<uint32, time_t> spreadWaitTimer;
std::unordered_map<uint32, time_t> dpsWaitTimer; std::unordered_map<uint32, time_t> dpsWaitTimer;
bool IsSafeFromMagtheridonHazards(PlayerbotAI* botAI, Player* bot, float x, float y, float z) bool IsSafeFromMagtheridonHazards(PlayerbotAI* botAI, Player* /*bot*/, float x, float y, float /*z*/)
{ {
// Debris // Debris
std::vector<Unit*> debrisHazards; std::vector<Unit*> debrisHazards;

View File

@ -24,7 +24,7 @@ void RaidOnyxiaStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
"ony whelps spawn", { NextAction("ony kill whelps", ACTION_RAID + 1) })); "ony whelps spawn", { NextAction("ony kill whelps", ACTION_RAID + 1) }));
} }
void RaidOnyxiaStrategy::InitMultipliers(std::vector<Multiplier*>& multipliers) void RaidOnyxiaStrategy::InitMultipliers(std::vector<Multiplier*>& /*multipliers*/)
{ {
// Empty for now // Empty for now
} }

View File

@ -1466,16 +1466,16 @@ bool MorogrimTidewalkerMoveBossToTankPositionAction::Execute(Event /*event*/)
if (tidewalker->GetVictim() == bot && bot->IsWithinMeleeRange(tidewalker)) if (tidewalker->GetVictim() == bot && bot->IsWithinMeleeRange(tidewalker))
{ {
if (tidewalker->GetHealthPct() > 26.0f) if (tidewalker->GetHealthPct() > 26.0f)
return MoveToPhase1TankPosition(tidewalker); return MoveToPhase1TankPosition();
else else
return MoveToPhase2TankPosition(tidewalker); return MoveToPhase2TankPosition();
} }
return false; return false;
} }
// Phase 1: tank position is up against the Northeast pillar // Phase 1: tank position is up against the Northeast pillar
bool MorogrimTidewalkerMoveBossToTankPositionAction::MoveToPhase1TankPosition(Unit* tidewalker) bool MorogrimTidewalkerMoveBossToTankPositionAction::MoveToPhase1TankPosition()
{ {
const Position& phase1 = TIDEWALKER_PHASE_1_TANK_POSITION; const Position& phase1 = TIDEWALKER_PHASE_1_TANK_POSITION;
float distToPhase1 = bot->GetExactDist2d(phase1.GetPositionX(), phase1.GetPositionY()); float distToPhase1 = bot->GetExactDist2d(phase1.GetPositionX(), phase1.GetPositionY());
@ -1495,7 +1495,7 @@ bool MorogrimTidewalkerMoveBossToTankPositionAction::MoveToPhase1TankPosition(Un
} }
// Phase 2: move in two steps to get around the pillar and back up into the Northeast corner // Phase 2: move in two steps to get around the pillar and back up into the Northeast corner
bool MorogrimTidewalkerMoveBossToTankPositionAction::MoveToPhase2TankPosition(Unit* tidewalker) bool MorogrimTidewalkerMoveBossToTankPositionAction::MoveToPhase2TankPosition()
{ {
const Position& phase2 = TIDEWALKER_PHASE_2_TANK_POSITION; const Position& phase2 = TIDEWALKER_PHASE_2_TANK_POSITION;
const Position& transition = TIDEWALKER_PHASE_TRANSITION_WAYPOINT; const Position& transition = TIDEWALKER_PHASE_TRANSITION_WAYPOINT;
@ -2151,7 +2151,7 @@ bool LadyVashjPassTheTaintedCoreAction::Execute(Event /*event*/)
{ {
// Passer order: HealAssistantOfIndex 0, 1, 2, then RangedDpsAssistantOfIndex 0 // Passer order: HealAssistantOfIndex 0, 1, 2, then RangedDpsAssistantOfIndex 0
if (bot == firstCorePasser && if (bot == firstCorePasser &&
LineUpFirstCorePasser(designatedLooter, closestTrigger)) LineUpFirstCorePasser(designatedLooter))
{ {
return true; return true;
} }
@ -2176,7 +2176,7 @@ bool LadyVashjPassTheTaintedCoreAction::Execute(Event /*event*/)
// Designated core looter logic // Designated core looter logic
// Applicable only if cheat mode is on and thus looter is a bot // Applicable only if cheat mode is on and thus looter is a bot
if (bot == designatedLooter && if (bot == designatedLooter &&
IsFirstCorePasserInPosition(designatedLooter, firstCorePasser, closestTrigger)) IsFirstCorePasserInPosition(firstCorePasser))
{ {
const time_t now = std::time(nullptr); const time_t now = std::time(nullptr);
auto it = lastImbueAttempt.find(instanceId); auto it = lastImbueAttempt.find(instanceId);
@ -2192,7 +2192,7 @@ bool LadyVashjPassTheTaintedCoreAction::Execute(Event /*event*/)
// First core passer: receive core from looter at the top of the stairs, // First core passer: receive core from looter at the top of the stairs,
// pass to second core passer // pass to second core passer
else if (bot == firstCorePasser && else if (bot == firstCorePasser &&
IsSecondCorePasserInPosition(firstCorePasser, secondCorePasser, closestTrigger)) IsSecondCorePasserInPosition(secondCorePasser))
{ {
const time_t now = std::time(nullptr); const time_t now = std::time(nullptr);
auto it = lastImbueAttempt.find(instanceId); auto it = lastImbueAttempt.find(instanceId);
@ -2209,7 +2209,7 @@ bool LadyVashjPassTheTaintedCoreAction::Execute(Event /*event*/)
// of the first passer, move to the generator; otherwise, move as close as // of the first passer, move to the generator; otherwise, move as close as
// possible to the generator while staying in passing range // possible to the generator while staying in passing range
else if (bot == secondCorePasser && !UseCoreOnNearestGenerator(instanceId) && else if (bot == secondCorePasser && !UseCoreOnNearestGenerator(instanceId) &&
IsThirdCorePasserInPosition(secondCorePasser, thirdCorePasser, closestTrigger)) IsThirdCorePasserInPosition(thirdCorePasser))
{ {
const time_t now = std::time(nullptr); const time_t now = std::time(nullptr);
auto it = lastImbueAttempt.find(instanceId); auto it = lastImbueAttempt.find(instanceId);
@ -2226,7 +2226,7 @@ bool LadyVashjPassTheTaintedCoreAction::Execute(Event /*event*/)
// of the second passer, move to the generator; otherwise, move as close as // of the second passer, move to the generator; otherwise, move as close as
// possible to the generator while staying in passing range // possible to the generator while staying in passing range
else if (bot == thirdCorePasser && !UseCoreOnNearestGenerator(instanceId) && else if (bot == thirdCorePasser && !UseCoreOnNearestGenerator(instanceId) &&
IsFourthCorePasserInPosition(thirdCorePasser, fourthCorePasser, closestTrigger)) IsFourthCorePasserInPosition(fourthCorePasser))
{ {
const time_t now = std::time(nullptr); const time_t now = std::time(nullptr);
auto it = lastImbueAttempt.find(instanceId); auto it = lastImbueAttempt.find(instanceId);
@ -2249,7 +2249,7 @@ bool LadyVashjPassTheTaintedCoreAction::Execute(Event /*event*/)
} }
bool LadyVashjPassTheTaintedCoreAction::LineUpFirstCorePasser( bool LadyVashjPassTheTaintedCoreAction::LineUpFirstCorePasser(
Player* designatedLooter, Unit* closestTrigger) Player* designatedLooter)
{ {
const float centerX = VASHJ_PLATFORM_CENTER_POSITION.GetPositionX(); const float centerX = VASHJ_PLATFORM_CENTER_POSITION.GetPositionX();
const float centerY = VASHJ_PLATFORM_CENTER_POSITION.GetPositionY(); const float centerY = VASHJ_PLATFORM_CENTER_POSITION.GetPositionY();
@ -2288,8 +2288,6 @@ bool LadyVashjPassTheTaintedCoreAction::LineUpSecondCorePasser(
if (itFirst == intendedLineup.end()) if (itFirst == intendedLineup.end())
return false; return false;
const Position& firstLineup = itFirst->second;
auto itSecond = intendedLineup.find(bot->GetGUID()); auto itSecond = intendedLineup.find(bot->GetGUID());
if (itSecond == intendedLineup.end()) if (itSecond == intendedLineup.end())
{ {
@ -2343,9 +2341,9 @@ bool LadyVashjPassTheTaintedCoreAction::LineUpThirdCorePasser(
Player* secondCorePasser, Unit* closestTrigger) Player* secondCorePasser, Unit* closestTrigger)
{ {
bool needThirdPasser = bool needThirdPasser =
(IsFirstCorePasserInPosition(designatedLooter, firstCorePasser, closestTrigger) && (IsFirstCorePasserInPosition(firstCorePasser) &&
firstCorePasser->GetExactDist2d(closestTrigger) > 42.0f) || firstCorePasser->GetExactDist2d(closestTrigger) > 42.0f) ||
(IsSecondCorePasserInPosition(firstCorePasser, secondCorePasser, closestTrigger) && (IsSecondCorePasserInPosition(secondCorePasser) &&
secondCorePasser->GetExactDist2d(closestTrigger) > 4.0f); secondCorePasser->GetExactDist2d(closestTrigger) > 4.0f);
if (!needThirdPasser) if (!needThirdPasser)
@ -2408,9 +2406,9 @@ bool LadyVashjPassTheTaintedCoreAction::LineUpFourthCorePasser(
Player* thirdCorePasser, Unit* closestTrigger) Player* thirdCorePasser, Unit* closestTrigger)
{ {
bool needFourthPasser = bool needFourthPasser =
(IsSecondCorePasserInPosition(firstCorePasser, secondCorePasser, closestTrigger) && (IsSecondCorePasserInPosition(secondCorePasser) &&
secondCorePasser->GetExactDist2d(closestTrigger) > 42.0f) || secondCorePasser->GetExactDist2d(closestTrigger) > 42.0f) ||
(IsThirdCorePasserInPosition(secondCorePasser, thirdCorePasser, closestTrigger) && (IsThirdCorePasserInPosition(thirdCorePasser) &&
thirdCorePasser->GetExactDist2d(closestTrigger) > 4.0f); thirdCorePasser->GetExactDist2d(closestTrigger) > 4.0f);
if (!needFourthPasser) if (!needFourthPasser)
@ -2460,8 +2458,7 @@ bool LadyVashjPassTheTaintedCoreAction::LineUpFourthCorePasser(
// The next four functions check if the respective passer is <= 2 yards of their intended // The next four functions check if the respective passer is <= 2 yards of their intended
// position and are used to determine when the prior bot in the chain can pass the core // position and are used to determine when the prior bot in the chain can pass the core
bool LadyVashjPassTheTaintedCoreAction::IsFirstCorePasserInPosition( bool LadyVashjPassTheTaintedCoreAction::IsFirstCorePasserInPosition(Player* firstCorePasser)
Player* designatedLooter, Player* firstCorePasser, Unit* closestTrigger)
{ {
auto itSnap = intendedLineup.find(firstCorePasser->GetGUID()); auto itSnap = intendedLineup.find(firstCorePasser->GetGUID());
if (itSnap != intendedLineup.end()) if (itSnap != intendedLineup.end())
@ -2474,8 +2471,7 @@ bool LadyVashjPassTheTaintedCoreAction::IsFirstCorePasserInPosition(
return false; return false;
} }
bool LadyVashjPassTheTaintedCoreAction::IsSecondCorePasserInPosition( bool LadyVashjPassTheTaintedCoreAction::IsSecondCorePasserInPosition(Player* secondCorePasser)
Player* firstCorePasser, Player* secondCorePasser, Unit* closestTrigger)
{ {
auto itSnap = intendedLineup.find(secondCorePasser->GetGUID()); auto itSnap = intendedLineup.find(secondCorePasser->GetGUID());
if (itSnap != intendedLineup.end()) if (itSnap != intendedLineup.end())
@ -2488,8 +2484,7 @@ bool LadyVashjPassTheTaintedCoreAction::IsSecondCorePasserInPosition(
return false; return false;
} }
bool LadyVashjPassTheTaintedCoreAction::IsThirdCorePasserInPosition( bool LadyVashjPassTheTaintedCoreAction::IsThirdCorePasserInPosition(Player* thirdCorePasser)
Player* secondCorePasser, Player* thirdCorePasser, Unit* closestTrigger)
{ {
auto itSnap = intendedLineup.find(thirdCorePasser->GetGUID()); auto itSnap = intendedLineup.find(thirdCorePasser->GetGUID());
if (itSnap != intendedLineup.end()) if (itSnap != intendedLineup.end())
@ -2502,8 +2497,7 @@ bool LadyVashjPassTheTaintedCoreAction::IsThirdCorePasserInPosition(
return false; return false;
} }
bool LadyVashjPassTheTaintedCoreAction::IsFourthCorePasserInPosition( bool LadyVashjPassTheTaintedCoreAction::IsFourthCorePasserInPosition(Player* fourthCorePasser)
Player* thirdCorePasser, Player* fourthCorePasser, Unit* closestTrigger)
{ {
auto itSnap = intendedLineup.find(fourthCorePasser->GetGUID()); auto itSnap = intendedLineup.find(fourthCorePasser->GetGUID());
if (itSnap != intendedLineup.end()) if (itSnap != intendedLineup.end())

View File

@ -312,8 +312,8 @@ public:
bool Execute(Event event) override; bool Execute(Event event) override;
private: private:
bool MoveToPhase1TankPosition(Unit* tidewalker); bool MoveToPhase1TankPosition();
bool MoveToPhase2TankPosition(Unit* tidewalker); bool MoveToPhase2TankPosition();
}; };
class MorogrimTidewalkerPhase2RepositionRangedAction : public MovementAction class MorogrimTidewalkerPhase2RepositionRangedAction : public MovementAction
@ -414,14 +414,14 @@ public:
bool Execute(Event event) override; bool Execute(Event event) override;
private: private:
bool LineUpFirstCorePasser(Player* designatedLooter, Unit* closestTrigger); bool LineUpFirstCorePasser(Player* designatedLooter);
bool LineUpSecondCorePasser(Player* firstCorePasser, Unit* closestTrigger); bool LineUpSecondCorePasser(Player* firstCorePasser, Unit* closestTrigger);
bool LineUpThirdCorePasser(Player* designatedLooter, Player* firstCorePasser, Player* secondCorePasser, Unit* closestTrigger); bool LineUpThirdCorePasser(Player* designatedLooter, Player* firstCorePasser, Player* secondCorePasser, Unit* closestTrigger);
bool LineUpFourthCorePasser(Player* firstCorePasser, Player* secondCorePasser, Player* thirdCorePasser, Unit* closestTrigger); bool LineUpFourthCorePasser(Player* firstCorePasser, Player* secondCorePasser, Player* thirdCorePasser, Unit* closestTrigger);
bool IsFirstCorePasserInPosition(Player* designatedLooter, Player* firstCorePasser, Unit* closestTrigger); bool IsFirstCorePasserInPosition(Player* firstCorePasser);
bool IsSecondCorePasserInPosition(Player* firstCorePasser, Player* secondCorePasser, Unit* closestTrigger); bool IsSecondCorePasserInPosition(Player* secondCorePasser);
bool IsThirdCorePasserInPosition(Player* secondCorePasser, Player* thirdCorePasser, Unit* closestTrigger); bool IsThirdCorePasserInPosition(Player* thirdCorePasser);
bool IsFourthCorePasserInPosition(Player* thirdCorePasser, Player* fourthCorePasser, Unit* closestTrigger); bool IsFourthCorePasserInPosition(Player* fourthCorePasser);
void ScheduleTransferCoreAfterImbue(PlayerbotAI* botAI, Player* giver, Player* receiver); void ScheduleTransferCoreAfterImbue(PlayerbotAI* botAI, Player* giver, Player* receiver);
bool UseCoreOnNearestGenerator(const uint32 instanceId); bool UseCoreOnNearestGenerator(const uint32 instanceId);
}; };

View File

@ -690,13 +690,11 @@ float LadyVashjCorePassersPrioritizePositioningMultiplier::GetValue(Action* acti
auto coreHandlers = GetCoreHandlers(botAI, bot); auto coreHandlers = GetCoreHandlers(botAI, bot);
bool isCoreHandler = false; bool isCoreHandler = false;
int myIndex = -1;
for (int i = 0; i < static_cast<int>(coreHandlers.size()); ++i) for (int i = 0; i < static_cast<int>(coreHandlers.size()); ++i)
{ {
if (coreHandlers[i] && coreHandlers[i] == bot) if (coreHandlers[i] && coreHandlers[i] == bot)
{ {
isCoreHandler = true; isCoreHandler = true;
myIndex = i;
} }
} }
if (!isCoreHandler) if (!isCoreHandler)

View File

@ -213,7 +213,7 @@ bool AlarAssistTanksPickUpEmbersAction::Execute(Event /*event*/)
if (!isAlarInPhase2[alar->GetMap()->GetInstanceId()]) if (!isAlarInPhase2[alar->GetMap()->GetInstanceId()])
return HandlePhase1Embers(alar); return HandlePhase1Embers(alar);
else else
return HandlePhase2Embers(alar); return HandlePhase2Embers();
} }
// Embers will be tanked by only the second assist tank in Phase 1 // Embers will be tanked by only the second assist tank in Phase 1
@ -275,7 +275,7 @@ bool AlarAssistTanksPickUpEmbersAction::HandlePhase1Embers(Unit* alar)
// One Ember will be tanked by the second assist tank in Phase 2, and the other by // One Ember will be tanked by the second assist tank in Phase 2, and the other by
// the main tank or first assist tank (whichever is not tanking Al'ar) // the main tank or first assist tank (whichever is not tanking Al'ar)
bool AlarAssistTanksPickUpEmbersAction::HandlePhase2Embers(Unit* alar) bool AlarAssistTanksPickUpEmbersAction::HandlePhase2Embers()
{ {
auto [firstEmber, secondEmber] = GetFirstTwoEmbersOfAlar(botAI); auto [firstEmber, secondEmber] = GetFirstTwoEmbersOfAlar(botAI);

View File

@ -66,7 +66,7 @@ public:
private: private:
bool HandlePhase1Embers(Unit* alar); bool HandlePhase1Embers(Unit* alar);
bool HandlePhase2Embers(Unit* alar); bool HandlePhase2Embers();
}; };
class AlarRangedDpsPrioritizeEmbersAction : public AttackAction class AlarRangedDpsPrioritizeEmbersAction : public AttackAction

View File

@ -2332,7 +2332,6 @@ bool MimironRocketStrikeAction::isUseful()
bool MimironRocketStrikeAction::Execute(Event /*event*/) bool MimironRocketStrikeAction::Execute(Event /*event*/)
{ {
Unit* leviathanMkII = nullptr;
Unit* vx001 = nullptr; Unit* vx001 = nullptr;
Unit* aerialCommandUnit = nullptr; Unit* aerialCommandUnit = nullptr;
@ -2344,9 +2343,7 @@ bool MimironRocketStrikeAction::Execute(Event /*event*/)
if (!target || !target->IsAlive()) if (!target || !target->IsAlive())
continue; continue;
if (target->GetEntry() == NPC_LEVIATHAN_MKII) if (target->GetEntry() == NPC_VX001)
leviathanMkII = target;
else if (target->GetEntry() == NPC_VX001)
vx001 = target; vx001 = target;
else if (target->GetEntry() == NPC_AERIAL_COMMAND_UNIT) else if (target->GetEntry() == NPC_AERIAL_COMMAND_UNIT)
aerialCommandUnit = target; aerialCommandUnit = target;

View File

@ -157,7 +157,7 @@ float JanalaiStayAwayFromFireBombsMultiplier::GetValue(Action* action)
if (!AI_VALUE2(Unit*, "find target", "jan'alai")) if (!AI_VALUE2(Unit*, "find target", "jan'alai"))
return 1.0f; return 1.0f;
if (!HasFireBombNearby(botAI, bot)) if (!HasFireBombNearby(bot))
return 1.0f; return 1.0f;
if (dynamic_cast<CastReachTargetSpellAction*>(action) || if (dynamic_cast<CastReachTargetSpellAction*>(action) ||

View File

@ -108,7 +108,7 @@ bool JanalaiBossEngagedByTanksTrigger::IsActive()
!AI_VALUE2(Unit*, "find target", "jan'alai")) !AI_VALUE2(Unit*, "find target", "jan'alai"))
return false; return false;
return !HasFireBombNearby(botAI, bot); return !HasFireBombNearby(bot);
} }
bool JanalaiBossCastsFlameBreathTrigger::IsActive() bool JanalaiBossCastsFlameBreathTrigger::IsActive()
@ -118,13 +118,13 @@ bool JanalaiBossCastsFlameBreathTrigger::IsActive()
AI_VALUE2(Unit*, "find target", "amani dragonhawk hatchling")) AI_VALUE2(Unit*, "find target", "amani dragonhawk hatchling"))
return false; return false;
return !HasFireBombNearby(botAI, bot); return !HasFireBombNearby(bot);
} }
bool JanalaiBossSummoningFireBombsTrigger::IsActive() bool JanalaiBossSummoningFireBombsTrigger::IsActive()
{ {
return AI_VALUE2(Unit*, "find target", "jan'alai") && return AI_VALUE2(Unit*, "find target", "jan'alai") &&
HasFireBombNearby(botAI, bot); HasFireBombNearby(bot);
} }
bool JanalaiAmanishiHatchersSpawnedTrigger::IsActive() bool JanalaiAmanishiHatchersSpawnedTrigger::IsActive()

View File

@ -143,7 +143,7 @@ namespace ZulAmanHelpers
// Jan'alai <Dragonhawk Avatar> // Jan'alai <Dragonhawk Avatar>
const Position JANALAI_TANK_POSITION = { -33.873f, 1149.571f, 19.146f }; const Position JANALAI_TANK_POSITION = { -33.873f, 1149.571f, 19.146f };
bool HasFireBombNearby(PlayerbotAI* botAI, Player* bot) bool HasFireBombNearby(Player* bot)
{ {
constexpr float searchRadius = 30.0f; constexpr float searchRadius = 30.0f;
std::list<Creature*> creatureList; std::list<Creature*> creatureList;

View File

@ -97,7 +97,7 @@ namespace ZulAmanHelpers
// Jan'alai <Dragonhawk Avatar> // Jan'alai <Dragonhawk Avatar>
extern const Position JANALAI_TANK_POSITION; extern const Position JANALAI_TANK_POSITION;
bool HasFireBombNearby(PlayerbotAI* botAI, Player* bot); bool HasFireBombNearby(Player* bot);
std::pair<Unit*, Unit*> GetAmanishiHatcherPair(PlayerbotAI* botAI); std::pair<Unit*, Unit*> GetAmanishiHatcherPair(PlayerbotAI* botAI);
// Halazzi <Lynx Avatar> // Halazzi <Lynx Avatar>

View File

@ -138,7 +138,7 @@ void Engine::Init()
} }
} }
bool Engine::DoNextAction(Unit* unit, uint32 depth, bool minimal) bool Engine::DoNextAction(Unit* /*unit*/, uint32 /*depth*/, bool minimal)
{ {
LogAction("--- AI Tick ---"); LogAction("--- AI Tick ---");

View File

@ -59,6 +59,7 @@ std::list<uint32> PlayerbotFactory::specialQuestIds;
std::vector<uint32> PlayerbotFactory::enchantSpellIdCache; std::vector<uint32> PlayerbotFactory::enchantSpellIdCache;
std::vector<uint32> PlayerbotFactory::enchantGemIdCache; std::vector<uint32> PlayerbotFactory::enchantGemIdCache;
std::unordered_map<uint32, std::vector<uint32>> PlayerbotFactory::trainerIdCache; std::unordered_map<uint32, std::vector<uint32>> PlayerbotFactory::trainerIdCache;
std::vector<uint32> PlayerbotFactory::ccBreakTrinketCache;
bool PlayerbotFactory::IsPrimaryTradeSkill(uint16 skillId) bool PlayerbotFactory::IsPrimaryTradeSkill(uint16 skillId)
{ {
@ -460,6 +461,69 @@ void PlayerbotFactory::Init()
enchantGemIdCache.push_back(gemId); enchantGemIdCache.push_back(gemId);
} }
LOG_INFO("playerbots", "Loading {} enchantment gems", enchantGemIdCache.size()); LOG_INFO("playerbots", "Loading {} enchantment gems", enchantGemIdCache.size());
BuildCcBreakTrinketCache();
}
void PlayerbotFactory::BuildCcBreakTrinketCache()
{
ccBreakTrinketCache.clear();
// Spell 42292: removes all movement-impairing and loss-of-control effects — the PvP trinket spell.
QueryResult result = WorldDatabase.Query(
"SELECT entry, ItemLevel FROM item_template "
"WHERE Quality >= 2 AND InventoryType = 12 "
"AND (FlagsExtra & 8192) = 0 "
"AND (spellid_1 = 42292 OR spellid_2 = 42292 OR spellid_3 = 42292 "
" OR spellid_4 = 42292 OR spellid_5 = 42292)");
if (!result)
{
LOG_INFO("playerbots", "CC-break trinket cache: no items found.");
return;
}
struct CcItem { uint32 itemId; uint16 itemLevel; };
std::vector<CcItem> tmp;
do
{
Field* f = result->Fetch();
tmp.push_back({f[0].Get<uint32>(), f[1].Get<uint16>()});
} while (result->NextRow());
std::sort(tmp.begin(), tmp.end(), [](const CcItem& a, const CcItem& b) {
return a.itemLevel > b.itemLevel;
});
for (auto& c : tmp)
ccBreakTrinketCache.push_back(c.itemId);
LOG_INFO("playerbots", "CC-break trinket cache: {} items.", ccBreakTrinketCache.size());
}
uint8 PlayerbotFactory::GetPreferredArmorType(uint8 cls)
{
switch (cls)
{
case CLASS_WARRIOR:
case CLASS_PALADIN:
case CLASS_DEATH_KNIGHT:
return ITEM_SUBCLASS_ARMOR_PLATE;
case CLASS_HUNTER:
case CLASS_SHAMAN:
return ITEM_SUBCLASS_ARMOR_MAIL;
case CLASS_ROGUE:
case CLASS_DRUID:
return ITEM_SUBCLASS_ARMOR_LEATHER;
case CLASS_PRIEST:
case CLASS_MAGE:
case CLASS_WARLOCK:
return ITEM_SUBCLASS_ARMOR_CLOTH;
default:
return 0;
}
} }
void PlayerbotFactory::Prepare() void PlayerbotFactory::Prepare()
@ -561,9 +625,9 @@ void PlayerbotFactory::Randomize(bool incremental)
if (!incremental || !sPlayerbotAIConfig.equipmentPersistence || if (!incremental || !sPlayerbotAIConfig.equipmentPersistence ||
bot->GetLevel() < sPlayerbotAIConfig.equipmentPersistenceLevel) bot->GetLevel() < sPlayerbotAIConfig.equipmentPersistenceLevel)
{ {
InitTalentsTree(); uint32 specIndex = InitTalentsTree();
sRandomPlayerbotMgr.SetValue(bot->GetGUID().GetCounter(), "specNo", specIndex + 1);
} }
sRandomPlayerbotMgr.SetValue(bot->GetGUID().GetCounter(), "specNo", 0);
if (botAI) if (botAI)
{ {
PlayerbotRepository::instance().Reset(botAI); PlayerbotRepository::instance().Reset(botAI);
@ -1359,7 +1423,7 @@ void PlayerbotFactory::ResetQuests()
} }
} }
void PlayerbotFactory::InitTalentsTree(bool increment /*false*/, bool use_template /*true*/, bool reset /*false*/) uint32 PlayerbotFactory::InitTalentsTree(bool increment /*false*/, bool use_template /*true*/, bool reset /*false*/)
{ {
uint32 specTab; uint32 specTab;
uint8 cls = bot->getClass(); uint8 cls = bot->getClass();
@ -1427,7 +1491,14 @@ void PlayerbotFactory::InitTalentsTree(bool increment /*false*/, bool use_templa
if (bot->GetFreeTalentPoints()) if (bot->GetFreeTalentPoints())
InitTalents((specTab + 2) % 3); InitTalents((specTab + 2) % 3);
if (bot->getClass() == CLASS_SHAMAN && bot->HasSpell(30798))
{
bot->SetSkill(SKILL_DUAL_WIELD, 0, 1, 1);
bot->SetCanDualWield(true);
}
bot->SendTalentsInfoData(false); bot->SendTalentsInfoData(false);
return sPlayerbotAIConfig.randomClassSpecIndex[cls][specTab];
} }
void PlayerbotFactory::InitTalentsBySpecNo(Player* bot, int specNo, bool reset) void PlayerbotFactory::InitTalentsBySpecNo(Player* bot, int specNo, bool reset)
@ -1505,7 +1576,15 @@ void PlayerbotFactory::InitTalentsBySpecNo(Player* bot, int specNo, bool reset)
break; break;
} }
} }
if (bot->getClass() == CLASS_SHAMAN && bot->HasSpell(30798))
{
bot->SetSkill(SKILL_DUAL_WIELD, 0, 1, 1);
bot->SetCanDualWield(true);
}
bot->SendTalentsInfoData(false); bot->SendTalentsInfoData(false);
sRandomPlayerbotMgr.SetValue(bot->GetGUID().GetCounter(), "specNo", (uint32)specNo + 1);
} }
void PlayerbotFactory::InitTalentsByParsedSpecLink(Player* bot, std::vector<std::vector<uint32>> parsedSpecLink, void PlayerbotFactory::InitTalentsByParsedSpecLink(Player* bot, std::vector<std::vector<uint32>> parsedSpecLink,
@ -2008,7 +2087,35 @@ void PlayerbotFactory::InitEquipment(bool incremental, bool second_chance)
uint32 blevel = bot->GetLevel(); uint32 blevel = bot->GetLevel();
int32 delta = std::min(blevel, 10u); int32 delta = std::min(blevel, 10u);
bool isPvp = sRandomPlayerbotMgr.IsSpecPvp(bot->GetGUID().GetCounter(), bot->getClass());
StatsWeightCalculator calculator(bot); StatsWeightCalculator calculator(bot);
if (isPvp)
calculator.SetPvpSpec(true);
// Pre-select CC-break trinket for PvP specs: best available by item level
// that the bot meets the level requirement for.
// Humans (Every Man for Himself) and Undead (Will of the Forsaken) have a
// racial that shares the PvP trinket cooldown, so they don't need one.
bool racialHasCcBreak = (bot->getRace() == RACE_HUMAN || bot->getRace() == RACE_UNDEAD_PLAYER);
uint32 pvpTrinket1 = 0;
if (isPvp && level >= 50 && !racialHasCcBreak)
{
for (uint32 itemId : ccBreakTrinketCache)
{
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemId);
if (!proto) continue;
// Respect gear quality limit: trinket must not exceed itemQuality setting
if (static_cast<int32>(proto->Quality) > itemQuality) continue;
if (proto->RequiredLevel > level) continue;
if (!CanEquipItem(proto)) continue;
uint16 dest;
if (!CanEquipUnseenItem(EQUIPMENT_SLOT_TRINKET1, dest, itemId)) continue;
pvpTrinket1 = itemId;
break;
}
}
for (int32 slot : initSlotsOrder) for (int32 slot : initSlotsOrder)
{ {
if (slot == EQUIPMENT_SLOT_TABARD || slot == EQUIPMENT_SLOT_BODY) if (slot == EQUIPMENT_SLOT_TABARD || slot == EQUIPMENT_SLOT_BODY)
@ -2028,6 +2135,10 @@ void PlayerbotFactory::InitEquipment(bool incremental, bool second_chance)
(slot != EQUIPMENT_SLOT_RANGED)) (slot != EQUIPMENT_SLOT_RANGED))
continue; continue;
// Exclude resilience weighting for trinkets
bool isTrinketSlot = (slot == EQUIPMENT_SLOT_TRINKET1 || slot == EQUIPMENT_SLOT_TRINKET2);
calculator.SetExcludeResilience(isTrinketSlot);
Item* oldItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, slot); Item* oldItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, slot);
if (second_chance && oldItem) if (second_chance && oldItem)
@ -2037,6 +2148,28 @@ void PlayerbotFactory::InitEquipment(bool incremental, bool second_chance)
oldItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, slot); oldItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, slot);
// PvP specs: force TRINKET1 to the best available CC-break trinket.
if (slot == EQUIPMENT_SLOT_TRINKET1 && pvpTrinket1 != 0)
{
if (oldItem)
{
uint8 bagIndex = oldItem->GetBagSlot();
uint8 oldSlot = oldItem->GetSlot();
uint8 dstBag = NULL_BAG;
WorldPacket packet(CMSG_AUTOSTORE_BAG_ITEM, 3);
packet << bagIndex << oldSlot << dstBag;
WorldPackets::Item::AutoStoreBagItem nicePacket(std::move(packet));
nicePacket.Read();
bot->GetSession()->HandleAutoStoreBagItemOpcode(nicePacket);
oldItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, slot);
if (oldItem) continue;
}
uint16 dest;
if (CanEquipUnseenItem(slot, dest, pvpTrinket1))
bot->EquipNewItem(dest, pvpTrinket1, true);
continue;
}
int32 desiredQuality = itemQuality; int32 desiredQuality = itemQuality;
if (urand(0, 100) < 100 * sPlayerbotAIConfig.randomGearLoweringChance && desiredQuality > ITEM_QUALITY_NORMAL) if (urand(0, 100) < 100 * sPlayerbotAIConfig.randomGearLoweringChance && desiredQuality > ITEM_QUALITY_NORMAL)
desiredQuality--; desiredQuality--;
@ -2054,6 +2187,7 @@ void PlayerbotFactory::InitEquipment(bool incremental, bool second_chance)
if (urand(1, 100) <= skipProb) if (urand(1, 100) <= skipProb)
continue; continue;
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemId);
// disable next expansion gear // disable next expansion gear
if (sPlayerbotAIConfig.limitGearExpansion && bot->GetLevel() <= 60 && itemId >= 23728) if (sPlayerbotAIConfig.limitGearExpansion && bot->GetLevel() <= 60 && itemId >= 23728)
continue; continue;
@ -2064,7 +2198,6 @@ void PlayerbotFactory::InitEquipment(bool incremental, bool second_chance)
// wearable TBC items above 35570 but nothing of significance // wearable TBC items above 35570 but nothing of significance
continue; continue;
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemId);
if (!proto) if (!proto)
continue; continue;
@ -2115,7 +2248,15 @@ void PlayerbotFactory::InitEquipment(bool incremental, bool second_chance)
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(newItemId); ItemTemplate const* proto = sObjectMgr->GetItemTemplate(newItemId);
float cur_score = calculator.CalculateItem(newItemId); float cur_score = calculator.CalculateItem(newItemId, 0, slot);
if (cur_score > 0.0f && proto && proto->Class == ITEM_CLASS_ARMOR && sPlayerbotAIConfig.preferClassArmorType)
{
uint8 preferredArmorType = GetPreferredArmorType(bot->getClass());
if (preferredArmorType != 0 && proto->SubClass == preferredArmorType)
cur_score *= 3.0f; // 3x multiplier for preferred armor type
}
if (cur_score > bestScoreForSlot) if (cur_score > bestScoreForSlot)
{ {
// delay heavy check to here // delay heavy check to here
@ -2141,7 +2282,7 @@ void PlayerbotFactory::InitEquipment(bool incremental, bool second_chance)
if (incremental && oldItem) if (incremental && oldItem)
{ {
float old_score = calculator.CalculateItem(oldItem->GetEntry(), oldItem->GetItemRandomPropertyId()); float old_score = calculator.CalculateItem(oldItem->GetEntry(), oldItem->GetItemRandomPropertyId(), slot);
if (bestScoreForSlot < 1.2f * old_score) if (bestScoreForSlot < 1.2f * old_score)
continue; continue;
} }
@ -2194,7 +2335,14 @@ void PlayerbotFactory::InitEquipment(bool incremental, bool second_chance)
(slot != EQUIPMENT_SLOT_RANGED)) (slot != EQUIPMENT_SLOT_RANGED))
continue; continue;
if (bot->GetItemByPos(INVENTORY_SLOT_BAG_0, slot) != nullptr) // CC-break trinket was force-equipped in the main pass; leave it alone.
if (slot == EQUIPMENT_SLOT_TRINKET1 && pvpTrinket1 != 0)
continue;
bool isTrinketSlot = (slot == EQUIPMENT_SLOT_TRINKET1 || slot == EQUIPMENT_SLOT_TRINKET2);
calculator.SetExcludeResilience(isTrinketSlot);
if (Item* oldItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
bot->DestroyItem(INVENTORY_SLOT_BAG_0, slot, true); bot->DestroyItem(INVENTORY_SLOT_BAG_0, slot, true);
std::vector<uint32>& ids = items[slot]; std::vector<uint32>& ids = items[slot];
@ -2209,7 +2357,15 @@ void PlayerbotFactory::InitEquipment(bool incremental, bool second_chance)
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(newItemId); ItemTemplate const* proto = sObjectMgr->GetItemTemplate(newItemId);
float cur_score = calculator.CalculateItem(newItemId); float cur_score = calculator.CalculateItem(newItemId, 0, slot);
if (cur_score > 0.0f && proto && proto->Class == ITEM_CLASS_ARMOR && sPlayerbotAIConfig.preferClassArmorType)
{
uint8 preferredArmorType = GetPreferredArmorType(bot->getClass());
if (preferredArmorType != 0 && proto->SubClass == preferredArmorType)
cur_score *= 3.0f; // 3x multiplier for preferred armor type
}
if (cur_score > bestScoreForSlot) if (cur_score > bestScoreForSlot)
{ {
// delay heavy check to here // delay heavy check to here
@ -2230,8 +2386,6 @@ void PlayerbotFactory::InitEquipment(bool incremental, bool second_chance)
if (!CanEquipUnseenItem(slot, dest, bestItemForSlot)) if (!CanEquipUnseenItem(slot, dest, bestItemForSlot))
continue; continue;
Item* newItem = bot->EquipNewItem(dest, bestItemForSlot, true);
bot->EquipNewItem(dest, bestItemForSlot, true); bot->EquipNewItem(dest, bestItemForSlot, true);
bot->AutoUnequipOffhandIfNeed(); bot->AutoUnequipOffhandIfNeed();
} }
@ -2393,7 +2547,7 @@ void PlayerbotFactory::InitBags(bool destroyOld)
if (old_bag) if (old_bag)
continue; continue;
Item* newItem = bot->EquipNewItem(dest, newItemId, true); bot->EquipNewItem(dest, newItemId, true);
// if (newItem) // if (newItem)
// { // {
// newItem->AddToWorld(); // newItem->AddToWorld();
@ -4729,7 +4883,7 @@ void PlayerbotFactory::ApplyEnchantTemplate(uint8 spec)
// const SpellItemEnchantmentEntry* a = sSpellItemEnchantmentStore.LookupEntry(1); // const SpellItemEnchantmentEntry* a = sSpellItemEnchantmentStore.LookupEntry(1);
} }
void PlayerbotFactory::ApplyEnchantAndGemsNew(bool destroyOld) void PlayerbotFactory::ApplyEnchantAndGemsNew(bool /*destroyOld*/)
{ {
//int32 bestGemEnchantId[4] = {-1, -1, -1, -1}; // 1, 2, 4, 8 color //not used, line marked for removal. //int32 bestGemEnchantId[4] = {-1, -1, -1, -1}; // 1, 2, 4, 8 color //not used, line marked for removal.
//float bestGemScore[4] = {0, 0, 0, 0}; //not used, line marked for removal. //float bestGemScore[4] = {0, 0, 0, 0}; //not used, line marked for removal.

View File

@ -63,7 +63,7 @@ public:
static uint32 tradeSkills[]; static uint32 tradeSkills[];
static float CalculateEnchantScore(uint32 enchant_id, Player* bot); static float CalculateEnchantScore(uint32 enchant_id, Player* bot);
void InitTalentsTree(bool incremental = false, bool use_template = true, bool reset = false); uint32 InitTalentsTree(bool incremental = false, bool use_template = true, bool reset = false);
static void InitTalentsBySpecNo(Player* bot, int specNo, bool reset); static void InitTalentsBySpecNo(Player* bot, int specNo, bool reset);
static void InitTalentsByParsedSpecLink(Player* bot, std::vector<std::vector<uint32>> parsedSpecLink, bool reset); static void InitTalentsByParsedSpecLink(Player* bot, std::vector<std::vector<uint32>> parsedSpecLink, bool reset);
void InitAvailableSpells(); void InitAvailableSpells();
@ -88,6 +88,7 @@ public:
void InitKeyring(); void InitKeyring();
void InitReputation(); void InitReputation();
void InitAttunementQuests(); void InitAttunementQuests();
void InitGuild();
private: private:
enum class ProfessionSpecializationSpell : uint32 enum class ProfessionSpecializationSpell : uint32
@ -189,6 +190,8 @@ private:
std::vector<uint32> GetCurrentGemsCount(); std::vector<uint32> GetCurrentGemsCount();
bool CanEquipArmor(ItemTemplate const* proto); bool CanEquipArmor(ItemTemplate const* proto);
bool CanEquipWeapon(ItemTemplate const* proto); bool CanEquipWeapon(ItemTemplate const* proto);
static void BuildCcBreakTrinketCache();
uint8 GetPreferredArmorType(uint8 cls);
void EnchantItem(Item* item); void EnchantItem(Item* item);
void AddItemStats(uint32 mod, uint8& sp, uint8& ap, uint8& tank); void AddItemStats(uint32 mod, uint8& sp, uint8& ap, uint8& tank);
bool CheckItemStats(uint8 sp, uint8 ap, uint8 tank); bool CheckItemStats(uint8 sp, uint8 ap, uint8 tank);
@ -199,7 +202,6 @@ private:
void InitInventoryEquip(); void InitInventoryEquip();
void InitInventorySkill(); void InitInventorySkill();
Item* StoreItem(uint32 itemId, uint32 count); Item* StoreItem(uint32 itemId, uint32 count);
void InitGuild();
void InitArenaTeam(); void InitArenaTeam();
void InitImmersive(); void InitImmersive();
static void AddPrevQuests(uint32 questId, std::list<uint32>& questIds); static void AddPrevQuests(uint32 questId, std::list<uint32>& questIds);
@ -220,6 +222,7 @@ private:
static std::unordered_map<uint32, std::vector<uint32>> trainerIdCache; static std::unordered_map<uint32, std::vector<uint32>> trainerIdCache;
static std::vector<uint32> enchantSpellIdCache; static std::vector<uint32> enchantSpellIdCache;
static std::vector<uint32> enchantGemIdCache; static std::vector<uint32> enchantGemIdCache;
static std::vector<uint32> ccBreakTrinketCache;
protected: protected:
EnchantContainer m_EnchantContainer; EnchantContainer m_EnchantContainer;

View File

@ -491,7 +491,7 @@ void PlayerbotAI::UpdateAIInternal([[maybe_unused]] uint32 elapsed, bool minimal
continue; continue;
} }
ChatReplyAction::ChatReplyDo(bot, it->m_type, it->m_guid1, it->m_guid2, it->m_msg, it->m_chanName, it->m_name); ChatReplyAction::ChatReplyDo(bot, it->m_type, it->m_guid1, it->m_msg, it->m_chanName, it->m_name);
it = chatReplies.erase(it); it = chatReplies.erase(it);
} }
@ -867,6 +867,7 @@ void PlayerbotAI::Reset(bool full)
aiObjectContext->GetValue<Unit*>("current target")->Set(nullptr); aiObjectContext->GetValue<Unit*>("current target")->Set(nullptr);
aiObjectContext->GetValue<GuidVector>("prioritized targets")->Reset(); aiObjectContext->GetValue<GuidVector>("prioritized targets")->Reset();
aiObjectContext->GetValue<ObjectGuid>("pull target")->Set(ObjectGuid::Empty); aiObjectContext->GetValue<ObjectGuid>("pull target")->Set(ObjectGuid::Empty);
aiObjectContext->GetValue<ObjectGuid>("pull strategy target")->Set(ObjectGuid::Empty);
aiObjectContext->GetValue<GuidPosition>("rpg target")->Set(GuidPosition()); aiObjectContext->GetValue<GuidPosition>("rpg target")->Set(GuidPosition());
aiObjectContext->GetValue<LootObject>("loot target")->Set(LootObject()); aiObjectContext->GetValue<LootObject>("loot target")->Set(LootObject());
aiObjectContext->GetValue<uint32>("lfg proposal")->Set(0); aiObjectContext->GetValue<uint32>("lfg proposal")->Set(0);
@ -1476,6 +1477,7 @@ void PlayerbotAI::DoNextAction(bool min)
aiObjectContext->GetValue<Unit*>("current target")->Set(nullptr); aiObjectContext->GetValue<Unit*>("current target")->Set(nullptr);
aiObjectContext->GetValue<Unit*>("enemy player target")->Set(nullptr); aiObjectContext->GetValue<Unit*>("enemy player target")->Set(nullptr);
aiObjectContext->GetValue<ObjectGuid>("pull target")->Set(ObjectGuid::Empty); aiObjectContext->GetValue<ObjectGuid>("pull target")->Set(ObjectGuid::Empty);
aiObjectContext->GetValue<ObjectGuid>("pull strategy target")->Set(ObjectGuid::Empty);
aiObjectContext->GetValue<LootObject>("loot target")->Set(LootObject()); aiObjectContext->GetValue<LootObject>("loot target")->Set(LootObject());
ChangeEngine(BOT_STATE_DEAD); ChangeEngine(BOT_STATE_DEAD);
@ -1811,7 +1813,7 @@ Strategy* PlayerbotAI::GetStrategy(std::string const name, BotState type)
return engines[type] ? engines[type]->GetStrategy(name) : nullptr; return engines[type] ? engines[type]->GetStrategy(name) : nullptr;
} }
void PlayerbotAI::ResetStrategies(bool load) void PlayerbotAI::ResetStrategies(bool /*load*/)
{ {
for (uint8 i = 0; i < BOT_STATE_MAX; i++) for (uint8 i = 0; i < BOT_STATE_MAX; i++)
engines[i]->removeAllStrategies(); engines[i]->removeAllStrategies();

View File

@ -1667,7 +1667,7 @@ void PlayerbotMgr::TellError(std::string const botName, std::string const text)
errors[text] = names; errors[text] = names;
} }
void PlayerbotMgr::CheckTellErrors(uint32 elapsed) void PlayerbotMgr::CheckTellErrors(uint32 /*elapsed*/)
{ {
time_t now = time(nullptr); time_t now = time(nullptr);
if ((now - lastErrorTell) < sPlayerbotAIConfig.errorDelay / 1000) if ((now - lastErrorTell) < sPlayerbotAIConfig.errorDelay / 1000)

View File

@ -278,7 +278,7 @@ void RandomPlayerbotMgr::LogPlayerLocation()
} }
} }
void RandomPlayerbotMgr::UpdateAIInternal(uint32 elapsed, bool /*minimal*/) void RandomPlayerbotMgr::UpdateAIInternal(uint32 /*elapsed*/, bool /*minimal*/)
{ {
if (totalPmo) if (totalPmo)
totalPmo->finish(); totalPmo->finish();
@ -2266,6 +2266,16 @@ CachedEvent* RandomPlayerbotMgr::FindEvent(uint32 bot, std::string const& event)
return &e; return &e;
} }
bool RandomPlayerbotMgr::IsSpecPvp(uint32 bot, uint8 cls)
{
uint32 stored = GetValue(bot, "specNo");
if (!stored)
return false;
uint32 specIndex = stored - 1;
std::string const& name = sPlayerbotAIConfig.premadeSpecName[cls][specIndex];
return !name.empty() && name.find("pvp") != std::string::npos;
}
uint32 RandomPlayerbotMgr::GetEventValue(uint32 bot, std::string const& event) uint32 RandomPlayerbotMgr::GetEventValue(uint32 bot, std::string const& event)
{ {
if (CachedEvent* e = FindEvent(bot, event)) if (CachedEvent* e = FindEvent(bot, event))
@ -2532,6 +2542,13 @@ void RandomPlayerbotMgr::OnBotLoginInternal(Player* const bot)
} }
} }
// Run guild recovery/assignment at login to handle empty guild tables after restart.
if (sPlayerbotAIConfig.randomBotGuildCount > 0)
{
PlayerbotFactory factory(bot, bot->GetLevel());
factory.InitGuild();
}
if (sPlayerbotAIConfig.randomBotFixedLevel) if (sPlayerbotAIConfig.randomBotFixedLevel)
{ {
bot->SetPlayerFlag(PLAYER_FLAGS_NO_XP_GAIN); bot->SetPlayerFlag(PLAYER_FLAGS_NO_XP_GAIN);

View File

@ -140,6 +140,7 @@ public:
std::string GetData(uint32 bot, std::string const& type); std::string GetData(uint32 bot, std::string const& type);
void SetValue(uint32 bot, std::string const& type, uint32 value, std::string const& data = ""); void SetValue(uint32 bot, std::string const& type, uint32 value, std::string const& data = "");
void SetValue(Player* bot, std::string const& type, uint32 value, std::string const& data = ""); void SetValue(Player* bot, std::string const& type, uint32 value, std::string const& data = "");
bool IsSpecPvp(uint32 bot, uint8 cls);
void Remove(Player* bot); void Remove(Player* bot);
ObjectGuid GetBattleMasterGUID(Player* bot, BattlegroundTypeId bgTypeId); ObjectGuid GetBattleMasterGUID(Player* bot, BattlegroundTypeId bgTypeId);
CreatureData const* GetCreatureDataByEntry(uint32 entry); CreatureData const* GetCreatureDataByEntry(uint32 entry);

View File

@ -65,7 +65,7 @@ void PlayerbotRepository::Save(PlayerbotAI* botAI)
SaveValue(guid, "dead", FormatStrategies("dead", botAI->GetStrategies(BOT_STATE_DEAD))); SaveValue(guid, "dead", FormatStrategies("dead", botAI->GetStrategies(BOT_STATE_DEAD)));
} }
std::string const PlayerbotRepository::FormatStrategies(std::string const type, std::vector<std::string> strategies) std::string const PlayerbotRepository::FormatStrategies(std::string const /*type*/, std::vector<std::string> strategies)
{ {
std::ostringstream out; std::ostringstream out;
for (std::vector<std::string>::iterator i = strategies.begin(); i != strategies.end(); ++i) for (std::vector<std::string>::iterator i = strategies.begin(); i != strategies.end(); ++i)

View File

@ -150,13 +150,10 @@ void PlayerbotGuildMgr::OnGuildUpdate(Guild* guild)
void PlayerbotGuildMgr::ResetGuildCache() void PlayerbotGuildMgr::ResetGuildCache()
{ {
for (auto it = _guildCache.begin(); it != _guildCache.end();) _guildCache.clear();
{
GuildCache& cached = it->second; for (auto& nameEntry : _guildNames)
cached.memberCount = 0; nameEntry.second = true;
cached.faction = 2;
cached.status = 0;
}
} }
void PlayerbotGuildMgr::LoadGuildNames() void PlayerbotGuildMgr::LoadGuildNames()

View File

@ -325,9 +325,6 @@ public:
FindMountVisitor(Player* bot) : FindUsableItemVisitor(bot) {} FindMountVisitor(Player* bot) : FindUsableItemVisitor(bot) {}
bool Accept(ItemTemplate const* proto) override; bool Accept(ItemTemplate const* proto) override;
private:
uint32 effectId;
}; };
class FindPetVisitor : public FindUsableItemVisitor class FindPetVisitor : public FindUsableItemVisitor

View File

@ -176,7 +176,7 @@ RandomItemMgr::~RandomItemMgr()
predicates.clear(); predicates.clear();
} }
bool RandomItemMgr::HandleConsoleCommand(ChatHandler* handler, char const* args) bool RandomItemMgr::HandleConsoleCommand(ChatHandler* /*handler*/, char const* args)
{ {
if (!args || !*args) if (!args || !*args)
{ {
@ -1823,7 +1823,7 @@ uint32 RandomItemMgr::GetUpgrade(Player* player, std::string spec, uint8 slot, u
} }
std::vector<uint32> RandomItemMgr::GetUpgradeList(Player* player, std::string spec, uint8 slot, uint32 quality, std::vector<uint32> RandomItemMgr::GetUpgradeList(Player* player, std::string spec, uint8 slot, uint32 quality,
uint32 itemId, uint32 amount) uint32 itemId, uint32 /*amount*/)
{ {
std::vector<uint32> listItems; std::vector<uint32> listItems;
if (!player) if (!player)

View File

@ -25,6 +25,10 @@ namespace
constexpr uint32 SPELL_MOLTEN_ARMOR_RANK_1 = 30482; constexpr uint32 SPELL_MOLTEN_ARMOR_RANK_1 = 30482;
constexpr uint32 SPELL_MOLTEN_ARMOR_RANK_2 = 43045; constexpr uint32 SPELL_MOLTEN_ARMOR_RANK_2 = 43045;
constexpr uint32 SPELL_MOLTEN_ARMOR_RANK_3 = 43046; constexpr uint32 SPELL_MOLTEN_ARMOR_RANK_3 = 43046;
constexpr uint32 SPELL_FEL_ARMOR_RANK_1 = 28176;
constexpr uint32 SPELL_FEL_ARMOR_RANK_2 = 28189;
constexpr uint32 SPELL_FEL_ARMOR_RANK_3 = 47892;
constexpr uint32 SPELL_FEL_ARMOR_RANK_4 = 47893;
} }
StatsWeightCalculator::StatsWeightCalculator(Player* player) : player_(player) StatsWeightCalculator::StatsWeightCalculator(Player* player) : player_(player)
@ -68,7 +72,7 @@ void StatsWeightCalculator::Reset()
} }
} }
float StatsWeightCalculator::CalculateItem(uint32 itemId, int32 randomPropertyIds) float StatsWeightCalculator::CalculateItem(uint32 itemId, int32 randomPropertyIds, int32 slot)
{ {
ItemTemplate const* proto = &sObjectMgr->GetItemTemplateStore()->at(itemId); ItemTemplate const* proto = &sObjectMgr->GetItemTemplateStore()->at(itemId);
@ -107,10 +111,12 @@ float StatsWeightCalculator::CalculateItem(uint32 itemId, int32 randomPropertyId
weight_ *= PlayerbotFactory::CalcMixedGearScore(lvl, ITEM_QUALITY_EPIC); weight_ *= PlayerbotFactory::CalcMixedGearScore(lvl, ITEM_QUALITY_EPIC);
else else
weight_ *= PlayerbotFactory::CalcMixedGearScore(proto->ItemLevel, proto->Quality); weight_ *= PlayerbotFactory::CalcMixedGearScore(proto->ItemLevel, proto->Quality);
return weight_;
} }
// If quality/level blending is disabled, also return the calculated weight.
// Apply weapon speed governance if slot is provided and this is a weapon
if (sPlayerbotAIConfig.preferredSpecWeapons && slot >= 0 && proto->Class == ITEM_CLASS_WEAPON)
weight_ *= ApplyPreferredSpecWeapons(proto, slot);
return weight_; return weight_;
} }
@ -208,6 +214,7 @@ void StatsWeightCalculator::GenerateBasicWeights(Player* player)
stats_weights_[STATS_TYPE_HIT] += 1.7f; stats_weights_[STATS_TYPE_HIT] += 1.7f;
stats_weights_[STATS_TYPE_CRIT] += 1.4f; stats_weights_[STATS_TYPE_CRIT] += 1.4f;
stats_weights_[STATS_TYPE_HASTE] += 1.6f; stats_weights_[STATS_TYPE_HASTE] += 1.6f;
stats_weights_[STATS_TYPE_SPELL_POWER] -= 1.0f;
stats_weights_[STATS_TYPE_RANGED_DPS] += 7.5f; stats_weights_[STATS_TYPE_RANGED_DPS] += 7.5f;
} }
else if (cls == CLASS_HUNTER && tab == HUNTER_TAB_MARKSMANSHIP) else if (cls == CLASS_HUNTER && tab == HUNTER_TAB_MARKSMANSHIP)
@ -218,6 +225,7 @@ void StatsWeightCalculator::GenerateBasicWeights(Player* player)
stats_weights_[STATS_TYPE_HIT] += 2.1f; stats_weights_[STATS_TYPE_HIT] += 2.1f;
stats_weights_[STATS_TYPE_CRIT] += 2.0f; stats_weights_[STATS_TYPE_CRIT] += 2.0f;
stats_weights_[STATS_TYPE_HASTE] += 1.8f; stats_weights_[STATS_TYPE_HASTE] += 1.8f;
stats_weights_[STATS_TYPE_SPELL_POWER] -= 1.0f;
stats_weights_[STATS_TYPE_RANGED_DPS] += 10.0f; stats_weights_[STATS_TYPE_RANGED_DPS] += 10.0f;
} }
else if (cls == CLASS_ROGUE && tab == ROGUE_TAB_COMBAT) else if (cls == CLASS_ROGUE && tab == ROGUE_TAB_COMBAT)
@ -229,6 +237,7 @@ void StatsWeightCalculator::GenerateBasicWeights(Player* player)
stats_weights_[STATS_TYPE_HIT] += 2.1f; stats_weights_[STATS_TYPE_HIT] += 2.1f;
stats_weights_[STATS_TYPE_CRIT] += 1.4f; stats_weights_[STATS_TYPE_CRIT] += 1.4f;
stats_weights_[STATS_TYPE_HASTE] += 1.7f; stats_weights_[STATS_TYPE_HASTE] += 1.7f;
stats_weights_[STATS_TYPE_SPELL_POWER] -= 1.0f;
stats_weights_[STATS_TYPE_EXPERTISE] += 2.0f; stats_weights_[STATS_TYPE_EXPERTISE] += 2.0f;
stats_weights_[STATS_TYPE_MELEE_DPS] += 7.0f; stats_weights_[STATS_TYPE_MELEE_DPS] += 7.0f;
} }
@ -253,64 +262,69 @@ void StatsWeightCalculator::GenerateBasicWeights(Player* player)
stats_weights_[STATS_TYPE_HIT] += 2.1f; stats_weights_[STATS_TYPE_HIT] += 2.1f;
stats_weights_[STATS_TYPE_CRIT] += 1.1f; stats_weights_[STATS_TYPE_CRIT] += 1.1f;
stats_weights_[STATS_TYPE_HASTE] += 1.8f; stats_weights_[STATS_TYPE_HASTE] += 1.8f;
stats_weights_[STATS_TYPE_SPELL_POWER] -= 1.0f;
stats_weights_[STATS_TYPE_EXPERTISE] += 2.1f; stats_weights_[STATS_TYPE_EXPERTISE] += 2.1f;
stats_weights_[STATS_TYPE_MELEE_DPS] += 5.0f; stats_weights_[STATS_TYPE_MELEE_DPS] += 5.0f;
} }
else if (cls == CLASS_WARRIOR && tab == WARRIOR_TAB_FURY) else if (cls == CLASS_WARRIOR && tab == WARRIOR_TAB_FURY)
{ {
stats_weights_[STATS_TYPE_AGILITY] += 1.8f; stats_weights_[STATS_TYPE_AGILITY] += 0.8f;
stats_weights_[STATS_TYPE_STRENGTH] += 2.6f; stats_weights_[STATS_TYPE_STRENGTH] += 2.5f;
stats_weights_[STATS_TYPE_ATTACK_POWER] += 1.0f; stats_weights_[STATS_TYPE_ATTACK_POWER] += 0.8f;
stats_weights_[STATS_TYPE_ARMOR_PENETRATION] += 2.1f; stats_weights_[STATS_TYPE_ARMOR_PENETRATION] += 2.1f;
stats_weights_[STATS_TYPE_HIT] += 2.3f; stats_weights_[STATS_TYPE_HIT] += 2.3f;
stats_weights_[STATS_TYPE_CRIT] += 2.2f; stats_weights_[STATS_TYPE_CRIT] += 2.2f;
stats_weights_[STATS_TYPE_HASTE] += 1.8f; stats_weights_[STATS_TYPE_HASTE] += 0.8f;
stats_weights_[STATS_TYPE_SPELL_POWER] -= 2.0f;
stats_weights_[STATS_TYPE_DEFENSE] -= 1.0f;
stats_weights_[STATS_TYPE_EXPERTISE] += 2.5f; stats_weights_[STATS_TYPE_EXPERTISE] += 2.5f;
stats_weights_[STATS_TYPE_MELEE_DPS] += 7.0f; stats_weights_[STATS_TYPE_MELEE_DPS] += 7.0f;
} }
else if (cls == CLASS_WARRIOR && tab == WARRIOR_TAB_ARMS) else if (cls == CLASS_WARRIOR && tab == WARRIOR_TAB_ARMS)
{ {
stats_weights_[STATS_TYPE_AGILITY] += 1.6f; stats_weights_[STATS_TYPE_AGILITY] += 0.8f;
stats_weights_[STATS_TYPE_STRENGTH] += 2.3f; stats_weights_[STATS_TYPE_STRENGTH] += 2.5f;
stats_weights_[STATS_TYPE_ATTACK_POWER] += 1.0f; stats_weights_[STATS_TYPE_ATTACK_POWER] += 0.8f;
stats_weights_[STATS_TYPE_ARMOR_PENETRATION] += 1.7f; stats_weights_[STATS_TYPE_ARMOR_PENETRATION] += 1.7f;
stats_weights_[STATS_TYPE_HIT] += 2.0f; stats_weights_[STATS_TYPE_HIT] += 2.0f;
stats_weights_[STATS_TYPE_CRIT] += 1.9f; stats_weights_[STATS_TYPE_CRIT] += 1.9f;
stats_weights_[STATS_TYPE_HASTE] += 0.8f; stats_weights_[STATS_TYPE_HASTE] += 0.8f;
stats_weights_[STATS_TYPE_SPELL_POWER] -= 2.0f;
stats_weights_[STATS_TYPE_DEFENSE] -= 1.0f;
stats_weights_[STATS_TYPE_EXPERTISE] += 1.4f; stats_weights_[STATS_TYPE_EXPERTISE] += 1.4f;
stats_weights_[STATS_TYPE_MELEE_DPS] += 7.0f; stats_weights_[STATS_TYPE_MELEE_DPS] += 7.0f;
} }
else if (cls == CLASS_DEATH_KNIGHT && tab == DEATH_KNIGHT_TAB_FROST) else if (cls == CLASS_DEATH_KNIGHT && tab == DEATH_KNIGHT_TAB_FROST)
{ {
stats_weights_[STATS_TYPE_AGILITY] += 1.7f; stats_weights_[STATS_TYPE_AGILITY] += 0.5f;
stats_weights_[STATS_TYPE_STRENGTH] += 2.8f; stats_weights_[STATS_TYPE_STRENGTH] += 2.5f;
stats_weights_[STATS_TYPE_ATTACK_POWER] += 1.0f; stats_weights_[STATS_TYPE_ATTACK_POWER] += 0.5f;
stats_weights_[STATS_TYPE_ARMOR_PENETRATION] += 2.7f; stats_weights_[STATS_TYPE_ARMOR_PENETRATION] += 2.7f;
stats_weights_[STATS_TYPE_HIT] += 2.3f; stats_weights_[STATS_TYPE_HIT] += 2.3f;
stats_weights_[STATS_TYPE_CRIT] += 2.2f; stats_weights_[STATS_TYPE_CRIT] += 2.2f;
stats_weights_[STATS_TYPE_HASTE] += 2.1f; stats_weights_[STATS_TYPE_HASTE] += 2.1f;
stats_weights_[STATS_TYPE_SPELL_POWER] -= 1.0f;
stats_weights_[STATS_TYPE_EXPERTISE] += 2.5f; stats_weights_[STATS_TYPE_EXPERTISE] += 2.5f;
stats_weights_[STATS_TYPE_MELEE_DPS] += 7.0f; stats_weights_[STATS_TYPE_MELEE_DPS] += 7.0f;
} }
else if (cls == CLASS_DEATH_KNIGHT && tab == DEATH_KNIGHT_TAB_UNHOLY) else if (cls == CLASS_DEATH_KNIGHT && tab == DEATH_KNIGHT_TAB_UNHOLY)
{ {
stats_weights_[STATS_TYPE_AGILITY] += 0.9f; stats_weights_[STATS_TYPE_AGILITY] += 0.5f;
stats_weights_[STATS_TYPE_STRENGTH] += 2.5f; stats_weights_[STATS_TYPE_STRENGTH] += 2.5f;
stats_weights_[STATS_TYPE_ATTACK_POWER] += 1.0f; stats_weights_[STATS_TYPE_ATTACK_POWER] += 0.5f;
stats_weights_[STATS_TYPE_ARMOR_PENETRATION] += 1.3f; stats_weights_[STATS_TYPE_ARMOR_PENETRATION] += 1.3f;
stats_weights_[STATS_TYPE_HIT] += 2.2f; stats_weights_[STATS_TYPE_HIT] += 2.2f;
stats_weights_[STATS_TYPE_CRIT] += 1.7f; stats_weights_[STATS_TYPE_CRIT] += 1.7f;
stats_weights_[STATS_TYPE_HASTE] += 1.8f; stats_weights_[STATS_TYPE_HASTE] += 1.8f;
stats_weights_[STATS_TYPE_SPELL_POWER] -= 1.0f;
stats_weights_[STATS_TYPE_EXPERTISE] += 1.5f; stats_weights_[STATS_TYPE_EXPERTISE] += 1.5f;
stats_weights_[STATS_TYPE_MELEE_DPS] += 5.0f; stats_weights_[STATS_TYPE_MELEE_DPS] += 5.0f;
} }
else if (cls == CLASS_PALADIN && tab == PALADIN_TAB_RETRIBUTION) else if (cls == CLASS_PALADIN && tab == PALADIN_TAB_RETRIBUTION)
{ {
stats_weights_[STATS_TYPE_AGILITY] += 1.6f; stats_weights_[STATS_TYPE_AGILITY] += 0.5f;
stats_weights_[STATS_TYPE_STRENGTH] += 2.5f; stats_weights_[STATS_TYPE_STRENGTH] += 2.5f;
stats_weights_[STATS_TYPE_INTELLECT] += 0.1f; stats_weights_[STATS_TYPE_ATTACK_POWER] += 0.5f;
stats_weights_[STATS_TYPE_ATTACK_POWER] += 1.0f;
stats_weights_[STATS_TYPE_SPELL_POWER] += 0.3f;
stats_weights_[STATS_TYPE_ARMOR_PENETRATION] += 1.5f; stats_weights_[STATS_TYPE_ARMOR_PENETRATION] += 1.5f;
stats_weights_[STATS_TYPE_HIT] += 1.9f; stats_weights_[STATS_TYPE_HIT] += 1.9f;
stats_weights_[STATS_TYPE_CRIT] += 1.7f; stats_weights_[STATS_TYPE_CRIT] += 1.7f;
@ -324,7 +338,7 @@ void StatsWeightCalculator::GenerateBasicWeights(Player* player)
stats_weights_[STATS_TYPE_STRENGTH] += 1.1f; stats_weights_[STATS_TYPE_STRENGTH] += 1.1f;
stats_weights_[STATS_TYPE_INTELLECT] += 0.3f; stats_weights_[STATS_TYPE_INTELLECT] += 0.3f;
stats_weights_[STATS_TYPE_ATTACK_POWER] += 1.0f; stats_weights_[STATS_TYPE_ATTACK_POWER] += 1.0f;
stats_weights_[STATS_TYPE_SPELL_POWER] += 0.95f; stats_weights_[STATS_TYPE_SPELL_POWER] += 0.5f;
stats_weights_[STATS_TYPE_ARMOR_PENETRATION] += 0.9f; stats_weights_[STATS_TYPE_ARMOR_PENETRATION] += 0.9f;
stats_weights_[STATS_TYPE_HIT] += 2.1f; stats_weights_[STATS_TYPE_HIT] += 2.1f;
stats_weights_[STATS_TYPE_CRIT] += 1.5f; stats_weights_[STATS_TYPE_CRIT] += 1.5f;
@ -343,6 +357,7 @@ void StatsWeightCalculator::GenerateBasicWeights(Player* player)
stats_weights_[STATS_TYPE_HIT] += 1.1f; stats_weights_[STATS_TYPE_HIT] += 1.1f;
stats_weights_[STATS_TYPE_CRIT] += 0.8f; stats_weights_[STATS_TYPE_CRIT] += 0.8f;
stats_weights_[STATS_TYPE_HASTE] += 1.0f; stats_weights_[STATS_TYPE_HASTE] += 1.0f;
stats_weights_[STATS_TYPE_ATTACK_POWER] -= 1.0f;
stats_weights_[STATS_TYPE_RANGED_DPS] += 1.0f; stats_weights_[STATS_TYPE_RANGED_DPS] += 1.0f;
} }
else if (cls == CLASS_MAGE && tab == MAGE_TAB_FIRE) else if (cls == CLASS_MAGE && tab == MAGE_TAB_FIRE)
@ -353,15 +368,17 @@ void StatsWeightCalculator::GenerateBasicWeights(Player* player)
stats_weights_[STATS_TYPE_HIT] += 1.2f; stats_weights_[STATS_TYPE_HIT] += 1.2f;
stats_weights_[STATS_TYPE_CRIT] += 1.1f; stats_weights_[STATS_TYPE_CRIT] += 1.1f;
stats_weights_[STATS_TYPE_HASTE] += 0.8f; stats_weights_[STATS_TYPE_HASTE] += 0.8f;
stats_weights_[STATS_TYPE_ATTACK_POWER] -= 1.0f;
stats_weights_[STATS_TYPE_RANGED_DPS] += 1.0f; stats_weights_[STATS_TYPE_RANGED_DPS] += 1.0f;
} }
else if (cls == CLASS_SHAMAN && tab == SHAMAN_TAB_ELEMENTAL) else if (cls == CLASS_SHAMAN && tab == SHAMAN_TAB_ELEMENTAL)
{ {
stats_weights_[STATS_TYPE_INTELLECT] += 0.25f; stats_weights_[STATS_TYPE_INTELLECT] += 0.5f;
stats_weights_[STATS_TYPE_SPELL_POWER] += 1.0f; stats_weights_[STATS_TYPE_SPELL_POWER] += 1.2f;
stats_weights_[STATS_TYPE_HIT] += 1.1f; stats_weights_[STATS_TYPE_HIT] += 1.1f;
stats_weights_[STATS_TYPE_CRIT] += 0.8f; stats_weights_[STATS_TYPE_CRIT] += 0.8f;
stats_weights_[STATS_TYPE_HASTE] += 1.0f; stats_weights_[STATS_TYPE_HASTE] += 1.0f;
stats_weights_[STATS_TYPE_MANA_REGENERATION] += 0.5f;
} }
else if ((cls == CLASS_PALADIN && tab == PALADIN_TAB_HOLY) || else if ((cls == CLASS_PALADIN && tab == PALADIN_TAB_HOLY) ||
(cls == CLASS_SHAMAN && tab == SHAMAN_TAB_RESTORATION)) (cls == CLASS_SHAMAN && tab == SHAMAN_TAB_RESTORATION))
@ -382,14 +399,15 @@ void StatsWeightCalculator::GenerateBasicWeights(Player* player)
stats_weights_[STATS_TYPE_MANA_REGENERATION] += 0.9f; stats_weights_[STATS_TYPE_MANA_REGENERATION] += 0.9f;
stats_weights_[STATS_TYPE_CRIT] += 0.6f; stats_weights_[STATS_TYPE_CRIT] += 0.6f;
stats_weights_[STATS_TYPE_HASTE] += 0.8f; stats_weights_[STATS_TYPE_HASTE] += 0.8f;
stats_weights_[STATS_TYPE_ATTACK_POWER] -= 1.0f;
stats_weights_[STATS_TYPE_RANGED_DPS] += 1.0f; stats_weights_[STATS_TYPE_RANGED_DPS] += 1.0f;
} }
else if ((cls == CLASS_WARRIOR && tab == WARRIOR_TAB_PROTECTION) || else if ((cls == CLASS_WARRIOR && tab == WARRIOR_TAB_PROTECTION) ||
(cls == CLASS_PALADIN && tab == PALADIN_TAB_PROTECTION)) (cls == CLASS_PALADIN && tab == PALADIN_TAB_PROTECTION))
{ {
stats_weights_[STATS_TYPE_AGILITY] += 2.0f; stats_weights_[STATS_TYPE_AGILITY] += 0.2f;
stats_weights_[STATS_TYPE_STRENGTH] += 1.0f; stats_weights_[STATS_TYPE_STRENGTH] += 1.3f;
stats_weights_[STATS_TYPE_STAMINA] += 3.5f; stats_weights_[STATS_TYPE_STAMINA] += 3.0f;
stats_weights_[STATS_TYPE_ATTACK_POWER] += 0.2f; stats_weights_[STATS_TYPE_ATTACK_POWER] += 0.2f;
stats_weights_[STATS_TYPE_DEFENSE] += 2.5f; stats_weights_[STATS_TYPE_DEFENSE] += 2.5f;
stats_weights_[STATS_TYPE_PARRY] += 2.0f; stats_weights_[STATS_TYPE_PARRY] += 2.0f;
@ -399,26 +417,26 @@ void StatsWeightCalculator::GenerateBasicWeights(Player* player)
stats_weights_[STATS_TYPE_BLOCK_VALUE] += 0.5f; stats_weights_[STATS_TYPE_BLOCK_VALUE] += 0.5f;
stats_weights_[STATS_TYPE_ARMOR] += 0.15f; stats_weights_[STATS_TYPE_ARMOR] += 0.15f;
stats_weights_[STATS_TYPE_HIT] += 2.0f; stats_weights_[STATS_TYPE_HIT] += 2.0f;
stats_weights_[STATS_TYPE_CRIT] += 0.2f; stats_weights_[STATS_TYPE_SPELL_POWER] -= 2.0f;
stats_weights_[STATS_TYPE_HASTE] += 0.5f;
stats_weights_[STATS_TYPE_EXPERTISE] += 3.0f; stats_weights_[STATS_TYPE_EXPERTISE] += 3.0f;
stats_weights_[STATS_TYPE_MELEE_DPS] += 2.0f; stats_weights_[STATS_TYPE_MELEE_DPS] += 2.0f;
} }
else if (cls == CLASS_DEATH_KNIGHT && tab == DEATH_KNIGHT_TAB_BLOOD) else if (cls == CLASS_DEATH_KNIGHT && tab == DEATH_KNIGHT_TAB_BLOOD)
{ {
stats_weights_[STATS_TYPE_AGILITY] += 2.0f; stats_weights_[STATS_TYPE_AGILITY] += 0.2f;
stats_weights_[STATS_TYPE_STRENGTH] += 1.0f; stats_weights_[STATS_TYPE_STRENGTH] += 1.3f;
stats_weights_[STATS_TYPE_STAMINA] += 3.5f; stats_weights_[STATS_TYPE_STAMINA] += 3.0f;
stats_weights_[STATS_TYPE_ATTACK_POWER] += 0.2f; stats_weights_[STATS_TYPE_ATTACK_POWER] += 0.2f;
stats_weights_[STATS_TYPE_DEFENSE] += 3.5f; stats_weights_[STATS_TYPE_DEFENSE] += 2.5f;
stats_weights_[STATS_TYPE_PARRY] += 2.0f; stats_weights_[STATS_TYPE_PARRY] += 2.0f;
stats_weights_[STATS_TYPE_DODGE] += 2.0f; stats_weights_[STATS_TYPE_DODGE] += 2.0f;
stats_weights_[STATS_TYPE_BLOCK_RATING] -= 2.0f;
stats_weights_[STATS_TYPE_BLOCK_VALUE] -= 2.0f;
// stats_weights_[STATS_TYPE_RESILIENCE] += 2.0f; // stats_weights_[STATS_TYPE_RESILIENCE] += 2.0f;
stats_weights_[STATS_TYPE_ARMOR] += 0.15f; stats_weights_[STATS_TYPE_ARMOR] += 0.15f;
stats_weights_[STATS_TYPE_HIT] += 2.0f; stats_weights_[STATS_TYPE_HIT] += 2.0f;
stats_weights_[STATS_TYPE_CRIT] += 0.5f; stats_weights_[STATS_TYPE_SPELL_POWER] -= 1.0f;
stats_weights_[STATS_TYPE_HASTE] += 0.5f; stats_weights_[STATS_TYPE_EXPERTISE] += 3.0f;
stats_weights_[STATS_TYPE_EXPERTISE] += 3.5f;
stats_weights_[STATS_TYPE_MELEE_DPS] += 2.0f; stats_weights_[STATS_TYPE_MELEE_DPS] += 2.0f;
} }
else else
@ -467,10 +485,23 @@ void StatsWeightCalculator::GenerateAdditionalWeights(Player* player)
&& !player->HasSpell(SPELL_MOLTEN_ARMOR_RANK_2) && !player->HasSpell(SPELL_MOLTEN_ARMOR_RANK_2)
&& !player->HasSpell(SPELL_MOLTEN_ARMOR_RANK_3)) && !player->HasSpell(SPELL_MOLTEN_ARMOR_RANK_3))
{ {
stats_weights_[STATS_TYPE_INTELLECT] += 0.2f; if (tab != MAGE_TAB_FIRE)
stats_weights_[STATS_TYPE_SPIRIT] -= 0.0f; stats_weights_[STATS_TYPE_SPIRIT] -= 0.6f;
else
stats_weights_[STATS_TYPE_SPIRIT] -= 0.7f;
} }
} }
else if (cls == CLASS_WARLOCK)
{
if (!player->HasSpell(SPELL_FEL_ARMOR_RANK_1) && !player->HasSpell(SPELL_FEL_ARMOR_RANK_2) &&
!player->HasSpell(SPELL_FEL_ARMOR_RANK_3) && !player->HasSpell(SPELL_FEL_ARMOR_RANK_4))
stats_weights_[STATS_TYPE_SPIRIT] -= 0.4f;
}
if (pvpSpec_ && !exclude_resilience_)
stats_weights_[STATS_TYPE_RESILIENCE] += 7.0f;
else if (!pvpSpec_)
stats_weights_[STATS_TYPE_RESILIENCE] -= 3.0f;
} }
void StatsWeightCalculator::CalculateItemSetMod(Player* player, ItemTemplate const* proto) void StatsWeightCalculator::CalculateItemSetMod(Player* player, ItemTemplate const* proto)
@ -517,7 +548,7 @@ void StatsWeightCalculator::CalculateItemSetMod(Player* player, ItemTemplate con
weight_ *= multiplier; weight_ *= multiplier;
} }
void StatsWeightCalculator::CalculateSocketBonus(Player* player, ItemTemplate const* proto) void StatsWeightCalculator::CalculateSocketBonus(Player* /*player*/, ItemTemplate const* proto)
{ {
uint32 socketNum = 0; uint32 socketNum = 0;
for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT + MAX_GEM_SOCKETS; for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT + MAX_GEM_SOCKETS;
@ -561,7 +592,8 @@ void StatsWeightCalculator::CalculateItemTypePenalty(ItemTemplate const* proto)
(cls == CLASS_WARRIOR && tab == WARRIOR_TAB_FURY && !player_->CanTitanGrip() && (cls == CLASS_WARRIOR && tab == WARRIOR_TAB_FURY && !player_->CanTitanGrip() &&
player_->CanDualWield()) || player_->CanDualWield()) ||
(cls == CLASS_WARRIOR && tab == WARRIOR_TAB_PROTECTION) || (cls == CLASS_WARRIOR && tab == WARRIOR_TAB_PROTECTION) ||
(cls == CLASS_PALADIN && tab == PALADIN_TAB_PROTECTION))) (cls == CLASS_PALADIN && tab == PALADIN_TAB_PROTECTION) ||
(cls == CLASS_PALADIN && tab == PALADIN_TAB_HOLY)))
{ {
weight_ *= 0.1; weight_ *= 0.1;
} }
@ -580,11 +612,16 @@ void StatsWeightCalculator::CalculateItemTypePenalty(ItemTemplate const* proto)
weight_ *= 0.1; weight_ *= 0.1;
} }
// caster's main hand (cannot duel weapon but can equip two-hands stuff) // caster's main hand (cannot duel weapon but can equip two-hands stuff)
if (cls == CLASS_MAGE || cls == CLASS_PRIEST || cls == CLASS_WARLOCK || cls == CLASS_DRUID || if ((cls == CLASS_MAGE || cls == CLASS_PRIEST || cls == CLASS_WARLOCK || cls == CLASS_DRUID ||
(cls == CLASS_SHAMAN && !player_->CanDualWield())) (cls == CLASS_SHAMAN && !player_->CanDualWield())) &&
!(cls == CLASS_PALADIN && tab == PALADIN_TAB_HOLY))
{ {
weight_ *= 0.65; weight_ *= 0.65;
} }
if (cls == CLASS_PALADIN && tab == PALADIN_TAB_HOLY)
{
weight_ *= 0.8;
}
} }
// fury with titan's grip // fury with titan's grip
if ((!isDoubleHand || proto->SubClass == ITEM_SUBCLASS_WEAPON_POLEARM || if ((!isDoubleHand || proto->SubClass == ITEM_SUBCLASS_WEAPON_POLEARM ||
@ -755,3 +792,163 @@ void StatsWeightCalculator::ApplyWeightFinetune(Player* player)
} }
} }
} }
float StatsWeightCalculator::ApplyPreferredSpecWeapons(ItemTemplate const* proto, int32 slot)
{
// Multiply score by 3x when this weapon's delay matches the spec-ideal speed.
float weight = 2.0f;
// Applies to mainhand, offhand, and ranged slots only.
if (slot != EQUIPMENT_SLOT_MAINHAND &&
slot != EQUIPMENT_SLOT_OFFHAND &&
slot != EQUIPMENT_SLOT_RANGED)
return 1.0f;
uint32 delay = proto->Delay; // milliseconds
float boost = 1.0f + weight; // applied on a match
// Hunter: melee weapons are stat sticks — speed irrelevant.
// Ranged weapons scale Aimed/Chimera/Explosive Shot from top-end damage,
// so a slow ranged weapon (>=2600 ms) is strongly preferred.
if (cls == CLASS_HUNTER)
{
if (slot == EQUIPMENT_SLOT_RANGED && delay >= 2600)
return boost;
return 1.0f;
}
// Feral Druid: forms normalise attack speed; raw weapon Delay is irrelevant.
if (cls == CLASS_DRUID && tab == DRUID_TAB_FERAL)
return 1.0f;
switch (cls)
{
case CLASS_WARRIOR:
if (tab == WARRIOR_TAB_ARMS)
{
// Arms: slow 2H axes or polearms in mainhand only (Axe Specialization: +5% crit).
bool isAxeOrPolearm = (proto->SubClass == ITEM_SUBCLASS_WEAPON_AXE2 ||
proto->SubClass == ITEM_SUBCLASS_WEAPON_POLEARM);
if (slot == EQUIPMENT_SLOT_MAINHAND && delay >= 3400 && isAxeOrPolearm)
return boost;
}
else if (tab == WARRIOR_TAB_FURY)
{
if (!player_->CanDualWield())
{
// Pre-DW: treat like Arms — slow 2H in mainhand only.
if (slot == EQUIPMENT_SLOT_MAINHAND && delay >= 3400)
return boost;
}
else if (player_->CanTitanGrip())
{
// Titan's Grip: slow 2H (>=3400) in both hands.
if (delay >= 3400)
return boost;
}
else
{
// 1H DW: slow 1H (>=2600) in both hands.
// 2H must be excluded — delay >= 2600 would otherwise pass
// for a 2H heirloom (~3600ms) just as it did for Enhancement.
if (proto->InventoryType == INVTYPE_2HWEAPON)
break;
if (delay >= 2600)
return boost;
}
}
else if (tab == WARRIOR_TAB_PROTECTION)
{
// Prot: slow 1H (>=2600) in mainhand. Shield in offhand, no speed bonus.
if (slot == EQUIPMENT_SLOT_MAINHAND && delay >= 2600)
return boost;
}
break;
case CLASS_PALADIN:
if (tab == PALADIN_TAB_RETRIBUTION)
{
// Ret: slow 2H in mainhand only.
if (slot == EQUIPMENT_SLOT_MAINHAND && delay >= 3400)
return boost;
}
else if (tab == PALADIN_TAB_PROTECTION)
{
// Prot: slow 1H (>=2600) in mainhand. Shield in offhand.
if (slot == EQUIPMENT_SLOT_MAINHAND && delay >= 2600)
return boost;
}
break;
case CLASS_DEATH_KNIGHT:
if (tab == DEATH_KNIGHT_TAB_BLOOD || tab == DEATH_KNIGHT_TAB_UNHOLY)
{
// Blood / Unholy: slow 2H in mainhand only.
if (slot == EQUIPMENT_SLOT_MAINHAND && delay >= 3400)
return boost;
}
else if (tab == DEATH_KNIGHT_TAB_FROST)
{
// Frost DK has Dual Wield innately — always dual-wields 1H.
if (proto->InventoryType == INVTYPE_2HWEAPON)
break;
if (delay >= 2600)
return boost;
}
break;
case CLASS_SHAMAN:
if (tab == SHAMAN_TAB_ENHANCEMENT)
{
if (!player_->CanDualWield())
{
// Pre-Dual Wield: Enhancement plays like a 2H spec.
if (slot == EQUIPMENT_SLOT_MAINHAND && delay >= 3400)
return boost;
}
else
{
// Post-Dual Wield: slow 1H (>=2600) in both hands.
if (proto->InventoryType == INVTYPE_2HWEAPON)
break;
if (delay >= 2600)
{
float mult = boost;
if (slot == EQUIPMENT_SLOT_OFFHAND)
{
Item* mh = player_->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
if (mh && mh->GetTemplate() && mh->GetTemplate()->Delay == delay)
mult *= boost; // synchronized: ×(1+weight)² total = ×9 for 2.0f weight
}
return mult;
}
}
}
break;
case CLASS_ROGUE:
if (tab == ROGUE_TAB_COMBAT)
{
// Combat: slow MH (>=2600), fast OH (<=1500).
if (slot == EQUIPMENT_SLOT_MAINHAND && delay >= 2600)
return boost;
if (slot == EQUIPMENT_SLOT_OFFHAND && delay <= 1500)
return boost;
}
else // Assassination or Subtlety: slow dagger MH, fast dagger OH.
{
bool isDagger = (proto->SubClass == ITEM_SUBCLASS_WEAPON_DAGGER);
if (slot == EQUIPMENT_SLOT_MAINHAND && isDagger && delay >= 1700)
return boost;
if (slot == EQUIPMENT_SLOT_OFFHAND && isDagger && delay <= 1500)
return boost;
}
break;
default:
break;
}
return 1.0f;
}

View File

@ -28,12 +28,14 @@ class StatsWeightCalculator
public: public:
StatsWeightCalculator(Player* player); StatsWeightCalculator(Player* player);
void Reset(); void Reset();
float CalculateItem(uint32 itemId, int32 randomPropertyId = 0); float CalculateItem(uint32 itemId, int32 randomPropertyId = 0, int32 slot = -1);
float CalculateEnchant(uint32 enchantId); float CalculateEnchant(uint32 enchantId);
void SetOverflowPenalty(bool apply) { enable_overflow_penalty_ = apply; } void SetOverflowPenalty(bool apply) { enable_overflow_penalty_ = apply; }
void SetItemSetBonus(bool apply) { enable_item_set_bonus_ = apply; } void SetItemSetBonus(bool apply) { enable_item_set_bonus_ = apply; }
void SetQualityBlend(bool apply) { enable_quality_blend_ = apply; } void SetQualityBlend(bool apply) { enable_quality_blend_ = apply; }
void SetPvpSpec(bool isPvp) { pvpSpec_ = isPvp; }
void SetExcludeResilience(bool exclude) { exclude_resilience_ = exclude; }
private: private:
void GenerateWeights(Player* player); void GenerateWeights(Player* player);
@ -45,6 +47,7 @@ public:
void CalculateSocketBonus(Player* player, ItemTemplate const* proto); void CalculateSocketBonus(Player* player, ItemTemplate const* proto);
void CalculateItemTypePenalty(ItemTemplate const* proto); void CalculateItemTypePenalty(ItemTemplate const* proto);
float ApplyPreferredSpecWeapons(ItemTemplate const* proto, int32 slot);
bool NotBestArmorType(uint32 item_subclass_armor); bool NotBestArmorType(uint32 item_subclass_armor);
@ -65,6 +68,8 @@ private:
float weight_; float weight_;
float stats_weights_[STATS_TYPE_MAX]; float stats_weights_[STATS_TYPE_MAX];
bool pvpSpec_ = false;
bool exclude_resilience_ = false;
}; };
#endif #endif

View File

@ -142,7 +142,7 @@ bool TalentSpec::CheckTalents(uint32 level, std::ostringstream* out)
} }
// Set the talents for the bots to the current spec. // Set the talents for the bots to the current spec.
void TalentSpec::ApplyTalents(Player* bot, std::ostringstream* out) void TalentSpec::ApplyTalents(Player* bot, std::ostringstream* /*out*/)
{ {
for (auto& entry : talents) for (auto& entry : talents)
{ {
@ -397,7 +397,7 @@ uint32 TalentSpec::highestTree()
return 0; return 0;
} }
std::string const TalentSpec::FormatSpec(Player* bot) std::string const TalentSpec::FormatSpec(Player* /*bot*/)
{ {
// uint8 cls = bot->getClass(); //not used, (used in lined 403), line marked for removal. // uint8 cls = bot->getClass(); //not used, (used in lined 403), line marked for removal.

Some files were not shown because too many files have changed in this diff Show More