Make gametype data available to Lua

This commit is contained in:
Lactozilla 2023-08-05 02:40:49 -03:00
parent 08c087f6f6
commit f38f568b2d
9 changed files with 223 additions and 24 deletions

View file

@ -1374,6 +1374,8 @@ void D_SRB2Main(void)
CONS_Printf("Z_Init(): Init zone memory allocation daemon. \n"); CONS_Printf("Z_Init(): Init zone memory allocation daemon. \n");
Z_Init(); Z_Init();
G_InitGametypes();
clientGamedata = M_NewGameDataStruct(); clientGamedata = M_NewGameDataStruct();
serverGamedata = M_NewGameDataStruct(); serverGamedata = M_NewGameDataStruct();

View file

@ -1324,12 +1324,12 @@ void readgametype(MYFILE *f, char *gtname)
gametypes[newgtidx].timelimit = newgttimelimit; gametypes[newgtidx].timelimit = newgttimelimit;
// Write the new gametype name. // Write the new gametype name.
gametypes[newgtidx].name = Z_StrDup((const char *)gtname); gametypes[newgtidx].name = Z_StrDup(gtname);
// Write the constant name. // Write the constant name.
if (gtconst[0] == '\0') if (gtconst[0] == '\0')
strncpy(gtconst, gtname, MAXLINELEN); strncpy(gtconst, gtname, MAXLINELEN);
G_AddGametypeConstant(newgtidx, (const char *)gtconst); G_AddGametypeConstant(newgtidx, gtconst);
// Update gametype_cons_t accordingly. // Update gametype_cons_t accordingly.
G_UpdateGametypeSelections(); G_UpdateGametypeSelections();

View file

