Merge branch 'master' into master

This commit is contained in:
Bobblybook
2024-12-15 23:47:38 +11:00
committed by GitHub
23 changed files with 204 additions and 50 deletions

View File

@@ -67,7 +67,7 @@
################################### ###################################
# # # #
# GENERAL SETTINGS # # GENERAL SETTINGS #
# # # #
################################### ###################################
@@ -368,6 +368,10 @@ AiPlayerbot.SyncQuestWithPlayer = 1
# Default: 0 (disabled) # Default: 0 (disabled)
AiPlayerbot.SyncQuestForPlayer = 0 AiPlayerbot.SyncQuestForPlayer = 0
# Bots will drop obsolete quests
# Default: 1 (enabled)
AiPlayerbot.DropObsoleteQuests = 1
# #
# #
# #
@@ -1022,6 +1026,56 @@ AiPlayerbot.PremadeSpecLink.11.3.80 = -553202032322010053100030310511-205503012
# #
################################################################################################### ###################################################################################################
###################################
# #
# WORLD BUFFS #
# #
###################################
####################################################################################################
#
#
#
# Applies a permanent buff to all bots when not in combat simulating flasks, food, rune etc.
# WorldBuff.Faction.Class.Spec.MinLevel.MaxLevel
AiPlayerbot.WorldBuff.0.1.0.80.80 = 53760,57358 #WARRIOR ARMS
AiPlayerbot.WorldBuff.0.1.1.80.80 = 53760,57358 #WARRIOR FURY
AiPlayerbot.WorldBuff.0.1.2.80.80 = 53758,57356 #WARRIOR PROTECTION
AiPlayerbot.WorldBuff.0.2.0.80.80 = 60347,53749,57332 #PALADIN HOLY
AiPlayerbot.WorldBuff.0.2.1.80.80 = 53758,57356 #PALADIN PROTECTION
AiPlayerbot.WorldBuff.0.2.2.80.80 = 53760,57371 #PALADIN RETRIBUTION
AiPlayerbot.WorldBuff.0.3.0.80.80 = 53760,57325 #HUNTER BEAST
AiPlayerbot.WorldBuff.0.3.1.80.80 = 53760,57358 #HUNTER MARKSMANSHIP
AiPlayerbot.WorldBuff.0.3.2.80.80 = 53760,57367 #HUNTER SURVIVAL
AiPlayerbot.WorldBuff.0.4.0.80.80 = 53760,57325 #ROGUE ASSASINATION
AiPlayerbot.WorldBuff.0.4.1.80.80 = 53760,57358 #ROGUE COMBAT
AiPlayerbot.WorldBuff.0.4.2.80.80 = 53760,57367 #ROGUE SUBTLETY
AiPlayerbot.WorldBuff.0.5.0.80.80 = 53755,57327 #PRIEST DISCIPLINE
AiPlayerbot.WorldBuff.0.5.1.80.80 = 53755,57327 #PRIEST HOLY
AiPlayerbot.WorldBuff.0.5.2.80.80 = 53755,57327 #PRIEST SHADOW
AiPlayerbot.WorldBuff.0.6.0.80.80 = 53758,57356 #DEATH KNIGHT BLOOD
AiPlayerbot.WorldBuff.0.6.1.80.80 = 53760,57358 #DEATH KNIGHT FROST
AiPlayerbot.WorldBuff.0.6.2.80.80 = 53760,57358 #DEATH KNIGHT UNHOLY
AiPlayerbot.WorldBuff.0.7.0.80.80 = 53755,57327 #SHAMAN ELEMENTAL
AiPlayerbot.WorldBuff.0.7.1.80.80 = 53760,57325 #SHAMAN ENHANCEMENT
AiPlayerbot.WorldBuff.0.7.2.80.80 = 53755,57327 #SHAMAN RESTORATION
AiPlayerbot.WorldBuff.0.8.0.80.80 = 53755,57327 #MAGE ARCANE
AiPlayerbot.WorldBuff.0.8.1.80.80 = 53755,57327 #MAGE FIRE
AiPlayerbot.WorldBuff.0.8.2.80.80 = 53755,57327 #MAGE FROST
AiPlayerbot.WorldBuff.0.9.0.80.80 = 53755,57327 #WARLOCK AFFLICTION
AiPlayerbot.WorldBuff.0.9.1.80.80 = 53755,57327 #WARLOCK DEMONOLOGY
AiPlayerbot.WorldBuff.0.9.2.80.80 = 53755,57327 #WARLOCK DESTRUCTION
AiPlayerbot.WorldBuff.0.11.0.80.80 = 53755,57327 #DRUID BALANCE
AiPlayerbot.WorldBuff.0.11.1.80.80 = 53749,53763,57367 #DRUID FERAL
AiPlayerbot.WorldBuff.0.11.2.80.80 = 54212,57334 #DRUID RESTORATION
#
#
#
###################################################################################################
################################### ###################################
# # # #
# RANDOM BOT DEFAULT TALENT SPEC # # RANDOM BOT DEFAULT TALENT SPEC #
@@ -1411,9 +1465,6 @@ AiPlayerbot.BroadcastChanceGuildManagement = 30000
# Example: AiPlayerbot.AllowedLogFiles = travelNodes.csv,travelPaths.csv,TravelNodeStore.h,bot_movement.csv,bot_location.csv # Example: AiPlayerbot.AllowedLogFiles = travelNodes.csv,travelPaths.csv,TravelNodeStore.h,bot_movement.csv,bot_location.csv
AiPlayerbot.AllowedLogFiles = "" AiPlayerbot.AllowedLogFiles = ""
Appender.Playerbots=2,5,0,Playerbots.log,w
Logger.playerbots=5,Console Playerbots
# #
# #
# #

