rpgxef/code/ui/ui_gameinfo.c

810 lines
16 KiB
C
Raw Normal View History

// Copyright (C) 1999-2000 Id Software, Inc.
//
//
// gameinfo.c
//
#include "ui_local.h"
#include "ui_logger.h"
//
// arena and bot info
//
2014-11-08 10:37:24 +00:00
enum ui_gameinfoLimits_e {
DIRLIST_SIZE = 16384,
POOLSIZE = 48 * DIRLIST_SIZE
};
//#define POOLSIZE 128 * 1024
2014-11-08 10:37:24 +00:00
int32_t ui_numBots;
static char* ui_botInfos[MAX_BOTS];
2014-11-08 10:37:24 +00:00
static int32_t ui_numArenas;
static char* ui_arenaInfos[MAX_ARENAS];
2014-11-08 10:37:24 +00:00
static int32_t ui_numSinglePlayerArenas;
static int32_t ui_numSpecialSinglePlayerArenas;
2014-11-08 10:37:24 +00:00
static char dirlist[DIRLIST_SIZE];
2014-11-08 10:37:24 +00:00
static char memoryPool[POOLSIZE];
static int32_t allocPoint, outOfMemory;
/*
===============
UI_Alloc
===============
*/
2014-11-08 10:37:24 +00:00
void *UI_Alloc(int32_t size) {
UI_LogFuncBegin();
char *p;
2014-11-08 10:37:24 +00:00
if (allocPoint + size > POOLSIZE) {
outOfMemory = qtrue;
UI_LogFuncEnd();
return NULL;
}
p = &memoryPool[allocPoint];
2014-11-08 10:37:24 +00:00
allocPoint += (size + 31) & ~31;
UI_LogFuncEnd();
return p;
}
/*
===============
UI_InitMemory
===============
*/
2014-11-08 10:37:24 +00:00
void UI_InitMemory(void) {
UI_LogFuncBegin();
allocPoint = 0;
outOfMemory = qfalse;
UI_LogFuncEnd();
}
/*
===============
UI_ParseInfos
===============
*/
2014-11-08 10:37:24 +00:00
int32_t UI_ParseInfos(char *buf, int32_t max, char *infos[]) {
UI_LogFuncBegin();
char *token;
int32_t count;
char key[MAX_TOKEN_CHARS];
char info[MAX_INFO_STRING];
count = 0;
2014-11-08 10:37:24 +00:00
while (1) {
token = COM_Parse(&buf);
if (!token[0]) {
break;
}
2014-11-08 10:37:24 +00:00
if (strcmp(token, "{")) {
UI_Logger(LL_ERROR, "Missing { in info file\n");
break;
}
2014-11-08 10:37:24 +00:00
if (count == max) {
UI_Logger(LL_ERROR, "Max infos exceeded\n");
break;
}
info[0] = '\0';
2014-11-08 10:37:24 +00:00
while (1) {
token = COM_ParseExt(&buf, qtrue);
if (!token[0]) {
UI_Logger(LL_ERROR, "Unexpected end of info file\n");
break;
}
2014-11-08 10:37:24 +00:00
if (!strcmp(token, "}")) {
break;
}
2014-11-08 10:37:24 +00:00
Q_strncpyz(key, token, sizeof(key));
2014-11-08 10:37:24 +00:00
token = COM_ParseExt(&buf, qfalse);
if (!token[0]) {
strcpy(token, "<NULL>");
}
2014-11-08 10:37:24 +00:00
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++;
}
}
UI_LogFuncEnd();
return count;
}
/*
===============
UI_LoadArenasFromFile
===============
*/
2014-11-08 10:37:24 +00:00
static void UI_LoadArenasFromFile(char *filename) {
UI_LogFuncBegin();
int32_t len;
fileHandle_t f;
char buf[MAX_ARENAS_TEXT];
2014-11-08 10:37:24 +00:00
len = trap_FS_FOpenFile(filename, &f, FS_READ);
if (!f) {
trap_Print(va(S_COLOR_RED "file not found: %s\n", filename));
UI_LogFuncEnd();
return;
}
2014-11-08 10:37:24 +00:00
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);
UI_LogFuncEnd();
return;
}
2014-11-08 10:37:24 +00:00
trap_FS_Read(buf, len, f);
buf[len] = 0;
2014-11-08 10:37:24 +00:00
trap_FS_FCloseFile(f);
2014-11-08 10:37:24 +00:00
ui_numArenas += UI_ParseInfos(buf, MAX_ARENAS - ui_numArenas, &ui_arenaInfos[ui_numArenas]);
}
/*
===============
UI_LoadArenas
===============
*/
2014-11-08 10:37:24 +00:00
static void UI_LoadArenas(void) {
UI_LogFuncBegin();
int32_t numdirs;
vmCvar_t arenasFile;
char filename[128];
char* dirptr;
int32_t i, n;
int32_t dirlen;
char *type;
char *tag;
int32_t singlePlayerNum, specialNum, otherNum;
ui_numArenas = 0;
2014-11-08 10:37:24 +00:00
trap_Cvar_Register(&arenasFile, "g_arenasFile", "", CVAR_INIT | CVAR_ROM);
if (*arenasFile.string)
{
UI_LoadArenasFromFile(arenasFile.string);
}
else
{
UI_LoadArenasFromFile("scripts/arenas.txt");
}
// get all arenas from .arena files
2014-11-08 10:37:24 +00:00
numdirs = trap_FS_GetFileList("scripts", ".arena", dirlist, DIRLIST_SIZE);
dirptr = dirlist;
for (i = 0; i < numdirs && ui_numArenas < 1024; i++, dirptr += dirlen + 1)
{
dirlen = strlen(dirptr);
strcpy(filename, "scripts/");
strcat(filename, dirptr);
UI_LoadArenasFromFile(filename);
}
2014-11-08 10:37:24 +00:00
trap_Print(va("%i arenas parsed\n", ui_numArenas));
if (outOfMemory) trap_Print(S_COLOR_YELLOW"WARNING: not enough memory in pool to load all arenas\n");
// set initial numbers
2014-11-08 10:37:24 +00:00
for (n = 0; n < ui_numArenas; n++) {
Info_SetValueForKey(ui_arenaInfos[n], "num", va("%i", n));
}
// go through and count single players levels
ui_numSinglePlayerArenas = 0;
ui_numSpecialSinglePlayerArenas = 0;
2014-11-08 10:37:24 +00:00
for (n = 0; n < ui_numArenas; n++) {
// determine type
2014-11-08 10:37:24 +00:00
type = Info_ValueForKey(ui_arenaInfos[n], "type");
// if no type specified, it will be treated as "ffa"
2014-11-08 10:37:24 +00:00
if (!*type) {
continue;
}
2014-11-08 10:37:24 +00:00
if (strstr(type, "single")) {
// check for special single player arenas (training, final)
2014-11-08 10:37:24 +00:00
tag = Info_ValueForKey(ui_arenaInfos[n], "special");
if (*tag) {
ui_numSpecialSinglePlayerArenas++;
continue;
}
ui_numSinglePlayerArenas++;
}
}
// go through once more and assign number to the levels
singlePlayerNum = 0;
specialNum = singlePlayerNum + ui_numSinglePlayerArenas;
otherNum = specialNum + ui_numSpecialSinglePlayerArenas;
2014-11-08 10:37:24 +00:00
for (n = 0; n < ui_numArenas; n++) {
// determine type
2014-11-08 10:37:24 +00:00
type = Info_ValueForKey(ui_arenaInfos[n], "type");
// if no type specified, it will be treated as "ffa"
2014-11-08 10:37:24 +00:00
if (*type) {
if (strstr(type, "single")) {
// check for special single player arenas (training, final)
2014-11-08 10:37:24 +00:00
tag = Info_ValueForKey(ui_arenaInfos[n], "special");
if (*tag) {
Info_SetValueForKey(ui_arenaInfos[n], "num", va("%i", specialNum++));
continue;
}
2014-11-08 10:37:24 +00:00
Info_SetValueForKey(ui_arenaInfos[n], "num", va("%i", singlePlayerNum++));
continue;
}
}
2014-11-08 10:37:24 +00:00
Info_SetValueForKey(ui_arenaInfos[n], "num", va("%i", otherNum++));
}
}
/*
===============
UI_GetArenaInfoByNumber
===============
*/
2014-11-08 10:37:24 +00:00
const char *UI_GetArenaInfoByNumber(int32_t num) {
UI_LogFuncBegin();
int32_t n;
char *value;
2014-11-08 10:37:24 +00:00
if (num < 0 || num >= ui_numArenas) {
trap_Print(va(S_COLOR_RED "Invalid arena number: %i\n", num));
UI_LogFuncEnd();
return NULL;
}
2014-11-08 10:37:24 +00:00
for (n = 0; n < ui_numArenas; n++) {
value = Info_ValueForKey(ui_arenaInfos[n], "num");
if (*value && atoi(value) == num) {
UI_LogFuncEnd();
return ui_arenaInfos[n];
}
}
UI_LogFuncEnd();
return NULL;
}
/*
===============
UI_GetArenaInfoByMap
===============
*/
2014-11-08 10:37:24 +00:00
const char *UI_GetArenaInfoByMap(const char *map) {
UI_LogFuncBegin();
int32_t n;
2014-11-08 10:37:24 +00:00
for (n = 0; n < ui_numArenas; n++) {
if (Q_stricmp(Info_ValueForKey(ui_arenaInfos[n], "map"), map) == 0) {
UI_LogFuncEnd();
return ui_arenaInfos[n];
}
}
UI_LogFuncEnd();
return NULL;
}
/*
===============
UI_GetSpecialArenaInfo
===============
*/
2014-11-08 10:37:24 +00:00
const char *UI_GetSpecialArenaInfo(const char *tag) {
UI_LogFuncBegin();
int32_t n;
2014-11-08 10:37:24 +00:00
for (n = 0; n < ui_numArenas; n++) {
if (Q_stricmp(Info_ValueForKey(ui_arenaInfos[n], "special"), tag) == 0) {
UI_LogFuncEnd();
return ui_arenaInfos[n];
}
}
UI_LogFuncEnd();
return NULL;
}
/*
===============
UI_LoadBotsFromFile
===============
*/
2014-11-08 10:37:24 +00:00
static void UI_LoadBotsFromFile(char *filename) {
UI_LogFuncBegin();
int32_t len;
fileHandle_t f;
char buf[MAX_BOTS_TEXT];
2014-11-08 10:37:24 +00:00
len = trap_FS_FOpenFile(filename, &f, FS_READ);
if (!f) {
trap_Print(va(S_COLOR_RED "file not found: %s\n", filename));
UI_LogFuncEnd();
return;
}
2014-11-08 10:37:24 +00:00
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);
UI_LogFuncEnd();
return;
}
2014-11-08 10:37:24 +00:00
trap_FS_Read(buf, len, f);
buf[len] = 0;
2014-11-08 10:37:24 +00:00
trap_FS_FCloseFile(f);
2014-11-08 10:37:24 +00:00
ui_numBots += UI_ParseInfos(buf, MAX_BOTS - ui_numBots, &ui_botInfos[ui_numBots]);
if (outOfMemory) trap_Print(S_COLOR_YELLOW"WARNING: not enough memory in pool to load all bots\n");
UI_LogFuncEnd();
}
/*
===============
UI_LoadBots
===============
*/
2014-11-08 10:37:24 +00:00
static void UI_LoadBots(void) {
UI_LogFuncBegin();
vmCvar_t botsFile;
int32_t numdirs;
char filename[128];
char* dirptr;
int32_t i;
int32_t dirlen;
ui_numBots = 0;
2014-11-08 10:37:24 +00:00
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
2014-11-08 10:37:24 +00:00
numdirs = trap_FS_GetFileList("scripts", ".bot", dirlist, DIRLIST_SIZE);
dirptr = dirlist;
for (i = 0; i < numdirs; i++, dirptr += dirlen + 1)
{
dirlen = strlen(dirptr);
strcpy(filename, "scripts/");
strcat(filename, dirptr);
UI_LoadBotsFromFile(filename);
}
2014-11-08 10:37:24 +00:00
trap_Print(va("%i bots parsed\n", ui_numBots));
UI_LogFuncEnd();
}
/*
===============
UI_GetBotInfoByNumber
===============
*/
2014-11-08 10:37:24 +00:00
char *UI_GetBotInfoByNumber(int32_t num) {
UI_LogFuncBegin();
2014-11-08 10:37:24 +00:00
if (num < 0 || num >= ui_numBots) {
trap_Print(va(S_COLOR_RED "Invalid bot number: %i\n", num));
UI_LogFuncEnd();
return NULL;
}
UI_LogFuncEnd();
return ui_botInfos[num];
}
/*
===============
UI_GetBotInfoByName
===============
*/
2014-11-08 10:37:24 +00:00
char *UI_GetBotInfoByName(const char *name) {
UI_LogFuncBegin();
int32_t n;
char *value;
2014-11-08 10:37:24 +00:00
for (n = 0; n < ui_numBots; n++) {
value = Info_ValueForKey(ui_botInfos[n], "name");
if (!Q_stricmp(value, name)) {
UI_LogFuncEnd();
return ui_botInfos[n];
}
}
UI_LogFuncEnd();
return NULL;
}
//
// single player game info
//
/*
===============
UI_GetBestScore
Returns the player's best finish on a given level, 0 if the have not played the level
===============
*/
2014-11-08 10:37:24 +00:00
void UI_GetBestScore(int32_t level, int32_t *score, int32_t *skill) {
UI_LogFuncBegin();
int32_t n;
int32_t skillScore;
int32_t bestScore;
int32_t bestScoreSkill;
char arenaKey[16];
char scores[MAX_INFO_VALUE];
2014-11-08 10:37:24 +00:00
if (!score || !skill) {
UI_LogFuncEnd();
return;
}
2014-11-08 10:37:24 +00:00
if (level < 0 || level > ui_numArenas) {
UI_LogFuncEnd();
return;
}
bestScore = 0;
bestScoreSkill = 0;
2014-11-08 10:37:24 +00:00
for (n = 1; n <= 5; n++) {
trap_Cvar_VariableStringBuffer(va("g_spScores%i", n), scores, MAX_INFO_VALUE);
2014-11-08 10:37:24 +00:00
Com_sprintf(arenaKey, sizeof(arenaKey), "l%i", level);
skillScore = atoi(Info_ValueForKey(scores, arenaKey));
2014-11-08 10:37:24 +00:00
if (skillScore < 1 || skillScore > 8) {
continue;
}
2014-11-08 10:37:24 +00:00
if (!bestScore || skillScore <= bestScore) {
bestScore = skillScore;
bestScoreSkill = n;
}
}
*score = bestScore;
*skill = bestScoreSkill;
UI_LogFuncEnd();
}
/*
===============
UI_SetBestScore
Set the player's best finish for a level
===============
*/
2014-11-08 10:37:24 +00:00
void UI_SetBestScore(int32_t level, int32_t score) {
UI_LogFuncBegin();
int32_t skill;
int32_t oldScore;
char arenaKey[16];
char scores[MAX_INFO_VALUE];
// validate score
2014-11-08 10:37:24 +00:00
if (score < 1 || score > 8) {
UI_LogFuncEnd();
return;
}
// validate skill
2014-11-08 10:37:24 +00:00
skill = (int32_t)trap_Cvar_VariableValue("g_spSkill");
if (skill < 1 || skill > 5) {
UI_LogFuncEnd();
return;
}
// get scores
2014-11-08 10:37:24 +00:00
trap_Cvar_VariableStringBuffer(va("g_spScores%i", skill), scores, MAX_INFO_VALUE);
// see if this is better
2014-11-08 10:37:24 +00:00
Com_sprintf(arenaKey, sizeof(arenaKey), "l%i", level);
oldScore = atoi(Info_ValueForKey(scores, arenaKey));
if (oldScore && oldScore <= score) {
UI_LogFuncEnd();
return;
}
// update scores
2014-11-08 10:37:24 +00:00
Info_SetValueForKey(scores, arenaKey, va("%i", score));
trap_Cvar_Set(va("g_spScores%i", skill), scores);
UI_LogFuncEnd();
}
/*
===============
UI_LogAwardData
===============
*/
2014-11-08 10:37:24 +00:00
void UI_LogAwardData(int32_t award, int32_t data) {
UI_LogFuncBegin();
char key[16];
char awardData[MAX_INFO_VALUE];
int32_t oldValue;
2014-11-08 10:37:24 +00:00
if (data == 0) {
UI_LogFuncEnd();
return;
}
2014-11-08 10:37:24 +00:00
if (award >= AWARD_MAX) {
trap_Print(va(S_COLOR_RED "Bad award %i in UI_LogAwardData\n", award));
UI_LogFuncEnd();
return;
}
2014-11-08 10:37:24 +00:00
trap_Cvar_VariableStringBuffer("g_spAwards", awardData, sizeof(awardData));
2014-11-08 10:37:24 +00:00
Com_sprintf(key, sizeof(key), "a%i", award);
oldValue = atoi(Info_ValueForKey(awardData, key));
2014-11-08 10:37:24 +00:00
Info_SetValueForKey(awardData, key, va("%i", oldValue + data));
trap_Cvar_Set("g_spAwards", awardData);
}
/*
===============
UI_GetAwardLevel
===============
*/
2014-11-08 10:37:24 +00:00
int32_t UI_GetAwardLevel(int32_t award) {
UI_LogFuncBegin();
char key[16];
char awardData[MAX_INFO_VALUE];
2014-11-08 10:37:24 +00:00
trap_Cvar_VariableStringBuffer("g_spAwards", awardData, sizeof(awardData));
2014-11-08 10:37:24 +00:00
Com_sprintf(key, sizeof(key), "a%i", award);
UI_LogFuncEnd();
2014-11-08 10:37:24 +00:00
return atoi(Info_ValueForKey(awardData, key));
}
/*
===============
UI_TierCompleted
===============
*/
2014-11-08 10:37:24 +00:00
int32_t UI_TierCompleted(int32_t levelWon) {
UI_LogFuncBegin();
int32_t level;
int32_t n;
int32_t tier;
int32_t score;
int32_t skill;
int32_t maxarenas;
const char *info;
tier = levelWon / ARENAS_PER_TIER;
level = tier * ARENAS_PER_TIER;
2014-11-08 10:37:24 +00:00
if (tier == UI_GetNumSPTiers()) {
info = UI_GetSpecialArenaInfo("training");
if (levelWon == atoi(Info_ValueForKey(info, "num"))) {
UI_LogFuncEnd();
return 0;
}
2014-11-08 10:37:24 +00:00
info = UI_GetSpecialArenaInfo("final");
if (!info || levelWon == atoi(Info_ValueForKey(info, "num"))) {
UI_LogFuncEnd();
return tier + 1;
}
UI_LogFuncEnd();
return -1;
}
if (uis.demoversion) {
maxarenas = 2;
2014-11-08 10:37:24 +00:00
}
else {
maxarenas = ARENAS_PER_TIER;
}
2014-11-08 10:37:24 +00:00
for (n = 0; n < maxarenas; n++, level++) {
UI_GetBestScore(level, &score, &skill);
if (score != 1) {
UI_LogFuncEnd();
return -1;
}
}
UI_LogFuncEnd();
return tier + 1;
}
/*
===============
UI_GetCurrentGame
Returns the next level the player has not won
===============
*/
2014-11-08 10:37:24 +00:00
int32_t UI_GetCurrentGame(int32_t curLevel) {
UI_LogFuncBegin();
int32_t level;
int32_t rank;
int32_t skill;
const char *info;
2014-11-08 10:37:24 +00:00
info = UI_GetSpecialArenaInfo("training");
if (info) {
level = atoi(Info_ValueForKey(info, "num"));
UI_GetBestScore(level, &rank, &skill);
if (!rank || rank > 1) {
UI_LogFuncEnd();
return level;
}
}
// kef 7/31/00 -- we think we'd like to just send you to the next map, not the first map you haven't won
2014-11-08 10:37:24 +00:00
if (curLevel == -1)
{
// -1 is a special value, the meaning of which is not currently clear to me
2014-11-08 10:37:24 +00:00
for (level = 0; level < ui_numSinglePlayerArenas; level++) {
UI_GetBestScore(level, &rank, &skill);
if (!rank || rank > 1)
{
UI_LogFuncEnd();
return level;
}
}
2014-11-08 10:37:24 +00:00
info = UI_GetSpecialArenaInfo("final");
if (!info) {
UI_LogFuncEnd();
return -1;
}
UI_LogFuncEnd();
2014-11-08 10:37:24 +00:00
return atoi(Info_ValueForKey(info, "num"));
}
2014-11-08 10:37:24 +00:00
else if ((curLevel >= 0) && (curLevel < (ui_numSinglePlayerArenas - 1)))
{
// go to next map
UI_LogFuncEnd();
2014-11-08 10:37:24 +00:00
return curLevel + 1;
}
2014-11-08 10:37:24 +00:00
else if (curLevel == (ui_numSinglePlayerArenas - 1))
{
// finished final map...back to the beginning
UI_LogFuncEnd();
return 0;
}
else
{
// bogus value for curLevel
2014-11-08 10:37:24 +00:00
info = UI_GetSpecialArenaInfo("final");
if (!info) {
UI_LogFuncEnd();
return -1;
}
UI_LogFuncEnd();
2014-11-08 10:37:24 +00:00
return atoi(Info_ValueForKey(info, "num"));
}
UI_LogFuncEnd();
}
/*
===============
UI_NewGame
Clears the scores and sets the difficutly level
===============
*/
2014-11-08 10:37:24 +00:00
void UI_NewGame(void) {
UI_LogFuncBegin();
2014-11-08 10:37:24 +00:00
trap_Cvar_Set("g_spScores1", "");
trap_Cvar_Set("g_spScores2", "");
trap_Cvar_Set("g_spScores3", "");
trap_Cvar_Set("g_spScores4", "");
trap_Cvar_Set("g_spScores5", "");
trap_Cvar_Set("g_spAwards", "");
trap_Cvar_Set("g_spVideos", "");
UI_LogFuncEnd();
}
/*
===============
UI_GetNumArenas
===============
*/
2014-11-08 10:37:24 +00:00
int32_t UI_GetNumArenas(void) {
UI_LogFuncBegin();
UI_LogFuncEnd();
return ui_numArenas;
}
/*
===============
UI_GetNumSPArenas
===============
*/
2014-11-08 10:37:24 +00:00
int32_t UI_GetNumSPArenas(void) {
UI_LogFuncBegin();
UI_LogFuncEnd();
return ui_numSinglePlayerArenas;
}
/*
===============
UI_GetNumSPTiers
===============
*/
2014-11-08 10:37:24 +00:00
int32_t UI_GetNumSPTiers(void)
{
UI_LogFuncBegin();
int32_t remainder;
remainder = ui_numSinglePlayerArenas % ARENAS_PER_TIER;
if (remainder)
{
remainder = 1;
}
UI_LogFuncEnd();
return ((ui_numSinglePlayerArenas / ARENAS_PER_TIER) + remainder);
}
/*
===============
UI_GetNumBots
===============
*/
2014-11-08 10:37:24 +00:00
int32_t UI_GetNumBots(void) {
UI_LogFuncBegin();
UI_LogFuncEnd();
return ui_numBots;
}
/*
===============
UI_InitGameinfo
===============
*/
2014-11-08 10:37:24 +00:00
void UI_InitGameinfo(void) {
UI_LogFuncBegin();
UI_InitMemory();
UI_LoadArenas();
UI_LoadBots();
2014-11-08 10:37:24 +00:00
if ((trap_Cvar_VariableValue("fs_restrict")) || (ui_numSpecialSinglePlayerArenas == 0 && ui_numSinglePlayerArenas == 2)) {
uis.demoversion = qtrue;
}
else {
uis.demoversion = qfalse;
}
UI_LogFuncEnd();
}