Skip to content

Commit 95c572b

Browse files
authored
feat(playerbots): staggered taxi take-off for bots (liyunfan1223#1281)
* feat(playerbots): staggered taxi take-off for bots Adds four new configurable settings to playerbots.conf: - AiPlayerbot.BotTaxiDelayMinMs: Min random delay before the 1st follower bot clicks the flight-master - AiPlayerbot.BotTaxiDelayMaxMs: Upper bound for the overall taxi delay window – larger spreads big raids - AiPlayerbot.BotTaxiGapMs: Fixed gap added per group-slot so bots never take off together - AiPlayerbot.BotTaxiGapJitterMs: Extra small randomness added to each gap so launches don’t look robotic These options allow server owners to fine-tune how bots queue up and take off from flight masters, making their behavior appear more natural. Closes liyunfan1223#1017 : Bots use Flight master nearly the same time. * fixed build errors Was missing a header and variable declarations.
1 parent 43b0852 commit 95c572b

File tree

6 files changed

+91
-0
lines changed

6 files changed

+91
-0
lines changed

conf/playerbots.conf.dist

+23
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
# COMBAT
1919
# CHEATS
2020
# SPELLS
21+
# FLIGHTPATH
2122
# PLAYERBOT RNDBOT SPECIFIC SETTINGS
2223
# GENERAL
2324
# LEVELS
@@ -495,6 +496,28 @@ AiPlayerbot.OpenGoSpell = 6477
495496
#
496497
###################################################################################################
497498

499+
####################################################################################################
500+
# FLIGHTPATH
501+
#
502+
#
503+
504+
# Min random delay before the 1st follower bot clicks the flight-master (ms)
505+
AiPlayerbot.BotTaxiDelayMinMs = 350
506+
507+
# Upper bound for the overall taxi delay window (ms) – larger spreads big raids
508+
AiPlayerbot.BotTaxiDelayMaxMs = 5000
509+
510+
# Fixed gap added per group-slot so bots never take off together (ms)
511+
AiPlayerbot.BotTaxiGapMs = 200
512+
513+
# Extra small randomness added to each gap so launches don’t look robotic (ms)
514+
AiPlayerbot.BotTaxiGapJitterMs = 100
515+
516+
#
517+
#
518+
#
519+
###################################################################################################
520+
498521
#######################################
499522
# #
500523
# PLAYERBOT RNDBOT SPECIFIC SETTINGS #

src/PlayerbotAI.cpp

+21
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "CreatureData.h"
2020
#include "EmoteAction.h"
2121
#include "Engine.h"
22+
#include "EventProcessor.h"
2223
#include "ExternalEventHelper.h"
2324
#include "GameObjectData.h"
2425
#include "GameTime.h"
@@ -6279,3 +6280,23 @@ SpellFamilyNames PlayerbotAI::Class2SpellFamilyName(uint8 cls)
62796280
}
62806281
return SPELLFAMILY_GENERIC;
62816282
}
6283+
6284+
void PlayerbotAI::AddTimedEvent(std::function<void()> callback, uint32 delayMs)
6285+
{
6286+
class LambdaEvent final : public BasicEvent
6287+
{
6288+
std::function<void()> _cb;
6289+
public:
6290+
explicit LambdaEvent(std::function<void()> cb) : _cb(std::move(cb)) {}
6291+
bool Execute(uint64 /*execTime*/, uint32 /*diff*/) override
6292+
{
6293+
_cb();
6294+
return true; // remove after execution
6295+
}
6296+
};
6297+
6298+
// Every Player already owns an EventMap called m_Events
6299+
bot->m_Events.AddEvent(
6300+
new LambdaEvent(std::move(callback)),
6301+
bot->m_Events.CalculateTime(delayMs));
6302+
}

src/PlayerbotAI.h

+3
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,9 @@ class PlayerbotAI : public PlayerbotAIBase
590590
NewRpgStatistic rpgStatistic;
591591
std::unordered_set<uint32> lowPriorityQuest;
592592

