Replays (net and timeeattack) now recognise gametypes by name

- Should support custom gametypes, but haven't been thoroughly testing those
- Custom gametypes must now be unique by name
- Custom gametypes now have a maximum name length of 31
This commit is contained in:
toaster 2022-12-29 23:13:15 +00:00
parent 834150585b
commit 52040c1248
6 changed files with 77 additions and 21 deletions

View file

@ -878,6 +878,28 @@ void readgametype(MYFILE *f, char *gtname)
I_Error("Out of Gametype Freeslots while allocating \"%s\"\nLoad less addons to fix this.", gtname);
}
if (gtname[0] == '\0')
{
deh_warning("Custom gametype must have a name");
return;
}
if (strlen(gtname) >= MAXGAMETYPELENGTH)
{
deh_warning("Custom gametype \"%s\"'s name must be %d long at most", gtname, MAXGAMETYPELENGTH-1);
return;
}
for (i = 0; i < numgametypes; i++)
if (fastcmp(gtname, gametypes[i]->name))
break;
if (i < numgametypes)
{
deh_warning("Custom gametype \"%s\"'s name is already in use", gtname);
return;
}
// Add the new gametype
newgametype = Z_Calloc(sizeof (gametype_t), PU_STATIC, NULL);
if (!newgametype)

View file

@ -450,6 +450,7 @@ extern INT32 nummapheaders, mapallocsize;
// Gametypes
#define NUMGAMETYPEFREESLOTS (MAXGAMETYPES-GT_FIRSTFREESLOT)
#define MAXGAMETYPELENGTH 32
enum GameType
{

View file

@ -2378,7 +2378,9 @@ void G_BeginRecording(void)
M_Memcpy(demo_p, mapmd5, 16); demo_p += 16;
WRITEUINT8(demo_p, demoflags);
WRITEUINT8(demo_p, gametype & 0xFF);
WRITESTRINGN(demo_p, gametypes[gametype]->name, MAXGAMETYPELENGTH);
WRITEUINT8(demo_p, numlaps);
// file list
@ -2652,7 +2654,7 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname)
SKIPSTRING(p); // gamemap
p += 16; // map md5
flags = READUINT8(p); // demoflags
p++; // gametype
SKIPSTRING(p); // gametype
p++; // numlaps
G_SkipDemoExtraFiles(&p);
@ -2711,7 +2713,7 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname)
SKIPSTRING(p); // gamemap
p += 16; // mapmd5
flags = READUINT8(p);
p++; // gametype
SKIPSTRING(p); // gametype
p++; // numlaps
G_SkipDemoExtraFiles(&p);
if (!(flags & aflags))
@ -2756,7 +2758,7 @@ void G_LoadDemoInfo(menudemo_t *pdemo)
UINT8 version, subversion, pdemoflags, worknumskins, skinid;
democharlist_t *skinlist = NULL;
UINT16 pdemoversion, count;
char mapname[MAXMAPLUMPNAME];
char mapname[MAXMAPLUMPNAME],gtname[MAXGAMETYPELENGTH];
INT32 i;
if (!FIL_ReadFile(pdemo->filepath, &infobuffer))
@ -2820,7 +2822,9 @@ void G_LoadDemoInfo(menudemo_t *pdemo)
return;
}
pdemo->gametype = READUINT8(info_p);
READSTRINGN(info_p, gtname, sizeof(gtname)); // gametype
pdemo->gametype = G_GetGametypeByName(gtname);
pdemo->numlaps = READUINT8(info_p);
pdemo->addonstatus = G_CheckDemoExtraFiles(&info_p, true);
@ -2932,9 +2936,11 @@ void G_DeferedPlayDemo(const char *name)
void G_DoPlayDemo(char *defdemoname)
{
UINT8 i, p, numslots = 0;
INT32 i;
UINT8 p, numslots = 0;
lumpnum_t l;
char color[MAXCOLORNAME+1],follower[17],mapname[MAXMAPLUMPNAME],*n,*pdemoname;
char color[MAXCOLORNAME+1],follower[17],mapname[MAXMAPLUMPNAME],gtname[MAXGAMETYPELENGTH];
char *n,*pdemoname;
UINT8 availabilities[MAXPLAYERS][MAXAVAILABILITY];
UINT8 version,subversion;
UINT32 randseed[PRNUMCLASS];
@ -2951,6 +2957,7 @@ void G_DoPlayDemo(char *defdemoname)
follower[16] = '\0';
color[MAXCOLORNAME] = '\0';
gtname[MAXGAMETYPELENGTH-1] = '\0';
// No demo name means we're restarting the current demo
if (defdemoname == NULL)
@ -3060,8 +3067,22 @@ void G_DoPlayDemo(char *defdemoname)
demo_p += 16; // mapmd5
demoflags = READUINT8(demo_p);
gametype = READUINT8(demo_p);
G_SetGametype(gametype);
READSTRINGN(demo_p, gtname, sizeof(gtname)); // gametype
i = G_GetGametypeByName(gtname);
if (i < 0)
{
snprintf(msg, 1024, M_GetText("%s is in a gametype that is not currently loaded and cannot be played.\n"), pdemoname);
CONS_Alert(CONS_ERROR, "%s", msg);
M_StartMessage(msg, NULL, MM_NOTHING);
Z_Free(pdemoname);
Z_Free(demobuffer);
demo.playback = false;
demo.title = false;
return;
}
G_SetGametype(i);
numlaps = READUINT8(demo_p);
if (demo.title) // Titledemos should always play and ought to always be compatible with whatever wadlist is running.
@ -3519,7 +3540,7 @@ void G_AddGhost(char *defdemoname)
return;
}
p++; // gametype
SKIPSTRING(p); // gametype
p++; // numlaps
G_SkipDemoExtraFiles(&p); // Don't wanna modify the file list for ghosts.
@ -3736,7 +3757,7 @@ void G_UpdateStaffGhostName(lumpnum_t l)
goto fail; // we don't NEED to do it here, but whatever
}
p++; // Gametype
SKIPSTRING(p); // gametype
p++; // numlaps
G_SkipDemoExtraFiles(&p);

