mirror of
https://github.com/mod-playerbots/mod-playerbots
synced 2025-11-29 15:58:20 +08:00
Add weighted bot to banker teleport logic and config (#1615)
* add weighted bot to banker teleport logic and config * moved banker location lookup tables to top of file
This commit is contained in:
@@ -1014,6 +1014,20 @@ AiPlayerbot.RandomBotMaps = 0,1,530,571
|
|||||||
# Default: 0.25
|
# Default: 0.25
|
||||||
AiPlayerbot.ProbTeleToBankers = 0.25
|
AiPlayerbot.ProbTeleToBankers = 0.25
|
||||||
|
|
||||||
|
# Control probability weights for bots teleporting to Capital city bankers
|
||||||
|
# Sum of weights need not be 100. Set to 0 to disable teleporting to the city.
|
||||||
|
AiPlayerbot.EnableWeightTeleToCityBankers = 1
|
||||||
|
AiPlayerbot.TeleToStormwindWeight = 2
|
||||||
|
AiPlayerbot.TeleToIronforgeWeight = 1
|
||||||
|
AiPlayerbot.TeleToDarnassusWeight = 1
|
||||||
|
AiPlayerbot.TeleToExodarWeight = 1
|
||||||
|
AiPlayerbot.TeleToOrgrimmarWeight = 2
|
||||||
|
AiPlayerbot.TeleToUndercityWeight = 1
|
||||||
|
AiPlayerbot.TeleToThunderBluffWeight = 1
|
||||||
|
AiPlayerbot.TeleToSilvermoonCityWeight = 1
|
||||||
|
AiPlayerbot.TeleToShattrathCityWeight = 1
|
||||||
|
AiPlayerbot.TeleToDalaranWeight = 1
|
||||||
|
|
||||||
# How far randombots are teleported after death
|
# How far randombots are teleported after death
|
||||||
AiPlayerbot.RandomBotTeleportDistance = 100
|
AiPlayerbot.RandomBotTeleportDistance = 100
|
||||||
|
|
||||||
|
|||||||
@@ -139,6 +139,17 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
randomBotMapsAsString = sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotMaps", "0,1,530,571");
|
randomBotMapsAsString = sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotMaps", "0,1,530,571");
|
||||||
LoadList<std::vector<uint32>>(randomBotMapsAsString, randomBotMaps);
|
LoadList<std::vector<uint32>>(randomBotMapsAsString, randomBotMaps);
|
||||||
probTeleToBankers = sConfigMgr->GetOption<float>("AiPlayerbot.ProbTeleToBankers", 0.25f);
|
probTeleToBankers = sConfigMgr->GetOption<float>("AiPlayerbot.ProbTeleToBankers", 0.25f);
|
||||||
|
enableWeightTeleToCityBankers = sConfigMgr->GetOption<bool>("AiPlayerbot.EnableWeightTeleToCityBankers", false);
|
||||||
|
weightTeleToStormwind = sConfigMgr->GetOption<int>("AiPlayerbot.TeleToStormwindWeight", 1);
|
||||||
|
weightTeleToIronforge = sConfigMgr->GetOption<int>("AiPlayerbot.TeleToIronforgeWeight", 1);
|
||||||
|
weightTeleToDarnassus = sConfigMgr->GetOption<int>("AiPlayerbot.TeleToDarnassusWeight", 1);
|
||||||
|
weightTeleToExodar = sConfigMgr->GetOption<int>("AiPlayerbot.TeleToExodarWeight", 1);
|
||||||
|
weightTeleToOrgrimmar = sConfigMgr->GetOption<int>("AiPlayerbot.TeleToOrgrimmarWeight", 1);
|
||||||
|
weightTeleToUndercity = sConfigMgr->GetOption<int>("AiPlayerbot.TeleToUndercityWeight", 1);
|
||||||
|
weightTeleToThunderBluff = sConfigMgr->GetOption<int>("AiPlayerbot.TeleToThunderBluffWeight", 1);
|
||||||
|
weightTeleToSilvermoonCity = sConfigMgr->GetOption<int>("AiPlayerbot.TeleToSilvermoonCityWeight", 1);
|
||||||
|
weightTeleToShattrathCity = sConfigMgr->GetOption<int>("AiPlayerbot.TeleToShattrathCityWeight", 1);
|
||||||
|
weightTeleToDalaran = sConfigMgr->GetOption<int>("AiPlayerbot.TeleToDalaranWeight", 1);
|
||||||
LoadList<std::vector<uint32>>(
|
LoadList<std::vector<uint32>>(
|
||||||
sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotQuestItems",
|
sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotQuestItems",
|
||||||
"6948,5175,5176,5177,5178,16309,12382,13704,11000"),
|
"6948,5175,5176,5177,5178,16309,12382,13704,11000"),
|
||||||
|
|||||||
@@ -102,6 +102,17 @@ public:
|
|||||||
bool botAutologin;
|
bool botAutologin;
|
||||||
std::string randomBotMapsAsString;
|
std::string randomBotMapsAsString;
|
||||||
float probTeleToBankers;
|
float probTeleToBankers;
|
||||||
|
bool enableWeightTeleToCityBankers;
|
||||||
|
int weightTeleToStormwind;
|
||||||
|
int weightTeleToIronforge;
|
||||||
|
int weightTeleToDarnassus;
|
||||||
|
int weightTeleToExodar;
|
||||||
|
int weightTeleToOrgrimmar;
|
||||||
|
int weightTeleToUndercity;
|
||||||
|
int weightTeleToThunderBluff;
|
||||||
|
int weightTeleToSilvermoonCity;
|
||||||
|
int weightTeleToShattrathCity;
|
||||||
|
int weightTeleToDalaran;
|
||||||
std::vector<uint32> randomBotMaps;
|
std::vector<uint32> randomBotMaps;
|
||||||
std::vector<uint32> randomBotQuestItems;
|
std::vector<uint32> randomBotQuestItems;
|
||||||
std::vector<uint32> randomBotAccounts;
|
std::vector<uint32> randomBotAccounts;
|
||||||
|
|||||||
@@ -60,6 +60,48 @@ struct GuidClassRaceInfo
|
|||||||
uint32 rRace;
|
uint32 rRace;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class CityId : uint8 {
|
||||||
|
STORMWIND, IRONFORGE, DARNASSUS, EXODAR,
|
||||||
|
ORGRIMMAR, UNDERCITY, THUNDER_BLUFF, SILVERMOON_CITY,
|
||||||
|
SHATTRATH_CITY, DALARAN
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class FactionId : uint8 { ALLIANCE, HORDE, NEUTRAL };
|
||||||
|
|
||||||
|
// Map of banker entry → city + faction
|
||||||
|
static const std::unordered_map<uint16, std::pair<CityId, FactionId>> bankerToCity = {
|
||||||
|
{2455, {CityId::STORMWIND, FactionId::ALLIANCE}}, {2456, {CityId::STORMWIND, FactionId::ALLIANCE}}, {2457, {CityId::STORMWIND, FactionId::ALLIANCE}},
|
||||||
|
{2460, {CityId::IRONFORGE, FactionId::ALLIANCE}}, {2461, {CityId::IRONFORGE, FactionId::ALLIANCE}}, {5099, {CityId::IRONFORGE, FactionId::ALLIANCE}},
|
||||||
|
{4155, {CityId::DARNASSUS, FactionId::ALLIANCE}}, {4208, {CityId::DARNASSUS, FactionId::ALLIANCE}}, {4209, {CityId::DARNASSUS, FactionId::ALLIANCE}},
|
||||||
|
{17773, {CityId::EXODAR, FactionId::ALLIANCE}}, {18350, {CityId::EXODAR, FactionId::ALLIANCE}}, {16710, {CityId::EXODAR, FactionId::ALLIANCE}},
|
||||||
|
{3320, {CityId::ORGRIMMAR, FactionId::HORDE}}, {3309, {CityId::ORGRIMMAR, FactionId::HORDE}}, {3318, {CityId::ORGRIMMAR, FactionId::HORDE}},
|
||||||
|
{4549, {CityId::UNDERCITY, FactionId::HORDE}}, {2459, {CityId::UNDERCITY, FactionId::HORDE}}, {2458, {CityId::UNDERCITY, FactionId::HORDE}}, {4550, {CityId::UNDERCITY, FactionId::HORDE}},
|
||||||
|
{2996, {CityId::THUNDER_BLUFF, FactionId::HORDE}}, {8356, {CityId::THUNDER_BLUFF, FactionId::HORDE}}, {8357, {CityId::THUNDER_BLUFF, FactionId::HORDE}},
|
||||||
|
{17631, {CityId::SILVERMOON_CITY, FactionId::HORDE}}, {17632, {CityId::SILVERMOON_CITY, FactionId::HORDE}}, {17633, {CityId::SILVERMOON_CITY, FactionId::HORDE}},
|
||||||
|
{16615, {CityId::SILVERMOON_CITY, FactionId::HORDE}}, {16616, {CityId::SILVERMOON_CITY, FactionId::HORDE}}, {16617, {CityId::SILVERMOON_CITY, FactionId::HORDE}},
|
||||||
|
{19246, {CityId::SHATTRATH_CITY, FactionId::NEUTRAL}}, {19338, {CityId::SHATTRATH_CITY, FactionId::NEUTRAL}},
|
||||||
|
{19034, {CityId::SHATTRATH_CITY, FactionId::NEUTRAL}}, {19318, {CityId::SHATTRATH_CITY, FactionId::NEUTRAL}},
|
||||||
|
{30604, {CityId::DALARAN, FactionId::NEUTRAL}}, {30605, {CityId::DALARAN, FactionId::NEUTRAL}}, {30607, {CityId::DALARAN, FactionId::NEUTRAL}},
|
||||||
|
{28675, {CityId::DALARAN, FactionId::NEUTRAL}}, {28676, {CityId::DALARAN, FactionId::NEUTRAL}}, {28677, {CityId::DALARAN, FactionId::NEUTRAL}}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Map of city → available banker entries
|
||||||
|
static const std::unordered_map<CityId, std::vector<uint16>> cityToBankers = {
|
||||||
|
{CityId::STORMWIND, {2455, 2456, 2457}},
|
||||||
|
{CityId::IRONFORGE, {2460, 2461, 5099}},
|
||||||
|
{CityId::DARNASSUS, {4155, 4208, 4209}},
|
||||||
|
{CityId::EXODAR, {17773, 18350, 16710}},
|
||||||
|
{CityId::ORGRIMMAR, {3320, 3309, 3318}},
|
||||||
|
{CityId::UNDERCITY, {4549, 2459, 2458, 4550}},
|
||||||
|
{CityId::THUNDER_BLUFF, {2996, 8356, 8357}},
|
||||||
|
{CityId::SILVERMOON_CITY, {17631, 17632, 17633, 16615, 16616, 16617}},
|
||||||
|
{CityId::SHATTRATH_CITY, {19246, 19338, 19034, 19318}},
|
||||||
|
{CityId::DALARAN, {30604, 30605, 30607, 28675, 28676, 28677, 29530}}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Quick lookup map: banker entry → location
|
||||||
|
static std::unordered_map<uint32, WorldLocation> bankerEntryToLocation;
|
||||||
|
|
||||||
void PrintStatsThread() { sRandomPlayerbotMgr->PrintStats(); }
|
void PrintStatsThread() { sRandomPlayerbotMgr->PrintStats(); }
|
||||||
|
|
||||||
void activatePrintStatsThread()
|
void activatePrintStatsThread()
|
||||||
@@ -1660,11 +1702,6 @@ void RandomPlayerbotMgr::RandomTeleport(Player* bot, std::vector<WorldLocation>&
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tlocs.empty())
|
|
||||||
{
|
|
||||||
LOG_DEBUG("playerbots", "Cannot teleport bot {} - no locations available", bot->GetName().c_str());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
PerformanceMonitorOperation* pmo = sPerformanceMonitor->start(PERF_MON_RNDBOT, "RandomTeleportByLocations");
|
PerformanceMonitorOperation* pmo = sPerformanceMonitor->start(PERF_MON_RNDBOT, "RandomTeleportByLocations");
|
||||||
|
|
||||||
@@ -2021,7 +2058,8 @@ void RandomPlayerbotMgr::PrepareTeleportCache()
|
|||||||
"position_y, "
|
"position_y, "
|
||||||
"position_z, "
|
"position_z, "
|
||||||
"orientation, "
|
"orientation, "
|
||||||
"t.minlevel "
|
"t.minlevel, "
|
||||||
|
"t.entry "
|
||||||
"FROM "
|
"FROM "
|
||||||
"creature c "
|
"creature c "
|
||||||
"INNER JOIN creature_template t on c.id1 = t.entry "
|
"INNER JOIN creature_template t on c.id1 = t.entry "
|
||||||
@@ -2048,27 +2086,30 @@ void RandomPlayerbotMgr::PrepareTeleportCache()
|
|||||||
float z = fields[3].Get<float>();
|
float z = fields[3].Get<float>();
|
||||||
float orient = fields[4].Get<float>();
|
float orient = fields[4].Get<float>();
|
||||||
uint32 level = fields[5].Get<uint32>();
|
uint32 level = fields[5].Get<uint32>();
|
||||||
WorldLocation loc(mapId, x + cos(orient) * 6.0f, y + sin(orient) * 6.0f, z + 2.0f, orient + M_PI);
|
uint32 entry = fields[6].Get<uint32>();
|
||||||
|
BankerLocation bLoc;
|
||||||
|
bLoc.loc = WorldLocation(mapId, x + cos(orient) * 6.0f, y + sin(orient) * 6.0f, z + 2.0f, orient + M_PI);
|
||||||
|
bLoc.entry = entry;
|
||||||
collected_locs++;
|
collected_locs++;
|
||||||
for (int32 l = 1; l <= maxLevel; l++)
|
for (int32 l = 1; l <= maxLevel; l++)
|
||||||
{
|
{
|
||||||
if (l <= 60 && level >= 60)
|
// Bots 1-60 go to base game bankers (all have minlevel 30 or 45)
|
||||||
|
if (l <=60 && level > 45)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (l <= 70 && level >= 70)
|
// Bots 61-70 go to Shattrath bankers (all have minlevel 60 or 70)
|
||||||
|
if ((l >=61 && l <=70) && (level < 60 || level > 70))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (l >= 70 && level >= 60 && level <= 70)
|
// Bots 71+ go to Dalaran bankers (all have minlevel 75)
|
||||||
|
if ((l >=71) && level != 75)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (l >= 30 && level <= 30)
|
bankerLocsPerLevelCache[(uint8)l].push_back(bLoc);
|
||||||
{
|
bankerEntryToLocation[bLoc.entry] = bLoc.loc;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
bankerLocsPerLevelCache[(uint8)l].push_back(loc);
|
|
||||||
}
|
}
|
||||||
} while (results->NextRow());
|
} while (results->NextRow());
|
||||||
}
|
}
|
||||||
@@ -2138,11 +2179,92 @@ void RandomPlayerbotMgr::RandomTeleportForLevel(Player* bot)
|
|||||||
locs = IsAlliance(race) ? &allianceStarterPerLevelCache[level] : &hordeStarterPerLevelCache[level];
|
locs = IsAlliance(race) ? &allianceStarterPerLevelCache[level] : &hordeStarterPerLevelCache[level];
|
||||||
else
|
else
|
||||||
locs = &locsPerLevelCache[level];
|
locs = &locsPerLevelCache[level];
|
||||||
LOG_DEBUG("playerbots", "Random teleporting bot {} for level {} ({} locations available)", bot->GetName().c_str(),
|
|
||||||
bot->GetLevel(), locs->size());
|
|
||||||
if (level >= 10 && urand(0, 100) < sPlayerbotAIConfig->probTeleToBankers * 100)
|
if (level >= 10 && urand(0, 100) < sPlayerbotAIConfig->probTeleToBankers * 100)
|
||||||
{
|
{
|
||||||
RandomTeleport(bot, bankerLocsPerLevelCache[level], true);
|
std::vector<WorldLocation> fallbackLocs;
|
||||||
|
for (auto& bLoc : bankerLocsPerLevelCache[level])
|
||||||
|
fallbackLocs.push_back(bLoc.loc);
|
||||||
|
|
||||||
|
if (!sPlayerbotAIConfig->enableWeightTeleToCityBankers)
|
||||||
|
{
|
||||||
|
RandomTeleport(bot, fallbackLocs, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect valid cities based on bot faction.
|
||||||
|
std::unordered_set<CityId> validBankerCities;
|
||||||
|
for (auto& loc : bankerLocsPerLevelCache[level])
|
||||||
|
{
|
||||||
|
auto cityIt = bankerToCity.find(loc.entry);
|
||||||
|
if (cityIt == bankerToCity.end()) continue;
|
||||||
|
|
||||||
|
CityId cityId = cityIt->second.first;
|
||||||
|
FactionId cityFactionId = cityIt->second.second;
|
||||||
|
|
||||||
|
if ((IsAlliance(bot->getRace()) && cityFactionId == FactionId::ALLIANCE) ||
|
||||||
|
(!IsAlliance(bot->getRace()) && cityFactionId == FactionId::HORDE) ||
|
||||||
|
(cityFactionId == FactionId::NEUTRAL))
|
||||||
|
{
|
||||||
|
validBankerCities.insert(cityId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback if no valid cities
|
||||||
|
if (validBankerCities.empty())
|
||||||
|
{
|
||||||
|
RandomTeleport(bot, fallbackLocs, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply weights to valid cities
|
||||||
|
std::vector<CityId> weightedCities;
|
||||||
|
for (CityId city : validBankerCities)
|
||||||
|
{
|
||||||
|
int weight = 0;
|
||||||
|
switch (city)
|
||||||
|
{
|
||||||
|
case CityId::STORMWIND: weight = sPlayerbotAIConfig->weightTeleToStormwind; break;
|
||||||
|
case CityId::IRONFORGE: weight = sPlayerbotAIConfig->weightTeleToIronforge; break;
|
||||||
|
case CityId::DARNASSUS: weight = sPlayerbotAIConfig->weightTeleToDarnassus; break;
|
||||||
|
case CityId::EXODAR: weight = sPlayerbotAIConfig->weightTeleToExodar; break;
|
||||||
|
case CityId::ORGRIMMAR: weight = sPlayerbotAIConfig->weightTeleToOrgrimmar; break;
|
||||||
|
case CityId::UNDERCITY: weight = sPlayerbotAIConfig->weightTeleToUndercity; break;
|
||||||
|
case CityId::THUNDER_BLUFF: weight = sPlayerbotAIConfig->weightTeleToThunderBluff; break;
|
||||||
|
case CityId::SILVERMOON_CITY: weight = sPlayerbotAIConfig->weightTeleToSilvermoonCity; break;
|
||||||
|
case CityId::SHATTRATH_CITY: weight = sPlayerbotAIConfig->weightTeleToShattrathCity; break;
|
||||||
|
case CityId::DALARAN: weight = sPlayerbotAIConfig->weightTeleToDalaran; break;
|
||||||
|
default: weight = 0; break;
|
||||||
|
}
|
||||||
|
if (weight <= 0) continue;
|
||||||
|
|
||||||
|
for (int i = 0; i < weight; ++i)
|
||||||
|
{
|
||||||
|
weightedCities.push_back(city);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback if no valid cities
|
||||||
|
if (weightedCities.empty())
|
||||||
|
{
|
||||||
|
RandomTeleport(bot, fallbackLocs, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pick a weighted city randomly, then a random banker in that city
|
||||||
|
// then teleport to that banker
|
||||||
|
CityId selectedCity = weightedCities[urand(0, weightedCities.size() - 1)];
|
||||||
|
const auto& bankers = cityToBankers.at(selectedCity);
|
||||||
|
uint32 selectedBankerEntry = bankers[urand(0, bankers.size() - 1)];
|
||||||
|
auto locIt = bankerEntryToLocation.find(selectedBankerEntry);
|
||||||
|
if (locIt != bankerEntryToLocation.end())
|
||||||
|
{
|
||||||
|
std::vector<WorldLocation> teleportTarget = { locIt->second };
|
||||||
|
RandomTeleport(bot, teleportTarget, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback if something went wrong
|
||||||
|
RandomTeleport(bot, *locs);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -183,7 +183,11 @@ public:
|
|||||||
bool InsideBracket(uint32 val) { return val >= low && val <= high; }
|
bool InsideBracket(uint32 val) { return val >= low && val <= high; }
|
||||||
};
|
};
|
||||||
std::map<uint32, LevelBracket> zone2LevelBracket;
|
std::map<uint32, LevelBracket> zone2LevelBracket;
|
||||||
std::map<uint8, std::vector<WorldLocation>> bankerLocsPerLevelCache;
|
struct BankerLocation {
|
||||||
|
WorldLocation loc;
|
||||||
|
uint32 entry;
|
||||||
|
};
|
||||||
|
std::map<uint8, std::vector<BankerLocation>> bankerLocsPerLevelCache;
|
||||||
|
|
||||||
// Account type management
|
// Account type management
|
||||||
void AssignAccountTypes();
|
void AssignAccountTypes();
|
||||||
|
|||||||
Reference in New Issue
Block a user