View File

@@ -5478,10 +5478,10 @@ bool PlayerbotAI::CanMove()
if (IsInVehicle() && !IsInVehicle(true)) if (IsInVehicle() && !IsInVehicle(true))
return false; return false;
if (bot->isFrozen() || bot->IsPolymorphed() || (bot->isDead() && !bot->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST)) || if (bot->isFrozen() || bot->IsPolymorphed() || (bot->isDead() && !bot->HasPlayerFlag(PLAYER_FLAGS_GHOST)) ||
bot->IsBeingTeleported() || bot->isInRoots() || bot->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION) || bot->IsBeingTeleported() || bot->HasRootAura() || bot->HasSpiritOfRedemptionAura() ||
bot->HasAuraType(SPELL_AURA_MOD_CONFUSE) || bot->IsCharmed() || bot->HasAuraType(SPELL_AURA_MOD_STUN) || bot->HasConfuseAura() || bot->IsCharmed() || bot->HasStunAura() ||
bot->HasUnitState(UNIT_STATE_IN_FLIGHT) || bot->HasUnitState(UNIT_STATE_LOST_CONTROL)) bot->IsInFlight() || bot->HasUnitState(UNIT_STATE_LOST_CONTROL))
return false; return false;
return bot->GetMotionMaster()->GetCurrentMovementGeneratorType() != FLIGHT_MOTION_TYPE; return bot->GetMotionMaster()->GetCurrentMovementGeneratorType() != FLIGHT_MOTION_TYPE;

View File

