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)
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
# Default: 1 (enabled)
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.RandomClassSpecIndex.1.0 = 0
# fury pve
AiPlayerbot.RandomClassSpecProb.1.1 = 40
AiPlayerbot.RandomClassSpecIndex.1.1 = 1
# prot pve
AiPlayerbot.RandomClassSpecProb.1.2 = 40
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.RandomClassSpecIndex.2.0 = 0
# prot pve
AiPlayerbot.RandomClassSpecProb.2.1 = 40
AiPlayerbot.RandomClassSpecIndex.2.1 = 1
# ret pve
AiPlayerbot.RandomClassSpecProb.2.2 = 30
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.RandomClassSpecIndex.3.0 = 0
# mm pve
AiPlayerbot.RandomClassSpecProb.3.1 = 33
AiPlayerbot.RandomClassSpecIndex.3.1 = 1
# surv pve
AiPlayerbot.RandomClassSpecProb.3.2 = 33
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.RandomClassSpecIndex.4.0 = 0
# combat pve
AiPlayerbot.RandomClassSpecProb.4.1 = 45
AiPlayerbot.RandomClassSpecIndex.4.1 = 1
# subtlety pve
AiPlayerbot.RandomClassSpecProb.4.2 = 10
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.RandomClassSpecIndex.5.0 = 0
# holy pve
AiPlayerbot.RandomClassSpecProb.5.1 = 35
AiPlayerbot.RandomClassSpecIndex.5.1 = 1
# shadow pve
AiPlayerbot.RandomClassSpecProb.5.2 = 25
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.RandomClassSpecIndex.6.0 = 0
# frost pve
AiPlayerbot.RandomClassSpecProb.6.1 = 40
AiPlayerbot.RandomClassSpecIndex.6.1 = 1
# unholy pve
AiPlayerbot.RandomClassSpecProb.6.2 = 30
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.RandomClassSpecIndex.7.0 = 0
# enh pve
AiPlayerbot.RandomClassSpecProb.7.1 = 33
AiPlayerbot.RandomClassSpecIndex.7.1 = 1
# resto pve
AiPlayerbot.RandomClassSpecProb.7.2 = 33
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.RandomClassSpecIndex.8.0 = 0
# fire pve
AiPlayerbot.RandomClassSpecProb.8.1 = 30
AiPlayerbot.RandomClassSpecIndex.8.1 = 1
# frost pve
AiPlayerbot.RandomClassSpecProb.8.2 = 40
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.RandomClassSpecIndex.9.0 = 0
# demo pve
AiPlayerbot.RandomClassSpecProb.9.1 = 34
AiPlayerbot.RandomClassSpecIndex.9.1 = 1
# destro pve
AiPlayerbot.RandomClassSpecProb.9.2 = 33
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.RandomClassSpecIndex.11.0 = 0
# bear pve
AiPlayerbot.RandomClassSpecProb.11.1 = 25
AiPlayerbot.RandomClassSpecIndex.11.1 = 1
# resto pve
AiPlayerbot.RandomClassSpecProb.11.2 = 35
AiPlayerbot.RandomClassSpecIndex.11.2 = 2
# cat pve
AiPlayerbot.RandomClassSpecProb.11.3 = 20
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;
}
// 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();
bool shouldMelee = bot->IsWithinMeleeRange(target) || botAI->IsMelee(bot);

View File

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

View File

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

View File

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

View File

@ -21,7 +21,7 @@ public:
}
bool Execute(Event event) override;
virtual std::string const castString(WorldObject* target) { return "cast"; }
virtual std::string const castString(WorldObject* /*target*/) { return "cast"; }
protected:
bool ncCast = false;
@ -49,7 +49,7 @@ public:
bool isUseful() override { return false; }
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);
bool Execute(Event event) override;

View File

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

View File