@ -388,8 +388,9 @@ typedef struct
extern mapheader_t* mapheaderinfo[NUMMAPS]; extern mapheader_t* mapheaderinfo[NUMMAPS];
// Gametypes
#define NUMGAMETYPEFREESLOTS 128 #define NUMGAMETYPEFREESLOTS 128
// Gametypes
enum GameType enum GameType
{ {
GT_COOP = 0, // also used in single player GT_COOP = 0, // also used in single player
@ -456,8 +457,8 @@ enum
typedef struct typedef struct
{ {
const char *name; char *name;
const char *constant_name; char *constant_name;
UINT32 rules; UINT32 rules;
UINT32 typeoflevel; UINT32 typeoflevel;
UINT8 intermission_type; UINT8 intermission_type;

View file

@ -3404,11 +3404,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] = { gametype_t gametypes[NUMGAMETYPES] = {
// GT_COOP // 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, .rules = GTR_CAMPAIGN|GTR_LIVES|GTR_FRIENDLY|GTR_SPAWNENEMIES|GTR_ALLOWEXIT|GTR_EMERALDHUNT|GTR_EMERALDTOKENS|GTR_SPECIALSTAGES|GTR_CUTSCENES,
.typeoflevel = TOL_COOP, .typeoflevel = TOL_COOP,
.intermission_type = int_coop, .intermission_type = int_coop,
@ -3416,8 +3445,6 @@ gametype_t gametypes[NUMGAMETYPES] = {
}, },
// GT_COMPETITION // GT_COMPETITION
{ {
.name = "Competition",
.constant_name = "GT_COMPETITION",
.rules = GTR_RACE|GTR_LIVES|GTR_SPAWNENEMIES|GTR_EMERALDTOKENS|GTR_SPAWNINVUL|GTR_ALLOWEXIT, .rules = GTR_RACE|GTR_LIVES|GTR_SPAWNENEMIES|GTR_EMERALDTOKENS|GTR_SPAWNINVUL|GTR_ALLOWEXIT,
.typeoflevel = TOL_COMPETITION, .typeoflevel = TOL_COMPETITION,
.intermission_type = int_comp, .intermission_type = int_comp,
@ -3425,8 +3452,6 @@ gametype_t gametypes[NUMGAMETYPES] = {
}, },
// GT_RACE // GT_RACE
{ {
.name = "Race",
.constant_name = "GT_RACE",
.rules = GTR_RACE|GTR_SPAWNENEMIES|GTR_SPAWNINVUL|GTR_ALLOWEXIT, .rules = GTR_RACE|GTR_SPAWNENEMIES|GTR_SPAWNINVUL|GTR_ALLOWEXIT,
.typeoflevel = TOL_RACE, .typeoflevel = TOL_RACE,
.intermission_type = int_race, .intermission_type = int_race,
@ -3434,8 +3459,6 @@ gametype_t gametypes[NUMGAMETYPES] = {
}, },
// GT_MATCH // 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, .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, .typeoflevel = TOL_MATCH,
.intermission_type = int_match, .intermission_type = int_match,
@ -3446,8 +3469,6 @@ gametype_t gametypes[NUMGAMETYPES] = {
}, },
// GT_TEAMMATCH // 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, .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, .typeoflevel = TOL_MATCH,
.intermission_type = int_teammatch, .intermission_type = int_teammatch,
@ -3458,8 +3479,6 @@ gametype_t gametypes[NUMGAMETYPES] = {
}, },
// GT_TAG // 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, .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, .typeoflevel = TOL_TAG,
.intermission_type = int_match, .intermission_type = int_match,
@ -3471,8 +3490,6 @@ gametype_t gametypes[NUMGAMETYPES] = {
}, },
// GT_HIDEANDSEEK // 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, .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, .typeoflevel = TOL_TAG,
.intermission_type = int_match, .intermission_type = int_match,
@ -3484,8 +3501,6 @@ gametype_t gametypes[NUMGAMETYPES] = {
}, },
// GT_CTF // 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, .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, .typeoflevel = TOL_CTF,
.intermission_type = int_ctf, .intermission_type = int_ctf,
@ -3496,6 +3511,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. // Sets a new gametype, also setting gametype rules accordingly.
// //
@ -3513,7 +3537,7 @@ INT16 G_AddGametype(UINT32 rules)
INT16 newgtype = gametypecount; INT16 newgtype = gametypecount;
gametypecount++; gametypecount++;
gametypes[newgtype].name = "???"; gametypes[newgtype].name = Z_StrDup("???");
gametypes[newgtype].rules = rules; gametypes[newgtype].rules = rules;
// Update gametype_cons_t accordingly. // Update gametype_cons_t accordingly.

View file

@ -191,6 +191,7 @@ void G_SaveGame(UINT32 slot, INT16 mapnum);
void G_SaveGameOver(UINT32 slot, boolean modifylives); void G_SaveGameOver(UINT32 slot, boolean modifylives);
void G_SetGametype(INT16 gametype); void G_SetGametype(INT16 gametype);
void G_InitGametypes(void);
INT16 G_AddGametype(UINT32 rules); INT16 G_AddGametype(UINT32 rules);
void G_AddGametypeConstant(INT16 gtype, const char *newgtconst); void G_AddGametypeConstant(INT16 gtype, const char *newgtconst);
void G_UpdateGametypeSelections(void); void G_UpdateGametypeSelections(void);

View file

@ -155,6 +155,7 @@ static const struct {
{META_SFXINFO, "sfxinfo_t"}, {META_SFXINFO, "sfxinfo_t"},
{META_SKINCOLOR, "skincolor_t"}, {META_SKINCOLOR, "skincolor_t"},
{META_COLORRAMP, "skincolor_t.ramp"}, {META_COLORRAMP, "skincolor_t.ramp"},
{META_GAMETYPE, "gametype_t"},
{META_SPRITEINFO, "spriteinfo_t"}, {META_SPRITEINFO, "spriteinfo_t"},
{META_PIVOTLIST, "spriteframepivot_t[]"}, {META_PIVOTLIST, "spriteframepivot_t[]"},
{META_FRAMEPIVOT, "spriteframepivot_t"}, {META_FRAMEPIVOT, "spriteframepivot_t"},
@ -3407,8 +3408,8 @@ static int lib_gAddGametype(lua_State *L)
const char *k; const char *k;
lua_Integer i; lua_Integer i;
const char *gtname = NULL; char *gtname = NULL;
const char *gtconst = NULL; char *gtconst = NULL;
const char *gtdescription = NULL; const char *gtdescription = NULL;
INT16 newgtidx = 0; INT16 newgtidx = 0;
UINT32 newgtrules = 0; UINT32 newgtrules = 0;

View file

@ -1899,6 +1899,140 @@ static int colorramp_len(lua_State *L)
return 1; 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! // Now push all these functions into the Lua state!
@ -1938,6 +2072,19 @@ int LUA_InfoLib(lua_State *L)
mobjinfo_fields_ref = Lua_CreateFieldTable(L, mobjinfo_opt); mobjinfo_fields_ref = Lua_CreateFieldTable(L, mobjinfo_opt);
luaL_newmetatable(L, META_GAMETYPE);
lua_pushcfunction(L, gametype_get);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, gametype_set);
lua_setfield(L, -2, "__newindex");
lua_pushcfunction(L, gametype_num);
lua_setfield(L, -2, "__len");
lua_pop(L, 1);
gametype_fields_ref = Lua_CreateFieldTable(L, gametype_opt);
luaL_newmetatable(L, META_SKINCOLOR); luaL_newmetatable(L, META_SKINCOLOR);
lua_pushcfunction(L, skincolor_get); lua_pushcfunction(L, skincolor_get);
lua_setfield(L, -2, "__index"); lua_setfield(L, -2, "__index");
@ -2104,6 +2251,16 @@ int LUA_InfoLib(lua_State *L)
lua_setmetatable(L, -2); lua_setmetatable(L, -2);
lua_setglobal(L, "spriteinfo"); lua_setglobal(L, "spriteinfo");
lua_newuserdata(L, 0);
lua_createtable(L, 0, 2);
lua_pushcfunction(L, lib_getGametypes);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, lib_gametypeslen);
lua_setfield(L, -2, "__len");
lua_setmetatable(L, -2);
lua_setglobal(L, "gametypes");
luaL_newmetatable(L, META_LUABANKS); luaL_newmetatable(L, META_LUABANKS);
lua_pushcfunction(L, lib_getluabanks); lua_pushcfunction(L, lib_getluabanks);
lua_setfield(L, -2, "__index"); lua_setfield(L, -2, "__index");

View file

@ -28,6 +28,7 @@ extern boolean mousegrabbedbylua;
#define META_SKINCOLOR "SKINCOLOR_T*" #define META_SKINCOLOR "SKINCOLOR_T*"
#define META_COLORRAMP "SKINCOLOR_T*RAMP" #define META_COLORRAMP "SKINCOLOR_T*RAMP"
#define META_SPRITEINFO "SPRITEINFO_T*" #define META_SPRITEINFO "SPRITEINFO_T*"
#define META_GAMETYPE "GAMETYPE_T*"
#define META_PIVOTLIST "SPRITEFRAMEPIVOT_T[]" #define META_PIVOTLIST "SPRITEFRAMEPIVOT_T[]"
#define META_FRAMEPIVOT "SPRITEFRAMEPIVOT_T*" #define META_FRAMEPIVOT "SPRITEFRAMEPIVOT_T*"

View file

@ -990,6 +990,7 @@ enum
ARCH_SKINCOLOR, ARCH_SKINCOLOR,
ARCH_MOUSE, ARCH_MOUSE,
ARCH_SKIN, ARCH_SKIN,
ARCH_GAMETYPE,
ARCH_TEND=0xFF, ARCH_TEND=0xFF,
}; };
@ -1019,6 +1020,7 @@ static const struct {
{META_SKINCOLOR, ARCH_SKINCOLOR}, {META_SKINCOLOR, ARCH_SKINCOLOR},
{META_MOUSE, ARCH_MOUSE}, {META_MOUSE, ARCH_MOUSE},
{META_SKIN, ARCH_SKIN}, {META_SKIN, ARCH_SKIN},
{META_GAMETYPE, ARCH_GAMETYPE},
{NULL, ARCH_NULL} {NULL, ARCH_NULL}
}; };
@ -1347,6 +1349,13 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
WRITEUINT8(save_p, skin - skins); // UINT8 because MAXSKINS is only 32 WRITEUINT8(save_p, skin - skins); // UINT8 because MAXSKINS is only 32
break; 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: default:
WRITEUINT8(save_p, ARCH_NULL); WRITEUINT8(save_p, ARCH_NULL);
return 2; return 2;
@ -1596,6 +1605,9 @@ static UINT8 UnArchiveValue(int TABLESINDEX)
case ARCH_SKIN: case ARCH_SKIN:
LUA_PushUserdata(gL, &skins[READUINT8(save_p)], META_SKIN); LUA_PushUserdata(gL, &skins[READUINT8(save_p)], META_SKIN);
break; break;
case ARCH_GAMETYPE:
LUA_PushUserdata(gL, &gametypes[READUINT8(save_p)], META_GAMETYPE);
break;
case ARCH_TEND: case ARCH_TEND:
return 1; return 1;
} }