@@ -403,11 +403,14 @@ bool PlayerbotAIConfig::Initialize()
{ {
for (uint32 classId = 0; classId < MAX_CLASSES; classId++) for (uint32 classId = 0; classId < MAX_CLASSES; classId++)
{ {
for (uint32 minLevel = 0; minLevel < MAX_LEVEL; minLevel++) for (uint32 specId = 0; specId < MAX_SPECNO; specId++)
{ {
for (uint32 maxLevel = 0; maxLevel < MAX_LEVEL; maxLevel++) for (uint32 minLevel = 0; minLevel < MAX_LEVEL; minLevel++)
{ {
loadWorldBuf(factionId, classId, minLevel, maxLevel); for (uint32 maxLevel = 0; maxLevel < MAX_LEVEL; maxLevel++)
{
loadWorldBuf(factionId, classId, specId, minLevel, maxLevel);
}
} }
} }
} }
@@ -491,6 +494,7 @@ bool PlayerbotAIConfig::Initialize()
twoRoundsGearInit = sConfigMgr->GetOption<bool>("AiPlayerbot.TwoRoundsGearInit", false); twoRoundsGearInit = sConfigMgr->GetOption<bool>("AiPlayerbot.TwoRoundsGearInit", false);
syncQuestWithPlayer = sConfigMgr->GetOption<bool>("AiPlayerbot.SyncQuestWithPlayer", true); syncQuestWithPlayer = sConfigMgr->GetOption<bool>("AiPlayerbot.SyncQuestWithPlayer", true);
syncQuestForPlayer = sConfigMgr->GetOption<bool>("AiPlayerbot.SyncQuestForPlayer", false); syncQuestForPlayer = sConfigMgr->GetOption<bool>("AiPlayerbot.SyncQuestForPlayer", false);
dropObsoleteQuests = sConfigMgr->GetOption<bool>("AiPlayerbot.DropObsoleteQuests", true);
autoTrainSpells = sConfigMgr->GetOption<std::string>("AiPlayerbot.AutoTrainSpells", "yes"); autoTrainSpells = sConfigMgr->GetOption<std::string>("AiPlayerbot.AutoTrainSpells", "yes");
autoPickTalents = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoPickTalents", true); autoPickTalents = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoPickTalents", true);
autoUpgradeEquip = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoUpgradeEquip", false); autoUpgradeEquip = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoUpgradeEquip", false);
@@ -644,36 +648,50 @@ void PlayerbotAIConfig::log(std::string const fileName, char const* str, ...)
fflush(stdout); fflush(stdout);
} }
void PlayerbotAIConfig::loadWorldBuf(uint32 factionId1, uint32 classId1, uint32 minLevel1, uint32 maxLevel1) void PlayerbotAIConfig::loadWorldBuf(uint32 factionId1, uint32 classId1, uint32 specId1, uint32 minLevel1, uint32 maxLevel1)
{ {
std::vector<uint32> buffs; std::vector<uint32> buffs;
std::ostringstream os; std::ostringstream os;
os << "AiPlayerbot.WorldBuff." << factionId1 << "." << classId1 << "." << minLevel1 << "." << maxLevel1; os << "AiPlayerbot.WorldBuff." << factionId1 << "." << classId1 << "." << specId1 << "." << minLevel1 << "." << maxLevel1;
LoadList<std::vector<uint32>>(sConfigMgr->GetOption<std::string>(os.str().c_str(), "", false), buffs); LoadList<std::vector<uint32>>(sConfigMgr->GetOption<std::string>(os.str().c_str(), "", false), buffs);
for (auto buff : buffs) for (auto buff : buffs)
{ {
worldBuff wb = {buff, factionId1, classId1, minLevel1, maxLevel1}; worldBuff wb = {buff, factionId1, classId1, specId1, minLevel1, maxLevel1};
worldBuffs.push_back(wb); worldBuffs.push_back(wb);
} }
if (maxLevel1 == 0) if (maxLevel1 == 0)
{ {
std::ostringstream os; std::ostringstream os;
os << "AiPlayerbot.WorldBuff." << factionId1 << "." << classId1 << "." << minLevel1; os << "AiPlayerbot.WorldBuff." << factionId1 << "." << classId1 << "." << specId1 << "." << minLevel1;
LoadList<std::vector<uint32>>(sConfigMgr->GetOption<std::string>(os.str().c_str(), "", false), buffs); LoadList<std::vector<uint32>>(sConfigMgr->GetOption<std::string>(os.str().c_str(), "", false), buffs);
for (auto buff : buffs) for (auto buff : buffs)
{ {
worldBuff wb = {buff, factionId1, classId1, minLevel1, maxLevel1}; worldBuff wb = {buff, factionId1, classId1, specId1, minLevel1, maxLevel1};
worldBuffs.push_back(wb); worldBuffs.push_back(wb);
} }
} }
if (maxLevel1 == 0 && minLevel1 == 0) if (maxLevel1 == 0 && minLevel1 == 0)
{
std::ostringstream os;
os << "AiPlayerbot.WorldBuff." << factionId1 << "." << factionId1 << "." << classId1 << "." << specId1;
LoadList<std::vector<uint32>>(sConfigMgr->GetOption<std::string>(os.str().c_str(), "", false), buffs);
for (auto buff : buffs)
{
worldBuff wb = {buff, factionId1, classId1, specId1, minLevel1, maxLevel1};
worldBuffs.push_back(wb);
}
}
if (maxLevel1 == 0 && minLevel1 == 0 && specId1 == 0)
{ {
std::ostringstream os; std::ostringstream os;
os << "AiPlayerbot.WorldBuff." << factionId1 << "." << factionId1 << "." << classId1; os << "AiPlayerbot.WorldBuff." << factionId1 << "." << factionId1 << "." << classId1;
@@ -682,12 +700,12 @@ void PlayerbotAIConfig::loadWorldBuf(uint32 factionId1, uint32 classId1, uint32
for (auto buff : buffs) for (auto buff : buffs)
{ {
worldBuff wb = {buff, factionId1, classId1, minLevel1, maxLevel1}; worldBuff wb = {buff, factionId1, classId1, specId1, minLevel1, maxLevel1};
worldBuffs.push_back(wb); worldBuffs.push_back(wb);
} }
} }
if (classId1 == 0 && maxLevel1 == 0 && minLevel1 == 0) if (classId1 == 0 && maxLevel1 == 0 && minLevel1 == 0 && specId1 == 0)
{ {
std::ostringstream os; std::ostringstream os;
os << "AiPlayerbot.WorldBuff." << factionId1; os << "AiPlayerbot.WorldBuff." << factionId1;
@@ -696,12 +714,12 @@ void PlayerbotAIConfig::loadWorldBuf(uint32 factionId1, uint32 classId1, uint32
for (auto buff : buffs) for (auto buff : buffs)
{ {
worldBuff wb = {buff, factionId1, classId1, minLevel1, maxLevel1}; worldBuff wb = {buff, factionId1, classId1, specId1, minLevel1, maxLevel1};
worldBuffs.push_back(wb); worldBuffs.push_back(wb);
} }
} }
if (factionId1 == 0 && classId1 == 0 && maxLevel1 == 0 && minLevel1 == 0) if (factionId1 == 0 && classId1 == 0 && maxLevel1 == 0 && minLevel1 == 0 && specId1 == 0)
{ {
std::ostringstream os; std::ostringstream os;
os << "AiPlayerbot.WorldBuff"; os << "AiPlayerbot.WorldBuff";
@@ -710,7 +728,7 @@ void PlayerbotAIConfig::loadWorldBuf(uint32 factionId1, uint32 classId1, uint32
for (auto buff : buffs) for (auto buff : buffs)
{ {
worldBuff wb = {buff, factionId1, classId1, minLevel1, maxLevel1}; worldBuff wb = {buff, factionId1, classId1, specId1, minLevel1, maxLevel1};
worldBuffs.push_back(wb); worldBuffs.push_back(wb);
} }
} }

View File

@@ -247,6 +247,7 @@ public:
uint32 spellId; uint32 spellId;
uint32 factionId = 0; uint32 factionId = 0;
uint32 classId = 0; uint32 classId = 0;
uint32 specId = 0;
uint32 minLevel = 0; uint32 minLevel = 0;
uint32 maxLevel = 0; uint32 maxLevel = 0;
}; };
@@ -275,6 +276,7 @@ public:
bool twoRoundsGearInit; bool twoRoundsGearInit;
bool syncQuestWithPlayer; bool syncQuestWithPlayer;
bool syncQuestForPlayer; bool syncQuestForPlayer;
bool dropObsoleteQuests;
std::string autoTrainSpells; std::string autoTrainSpells;
bool autoPickTalents; bool autoPickTalents;
bool autoUpgradeEquip; bool autoUpgradeEquip;
@@ -327,7 +329,7 @@ public:
} }
void log(std::string const fileName, const char* str, ...); void log(std::string const fileName, const char* str, ...);
void loadWorldBuf(uint32 factionId, uint32 classId, uint32 minLevel, uint32 maxLevel); void loadWorldBuf(uint32 factionId, uint32 classId, uint32 specId, uint32 minLevel, uint32 maxLevel);
static std::vector<std::vector<uint32>> ParseTempTalentsOrder(uint32 cls, std::string temp_talents_order); static std::vector<std::vector<uint32>> ParseTempTalentsOrder(uint32 cls, std::string temp_talents_order);
static std::vector<std::vector<uint32>> ParseTempPetTalentsOrder(uint32 spec, std::string temp_talents_order); static std::vector<std::vector<uint32>> ParseTempPetTalentsOrder(uint32 spec, std::string temp_talents_order);
}; };

