mirror of
https://github.com/liyunfan1223/mod-playerbots.git
synced 2026-06-20 15:39:25 +02:00
Fix arena
This commit is contained in:
parent
fd5910e4b6
commit
3d0fb90c4f
@ -11,6 +11,7 @@
|
|||||||
#include "AiFactory.h"
|
#include "AiFactory.h"
|
||||||
#include "ArenaTeam.h"
|
#include "ArenaTeam.h"
|
||||||
#include "ArenaTeamMgr.h"
|
#include "ArenaTeamMgr.h"
|
||||||
|
#include "CharacterCache.h"
|
||||||
#include "DBCStores.h"
|
#include "DBCStores.h"
|
||||||
#include "DBCStructure.h"
|
#include "DBCStructure.h"
|
||||||
#include "GuildMgr.h"
|
#include "GuildMgr.h"
|
||||||
@ -450,7 +451,6 @@ void PlayerbotFactory::Randomize(bool incremental)
|
|||||||
if (bot->GetLevel() >= 70)
|
if (bot->GetLevel() >= 70)
|
||||||
{
|
{
|
||||||
pmo = sPerfMonitor.start(PERF_MON_RNDBOT, "PlayerbotFactory_Arenas");
|
pmo = sPerfMonitor.start(PERF_MON_RNDBOT, "PlayerbotFactory_Arenas");
|
||||||
// LOG_INFO("playerbots", "Initializing arena teams...");
|
|
||||||
InitArenaTeam();
|
InitArenaTeam();
|
||||||
if (pmo)
|
if (pmo)
|
||||||
pmo->finish();
|
pmo->finish();
|
||||||
@ -4049,125 +4049,112 @@ void PlayerbotFactory::InitImmersive()
|
|||||||
|
|
||||||
void PlayerbotFactory::InitArenaTeam()
|
void PlayerbotFactory::InitArenaTeam()
|
||||||
{
|
{
|
||||||
|
|
||||||
if (!sPlayerbotAIConfig.IsInRandomAccountList(bot->GetSession()->GetAccountId()))
|
if (!sPlayerbotAIConfig.IsInRandomAccountList(bot->GetSession()->GetAccountId()))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Currently the teams are only remade after a server restart and if deleteRandomBotArenaTeams = 1
|
|
||||||
// This is because randomBotArenaTeams is only empty on server restart.
|
|
||||||
// A manual reinitalization (.playerbots rndbot init) is also required after the teams have been deleted.
|
|
||||||
if (sPlayerbotAIConfig.randomBotArenaTeams.empty())
|
|
||||||
{
|
|
||||||
if (sPlayerbotAIConfig.deleteRandomBotArenaTeams)
|
if (sPlayerbotAIConfig.deleteRandomBotArenaTeams)
|
||||||
{
|
|
||||||
LOG_INFO("playerbots", "Deleting random bot arena teams...");
|
|
||||||
|
|
||||||
for (auto it = sArenaTeamMgr->GetArenaTeams().begin(); it != sArenaTeamMgr->GetArenaTeams().end(); ++it)
|
|
||||||
{
|
|
||||||
ArenaTeam* arenateam = it->second;
|
|
||||||
if (arenateam->GetCaptain() && arenateam->GetCaptain().IsPlayer())
|
|
||||||
{
|
|
||||||
Player* bot = ObjectAccessor::FindPlayer(arenateam->GetCaptain());
|
|
||||||
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
|
|
||||||
if (!botAI || botAI->IsRealPlayer())
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
arenateam->Disband(nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_INFO("playerbots", "Random bot arena teams deleted");
|
|
||||||
}
|
|
||||||
|
|
||||||
RandomPlayerbotFactory::CreateRandomArenaTeams(ARENA_TYPE_2v2, sPlayerbotAIConfig.randomBotArenaTeam2v2Count);
|
|
||||||
RandomPlayerbotFactory::CreateRandomArenaTeams(ARENA_TYPE_3v3, sPlayerbotAIConfig.randomBotArenaTeam3v3Count);
|
|
||||||
RandomPlayerbotFactory::CreateRandomArenaTeams(ARENA_TYPE_5v5, sPlayerbotAIConfig.randomBotArenaTeam5v5Count);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<uint32> arenateams;
|
|
||||||
for (std::vector<uint32>::iterator i = sPlayerbotAIConfig.randomBotArenaTeams.begin();
|
|
||||||
i != sPlayerbotAIConfig.randomBotArenaTeams.end(); ++i)
|
|
||||||
arenateams.push_back(*i);
|
|
||||||
|
|
||||||
if (arenateams.empty())
|
|
||||||
{
|
|
||||||
LOG_ERROR("playerbots", "No random arena team available");
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
while (!arenateams.empty())
|
if (bot->GetLevel() < 70)
|
||||||
{
|
return;
|
||||||
int index = urand(0, arenateams.size() - 1);
|
|
||||||
uint32 arenateamID = arenateams[index];
|
|
||||||
ArenaTeam* arenateam = sArenaTeamMgr->GetArenaTeamById(arenateamID);
|
|
||||||
if (!arenateam)
|
|
||||||
{
|
|
||||||
LOG_ERROR("playerbots", "Invalid arena team {}", arenateamID);
|
|
||||||
arenateams.erase(arenateams.begin() + index);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (arenateam->GetMembersSize() < ((uint32)arenateam->GetType()) && bot->GetLevel() >= 70)
|
// One team max to avoid queueing conflicts
|
||||||
{
|
|
||||||
ObjectGuid capt = arenateam->GetCaptain();
|
|
||||||
Player* botcaptain = ObjectAccessor::FindPlayer(capt);
|
|
||||||
|
|
||||||
// To avoid bots removing each other from groups when queueing, force them to only be in one team
|
|
||||||
for (uint32 arena_slot = 0; arena_slot < MAX_ARENA_SLOT; ++arena_slot)
|
for (uint32 arena_slot = 0; arena_slot < MAX_ARENA_SLOT; ++arena_slot)
|
||||||
{
|
{
|
||||||
uint32 arenaTeamId = bot->GetArenaTeamId(arena_slot);
|
if (bot->GetArenaTeamId(arena_slot))
|
||||||
if (!arenaTeamId)
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If captains are still needed, create a team with this bot as captain.
|
||||||
|
for (auto& [type, needed] : sRandomPlayerbotMgr.arenaCaptainsNeeded)
|
||||||
|
{
|
||||||
|
if (needed > 0)
|
||||||
|
{
|
||||||
|
if (CreateArenaTeamWithCaptain(type))
|
||||||
|
--needed;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sRandomPlayerbotMgr.arenaTeamsFull)
|
||||||
|
AssignToArenaTeam();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PlayerbotFactory::CreateArenaTeamWithCaptain(ArenaType type)
|
||||||
|
{
|
||||||
|
std::string teamName = RandomPlayerbotFactory::CreateRandomArenaTeamName();
|
||||||
|
if (teamName.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ArenaTeam* arenateam = new ArenaTeam();
|
||||||
|
if (!arenateam->Create(bot->GetGUID(), type, teamName, 0, 0, 0, 0, 0))
|
||||||
|
{
|
||||||
|
LOG_ERROR("playerbots", "Error creating arena team {}", teamName);
|
||||||
|
delete arenateam;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
arenateam->SetCaptain(bot->GetGUID());
|
||||||
|
arenateam->SetRatingForAll(
|
||||||
|
urand(sPlayerbotAIConfig.randomBotArenaTeamMinRating, sPlayerbotAIConfig.randomBotArenaTeamMaxRating));
|
||||||
|
|
||||||
|
uint32 backgroundColor = urand(0xFF000000, 0xFFFFFFFF);
|
||||||
|
uint32 emblemStyle = urand(0, 101);
|
||||||
|
uint32 emblemColor = urand(0xFF000000, 0xFFFFFFFF);
|
||||||
|
uint32 borderStyle = urand(0, 5);
|
||||||
|
uint32 borderColor = urand(0xFF000000, 0xFFFFFFFF);
|
||||||
|
arenateam->SetEmblem(backgroundColor, emblemStyle, emblemColor, borderStyle, borderColor);
|
||||||
|
|
||||||
|
arenateam->SaveToDB();
|
||||||
|
sArenaTeamMgr->AddArenaTeam(arenateam);
|
||||||
|
|
||||||
|
LOG_DEBUG("playerbots", "Created {}v{} arena team '{}' with captain {}",
|
||||||
|
type, type, teamName, bot->GetName());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayerbotFactory::AssignToArenaTeam()
|
||||||
|
{
|
||||||
|
ArenaTeam* arenateam = nullptr;
|
||||||
|
for (auto const& [id, team] : sArenaTeamMgr->GetArenaTeams())
|
||||||
|
{
|
||||||
|
if (team->GetMembersSize() >= static_cast<uint32>(team->GetType()))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ArenaTeam* team = sArenaTeamMgr->GetArenaTeamById(arenaTeamId);
|
if (!RandomPlayerbotFactory::IsBotArenaTeam(team))
|
||||||
if (team)
|
continue;
|
||||||
{
|
|
||||||
if (sCharacterCache->GetCharacterArenaTeamIdByGuid(bot->GetGUID(), team->GetSlot()) != 0)
|
ObjectGuid captainGuid = team->GetCaptain();
|
||||||
{
|
CharacterCacheEntry const* captainEntry = sCharacterCache->GetCharacterCacheByGuid(captainGuid);
|
||||||
return;
|
if (!captainEntry || Player::TeamIdForRace(captainEntry->Race) != bot->GetTeamId())
|
||||||
}
|
continue;
|
||||||
return;
|
|
||||||
}
|
arenateam = team;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (botcaptain && botcaptain->GetTeamId() == bot->GetTeamId()) // need?
|
if (!arenateam)
|
||||||
{
|
{
|
||||||
// Add bot to arena team
|
sRandomPlayerbotMgr.arenaTeamsFull = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
arenateam->AddMember(bot->GetGUID());
|
arenateam->AddMember(bot->GetGUID());
|
||||||
|
|
||||||
// Only synchronize ratings once the team is full (avoid redundant work)
|
// Synchronize ratings once the team is full
|
||||||
// The captain was added with incorrect ratings when the team was created,
|
if (arenateam->GetMembersSize() >= static_cast<uint32>(arenateam->GetType()))
|
||||||
// so we fix everyone's ratings once the roster is complete
|
|
||||||
if (arenateam->GetMembersSize() >= (uint32)arenateam->GetType())
|
|
||||||
{
|
{
|
||||||
uint32 teamRating = arenateam->GetRating();
|
uint32 teamRating = arenateam->GetRating();
|
||||||
|
|
||||||
// Use SetRatingForAll to align all members with team rating
|
|
||||||
arenateam->SetRatingForAll(teamRating);
|
arenateam->SetRatingForAll(teamRating);
|
||||||
|
|
||||||
// For bot-only teams, keep MMR synchronized with team rating
|
|
||||||
// This ensures matchmaking reflects the artificial team strength (1000-2000 range)
|
|
||||||
// instead of being influenced by the global CONFIG_ARENA_START_MATCHMAKER_RATING
|
|
||||||
for (auto& member : arenateam->GetMembers())
|
for (auto& member : arenateam->GetMembers())
|
||||||
{
|
{
|
||||||
// Set MMR to match personal rating (which already matches team rating)
|
|
||||||
member.MatchMakerRating = member.PersonalRating;
|
member.MatchMakerRating = member.PersonalRating;
|
||||||
member.MaxMMR = std::max(member.MaxMMR, member.PersonalRating);
|
member.MaxMMR = std::max(member.MaxMMR, member.PersonalRating);
|
||||||
}
|
}
|
||||||
// Force save all member data to database
|
|
||||||
arenateam->SaveToDB(true);
|
arenateam->SaveToDB(true);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
arenateams.erase(arenateams.begin() + index);
|
|
||||||
}
|
|
||||||
|
|
||||||
// bot->SaveToDB(false, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerbotFactory::ApplyEnchantTemplate()
|
void PlayerbotFactory::ApplyEnchantTemplate()
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
#ifndef _PLAYERBOT_PLAYERBOTFACTORY_H
|
#ifndef _PLAYERBOT_PLAYERBOTFACTORY_H
|
||||||
#define _PLAYERBOT_PLAYERBOTFACTORY_H
|
#define _PLAYERBOT_PLAYERBOTFACTORY_H
|
||||||
|
|
||||||
|
#include "Battleground.h"
|
||||||
#include "InventoryAction.h"
|
#include "InventoryAction.h"
|
||||||
#include "Player.h"
|
#include "Player.h"
|
||||||
#include "PlayerbotAI.h"
|
#include "PlayerbotAI.h"
|
||||||
@ -119,6 +120,8 @@ private:
|
|||||||
void InitInventorySkill();
|
void InitInventorySkill();
|
||||||
Item* StoreItem(uint32 itemId, uint32 count);
|
Item* StoreItem(uint32 itemId, uint32 count);
|
||||||
void InitArenaTeam();
|
void InitArenaTeam();
|
||||||
|
bool CreateArenaTeamWithCaptain(ArenaType type);
|
||||||
|
void AssignToArenaTeam();
|
||||||
void InitImmersive();
|
void InitImmersive();
|
||||||
static void AddPrevQuests(uint32 questId, std::list<uint32>& questIds);
|
static void AddPrevQuests(uint32 questId, std::list<uint32>& questIds);
|
||||||
void LoadEnchantContainer();
|
void LoadEnchantContainer();
|
||||||
|
|||||||
@ -7,8 +7,10 @@
|
|||||||
|
|
||||||
#include "AccountMgr.h"
|
#include "AccountMgr.h"
|
||||||
#include "ArenaTeamMgr.h"
|
#include "ArenaTeamMgr.h"
|
||||||
|
#include "CharacterCache.h"
|
||||||
#include "DatabaseEnv.h"
|
#include "DatabaseEnv.h"
|
||||||
#include "PlayerbotAI.h"
|
#include "PlayerbotAI.h"
|
||||||
|
#include "PlayerbotAIConfig.h"
|
||||||
#include "RaceMgr.h"
|
#include "RaceMgr.h"
|
||||||
#include "ScriptMgr.h"
|
#include "ScriptMgr.h"
|
||||||
#include "SharedDefines.h"
|
#include "SharedDefines.h"
|
||||||
@ -782,145 +784,90 @@ std::string const RandomPlayerbotFactory::CreateRandomGuildName()
|
|||||||
return guildName;
|
return guildName;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RandomPlayerbotFactory::CreateRandomArenaTeams(ArenaType type, uint32 count)
|
bool RandomPlayerbotFactory::IsBotArenaTeam(ArenaTeam const* team)
|
||||||
{
|
{
|
||||||
std::vector<uint32> randomBots;
|
if (!team)
|
||||||
|
return false;
|
||||||
|
|
||||||
PlayerbotsDatabasePreparedStatement* stmt = PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_SEL_RANDOM_BOTS_BOT);
|
ObjectGuid captainGuid = team->GetCaptain();
|
||||||
stmt->SetData(0, "add");
|
if (!captainGuid || !captainGuid.IsPlayer())
|
||||||
if (PreparedQueryResult result = PlayerbotsDatabase.Query(stmt))
|
return false;
|
||||||
|
|
||||||
|
uint32 accountId = sCharacterCache->GetCharacterAccountIdByGuid(captainGuid);
|
||||||
|
return accountId && sPlayerbotAIConfig.IsInRandomAccountList(accountId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RandomPlayerbotFactory::LoadArenaTeamNames()
|
||||||
|
{
|
||||||
|
_availableArenaTeamNames.clear();
|
||||||
|
|
||||||
|
QueryResult result = CharacterDatabase.Query(
|
||||||
|
"SELECT n.name FROM playerbots_arena_team_names n "
|
||||||
|
"LEFT OUTER JOIN arena_team e ON e.name = n.name "
|
||||||
|
"WHERE e.arenateamid IS NULL");
|
||||||
|
|
||||||
|
if (!result)
|
||||||
{
|
{
|
||||||
|
LOG_ERROR("playerbots", "No arena team names available in playerbots_arena_team_names");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
Field* fields = result->Fetch();
|
Field* fields = result->Fetch();
|
||||||
uint32 bot = fields[0].Get<uint32>();
|
_availableArenaTeamNames.push_back(fields[0].Get<std::string>());
|
||||||
randomBots.push_back(bot);
|
|
||||||
} while (result->NextRow());
|
} while (result->NextRow());
|
||||||
}
|
|
||||||
|
|
||||||
uint32 arenaTeamNumber = 0;
|
for (size_t i = _availableArenaTeamNames.size() - 1; i > 0; --i)
|
||||||
GuidVector availableCaptains;
|
|
||||||
for (std::vector<uint32>::iterator i = randomBots.begin(); i != randomBots.end(); ++i)
|
|
||||||
{
|
{
|
||||||
ObjectGuid captain = ObjectGuid::Create<HighGuid::Player>(*i);
|
size_t j = urand(0, i);
|
||||||
ArenaTeam* arenateam = sArenaTeamMgr->GetArenaTeamByCaptain(captain, type);
|
std::swap(_availableArenaTeamNames[i], _availableArenaTeamNames[j]);
|
||||||
if (arenateam)
|
|
||||||
{
|
|
||||||
++arenaTeamNumber;
|
|
||||||
sPlayerbotAIConfig.randomBotArenaTeams.push_back(arenateam->GetId());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Player* player = ObjectAccessor::FindConnectedPlayer(captain);
|
|
||||||
|
|
||||||
if (!arenateam && player && player->GetLevel() >= 70)
|
|
||||||
availableCaptains.push_back(captain);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (; arenaTeamNumber < count; ++arenaTeamNumber)
|
LOG_INFO("playerbots", "Loaded {} available arena team names", _availableArenaTeamNames.size());
|
||||||
{
|
|
||||||
std::string const arenaTeamName = CreateRandomArenaTeamName();
|
|
||||||
if (arenaTeamName.empty())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (availableCaptains.empty())
|
|
||||||
{
|
|
||||||
LOG_ERROR("playerbots", "No captains for random arena teams available");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 index = urand(0, availableCaptains.size() - 1);
|
|
||||||
ObjectGuid captain = availableCaptains[index];
|
|
||||||
Player* player = ObjectAccessor::FindConnectedPlayer(captain);
|
|
||||||
if (!player)
|
|
||||||
{
|
|
||||||
LOG_ERROR("playerbots", "Cannot find player for captain {}", captain.ToString().c_str());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (player->GetLevel() < 70)
|
|
||||||
{
|
|
||||||
LOG_ERROR("playerbots", "Bot {} must be level 70 to create an arena team", captain.ToString().c_str());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Below query no longer required as now user has control over the number of each type of arena team they want
|
|
||||||
// to create. Keeping commented for potential future reference. QueryResult results =
|
|
||||||
// CharacterDatabase.Query("SELECT `type` FROM playerbots_arena_team_names WHERE name = '{}'",
|
|
||||||
// arenaTeamName.c_str()); if (!results)
|
|
||||||
// {
|
|
||||||
// LOG_ERROR("playerbots", "No valid types for arena teams");
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Field* fields = results->Fetch();
|
|
||||||
// uint8 slot = fields[0].Get<uint8>();
|
|
||||||
|
|
||||||
ArenaTeam* arenateam = new ArenaTeam();
|
|
||||||
if (!arenateam->Create(player->GetGUID(), type, arenaTeamName, 0, 0, 0, 0, 0))
|
|
||||||
{
|
|
||||||
LOG_ERROR("playerbots", "Error creating arena team {}", arenaTeamName.c_str());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
arenateam->SetCaptain(player->GetGUID());
|
|
||||||
|
|
||||||
// set random rating
|
|
||||||
arenateam->SetRatingForAll(
|
|
||||||
urand(sPlayerbotAIConfig.randomBotArenaTeamMinRating, sPlayerbotAIConfig.randomBotArenaTeamMaxRating));
|
|
||||||
|
|
||||||
// set random emblem
|
|
||||||
uint32 backgroundColor = urand(0xFF000000, 0xFFFFFFFF);
|
|
||||||
uint32 emblemStyle = urand(0, 101);
|
|
||||||
uint32 emblemColor = urand(0xFF000000, 0xFFFFFFFF);
|
|
||||||
uint32 borderStyle = urand(0, 5);
|
|
||||||
uint32 borderColor = urand(0xFF000000, 0xFFFFFFFF);
|
|
||||||
arenateam->SetEmblem(backgroundColor, emblemStyle, emblemColor, borderStyle, borderColor);
|
|
||||||
|
|
||||||
// set random kills (wip)
|
|
||||||
// arenateam->SetStats(STAT_TYPE_GAMES_WEEK, urand(0, 30));
|
|
||||||
// arenateam->SetStats(STAT_TYPE_WINS_WEEK, urand(0, arenateam->GetStats().games_week));
|
|
||||||
// arenateam->SetStats(STAT_TYPE_GAMES_SEASON, urand(arenateam->GetStats().games_week,
|
|
||||||
// arenateam->GetStats().games_week * 5)); arenateam->SetStats(STAT_TYPE_WINS_SEASON,
|
|
||||||
// urand(arenateam->GetStats().wins_week, arenateam->GetStats().games
|
|
||||||
arenateam->SaveToDB();
|
|
||||||
|
|
||||||
sArenaTeamMgr->AddArenaTeam(arenateam);
|
|
||||||
sPlayerbotAIConfig.randomBotArenaTeams.push_back(arenateam->GetId());
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_DEBUG("playerbots", "{} random bot {}vs{} arena teams available", arenaTeamNumber, type, type);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string const RandomPlayerbotFactory::CreateRandomArenaTeamName()
|
uint32 RandomPlayerbotFactory::GetBotArenaTeamCount(ArenaType type)
|
||||||
{
|
{
|
||||||
std::string arenaTeamName = "";
|
uint32 count = 0;
|
||||||
|
for (auto const& [id, arenateam] : sArenaTeamMgr->GetArenaTeams())
|
||||||
QueryResult result = CharacterDatabase.Query("SELECT MAX(name_id) FROM playerbots_arena_team_names");
|
|
||||||
if (!result)
|
|
||||||
{
|
{
|
||||||
LOG_ERROR("playerbots", "No more names left for random arena teams");
|
if (arenateam->GetType() == type && IsBotArenaTeam(arenateam))
|
||||||
return arenaTeamName;
|
++count;
|
||||||
}
|
}
|
||||||
|
return count;
|
||||||
Field* fields = result->Fetch();
|
}
|
||||||
uint32 maxId = fields[0].Get<uint32>();
|
|
||||||
|
void RandomPlayerbotFactory::DeleteBotArenaTeams()
|
||||||
uint32 id = urand(0, maxId);
|
{
|
||||||
result = CharacterDatabase.Query(
|
LOG_INFO("playerbots", "Deleting random bot arena teams...");
|
||||||
"SELECT n.name FROM playerbots_arena_team_names n LEFT OUTER JOIN arena_team e ON e.name = n.name "
|
|
||||||
"WHERE e.arenateamid IS NULL AND n.name_id >= {} LIMIT 1",
|
std::vector<uint32> teamsToDisband;
|
||||||
id);
|
for (auto const& [id, arenateam] : sArenaTeamMgr->GetArenaTeams())
|
||||||
|
{
|
||||||
if (!result)
|
if (IsBotArenaTeam(arenateam))
|
||||||
{
|
teamsToDisband.push_back(id);
|
||||||
LOG_ERROR("playerbots", "No more names left for random arena teams");
|
}
|
||||||
return arenaTeamName;
|
|
||||||
}
|
for (uint32 teamId : teamsToDisband)
|
||||||
|
{
|
||||||
fields = result->Fetch();
|
ArenaTeam* team = sArenaTeamMgr->GetArenaTeamById(teamId);
|
||||||
arenaTeamName = fields[0].Get<std::string>();
|
if (team)
|
||||||
|
team->Disband(nullptr);
|
||||||
return arenaTeamName;
|
}
|
||||||
|
|
||||||
|
LOG_INFO("playerbots", "Deleted {} random bot arena teams", teamsToDisband.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string RandomPlayerbotFactory::CreateRandomArenaTeamName()
|
||||||
|
{
|
||||||
|
if (_availableArenaTeamNames.empty())
|
||||||
|
{
|
||||||
|
LOG_ERROR("playerbots", "No more names left for random arena teams");
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string name = std::move(_availableArenaTeamNames.back());
|
||||||
|
_availableArenaTeamNames.pop_back();
|
||||||
|
return name;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,17 +7,17 @@
|
|||||||
#define _PLAYERBOT_RANDOMPLAYERBOTFACTORY_H
|
#define _PLAYERBOT_RANDOMPLAYERBOTFACTORY_H
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "ArenaTeam.h"
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "DBCEnums.h"
|
#include "DBCEnums.h"
|
||||||
|
|
||||||
class Player;
|
class Player;
|
||||||
class WorldSession;
|
class WorldSession;
|
||||||
|
|
||||||
enum ArenaType : uint8;
|
|
||||||
|
|
||||||
class RandomPlayerbotFactory
|
class RandomPlayerbotFactory
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -51,15 +51,22 @@ public:
|
|||||||
|
|
||||||
Player* CreateRandomBot(WorldSession* session, uint8 cls, std::unordered_map<NameRaceAndGender, std::vector<std::string>>& names);
|
Player* CreateRandomBot(WorldSession* session, uint8 cls, std::unordered_map<NameRaceAndGender, std::vector<std::string>>& names);
|
||||||
static void CreateRandomBots();
|
static void CreateRandomBots();
|
||||||
static void CreateRandomArenaTeams(ArenaType slot, uint32 count);
|
|
||||||
static std::string const CreateRandomGuildName();
|
static std::string const CreateRandomGuildName();
|
||||||
static uint32 CalculateTotalAccountCount();
|
static uint32 CalculateTotalAccountCount();
|
||||||
static uint32 CalculateAvailableCharsPerAccount();
|
static uint32 CalculateAvailableCharsPerAccount();
|
||||||
|
|
||||||
|
// Arena team utilities (static — no bot instance needed)
|
||||||
|
static void DeleteBotArenaTeams();
|
||||||
|
static uint32 GetBotArenaTeamCount(ArenaType type);
|
||||||
|
static bool IsBotArenaTeam(ArenaTeam const* team);
|
||||||
|
static void LoadArenaTeamNames();
|
||||||
|
static std::string CreateRandomArenaTeamName();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static bool IsValidRaceClassCombination(uint8 race, uint8 class_, uint32 expansion);
|
static bool IsValidRaceClassCombination(uint8 race, uint8 class_, uint32 expansion);
|
||||||
std::string const CreateRandomBotName(NameRaceAndGender raceAndGender);
|
std::string const CreateRandomBotName(NameRaceAndGender raceAndGender);
|
||||||
static std::string const CreateRandomArenaTeamName();
|
|
||||||
|
static inline std::vector<std::string> _availableArenaTeamNames;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -1763,6 +1763,47 @@ void RandomPlayerbotMgr::Init()
|
|||||||
PlayerbotsDatabase.Execute("DELETE FROM playerbots_random_bots WHERE event = 'add'");
|
PlayerbotsDatabase.Execute("DELETE FROM playerbots_random_bots WHERE event = 'add'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RandomPlayerbotMgr::InitArenaTeams()
|
||||||
|
{
|
||||||
|
if (sPlayerbotAIConfig.deleteRandomBotArenaTeams)
|
||||||
|
{
|
||||||
|
RandomPlayerbotFactory::DeleteBotArenaTeams();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RandomPlayerbotFactory::LoadArenaTeamNames();
|
||||||
|
|
||||||
|
uint32 existing2v2 = RandomPlayerbotFactory::GetBotArenaTeamCount(ARENA_TYPE_2v2);
|
||||||
|
uint32 existing3v3 = RandomPlayerbotFactory::GetBotArenaTeamCount(ARENA_TYPE_3v3);
|
||||||
|
uint32 existing5v5 = RandomPlayerbotFactory::GetBotArenaTeamCount(ARENA_TYPE_5v5);
|
||||||
|
|
||||||
|
auto deficit = [](uint32 existing, uint32 target) -> uint32
|
||||||
|
{
|
||||||
|
return existing < target ? target - existing : 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
arenaCaptainsNeeded[ARENA_TYPE_2v2] = deficit(existing2v2, sPlayerbotAIConfig.randomBotArenaTeam2v2Count);
|
||||||
|
arenaCaptainsNeeded[ARENA_TYPE_3v3] = deficit(existing3v3, sPlayerbotAIConfig.randomBotArenaTeam3v3Count);
|
||||||
|
arenaCaptainsNeeded[ARENA_TYPE_5v5] = deficit(existing5v5, sPlayerbotAIConfig.randomBotArenaTeam5v5Count);
|
||||||
|
|
||||||
|
LOG_INFO("playerbots", "Bot arena teams: 2v2={}/{}, 3v3={}/{}, 5v5={}/{} (captains needed: {}/{}/{})",
|
||||||
|
existing2v2, sPlayerbotAIConfig.randomBotArenaTeam2v2Count,
|
||||||
|
existing3v3, sPlayerbotAIConfig.randomBotArenaTeam3v3Count,
|
||||||
|
existing5v5, sPlayerbotAIConfig.randomBotArenaTeam5v5Count,
|
||||||
|
arenaCaptainsNeeded[ARENA_TYPE_2v2],
|
||||||
|
arenaCaptainsNeeded[ARENA_TYPE_3v3],
|
||||||
|
arenaCaptainsNeeded[ARENA_TYPE_5v5]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RandomPlayerbotMgr::OnBotLoginArenaTeam(Player* bot)
|
||||||
|
{
|
||||||
|
if (!bot)
|
||||||
|
return;
|
||||||
|
|
||||||
|
PlayerbotFactory factory(bot, bot->GetLevel());
|
||||||
|
factory.InitArenaTeam();
|
||||||
|
}
|
||||||
|
|
||||||
void RandomPlayerbotMgr::RandomTeleportForLevel(Player* bot)
|
void RandomPlayerbotMgr::RandomTeleportForLevel(Player* bot)
|
||||||
{
|
{
|
||||||
if (bot->InBattleground())
|
if (bot->InBattleground())
|
||||||
@ -2539,6 +2580,9 @@ void RandomPlayerbotMgr::OnBotLoginInternal(Player* const bot)
|
|||||||
factory.InitGuild();
|
factory.InitGuild();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Assign bot to an arena team if eligible
|
||||||
|
OnBotLoginArenaTeam(bot);
|
||||||
|
|
||||||
if (sPlayerbotAIConfig.randomBotFixedLevel)
|
if (sPlayerbotAIConfig.randomBotFixedLevel)
|
||||||
{
|
{
|
||||||
bot->SetPlayerFlag(PLAYER_FLAGS_NO_XP_GAIN);
|
bot->SetPlayerFlag(PLAYER_FLAGS_NO_XP_GAIN);
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
#ifndef _PLAYERBOT_RANDOMPLAYERBOTMGR_H
|
#ifndef _PLAYERBOT_RANDOMPLAYERBOTMGR_H
|
||||||
#define _PLAYERBOT_RANDOMPLAYERBOTMGR_H
|
#define _PLAYERBOT_RANDOMPLAYERBOTMGR_H
|
||||||
|
|
||||||
|
#include "Battleground.h"
|
||||||
#include "NewRpgInfo.h"
|
#include "NewRpgInfo.h"
|
||||||
#include "ObjectGuid.h"
|
#include "ObjectGuid.h"
|
||||||
#include "PlayerbotMgr.h"
|
#include "PlayerbotMgr.h"
|
||||||
@ -120,6 +121,10 @@ public:
|
|||||||
Player* GetRandomPlayer();
|
Player* GetRandomPlayer();
|
||||||
std::vector<Player*> GetPlayers() { return players; };
|
std::vector<Player*> GetPlayers() { return players; };
|
||||||
PlayerBotMap GetAllBots() { return playerBots; };
|
PlayerBotMap GetAllBots() { return playerBots; };
|
||||||
|
void InitArenaTeams();
|
||||||
|
void OnBotLoginArenaTeam(Player* bot);
|
||||||
|
std::map<ArenaType, uint32> arenaCaptainsNeeded;
|
||||||
|
bool arenaTeamsFull = false;
|
||||||
void PrintStats();
|
void PrintStats();
|
||||||
double GetBuyMultiplier(Player* bot);
|
double GetBuyMultiplier(Player* bot);
|
||||||
double GetSellMultiplier(Player* bot);
|
double GetSellMultiplier(Player* bot);
|
||||||
|
|||||||
@ -681,6 +681,7 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
}
|
}
|
||||||
|
|
||||||
PlayerbotGuildMgr::instance().Init();
|
PlayerbotGuildMgr::instance().Init();
|
||||||
|
sRandomPlayerbotMgr.InitArenaTeams();
|
||||||
sRandomItemMgr.Init();
|
sRandomItemMgr.Init();
|
||||||
sRandomItemMgr.InitAfterAhBot();
|
sRandomItemMgr.InitAfterAhBot();
|
||||||
PlayerbotTextMgr::instance().LoadBotTexts();
|
PlayerbotTextMgr::instance().LoadBotTexts();
|
||||||
|
|||||||
@ -375,14 +375,12 @@ public:
|
|||||||
int32 enableRandomBotTrading;
|
int32 enableRandomBotTrading;
|
||||||
uint32 tweakValue; // Debugging config
|
uint32 tweakValue; // Debugging config
|
||||||
|
|
||||||
uint32 randomBotArenaTeamCount;
|
|
||||||
uint32 randomBotArenaTeamMaxRating;
|
uint32 randomBotArenaTeamMaxRating;
|
||||||
uint32 randomBotArenaTeamMinRating;
|
uint32 randomBotArenaTeamMinRating;
|
||||||
uint32 randomBotArenaTeam2v2Count;
|
uint32 randomBotArenaTeam2v2Count;
|
||||||
uint32 randomBotArenaTeam3v3Count;
|
uint32 randomBotArenaTeam3v3Count;
|
||||||
uint32 randomBotArenaTeam5v5Count;
|
uint32 randomBotArenaTeam5v5Count;
|
||||||
bool deleteRandomBotArenaTeams;
|
bool deleteRandomBotArenaTeams;
|
||||||
std::vector<uint32> randomBotArenaTeams;
|
|
||||||
|
|
||||||
uint32 selfBotLevel;
|
uint32 selfBotLevel;
|
||||||
bool downgradeMaxLevelBot;
|
bool downgradeMaxLevelBot;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user