From 80359c35f0d8e51a1e8ec8c6246ac5a17dbbadc0 Mon Sep 17 00:00:00 2001 From: Lactozilla Date: Sat, 5 Aug 2023 02:40:49 -0300 Subject: [PATCH] Make gametype data available to Lua --- src/d_main.c | 2 + src/deh_soc.c | 4 +- src/doomstat.h | 7 ++- src/g_game.c | 58 ++++++++++++++------ src/g_game.h | 1 + src/lua_baselib.c | 5 +- src/lua_infolib.c | 136 ++++++++++++++++++++++++++++++++++++++++++++++ src/lua_libs.h | 1 + src/lua_script.c | 12 ++++ 9 files changed, 202 insertions(+), 24 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index 274e4ceb3..697e9570d 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1375,6 +1375,8 @@ void D_SRB2Main(void) CONS_Printf("Z_Init(): Init zone memory allocation daemon. \n"); Z_Init(); + G_InitGametypes(); + clientGamedata = M_NewGameDataStruct(); serverGamedata = M_NewGameDataStruct(); diff --git a/src/deh_soc.c b/src/deh_soc.c index 260e64f82..5ec9816d6 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -1325,12 +1325,12 @@ void readgametype(MYFILE *f, char *gtname) gametypes[newgtidx].timelimit = newgttimelimit; // Write the new gametype name. - gametypes[newgtidx].name = Z_StrDup((const char *)gtname); + gametypes[newgtidx].name = Z_StrDup(gtname); // Write the constant name. if (gtconst[0] == '\0') strncpy(gtconst, gtname, MAXLINELEN); - G_AddGametypeConstant(newgtidx, (const char *)gtconst); + G_AddGametypeConstant(newgtidx, gtconst); // Update gametype_cons_t accordingly. G_UpdateGametypeSelections(); diff --git a/src/doomstat.h b/src/doomstat.h index 00db0cf3e..7dbe3e778 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -389,8 +389,9 @@ typedef struct extern mapheader_t* mapheaderinfo[NUMMAPS]; -// Gametypes #define NUMGAMETYPEFREESLOTS 128 + +// Gametypes enum GameType { GT_COOP = 0, // also used in single player @@ -457,8 +458,8 @@ enum typedef struct { - const char *name; - const char *constant_name; + char *name; + char *constant_name; UINT32 rules; UINT32 typeoflevel; UINT8 intermission_type; diff --git a/src/g_game.c b/src/g_game.c index 04c8d9150..424910481 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3392,11 +3392,40 @@ void G_ExitLevel(void) } } +// See also the enum GameType in doomstat.h +static const char *Gametype_Names[NUMGAMETYPES] = +{ + "Co-op", // GT_COOP + "Competition", // GT_COMPETITION + "Race", // GT_RACE + + "Match", // GT_MATCH + "Team Match", // GT_TEAMMATCH + + "Tag", // GT_TAG + "Hide & Seek", // GT_HIDEANDSEEK + + "CTF" // GT_CTF +}; + +static const char *Gametype_ConstantNames[NUMGAMETYPES] = +{ + "GT_COOP", // GT_COOP + "GT_COMPETITION", // GT_COMPETITION + "GT_RACE", // GT_RACE + + "GT_MATCH", // GT_MATCH + "GT_TEAMMATCH", // GT_TEAMMATCH + + "GT_TAG", // GT_TAG + "GT_HIDEANDSEEK", // GT_HIDEANDSEEK + + "GT_CTF" // GT_CTF +}; + gametype_t gametypes[NUMGAMETYPES] = { // GT_COOP { - .name = "Co-op", - .constant_name = "GT_COOP", .rules = GTR_CAMPAIGN|GTR_LIVES|GTR_FRIENDLY|GTR_SPAWNENEMIES|GTR_ALLOWEXIT|GTR_EMERALDHUNT|GTR_EMERALDTOKENS|GTR_SPECIALSTAGES|GTR_CUTSCENES, .typeoflevel = TOL_COOP, .intermission_type = int_coop, @@ -3404,8 +3433,6 @@ gametype_t gametypes[NUMGAMETYPES] = { }, // GT_COMPETITION { - .name = "Competition", - .constant_name = "GT_COMPETITION", .rules = GTR_RACE|GTR_LIVES|GTR_SPAWNENEMIES|GTR_EMERALDTOKENS|GTR_SPAWNINVUL|GTR_ALLOWEXIT, .typeoflevel = TOL_COMPETITION, .intermission_type = int_comp, @@ -3413,8 +3440,6 @@ gametype_t gametypes[NUMGAMETYPES] = { }, // GT_RACE { - .name = "Race", - .constant_name = "GT_RACE", .rules = GTR_RACE|GTR_SPAWNENEMIES|GTR_SPAWNINVUL|GTR_ALLOWEXIT, .typeoflevel = TOL_RACE, .intermission_type = int_race, @@ -3422,8 +3447,6 @@ gametype_t gametypes[NUMGAMETYPES] = { }, // GT_MATCH { - .name = "Match", - .constant_name = "GT_MATCH", .rules = GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_OVERTIME|GTR_POWERSTONES|GTR_DEATHMATCHSTARTS|GTR_SPAWNINVUL|GTR_RESPAWNDELAY|GTR_PITYSHIELD|GTR_DEATHPENALTY, .typeoflevel = TOL_MATCH, .intermission_type = int_match, @@ -3434,8 +3457,6 @@ gametype_t gametypes[NUMGAMETYPES] = { }, // GT_TEAMMATCH { - .name = "Team Match", - .constant_name = "GT_TEAMMATCH", .rules = GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_SPECTATORS|GTR_TEAMS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_OVERTIME|GTR_DEATHMATCHSTARTS|GTR_SPAWNINVUL|GTR_RESPAWNDELAY|GTR_PITYSHIELD, .typeoflevel = TOL_MATCH, .intermission_type = int_teammatch, @@ -3446,8 +3467,6 @@ gametype_t gametypes[NUMGAMETYPES] = { }, // GT_TAG { - .name = "Tag", - .constant_name = "GT_TAG", .rules = GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_TAG|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_OVERTIME|GTR_STARTCOUNTDOWN|GTR_BLINDFOLDED|GTR_DEATHMATCHSTARTS|GTR_SPAWNINVUL|GTR_RESPAWNDELAY, .typeoflevel = TOL_TAG, .intermission_type = int_match, @@ -3459,8 +3478,6 @@ gametype_t gametypes[NUMGAMETYPES] = { }, // GT_HIDEANDSEEK { - .name = "Hide & Seek", - .constant_name = "GT_HIDEANDSEEK", .rules = GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_TAG|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_OVERTIME|GTR_STARTCOUNTDOWN|GTR_HIDEFROZEN|GTR_BLINDFOLDED|GTR_DEATHMATCHSTARTS|GTR_SPAWNINVUL|GTR_RESPAWNDELAY, .typeoflevel = TOL_TAG, .intermission_type = int_match, @@ -3472,8 +3489,6 @@ gametype_t gametypes[NUMGAMETYPES] = { }, // GT_CTF { - .name = "CTF", - .constant_name = "GT_CTF", .rules = GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_SPECTATORS|GTR_TEAMS|GTR_TEAMFLAGS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_OVERTIME|GTR_POWERSTONES|GTR_DEATHMATCHSTARTS|GTR_SPAWNINVUL|GTR_RESPAWNDELAY|GTR_PITYSHIELD, .typeoflevel = TOL_CTF, .intermission_type = int_ctf, @@ -3484,6 +3499,15 @@ gametype_t gametypes[NUMGAMETYPES] = { }, }; +void G_InitGametypes(void) +{ + for (unsigned i = 0; i <= GT_CTF; i++) + { + gametypes[i].name = Z_StrDup(Gametype_Names[i]); + gametypes[i].constant_name = Z_StrDup(Gametype_ConstantNames[i]); + } +} + // // Sets a new gametype, also setting gametype rules accordingly. // @@ -3501,7 +3525,7 @@ INT16 G_AddGametype(UINT32 rules) INT16 newgtype = gametypecount; gametypecount++; - gametypes[newgtype].name = "???"; + gametypes[newgtype].name = Z_StrDup("???"); gametypes[newgtype].rules = rules; // Update gametype_cons_t accordingly. diff --git a/src/g_game.h b/src/g_game.h index 6fbfdd678..97e38d88a 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -192,6 +192,7 @@ void G_SaveGame(UINT32 slot, INT16 mapnum); void G_SaveGameOver(UINT32 slot, boolean modifylives); void G_SetGametype(INT16 gametype); +void G_InitGametypes(void); INT16 G_AddGametype(UINT32 rules); void G_AddGametypeConstant(INT16 gtype, const char *newgtconst); void G_UpdateGametypeSelections(void); diff --git a/src/lua_baselib.c b/src/lua_baselib.c index cbd93fb3c..5fcd0f9b2 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -155,6 +155,7 @@ static const struct { {META_SFXINFO, "sfxinfo_t"}, {META_SKINCOLOR, "skincolor_t"}, {META_COLORRAMP, "skincolor_t.ramp"}, + {META_GAMETYPE, "gametype_t"}, {META_SPRITEINFO, "spriteinfo_t"}, {META_PIVOTLIST, "spriteframepivot_t[]"}, {META_FRAMEPIVOT, "spriteframepivot_t"}, @@ -3550,8 +3551,8 @@ static int lib_gAddGametype(lua_State *L) const char *k; lua_Integer i; - const char *gtname = NULL; - const char *gtconst = NULL; + char *gtname = NULL; + char *gtconst = NULL; const char *gtdescription = NULL; INT16 newgtidx = 0; UINT32 newgtrules = 0; diff --git a/src/lua_infolib.c b/src/lua_infolib.c index ed78811ce..d337b053f 100644 --- a/src/lua_infolib.c +++ b/src/lua_infolib.c @@ -1902,6 +1902,140 @@ static int colorramp_len(lua_State *L) return 1; } +/////////////// +// GAMETYPES // +/////////////// + +static int lib_getGametypes(lua_State *L) +{ + INT16 i; + lua_remove(L, 1); + + i = luaL_checkinteger(L, 1); + if (i < 0 || i >= gametypecount) + return luaL_error(L, "gametypes[] index %d out of range (0 - %d)", i, gametypecount-1); + LUA_PushUserdata(L, &gametypes[i], META_GAMETYPE); + return 1; +} + +// #gametypes -> gametypecount +static int lib_gametypeslen(lua_State *L) +{ + lua_pushinteger(L, gametypecount); + return 1; +} + +enum gametype_e +{ + gametype_name, + gametype_rules, + gametype_typeoflevel, + gametype_intermission_type, + gametype_rankings_type, + gametype_pointlimit, + gametype_timelimit +}; + +const char *const gametype_opt[] = { + "name", + "rules", + "type_of_level", + "intermission_type", + "rankings_type", + "point_limit", + "time_limit", + NULL, +}; + +static int gametype_fields_ref = LUA_NOREF; + +static int gametype_get(lua_State *L) +{ + gametype_t *gt = *((gametype_t **)luaL_checkudata(L, 1, META_GAMETYPE)); + enum gametype_e field = Lua_optoption(L, 2, gametype_name, gametype_fields_ref); + + I_Assert(gt != NULL); + I_Assert(gt >= gametypes); + + switch (field) + { + case gametype_name: + lua_pushstring(L, gt->name); + break; + case gametype_rules: + lua_pushinteger(L, gt->rules); + break; + case gametype_typeoflevel: + lua_pushinteger(L, gt->typeoflevel); + break; + case gametype_intermission_type: + lua_pushinteger(L, gt->intermission_type); + break; + case gametype_rankings_type: + lua_pushinteger(L, gt->rankings_type); + break; + case gametype_pointlimit: + lua_pushinteger(L, gt->pointlimit); + break; + case gametype_timelimit: + lua_pushinteger(L, gt->timelimit); + break; + } + return 1; +} + +static int gametype_set(lua_State *L) +{ + gametype_t *gt = *((gametype_t **)luaL_checkudata(L, 1, META_GAMETYPE)); + enum gametype_e field = Lua_optoption(L, 2, -1, gametype_fields_ref); + + if (hud_running) + return luaL_error(L, "Do not alter gametype data in HUD rendering code!"); + if (hook_cmd_running) + return luaL_error(L, "Do not alter gametype data in CMD building code!"); + + I_Assert(gt != NULL); + I_Assert(gt >= gametypes); + + switch (field) + { + case gametype_name: + Z_Free(gt->name); + gt->name = Z_StrDup(luaL_checkstring(L, 3)); + break; + case gametype_rules: + gt->rules = luaL_checkinteger(L, 3); + break; + case gametype_typeoflevel: + gt->typeoflevel = luaL_checkinteger(L, 3); + break; + case gametype_intermission_type: + gt->intermission_type = luaL_checkinteger(L, 3); + break; + case gametype_rankings_type: + gt->rankings_type = luaL_checkinteger(L, 3); + break; + case gametype_pointlimit: + gt->pointlimit = luaL_checkinteger(L, 3); + break; + case gametype_timelimit: + gt->timelimit = luaL_checkinteger(L, 3); + break; + } + return 0; +} + +static int gametype_num(lua_State *L) +{ + gametype_t *gt = *((gametype_t **)luaL_checkudata(L, 1, META_GAMETYPE)); + + I_Assert(gt != NULL); + I_Assert(gt >= gametypes); + + lua_pushinteger(L, gt-gametypes); + return 1; +} + ////////////////////////////// // // Now push all these functions into the Lua state! @@ -1919,6 +2053,7 @@ int LUA_InfoLib(lua_State *L) LUA_RegisterUserdataMetatable(L, META_STATE, state_get, state_set, state_num); LUA_RegisterUserdataMetatable(L, META_MOBJINFO, mobjinfo_get, mobjinfo_set, mobjinfo_num); + LUA_RegisterUserdataMetatable(L, META_GAMETYPE, gametype_get, gametype_set, gametype_num); LUA_RegisterUserdataMetatable(L, META_SKINCOLOR, skincolor_get, skincolor_set, skincolor_num); LUA_RegisterUserdataMetatable(L, META_COLORRAMP, colorramp_get, colorramp_set, colorramp_len); LUA_RegisterUserdataMetatable(L, META_SFXINFO, sfxinfo_get, sfxinfo_set, sfxinfo_num); @@ -1934,6 +2069,7 @@ int LUA_InfoLib(lua_State *L) LUA_RegisterGlobalUserdata(L, "spr2defaults", lib_getSpr2default, lib_setSpr2default, lib_spr2namelen); LUA_RegisterGlobalUserdata(L, "states", lib_getState, lib_setState, lib_statelen); LUA_RegisterGlobalUserdata(L, "mobjinfo", lib_getMobjInfo, lib_setMobjInfo, lib_mobjinfolen); + LUA_RegisterGlobalUserdata(L, "gametypes", lib_getGametypes, NULL, lib_gametypeslen); LUA_RegisterGlobalUserdata(L, "skincolors", lib_getSkinColor, lib_setSkinColor, lib_skincolorslen); LUA_RegisterGlobalUserdata(L, "spriteinfo", lib_getSpriteInfo, lib_setSpriteInfo, lib_spriteinfolen); LUA_RegisterGlobalUserdata(L, "sfxinfo", lib_getSfxInfo, lib_setSfxInfo, lib_sfxlen); diff --git a/src/lua_libs.h b/src/lua_libs.h index 2e3c70652..41e119fcc 100644 --- a/src/lua_libs.h +++ b/src/lua_libs.h @@ -29,6 +29,7 @@ extern boolean ignoregameinputs; #define META_SKINCOLOR "SKINCOLOR_T*" #define META_COLORRAMP "SKINCOLOR_T*RAMP" #define META_SPRITEINFO "SPRITEINFO_T*" +#define META_GAMETYPE "GAMETYPE_T*" #define META_PIVOTLIST "SPRITEFRAMEPIVOT_T[]" #define META_FRAMEPIVOT "SPRITEFRAMEPIVOT_T*" diff --git a/src/lua_script.c b/src/lua_script.c index 5cacc3f01..e352673c0 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -991,6 +991,7 @@ enum ARCH_SKINCOLOR, ARCH_MOUSE, ARCH_SKIN, + ARCH_GAMETYPE, ARCH_TEND=0xFF, }; @@ -1020,6 +1021,7 @@ static const struct { {META_SKINCOLOR, ARCH_SKINCOLOR}, {META_MOUSE, ARCH_MOUSE}, {META_SKIN, ARCH_SKIN}, + {META_GAMETYPE, ARCH_GAMETYPE}, {NULL, ARCH_NULL} }; @@ -1348,6 +1350,13 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex) WRITEUINT8(save_p, skin - skins); // UINT8 because MAXSKINS is only 32 break; } + case ARCH_GAMETYPE: + { + gametype_t *gt = *((gametype_t **)lua_touserdata(gL, myindex)); + WRITEUINT8(save_p, ARCH_GAMETYPE); + WRITEUINT8(save_p, gt - gametypes); + break; + } default: WRITEUINT8(save_p, ARCH_NULL); return 2; @@ -1597,6 +1606,9 @@ static UINT8 UnArchiveValue(int TABLESINDEX) case ARCH_SKIN: LUA_PushUserdata(gL, &skins[READUINT8(save_p)], META_SKIN); break; + case ARCH_GAMETYPE: + LUA_PushUserdata(gL, &gametypes[READUINT8(save_p)], META_GAMETYPE); + break; case ARCH_TEND: return 1; }