View File

@@ -958,9 +958,17 @@ std::vector<std::string> PlayerbotHolder::HandlePlayerbotCommand(char const* arg
if (!strcmp(cmd, "reload")) if (!strcmp(cmd, "reload"))
{ {
messages.push_back("Reloading config"); if (master->GetSession()->GetSecurity() >= SEC_GAMEMASTER)
sPlayerbotAIConfig->Initialize(); {
return messages; sPlayerbotAIConfig->Initialize();
messages.push_back("Config reloaded.");
return messages;
}
else
{
messages.push_back("ERROR: Only GM can use this command.");
return messages;
}
} }
if (!strcmp(cmd, "tweak")) if (!strcmp(cmd, "tweak"))

View File

@@ -52,7 +52,7 @@ public:
void OnDatabaseSelectIndexLogout(Player* player, uint32& statementIndex, uint32& statementParam) override void OnDatabaseSelectIndexLogout(Player* player, uint32& statementIndex, uint32& statementParam) override
{ {
statementIndex = CHAR_UPD_CHAR_ONLINE; statementIndex = CHAR_UPD_CHAR_OFFLINE;
statementParam = player->GetGUID().GetCounter(); statementParam = player->GetGUID().GetCounter();
} }

View File

@@ -165,6 +165,13 @@ RandomPlayerbotMgr::RandomPlayerbotMgr() : PlayerbotHolder(), processTicks(0)
} }
BattlegroundData.clear(); BattlegroundData.clear();
for (int bracket = BG_BRACKET_ID_FIRST; bracket < MAX_BATTLEGROUND_BRACKETS; ++bracket)
{
for (int queueType = BATTLEGROUND_QUEUE_AV; queueType < MAX_BATTLEGROUND_QUEUE_TYPES; ++queueType)
{
BattlegroundData[queueType][bracket] = BattlegroundInfo();
}
}
BgCheckTimer = 0; BgCheckTimer = 0;
LfgCheckTimer = 0; LfgCheckTimer = 0;
PlayersCheckTimer = 0; PlayersCheckTimer = 0;
@@ -341,19 +348,19 @@ void RandomPlayerbotMgr::UpdateAIInternal(uint32 elapsed, bool /*minimal*/)
if (sPlayerbotAIConfig->syncLevelWithPlayers && !players.empty()) if (sPlayerbotAIConfig->syncLevelWithPlayers && !players.empty())
{ {
if (time(nullptr) > (PlayersCheckTimer + 60)) if (time(nullptr) > (PlayersCheckTimer + 60))
activateCheckPlayersThread(); sRandomPlayerbotMgr->CheckPlayers();
} }
if (sPlayerbotAIConfig->randomBotJoinBG /* && !players.empty()*/) if (sPlayerbotAIConfig->randomBotJoinBG /* && !players.empty()*/)
{ {
if (time(nullptr) > (BgCheckTimer + 30)) if (time(nullptr) > (BgCheckTimer + 30))
activateCheckBgQueueThread(); sRandomPlayerbotMgr->CheckBgQueue();
} }
if (sPlayerbotAIConfig->randomBotJoinLfg /* && !players.empty()*/) if (sPlayerbotAIConfig->randomBotJoinLfg /* && !players.empty()*/)
{ {
if (time(nullptr) > (LfgCheckTimer + 30)) if (time(nullptr) > (LfgCheckTimer + 30))
activateCheckLfgQueueThread(); sRandomPlayerbotMgr->CheckLfgQueue();
} }
uint32 updateBots = sPlayerbotAIConfig->randomBotsPerInterval * onlineBotFocus / 100; uint32 updateBots = sPlayerbotAIConfig->randomBotsPerInterval * onlineBotFocus / 100;
@@ -594,6 +601,14 @@ void RandomPlayerbotMgr::CheckBgQueue()
BattlegroundData.clear(); BattlegroundData.clear();
for (int bracket = BG_BRACKET_ID_FIRST; bracket < MAX_BATTLEGROUND_BRACKETS; ++bracket)
{
for (int queueType = BATTLEGROUND_QUEUE_AV; queueType < MAX_BATTLEGROUND_QUEUE_TYPES; ++queueType)
{
BattlegroundData[queueType][bracket] = BattlegroundInfo();
}
}
for (Player* player : players) for (Player* player : players)
{ {
if (!player->InBattlegroundQueue()) if (!player->InBattlegroundQueue())
@@ -840,7 +855,8 @@ void RandomPlayerbotMgr::LogBattlegroundInfo()
for (const auto& bracketIdPair : queueTypePair.second) for (const auto& bracketIdPair : queueTypePair.second)
{ {
auto& bgInfo = bracketIdPair.second; auto& bgInfo = bracketIdPair.second;
if (bgInfo.minLevel == 0)
continue;
LOG_INFO("playerbots", LOG_INFO("playerbots",
"ARENA:{} {}: Player (Skirmish:{}, Rated:{}) Bots (Skirmish:{}, Rated:{}) Total (Skirmish:{} " "ARENA:{} {}: Player (Skirmish:{}, Rated:{}) Bots (Skirmish:{}, Rated:{}) Total (Skirmish:{} "
"Rated:{}), Instances (Skirmish:{} Rated:{})", "Rated:{}), Instances (Skirmish:{} Rated:{})",
@@ -889,6 +905,8 @@ void RandomPlayerbotMgr::LogBattlegroundInfo()
for (const auto& bracketIdPair : queueTypePair.second) for (const auto& bracketIdPair : queueTypePair.second)
{ {
auto& bgInfo = bracketIdPair.second; auto& bgInfo = bracketIdPair.second;
if (bgInfo.minLevel == 0)
continue;
LOG_INFO("playerbots", "BG:{} {}: Player ({}:{}) Bot ({}:{}) Total (A:{} H:{}), Instances {}", _bgType, LOG_INFO("playerbots", "BG:{} {}: Player ({}:{}) Bot ({}:{}) Total (A:{} H:{}), Instances {}", _bgType,
std::to_string(bgInfo.minLevel) + "-" + std::to_string(bgInfo.maxLevel), std::to_string(bgInfo.minLevel) + "-" + std::to_string(bgInfo.maxLevel),

View File

@@ -10,8 +10,8 @@
#include "LootObjectStack.h" #include "LootObjectStack.h"
#include "Playerbots.h" #include "Playerbots.h"
#include "PossibleRpgTargetsValue.h" #include "PossibleRpgTargetsValue.h"
#include "ServerFacade.h"
#include "PvpTriggers.h" #include "PvpTriggers.h"
#include "ServerFacade.h"
bool AttackEnemyPlayerAction::isUseful() bool AttackEnemyPlayerAction::isUseful()
{ {
@@ -129,3 +129,33 @@ bool DpsAssistAction::isUseful()
return true; return true;
} }
bool AttackRtiTargetAction::Execute(Event event)
{
Unit* rtiTarget = AI_VALUE(Unit*, "rti target");
if (rtiTarget && rtiTarget->IsInWorld() && rtiTarget->GetMapId() == bot->GetMapId())
{
botAI->GetAiObjectContext()->GetValue<GuidVector>("prioritized targets")->Set({rtiTarget->GetGUID()});
bool result = Attack(botAI->GetUnit(rtiTarget->GetGUID()));
if (result)
{
context->GetValue<ObjectGuid>("pull target")->Set(rtiTarget->GetGUID());
return true;
}
}
else
{
botAI->TellError("I dont see my rti attack target");
}
return false;
}
bool AttackRtiTargetAction::isUseful()
{
if (botAI->ContainsStrategy(STRATEGY_TYPE_HEAL))
return false;
return true;
}

View File

@@ -69,6 +69,8 @@ public:
AttackRtiTargetAction(PlayerbotAI* botAI) : AttackAction(botAI, "attack rti target") {} AttackRtiTargetAction(PlayerbotAI* botAI) : AttackAction(botAI, "attack rti target") {}
std::string const GetTargetName() override { return "rti target"; } std::string const GetTargetName() override { return "rti target"; }
bool Execute(Event event) override;
bool isUseful() override;
}; };
class AttackEnemyFlagCarrierAction : public AttackAction class AttackEnemyFlagCarrierAction : public AttackAction

View File

@@ -68,6 +68,11 @@ bool CleanQuestLogAction::Execute(Event event)
return false; return false;
} }
if (!sPlayerbotAIConfig->dropObsoleteQuests)
{
return false;
}
// Only output this message if "debug rpg" strategy is enabled // Only output this message if "debug rpg" strategy is enabled
if (botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT)) if (botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT))
{ {

View File

@@ -923,10 +923,10 @@ bool MovementAction::IsMovingAllowed()
if (botAI->IsInVehicle() && !botAI->IsInVehicle(true)) if (botAI->IsInVehicle() && !botAI->IsInVehicle(true))
return false; return false;
if (bot->isFrozen() || bot->IsPolymorphed() || (bot->isDead() && !bot->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST)) || if (bot->isFrozen() || bot->IsPolymorphed() || (bot->isDead() && !bot->HasPlayerFlag(PLAYER_FLAGS_GHOST)) ||
bot->IsBeingTeleported() || bot->isInRoots() || bot->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION) || bot->IsBeingTeleported() || bot->HasRootAura() || bot->HasSpiritOfRedemptionAura() ||
bot->HasAuraType(SPELL_AURA_MOD_CONFUSE) || bot->IsCharmed() || bot->HasAuraType(SPELL_AURA_MOD_STUN) || bot->HasConfuseAura() || bot->IsCharmed() || bot->HasStunAura() ||
bot->HasUnitState(UNIT_STATE_IN_FLIGHT) || bot->HasUnitState(UNIT_STATE_LOST_CONTROL)) bot->IsInFlight() || bot->HasUnitState(UNIT_STATE_LOST_CONTROL))
return false; return false;
if (bot->GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_CONTROLLED) != NULL_MOTION_TYPE) if (bot->GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_CONTROLLED) != NULL_MOTION_TYPE)
@@ -2537,9 +2537,9 @@ bool SetFacingTargetAction::isUseful() { return !AI_VALUE2(bool, "facing", "curr
bool SetFacingTargetAction::isPossible() bool SetFacingTargetAction::isPossible()
{ {
if (bot->isFrozen() || bot->IsPolymorphed() || (bot->isDead() && !bot->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST)) || if (bot->isFrozen() || bot->IsPolymorphed() || (bot->isDead() && !bot->HasPlayerFlag(PLAYER_FLAGS_GHOST)) ||
bot->IsBeingTeleported() || bot->HasAuraType(SPELL_AURA_MOD_CONFUSE) || bot->IsCharmed() || bot->IsBeingTeleported() || bot->HasConfuseAura() || bot->IsCharmed() ||
bot->HasAuraType(SPELL_AURA_MOD_STUN) || bot->HasUnitState(UNIT_STATE_IN_FLIGHT) || bot->HasStunAura() || bot->IsInFlight() ||
bot->HasUnitState(UNIT_STATE_LOST_CONTROL)) bot->HasUnitState(UNIT_STATE_LOST_CONTROL))
return false; return false;

View File

@@ -22,7 +22,7 @@ bool ReleaseSpiritAction::Execute(Event event)
return false; return false;
} }
if (bot->GetCorpse() && bot->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST)) if (bot->GetCorpse() && bot->HasPlayerFlag(PLAYER_FLAGS_GHOST))
{ {
botAI->TellMasterNoFacing("I am already a spirit"); botAI->TellMasterNoFacing("I am already a spirit");
return false; return false;
@@ -149,7 +149,7 @@ bool AutoReleaseSpiritAction::isUseful()
if (bot->InBattleground()) if (bot->InBattleground())
return true; return true;
if (bot->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST)) if (bot->HasPlayerFlag(PLAYER_FLAGS_GHOST))
return false; return false;
if (!bot->GetGroup()) if (!bot->GetGroup())

View File

@@ -360,4 +360,4 @@ bool SpiritHealerAction::Execute(Event event)
return false; return false;
} }
bool SpiritHealerAction::isUseful() { return bot->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST); } bool SpiritHealerAction::isUseful() { return bot->HasPlayerFlag(PLAYER_FLAGS_GHOST); }

