/* =========================================================================== Copyright (C) 1999-2005 Id Software, Inc. Copyright (C) 2000-2013 Darklegion Development Copyright (C) 2015-2019 GrangerHub This file is part of Tremulous. Tremulous is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. Tremulous is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Tremulous; if not, see =========================================================================== */ // // gameinfo.c // #include "ui_local.h" // // arena and bot info // int ui_numBots; static char *ui_botInfos[MAX_BOTS]; static int ui_numArenas; static char *ui_arenaInfos[MAX_ARENAS]; /* =============== UI_ParseInfos =============== */ int UI_ParseInfos(char *buf, int max, char *infos[]) { char *token; int count; char key[MAX_TOKEN_CHARS]; char info[MAX_INFO_STRING]; count = 0; while (1) { token = COM_Parse(&buf); if (!token[0]) break; if (strcmp(token, "{")) { Com_Printf("Missing { in info file\n"); break; } if (count == max) { Com_Printf("Max infos exceeded\n"); break; } info[0] = '\0'; while (1) { token = COM_ParseExt(&buf, qtrue); if (!token[0]) { Com_Printf("Unexpected end of info file\n"); break; } if (!strcmp(token, "}")) break; Q_strncpyz(key, token, sizeof(key)); token = COM_ParseExt(&buf, qfalse); if (!token[0]) strcpy(token, ""); Info_SetValueForKey(info, key, token); } // NOTE: extra space for arena number infos[count] = UI_Alloc(strlen(info) + strlen("\\num\\") + strlen(va("%d", MAX_ARENAS)) + 1); if (infos[count]) { strcpy(infos[count], info); count++; } } return count; } /* =============== UI_LoadArenasFromFile =============== */ static void UI_LoadArenasFromFile(char *filename) { int len; fileHandle_t f; char buf[MAX_ARENAS_TEXT]; len = trap_FS_FOpenFile(filename, &f, FS_READ); if (!f) { trap_Print(va(S_COLOR_RED "file not found: %s\n", filename)); return; } if (len >= MAX_ARENAS_TEXT) { trap_Print(va(S_COLOR_RED "file too large: %s is %i, max allowed is %i", filename, len, MAX_ARENAS_TEXT)); trap_FS_FCloseFile(f); return; } trap_FS_Read(buf, len, f); buf[len] = 0; trap_FS_FCloseFile(f); ui_numArenas += UI_ParseInfos(buf, MAX_ARENAS - ui_numArenas, &ui_arenaInfos[ui_numArenas]); } /* ================= UI_MapNameCompare ================= */ static int UI_MapNameCompare(const void *a, const void *b) { mapInfo *A = (mapInfo *)a; mapInfo *B = (mapInfo *)b; return Q_stricmp(A->mapName, B->mapName); } /* =============== UI_LoadArenas =============== */ void UI_LoadArenas(void) { int numdirs; char filename[128]; char dirlist[1024]; char *dirptr; int i, n; int dirlen; ui_numArenas = 0; uiInfo.mapCount = 0; // get all arenas from .arena files numdirs = trap_FS_GetFileList("scripts", ".arena", dirlist, 1024); dirptr = dirlist; for (i = 0; i < numdirs; i++, dirptr += dirlen + 1) { dirlen = strlen(dirptr); strcpy(filename, "scripts/"); strcat(filename, dirptr); UI_LoadArenasFromFile(filename); } trap_Print(va("[skipnotify]%i arenas parsed\n", ui_numArenas)); if (UI_OutOfMemory()) trap_Print(S_COLOR_YELLOW "WARNING: not anough memory in pool to load all arenas\n"); for (n = 0; n < ui_numArenas; n++) { uiInfo.mapList[uiInfo.mapCount].cinematic = -1; uiInfo.mapList[uiInfo.mapCount].mapLoadName = String_Alloc(Info_ValueForKey(ui_arenaInfos[n], "map")); uiInfo.mapList[uiInfo.mapCount].mapName = String_Alloc(Info_ValueForKey(ui_arenaInfos[n], "longname")); uiInfo.mapList[uiInfo.mapCount].levelShot = -1; uiInfo.mapList[uiInfo.mapCount].imageName = String_Alloc(va("levelshots/%s", uiInfo.mapList[uiInfo.mapCount].mapLoadName)); uiInfo.mapCount++; if (uiInfo.mapCount >= MAX_MAPS) break; } qsort(uiInfo.mapList, uiInfo.mapCount, sizeof(mapInfo), UI_MapNameCompare); } /* =============== UI_LoadBotsFromFile =============== */ static void UI_LoadBotsFromFile(char *filename) { int len; fileHandle_t f; char buf[MAX_BOTS_TEXT]; len = trap_FS_FOpenFile(filename, &f, FS_READ); if (!f) { trap_Print(va(S_COLOR_RED "file not found: %s\n", filename)); return; } if (len >= MAX_BOTS_TEXT) { trap_Print(va(S_COLOR_RED "file too large: %s is %i, max allowed is %i", filename, len, MAX_BOTS_TEXT)); trap_FS_FCloseFile(f); return; } trap_FS_Read(buf, len, f); buf[len] = 0; trap_FS_FCloseFile(f); COM_Compress(buf); ui_numBots += UI_ParseInfos(buf, MAX_BOTS - ui_numBots, &ui_botInfos[ui_numBots]); } /* =============== UI_LoadBots =============== */ void UI_LoadBots(void) { vmCvar_t botsFile; int numdirs; char filename[128]; char dirlist[1024]; char *dirptr; int i; int dirlen; ui_numBots = 0; trap_Cvar_Register(&botsFile, "g_botsFile", "", CVAR_INIT | CVAR_ROM); if (*botsFile.string) UI_LoadBotsFromFile(botsFile.string); else UI_LoadBotsFromFile("scripts/bots.txt"); // get all bots from .bot files numdirs = trap_FS_GetFileList("scripts", ".bot", dirlist, 1024); dirptr = dirlist; for (i = 0; i < numdirs; i++, dirptr += dirlen + 1) { dirlen = strlen(dirptr); strcpy(filename, "scripts/"); strcat(filename, dirptr); UI_LoadBotsFromFile(filename); } trap_Print(va("%i bots parsed\n", ui_numBots)); } /* =============== UI_GetBotInfoByNumber =============== */ char *UI_GetBotInfoByNumber(int num) { if (num < 0 || num >= ui_numBots) { trap_Print(va(S_COLOR_RED "Invalid bot number: %i\n", num)); return NULL; } return ui_botInfos[num]; } /* =============== UI_GetBotInfoByName =============== */ char *UI_GetBotInfoByName(const char *name) { int n; char *value; for (n = 0; n < ui_numBots; n++) { value = Info_ValueForKey(ui_botInfos[n], "name"); if (!Q_stricmp(value, name)) return ui_botInfos[n]; } return NULL; } int UI_GetNumBots(void) { return ui_numBots; } char *UI_GetBotNameByNumber(int num) { char *info = UI_GetBotInfoByNumber(num); if (info) return Info_ValueForKey(info, "name"); return ""; } void UI_ServerInfo(void) { char info[MAX_INFO_VALUE]; char hostname[MAX_HOSTNAME_LENGTH]; info[0] = '\0'; if (trap_GetConfigString(CS_SERVERINFO, info, sizeof(info))) { trap_Cvar_Set("ui_serverinfo_mapname", Info_ValueForKey(info, "mapname")); trap_Cvar_Set("ui_serverinfo_timelimit", Info_ValueForKey(info, "timelimit")); trap_Cvar_Set("ui_serverinfo_sd", Info_ValueForKey(info, "g_suddenDeathTime")); UI_EscapeEmoticons(hostname, Info_ValueForKey(info, "sv_hostname"), sizeof(hostname)); trap_Cvar_Set("ui_serverinfo_hostname", hostname); trap_Cvar_Set("ui_serverinfo_maxclients", Info_ValueForKey(info, "sv_maxclients")); trap_Cvar_Set("ui_serverinfo_version", Info_ValueForKey(info, "version")); trap_Cvar_Set("ui_serverinfo_unlagged", Info_ValueForKey(info, "g_unlagged")); trap_Cvar_Set("ui_serverinfo_friendlyFire", Info_ValueForKey(info, "g_friendlyFire")); trap_Cvar_Set("ui_serverinfo_friendlyBuildableFire", Info_ValueForKey(info, "g_friendlyBuildableFire")); trap_Cvar_Set("ui_serverinfo_allowdl", Info_ValueForKey(info, "sv_allowdownload")); } }