mirror of
https://github.com/liyunfan1223/mod-playerbots.git
synced 2026-06-20 15:39:25 +02:00
commit
da3237fa78
@ -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
|
||||
|
||||
#
|
||||
#
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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 == "?")
|
||||
{
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -80,7 +80,7 @@ bool FollowChatShortcutAction::Execute(Event /*event*/)
|
||||
true, priority);
|
||||
}
|
||||
|
||||
if (Pet* pet = bot->GetPet())
|
||||
if (bot->GetPet())
|
||||
botAI->PetFollow();
|
||||
|
||||
if (moved)
|
||||
|
||||
@ -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.
|
||||
}
|
||||
|
||||
@ -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,19 +120,15 @@ 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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -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,9 +168,11 @@ 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
|
||||
{
|
||||
if (isGreen)
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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"));
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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(); }
|
||||
|
||||
@ -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())
|
||||
{
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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*/ {},
|
||||
|
||||
@ -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*/)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@ -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) {}
|
||||
|
||||
@ -12,6 +12,6 @@ std::vector<NextAction> FollowMasterStrategy::getDefaultActions()
|
||||
};
|
||||
}
|
||||
|
||||
void FollowMasterStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
void FollowMasterStrategy::InitTriggers(std::vector<TriggerNode*>& /*triggers*/)
|
||||
{
|
||||
}
|
||||
|
||||
@ -12,4 +12,4 @@ std::vector<NextAction> GuardStrategy::getDefaultActions()
|
||||
};
|
||||
}
|
||||
|
||||
void GuardStrategy::InitTriggers(std::vector<TriggerNode*>& triggers) {}
|
||||
void GuardStrategy::InitTriggers(std::vector<TriggerNode*>& /*triggers*/) {}
|
||||
|
||||
@ -13,7 +13,7 @@ void MaintenanceStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode(
|
||||
"random",
|
||||
"seldom",
|
||||
{
|
||||
NextAction("clean quest log", 6.0f)
|
||||
}
|
||||
|
||||
@ -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*/)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -7,4 +7,4 @@
|
||||
|
||||
RTSCStrategy::RTSCStrategy(PlayerbotAI* botAI) : Strategy(botAI) {}
|
||||
|
||||
void RTSCStrategy::InitTriggers(std::vector<TriggerNode*>& triggers) {}
|
||||
void RTSCStrategy::InitTriggers(std::vector<TriggerNode*>& /*triggers*/) {}
|
||||
|
||||
@ -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*/ {},
|
||||
|
||||
@ -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*/ {},
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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))
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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())
|
||||
{
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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"; }
|
||||
};
|
||||
|
||||
@ -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; }
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -40,12 +40,12 @@ 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))
|
||||
if (Item* item = AI_VALUE2(Item*, "item for spell", spellid);
|
||||
item && item->IsInWorld() && item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -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())
|
||||
{
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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); }
|
||||
|
||||
@ -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*/)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@ -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*/) {}
|
||||
|
||||
@ -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());
|
||||
}
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -41,6 +41,6 @@ std::vector<NextAction> TankWarlockStrategy::getDefaultActions()
|
||||
};
|
||||
}
|
||||
|
||||
void TankWarlockStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
void TankWarlockStrategy::InitTriggers(std::vector<TriggerNode*>& /*triggers*/)
|
||||
{
|
||||
}
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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*/)
|
||||
{
|
||||
}
|
||||
|
||||
@ -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)))
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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");
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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) &&
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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())
|
||||
|
||||
@ -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);
|
||||
};
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -66,7 +66,7 @@ public:
|
||||
|
||||
private:
|
||||
bool HandlePhase1Embers(Unit* alar);
|
||||
bool HandlePhase2Embers(Unit* alar);
|
||||
bool HandlePhase2Embers();
|
||||
};
|
||||
|
||||
class AlarRangedDpsPrioritizeEmbersAction : public AttackAction
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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) ||
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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 ---");
|
||||
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -325,9 +325,6 @@ public:
|
||||
FindMountVisitor(Player* bot) : FindUsableItemVisitor(bot) {}
|
||||
|
||||
bool Accept(ItemTemplate const* proto) override;
|
||||
|
||||
private:
|
||||
uint32 effectId;
|
||||
};
|
||||
|
||||
class FindPetVisitor : public FindUsableItemVisitor
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
Loading…
x
Reference in New Issue
Block a user