View File

@@ -80,7 +80,7 @@ bool MarkRtiAction::Execute(Event event)
for (uint8 i = 0; i < 8; i++) for (uint8 i = 0; i < 8; i++)
{ {
ObjectGuid iconGUID = group->GetTargetIcon(i); ObjectGuid iconGUID = group->GetTargetIcon(i);
if (guid == unit->GetGUID()) if (iconGUID == unit->GetGUID())
{ {
marked = true; marked = true;
break; break;

View File

@@ -5,6 +5,7 @@
#include "WorldBuffAction.h" #include "WorldBuffAction.h"
#include "AiFactory.h"
#include "Event.h" #include "Event.h"
#include "Playerbots.h" #include "Playerbots.h"
@@ -39,6 +40,11 @@ std::vector<uint32> WorldBuffAction::NeedWorldBuffs(Unit* unit)
if (wb.classId != 0 && wb.classId != unit->getClass()) if (wb.classId != 0 && wb.classId != unit->getClass())
continue; continue;
uint8 tab = AiFactory::GetPlayerSpecTab(unit->ToPlayer());
if (wb.specId != tab)
continue;
if (wb.minLevel != 0 && wb.minLevel > unit->GetLevel()) if (wb.minLevel != 0 && wb.minLevel > unit->GetLevel())
continue; continue;

View File

@@ -25,4 +25,8 @@ bool PartyMemberNeedCureTrigger::IsActive()
return target && target->IsInWorld(); return target && target->IsInWorld();
} }
bool NeedWorldBuffTrigger::IsActive() { return !WorldBuffAction::NeedWorldBuffs(bot).empty(); } bool NeedWorldBuffTrigger::IsActive()
{
std::any_of(WorldBuffAction::NeedWorldBuffs(bot).begin(), WorldBuffAction::NeedWorldBuffs(bot).end(),
[](const auto& wb) { return true; });
}

View File

@@ -175,7 +175,7 @@ bool AttackersValue::IsPossibleTarget(Unit* attacker, Player* bot, float range)
// !((attacker->IsPolymorphed() || botAI->HasAura("sap", attacker) || /*attacker->IsCharmed() ||*/ // !((attacker->IsPolymorphed() || botAI->HasAura("sap", attacker) || /*attacker->IsCharmed() ||*/
// attacker->isFeared()) && !rti) && // attacker->isFeared()) && !rti) &&
/*!sServerFacade->IsInRoots(attacker) &&*/ /*!sServerFacade->IsInRoots(attacker) &&*/
!attacker->IsFriendlyTo(bot) && !attacker->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION) && !attacker->IsFriendlyTo(bot) && !attacker->HasSpiritOfRedemptionAura() &&
// !(attacker->GetGUID().IsPet() && enemy) && // !(attacker->GetGUID().IsPet() && enemy) &&
!(attacker->GetCreatureType() == CREATURE_TYPE_CRITTER && !attacker->IsInCombat()) && !(attacker->GetCreatureType() == CREATURE_TYPE_CRITTER && !attacker->IsInCombat()) &&
!attacker->HasUnitFlag(UNIT_FLAG_IMMUNE_TO_PC) && !attacker->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE) && !attacker->HasUnitFlag(UNIT_FLAG_IMMUNE_TO_PC) && !attacker->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE) &&