@ -116,6 +116,7 @@ bool ChooseRpgTargetAction::Execute(Event /*event*/)
GuidPosition masterRpgTarget;
if (master && master != bot && GET_PLAYERBOT_AI(master) && master->GetMapId() == bot->GetMapId() && !master->IsBeingTeleported())
{
//TODO Implement
Player* player = botAI->GetMaster();
//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();
if (!requester)
{
botAI->TellMaster("No event owner detected");
return false;
}
if (!sPlayerbotAIConfig.dropObsoleteQuests)
{
return false;
}
// Only output this message if "debug rpg" strategy is enabled
if (botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT))
{
botAI->TellMaster("Clean Quest Log command received, removing grey/trivial quests...");
}
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)
{
@ -101,34 +86,24 @@ bool CleanQuestLogAction::Execute(Event event)
// Determine if quest is trivial by comparing levels
int32 questLevel = quest->GetQuestLevel();
if (questLevel == -1) // For scaling quests, default to bot level
{
questLevel = botLevel;
}
// Set the level difference for when a quest becomes trivial
// This was determined by using the Lua code the client uses
int32 trivialLevel = 5;
if (botLevel >= 40)
{
trivialLevel = 8;
}
else if (botLevel >= 30)
{
trivialLevel = 7;
}
else if (botLevel >= 20)
{
trivialLevel = 6;
}
// Check if the quest is trivial (grey) for the bot
if ((botLevel - questLevel) > trivialLevel)
{
// Output only if "debug rpg" strategy is enabled
if (botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT))
{
botAI->TellMaster("Quest [ " + quest->GetTitle() + " ] will be removed because it is trivial (grey).");
}
// Remove quest
botAI->rpgStatistic.questDropped++;
@ -137,8 +112,6 @@ bool CleanQuestLogAction::Execute(Event event)
bot->SetQuestStatus(questId, QUEST_STATUS_NONE);
bot->RemoveRewardedQuest(questId);
numQuest--;
if (botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT))
{
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))
{
botAI->TellMaster("Quest [ " + quest->GetTitle() + " ] has been removed.");
}
}
else
{
// Only output if "debug rpg" strategy is enabled
if (botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT))
{
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::mt19937 g(rd());
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
{
if (bot->GetLevel() + 5 > bot->GetQuestLevel(quest)) // Quest is not red
{
if (!isGreen)
continue;
}
}
else // Quest is gray
{

View File

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

View File

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

View File

@ -78,7 +78,7 @@ private:
class TakeMailProcessor : public MailProcessor
{
public:
bool Process(uint32 index, Mail* mail, PlayerbotAI* botAI) override
bool Process(uint32 /*index*/, Mail* mail, PlayerbotAI* botAI) override
{
Player* bot = botAI->GetBot();
if (!CheckBagSpace(bot))
@ -104,7 +104,7 @@ public:
{
std::vector<uint32> guids;
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);
for (std::vector<uint32>::iterator i = guids.begin(); i != guids.end(); ++i)
@ -157,7 +157,7 @@ private:
class DeleteMailProcessor : public MailProcessor
{
public:
bool Process(uint32 index, Mail* mail, PlayerbotAI* botAI) override
bool Process(uint32 /*index*/, Mail* mail, PlayerbotAI* botAI) override
{
std::ostringstream out;
out << "|cffffffff" << mail->subject << "|cffff0000 deleted";
@ -172,7 +172,7 @@ public:
class ReadMailProcessor : public MailProcessor
{
public:
bool Process(uint32 index, Mail* mail, PlayerbotAI* botAI) override
bool Process(uint32 /*index*/, Mail* mail, PlayerbotAI* botAI) override
{
std::ostringstream out, body;
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)
{
UpdateMovementState();
if (!IsMovingAllowed(mapId, x, y, z))
if (!IsMovingAllowed())
return false;
if (IsDuplicateMove(mapId, x, y, z))
if (IsDuplicateMove(x, y, z))
return false;
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)
{
UpdateMovementState();
if (!IsMovingAllowed(mapId, x, y, z))
if (!IsMovingAllowed())
{
return false;
}
if (IsDuplicateMove(mapId, x, y, z))
if (IsDuplicateMove(x, y, z))
{
return false;
}
@ -897,20 +897,7 @@ bool MovementAction::IsMovingAllowed(WorldObject* target)
return IsMovingAllowed();
}
bool MovementAction::IsMovingAllowed(uint32 mapId, 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)
bool MovementAction::IsDuplicateMove(float x, float y, float z)
{
LastMovement& lastMove = *context->GetValue<LastMovement&>("last movement");
@ -1286,7 +1273,7 @@ bool MovementAction::Follow(Unit* target, float distance, float angle)
return true;
}
bool MovementAction::ChaseTo(WorldObject* obj, float distance, float angle)
bool MovementAction::ChaseTo(WorldObject* obj, float distance)
{
if (!IsMovingAllowed())
{
@ -1859,7 +1846,7 @@ bool FleeAction::isUseful()
bool FleeWithPetAction::Execute(Event /*event*/)
{
if (Pet* pet = bot->GetPet())
if (bot->GetPet())
botAI->PetFollow();
return Flee(AI_VALUE(Unit*, "current target"));

View File

@ -43,14 +43,13 @@ protected:
float GetFollowAngle();
bool Follow(Unit* target, float distance = sPlayerbotAIConfig.followDistance);
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);
float MoveDelay(float distance, bool backwards = false);
void WaitForReach(float distance);
void SetNextMovementDelay(float delayMillis);
bool IsMovingAllowed(WorldObject* target);
bool IsMovingAllowed(uint32 mapId, float x, float y, float z);
bool IsDuplicateMove(uint32 mapId, float x, float y, float z);
bool IsDuplicateMove(float x, float y, float z);
bool IsWaitingForLastMove(MovementPriority priority);
bool IsMovingAllowed();
bool Flee(Unit* target);

View File

@ -45,7 +45,7 @@ std::once_flag ReadyChecker::initFlag;
class HealthChecker : public ReadyChecker
{
public:
bool Check(PlayerbotAI* botAI, AiObjectContext* context) override
bool Check(PlayerbotAI* /*botAI*/, AiObjectContext* context) override
{
return AI_VALUE2(uint8, "health", "self target") > sPlayerbotAIConfig.almostFullHealth;
}
@ -56,7 +56,7 @@ public:
class ManaChecker : public ReadyChecker
{
public:
bool Check(PlayerbotAI* botAI, AiObjectContext* context) override
bool Check(PlayerbotAI* /*botAI*/, AiObjectContext* context) override
{
return !AI_VALUE2(bool, "has mana", "self target") ||
AI_VALUE2(uint8, "mana", "self target") > sPlayerbotAIConfig.mediumHealth;
@ -68,7 +68,7 @@ public:
class DistanceChecker : public ReadyChecker
{
public:
bool Check(PlayerbotAI* botAI, AiObjectContext* context) override
bool Check(PlayerbotAI* botAI, AiObjectContext* /*context*/) override
{
Player* bot = botAI->GetBot();
if (Player* master = botAI->GetMaster())
@ -90,7 +90,7 @@ public:
class HunterChecker : public ReadyChecker
{
public:
bool Check(PlayerbotAI* botAI, AiObjectContext* context) override
bool Check(PlayerbotAI* botAI, AiObjectContext* /*context*/) override
{
Player* bot = botAI->GetBot();
if (bot->getClass() == CLASS_HUNTER)
@ -126,7 +126,7 @@ class ItemCountChecker : public ReadyChecker
public:
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;
}
@ -225,4 +225,4 @@ bool ReadyCheckAction::ReadyCheck()
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";
@ -82,13 +82,13 @@ bool AutoReleaseSpiritAction::Execute(Event /*event*/)
{
IncrementDeathCount();
bot->DurabilityRepairAll(false, 1.0f, false);
LogRelease("auto released", true);
LogRelease("auto released");
WorldPacket packet(CMSG_REPOP_REQUEST);
packet << uint8(0);
bot->GetSession()->HandleRepopRequestOpcode(packet);
LogRelease("releases spirit", true);
LogRelease("releases spirit");
if (bot->InBattleground())
{

View File

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

View File

@ -251,9 +251,9 @@ GraveyardStruct const* SpiritHealerAction::GetGrave(bool startZone)
std::vector<uint32> races;
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
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;

View File

@ -154,7 +154,7 @@ bool SayAction::isUseful()
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 = "";
@ -205,14 +205,14 @@ void ChatReplyAction::ChatReplyDo(Player* bot, uint32& type, uint32& guid1, uint
if (msg.starts_with(sPlayerbotAIConfig.toxicLinksPrefix)
&& (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;
}
//thunderfury
if (GET_PLAYERBOT_AI(bot)->GetChatHelper()->ExtractAllItemIds(msg).count(19019))
{
HandleThunderfuryReply(bot, chatChannelSource, msg, name);
HandleThunderfuryReply(bot, chatChannelSource);
return;
}
@ -220,7 +220,7 @@ void ChatReplyAction::ChatReplyDo(Player* bot, uint32& type, uint32& guid1, uint
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;
const auto thunderfury = sObjectMgr->GetItemTemplate(19019);
@ -248,7 +248,7 @@ bool ChatReplyAction::HandleThunderfuryReply(Player* bot, ChatChannelSource chat
return true;
}
bool ChatReplyAction::HandleToxicLinksReply(Player* bot, ChatChannelSource chatChannelSource, std::string& msg, std::string& name)
bool ChatReplyAction::HandleToxicLinksReply(Player* bot, ChatChannelSource chatChannelSource)
{
//quests
std::vector<uint32> incompleteQuests;

View File

@ -29,12 +29,12 @@ class ChatReplyAction : public Action
{
public:
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; }
static void ChatReplyDo(Player* bot, uint32& type, uint32& guid1, uint32& guid2, std::string& msg, std::string& chanName, std::string& name);
static bool HandleThunderfuryReply(Player* bot, ChatChannelSource chatChannelSource, std::string& msg, std::string& name);
static bool HandleToxicLinksReply(Player* bot, ChatChannelSource chatChannelSource, std::string& msg, 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);
static bool HandleToxicLinksReply(Player* bot, ChatChannelSource chatChannelSource);
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 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};
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)
{
float dist = wpOwner->GetDistance(x, y, z);

View File

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

View File

@ -11,7 +11,7 @@ public:
ChatCommandActionNodeFactoryInternal() { creators["tank attack chat shortcut"] = &tank_attack_chat_shortcut; }
private:
static ActionNode* tank_attack_chat_shortcut(PlayerbotAI* botAI)
static ActionNode* tank_attack_chat_shortcut(PlayerbotAI* /*botAI*/)
{
return new ActionNode("tank attack chat shortcut",
/*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) {}
void StartDuelStrategy::InitTriggers(std::vector<TriggerNode*>& triggers) {}
void StartDuelStrategy::InitTriggers(std::vector<TriggerNode*>& /*triggers*/) {}
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(
new TriggerNode(
"random",
"seldom",
{
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) }));
}
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
{
ObjectGuid const guid = botAI->GetAiObjectContext()->GetValue<ObjectGuid>("pull target")->Get();
ObjectGuid const guid = botAI->GetAiObjectContext()->GetValue<ObjectGuid>("pull strategy target")->Get();
if (guid.IsEmpty())
return nullptr;
@ -66,7 +66,7 @@ bool PullStrategy::HasTarget() const { return GetTarget() != nullptr; }
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

View File

@ -7,4 +7,4 @@
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; }
private:
static ActionNode* lifeblood(PlayerbotAI* botAI)
static ActionNode* lifeblood(PlayerbotAI* /*botAI*/)
{
return new ActionNode("lifeblood",
/*P*/ {},

View File

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

View File

@ -19,6 +19,7 @@ WorldLocation ArrowFormation::GetLocationInternal()
uint32 tankLines = 1 + tanks.Size() / 6;
uint32 meleeLines = 1 + melee.Size() / 6;
uint32 rangedLines = 1 + ranged.Size() / 6;
//TODO Implement Healer Lines
uint32 healerLines = 1 + healers.Size() / 6;
float offset = 0.f;
@ -147,7 +148,7 @@ UnitPosition MultiLineUnitPlacer::Place(FormationUnit* unit, uint32 index, uint3
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 x = cos(angle) * sPlayerbotAIConfig.followDistance * ((float)index - (float)count / 2);

View File

@ -20,7 +20,7 @@ public:
}
public:
void CheckAttacker(Unit* creature, ThreatManager* threatMgr) override
void CheckAttacker(Unit* creature, ThreatManager* /*threatMgr*/) override
{
Player* bot = botAI->GetBot();
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))
result = attacker;

View File

@ -50,7 +50,7 @@ public:
result = nullptr;
}
void CheckAttacker(Unit* attacker, ThreatManager* threatMgr) override
void CheckAttacker(Unit* attacker, ThreatManager* /*threatMgr*/) override
{
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;
Player* bot = InventoryAction::botAI->GetBot();
std::vector<Item*> items = InventoryAction::parseItems(qualifier);
for (Item* item : items)
result.push_back(item);

View File

@ -17,7 +17,7 @@ class InventoryItemValueBase : public InventoryAction
public:
InventoryItemValueBase(PlayerbotAI* botAI) : InventoryAction(botAI, "empty") {}
bool Execute(Event event) override { return false; }
bool Execute(Event /*event*/) override { return false; }
protected:
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))
return nullptr;

View File

@ -234,6 +234,11 @@ ItemUsage ItemUsageValue::QueryItemUsageForEquip(ItemTemplate const* itemProto,
calculator.SetItemSetBonus(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);
if (itemScore)
@ -864,8 +869,6 @@ bool ItemUsageValue::SpellGivesSkillUp(uint32 spellId, Player* bot)
{
uint32 SkillValue = bot->GetPureSkillValue(skill->SkillLine);
uint32 craft_skill_gain = sWorld->getIntConfig(CONFIG_SKILL_GAIN_CRAFTING);
if (SkillGainChance(SkillValue, skill->TrivialSkillLineRankHigh,
(skill->TrivialSkillLineRankHigh + skill->TrivialSkillLineRankLow) / 2,
skill->TrivialSkillLineRankLow) > 0)

View File

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

View File

@ -60,7 +60,7 @@ public:
class AllLootStrategy : public LootStrategy
{
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"; }
};

View File

@ -28,4 +28,4 @@ void NearestCorpsesValue::FindUnits(std::list<Unit*>& targets)
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;
}
Unit* PartyMemberValue::FindPartyMember(FindPlayerPredicate& predicate, bool ignoreOutOfGroup)
Unit* PartyMemberValue::FindPartyMember(FindPlayerPredicate& predicate, bool /*ignoreOutOfGroup*/)
{
Player* master = GetMaster();
// GuidVector nearestPlayers;

View File

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

View File

@ -49,7 +49,7 @@ class FindTankTargetSmartStrategy : public FindTargetStrategy
public:
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())
{

View File

@ -161,7 +161,7 @@ Unit* FindTargetValue::Calculate()
return nullptr;
}
void FindBossTargetStrategy::CheckAttacker(Unit* attacker, ThreatManager* threatManager)
void FindBossTargetStrategy::CheckAttacker(Unit* attacker, ThreatManager* /*threatManager*/)
{
UnitAI* unitAI = attacker->GetAI();
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
{
public:

View File

@ -241,6 +241,7 @@ public:
creators["travel target"] = &ValueContext::travel_target;
creators["talk target"] = &ValueContext::talk_target;
creators["pull target"] = &ValueContext::pull_target;
creators["pull strategy target"] = &ValueContext::pull_strategy_target;
creators["focus heal targets"] = &ValueContext::focus_heal_targets;
creators["group"] = &ValueContext::group;
creators["range"] = &ValueContext::range;
@ -498,6 +499,7 @@ private:
static UntypedValue* next_rpg_action(PlayerbotAI* botAI) { return new NextRpgActionValue(botAI); }
static UntypedValue* travel_target(PlayerbotAI* botAI) { return new TravelTargetValue(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* 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) }));
}
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:
CastExplosiveShotRank4Action(PlayerbotAI* botAI) :
CastExplosiveShotBaseAction(botAI) {}
bool Execute(Event event) override
bool Execute(Event /*event*/) override
{
return botAI->CastSpell(60053, GetTarget());
}
@ -412,7 +412,7 @@ class CastExplosiveShotRank3Action : public CastExplosiveShotBaseAction
public:
CastExplosiveShotRank3Action(PlayerbotAI* botAI) :
CastExplosiveShotBaseAction(botAI) {}
bool Execute(Event event) override
bool Execute(Event /*event*/) override
{
return botAI->CastSpell(60052, GetTarget());
}
@ -432,7 +432,7 @@ class CastExplosiveShotRank2Action : public CastExplosiveShotBaseAction
public:
CastExplosiveShotRank2Action(PlayerbotAI* botAI) :
CastExplosiveShotBaseAction(botAI) {}
bool Execute(Event event) override
bool Execute(Event /*event*/) override
{
return botAI->CastSpell(60051, GetTarget());
}
@ -452,7 +452,7 @@ class CastExplosiveShotRank1Action : public CastExplosiveShotBaseAction
public:
CastExplosiveShotRank1Action(PlayerbotAI* botAI) :
CastExplosiveShotBaseAction(botAI) {}
bool Execute(Event event) override
bool Execute(Event /*event*/) override
{
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) }));
}
void PaladinBoostStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
void PaladinBoostStrategy::InitTriggers(std::vector<TriggerNode*>& /*triggers*/)
{
// 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
}
void WarlockPetStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
void WarlockPetStrategy::InitTriggers(std::vector<TriggerNode*>& /*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:
static ActionNode* charge(PlayerbotAI* botAI)
static ActionNode* charge(PlayerbotAI* /*botAI*/)
{
return new ActionNode(
"charge",
@ -31,7 +31,7 @@ private:
);
}
static ActionNode* death_wish(PlayerbotAI* botAI)
static ActionNode* death_wish(PlayerbotAI* /*botAI*/)
{
return new ActionNode(
"death wish",
@ -41,7 +41,7 @@ private:
);
}
static ActionNode* piercing_howl(PlayerbotAI* botAI)
static ActionNode* piercing_howl(PlayerbotAI* /*botAI*/)
{
return new ActionNode(
"piercing howl",
@ -51,7 +51,7 @@ private:
);
}
static ActionNode* mocking_blow(PlayerbotAI* botAI)
static ActionNode* mocking_blow(PlayerbotAI* /*botAI*/)
{
return new ActionNode(
"mocking blow",
@ -61,7 +61,7 @@ private:
);
}
static ActionNode* heroic_strike(PlayerbotAI* botAI)
static ActionNode* heroic_strike(PlayerbotAI* /*botAI*/)
{
return new ActionNode(
"heroic strike",
@ -71,7 +71,7 @@ private:
);
}
static ActionNode* enraged_regeneration(PlayerbotAI* botAI)
static ActionNode* enraged_regeneration(PlayerbotAI* /*botAI*/)
{
return new ActionNode(
"enraged regeneration",
@ -81,7 +81,7 @@ private:
);
}
static ActionNode* retaliation(PlayerbotAI* botAI)
static ActionNode* retaliation(PlayerbotAI* /*botAI*/)
{
return new ActionNode(
"retaliation",
@ -91,7 +91,7 @@ private:
);
}
static ActionNode* shattering_throw(PlayerbotAI* botAI)
static ActionNode* shattering_throw(PlayerbotAI* /*botAI*/)
{
return new ActionNode(
"shattering throw",

View File

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

View File

@ -24,7 +24,7 @@ public:
}
private:
static ActionNode* heroic_throw_taunt(PlayerbotAI* botAI)
static ActionNode* heroic_throw_taunt(PlayerbotAI* /*botAI*/)
{
return new ActionNode(
"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(
"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(
"last stand",
@ -54,7 +54,7 @@ private:
);
}
static ActionNode* devastate(PlayerbotAI* botAI)
static ActionNode* devastate(PlayerbotAI* /*botAI*/)
{
return new ActionNode(
"devastate",
@ -64,7 +64,7 @@ private:
);
}
static ActionNode* commanding_shout(PlayerbotAI* botAI)
static ActionNode* commanding_shout(PlayerbotAI* /*botAI*/)
{
return new ActionNode(
"commanding shout",
@ -74,7 +74,7 @@ private:
);
}
static ActionNode* sunder_armor(PlayerbotAI* botAI)
static ActionNode* sunder_armor(PlayerbotAI* /*botAI*/)
{
return new ActionNode(
"sunder armor",
@ -84,7 +84,7 @@ private:
);
}
static ActionNode* charge(PlayerbotAI* botAI)
static ActionNode* charge(PlayerbotAI* /*botAI*/)
{
return new ActionNode(
"charge",
@ -94,7 +94,7 @@ private:
);
}
static ActionNode* taunt(PlayerbotAI* botAI)
static ActionNode* taunt(PlayerbotAI* /*botAI*/)
{
return new ActionNode(
"taunt",
@ -104,7 +104,7 @@ private:
);
}
static ActionNode* vigilance(PlayerbotAI* botAI)
static ActionNode* vigilance(PlayerbotAI* /*botAI*/)
{
return new ActionNode(
"vigilance",
@ -114,7 +114,7 @@ private:
);
}
static ActionNode* enraged_regeneration(PlayerbotAI* botAI)
static ActionNode* enraged_regeneration(PlayerbotAI* /*botAI*/)
{
return new ActionNode(
"enraged regeneration",

View File

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

View File

@ -27,7 +27,7 @@ float IckAndKrickMultiplier::GetValue(Action* action)
return 1.0f;
}
float GarfrostMultiplier::GetValue(Action* action)
float GarfrostMultiplier::GetValue(Action* /*action*/)
{
Unit* boss = AI_VALUE2(Unit*, "find target", "garfrost");
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)
{
if (IsKroshMageTank(botAI, bot) &&
if (IsKroshMageTank(bot) &&
(dynamic_cast<CastFrostNovaAction*>(action) || dynamic_cast<CastBlizzardAction*>(action) ||
dynamic_cast<CastConeOfColdAction*>(action) || dynamic_cast<CastFlamestrikeAction*>(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");
return IsKroshMageTank(botAI, bot) && krosh;
return IsKroshMageTank(bot) && krosh;
}
bool HighKingMaulgarIsMoonkinTankTrigger::IsActive()
{
Unit* kiggler = AI_VALUE2(Unit*, "find target", "kiggler the crazed");
return IsKigglerMoonkinTank(botAI, bot) && kiggler;
return IsKigglerMoonkinTank(bot) && kiggler;
}
bool HighKingMaulgarDeterminingKillOrderTrigger::IsActive()
@ -53,8 +53,8 @@ bool HighKingMaulgarDeterminingKillOrderTrigger::IsActive()
!(botAI->IsMainTank(bot) && maulgar) &&
!(botAI->IsAssistTankOfIndex(bot, 0, false) && olm) &&
!(botAI->IsAssistTankOfIndex(bot, 1, false) && blindeye) &&
!(IsKroshMageTank(botAI, bot) && krosh) &&
!(IsKigglerMoonkinTank(botAI, bot) && kiggler);
!(IsKroshMageTank(bot) && krosh) &&
!(IsKigglerMoonkinTank(bot) && kiggler);
}
bool HighKingMaulgarHealerInDangerTrigger::IsActive()

View File

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

View File

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

View File

@ -1998,10 +1998,10 @@ bool IccRotfaceGroupPositionAction::PositionRangedAndHealers(Unit* boss,Unit *sm
if (!isHeroic)
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");
@ -6925,7 +6925,7 @@ bool IccLichKingWinterAction::Execute(Event /*event*/)
isVictim = true;
// 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)
const Position* safePos = botAI->IsTank(bot) ? GetMainTankPosition() : GetMainTankRangedPosition();
@ -7124,7 +7124,7 @@ const Position* IccLichKingWinterAction::GetMainTankRangedPosition()
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");
if (!boss)
@ -7190,7 +7190,7 @@ bool IccLichKingWinterAction::TryMoveToPosition(float targetX, float targetY, fl
dy /= distance;
// 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)
botAI->Reset();
@ -7221,7 +7221,7 @@ bool IccLichKingWinterAction::TryMoveToPosition(float targetX, float targetY, fl
float testY = currentY + dy * attemptDistance + offsetY * direction;
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)
botAI->Reset();
@ -7271,7 +7271,7 @@ void IccLichKingWinterAction::HandleTankPositioning()
const Position* targetPos = GetMainTankPosition();
// 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
TryMoveToPosition(targetPos->GetPositionX(), targetPos->GetPositionY(), 840.857f, true);
@ -7295,7 +7295,7 @@ void IccLichKingWinterAction::HandleTankPositioning()
}
// Once in position, handle add management from tank position
HandleMainTankAddManagement(boss, targetPos);
HandleMainTankAddManagement(targetPos);
}
// ASSIST TANK: More flexible positioning based on add collection
else if (botAI->IsAssistTank(bot))
@ -7312,7 +7312,7 @@ void IccLichKingWinterAction::HandleTankPositioning()
}
// Handle assist tank add collection and positioning
HandleAssistTankAddManagement(boss, targetPos);
HandleAssistTankAddManagement(targetPos);
}
}
@ -7405,7 +7405,7 @@ void IccLichKingWinterAction::HandleRangedPositioning()
const Position* targetPos = GetMainTankRangedPosition();
// 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
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))
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))
return;
@ -7812,7 +7812,7 @@ bool IccLichKingAddsAction::Execute(Event /*event*/)
return true;
// Handle shambling horror interactions
HandleShamblingHorrors(boss, hasPlague);
HandleShamblingHorrors();
// Handle assist tank add management
if (HandleAssistTankAddManagement(boss, diff))
@ -8251,7 +8251,7 @@ bool IccLichKingAddsAction::HandleQuakeMechanics(Unit* boss)
return false;
}
void IccLichKingAddsAction::HandleShamblingHorrors(Unit* boss, bool hasPlague)
void IccLichKingAddsAction::HandleShamblingHorrors()
{
// Find closest shambling horror
GuidVector npcs2 = AI_VALUE(GuidVector, "nearest hostile npcs");

View File

@ -286,7 +286,7 @@ public:
bool HandleOozeTargeting();
bool HandleOozeMemberPositioning();
bool PositionRangedAndHealers(Unit* boss,Unit* smallOoze);
bool FindAndMoveFromClosestMember(Unit* boss, Unit* smallOoze);
bool FindAndMoveFromClosestMember(Unit* smallOoze);
};
class IccRotfaceMoveAwayFromExplosionAction : public MovementAction
@ -623,12 +623,12 @@ class IccLichKingWinterAction : public AttackAction
void HandlePositionCorrection();
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 HandleMeleePositioning();
void HandleRangedPositioning();
void HandleMainTankAddManagement(Unit* boss, const Position* tankPos);
void HandleAssistTankAddManagement(Unit* boss, const Position* tankPos);
void HandleMainTankAddManagement(const Position* tankPos);
void HandleAssistTankAddManagement(const Position* tankPos);
private:
const Position* GetMainTankPosition();
@ -648,7 +648,7 @@ class IccLichKingAddsAction : public AttackAction
void HandleHeroicNonTankPositioning(Difficulty diff, Unit* terenasMenethilHC);
void HandleSpiritMarkingAndTargeting(Difficulty diff, Unit* terenasMenethilHC);
bool HandleQuakeMechanics(Unit* boss);
void HandleShamblingHorrors(Unit* boss, bool hasPlague);
void HandleShamblingHorrors();
bool HandleAssistTankAddManagement(Unit* boss, Difficulty diff);
void HandleMeleePositioning(Unit* boss, bool hasPlague, Difficulty diff);
void HandleMainTankTargeting(Unit* boss, Difficulty diff);

View File

@ -559,7 +559,7 @@ bool IccBqlVampiricBiteTrigger::IsActive()
bool IccValkyreSpearTrigger::IsActive()
{
// 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 false;

View File

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

View File

@ -272,7 +272,7 @@ namespace KarazhanHelpers
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)
{
@ -351,7 +351,7 @@ namespace KarazhanHelpers
destX, destY, destZ, true))
continue;
if (!IsSafePosition(destX, destY, destZ, hazards, safeDistance))
if (!IsSafePosition(destX, destY, hazards, safeDistance))
continue;
if (requireSafePath)

View File

@ -116,7 +116,7 @@ namespace KarazhanHelpers
std::vector<Player*> GetGreenBlockers(PlayerbotAI* botAI, Player* bot);
std::tuple<Player*, Player*, Player*> GetCurrentBeamBlockers(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);
bool IsStraightPathSafe(
const Position& start, const Position& target,

View File

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

View File

@ -81,7 +81,7 @@ public:
bool Execute(Event event) override;
private:
bool HandleCubeRelease(Unit* magtheridon, GameObject* cube);
bool HandleCubeRelease(Unit* magtheridon);
bool ShouldActivateCubeLogic(Unit* magtheridon);
bool HandleWaitingPhase(const MagtheridonHelpers::CubeInfo& cubeInfo);
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> 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
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) }));
}
void RaidOnyxiaStrategy::InitMultipliers(std::vector<Multiplier*>& multipliers)
void RaidOnyxiaStrategy::InitMultipliers(std::vector<Multiplier*>& /*multipliers*/)
{
// Empty for now
}

View File

@ -1466,16 +1466,16 @@ bool MorogrimTidewalkerMoveBossToTankPositionAction::Execute(Event /*event*/)
if (tidewalker->GetVictim() == bot && bot->IsWithinMeleeRange(tidewalker))
{
if (tidewalker->GetHealthPct() > 26.0f)
return MoveToPhase1TankPosition(tidewalker);
return MoveToPhase1TankPosition();
else
return MoveToPhase2TankPosition(tidewalker);
return MoveToPhase2TankPosition();
}
return false;
}
// 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;
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
bool MorogrimTidewalkerMoveBossToTankPositionAction::MoveToPhase2TankPosition(Unit* tidewalker)
bool MorogrimTidewalkerMoveBossToTankPositionAction::MoveToPhase2TankPosition()
{
const Position& phase2 = TIDEWALKER_PHASE_2_TANK_POSITION;
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
if (bot == firstCorePasser &&
LineUpFirstCorePasser(designatedLooter, closestTrigger))
LineUpFirstCorePasser(designatedLooter))
{
return true;
}
@ -2176,7 +2176,7 @@ bool LadyVashjPassTheTaintedCoreAction::Execute(Event /*event*/)
// Designated core looter logic
// Applicable only if cheat mode is on and thus looter is a bot
if (bot == designatedLooter &&
IsFirstCorePasserInPosition(designatedLooter, firstCorePasser, closestTrigger))
IsFirstCorePasserInPosition(firstCorePasser))
{
const time_t now = std::time(nullptr);
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,
// pass to second core passer
else if (bot == firstCorePasser &&
IsSecondCorePasserInPosition(firstCorePasser, secondCorePasser, closestTrigger))
IsSecondCorePasserInPosition(secondCorePasser))
{
const time_t now = std::time(nullptr);
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
// possible to the generator while staying in passing range
else if (bot == secondCorePasser && !UseCoreOnNearestGenerator(instanceId) &&
IsThirdCorePasserInPosition(secondCorePasser, thirdCorePasser, closestTrigger))
IsThirdCorePasserInPosition(thirdCorePasser))
{
const time_t now = std::time(nullptr);
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
// possible to the generator while staying in passing range
else if (bot == thirdCorePasser && !UseCoreOnNearestGenerator(instanceId) &&
IsFourthCorePasserInPosition(thirdCorePasser, fourthCorePasser, closestTrigger))
IsFourthCorePasserInPosition(fourthCorePasser))
{
const time_t now = std::time(nullptr);
auto it = lastImbueAttempt.find(instanceId);
@ -2249,7 +2249,7 @@ bool LadyVashjPassTheTaintedCoreAction::Execute(Event /*event*/)
}
bool LadyVashjPassTheTaintedCoreAction::LineUpFirstCorePasser(
Player* designatedLooter, Unit* closestTrigger)
Player* designatedLooter)
{
const float centerX = VASHJ_PLATFORM_CENTER_POSITION.GetPositionX();
const float centerY = VASHJ_PLATFORM_CENTER_POSITION.GetPositionY();
@ -2288,8 +2288,6 @@ bool LadyVashjPassTheTaintedCoreAction::LineUpSecondCorePasser(
if (itFirst == intendedLineup.end())
return false;
const Position& firstLineup = itFirst->second;
auto itSecond = intendedLineup.find(bot->GetGUID());
if (itSecond == intendedLineup.end())
{
@ -2343,9 +2341,9 @@ bool LadyVashjPassTheTaintedCoreAction::LineUpThirdCorePasser(
Player* secondCorePasser, Unit* closestTrigger)
{
bool needThirdPasser =
(IsFirstCorePasserInPosition(designatedLooter, firstCorePasser, closestTrigger) &&
(IsFirstCorePasserInPosition(firstCorePasser) &&
firstCorePasser->GetExactDist2d(closestTrigger) > 42.0f) ||
(IsSecondCorePasserInPosition(firstCorePasser, secondCorePasser, closestTrigger) &&
(IsSecondCorePasserInPosition(secondCorePasser) &&
secondCorePasser->GetExactDist2d(closestTrigger) > 4.0f);
if (!needThirdPasser)
@ -2408,9 +2406,9 @@ bool LadyVashjPassTheTaintedCoreAction::LineUpFourthCorePasser(
Player* thirdCorePasser, Unit* closestTrigger)
{
bool needFourthPasser =
(IsSecondCorePasserInPosition(firstCorePasser, secondCorePasser, closestTrigger) &&
(IsSecondCorePasserInPosition(secondCorePasser) &&
secondCorePasser->GetExactDist2d(closestTrigger) > 42.0f) ||
(IsThirdCorePasserInPosition(secondCorePasser, thirdCorePasser, closestTrigger) &&
(IsThirdCorePasserInPosition(thirdCorePasser) &&
thirdCorePasser->GetExactDist2d(closestTrigger) > 4.0f);
if (!needFourthPasser)
@ -2460,8 +2458,7 @@ bool LadyVashjPassTheTaintedCoreAction::LineUpFourthCorePasser(
// 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
bool LadyVashjPassTheTaintedCoreAction::IsFirstCorePasserInPosition(
Player* designatedLooter, Player* firstCorePasser, Unit* closestTrigger)
bool LadyVashjPassTheTaintedCoreAction::IsFirstCorePasserInPosition(Player* firstCorePasser)
{
auto itSnap = intendedLineup.find(firstCorePasser->GetGUID());
if (itSnap != intendedLineup.end())
@ -2474,8 +2471,7 @@ bool LadyVashjPassTheTaintedCoreAction::IsFirstCorePasserInPosition(
return false;
}
bool LadyVashjPassTheTaintedCoreAction::IsSecondCorePasserInPosition(
Player* firstCorePasser, Player* secondCorePasser, Unit* closestTrigger)
bool LadyVashjPassTheTaintedCoreAction::IsSecondCorePasserInPosition(Player* secondCorePasser)
{
auto itSnap = intendedLineup.find(secondCorePasser->GetGUID());
if (itSnap != intendedLineup.end())
@ -2488,8 +2484,7 @@ bool LadyVashjPassTheTaintedCoreAction::IsSecondCorePasserInPosition(
return false;
}
bool LadyVashjPassTheTaintedCoreAction::IsThirdCorePasserInPosition(
Player* secondCorePasser, Player* thirdCorePasser, Unit* closestTrigger)
bool LadyVashjPassTheTaintedCoreAction::IsThirdCorePasserInPosition(Player* thirdCorePasser)
{
auto itSnap = intendedLineup.find(thirdCorePasser->GetGUID());
if (itSnap != intendedLineup.end())
@ -2502,8 +2497,7 @@ bool LadyVashjPassTheTaintedCoreAction::IsThirdCorePasserInPosition(
return false;
}
bool LadyVashjPassTheTaintedCoreAction::IsFourthCorePasserInPosition(
Player* thirdCorePasser, Player* fourthCorePasser, Unit* closestTrigger)
bool LadyVashjPassTheTaintedCoreAction::IsFourthCorePasserInPosition(Player* fourthCorePasser)
{
auto itSnap = intendedLineup.find(fourthCorePasser->GetGUID());
if (itSnap != intendedLineup.end())

View File

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

View File

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

View File

@ -213,7 +213,7 @@ bool AlarAssistTanksPickUpEmbersAction::Execute(Event /*event*/)
if (!isAlarInPhase2[alar->GetMap()->GetInstanceId()])
return HandlePhase1Embers(alar);
else
return HandlePhase2Embers(alar);
return HandlePhase2Embers();
}
// 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
// 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);

View File

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

View File

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

View File

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

View File

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

View File

@ -143,7 +143,7 @@ namespace ZulAmanHelpers
// Jan'alai <Dragonhawk Avatar>
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;
std::list<Creature*> creatureList;

View File

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

View File

@ -59,6 +59,7 @@ std::list<uint32> PlayerbotFactory::specialQuestIds;
std::vector<uint32> PlayerbotFactory::enchantSpellIdCache;
std::vector<uint32> PlayerbotFactory::enchantGemIdCache;
std::unordered_map<uint32, std::vector<uint32>> PlayerbotFactory::trainerIdCache;
std::vector<uint32> PlayerbotFactory::ccBreakTrinketCache;
bool PlayerbotFactory::IsPrimaryTradeSkill(uint16 skillId)
{
@ -460,6 +461,69 @@ void PlayerbotFactory::Init()
enchantGemIdCache.push_back(gemId);
}
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()
@ -561,9 +625,9 @@ void PlayerbotFactory::Randomize(bool incremental)
if (!incremental || !sPlayerbotAIConfig.equipmentPersistence ||
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)
{
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;
uint8 cls = bot->getClass();
@ -1427,7 +1491,14 @@ void PlayerbotFactory::InitTalentsTree(bool increment /*false*/, bool use_templa
if (bot->GetFreeTalentPoints())
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);
return sPlayerbotAIConfig.randomClassSpecIndex[cls][specTab];
}
void PlayerbotFactory::InitTalentsBySpecNo(Player* bot, int specNo, bool reset)
@ -1505,7 +1576,15 @@ void PlayerbotFactory::InitTalentsBySpecNo(Player* bot, int specNo, bool reset)
break;
}
}
if (bot->getClass() == CLASS_SHAMAN && bot->HasSpell(30798))
{
bot->SetSkill(SKILL_DUAL_WIELD, 0, 1, 1);
bot->SetCanDualWield(true);
}
bot->SendTalentsInfoData(false);
sRandomPlayerbotMgr.SetValue(bot->GetGUID().GetCounter(), "specNo", (uint32)specNo + 1);
}
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();
int32 delta = std::min(blevel, 10u);
bool isPvp = sRandomPlayerbotMgr.IsSpecPvp(bot->GetGUID().GetCounter(), bot->getClass());
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)
{
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))
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);
if (second_chance && oldItem)
@ -2037,6 +2148,28 @@ void PlayerbotFactory::InitEquipment(bool incremental, bool second_chance)
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;
if (urand(0, 100) < 100 * sPlayerbotAIConfig.randomGearLoweringChance && desiredQuality > ITEM_QUALITY_NORMAL)
desiredQuality--;
@ -2054,6 +2187,7 @@ void PlayerbotFactory::InitEquipment(bool incremental, bool second_chance)
if (urand(1, 100) <= skipProb)
continue;
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemId);
// disable next expansion gear
if (sPlayerbotAIConfig.limitGearExpansion && bot->GetLevel() <= 60 && itemId >= 23728)
continue;
@ -2064,7 +2198,6 @@ void PlayerbotFactory::InitEquipment(bool incremental, bool second_chance)
// wearable TBC items above 35570 but nothing of significance
continue;
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemId);
if (!proto)
continue;
@ -2115,7 +2248,15 @@ void PlayerbotFactory::InitEquipment(bool incremental, bool second_chance)
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)
{
// delay heavy check to here
@ -2141,7 +2282,7 @@ void PlayerbotFactory::InitEquipment(bool incremental, bool second_chance)
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)
continue;
}
@ -2194,7 +2335,14 @@ void PlayerbotFactory::InitEquipment(bool incremental, bool second_chance)
(slot != EQUIPMENT_SLOT_RANGED))
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);
std::vector<uint32>& ids = items[slot];
@ -2209,7 +2357,15 @@ void PlayerbotFactory::InitEquipment(bool incremental, bool second_chance)
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)
{
// delay heavy check to here
@ -2230,8 +2386,6 @@ void PlayerbotFactory::InitEquipment(bool incremental, bool second_chance)
if (!CanEquipUnseenItem(slot, dest, bestItemForSlot))
continue;
Item* newItem = bot->EquipNewItem(dest, bestItemForSlot, true);
bot->EquipNewItem(dest, bestItemForSlot, true);
bot->AutoUnequipOffhandIfNeed();
}
@ -2393,7 +2547,7 @@ void PlayerbotFactory::InitBags(bool destroyOld)
if (old_bag)
continue;
Item* newItem = bot->EquipNewItem(dest, newItemId, true);
bot->EquipNewItem(dest, newItemId, true);
// if (newItem)
// {
// newItem->AddToWorld();
@ -4729,7 +4883,7 @@ void PlayerbotFactory::ApplyEnchantTemplate(uint8 spec)
// 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.
//float bestGemScore[4] = {0, 0, 0, 0}; //not used, line marked for removal.

View File

@ -63,7 +63,7 @@ public:
static uint32 tradeSkills[];
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 InitTalentsByParsedSpecLink(Player* bot, std::vector<std::vector<uint32>> parsedSpecLink, bool reset);
void InitAvailableSpells();
@ -88,6 +88,7 @@ public:
void InitKeyring();
void InitReputation();
void InitAttunementQuests();
void InitGuild();
private:
enum class ProfessionSpecializationSpell : uint32
@ -189,6 +190,8 @@ private:
std::vector<uint32> GetCurrentGemsCount();
bool CanEquipArmor(ItemTemplate const* proto);
bool CanEquipWeapon(ItemTemplate const* proto);
static void BuildCcBreakTrinketCache();
uint8 GetPreferredArmorType(uint8 cls);
void EnchantItem(Item* item);
void AddItemStats(uint32 mod, uint8& sp, uint8& ap, uint8& tank);
bool CheckItemStats(uint8 sp, uint8 ap, uint8 tank);
@ -199,7 +202,6 @@ private:
void InitInventoryEquip();
void InitInventorySkill();
Item* StoreItem(uint32 itemId, uint32 count);
void InitGuild();
void InitArenaTeam();
void InitImmersive();
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::vector<uint32> enchantSpellIdCache;
static std::vector<uint32> enchantGemIdCache;
static std::vector<uint32> ccBreakTrinketCache;
protected:
EnchantContainer m_EnchantContainer;

View File

@ -491,7 +491,7 @@ void PlayerbotAI::UpdateAIInternal([[maybe_unused]] uint32 elapsed, bool minimal
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);
}
@ -867,6 +867,7 @@ void PlayerbotAI::Reset(bool full)
aiObjectContext->GetValue<Unit*>("current target")->Set(nullptr);
aiObjectContext->GetValue<GuidVector>("prioritized targets")->Reset();
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<LootObject>("loot target")->Set(LootObject());
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*>("enemy player target")->Set(nullptr);
aiObjectContext->GetValue<ObjectGuid>("pull target")->Set(ObjectGuid::Empty);
aiObjectContext->GetValue<ObjectGuid>("pull strategy target")->Set(ObjectGuid::Empty);
aiObjectContext->GetValue<LootObject>("loot target")->Set(LootObject());
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;
}
void PlayerbotAI::ResetStrategies(bool load)
void PlayerbotAI::ResetStrategies(bool /*load*/)
{
for (uint8 i = 0; i < BOT_STATE_MAX; i++)
engines[i]->removeAllStrategies();

View File

@ -1667,7 +1667,7 @@ void PlayerbotMgr::TellError(std::string const botName, std::string const text)
errors[text] = names;
}
void PlayerbotMgr::CheckTellErrors(uint32 elapsed)
void PlayerbotMgr::CheckTellErrors(uint32 /*elapsed*/)
{
time_t now = time(nullptr);
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)
totalPmo->finish();
@ -2266,6 +2266,16 @@ CachedEvent* RandomPlayerbotMgr::FindEvent(uint32 bot, std::string const& event)
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)
{
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)
{
bot->SetPlayerFlag(PLAYER_FLAGS_NO_XP_GAIN);

View File

@ -140,6 +140,7 @@ public:
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(Player* bot, std::string const& type, uint32 value, std::string const& data = "");
bool IsSpecPvp(uint32 bot, uint8 cls);
void Remove(Player* bot);
ObjectGuid GetBattleMasterGUID(Player* bot, BattlegroundTypeId bgTypeId);
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)));
}
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;
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()
{
for (auto it = _guildCache.begin(); it != _guildCache.end();)
{
GuildCache& cached = it->second;
cached.memberCount = 0;
cached.faction = 2;
cached.status = 0;
}
_guildCache.clear();
for (auto& nameEntry : _guildNames)
nameEntry.second = true;
}
void PlayerbotGuildMgr::LoadGuildNames()

