diff --git a/code_format.sh b/code_format.sh old mode 100755 new mode 100644 index 3e2d3552..e9612dac --- a/code_format.sh +++ b/code_format.sh @@ -15,4 +15,4 @@ for file in $cpp_files; do $CLANG_FORMAT_PATH -i $file done -echo "All .cpp or .h files have been formatted." +echo "All .cpp or .h files have been formatted." \ No newline at end of file diff --git a/src/PlayerbotAI.cpp b/src/PlayerbotAI.cpp index 48a259e1..f014151e 100644 --- a/src/PlayerbotAI.cpp +++ b/src/PlayerbotAI.cpp @@ -355,7 +355,7 @@ void PlayerbotAI::UpdateAI(uint32 elapsed, bool minimal) } // Update the bot's group status (moved to helper function) - UpdateAIGroupMembership(); + UpdateAIGroupAndMaster(); // Update internal AI UpdateAIInternal(elapsed, minimal); @@ -363,47 +363,60 @@ void PlayerbotAI::UpdateAI(uint32 elapsed, bool minimal) } // Helper function for UpdateAI to check group membership and handle removal if necessary -void PlayerbotAI::UpdateAIGroupMembership() +void PlayerbotAI::UpdateAIGroupAndMaster() { - if (!bot || !bot->GetGroup()) + if (!bot) + return; + Group* group = bot->GetGroup(); + // If bot is not in group verify that for is RandomBot before clearing master and resetting. + if (!group) + { + if (master && sRandomPlayerbotMgr->IsRandomBot(bot)) + { + SetMaster(nullptr); + Reset(true); + ResetStrategies(); + } + return; + } + + if (bot->InBattleground() && bot->GetBattleground()->GetBgTypeID() != BATTLEGROUND_AV) return; - Group* group = bot->GetGroup(); + PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot); + if (!botAI) + return; - if (!bot->InBattleground() && !bot->inRandomLfgDungeon() && !group->isLFGGroup()) + PlayerbotAI* masterBotAI = nullptr; + if (master) + masterBotAI = GET_PLAYERBOT_AI(master); + + if (!master || (masterBotAI && !masterBotAI->IsRealPlayer())) { - Player* leader = group->GetLeader(); - if (leader && leader != bot) // Ensure the leader is valid and not the bot itself + Player* newMaster = FindNewMaster(); + if (newMaster) { - PlayerbotAI* leaderAI = GET_PLAYERBOT_AI(leader); - if (leaderAI && !leaderAI->IsRealPlayer()) + master = newMaster; + botAI->SetMaster(newMaster); + botAI->ResetStrategies(); + + if (!bot->InBattleground()) { - LeaveOrDisbandGroup(); + botAI->ChangeStrategy("+follow", BOT_STATE_NON_COMBAT); + + if (botAI->GetMaster() == botAI->GetGroupMaster()) + botAI->TellMaster("Hello, I follow you!"); + else + botAI->TellMaster(!urand(0, 2) ? "Hello!" : "Hi!"); + } + else + { + // we're in a battleground, stay with the pack and focus on objective + botAI->ChangeStrategy("-follow", BOT_STATE_NON_COMBAT); } } - } - else if (group->isLFGGroup()) - { - bool hasRealPlayer = false; - - // Iterate over all group members to check if at least one is a real player - for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) - { - Player* member = ref->GetSource(); - if (!member) - continue; - - PlayerbotAI* memberAI = GET_PLAYERBOT_AI(member); - if (memberAI && !memberAI->IsRealPlayer()) - continue; - - hasRealPlayer = true; - break; - } - if (!hasRealPlayer) - { + else if (!newMaster && !bot->InBattleground()) LeaveOrDisbandGroup(); - } } } @@ -792,7 +805,6 @@ void PlayerbotAI::LeaveOrDisbandGroup() WorldPacket* packet = new WorldPacket(CMSG_GROUP_DISBAND); bot->GetSession()->QueuePacket(packet); - ResetStrategies(); } bool PlayerbotAI::IsAllowedCommand(std::string const text) @@ -1301,7 +1313,6 @@ void PlayerbotAI::DoNextAction(bool min) return; } - // Change engine if just died bool isBotAlive = bot->IsAlive(); if (currentEngine != engines[BOT_STATE_DEAD] && !isBotAlive) @@ -1361,92 +1372,6 @@ void PlayerbotAI::DoNextAction(bool min) Group* group = bot->GetGroup(); PlayerbotAI* masterBotAI = nullptr; - if (master) - masterBotAI = GET_PLAYERBOT_AI(master); - - // Test BG master set - if ((!master || (masterBotAI && !masterBotAI->IsRealPlayer())) && group) - { - PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot); - if (!botAI) - { - return; - } - - // Ideally we want to have the leader as master. - Player* newMaster = botAI->GetGroupMaster(); - Player* playerMaster = nullptr; - - // Are there any non-bot players in the group? - if (!newMaster || GET_PLAYERBOT_AI(newMaster)) - { - for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next()) - { - Player* member = gref->GetSource(); - if (!member || member == bot || member == newMaster || !member->IsInWorld() || - !member->IsInSameRaidWith(bot)) - continue; - - PlayerbotAI* memberBotAI = GET_PLAYERBOT_AI(member); - if (memberBotAI) - { - if (memberBotAI->IsRealPlayer() && !bot->InBattleground()) - playerMaster = member; - - continue; - } - - // Same BG checks (optimize checking conditions here) - if (bot->InBattleground() && bot->GetBattleground() && - bot->GetBattleground()->GetBgTypeID() == BATTLEGROUND_AV && !GET_PLAYERBOT_AI(member) && - member->InBattleground() && bot->GetMapId() == member->GetMapId()) - { - // Skip if same BG but same subgroup or lower level - if (!group->SameSubGroup(bot, member) || member->GetLevel() < bot->GetLevel()) - continue; - - // Follow real player only if higher honor points - uint32 honorpts = member->GetHonorPoints(); - if (bot->GetHonorPoints() && honorpts < bot->GetHonorPoints()) - continue; - - playerMaster = member; - continue; - } - - if (bot->InBattleground()) - continue; - - newMaster = member; - break; - } - } - - if (!newMaster && playerMaster) - newMaster = playerMaster; - - if (newMaster && (!master || master != newMaster) && bot != newMaster) - { - master = newMaster; - botAI->SetMaster(newMaster); - botAI->ResetStrategies(); - - if (!bot->InBattleground()) - { - botAI->ChangeStrategy("+follow", BOT_STATE_NON_COMBAT); - - if (botAI->GetMaster() == botAI->GetGroupMaster()) - botAI->TellMaster("Hello, I follow you!"); - else - botAI->TellMaster(!urand(0, 2) ? "Hello!" : "Hi!"); - } - else - { - // we're in a battleground, stay with the pack and focus on objective - botAI->ChangeStrategy("-follow", BOT_STATE_NON_COMBAT); - } - } - } if (master && master->IsInWorld()) { @@ -4135,6 +4060,50 @@ bool IsAlliance(uint8 race) race == RACE_DRAENEI; } +Player* PlayerbotAI::FindNewMaster() +{ + // Ideally we want to have the leader as master. + Group* group = bot->GetGroup(); + // Only allow real players as masters unless in battleground. + if (!group) + return nullptr; + + Player* groupLeader = GetGroupMaster(); + PlayerbotAI* leaderBotAI = GET_PLAYERBOT_AI(groupLeader); + if (!leaderBotAI || leaderBotAI->IsRealPlayer()) + return groupLeader; + + // Find the real player in group + for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next()) + { + Player* member = gref->GetSource(); + if (!member || member == bot || !member->IsInWorld() || + !member->IsInSameRaidWith(bot)) + continue; + + PlayerbotAI* memberBotAI = GET_PLAYERBOT_AI(member); + if ((!memberBotAI || memberBotAI->IsRealPlayer()) && !bot->InBattleground()) + return member; + + if (bot->InBattleground() && bot->GetBattleground() && + bot->GetBattleground()->GetBgTypeID() == BATTLEGROUND_AV && !GET_PLAYERBOT_AI(member) && + member->InBattleground() && bot->GetMapId() == member->GetMapId()) + { + // Skip if same BG but same subgroup or lower level + if (!group->SameSubGroup(bot, member) || member->GetLevel() < bot->GetLevel()) + continue; + + // Follow real player only if higher honor points + uint32 honorpts = member->GetHonorPoints(); + if (bot->GetHonorPoints() && honorpts < bot->GetHonorPoints()) + continue; + + return member; + } + } + return nullptr; +} + bool PlayerbotAI::HasRealPlayerMaster() { if (master) diff --git a/src/PlayerbotAI.h b/src/PlayerbotAI.h index a6600845..b5dacd76 100644 --- a/src/PlayerbotAI.h +++ b/src/PlayerbotAI.h @@ -529,7 +529,8 @@ public: Player* GetBot() { return bot; } Player* GetMaster() { return master; } - + Player* FindNewMaster(); + // Checks if the bot is really a player. Players always have themselves as master. bool IsRealPlayer() { return master ? (master == bot) : false; } // Bot has a master that is a player. @@ -611,7 +612,7 @@ private: static void _fillGearScoreData(Player* player, Item* item, std::vector* gearScore, uint32& twoHandScore, bool mixed = false); bool IsTellAllowed(PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL); - void UpdateAIGroupMembership(); + void UpdateAIGroupAndMaster(); Item* FindItemInInventory(std::function checkItem) const; void HandleCommands(); void HandleCommand(uint32 type, const std::string& text, Player& fromPlayer, const uint32 lang = LANG_UNIVERSAL); diff --git a/src/strategy/actions/LeaveGroupAction.cpp b/src/strategy/actions/LeaveGroupAction.cpp index 88567b1d..039c476b 100644 --- a/src/strategy/actions/LeaveGroupAction.cpp +++ b/src/strategy/actions/LeaveGroupAction.cpp @@ -11,8 +11,11 @@ bool LeaveGroupAction::Execute(Event event) { - Player* master = event.getOwner(); - return Leave(master); + Player* player = event.getOwner(); + if (player == botAI->GetMaster()) + return Leave(); + + return false; } bool PartyCommandAction::Execute(Event event) @@ -26,13 +29,21 @@ bool PartyCommandAction::Execute(Event event) if (operation != PARTY_OP_LEAVE) return false; - + // Only leave if master has left the party, and randombot cannot set new master. Player* master = GetMaster(); if (master && member == master->GetName()) - return Leave(bot); - - botAI->Reset(); - + { + if (sRandomPlayerbotMgr->IsRandomBot(bot)) + { + Player* newMaster = botAI->FindNewMaster(); + if (newMaster || bot->InBattleground()) + { + botAI->SetMaster(newMaster); + return false; + } + } + return Leave(); + } return false; } @@ -42,17 +53,17 @@ bool UninviteAction::Execute(Event event) if (p.GetOpcode() == CMSG_GROUP_UNINVITE) { p.rpos(0); - std::string membername; - p >> membername; + std::string memberName; + p >> memberName; // player not found - if (!normalizePlayerName(membername)) + if (!normalizePlayerName(memberName)) { return false; } - if (bot->GetName() == membername) - return Leave(bot); + if (bot->GetName() == memberName) + return Leave(); } if (p.GetOpcode() == CMSG_GROUP_UNINVITE_GUID) @@ -62,50 +73,29 @@ bool UninviteAction::Execute(Event event) p >> guid; if (bot->GetGUID() == guid) - return Leave(bot); + return Leave(); } - botAI->Reset(); - return false; } -bool LeaveGroupAction::Leave(Player* player) +bool LeaveGroupAction::Leave() { - if (player && - !botAI && - !botAI->GetSecurity()->CheckLevelFor(PLAYERBOT_SECURITY_INVITE, false, player)) - + if (!botAI) return false; - bool aiMaster = GET_PLAYERBOT_AI(botAI->GetMaster()) != nullptr; - - botAI->TellMaster("Goodbye!", PLAYERBOT_SECURITY_TALK); - - bool randomBot = sRandomPlayerbotMgr->IsRandomBot(bot); - bool shouldStay = randomBot && bot->GetGroup() && player == bot; - if (!shouldStay) - { - botAI->LeaveOrDisbandGroup(); - } - - if (randomBot) - { - GET_PLAYERBOT_AI(bot)->SetMaster(nullptr); - } - - if (!aiMaster) - botAI->ResetStrategies(!randomBot); - - botAI->Reset(); + Player* master = botAI -> GetMaster(); + if (master) + botAI->TellMaster("Goodbye!", PLAYERBOT_SECURITY_TALK); + botAI->LeaveOrDisbandGroup(); return true; } bool LeaveFarAwayAction::Execute(Event event) { // allow bot to leave party when they want - return Leave(botAI->GetGroupMaster()); + return Leave(); } bool LeaveFarAwayAction::isUseful() @@ -165,7 +155,5 @@ bool LeaveFarAwayAction::isUseful() return true; } - botAI->Reset(); - return false; } diff --git a/src/strategy/actions/LeaveGroupAction.h b/src/strategy/actions/LeaveGroupAction.h index dcb4e96c..83baea3c 100644 --- a/src/strategy/actions/LeaveGroupAction.h +++ b/src/strategy/actions/LeaveGroupAction.h @@ -18,7 +18,7 @@ public: bool Execute(Event event) override; - virtual bool Leave(Player* player); + virtual bool Leave(); }; class PartyCommandAction : public LeaveGroupAction