View file

@ -84,7 +84,7 @@ struct menudemo_t {
char title[65]; // Null-terminated for string prints
UINT16 map;
UINT8 addonstatus; // What do we need to do addon-wise to play this demo?
UINT8 gametype;
INT16 gametype;
SINT8 kartspeed; // Add OR DF_ENCORE for encore mode, idk
UINT8 numlaps;

View file

@ -3969,9 +3969,11 @@ static void M_DrawReplayHutReplayInfo(menudemo_t *demoref)
V_DrawThinString(x, y+9, V_SNAPTOTOP|V_ALLOWLOWERCASE, va("(%d laps)", demoref->numlaps));
{
const char *gtstring = "???";
if (demoref->gametype >= GT_FIRSTFREESLOT)
; // TODO: Support custom gametypes in netreplays (would require deeper changes than this)
const char *gtstring;
if (demoref->gametype < 0)
{
gtstring = "Custom (not loaded)";
}
else
{
gtstring = gametypes[demoref->gametype]->name;
@ -3994,7 +3996,7 @@ static void M_DrawReplayHutReplayInfo(menudemo_t *demoref)
V_DrawThinString(x, y+29, V_SNAPTOTOP|highlightflags, "WINNER");
V_DrawString(x+38, y+30, V_SNAPTOTOP|V_ALLOWLOWERCASE, demoref->standings[0].name);
if (demoref->gametype < GT_FIRSTFREESLOT)
if (demoref->gametype >= 0)
{
if (gametypes[demoref->gametype]->rules & GTR_POINTLIMIT)
{
@ -4215,7 +4217,7 @@ void M_DrawReplayStartMenu(void)
if (demoref->standings[i].timeorscore == UINT32_MAX-1)
V_DrawThinString(BASEVIDWIDTH-92, STARTY + i*20 + 9, V_SNAPTOTOP, "NO CONTEST");
else if (demoref->gametype >= GT_FIRSTFREESLOT)
else if (demoref->gametype < 0)
;
else if (gametypes[demoref->gametype]->rules & GTR_POINTLIMIT)
V_DrawString(BASEVIDWIDTH-92, STARTY + i*20 + 9, V_SNAPTOTOP, va("%d", demoref->standings[i].timeorscore));

View file

@ -2980,6 +2980,7 @@ static int lib_gAddGametype(lua_State *L)
INT32 newgtpointlimit = 0;
INT32 newgttimelimit = 0;
UINT8 newgtinttype = 0;
INT16 j;
luaL_checktype(L, 1, LUA_TTABLE);
lua_settop(L, 1); // Clear out all other possible arguments, leaving only the first one.
@ -3043,13 +3044,22 @@ static int lib_gAddGametype(lua_State *L)
#undef FIELDERROR
#undef TYPEERROR
if (gtname == NULL)
return luaL_error(L, "Custom gametype must have a name");
if (strlen(gtname) >= MAXGAMETYPELENGTH)
return luaL_error(L, "Custom gametype \"%s\"'s name must be %d long at most", gtname, MAXGAMETYPELENGTH-1);
for (j = 0; j < numgametypes; j++)
if (!strcmp(gtname, gametypes[j]->name))
break;
if (j < numgametypes)
return luaL_error(L, "Custom gametype \"%s\"'s name is already in use", gtname);
// pop gametype table
lua_pop(L, 1);
// Set defaults
if (gtname == NULL)
gtname = Z_StrDup("Unnamed gametype");
// Add the new gametype
newgametype = Z_Calloc(sizeof (gametype_t), PU_STATIC, NULL);
if (!newgametype)