View File

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

View File

@ -176,7 +176,7 @@ RandomItemMgr::~RandomItemMgr()
predicates.clear();
}
bool RandomItemMgr::HandleConsoleCommand(ChatHandler* handler, char const* args)
bool RandomItemMgr::HandleConsoleCommand(ChatHandler* /*handler*/, char const* 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,
uint32 itemId, uint32 amount)
uint32 itemId, uint32 /*amount*/)
{
std::vector<uint32> listItems;
if (!player)

View File

@ -25,6 +25,10 @@ namespace
constexpr uint32 SPELL_MOLTEN_ARMOR_RANK_1 = 30482;
constexpr uint32 SPELL_MOLTEN_ARMOR_RANK_2 = 43045;
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)
@ -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);
@ -107,10 +111,12 @@ float StatsWeightCalculator::CalculateItem(uint32 itemId, int32 randomPropertyId
weight_ *= PlayerbotFactory::CalcMixedGearScore(lvl, ITEM_QUALITY_EPIC);
else
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_;
}
@ -208,6 +214,7 @@ void StatsWeightCalculator::GenerateBasicWeights(Player* player)
stats_weights_[STATS_TYPE_HIT] += 1.7f;
stats_weights_[STATS_TYPE_CRIT] += 1.4f;
stats_weights_[STATS_TYPE_HASTE] += 1.6f;
stats_weights_[STATS_TYPE_SPELL_POWER] -= 1.0f;
stats_weights_[STATS_TYPE_RANGED_DPS] += 7.5f;
}
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_CRIT] += 2.0f;
stats_weights_[STATS_TYPE_HASTE] += 1.8f;
stats_weights_[STATS_TYPE_SPELL_POWER] -= 1.0f;
stats_weights_[STATS_TYPE_RANGED_DPS] += 10.0f;
}
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_CRIT] += 1.4f;
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_MELEE_DPS] += 7.0f;
}
@ -253,64 +262,69 @@ void StatsWeightCalculator::GenerateBasicWeights(Player* player)
stats_weights_[STATS_TYPE_HIT] += 2.1f;
stats_weights_[STATS_TYPE_CRIT] += 1.1f;
stats_weights_[STATS_TYPE_HASTE] += 1.8f;
stats_weights_[STATS_TYPE_SPELL_POWER] -= 1.0f;
stats_weights_[STATS_TYPE_EXPERTISE] += 2.1f;
stats_weights_[STATS_TYPE_MELEE_DPS] += 5.0f;
}
else if (cls == CLASS_WARRIOR && tab == WARRIOR_TAB_FURY)
{
stats_weights_[STATS_TYPE_AGILITY] += 1.8f;
stats_weights_[STATS_TYPE_STRENGTH] += 2.6f;
stats_weights_[STATS_TYPE_ATTACK_POWER] += 1.0f;
stats_weights_[STATS_TYPE_AGILITY] += 0.8f;
stats_weights_[STATS_TYPE_STRENGTH] += 2.5f;
stats_weights_[STATS_TYPE_ATTACK_POWER] += 0.8f;
stats_weights_[STATS_TYPE_ARMOR_PENETRATION] += 2.1f;
stats_weights_[STATS_TYPE_HIT] += 2.3f;
stats_weights_[STATS_TYPE_CRIT] += 2.2f;
stats_weights_[STATS_TYPE_HASTE] += 1.8f;
stats_weights_[STATS_TYPE_HASTE] += 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_MELEE_DPS] += 7.0f;
}
else if (cls == CLASS_WARRIOR && tab == WARRIOR_TAB_ARMS)
{
stats_weights_[STATS_TYPE_AGILITY] += 1.6f;
stats_weights_[STATS_TYPE_STRENGTH] += 2.3f;
stats_weights_[STATS_TYPE_ATTACK_POWER] += 1.0f;
stats_weights_[STATS_TYPE_AGILITY] += 0.8f;
stats_weights_[STATS_TYPE_STRENGTH] += 2.5f;
stats_weights_[STATS_TYPE_ATTACK_POWER] += 0.8f;
stats_weights_[STATS_TYPE_ARMOR_PENETRATION] += 1.7f;
stats_weights_[STATS_TYPE_HIT] += 2.0f;
stats_weights_[STATS_TYPE_CRIT] += 1.9f;
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_MELEE_DPS] += 7.0f;
}
else if (cls == CLASS_DEATH_KNIGHT && tab == DEATH_KNIGHT_TAB_FROST)
{
stats_weights_[STATS_TYPE_AGILITY] += 1.7f;
stats_weights_[STATS_TYPE_STRENGTH] += 2.8f;
stats_weights_[STATS_TYPE_ATTACK_POWER] += 1.0f;
stats_weights_[STATS_TYPE_AGILITY] += 0.5f;
stats_weights_[STATS_TYPE_STRENGTH] += 2.5f;
stats_weights_[STATS_TYPE_ATTACK_POWER] += 0.5f;
stats_weights_[STATS_TYPE_ARMOR_PENETRATION] += 2.7f;
stats_weights_[STATS_TYPE_HIT] += 2.3f;
stats_weights_[STATS_TYPE_CRIT] += 2.2f;
stats_weights_[STATS_TYPE_HASTE] += 2.1f;
stats_weights_[STATS_TYPE_SPELL_POWER] -= 1.0f;
stats_weights_[STATS_TYPE_EXPERTISE] += 2.5f;
stats_weights_[STATS_TYPE_MELEE_DPS] += 7.0f;
}
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_ATTACK_POWER] += 1.0f;
stats_weights_[STATS_TYPE_ATTACK_POWER] += 0.5f;
stats_weights_[STATS_TYPE_ARMOR_PENETRATION] += 1.3f;
stats_weights_[STATS_TYPE_HIT] += 2.2f;
stats_weights_[STATS_TYPE_CRIT] += 1.7f;
stats_weights_[STATS_TYPE_HASTE] += 1.8f;
stats_weights_[STATS_TYPE_SPELL_POWER] -= 1.0f;
stats_weights_[STATS_TYPE_EXPERTISE] += 1.5f;
stats_weights_[STATS_TYPE_MELEE_DPS] += 5.0f;
}
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_INTELLECT] += 0.1f;
stats_weights_[STATS_TYPE_ATTACK_POWER] += 1.0f;
stats_weights_[STATS_TYPE_SPELL_POWER] += 0.3f;
stats_weights_[STATS_TYPE_ATTACK_POWER] += 0.5f;
stats_weights_[STATS_TYPE_ARMOR_PENETRATION] += 1.5f;
stats_weights_[STATS_TYPE_HIT] += 1.9f;
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_INTELLECT] += 0.3f;
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_HIT] += 2.1f;
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_CRIT] += 0.8f;
stats_weights_[STATS_TYPE_HASTE] += 1.0f;
stats_weights_[STATS_TYPE_ATTACK_POWER] -= 1.0f;
stats_weights_[STATS_TYPE_RANGED_DPS] += 1.0f;
}
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_CRIT] += 1.1f;
stats_weights_[STATS_TYPE_HASTE] += 0.8f;
stats_weights_[STATS_TYPE_ATTACK_POWER] -= 1.0f;
stats_weights_[STATS_TYPE_RANGED_DPS] += 1.0f;
}
else if (cls == CLASS_SHAMAN && tab == SHAMAN_TAB_ELEMENTAL)
{
stats_weights_[STATS_TYPE_INTELLECT] += 0.25f;
stats_weights_[STATS_TYPE_SPELL_POWER] += 1.0f;
stats_weights_[STATS_TYPE_INTELLECT] += 0.5f;
stats_weights_[STATS_TYPE_SPELL_POWER] += 1.2f;
stats_weights_[STATS_TYPE_HIT] += 1.1f;
stats_weights_[STATS_TYPE_CRIT] += 0.8f;
stats_weights_[STATS_TYPE_HASTE] += 1.0f;
stats_weights_[STATS_TYPE_MANA_REGENERATION] += 0.5f;
}
else if ((cls == CLASS_PALADIN && tab == PALADIN_TAB_HOLY) ||
(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_CRIT] += 0.6f;
stats_weights_[STATS_TYPE_HASTE] += 0.8f;
stats_weights_[STATS_TYPE_ATTACK_POWER] -= 1.0f;
stats_weights_[STATS_TYPE_RANGED_DPS] += 1.0f;
}
else if ((cls == CLASS_WARRIOR && tab == WARRIOR_TAB_PROTECTION) ||
(cls == CLASS_PALADIN && tab == PALADIN_TAB_PROTECTION))
{
stats_weights_[STATS_TYPE_AGILITY] += 2.0f;
stats_weights_[STATS_TYPE_STRENGTH] += 1.0f;
stats_weights_[STATS_TYPE_STAMINA] += 3.5f;
stats_weights_[STATS_TYPE_AGILITY] += 0.2f;
stats_weights_[STATS_TYPE_STRENGTH] += 1.3f;
stats_weights_[STATS_TYPE_STAMINA] += 3.0f;
stats_weights_[STATS_TYPE_ATTACK_POWER] += 0.2f;
stats_weights_[STATS_TYPE_DEFENSE] += 2.5f;
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_ARMOR] += 0.15f;
stats_weights_[STATS_TYPE_HIT] += 2.0f;
stats_weights_[STATS_TYPE_CRIT] += 0.2f;
stats_weights_[STATS_TYPE_HASTE] += 0.5f;
stats_weights_[STATS_TYPE_SPELL_POWER] -= 2.0f;
stats_weights_[STATS_TYPE_EXPERTISE] += 3.0f;
stats_weights_[STATS_TYPE_MELEE_DPS] += 2.0f;
}
else if (cls == CLASS_DEATH_KNIGHT && tab == DEATH_KNIGHT_TAB_BLOOD)
{
stats_weights_[STATS_TYPE_AGILITY] += 2.0f;
stats_weights_[STATS_TYPE_STRENGTH] += 1.0f;
stats_weights_[STATS_TYPE_STAMINA] += 3.5f;
stats_weights_[STATS_TYPE_AGILITY] += 0.2f;
stats_weights_[STATS_TYPE_STRENGTH] += 1.3f;
stats_weights_[STATS_TYPE_STAMINA] += 3.0f;
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_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_ARMOR] += 0.15f;
stats_weights_[STATS_TYPE_HIT] += 2.0f;
stats_weights_[STATS_TYPE_CRIT] += 0.5f;
stats_weights_[STATS_TYPE_HASTE] += 0.5f;
stats_weights_[STATS_TYPE_EXPERTISE] += 3.5f;
stats_weights_[STATS_TYPE_SPELL_POWER] -= 1.0f;
stats_weights_[STATS_TYPE_EXPERTISE] += 3.0f;
stats_weights_[STATS_TYPE_MELEE_DPS] += 2.0f;
}
else
@ -467,10 +485,23 @@ void StatsWeightCalculator::GenerateAdditionalWeights(Player* player)
&& !player->HasSpell(SPELL_MOLTEN_ARMOR_RANK_2)
&& !player->HasSpell(SPELL_MOLTEN_ARMOR_RANK_3))
{
stats_weights_[STATS_TYPE_INTELLECT] += 0.2f;
stats_weights_[STATS_TYPE_SPIRIT] -= 0.0f;
if (tab != MAGE_TAB_FIRE)
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)
@ -517,7 +548,7 @@ void StatsWeightCalculator::CalculateItemSetMod(Player* player, ItemTemplate con
weight_ *= multiplier;
}
void StatsWeightCalculator::CalculateSocketBonus(Player* player, ItemTemplate const* proto)
void StatsWeightCalculator::CalculateSocketBonus(Player* /*player*/, ItemTemplate const* proto)
{
uint32 socketNum = 0;
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() &&
player_->CanDualWield()) ||
(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;
}
@ -580,11 +612,16 @@ void StatsWeightCalculator::CalculateItemTypePenalty(ItemTemplate const* proto)
weight_ *= 0.1;
}
// 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 ||
(cls == CLASS_SHAMAN && !player_->CanDualWield()))
if ((cls == CLASS_MAGE || cls == CLASS_PRIEST || cls == CLASS_WARLOCK || cls == CLASS_DRUID ||
(cls == CLASS_SHAMAN && !player_->CanDualWield())) &&
!(cls == CLASS_PALADIN && tab == PALADIN_TAB_HOLY))
{
weight_ *= 0.65;
}
if (cls == CLASS_PALADIN && tab == PALADIN_TAB_HOLY)
{
weight_ *= 0.8;
}
}
// fury with titan's grip
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:
StatsWeightCalculator(Player* player);
void Reset();
float CalculateItem(uint32 itemId, int32 randomPropertyId = 0);
float CalculateItem(uint32 itemId, int32 randomPropertyId = 0, int32 slot = -1);
float CalculateEnchant(uint32 enchantId);
void SetOverflowPenalty(bool apply) { enable_overflow_penalty_ = apply; }
void SetItemSetBonus(bool apply) { enable_item_set_bonus_ = apply; }
void SetQualityBlend(bool apply) { enable_quality_blend_ = apply; }
void SetPvpSpec(bool isPvp) { pvpSpec_ = isPvp; }
void SetExcludeResilience(bool exclude) { exclude_resilience_ = exclude; }
private:
void GenerateWeights(Player* player);
@ -45,6 +47,7 @@ public:
void CalculateSocketBonus(Player* player, ItemTemplate const* proto);
void CalculateItemTypePenalty(ItemTemplate const* proto);
float ApplyPreferredSpecWeapons(ItemTemplate const* proto, int32 slot);
bool NotBestArmorType(uint32 item_subclass_armor);
@ -65,6 +68,8 @@ private:
float weight_;
float stats_weights_[STATS_TYPE_MAX];
bool pvpSpec_ = false;
bool exclude_resilience_ = false;
};
#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.
void TalentSpec::ApplyTalents(Player* bot, std::ostringstream* out)
void TalentSpec::ApplyTalents(Player* bot, std::ostringstream* /*out*/)
{
for (auto& entry : talents)
{
@ -397,7 +397,7 @@ uint32 TalentSpec::highestTree()
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.

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