View File

@@ -18,7 +18,7 @@ bool NearestEnemyPlayersValue::AcceptUnit(Unit* unit)
!enemy->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NON_ATTACKABLE_2) && !enemy->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NON_ATTACKABLE_2) &&
((inCannon || !enemy->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE))) && ((inCannon || !enemy->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE))) &&
/*!enemy->HasStealthAura() && !enemy->HasInvisibilityAura()*/ enemy->CanSeeOrDetect(bot) && /*!enemy->HasStealthAura() && !enemy->HasInvisibilityAura()*/ enemy->CanSeeOrDetect(bot) &&
!(enemy->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION))) !(enemy->HasSpiritOfRedemptionAura()))
return true; return true;
return false; return false;

View File

@@ -21,7 +21,7 @@ bool InvalidTargetValue::Calculate()
return target->GetMapId() != bot->GetMapId() || target->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE) || return target->GetMapId() != bot->GetMapId() || target->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE) ||
target->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE) || target->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE_2) || target->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE) || target->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE_2) ||
!target->IsVisible() || !target->IsAlive() || target->IsPolymorphed() || target->IsCharmed() || !target->IsVisible() || !target->IsAlive() || target->IsPolymorphed() || target->IsCharmed() ||
target->isFeared() || target->HasUnitState(UNIT_STATE_ISOLATED) || target->IsFriendlyTo(bot) || target->HasFearAura() || target->HasUnitState(UNIT_STATE_ISOLATED) || target->IsFriendlyTo(bot) ||
!AttackersValue::IsValidTarget(target, bot); !AttackersValue::IsValidTarget(target, bot);
} }