593+
// Schedules a callback to run once after <delayMs> milliseconds.
594+
void AddTimedEvent(std::function<void()> callback, uint32 delayMs);
595+
593596
private:
594597
static void _fillGearScoreData(Player* player, Item* item, std::vector<uint32>* gearScore, uint32& twoHandScore,
595598
bool mixed = false);

src/PlayerbotAIConfig.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,12 @@ bool PlayerbotAIConfig::Initialize()
331331
useFlyMountAtMinLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.UseFlyMountAtMinLevel", 60);
332332
useFastFlyMountAtMinLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.UseFastFlyMountAtMinLevel", 70);
333333

334+
// stagger bot flightpath takeoff
335+
delayMin = sConfigMgr->GetOption<uint32>("AiPlayerbot.BotTaxiDelayMinMs", 350u);
336+
delayMax = sConfigMgr->GetOption<uint32>("AiPlayerbot.BotTaxiDelayMaxMs", 5000u);
337+
gapMs = sConfigMgr->GetOption<uint32>("AiPlayerbot.BotTaxiGapMs", 200u);
338+
gapJitterMs = sConfigMgr->GetOption<uint32>("AiPlayerbot.BotTaxiGapJitterMs", 100u);
339+
334340
LOG_INFO("server.loading", "Loading TalentSpecs...");
335341

336342
for (uint32 cls = 1; cls < MAX_CLASSES; ++cls)

src/PlayerbotAIConfig.h

+6
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,12 @@ class PlayerbotAIConfig
348348
uint32 useFlyMountAtMinLevel;
349349
uint32 useFastFlyMountAtMinLevel;
350350

351+
// stagger flightpath takeoff
352+
uint32 delayMin;
353+
uint32 delayMax;
354+
uint32 gapMs;
355+
uint32 gapJitterMs;
356+
351357
std::string const GetTimestampStr();
352358
bool hasLog(std::string const fileName)
353359
{

src/strategy/actions/TaxiAction.cpp

+32
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
#include "Event.h"
99
#include "LastMovementValue.h"
1010
#include "Playerbots.h"
11+
#include "PlayerbotAIConfig.h"
12+
#include "Config.h"
1113

1214
bool TaxiAction::Execute(Event event)
1315
{
@@ -48,6 +50,36 @@ bool TaxiAction::Execute(Event event)
4850
}
4951
}
5052

53+
// stagger bot takeoff
54+
uint32 delayMin = sConfigMgr->GetOption<uint32>("AiPlayerbot.BotTaxiDelayMinMs", 350u, false);
55+
uint32 delayMax = sConfigMgr->GetOption<uint32>("AiPlayerbot.BotTaxiDelayMaxMs", 5000u, false);
56+
uint32 gapMs = sConfigMgr->GetOption<uint32>("AiPlayerbot.BotTaxiGapMs", 200u, false);
57+
uint32 gapJitterMs = sConfigMgr->GetOption<uint32>("AiPlayerbot.BotTaxiGapJitterMs", 100u, false);
58+
59+
// Only for follower bots
60+
if (botAI->HasRealPlayerMaster())
61+
{
62+
uint32 index = botAI->GetGroupSlotIndex(bot);
63+
uint32 delay = delayMin + index * gapMs + urand(0, gapJitterMs);
64+
65+
delay = std::min(delay, delayMax);
66+
67+
// Store the npc’s GUID so we can re-acquire the pointer later
68+
ObjectGuid npcGuid = npc->GetGUID();
69+
70+
// schedule the take-off
71+
botAI->AddTimedEvent(
72+
[bot = bot, &movement, npcGuid]() -> void
73+
{
74+
if (Creature* npcPtr = ObjectAccessor::GetCreature(*bot, npcGuid))
75+
if (!movement.taxiNodes.empty())
76+
bot->ActivateTaxiPathTo(movement.taxiNodes, npcPtr);
77+
},
78+
delay);
79+
botAI->SetNextCheckDelay(delay + 50);
80+
return true;
81+
}
82+
5183
if (param == "?")
5284
{
5385
botAI->TellMasterNoFacing("=== Taxi ===");

0 commit comments

Comments
 (0)