mirror of
https://github.com/mod-playerbots/mod-playerbots
synced 2025-11-29 15:58:20 +08:00
Merge branch 'master' of https://github.com/Bobblybook/mod-playerbots
This commit is contained in:
@@ -304,9 +304,13 @@ ItemIds ChatHelper::parseItems(std::string const text)
|
||||
|
||||
std::string const ChatHelper::FormatQuest(Quest const* quest)
|
||||
{
|
||||
if (!quest)
|
||||
{
|
||||
return "Invalid quest";
|
||||
}
|
||||
|
||||
std::ostringstream out;
|
||||
out << "|cFFFFFF00|Hquest:" << quest->GetQuestId() << ':' << quest->GetQuestLevel() << "|h[" << quest->GetTitle()
|
||||
<< "]|h|r";
|
||||
out << "|cFFFFFF00|Hquest:" << quest->GetQuestId() << ':' << quest->GetQuestLevel() << "|h[" << quest->GetTitle() << "]|h|r";
|
||||
return out.str();
|
||||
}
|
||||
|
||||
|
||||
@@ -239,6 +239,7 @@ void PlayerbotAI::UpdateAI(uint32 elapsed, bool minimal)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// if (!GetMaster() || !GetMaster()->IsInWorld() || !GetMaster()->GetSession() ||
|
||||
// GetMaster()->GetSession()->isLogingOut()) {
|
||||
// return;
|
||||
@@ -301,6 +302,7 @@ void PlayerbotAI::UpdateAI(uint32 elapsed, bool minimal)
|
||||
// bot->GetMotionMaster()->Clear();
|
||||
// bot->GetMotionMaster()->MoveIdle();
|
||||
// }
|
||||
|
||||
// cheat options
|
||||
if (bot->IsAlive() && ((uint32)GetCheat() > 0 || (uint32)sPlayerbotAIConfig->botCheatMask > 0))
|
||||
{
|
||||
@@ -3926,7 +3928,10 @@ Player* PlayerbotAI::GetGroupMaster()
|
||||
|
||||
uint32 PlayerbotAI::GetFixedBotNumer(BotTypeNumber typeNumber, uint32 maxNum, float cyclePerMin)
|
||||
{
|
||||
uint32 randseed = rand32(); // Seed random number
|
||||
//deterministic seed
|
||||
uint8 seedNumber = uint8(typeNumber);
|
||||
std::mt19937 rng(seedNumber);
|
||||
uint32 randseed = rng(); // Seed random number
|
||||
uint32 randnum = bot->GetGUID().GetCounter() + randseed; // Semi-random but fixed number for each bot.
|
||||
|
||||
if (cyclePerMin > 0)
|
||||
@@ -3936,8 +3941,7 @@ uint32 PlayerbotAI::GetFixedBotNumer(BotTypeNumber typeNumber, uint32 maxNum, fl
|
||||
randnum += cycle; // Make the random number cylce.
|
||||
}
|
||||
|
||||
randnum =
|
||||
(randnum % (maxNum + 1)); // Loops the randomnumber at maxNum. Bassically removes all the numbers above 99.
|
||||
randnum = (randnum % (maxNum + 1)); // Loops the randomnumber at maxNum. Bassically removes all the numbers above 99.
|
||||
return randnum; // Now we have a number unique for each bot between 0 and maxNum that increases by cyclePerMin.
|
||||
}
|
||||
|
||||
@@ -4075,18 +4079,15 @@ inline bool HasRealPlayers(Map* map)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PlayerbotAI::AllowActive(ActivityType activityType)
|
||||
ActivePiorityType PlayerbotAI::GetPriorityType(ActivityType activityType)
|
||||
{
|
||||
// General exceptions
|
||||
if (activityType == PACKET_ACTIVITY)
|
||||
return true;
|
||||
// First priority - priorities disabled or has player master. Always active.
|
||||
if (HasRealPlayerMaster())
|
||||
return ActivePiorityType::HAS_REAL_PLAYER_MASTER;
|
||||
|
||||
if (GetMaster()) // Has player master. Always active.
|
||||
{
|
||||
PlayerbotAI* masterBotAI = GET_PLAYERBOT_AI(GetMaster());
|
||||
if (!masterBotAI || masterBotAI->IsRealPlayer())
|
||||
return true;
|
||||
}
|
||||
// Self bot in a group with a bot master.
|
||||
if (IsRealPlayer())
|
||||
return ActivePiorityType::IS_REAL_PLAYER;
|
||||
|
||||
Group* group = bot->GetGroup();
|
||||
if (group)
|
||||
@@ -4100,21 +4101,49 @@ bool PlayerbotAI::AllowActive(ActivityType activityType)
|
||||
if (member == bot)
|
||||
continue;
|
||||
|
||||
//IN_GROUP_WITH_REAL_PLAYER
|
||||
PlayerbotAI* memberBotAI = GET_PLAYERBOT_AI(member);
|
||||
if (!memberBotAI || memberBotAI->HasRealPlayerMaster())
|
||||
return true;
|
||||
return ActivePiorityType::IN_GROUP_WITH_REAL_PLAYER;
|
||||
|
||||
//IN_GROUP_WITH_REAL_PLAYER
|
||||
if (group->IsLeader(member->GetGUID()))
|
||||
{
|
||||
if (!memberBotAI->AllowActivity(PARTY_ACTIVITY))
|
||||
return false;
|
||||
return ActivePiorityType::IN_GROUP_WITH_REAL_PLAYER;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!WorldPosition(bot).isOverworld()) // bg, raid, dungeon
|
||||
return true;
|
||||
//IN_INSTANCE
|
||||
if (bot->IsBeingTeleported()) // Allow activity while teleportation.
|
||||
return ActivePiorityType::IN_INSTANCE;
|
||||
|
||||
if (bot->InBattlegroundQueue()) // In bg queue. Speed up bg queue/join.
|
||||
return true;
|
||||
//IN_INSTANCE
|
||||
if (!WorldPosition(bot).isOverworld())
|
||||
return ActivePiorityType::IN_INSTANCE;
|
||||
|
||||
//VISIBLE_FOR_PLAYER
|
||||
if (HasPlayerNearby(sPlayerbotAIConfig->reactDistance))
|
||||
return ActivePiorityType::VISIBLE_FOR_PLAYER;
|
||||
|
||||
//IN_COMBAT
|
||||
if (activityType != OUT_OF_PARTY_ACTIVITY && activityType != PACKET_ACTIVITY)
|
||||
{
|
||||
// Is in combat, defend yourself.
|
||||
if (bot->IsInCombat())
|
||||
return ActivePiorityType::IN_COMBAT;
|
||||
}
|
||||
|
||||
//NEARBY_PLAYER
|
||||
if (HasPlayerNearby(300.f))
|
||||
return ActivePiorityType::NEARBY_PLAYER;
|
||||
|
||||
//if (sPlayerbotAIConfig->IsFreeAltBot(bot) || HasStrategy("travel once", BotState::BOT_STATE_NON_COMBAT))
|
||||
// return ActivePiorityType::IS_ALWAYS_ACTIVE;
|
||||
|
||||
if (bot->InBattlegroundQueue())
|
||||
return ActivePiorityType::IN_BG_QUEUE;
|
||||
|
||||
bool isLFG = false;
|
||||
if (group)
|
||||
@@ -4124,62 +4153,172 @@ bool PlayerbotAI::AllowActive(ActivityType activityType)
|
||||
isLFG = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (sLFGMgr->GetState(bot->GetGUID()) != lfg::LFG_STATE_NONE)
|
||||
{
|
||||
isLFG = true;
|
||||
}
|
||||
|
||||
if (isLFG)
|
||||
return true;
|
||||
return ActivePiorityType::IN_LFG;
|
||||
|
||||
if (activityType != OUT_OF_PARTY_ACTIVITY && activityType != PACKET_ACTIVITY) // Is in combat. Defend yourself.
|
||||
if (bot->IsInCombat())
|
||||
return true;
|
||||
//IN_EMPTY_SERVER
|
||||
if (sRandomPlayerbotMgr->GetPlayers().empty())
|
||||
return ActivePiorityType::IN_EMPTY_SERVER;
|
||||
|
||||
if (HasPlayerNearby(300.f)) // Player is near. Always active.
|
||||
return true;
|
||||
|
||||
// friends always active
|
||||
|
||||
// HasFriend sometimes cause crash, disable
|
||||
// for (auto& player : sRandomPlayerbotMgr->GetPlayers())
|
||||
// {
|
||||
// if (!player || !player->IsInWorld())
|
||||
// continue;
|
||||
|
||||
// if (player->GetSocial()->HasFriend(bot->GetGUID()))
|
||||
// return true;
|
||||
// }
|
||||
|
||||
if (activityType == OUT_OF_PARTY_ACTIVITY ||
|
||||
activityType == GRIND_ACTIVITY) // Many bots nearby. Do not do heavy area checks.
|
||||
if (HasManyPlayersNearby())
|
||||
return false;
|
||||
|
||||
// Bots don't need to move using PathGenerator.
|
||||
if (activityType == DETAILED_MOVE_ACTIVITY)
|
||||
return false;
|
||||
|
||||
// All exceptions are now done.
|
||||
// Below is code to have a specified % of bots active at all times.
|
||||
// The default is 10%. With 0.1% of all bots going active or inactive each minute.
|
||||
if (sPlayerbotAIConfig->botActiveAlone <= 0)
|
||||
return false;
|
||||
|
||||
uint32 mod = sPlayerbotAIConfig->botActiveAlone > 100 ? 100 : sPlayerbotAIConfig->botActiveAlone;
|
||||
if (sPlayerbotAIConfig->botActiveAloneAutoScale)
|
||||
//PLAYER_FRIEND (on friendlist of real player) (needs to be tested for stability)
|
||||
/*for (auto& player : sRandomPlayerbotMgr->GetPlayers())
|
||||
{
|
||||
mod = AutoScaleActivity(mod);
|
||||
if (!player || !player->IsInWorld())
|
||||
continue;
|
||||
|
||||
if (player->GetSocial() &&
|
||||
bot->GetGUID() &&
|
||||
player->GetSocial()->HasFriend(bot->GetGUID()))
|
||||
return ActivePiorityType::PLAYER_FRIEND;
|
||||
}*/
|
||||
|
||||
//PLAYER_GUILD (contains real player)
|
||||
if (IsInRealGuild())
|
||||
return ActivePiorityType::PLAYER_GUILD;
|
||||
|
||||
//IN_INACTIVE_MAP
|
||||
if (bot->IsBeingTeleported() || !bot->IsInWorld() || !HasRealPlayers(bot->GetMap()))
|
||||
return ActivePiorityType::IN_INACTIVE_MAP;
|
||||
|
||||
//IN_ACTIVE_MAP
|
||||
if (!bot->IsBeingTeleported() && bot->IsInWorld() && HasRealPlayers(bot->GetMap()))
|
||||
return ActivePiorityType::IN_ACTIVE_MAP;
|
||||
|
||||
// IN_ACTIVE_AREA
|
||||
if (activityType == OUT_OF_PARTY_ACTIVITY || activityType == GRIND_ACTIVITY)
|
||||
{
|
||||
if (HasManyPlayersNearby(20, sPlayerbotAIConfig->sightDistance))
|
||||
return ActivePiorityType::IN_ACTIVE_AREA;
|
||||
}
|
||||
|
||||
uint32 ActivityNumber =
|
||||
GetFixedBotNumer(BotTypeNumber::ACTIVITY_TYPE_NUMBER, 100,
|
||||
sPlayerbotAIConfig->botActiveAlone * static_cast<float>(mod) / 100 * 0.01f);
|
||||
return ActivePiorityType::IN_ACTIVE_AREA;
|
||||
}
|
||||
|
||||
return ActivityNumber <=
|
||||
(sPlayerbotAIConfig->botActiveAlone * mod) /
|
||||
100; // The given percentage of bots should be active and rotate 1% of those active bots each minute.
|
||||
// Returns the lower and upper bracket for bots to be active.
|
||||
// Ie. { 10, 20 } means all bots in this bracket will be inactive below 10% activityMod,
|
||||
// and will be active above 20% activityMod and scale between those values.
|
||||
std::pair<uint32, uint32> PlayerbotAI::GetPriorityBracket(ActivePiorityType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ActivePiorityType::HAS_REAL_PLAYER_MASTER:
|
||||
case ActivePiorityType::IS_REAL_PLAYER:
|
||||
case ActivePiorityType::IN_GROUP_WITH_REAL_PLAYER:
|
||||
case ActivePiorityType::IN_INSTANCE:
|
||||
case ActivePiorityType::VISIBLE_FOR_PLAYER:
|
||||
return {0, 0};
|
||||
case ActivePiorityType::IS_ALWAYS_ACTIVE:
|
||||
case ActivePiorityType::IN_COMBAT:
|
||||
return {0, 10};
|
||||
case ActivePiorityType::IN_BG_QUEUE:
|
||||
return {0, 20};
|
||||
case ActivePiorityType::IN_LFG:
|
||||
return {0, 30};
|
||||
case ActivePiorityType::NEARBY_PLAYER:
|
||||
return {0, 40};
|
||||
case ActivePiorityType::PLAYER_FRIEND:
|
||||
case ActivePiorityType::PLAYER_GUILD:
|
||||
return {0, 50};
|
||||
case ActivePiorityType::IN_ACTIVE_AREA:
|
||||
case ActivePiorityType::IN_EMPTY_SERVER:
|
||||
return {50, 100};
|
||||
case ActivePiorityType::IN_ACTIVE_MAP:
|
||||
return {70, 100};
|
||||
case ActivePiorityType::IN_INACTIVE_MAP:
|
||||
return {80, 100};
|
||||
default:
|
||||
return {90, 100};
|
||||
}
|
||||
|
||||
return {90, 100};
|
||||
}
|
||||
|
||||
bool PlayerbotAI::AllowActive(ActivityType activityType)
|
||||
{
|
||||
// General exceptions
|
||||
if (activityType == PACKET_ACTIVITY)
|
||||
return true;
|
||||
|
||||
ActivePiorityType type = GetPriorityType(activityType);
|
||||
if (activityType == DETAILED_MOVE_ACTIVITY)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ActivePiorityType::HAS_REAL_PLAYER_MASTER:
|
||||
case ActivePiorityType::IS_REAL_PLAYER:
|
||||
case ActivePiorityType::IN_GROUP_WITH_REAL_PLAYER:
|
||||
case ActivePiorityType::IN_INSTANCE:
|
||||
case ActivePiorityType::VISIBLE_FOR_PLAYER:
|
||||
case ActivePiorityType::IN_COMBAT:
|
||||
case ActivePiorityType::NEARBY_PLAYER:
|
||||
return true;
|
||||
break;
|
||||
case ActivePiorityType::IS_ALWAYS_ACTIVE:
|
||||
case ActivePiorityType::IN_BG_QUEUE:
|
||||
case ActivePiorityType::IN_LFG:
|
||||
case ActivePiorityType::PLAYER_FRIEND:
|
||||
case ActivePiorityType::PLAYER_GUILD:
|
||||
case ActivePiorityType::IN_ACTIVE_AREA:
|
||||
case ActivePiorityType::IN_EMPTY_SERVER:
|
||||
case ActivePiorityType::IN_ACTIVE_MAP:
|
||||
case ActivePiorityType::IN_INACTIVE_MAP:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (activityType == REACT_ACTIVITY)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ActivePiorityType::HAS_REAL_PLAYER_MASTER:
|
||||
case ActivePiorityType::IS_REAL_PLAYER:
|
||||
case ActivePiorityType::IN_GROUP_WITH_REAL_PLAYER:
|
||||
case ActivePiorityType::IN_INSTANCE:
|
||||
case ActivePiorityType::VISIBLE_FOR_PLAYER:
|
||||
case ActivePiorityType::IS_ALWAYS_ACTIVE:
|
||||
case ActivePiorityType::IN_COMBAT:
|
||||
return true;
|
||||
break;
|
||||
case ActivePiorityType::NEARBY_PLAYER:
|
||||
case ActivePiorityType::IN_BG_QUEUE:
|
||||
case ActivePiorityType::IN_LFG:
|
||||
case ActivePiorityType::PLAYER_FRIEND:
|
||||
case ActivePiorityType::PLAYER_GUILD:
|
||||
case ActivePiorityType::IN_ACTIVE_AREA:
|
||||
case ActivePiorityType::IN_EMPTY_SERVER:
|
||||
case ActivePiorityType::IN_ACTIVE_MAP:
|
||||
case ActivePiorityType::IN_INACTIVE_MAP:
|
||||
default:
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// GetPriorityBracket acitivity
|
||||
float normalizedBotActiveAlone = sPlayerbotAIConfig->botActiveAlone > 100 ? 100 : sPlayerbotAIConfig->botActiveAlone;
|
||||
float activePerc = normalizedBotActiveAlone;
|
||||
if (sPlayerbotAIConfig->botActiveAloneSmartScale &&
|
||||
bot->GetLevel() >= sPlayerbotAIConfig->botActiveAloneSmartScaleWhenMinLevel &&
|
||||
bot->GetLevel() <= sPlayerbotAIConfig->botActiveAloneSmartScaleWhenMaxLevel)
|
||||
{
|
||||
std::pair<uint8, uint8> priorityBracket = GetPriorityBracket(type);
|
||||
if (!priorityBracket.second) return true;
|
||||
float activityPercentage = sRandomPlayerbotMgr->getActivityPercentage();
|
||||
if (priorityBracket.first >= activityPercentage) return false;
|
||||
if (priorityBracket.second <= activityPercentage && priorityBracket.second < 100) return true;
|
||||
activePerc = (activityPercentage - priorityBracket.first) / (priorityBracket.second - priorityBracket.first);
|
||||
activePerc *= (priorityBracket.second == 100) ? normalizedBotActiveAlone : 100;
|
||||
}
|
||||
|
||||
// The last number if the amount it cycles per min. Currently set to 1% of the active bots.
|
||||
uint32 ActivityNumber = GetFixedBotNumer(BotTypeNumber::ACTIVITY_TYPE_NUMBER, 100, activePerc * 0.01f);
|
||||
|
||||
// The given percentage of bots should be active and rotate 1% of those active bots each minute.
|
||||
return ActivityNumber <= (activePerc);
|
||||
}
|
||||
|
||||
bool PlayerbotAI::AllowActivity(ActivityType activityType, bool checkNow)
|
||||
@@ -4196,31 +4335,6 @@ bool PlayerbotAI::AllowActivity(ActivityType activityType, bool checkNow)
|
||||
return allowed;
|
||||
}
|
||||
|
||||
uint32 PlayerbotAI::AutoScaleActivity(uint32 mod)
|
||||
{
|
||||
uint32 maxDiff = sWorldUpdateTime.GetAverageUpdateTime();
|
||||
|
||||
if (maxDiff > 500) return 0;
|
||||
if (maxDiff > 250)
|
||||
{
|
||||
if (Map* map = bot->GetMap())
|
||||
{
|
||||
if (map->GetEntry()->IsWorldMap() &&
|
||||
(!HasRealPlayers(map) ||
|
||||
!map->IsGridLoaded(bot->GetPositionX(), bot->GetPositionY())))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (mod * 1) / 10;
|
||||
}
|
||||
if (maxDiff > 200) return (mod * 3) / 10;
|
||||
if (maxDiff > 150) return (mod * 5) / 10;
|
||||
if (maxDiff > 100) return (mod * 6) / 10;
|
||||
if (maxDiff > 80) return (mod * 9) / 10;
|
||||
|
||||
return mod;
|
||||
}
|
||||
|
||||
bool PlayerbotAI::IsOpposing(Player* player) { return IsOpposing(player->getRace(), bot->getRace()); }
|
||||
|
||||
bool PlayerbotAI::IsOpposing(uint8 race1, uint8 race2)
|
||||
@@ -5328,15 +5442,29 @@ bool PlayerbotAI::CanMove()
|
||||
if (IsInVehicle() && !IsInVehicle(true))
|
||||
return false;
|
||||
|
||||
if (bot->isFrozen() || bot->IsPolymorphed() || (bot->isDead() && !bot->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST)) ||
|
||||
bot->IsBeingTeleported() || bot->isInRoots() || bot->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION) ||
|
||||
bot->HasAuraType(SPELL_AURA_MOD_CONFUSE) || bot->IsCharmed() || bot->HasAuraType(SPELL_AURA_MOD_STUN) ||
|
||||
bot->HasUnitState(UNIT_STATE_IN_FLIGHT) || bot->HasUnitState(UNIT_STATE_LOST_CONTROL))
|
||||
if (bot->isFrozen() ||
|
||||
bot->IsPolymorphed() ||
|
||||
(bot->isDead() && !bot->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST)) ||
|
||||
bot->IsBeingTeleported() ||
|
||||
bot->isInRoots() ||
|
||||
bot->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION) ||
|
||||
bot->HasAuraType(SPELL_AURA_MOD_CONFUSE) ||
|
||||
bot->IsCharmed() ||
|
||||
bot->HasAuraType(SPELL_AURA_MOD_STUN) ||
|
||||
bot->HasUnitState(UNIT_STATE_IN_FLIGHT) ||
|
||||
bot->HasUnitState(UNIT_STATE_LOST_CONTROL))
|
||||
|
||||
return false;
|
||||
|
||||
return bot->GetMotionMaster()->GetCurrentMovementGeneratorType() != FLIGHT_MOTION_TYPE;
|
||||
}
|
||||
|
||||
bool PlayerbotAI::IsTaxiFlying()
|
||||
{
|
||||
return bot->HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT) &&
|
||||
bot->HasUnitState(UNIT_STATE_IGNORE_PATHFINDING);
|
||||
}
|
||||
|
||||
bool PlayerbotAI::IsInRealGuild()
|
||||
{
|
||||
if (!bot->GetGuildId())
|
||||
|
||||
@@ -241,6 +241,27 @@ enum class GuilderType : uint8
|
||||
VERY_LARGE = 250
|
||||
};
|
||||
|
||||
enum class ActivePiorityType : uint8
|
||||
{
|
||||
IS_REAL_PLAYER = 0,
|
||||
HAS_REAL_PLAYER_MASTER = 1,
|
||||
IN_GROUP_WITH_REAL_PLAYER = 2,
|
||||
IN_INSTANCE = 3,
|
||||
VISIBLE_FOR_PLAYER = 4,
|
||||
IS_ALWAYS_ACTIVE = 5,
|
||||
IN_COMBAT = 6,
|
||||
IN_BG_QUEUE = 7,
|
||||
IN_LFG = 8,
|
||||
NEARBY_PLAYER = 9,
|
||||
PLAYER_FRIEND = 10,
|
||||
PLAYER_GUILD = 11,
|
||||
IN_ACTIVE_AREA = 12,
|
||||
IN_ACTIVE_MAP = 13,
|
||||
IN_INACTIVE_MAP = 14,
|
||||
IN_EMPTY_SERVER = 15,
|
||||
MAX_TYPE
|
||||
};
|
||||
|
||||
enum ActivityType
|
||||
{
|
||||
GRIND_ACTIVITY = 1,
|
||||
@@ -250,8 +271,8 @@ enum ActivityType
|
||||
PACKET_ACTIVITY = 5,
|
||||
DETAILED_MOVE_ACTIVITY = 6,
|
||||
PARTY_ACTIVITY = 7,
|
||||
ALL_ACTIVITY = 8,
|
||||
|
||||
REACT_ACTIVITY = 8,
|
||||
ALL_ACTIVITY = 9,
|
||||
MAX_ACTIVITY_TYPE
|
||||
};
|
||||
|
||||
@@ -525,9 +546,10 @@ public:
|
||||
bool HasPlayerNearby(WorldPosition* pos, float range = sPlayerbotAIConfig->reactDistance);
|
||||
bool HasPlayerNearby(float range = sPlayerbotAIConfig->reactDistance);
|
||||
bool HasManyPlayersNearby(uint32 trigerrValue = 20, float range = sPlayerbotAIConfig->sightDistance);
|
||||
ActivePiorityType GetPriorityType(ActivityType activityType);
|
||||
std::pair<uint32, uint32> GetPriorityBracket(ActivePiorityType type);
|
||||
bool AllowActive(ActivityType activityType);
|
||||
bool AllowActivity(ActivityType activityType = ALL_ACTIVITY, bool checkNow = false);
|
||||
uint32 AutoScaleActivity(uint32 mod);
|
||||
|
||||
// Check if player is safe to use.
|
||||
bool IsSafe(Player* player);
|
||||
@@ -554,6 +576,7 @@ public:
|
||||
void ResetJumpDestination() { jumpDestination = Position(); }
|
||||
|
||||
bool CanMove();
|
||||
bool IsTaxiFlying();
|
||||
bool IsInRealGuild();
|
||||
static std::vector<std::string> dispel_whitelist;
|
||||
bool EqualLowercaseName(std::string s1, std::string s2);
|
||||
|
||||
@@ -465,11 +465,15 @@ bool PlayerbotAIConfig::Initialize()
|
||||
playerbotsXPrate = sConfigMgr->GetOption<int32>("AiPlayerbot.KillXPRate", 1);
|
||||
disableDeathKnightLogin = sConfigMgr->GetOption<bool>("AiPlayerbot.DisableDeathKnightLogin", 0);
|
||||
botActiveAlone = sConfigMgr->GetOption<int32>("AiPlayerbot.BotActiveAlone", 100);
|
||||
botActiveAloneAutoScale = sConfigMgr->GetOption<bool>("AiPlayerbot.botActiveAloneAutoScale", true);
|
||||
|
||||
enablePrototypePerformanceDiff = sConfigMgr->GetOption<bool>("AiPlayerbot.EnablePrototypePerformanceDiff", false);
|
||||
diffWithPlayer = sConfigMgr->GetOption<int32>("AiPlayerbot.DiffWithPlayer", 100);
|
||||
diffEmpty = sConfigMgr->GetOption<int32>("AiPlayerbot.DiffEmpty", 200);
|
||||
botActiveAloneSmartScale = sConfigMgr->GetOption<bool>("AiPlayerbot.botActiveAloneSmartScale", 1);
|
||||
botActiveAloneSmartScaleWhenMinLevel =
|
||||
sConfigMgr->GetOption<uint32>("AiPlayerbot.botActiveAloneSmartScaleWhenMinLevel", 1);
|
||||
botActiveAloneSmartScaleWhenMaxLevel =
|
||||
sConfigMgr->GetOption<uint32>("AiPlayerbot.botActiveAloneSmartScaleWhenMaxLevel", 80);
|
||||
botActiveAloneSmartScaleDiffWithPlayer =
|
||||
sConfigMgr->GetOption<uint32>("AiPlayerbot.botActiveAloneSmartScaleDiffWithPlayer", 100);
|
||||
botActiveAloneSmartScaleDiffEmpty =
|
||||
sConfigMgr->GetOption<uint32>("AiPlayerbot.botActiveAloneSmartScaleDiffEmpty", 200);
|
||||
|
||||
randombotsWalkingRPG = sConfigMgr->GetOption<bool>("AiPlayerbot.RandombotsWalkingRPG", false);
|
||||
randombotsWalkingRPGInDoors = sConfigMgr->GetOption<bool>("AiPlayerbot.RandombotsWalkingRPG.InDoors", false);
|
||||
|
||||
@@ -263,11 +263,11 @@ public:
|
||||
uint32 playerbotsXPrate;
|
||||
bool disableDeathKnightLogin;
|
||||
uint32 botActiveAlone;
|
||||
bool botActiveAloneAutoScale;
|
||||
|
||||
uint32 enablePrototypePerformanceDiff;
|
||||
uint32 diffWithPlayer;
|
||||
uint32 diffEmpty;
|
||||
bool botActiveAloneSmartScale;
|
||||
uint32 botActiveAloneSmartScaleWhenMinLevel;
|
||||
uint32 botActiveAloneSmartScaleWhenMaxLevel;
|
||||
uint32 botActiveAloneSmartScaleDiffWithPlayer;
|
||||
uint32 botActiveAloneSmartScaleDiffEmpty;
|
||||
|
||||
bool freeMethodLoot;
|
||||
int32 lootRollLevel;
|
||||
|
||||
@@ -100,6 +100,8 @@ void PlayerbotHolder::HandlePlayerBotLoginCallback(PlayerbotLoginQueryHolder con
|
||||
Player* bot = botSession->GetPlayer();
|
||||
if (!bot)
|
||||
{
|
||||
// Log para debug
|
||||
LOG_ERROR("mod-playerbots", "Bot player could not be loaded for account ID: {}", botAccountId);
|
||||
botSession->LogoutPlayer(true);
|
||||
delete botSession;
|
||||
botLoading.erase(holder.GetGuid());
|
||||
@@ -108,6 +110,14 @@ void PlayerbotHolder::HandlePlayerBotLoginCallback(PlayerbotLoginQueryHolder con
|
||||
|
||||
uint32 masterAccount = holder.GetMasterAccountId();
|
||||
WorldSession* masterSession = masterAccount ? sWorld->FindSession(masterAccount) : nullptr;
|
||||
|
||||
// Check if masterSession->GetPlayer() is valid
|
||||
Player* masterPlayer = masterSession ? masterSession->GetPlayer() : nullptr;
|
||||
if (masterSession && !masterPlayer)
|
||||
{
|
||||
LOG_ERROR("mod-playerbots", "Master session found but no player is associated for master account ID: {}", masterAccount);
|
||||
}
|
||||
|
||||
std::ostringstream out;
|
||||
bool allowed = false;
|
||||
if (botAccountId == masterAccount)
|
||||
@@ -115,7 +125,7 @@ void PlayerbotHolder::HandlePlayerBotLoginCallback(PlayerbotLoginQueryHolder con
|
||||
allowed = true;
|
||||
}
|
||||
else if (masterSession && sPlayerbotAIConfig->allowGuildBots && bot->GetGuildId() != 0 &&
|
||||
bot->GetGuildId() == masterSession->GetPlayer()->GetGuildId())
|
||||
bot->GetGuildId() == masterPlayer->GetGuildId())
|
||||
{
|
||||
allowed = true;
|
||||
}
|
||||
@@ -129,10 +139,14 @@ void PlayerbotHolder::HandlePlayerBotLoginCallback(PlayerbotLoginQueryHolder con
|
||||
out << "Failure: You are not allowed to control bot " << bot->GetName().c_str();
|
||||
}
|
||||
|
||||
if (allowed && masterSession)
|
||||
if (allowed && masterSession && masterPlayer)
|
||||
{
|
||||
Player* player = masterSession->GetPlayer();
|
||||
PlayerbotMgr* mgr = GET_PLAYERBOT_MGR(player);
|
||||
PlayerbotMgr* mgr = GET_PLAYERBOT_MGR(masterPlayer);
|
||||
if (!mgr)
|
||||
{
|
||||
LOG_ERROR("mod-playerbots", "PlayerbotMgr not found for master player with GUID: {}", masterPlayer->GetGUID().GetRawValue());
|
||||
}
|
||||
|
||||
uint32 count = mgr->GetPlayerbotsCount();
|
||||
uint32 cls_count = mgr->GetPlayerbotsCountByClass(bot->getClass());
|
||||
if (count >= sPlayerbotAIConfig->maxAddedBots)
|
||||
@@ -428,14 +442,17 @@ void PlayerbotHolder::OnBotLogin(Player* const bot)
|
||||
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
|
||||
if (!botAI)
|
||||
{
|
||||
// Log a warning here to indicate that the botAI is null
|
||||
LOG_ERROR("mod-playerbots", "PlayerbotAI is null for bot with GUID: {}", bot->GetGUID().GetRawValue());
|
||||
return;
|
||||
}
|
||||
|
||||
Player* master = botAI->GetMaster();
|
||||
if (master)
|
||||
if (!master)
|
||||
{
|
||||
ObjectGuid masterGuid = master->GetGUID();
|
||||
if (master->GetGroup() && !master->GetGroup()->IsLeader(masterGuid))
|
||||
master->GetGroup()->ChangeLeader(masterGuid);
|
||||
// Log a warning to indicate that the master is null
|
||||
LOG_ERROR("mod-playerbots", "Master is null for bot with GUID: {}", bot->GetGUID().GetRawValue());
|
||||
return;
|
||||
}
|
||||
|
||||
Group* group = bot->GetGroup();
|
||||
|
||||
@@ -292,12 +292,8 @@ void RandomPlayerbotMgr::UpdateAIInternal(uint32 elapsed, bool /*minimal*/)
|
||||
if (!sPlayerbotAIConfig->randomBotAutologin || !sPlayerbotAIConfig->enabled)
|
||||
return;
|
||||
|
||||
if (sPlayerbotAIConfig->enablePrototypePerformanceDiff)
|
||||
if (sPlayerbotAIConfig->botActiveAloneSmartScale)
|
||||
{
|
||||
LOG_INFO("playerbots", "---------------------------------------");
|
||||
LOG_INFO("playerbots",
|
||||
"PROTOTYPE: Playerbot performance enhancements are active. Issues and instability may occur.");
|
||||
LOG_INFO("playerbots", "---------------------------------------");
|
||||
ScaleBotActivity();
|
||||
}
|
||||
|
||||
@@ -414,8 +410,9 @@ void RandomPlayerbotMgr::ScaleBotActivity()
|
||||
// max/min activity
|
||||
|
||||
// % increase/decrease wanted diff , avg diff
|
||||
float activityPercentageMod = pid.calculate(
|
||||
sRandomPlayerbotMgr->GetPlayers().empty() ? sPlayerbotAIConfig->diffEmpty : sPlayerbotAIConfig->diffWithPlayer,
|
||||
float activityPercentageMod = pid.calculate(sRandomPlayerbotMgr->GetPlayers().empty() ?
|
||||
sPlayerbotAIConfig->botActiveAloneSmartScaleDiffEmpty :
|
||||
sPlayerbotAIConfig->botActiveAloneSmartScaleDiffWithPlayer,
|
||||
sWorldUpdateTime.GetAverageUpdateTime());
|
||||
|
||||
activityPercentage = activityPercentageMod + 50;
|
||||
@@ -1108,6 +1105,9 @@ bool RandomPlayerbotMgr::ProcessBot(uint32 bot)
|
||||
|
||||
bool RandomPlayerbotMgr::ProcessBot(Player* player)
|
||||
{
|
||||
if (!player || !player->IsInWorld() || player->IsBeingTeleported() || player->GetSession()->isLogingOut())
|
||||
return false;
|
||||
|
||||
uint32 bot = player->GetGUID().GetCounter();
|
||||
|
||||
if (player->InBattleground())
|
||||
@@ -1262,9 +1262,7 @@ void RandomPlayerbotMgr::RandomTeleport(Player* bot, std::vector<WorldLocation>&
|
||||
if (botAI)
|
||||
{
|
||||
// ignore when in when taxi with boat/zeppelin and has players nearby
|
||||
if (bot->HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT) &&
|
||||
bot->HasUnitState(UNIT_STATE_IGNORE_PATHFINDING) &&
|
||||
botAI->HasPlayerNearby())
|
||||
if (botAI->IsTaxiFlying() && botAI->HasPlayerNearby())
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -234,16 +234,15 @@ bool BGJoinAction::shouldJoinBg(BattlegroundQueueTypeId queueTypeId, Battlegroun
|
||||
return false;
|
||||
|
||||
TeamId teamId = bot->GetTeamId();
|
||||
bool noLag = sWorldUpdateTime.GetAverageUpdateTime() < (sRandomPlayerbotMgr->GetPlayers().empty()
|
||||
? sPlayerbotAIConfig->diffEmpty
|
||||
: sPlayerbotAIConfig->diffWithPlayer) *
|
||||
1.1;
|
||||
bool noLag = sWorldUpdateTime.GetAverageUpdateTime() < (sRandomPlayerbotMgr->GetPlayers().empty() ?
|
||||
sPlayerbotAIConfig->botActiveAloneSmartScaleDiffEmpty :
|
||||
sPlayerbotAIConfig->botActiveAloneSmartScaleDiffWithPlayer) * 1.1;
|
||||
|
||||
uint32 BracketSize = bg->GetMaxPlayersPerTeam() * 2;
|
||||
uint32 TeamSize = bg->GetMaxPlayersPerTeam();
|
||||
|
||||
// If performance diff is enabled, only queue if there is no lag
|
||||
if (sPlayerbotAIConfig->enablePrototypePerformanceDiff && !noLag)
|
||||
if (sPlayerbotAIConfig->botActiveAloneSmartScale && !noLag)
|
||||
return false;
|
||||
|
||||
// If the bot is in a group, only the leader can queue
|
||||
@@ -578,16 +577,15 @@ bool FreeBGJoinAction::shouldJoinBg(BattlegroundQueueTypeId queueTypeId, Battleg
|
||||
return false;
|
||||
|
||||
TeamId teamId = bot->GetTeamId();
|
||||
bool noLag = sWorldUpdateTime.GetAverageUpdateTime() < (sRandomPlayerbotMgr->GetPlayers().empty()
|
||||
? sPlayerbotAIConfig->diffEmpty
|
||||
: sPlayerbotAIConfig->diffWithPlayer) *
|
||||
1.1;
|
||||
bool noLag = sWorldUpdateTime.GetAverageUpdateTime() < (sRandomPlayerbotMgr->GetPlayers().empty() ?
|
||||
sPlayerbotAIConfig->botActiveAloneSmartScaleDiffEmpty :
|
||||
sPlayerbotAIConfig->botActiveAloneSmartScaleDiffWithPlayer) * 1.1;
|
||||
|
||||
uint32 BracketSize = bg->GetMaxPlayersPerTeam() * 2;
|
||||
uint32 TeamSize = bg->GetMaxPlayersPerTeam();
|
||||
|
||||
// If performance diff is enabled, only queue if there is no lag
|
||||
if (sPlayerbotAIConfig->enablePrototypePerformanceDiff && !noLag)
|
||||
if (sPlayerbotAIConfig->botActiveAloneSmartScale && !noLag)
|
||||
return false;
|
||||
|
||||
// If the bot is in a group, only the leader can queue
|
||||
|
||||
@@ -58,55 +58,92 @@ bool DropQuestAction::Execute(Event event)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CleanQuestLogAction::Execute(Event event)
|
||||
{
|
||||
Player* requester = event.getOwner() ? event.getOwner() : GetMaster();
|
||||
std::string link = event.getParam();
|
||||
if (botAI->HasActivePlayerMaster() || !sRandomPlayerbotMgr->IsRandomBot(bot))
|
||||
if (!requester)
|
||||
{
|
||||
botAI->TellMaster("No event owner detected");
|
||||
return false;
|
||||
|
||||
uint8 totalQuests = 0;
|
||||
// Count the total quests
|
||||
DropQuestType(totalQuests);
|
||||
if (MAX_QUEST_LOG_SIZE - totalQuests > 6)
|
||||
{
|
||||
// Drop failed quests
|
||||
DropQuestType(totalQuests, MAX_QUEST_LOG_SIZE, true, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Only drop gray quests when able to fight proper lvl quests.
|
||||
if (AI_VALUE(bool, "can fight equal"))
|
||||
// Only output this message if "debug rpg" strategy is enabled
|
||||
if (botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT))
|
||||
{
|
||||
// Drop gray/red quests.
|
||||
DropQuestType(totalQuests, MAX_QUEST_LOG_SIZE - 6);
|
||||
// Drop gray/red quests with progress.
|
||||
DropQuestType(totalQuests, MAX_QUEST_LOG_SIZE - 6, false, true);
|
||||
// Drop gray/red completed quests.
|
||||
DropQuestType(totalQuests, MAX_QUEST_LOG_SIZE - 6, false, true, true);
|
||||
botAI->TellMaster("Clean Quest Log command received, removing grey/trivial quests...");
|
||||
}
|
||||
|
||||
if (MAX_QUEST_LOG_SIZE - totalQuests > 4)
|
||||
return true;
|
||||
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++;
|
||||
}
|
||||
}
|
||||
|
||||
DropQuestType(totalQuests, MAX_QUEST_LOG_SIZE - 4, true); // Drop quests without progress.
|
||||
for (uint8 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot)
|
||||
{
|
||||
uint32 questId = bot->GetQuestSlotQuestId(slot);
|
||||
if (!questId)
|
||||
continue;
|
||||
|
||||
if (MAX_QUEST_LOG_SIZE - totalQuests > 2)
|
||||
return true;
|
||||
const Quest* quest = sObjectMgr->GetQuestTemplate(questId);
|
||||
if (!quest)
|
||||
continue;
|
||||
|
||||
DropQuestType(totalQuests, MAX_QUEST_LOG_SIZE - 2, true, true); // Drop quests with progress.
|
||||
// Determine if quest is trivial by comparing levels
|
||||
int32 questLevel = quest->GetQuestLevel();
|
||||
if (questLevel == -1) // For scaling quests, default to bot level
|
||||
{
|
||||
questLevel = botLevel;
|
||||
}
|
||||
|
||||
if (MAX_QUEST_LOG_SIZE - totalQuests > 0)
|
||||
return true;
|
||||
// Check if the quest is trivial (grey) for the bot
|
||||
if ((botLevel - questLevel) >= 5)
|
||||
{
|
||||
// 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).");
|
||||
}
|
||||
|
||||
DropQuestType(totalQuests, MAX_QUEST_LOG_SIZE - 1, true, true, true); // Drop completed quests.
|
||||
// Remove quest
|
||||
bot->SetQuestSlot(slot, 0);
|
||||
bot->TakeQuestSourceItem(questId, false);
|
||||
bot->SetQuestStatus(questId, QUEST_STATUS_NONE);
|
||||
bot->RemoveRewardedQuest(questId);
|
||||
|
||||
if (MAX_QUEST_LOG_SIZE - totalQuests > 0)
|
||||
return true;
|
||||
numQuest--;
|
||||
|
||||
return false;
|
||||
if (botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT))
|
||||
{
|
||||
const std::string text_quest = ChatHelper::FormatQuest(quest);
|
||||
LOG_INFO("playerbots", "{} => Quest [ {} ] removed", bot->GetName(), quest->GetTitle());
|
||||
bot->Say("Quest [ " + text_quest + " ] removed", LANG_UNIVERSAL);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
void CleanQuestLogAction::DropQuestType(uint8& numQuest, uint8 wantNum, bool isGreen, bool hasProgress, bool isComplete)
|
||||
{
|
||||
std::vector<uint8> slots;
|
||||
|
||||
@@ -30,6 +30,8 @@ bool PartyCommandAction::Execute(Event event)
|
||||
Player* master = GetMaster();
|
||||
if (master && member == master->GetName())
|
||||
return Leave(bot);
|
||||
|
||||
botAI->Reset();
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -62,6 +64,8 @@ bool UninviteAction::Execute(Event event)
|
||||
if (bot->GetGUID() == guid)
|
||||
return Leave(bot);
|
||||
}
|
||||
|
||||
botAI->Reset();
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -160,6 +164,8 @@ bool LeaveFarAwayAction::isUseful()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
botAI->Reset();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ bool RpgAction::SetNextRpgAction()
|
||||
{
|
||||
NextAction* nextAction = nextActions[i];
|
||||
|
||||
if (nextAction->getRelevance() > 2.0f)
|
||||
if (nextAction->getRelevance() > 5.0f)
|
||||
continue;
|
||||
|
||||
if (!isChecked && !trigger->IsActive())
|
||||
@@ -92,7 +92,7 @@ bool RpgAction::SetNextRpgAction()
|
||||
continue;
|
||||
|
||||
actions.push_back(action);
|
||||
relevances.push_back((nextAction->getRelevance() - 1) * 1000);
|
||||
relevances.push_back((nextAction->getRelevance() - 1) * 500);
|
||||
}
|
||||
NextAction::destroy(nextActions);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user