View File

@@ -48,9 +48,6 @@ Unit* RtiTargetValue::Calculate()
if (!guid) if (!guid)
return nullptr; return nullptr;
if (!bot->IsInCombat())
return nullptr;
//////////////////////////////////////////////////////begin: delete below check //////////////////////////////////////////////////////begin: delete below check
// Some units that need to be killed in battle are not on the list of attackers, // Some units that need to be killed in battle are not on the list of attackers,
// such as the Kor'kron Battle-Mage in Icecrown Citadel. // such as the Kor'kron Battle-Mage in Icecrown Citadel.

View File

@@ -23,3 +23,5 @@ bool CastFearOnCcAction::isPossible() { return botAI->CanCastSpell("fear", GetTa
bool CastFearOnCcAction::isUseful() { return true; } bool CastFearOnCcAction::isUseful() { return true; }
bool CastLifeTapAction::isUseful() { return AI_VALUE2(uint8, "health", "self target") > sPlayerbotAIConfig->lowHealth; } bool CastLifeTapAction::isUseful() { return AI_VALUE2(uint8, "health", "self target") > sPlayerbotAIConfig->lowHealth; }
Unit* UseSoulstoneAction::GetTarget() { return botAI->GetMaster(); }

View File

@@ -7,6 +7,7 @@
#define _PLAYERBOT_WARLOCKACTIONS_H #define _PLAYERBOT_WARLOCKACTIONS_H
#include "GenericSpellActions.h" #include "GenericSpellActions.h"
#include "UseItemAction.h"
class PlayerbotAI; class PlayerbotAI;
class Unit; class Unit;
@@ -302,4 +303,12 @@ class CastIncinerateAction : public CastSpellAction
public: public:
CastIncinerateAction(PlayerbotAI* ai) : CastSpellAction(ai, "incinerate") {} CastIncinerateAction(PlayerbotAI* ai) : CastSpellAction(ai, "incinerate") {}
}; };
class UseSoulstoneAction : public UseSpellItemAction
{
public:
UseSoulstoneAction(PlayerbotAI* ai) : UseSpellItemAction(ai, "soulstone") {}
Unit* GetTarget() override;
};
#endif #endif

