/** * Sourcemod 1.7 Plugin Template */ #pragma semicolon 1 #include #include #include #pragma newdecls required #define PLUGIN_VERSION "0.1.2" public Plugin myinfo = { name = "[CSRD] Bot Names", author = "nosoop", description = "Pulls bot names from a database.", version = PLUGIN_VERSION, url = "localhost" } Database g_NameDatabase; DBStatement g_hGetBotNames; /** * We use a stack so players can't force reconnecting bots to get new names * An ArrayList would work just as well, too. */ ArrayStack g_BotNames; char g_OriginalBotName[MAXPLAYERS+1][MAX_NAME_LENGTH]; public void OnPluginStart() { char error[256]; g_NameDatabase = SQLite_UseDatabase("bot-names", error, sizeof(error)); g_hGetBotNames = SQL_PrepareQuery(g_NameDatabase, "SELECT name FROM namelist ORDER BY random() LIMIT ?;", error, sizeof(error)); if (!g_hGetBotNames) { SetFailState("Failed to get bot names from database: %s", error); } g_BotNames = new ArrayStack(ByteCountToCells(MAX_NAME_LENGTH + 1)); } public void OnPluginEnd() { delete g_hGetBotNames; delete g_NameDatabase; } public void OnMapStart() { // deal with late loads just to be safe ArrayList usedBotNames = new ArrayList(ByteCountToCells(MAX_NAME_LENGTH + 1)); int nExistingBots; for (int i = 1; i <= MaxClients; i++) { if (IsClientInGame(i) && IsFakeClient(i)) { char name[MAX_NAME_LENGTH]; GetClientName(i, name, sizeof(name)); usedBotNames.PushString(name); nExistingBots++; } } // use database g_hGetBotNames.BindInt(0, MaxClients + nExistingBots); SQL_Execute(g_hGetBotNames); while (SQL_FetchRow(g_hGetBotNames)) { char name[MAX_NAME_LENGTH]; SQL_FetchString(g_hGetBotNames, 0, name, sizeof(name)); if (usedBotNames.FindString(name) == -1) { g_BotNames.PushString(name); } } delete usedBotNames; } public void OnMapEnd() { // empty the bot name stack EmptyStack(g_BotNames); for (int i = 1; i <= MAXPLAYERS; i++) { g_OriginalBotName[i] = ""; } } /** * Sets the name of a freshly-added bot. */ public int Bot_OnBotAdd(TFClassType &class, TFTeam &team, int &difficulty, char name[MAX_NAME_LENGTH]) { // pop the name off the stack if (strlen(name) == 0 && !g_BotNames.Empty) { g_BotNames.PopString(name, MAX_NAME_LENGTH); } } /** * Store the bot's name at the time of connection. * We'll assume it's a valid name from the pool. */ public void OnClientConnected(int client) { if (IsFakeClient(client)) { GetClientName(client, g_OriginalBotName[client], sizeof(g_OriginalBotName[])); } } /** * Returns the bot name to the name stack. */ public void OnClientDisconnect(int client) { if (IsFakeClient(client)) { char name[MAX_NAME_LENGTH]; if (strlen(g_OriginalBotName[client]) > 0) { name = g_OriginalBotName[client]; g_OriginalBotName[client] = ""; g_BotNames.PushString(name); } /** * else plugin got reloaded or a TFBot snuck in so we have no idea what's up * don't worry about them */ } } /** * Empties an ArrayStack. */ stock int EmptyStack(ArrayStack stack) { int nPopped; while (PopStack(stack)) { nPopped++; } return nPopped; }