From 4932bde9b05693c531cdf3553f208601761c7951 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 10 Mar 2026 20:56:33 -0400 Subject: [PATCH] gametype_t - New array of pointers to structures in memory (currently mixing static for base-game and Callocated for custom) - Centralises a metric-ton of previously seperately handled properties into one struct - Gametype_Names[] - Gametype_ConstantNames[] - gametypetol[] - timelimits[] - pointlimits[] - gametypedefaultrules[] - gametypecolor[] - Nep: This one was blan exclusive but I added it regardless. - Don't attempt to guess custom gametype in Replay Hut (requires more work to make custom gametypes behave across the entire experience) - I_Error if invalid gametype set - gametyperules is deprecated since it will never be modified seperately from gametype (temporarily a #define, don't wanna bloat this commit too much) --- src/d_clisrv.c | 2 +- src/d_main.cpp | 5 +- src/d_netcmd.c | 55 ++++++--------- src/deh_lua.c | 9 ++- src/deh_soc.c | 50 ++++++-------- src/doomstat.h | 44 ++++++------ src/g_game.c | 167 +++++++++++++++++++--------------------------- src/g_game.h | 9 +-- src/hu_stuff.c | 4 +- src/k_kart.c | 2 +- src/lua_baselib.c | 57 ++++++++-------- src/m_menu.c | 10 +-- src/p_setup.c | 1 - src/typedef.h | 1 + src/y_inter.c | 25 +++---- src/y_inter.h | 1 - 16 files changed, 191 insertions(+), 251 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 245904258..a1d207cbe 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1008,7 +1008,7 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime) else netbuffer->u.serverinfo.refusereason = 0; - strncpy(netbuffer->u.serverinfo.gametypename, Gametype_Names[prefgametype], + strncpy(netbuffer->u.serverinfo.gametypename, gametypes[prefgametype]->name, sizeof netbuffer->u.serverinfo.gametypename); netbuffer->u.serverinfo.modifiedgame = (UINT8)modifiedgame; netbuffer->u.serverinfo.cheatsenabled = CV_CheatsEnabled(); diff --git a/src/d_main.cpp b/src/d_main.cpp index 0362fddb7..0afd9bdbc 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -1752,9 +1752,6 @@ void D_SRB2Main(void) CON_Init(); - memset(timelimits, 0, sizeof(timelimits)); - memset(pointlimits, 0, sizeof(pointlimits)); - CON_SetLoadingProgress(LOADED_HUINIT); if (modifiedgame) @@ -2097,7 +2094,7 @@ void D_SRB2Main(void) if (newgametype == -1) // reached end of the list with no match { j = atoi(sgametype); // assume they gave us a gametype number, which is okay too - if (j >= 0 && j < gametypecount) + if (j >= 0 && j < numgametypes) newgametype = (INT16)j; } diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 25b50fa15..21eefaadd 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -766,10 +766,6 @@ consvar_t cv_timelimit = CVAR_INIT ("timelimit", "2", CV_NETVAR|CV_CALL|CV_NOINI static CV_PossibleValue_t numlaps_cons_t[] = {{0, "MIN"}, {MAX_LAPS, "MAX"}, {-1, "Map default"}, {0, NULL}}; consvar_t cv_numlaps = CVAR_INIT ("numlaps", "Map default", CV_NETVAR|CV_CALL|CV_CHEAT, numlaps_cons_t, NumLaps_OnChange); -// Point and time limits for every gametype -INT32 pointlimits[NUMGAMETYPES]; -INT32 timelimits[NUMGAMETYPES]; - consvar_t cv_forceskin = CVAR_INIT ("forceskin", "None", CV_NETVAR|CV_CALL|CV_CHEAT, NULL, ForceSkin_OnChange); consvar_t cv_downloading = CVAR_INIT ("downloading", "On", 0, CV_OnOff, NULL); @@ -873,8 +869,7 @@ char timedemo_csv_id[256]; boolean timedemo_quit; INT16 gametype = GT_RACE; -UINT32 gametyperules = 0; -INT16 gametypecount = GT_FIRSTFREESLOT; +INT16 numgametypes = GT_FIRSTFREESLOT; boolean forceresetplayers = false; boolean deferencoremode = false; @@ -960,13 +955,7 @@ void D_RegisterServerCommands(void) Forceskin_cons_t[0].value = -1; Forceskin_cons_t[0].strvalue = "Off"; - for (i = 0; i < NUMGAMETYPES; i++) - { - gametype_cons_t[i].value = i; - gametype_cons_t[i].strvalue = Gametype_Names[i]; - } - gametype_cons_t[NUMGAMETYPES].value = 0; - gametype_cons_t[NUMGAMETYPES].strvalue = NULL; + G_UpdateGametypeSelections(); // Set the values to 0/NULL, it will be overwritten later when a skin is assigned to the slot. for (i = 1; i < MAXSKINS; i++) @@ -3420,12 +3409,12 @@ void D_SetupVote(void) UINT8 secondgt = G_SometimesGetDifferentGametype(gt); INT16 votebuffer[4] = {-1,-1,-1,0}; - if (cv_kartencore.value && cv_encorevotes.value == 1 && (gametypedefaultrules[gt] & GTR_CIRCUIT)) + if (cv_kartencore.value && cv_encorevotes.value == 1 && (gametypes[gt]->rules & GTR_CIRCUIT)) WRITEUINT8(p, (gt|VOTEMODIFIER_ENCORE)); else WRITEUINT8(p, gt); - if (cv_kartencore.value && cv_encorevotes.value == 0 && (gametypedefaultrules[gt] & GTR_CIRCUIT)) + if (cv_kartencore.value && cv_encorevotes.value == 0 && (gametyperules & GTR_CIRCUIT)) WRITEUINT8(p, secondgt|VOTEMODIFIER_ENCORE); else WRITEUINT8(p, secondgt); @@ -3680,7 +3669,7 @@ static void Command_Map_f(void) if (isdigit(gametypename[0])) { d = atoi(gametypename); - if (d >= 0 && d < gametypecount) + if (d >= 0 && d < numgametypes) newgametype = d; else { @@ -3688,7 +3677,7 @@ static void Command_Map_f(void) "Gametype number %d is out of range. Use a number between" " 0 and %d inclusive. ...Or just use the name. :v\n", d, - gametypecount-1); + numgametypes-1); Z_Free(realmapname); Z_Free(mapname); return; @@ -3923,7 +3912,7 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum) gametype = READUINT8(*cp); G_SetGametype(gametype); // I fear putting that macro as an argument - if (gametype < 0 || gametype >= gametypecount) + if (gametype < 0 || gametype >= numgametypes) gametype = lastgametype; else if (gametype != lastgametype) D_GameTypeChanged(lastgametype); // emulate consvar_t behavior for gametype @@ -5944,8 +5933,8 @@ static void Command_ShowGametype_f(void) const char *gametypestr = NULL; // get name string for current gametype - if (gametype >= 0 && gametype < gametypecount) - gametypestr = Gametype_Names[gametype]; + if (gametype >= 0 && gametype < numgametypes) + gametypestr = gametypes[gametype]->name; if (gametypestr) CONS_Printf(M_GetText("Current gametype is %s\n"), gametypestr); @@ -6110,10 +6099,10 @@ void D_GameTypeChanged(INT32 lastgametype) { const char *oldgt = NULL, *newgt = NULL; - if (lastgametype >= 0 && lastgametype < gametypecount) - oldgt = Gametype_Names[lastgametype]; - if (gametype >= 0 && lastgametype < gametypecount) - newgt = Gametype_Names[gametype]; + if (lastgametype >= 0 && lastgametype < numgametypes) + oldgt = gametypes[lastgametype]->name; + if (gametype >= 0 && gametype < numgametypes) + newgt = gametypes[gametype]->name; if (oldgt && newgt) CONS_Printf(M_GetText("Gametype was changed from %s to %s\n"), oldgt, newgt); @@ -6124,11 +6113,11 @@ void D_GameTypeChanged(INT32 lastgametype) { if (!cv_timelimit.changed) // user hasn't changed limits { - CV_SetValue(&cv_timelimit, timelimits[gametype]); + CV_SetValue(&cv_timelimit, gametypes[gametype]->timelimit); } if (!cv_pointlimit.changed) { - CV_SetValue(&cv_pointlimit, pointlimits[gametype]); + CV_SetValue(&cv_pointlimit, gametypes[gametype]->pointlimit); } } @@ -6429,25 +6418,25 @@ static void Got_SetupVotecmd(UINT8 **cp, INT32 playernum) // Strip illegal Encore flag. if ((gt & VOTEMODIFIER_ENCORE) - && !(gametypedefaultrules[(gt & ~VOTEMODIFIER_ENCORE)] & GTR_CIRCUIT)) + && !(gametypes[(gt & ~VOTEMODIFIER_ENCORE)]->rules & GTR_CIRCUIT)) { gt &= ~VOTEMODIFIER_ENCORE; } - if ((gt & ~VOTEMODIFIER_ENCORE) >= gametypecount) + if ((gt & ~VOTEMODIFIER_ENCORE) >= numgametypes) { gt &= ~VOTEMODIFIER_ENCORE; if (server) - I_Error("Got_SetupVotecmd: Internal gametype ID %d not found (gametypecount = %d)", gt, gametypecount); + I_Error("Got_SetupVotecmd: Internal gametype ID %d not found (numgametypes = %d)", gt, numgametypes); CONS_Alert(CONS_WARNING, M_GetText("Vote setup with bad gametype ID %d received from %s\n"), gt, player_names[playernum]); return; } - if ((secondgt & ~VOTEMODIFIER_ENCORE) >= gametypecount) + if ((secondgt & ~VOTEMODIFIER_ENCORE) >= numgametypes) { secondgt &= ~VOTEMODIFIER_ENCORE; if (server) - I_Error("Got_SetupVotecmd: Internal second gametype ID %d not found (gametypecount = %d)", secondgt, gametypecount); + I_Error("Got_SetupVotecmd: Internal second gametype ID %d not found (numgametypes = %d)", secondgt, numgametypes); CONS_Alert(CONS_WARNING, M_GetText("Vote setup with bad second gametype ID %d received from %s\n"), secondgt, player_names[playernum]); return; } @@ -6471,11 +6460,11 @@ static void Got_SetupVotecmd(UINT8 **cp, INT32 playernum) // If third entry has an illelegal Encore flag... (illelegal!?) if ((secondgt & VOTEMODIFIER_ENCORE) - && !(gametypedefaultrules[(secondgt & ~VOTEMODIFIER_ENCORE)] & GTR_CIRCUIT)) + && !(gametypes[(secondgt & ~VOTEMODIFIER_ENCORE)]->rules & GTR_CIRCUIT)) { secondgt &= ~VOTEMODIFIER_ENCORE; // Apply it to the second entry instead, gametype permitting! - if (gametypedefaultrules[gt] & GTR_CIRCUIT) + if (gametypes[gt]->rules & GTR_CIRCUIT) { g_voteLevels[1][1] |= VOTEMODIFIER_ENCORE; } diff --git a/src/deh_lua.c b/src/deh_lua.c index 21ad657a6..6a7c08a9c 100644 --- a/src/deh_lua.c +++ b/src/deh_lua.c @@ -202,11 +202,16 @@ static int ScanConstants(lua_State *L, boolean mathlib, const char *word) } else if (fastncmp("GT_", word, 3)) { p = word; - for (i = 0; Gametype_ConstantNames[i]; i++) - if (fastcmp(p, Gametype_ConstantNames[i])) { + i = 0; + while (gametypes[i] != NULL) + { + if (fastcmp(p, gametypes[i]->constant)) + { CacheAndPushConstant(L, word, i); return 1; } + i++; + } if (mathlib) return luaL_error(L, "gametype '%s' could not be found.\n", word); return 0; } diff --git a/src/deh_soc.c b/src/deh_soc.c index 9b41bb0f0..52f360772 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -642,14 +642,13 @@ void readgametype(MYFILE *f, char *gtname) char *tmp; INT32 i, j; - INT16 newgtidx = 0; + gametype_t *newgametype = NULL; UINT32 newgtrules = 0; UINT32 newgttol = 0; INT32 newgtpointlimit = 0; INT32 newgttimelimit = 0; - INT16 newgtrankingstype = -1; INT32 newgtcolor = V_YELLOWMAP; - int newgtinttype = 0; + UINT8 newgtinttype = 0; char gtconst[MAXLINELEN]; // Empty strings. @@ -700,12 +699,6 @@ void readgametype(MYFILE *f, char *gtname) newgtpointlimit = (INT32)i; else if (fastcmp(word, "DEFAULTTIMELIMIT")) newgttimelimit = (INT32)i; - // Rankings type - else if (fastcmp(word, "RANKINGTYPE")) - { - // Case insensitive - newgtrankingstype = (int)get_number(word2); - } // Intermission type else if (fastcmp(word, "INTERMISSIONTYPE")) { @@ -765,37 +758,36 @@ void readgametype(MYFILE *f, char *gtname) Z_Free(word2lwr); // Ran out of gametype slots - if (gametypecount == NUMGAMETYPEFREESLOTS) + if (numgametypes == GT_LASTFREESLOT) { I_Error("Out of Gametype Freeslots while allocating \"%s\"\nLoad less addons to fix this.", gtname); - return; } // Add the new gametype - newgtidx = G_AddGametype(newgtrules); - G_AddGametypeTOL(newgtidx, newgttol); + newgametype = Z_Calloc(sizeof (gametype_t), PU_STATIC, NULL); + if (!newgametype) + { + I_Error("Out of memory allocating gametype \"%s\"", gtname); + } - // Not covered by G_AddGametype alone. - if (newgtrankingstype == -1) - newgtrankingstype = newgtidx; - gametyperankings[newgtidx] = newgtrankingstype; - intermissiontypes[newgtidx] = newgtinttype; - pointlimits[newgtidx] = newgtpointlimit; - timelimits[newgtidx] = newgttimelimit; - gametypecolor[newgtidx] = newgtcolor; - - // Write the new gametype name. - Gametype_Names[newgtidx] = Z_StrDup((const char *)gtname); - - // Write the constant name. if (gtconst[0] == '\0') strncpy(gtconst, gtname, MAXLINELEN); - G_AddGametypeConstant(newgtidx, (const char *)gtconst); + + newgametype->name = Z_StrDup((const char *)gtname); + newgametype->rules = newgtrules; + newgametype->constant = G_PrepareGametypeConstant((const char *)gtconst); + newgametype->tol = newgttol; + newgametype->intermission = newgtinttype; + newgametype->pointlimit = newgtpointlimit; + newgametype->timelimit = newgttimelimit; + newgametype->color = newgtcolor; + + gametypes[numgametypes++] = newgametype; // Update gametype_cons_t accordingly. G_UpdateGametypeSelections(); - CONS_Printf("Added gametype %s\n", Gametype_Names[newgtidx]); + CONS_Printf("Added gametype %s\n", gtname); } static mapheader_lighting_t *usemaplighting(INT32 mapnum, const char *word) @@ -4497,7 +4489,7 @@ menudrawer_f *get_menudrawer(const char *word) return atoi(word); if (fastncmp("GT_",word,3)) word += 3; // take off the GT_ - for (i = 0; i < NUMGAMETYPES; i++) + for (i = 0; i < MAXGAMETYPES; i++) if (fastcmp(word, Gametype_ConstantNames[i]+3)) return i; deh_warning("Couldn't find gametype named 'GT_%s'",word); diff --git a/src/doomstat.h b/src/doomstat.h index ce3012d07..1a9ad1b9a 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -146,11 +146,6 @@ extern boolean addedtogame; // true after the server has added you // Only true if >1 player. netgame => multiplayer but not (multiplayer=>netgame) extern boolean multiplayer; -extern INT16 gametype; - -extern UINT32 gametyperules; -extern INT16 gametypecount; - extern UINT8 splitscreen; extern int r_splitscreen; @@ -458,7 +453,7 @@ extern mapheader_t** mapheaderinfo; extern INT32 nummapheaders, mapallocsize; // Gametypes -#define NUMGAMETYPEFREESLOTS (NUMGAMETYPES-GT_FIRSTFREESLOT) +#define NUMGAMETYPEFREESLOTS (MAXGAMETYPES-GT_FIRSTFREESLOT) enum GameType { @@ -467,9 +462,29 @@ enum GameType GT_FIRSTFREESLOT, GT_LASTFREESLOT = 127, // Previously (GT_FIRSTFREESLOT + NUMGAMETYPEFREESLOTS - 1) - it would be necessary to rewrite VOTEMODIFIER_ENCORE to go higher than this. - NUMGAMETYPES + MAXGAMETYPES }; -// If you alter this list, update deh_tables.c, MISC_ChangeGameTypeMenu in m_menu.c, and Gametype_Names in g_game.c +// If you alter this list, update defaultgametypes and *gametypes in g_game.c +#define MAXTOL (1<<31) +#define NUMBASETOLNAMES (10) +#define NUMTOLNAMES (NUMBASETOLNAMES + NUMGAMETYPEFREESLOTS) + +struct gametype_t +{ + const char *name; + const char *constant; + UINT32 rules; + UINT32 tol; + UINT8 intermission; + INT32 pointlimit; + INT32 timelimit; + INT32 color; +}; + +extern gametype_t *gametypes[MAXGAMETYPES+1]; +extern INT16 numgametypes; + +extern INT16 gametype; // Gametype rules enum GameTypeRules @@ -516,13 +531,8 @@ enum GameTypeRules // free: to and including 1<<31 }; -// String names for gametypes -extern const char *Gametype_Names[NUMGAMETYPES]; -extern const char *Gametype_ConstantNames[NUMGAMETYPES]; - -// Point and time limits for every gametype -extern INT32 pointlimits[NUMGAMETYPES]; -extern INT32 timelimits[NUMGAMETYPES]; +// TODO: replace every instance +#define gametyperules (gametypes[gametype]->rules) // TypeOfLevel things enum TypeOfLevel @@ -545,10 +555,6 @@ enum TypeOfLevel TOL_TV = 0x0200 ///< Midnight Channel specific: draw TV like overlay on HUD }; -#define MAXTOL (1<<31) -#define NUMBASETOLNAMES (10) -#define NUMTOLNAMES (NUMBASETOLNAMES + NUMGAMETYPEFREESLOTS) - struct tolinfo_t { const char *name; diff --git a/src/g_game.c b/src/g_game.c index 549aea796..9793a6e0c 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3846,28 +3846,55 @@ void G_FinishExitLevel(void) } } -// See also the enum GameType in doomstat.h -const char *Gametype_Names[NUMGAMETYPES] = +static gametype_t defaultgametypes[] = { - "Race", // GT_RACE - "Battle" // GT_BATTLE + // GT_RACE + { + "Race", + "GT_RACE", + GTR_CIRCUIT|GTR_BOTS|GTR_RINGS|GTR_ENCORE|GTR_RACEODDS, + TOL_RACE, + int_race, + 0, + 0, + V_SKYMAP, + }, + { + "Battle", + "GT_BATTLE", + GTR_BUMPERS|GTR_POINTS|GTR_RINGS|GTR_KARMA|GTR_WANTED|GTR_WANTEDSPB|GTR_ITEMARROWS|GTR_ITEMBREAKER|GTR_BATTLESTARTS|GTR_TIMELIMIT|GTR_POINTLIMIT|GTR_BATTLEODDS|GTR_CLOSERPLAYERS|GTR_BATTLEBOXES|GTR_BATTLESPEED, + TOL_BATTLE, + int_battle, + 0, + 2, + V_REDMAP, + }, }; -// For dehacked -const char *Gametype_ConstantNames[NUMGAMETYPES] = +gametype_t *gametypes[MAXGAMETYPES+1] = { - "GT_RACE", // GT_RACE - "GT_BATTLE" // GT_BATTLE + &defaultgametypes[GT_RACE], + &defaultgametypes[GT_BATTLE], }; -// Gametype rules -UINT32 gametypedefaultrules[NUMGAMETYPES] = +// +// G_GetGametypeByName +// +// Returns the number for the given gametype name string, or -1 if not valid. +// +INT32 G_GetGametypeByName(const char *gametypestr) { - // Race - GTR_CIRCUIT|GTR_BOTS|GTR_RINGS|GTR_ENCORE|GTR_RACEODDS, - // Battle - GTR_BUMPERS|GTR_POINTS|GTR_RINGS|GTR_KARMA|GTR_WANTED|GTR_WANTEDSPB|GTR_ITEMARROWS|GTR_ITEMBREAKER|GTR_BATTLESTARTS|GTR_TIMELIMIT|GTR_POINTLIMIT|GTR_BATTLEODDS|GTR_CLOSERPLAYERS|GTR_BATTLEBOXES|GTR_BATTLESPEED -}; + INT32 i = 0; + + while (gametypes[i] != NULL) + { + if (!stricmp(gametypestr, gametypes[i]->name)) + return i; + i++; + } + + return -1; // unknown gametype +} // // G_SetGametype @@ -3876,41 +3903,26 @@ UINT32 gametypedefaultrules[NUMGAMETYPES] = // void G_SetGametype(INT16 gtype) { + if (gtype < 0 || gtype > numgametypes) + { + I_Error("G_SetGametype: Bad gametype change %d (was %d/\"%s\")", gtype, gametype, gametypes[gametype]->name); + } + gametype = gtype; - gametyperules = gametypedefaultrules[gametype]; } // -// G_AddGametype -// -// Add a gametype. Returns the new gametype number. -// -INT16 G_AddGametype(UINT32 rules) -{ - INT16 newgtype = gametypecount; - gametypecount++; - - // Set gametype rules. - gametypedefaultrules[newgtype] = rules; - Gametype_Names[newgtype] = "???"; - - // Update gametype_cons_t accordingly. - G_UpdateGametypeSelections(); - - return newgtype; -} - -// -// G_AddGametypeConstant +// G_PrepareGametypeConstant // // Self-explanatory. Filters out "bad" characters. // -void G_AddGametypeConstant(INT16 gtype, const char *newgtconst) +char *G_PrepareGametypeConstant(const char *newgtconst) { size_t r = 0; // read size_t w = 0; // write - char *gtconst = Z_Calloc(strlen(newgtconst) + 4, PU_STATIC, NULL); - char *tmpconst = Z_Calloc(strlen(newgtconst) + 1, PU_STATIC, NULL); + size_t len = strlen(newgtconst); + char *gtconst = Z_Calloc(len + 4, PU_STATIC, NULL); + char *tmpconst = Z_Calloc(len + 1, PU_STATIC, NULL); // Copy the gametype name. strcpy(tmpconst, newgtconst); @@ -3932,7 +3944,7 @@ void G_AddGametypeConstant(INT16 gtype, const char *newgtconst) case ' ': case '@': case '?': - // Used for operations + // Used for operations case '+': case '-': case '*': @@ -3941,7 +3953,7 @@ void G_AddGametypeConstant(INT16 gtype, const char *newgtconst) case '^': case '&': case '!': - // Part of Lua's syntax + // Part of Lua's syntax case '#': case '=': case '~': @@ -3970,8 +3982,8 @@ void G_AddGametypeConstant(INT16 gtype, const char *newgtconst) // Free the temporary string. Z_Free(tmpconst); - // Finally, set the constant string. - Gametype_ConstantNames[gtype] = gtconst; + // Finally, return the constant string. + return gtconst; } // @@ -3982,36 +3994,15 @@ void G_AddGametypeConstant(INT16 gtype, const char *newgtconst) void G_UpdateGametypeSelections(void) { INT32 i; - for (i = 0; i < gametypecount; i++) + for (i = 0; i < numgametypes; i++) { gametype_cons_t[i].value = i; - gametype_cons_t[i].strvalue = Gametype_Names[i]; + gametype_cons_t[i].strvalue = gametypes[i]->name; } - gametype_cons_t[NUMGAMETYPES].value = 0; - gametype_cons_t[NUMGAMETYPES].strvalue = NULL; + gametype_cons_t[numgametypes].value = 0; + gametype_cons_t[numgametypes].strvalue = NULL; } -INT32 gametypecolor[NUMGAMETYPES] = -{ - V_SKYMAP, - V_REDMAP, -}; - -// Gametype rankings -INT16 gametyperankings[NUMGAMETYPES] = -{ - GT_RACE, - GT_BATTLE, -}; - -// Gametype to TOL (Type Of Level) -UINT32 gametypetol[NUMGAMETYPES] = -{ - TOL_RACE, // Race - TOL_BATTLE, // Battle - TOL_TV, // Midnight Channel effect -}; - tolinfo_t TYPEOFLEVEL[NUMTOLNAMES] = { {"RACE",TOL_RACE}, {"BATTLE",TOL_BATTLE}, @@ -4052,32 +4043,6 @@ void G_AddTOL(UINT32 newtol, const char *tolname) TYPEOFLEVEL[i].flag = newtol; } -// -// G_AddGametypeTOL -// -// Assigns a type of level to a gametype. -// -void G_AddGametypeTOL(INT16 gtype, UINT32 newtol) -{ - gametypetol[gtype] = newtol; -} - -// -// G_GetGametypeByName -// -// Returns the number for the given gametype name string, or -1 if not valid. -// -INT32 G_GetGametypeByName(const char *gametypestr) -{ - INT32 i; - - for (i = 0; i < gametypecount; i++) - if (fasticmp(gametypestr, Gametype_Names[i])) - return i; - - return -1; // unknown gametype -} - // // G_IsSpecialStage // @@ -4168,7 +4133,7 @@ INT16 G_SometimesGetDifferentGametype(UINT8 prefgametype) // This is so a server CAN continue playing a gametype if they like the taste of it. // The encore check needs prefgametype so can't use G_RaceGametype... boolean encorepossible = ((M_SecretUnlocked(SECRET_ENCORE) || encorescramble == 1) - && ((gametyperules|gametypedefaultrules[prefgametype]) & GTR_CIRCUIT)); + && (gametypes[prefgametype]->rules & GTR_CIRCUIT)); UINT8 encoremodifier = 0; // -- the below is only necessary if you want to use randmaps.mapbuffer here @@ -4248,8 +4213,8 @@ UINT8 G_GetGametypeColor(INT16 gt) || gamestate == GS_TIMEATTACK) return orangemap[0]; - if (gametypecolor[gt]) - return *V_GetStringColormap(gametypecolor[gt]); + if (gametypes[gt]->color) + return *V_GetStringColormap(gametypes[gt]->color); return yellowmap[0]; // FALLBACK } @@ -4261,7 +4226,9 @@ UINT8 G_GetGametypeColor(INT16 gt) */ UINT32 G_TOLFlag(INT32 pgametype) { - return gametypetol[pgametype]; + if (pgametype >= 0 && pgametype < numgametypes) + return gametypes[pgametype]->tol; + return 0; } INT16 G_GetFirstMapOfGametype(UINT8 pgametype) @@ -4269,7 +4236,7 @@ INT16 G_GetFirstMapOfGametype(UINT8 pgametype) INT16 mapnum = NEXTMAP_INVALID; /* G: not sure what to do with this - if ((gametypedefaultrules[pgametype] & GTR_CAMPAIGN) && kartcupheaders) + if ((gametypes[pgametype]->rules & GTR_CAMPAIGN) && kartcupheaders) { mapnum = kartcupheaders->cachedlevels[0]; } diff --git a/src/g_game.h b/src/g_game.h index 929ec1892..5ce9bdb7b 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -202,18 +202,11 @@ void G_SaveGame(UINT32 slot, INT16 mapnum); void G_SaveGameOver(UINT32 slot, boolean modifylives); -extern UINT32 gametypedefaultrules[NUMGAMETYPES]; -extern UINT32 gametypetol[NUMGAMETYPES]; -extern INT32 gametypecolor[NUMGAMETYPES]; -extern INT16 gametyperankings[NUMGAMETYPES]; - void G_SetGametype(INT16 gametype); -INT16 G_AddGametype(UINT32 rules); -void G_AddGametypeConstant(INT16 gtype, const char *newgtconst); +char *G_PrepareGametypeConstant(const char *newgtconst); void G_UpdateGametypeSelections(void); void G_SetGametypeColor(INT16 gtype,INT32 color); void G_AddTOL(UINT32 newtol, const char *tolname); -void G_AddGametypeTOL(INT16 gtype, UINT32 newtol); INT32 G_GetGametypeByName(const char *gametypestr); boolean G_IsSpecialStage(INT32 mapnum); boolean G_GametypeUsesLives(void); diff --git a/src/hu_stuff.c b/src/hu_stuff.c index b7baa4a3d..312a00537 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -2527,8 +2527,8 @@ static void HU_DrawRankings(void) hilicol = V_ORANGEMAP; else { - if (gametypecolor[gametype]) - hilicol = gametypecolor[gametype]; + if (gametypes[gametype]->color) + hilicol = gametypes[gametype]->color; else hilicol = V_YELLOWMAP; } diff --git a/src/k_kart.c b/src/k_kart.c index c96b6f17c..dfeba5f46 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -157,7 +157,7 @@ void K_TimerInit(void) } else { - timelimitintics = timelimits[gametype] * (60*TICRATE); + timelimitintics = gametypes[gametype]->timelimit * (60*TICRATE); } } else diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 4f43b76a7..cc30f2c64 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -3209,16 +3209,16 @@ static int lib_gAddGametype(lua_State *L) const char *k; lua_Integer i; + gametype_t *newgametype = NULL; + const char *gtname = NULL; const char *gtconst = NULL; - INT16 newgtidx = 0; UINT32 newgtrules = 0; UINT32 newgttol = 0; INT32 newgtpointlimit = 0; INT32 newgttimelimit = 0; - INT16 newgtrankingstype = -1; INT32 newgtcolor = V_YELLOWMAP; - int newgtinttype = 0; + UINT8 newgtinttype = 0; luaL_checktype(L, 1, LUA_TTABLE); lua_settop(L, 1); // Clear out all other possible arguments, leaving only the first one. @@ -3227,8 +3227,10 @@ static int lib_gAddGametype(lua_State *L) return luaL_error(L, "This function cannot be called from within a hook or coroutine!"); // Ran out of gametype slots - if (gametypecount == NUMGAMETYPEFREESLOTS) - return luaL_error(L, "Ran out of free gametype slots!"); + if (numgametypes == GT_LASTFREESLOT) + { + I_Error("Out of Gametype Freeslots while allocating \"%s\"\nLoad less addons to fix this.", gtname); + } #define FIELDERROR(f, e) luaL_error(L, "bad value for " LUA_QL(f) " in table passed to " LUA_QL("G_AddGametype") " (%s)", e); #define TYPEERROR(f, t) FIELDERROR(f, va("%s expected, got %s", lua_typename(L, t), luaL_typename(L, -1))) @@ -3261,23 +3263,19 @@ static int lib_gAddGametype(lua_State *L) if (!lua_isnumber(L, 3)) TYPEERROR("typeoflevel", LUA_TNUMBER) newgttol = (UINT32)lua_tointeger(L, 3); - } else if (i == 5 || (k && fasticmp(k, "rankingtype"))) { - if (!lua_isnumber(L, 3)) - TYPEERROR("rankingtype", LUA_TNUMBER) - newgtrankingstype = (INT16)lua_tointeger(L, 3); - } else if (i == 6 || (k && fasticmp(k, "intermissiontype"))) { + } else if (i == 5 || (k && fasticmp(k, "intermissiontype"))) { if (!lua_isnumber(L, 3)) TYPEERROR("intermissiontype", LUA_TNUMBER) newgtinttype = (int)lua_tointeger(L, 3); - } else if (i == 7 || (k && fasticmp(k, "defaultpointlimit"))) { + } else if (i == 6 || (k && fasticmp(k, "defaultpointlimit"))) { if (!lua_isnumber(L, 3)) TYPEERROR("defaultpointlimit", LUA_TNUMBER) newgtpointlimit = (INT32)lua_tointeger(L, 3); - } else if (i == 8 || (k && fasticmp(k, "defaulttimelimit"))) { + } else if (i == 7 || (k && fasticmp(k, "defaulttimelimit"))) { if (!lua_isnumber(L, 3)) TYPEERROR("defaulttimelimit", LUA_TNUMBER) newgttimelimit = (INT32)lua_tointeger(L, 3); - } else if (i == 9 || (k && fasticmp(k, "menucolor"))) { + } else if (i == 8 || (k && fasticmp(k, "menucolor"))) { if (!lua_isnumber(L, 3)) TYPEERROR("menucolor", LUA_TNUMBER) { @@ -3300,31 +3298,32 @@ static int lib_gAddGametype(lua_State *L) gtname = Z_StrDup("Unnamed gametype"); // Add the new gametype - newgtidx = G_AddGametype(newgtrules); - G_AddGametypeTOL(newgtidx, newgttol); - - // Not covered by G_AddGametype alone. - if (newgtrankingstype == -1) - newgtrankingstype = newgtidx; - gametyperankings[newgtidx] = newgtrankingstype; - intermissiontypes[newgtidx] = newgtinttype; - pointlimits[newgtidx] = newgtpointlimit; - timelimits[newgtidx] = newgttimelimit; - gametypecolor[newgtidx] = newgtcolor; - - // Write the new gametype name. - Gametype_Names[newgtidx] = gtname; + newgametype = Z_Calloc(sizeof (gametype_t), PU_STATIC, NULL); + if (!newgametype) + { + I_Error("Out of memory allocating gametype \"%s\"", gtname); + } // Write the constant name. if (gtconst == NULL) gtconst = gtname; - G_AddGametypeConstant(newgtidx, gtconst); + + newgametype->name = gtname; + newgametype->rules = newgtrules; + newgametype->constant = G_PrepareGametypeConstant(gtconst); + newgametype->tol = newgttol; + newgametype->intermission = newgtinttype; + newgametype->pointlimit = newgtpointlimit; + newgametype->timelimit = newgttimelimit; + newgametype->color = newgtcolor; + + gametypes[numgametypes++] = newgametype; // Update gametype_cons_t accordingly. G_UpdateGametypeSelections(); // done - CONS_Printf("Added gametype %s\n", Gametype_Names[newgtidx]); + CONS_Printf("Added gametype %s\n", gtname); return 0; } diff --git a/src/m_menu.c b/src/m_menu.c index f358faae3..6b45469aa 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -454,7 +454,7 @@ consvar_t cv_skinselectsort = CVAR_INIT ("skinselectsort", "Name", CV_SAVE|CV_CA // This gametype list is integral for many different reasons. // When you add gametypes here, don't forget to update them in dehacked.c and doomstat.h! -CV_PossibleValue_t gametype_cons_t[NUMGAMETYPES+1]; +CV_PossibleValue_t gametype_cons_t[MAXGAMETYPES+1]; consvar_t cv_newgametype = CVAR_INIT ("newgametype", "Race", CV_HIDEN|CV_CALL|CV_NOINIT, gametype_cons_t, Levelplatter_OnChange); @@ -613,19 +613,19 @@ inline static void M_GetGametypeColor(void) if (gt == GT_BATTLE || levellistmode == LLM_BOSS) { - highlightflags = gametypecolor[gt]; + highlightflags = gametypes[gt]->color; warningflags = V_ORANGEMAP; return; } if (gt == GT_RACE) { - highlightflags = gametypecolor[gt]; + highlightflags = gametypes[gt]->color; return; } - if (gametypecolor[gt]) + if (gametypes[gt]->color) { - highlightflags = gametypecolor[gt]; + highlightflags = gametypes[gt]->color; return; } diff --git a/src/p_setup.c b/src/p_setup.c index 2631db202..8fac02b46 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -8747,7 +8747,6 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) // This is needed. Don't touch. maptol = mapheaderinfo[gamemap-1]->typeoflevel; - gametyperules = gametypedefaultrules[gametype]; CON_Drawer(); // let the user know what we are going to do I_FinishUpdate(); // page flip or blit buffer diff --git a/src/typedef.h b/src/typedef.h index c5f78200a..bf35ecadc 100644 --- a/src/typedef.h +++ b/src/typedef.h @@ -115,6 +115,7 @@ TYPEDEF (textpage_t); TYPEDEF (textprompt_t); TYPEDEF (mappoint_t); TYPEDEF (customoption_t); +TYPEDEF (gametype_t); TYPEDEF (mapheader_t); TYPEDEF (tolinfo_t); TYPEDEF (cupheader_t); diff --git a/src/y_inter.c b/src/y_inter.c index 207e0437b..28dad29b3 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -115,7 +115,6 @@ static INT32 listscroll_delay = 0; static fixed_t xscroll = 0; intertype_t intertype = int_none; -intertype_t intermissiontypes[NUMGAMETYPES]; static huddrawlist_h luahuddrawlist_intermission; static huddrawlist_h luahuddrawlist_vote; @@ -464,8 +463,8 @@ void Y_IntermissionDrawer(void) hilicol = V_ORANGEMAP; else { - if (gametypecolor[gametype]) - hilicol = gametypecolor[gametype]; + if (gametypes[gametype]->color) + hilicol = gametypes[gametype]->color; else hilicol = V_YELLOWMAP; } @@ -1052,12 +1051,11 @@ void Y_Ticker(void) // void Y_DetermineIntermissionType(void) { - // set to int_none initially - intertype = int_none; + // set initially + intertype = gametypes[gametype]->intermission; - if (gametype == GT_RACE) - intertype = int_race; - else if (gametype == GT_BATTLE) + // TODO: special cases + if (gametype == GT_BATTLE) { if (grandprixinfo.gp == true && bossinfo.boss == false) intertype = int_none; @@ -1073,8 +1071,6 @@ void Y_DetermineIntermissionType(void) intertype = (nump < 2 ? int_battletime : int_battle); } } - else //if (intermissiontypes[gametype] != int_none) - intertype = intermissiontypes[gametype]; } // @@ -1132,9 +1128,6 @@ void Y_StartIntermission(void) sorttic = max((timer/2) - 2*TICRATE, 2*TICRATE); } - if (intermissiontypes[gametype] != int_none) - intertype = intermissiontypes[gametype]; - // We couldn't display the intermission even if we wanted to. // But we still need to give the players their score bonuses, dummy. //if (dedicated) return; @@ -1808,8 +1801,8 @@ void Y_VoteDrawer(void) hilicol = cons_menuhighlight.value; else { - if (gametypecolor[gametype]) - hilicol = gametypecolor[gametype]; + if (gametypes[gametype]->color) + hilicol = gametypes[gametype]->color; else hilicol = V_YELLOWMAP; } @@ -2231,7 +2224,7 @@ void Y_StartVote(void) // set up the gtc and gts levelinfo[i].gtc = G_GetGametypeColor(g_voteLevels[i][1]); if (i == 2 && g_voteLevels[i][1] != g_voteLevels[0][1]) - levelinfo[i].gts = gametype_cons_t[g_voteLevels[i][1]].strvalue; + levelinfo[i].gts = gametypes[g_voteLevels[i][1]]->name; else levelinfo[i].gts = NULL; } diff --git a/src/y_inter.h b/src/y_inter.h index ef689fa18..2e2042592 100644 --- a/src/y_inter.h +++ b/src/y_inter.h @@ -45,7 +45,6 @@ typedef enum } intertype_t; extern intertype_t intertype; -extern intertype_t intermissiontypes[NUMGAMETYPES]; // Votescreen stuff typedef struct