View File

@@ -184,6 +184,7 @@ public:
creators["metamorphosis"] = &WarlockAiObjectContextInternal::metamorphosis; creators["metamorphosis"] = &WarlockAiObjectContextInternal::metamorphosis;
creators["soul fire"] = &WarlockAiObjectContextInternal::soul_fire; creators["soul fire"] = &WarlockAiObjectContextInternal::soul_fire;
creators["incinerate"] = &WarlockAiObjectContextInternal::incinerate; creators["incinerate"] = &WarlockAiObjectContextInternal::incinerate;
creators["soulstone"] = &WarlockAiObjectContextInternal::soulstone;
} }
private: private:
@@ -239,6 +240,7 @@ private:
static Action* metamorphosis(PlayerbotAI* ai) { return new CastMetamorphosisAction(ai); } static Action* metamorphosis(PlayerbotAI* ai) { return new CastMetamorphosisAction(ai); }
static Action* soul_fire(PlayerbotAI* ai) { return new CastSoulFireAction(ai); } static Action* soul_fire(PlayerbotAI* ai) { return new CastSoulFireAction(ai); }
static Action* incinerate(PlayerbotAI* ai) { return new CastIncinerateAction(ai); } static Action* incinerate(PlayerbotAI* ai) { return new CastIncinerateAction(ai); }
static Action* soulstone(PlayerbotAI* ai) { return new UseSoulstoneAction(ai); }
}; };
WarlockAiObjectContext::WarlockAiObjectContext(PlayerbotAI* botAI) : AiObjectContext(botAI) WarlockAiObjectContext::WarlockAiObjectContext(PlayerbotAI* botAI) : AiObjectContext(botAI)