From 42bca87c9af79984b8bf13907c630945f6f1cd01 Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 11 Feb 2024 05:33:20 -0800 Subject: [PATCH 01/33] Got_Luacmd: ensure lua stack is large enough for command arguments --- src/lua_consolelib.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/lua_consolelib.c b/src/lua_consolelib.c index 8a205fb51..98591bec9 100644 --- a/src/lua_consolelib.c +++ b/src/lua_consolelib.c @@ -30,6 +30,12 @@ return luaL_error(L, "HUD rendering code should not call this function!"); static consvar_t *this_cvar; +static void clear_lua_stack(void) +{ + if (gL) // check if Lua is actually turned on first, you dummmy -- Monster Iestyn 04/07/18 + lua_settop(gL, 0); // clear stack +} + void Got_Luacmd(UINT8 **cp, INT32 playernum) { UINT8 i, argc, flags; @@ -74,6 +80,13 @@ void Got_Luacmd(UINT8 **cp, INT32 playernum) lua_remove(gL, -2); // pop command info table + if (!lua_checkstack(gL, argc)) // player + command arguments + { + clear_lua_stack(); + CONS_Alert(CONS_WARNING, "lua command stack overflow from %s (%d, need %d more)\n", player_names[playernum], lua_gettop(gL), argc); + return; + } + LUA_PushUserdata(gL, &players[playernum], META_PLAYER); for (i = 1; i < argc; i++) { @@ -85,8 +98,7 @@ void Got_Luacmd(UINT8 **cp, INT32 playernum) deny: //must be hacked/buggy client - if (gL) // check if Lua is actually turned on first, you dummmy -- Monster Iestyn 04/07/18 - lua_settop(gL, 0); // clear stack + clear_lua_stack(); CONS_Alert(CONS_WARNING, M_GetText("Illegal lua command received from %s\n"), player_names[playernum]); if (server) From 6d64d15216cf8e84f7f6c9fed088afabc64297f6 Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 11 Feb 2024 05:35:42 -0800 Subject: [PATCH 02/33] Got_Saycmd: copy message content into intermediate buffer This prevents modifying the original buffer at the cleanup step as well as potentially writing out of bounds. --- src/hu_stuff.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 39ccfbb21..74a2a8ff0 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -665,6 +665,7 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum) SINT8 target; UINT8 flags; const char *dispname; + char buf[HU_MAXMSGLEN + 1]; char *msg; boolean action = false; char *ptr; @@ -678,8 +679,8 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum) target = READSINT8(*p); flags = READUINT8(*p); playernum = READUINT8(*p); - msg = (char *)*p; - SKIPSTRINGL(*p, HU_MAXMSGLEN + 1); + msg = buf; + READSTRINGL(*p, msg, HU_MAXMSGLEN + 1); //check for invalid characters (0x80 or above) { From c0b823fe6a1e4715a59ca098d4b54c267849453a Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 11 Feb 2024 05:39:18 -0800 Subject: [PATCH 03/33] Let READ macros be used with const pointers --- src/byteptr.h | 54 +++++++++++++++++++++++++-------------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/byteptr.h b/src/byteptr.h index 5416a8455..00bf34c36 100644 --- a/src/byteptr.h +++ b/src/byteptr.h @@ -52,25 +52,25 @@ extern "C" { // what is this? #if defined (__GNUC__) && defined (DEALIGNED) -#define READUINT8(p) ({ UINT8 *p_tmp = (UINT8 *)p; UINT8 b; memcpy(&b, p, sizeof( UINT8)); p_tmp++; *(void**)(&(p)) = (void *)p_tmp; b; }) -#define READSINT8(p) ({ SINT8 *p_tmp = (SINT8 *)p; SINT8 b; memcpy(&b, p, sizeof( SINT8)); p_tmp++; *(void**)(&(p)) = (void *)p_tmp; b; }) -#define READINT16(p) ({ INT16 *p_tmp = (INT16 *)p; INT16 b; memcpy(&b, p, sizeof( INT16)); p_tmp++; *(void**)(&(p)) = (void *)p_tmp; b; }) -#define READUINT16(p) ({ UINT16 *p_tmp = (UINT16 *)p; UINT16 b; memcpy(&b, p, sizeof( UINT16)); p_tmp++; *(void**)(&(p)) = (void *)p_tmp; b; }) -#define READINT32(p) ({ INT32 *p_tmp = (INT32 *)p; INT32 b; memcpy(&b, p, sizeof( INT32)); p_tmp++; *(void**)(&(p)) = (void *)p_tmp; b; }) -#define READUINT32(p) ({ UINT32 *p_tmp = (UINT32 *)p; UINT32 b; memcpy(&b, p, sizeof( UINT32)); p_tmp++; *(void**)(&(p)) = (void *)p_tmp; b; }) -#define READCHAR(p) ({ char *p_tmp = (char *)p; char b; memcpy(&b, p, sizeof( char)); p_tmp++; *(void**)(&(p)) = (void *)p_tmp; b; }) -#define READFIXED(p) ({ fixed_t *p_tmp = (fixed_t *)p; fixed_t b; memcpy(&b, p, sizeof(fixed_t)); p_tmp++; *(void**)(&(p)) = (void *)p_tmp; b; }) -#define READANGLE(p) ({ angle_t *p_tmp = (angle_t *)p; angle_t b; memcpy(&b, p, sizeof(angle_t)); p_tmp++; *(void**)(&(p)) = (void *)p_tmp; b; }) +#define READUINT8(p) ({ const UINT8 *p_tmp = (const UINT8 *)p; UINT8 b; memcpy(&b, p, sizeof( UINT8)); p_tmp++; *(const void**)(&(p)) = (const void *)p_tmp; b; }) +#define READSINT8(p) ({ const SINT8 *p_tmp = (const SINT8 *)p; SINT8 b; memcpy(&b, p, sizeof( SINT8)); p_tmp++; *(const void**)(&(p)) = (const void *)p_tmp; b; }) +#define READINT16(p) ({ const INT16 *p_tmp = (const INT16 *)p; INT16 b; memcpy(&b, p, sizeof( INT16)); p_tmp++; *(const void**)(&(p)) = (const void *)p_tmp; b; }) +#define READUINT16(p) ({ const UINT16 *p_tmp = (const UINT16 *)p; UINT16 b; memcpy(&b, p, sizeof( UINT16)); p_tmp++; *(const void**)(&(p)) = (const void *)p_tmp; b; }) +#define READINT32(p) ({ const INT32 *p_tmp = (const INT32 *)p; INT32 b; memcpy(&b, p, sizeof( INT32)); p_tmp++; *(const void**)(&(p)) = (const void *)p_tmp; b; }) +#define READUINT32(p) ({ const UINT32 *p_tmp = (const UINT32 *)p; UINT32 b; memcpy(&b, p, sizeof( UINT32)); p_tmp++; *(const void**)(&(p)) = (const void *)p_tmp; b; }) +#define READCHAR(p) ({ const char *p_tmp = (const char *)p; char b; memcpy(&b, p, sizeof( char)); p_tmp++; *(const void**)(&(p)) = (const void *)p_tmp; b; }) +#define READFIXED(p) ({ const fixed_t *p_tmp = (const fixed_t *)p; fixed_t b; memcpy(&b, p, sizeof(fixed_t)); p_tmp++; *(const void**)(&(p)) = (const void *)p_tmp; b; }) +#define READANGLE(p) ({ const angle_t *p_tmp = (const angle_t *)p; angle_t b; memcpy(&b, p, sizeof(angle_t)); p_tmp++; *(const void**)(&(p)) = (const void *)p_tmp; b; }) #else -#define READUINT8(p) ((UINT8*)(*(void**)(&(p)) = (void*)&((UINT8*)(p))[1]))[-1] -#define READSINT8(p) ((SINT8*)(*(void**)(&(p)) = (void*)&((SINT8*)(p))[1]))[-1] -#define READINT16(p) ((INT16*)(*(void**)(&(p)) = (void*)&((INT16*)(p))[1]))[-1] -#define READUINT16(p) ((UINT16*)(*(void**)(&(p)) = (void*)&((UINT16*)(p))[1]))[-1] -#define READINT32(p) ((INT32*)(*(void**)(&(p)) = (void*)&((INT32*)(p))[1]))[-1] -#define READUINT32(p) ((UINT32*)(*(void**)(&(p)) = (void*)&((UINT32*)(p))[1]))[-1] -#define READCHAR(p) ((char*)(*(void**)(&(p)) = (void*)&((char*)(p))[1]))[-1] -#define READFIXED(p) ((fixed_t*)(*(void**)(&(p)) = (void*)&((fixed_t*)(p))[1]))[-1] -#define READANGLE(p) ((angle_t*)(*(void**)(&(p)) = (void*)&((angle_t*)(p))[1]))[-1] +#define READUINT8(p) ((const UINT8*)(*(const void**)(&(p)) = (const void*)&((const UINT8*)(p))[1]))[-1] +#define READSINT8(p) ((const SINT8*)(*(const void**)(&(p)) = (const void*)&((const SINT8*)(p))[1]))[-1] +#define READINT16(p) ((const INT16*)(*(const void**)(&(p)) = (const void*)&((const INT16*)(p))[1]))[-1] +#define READUINT16(p) ((const UINT16*)(*(const void**)(&(p)) = (const void*)&((const UINT16*)(p))[1]))[-1] +#define READINT32(p) ((const INT32*)(*(const void**)(&(p)) = (const void*)&((const INT32*)(p))[1]))[-1] +#define READUINT32(p) ((const UINT32*)(*(const void**)(&(p)) = (const void*)&((const UINT32*)(p))[1]))[-1] +#define READCHAR(p) ((const char*)(*(const void**)(&(p)) = (const void*)&((const char*)(p))[1]))[-1] +#define READFIXED(p) ((const fixed_t*)(*(const void**)(&(p)) = (const void*)&((const fixed_t*)(p))[1]))[-1] +#define READANGLE(p) ((const angle_t*)(*(const void**)(&(p)) = (const void*)&((const angle_t*)(p))[1]))[-1] #endif #else //SRB2_BIG_ENDIAN @@ -133,15 +133,15 @@ FUNCINLINE static ATTRINLINE UINT32 readulong(void *ptr) return (ucp[3] << 24) | (ucp[2] << 16) | (ucp[1] << 8) | ucp[0]; } -#define READUINT8(p) ((UINT8*)(p = (void*)&((UINT8*)p)[1]))[-1] -#define READSINT8(p) ((SINT8*)(p = (void*)&((SINT8*)p)[1]))[-1] -#define READINT16(p) readshort(&((INT16*)(p = (void*)&((INT16*)p)[1]))[-1]) -#define READUINT16(p) readushort(&((UINT16*)(p = (void*)&((UINT16*)p)[1]))[-1]) -#define READINT32(p) readlong(&((INT32*)(p = (void*)&((INT32*)p)[1]))[-1]) -#define READUINT32(p) readulong(&((UINT32*)(p = (void*)&((UINT32*)p)[1])) -#define READCHAR(p) ((char*)(p = (void*)&((char*)p)[1]))[-1] -#define READFIXED(p) readlong(&((fixed_t*)(p = (void*)&((fixed_t*)p)[1]))[-1]) -#define READANGLE(p) readulong(&((angle_t*)(p = (void*)&((angle_t*)p)[1]))[-1]) +#define READUINT8(p) ((const UINT8*)(p = (const void*)&((const UINT8*)p)[1]))[-1] +#define READSINT8(p) ((const SINT8*)(p = (const void*)&((const SINT8*)p)[1]))[-1] +#define READINT16(p) readshort(&((const INT16*)(p = (const void*)&((const INT16*)p)[1]))[-1]) +#define READUINT16(p) readushort(&((const UINT16*)(p = (const void*)&((const UINT16*)p)[1]))[-1]) +#define READINT32(p) readlong(&((const INT32*)(p = (const void*)&((const INT32*)p)[1]))[-1]) +#define READUINT32(p) readulong(&((const UINT32*)(p = (const void*)&((const UINT32*)p)[1])) +#define READCHAR(p) ((const char*)(p = (const void*)&((const char*)p)[1]))[-1] +#define READFIXED(p) readlong(&((const fixed_t*)(p = (const void*)&((const fixed_t*)p)[1]))[-1]) +#define READANGLE(p) readulong(&((const angle_t*)(p = (const void*)&((const angle_t*)p)[1]))[-1]) #endif //SRB2_BIG_ENDIAN #undef DEALIGNED From 4ee00d433328391f1333d9be3a7b1fc8c87e1e4f Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 11 Feb 2024 05:40:52 -0800 Subject: [PATCH 04/33] Pass const pointer to all netxcmd handlers Ensure buffer data is read-only and not modified by handler --- src/blua/liolib.c | 2 +- src/command.c | 43 ++++++++------- src/command.h | 4 +- src/d_clisrv.c | 24 ++++----- src/d_clisrv.h | 2 +- src/d_netcmd.c | 121 ++++++++++++++++++++++--------------------- src/d_netcmd.h | 2 +- src/d_netfil.h | 2 +- src/g_demo.c | 4 +- src/hu_stuff.c | 4 +- src/k_zvote.c | 8 +-- src/lua_consolelib.c | 2 +- src/lua_script.h | 2 +- src/p_saveg.c | 2 +- src/s_sound.c | 4 +- 15 files changed, 116 insertions(+), 110 deletions(-) diff --git a/src/blua/liolib.c b/src/blua/liolib.c index 5eec97fb4..4ed64110b 100644 --- a/src/blua/liolib.c +++ b/src/blua/liolib.c @@ -261,7 +261,7 @@ static int io_openlocal (lua_State *L) { } -void Got_LuaFile(UINT8 **cp, INT32 playernum) +void Got_LuaFile(const UINT8 **cp, INT32 playernum) { FILE **pf = NULL; UINT8 success = READUINT8(*cp); // The first (and only) byte indicates whether the file could be opened diff --git a/src/command.c b/src/command.c index 4a360018a..932730349 100644 --- a/src/command.c +++ b/src/command.c @@ -341,7 +341,7 @@ static const char *com_null_string = ""; static char *com_args = NULL; // current command args or NULL static int com_flags; -static void Got_NetVar(UINT8 **p, INT32 playernum); +static void Got_NetVar(const UINT8 **p, INT32 playernum); /** Initializes command buffer and adds basic commands. */ @@ -1749,16 +1749,16 @@ badinput: static boolean serverloading = false; static consvar_t * -ReadNetVar (UINT8 **p, char **return_value, boolean *return_stealth) +ReadNetVar (const UINT8 **p, const char **return_value, boolean *return_stealth) { UINT16 netid; - char *val; + const char *val; boolean stealth; consvar_t *cvar; netid = READUINT16 (*p); - val = (char *)*p; + val = (const char *)*p; SKIPSTRING (*p); stealth = READUINT8 (*p); @@ -1778,17 +1778,17 @@ ReadNetVar (UINT8 **p, char **return_value, boolean *return_stealth) } static consvar_t * -ReadDemoVar (UINT8 **p, char **return_value, boolean *return_stealth) +ReadDemoVar (const UINT8 **p, const char **return_value, boolean *return_stealth) { - char *name; - char *val; + const char *name; + const char *val; boolean stealth; consvar_t *cvar; - name = (char *)*p; + name = (const char *)*p; SKIPSTRING (*p); - val = (char *)*p; + val = (const char *)*p; SKIPSTRING (*p); stealth = READUINT8 (*p); @@ -1805,10 +1805,10 @@ ReadDemoVar (UINT8 **p, char **return_value, boolean *return_stealth) return cvar; } -static void Got_NetVar(UINT8 **p, INT32 playernum) +static void Got_NetVar(const UINT8 **p, INT32 playernum) { consvar_t *cvar; - char *svalue; + const char *svalue; boolean stealth; if (playernum != serverplayer && !IsPlayerAdmin(playernum) && !serverloading) @@ -1858,15 +1858,16 @@ void CV_SaveVars(UINT8 **p, boolean in_demo) WRITEUINT16(count_p, count); } -static void CV_LoadVars(UINT8 **p, - consvar_t *(*got)(UINT8 **p, char **ret_value, boolean *ret_stealth)) +static size_t CV_LoadVars(const UINT8 *bufstart, + consvar_t *(*got)(const UINT8 **p, const char **ret_value, boolean *ret_stealth)) { + const UINT8 *p = bufstart; const boolean store = (client || demo.playback); consvar_t *cvar; UINT16 count; - char *val; + const char *val; boolean stealth; // prevent "invalid command received" @@ -1887,16 +1888,18 @@ static void CV_LoadVars(UINT8 **p, } } - count = READUINT16(*p); + count = READUINT16(p); while (count--) { - cvar = (*got)(p, &val, &stealth); + cvar = (*got)(&p, &val, &stealth); if (cvar) Setvalue(cvar, val, stealth); } serverloading = false; + + return p - bufstart; } void CV_RevertNetVars(void) @@ -1928,14 +1931,14 @@ void CV_RevertNetVars(void) } } -void CV_LoadNetVars(UINT8 **p) +size_t CV_LoadNetVars(const UINT8 *p) { - CV_LoadVars(p, ReadNetVar); + return CV_LoadVars(p, ReadNetVar); } -void CV_LoadDemoVars(UINT8 **p) +size_t CV_LoadDemoVars(const UINT8 *p) { - CV_LoadVars(p, ReadDemoVar); + return CV_LoadVars(p, ReadDemoVar); } static void CV_SetCVar(consvar_t *var, const char *value, boolean stealth); diff --git a/src/command.h b/src/command.h index b8d71bb1f..74fc49708 100644 --- a/src/command.h +++ b/src/command.h @@ -281,13 +281,13 @@ void CV_SaveVariables(FILE *f); void CV_SaveVars(UINT8 **p, boolean in_demo); #define CV_SaveNetVars(p) CV_SaveVars(p, false) -void CV_LoadNetVars(UINT8 **p); +size_t CV_LoadNetVars(const UINT8 *p); // then revert after leaving a netgame void CV_RevertNetVars(void); #define CV_SaveDemoVars(p) CV_SaveVars(p, true) -void CV_LoadDemoVars(UINT8 **p); +size_t CV_LoadDemoVars(const UINT8 *p); // reset cheat netvars after cheats is deactivated void CV_CheatsChanged(void); diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 9030f562e..224a6d8ae 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -320,9 +320,9 @@ tic_t ExpandTics(INT32 low, tic_t basetic) // Some extra data function for handle textcmd buffer // ----------------------------------------------------------------- -static void (*listnetxcmd[MAXNETXCMD])(UINT8 **p, INT32 playernum); +static void (*listnetxcmd[MAXNETXCMD])(const UINT8 **p, INT32 playernum); -void RegisterNetXCmd(netxcmd_t id, void (*cmd_f)(UINT8 **p, INT32 playernum)) +void RegisterNetXCmd(netxcmd_t id, void (*cmd_f)(const UINT8 **p, INT32 playernum)) { #ifdef PARANOIA if (id >= MAXNETXCMD) @@ -463,12 +463,12 @@ static boolean ExtraDataTicker(void) { if (playeringame[i] || i == 0) { - UINT8 *bufferstart = D_GetExistingTextcmd(gametic, i); + const UINT8 *bufferstart = D_GetExistingTextcmd(gametic, i); if (bufferstart) { - UINT8 *curpos = bufferstart; - UINT8 *bufferend = &curpos[((UINT16*)curpos)[0]+2]; + const UINT8 *curpos = bufferstart; + const UINT8 *bufferend = &curpos[((const UINT16*)curpos)[0]+2]; curpos += 2; while (curpos < bufferend) @@ -2825,7 +2825,7 @@ static void Command_Kick(void) CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n")); } -static void Got_KickCmd(UINT8 **p, INT32 playernum) +static void Got_KickCmd(const UINT8 **p, INT32 playernum) { INT32 pnum, msg; char buf[3 + MAX_REASONLENGTH]; @@ -3195,9 +3195,9 @@ static void Command_ResendGamestate(void) } } -static void Got_AddPlayer(UINT8 **p, INT32 playernum); -static void Got_RemovePlayer(UINT8 **p, INT32 playernum); -static void Got_AddBot(UINT8 **p, INT32 playernum); +static void Got_AddPlayer(const UINT8 **p, INT32 playernum); +static void Got_RemovePlayer(const UINT8 **p, INT32 playernum); +static void Got_AddBot(const UINT8 **p, INT32 playernum); void Joinable_OnChange(void); void Joinable_OnChange(void) @@ -3457,7 +3457,7 @@ static inline void SV_AddNode(INT32 node) } // Xcmd XD_ADDPLAYER -static void Got_AddPlayer(UINT8 **p, INT32 playernum) +static void Got_AddPlayer(const UINT8 **p, INT32 playernum) { INT16 node, newplayernum; UINT8 console; @@ -3566,7 +3566,7 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum) } // Xcmd XD_REMOVEPLAYER -static void Got_RemovePlayer(UINT8 **p, INT32 playernum) +static void Got_RemovePlayer(const UINT8 **p, INT32 playernum) { SINT8 pnum, reason; @@ -3593,7 +3593,7 @@ static void Got_RemovePlayer(UINT8 **p, INT32 playernum) // Xcmd XD_ADDBOT // Compacted version of XD_ADDPLAYER for simplicity -static void Got_AddBot(UINT8 **p, INT32 playernum) +static void Got_AddBot(const UINT8 **p, INT32 playernum) { INT16 newplayernum; UINT8 skinnum = 0; diff --git a/src/d_clisrv.h b/src/d_clisrv.h index a237cce7e..b75c26386 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -582,7 +582,7 @@ void GenerateChallenge(uint8_t *buf); shouldsign_t ShouldSignChallenge(uint8_t *message); // Initialise the other field -void RegisterNetXCmd(netxcmd_t id, void (*cmd_f)(UINT8 **p, INT32 playernum)); +void RegisterNetXCmd(netxcmd_t id, void (*cmd_f)(const UINT8 **p, INT32 playernum)); void SendNetXCmdForPlayer(UINT8 playerid, netxcmd_t id, const void *param, size_t nparam); #define SendNetXCmd(id, param, nparam) SendNetXCmdForPlayer(0, id, param, nparam) // Shortcut for P1 void SendKick(UINT8 playernum, UINT8 msg); diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 812de6e5d..c7678f754 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -84,31 +84,31 @@ // protos // ------ -static void Got_NameAndColor(UINT8 **cp, INT32 playernum); -static void Got_WeaponPref(UINT8 **cp, INT32 playernum); -static void Got_PartyInvite(UINT8 **cp, INT32 playernum); -static void Got_AcceptPartyInvite(UINT8 **cp, INT32 playernum); -static void Got_CancelPartyInvite(UINT8 **cp, INT32 playernum); -static void Got_LeaveParty(UINT8 **cp, INT32 playernum); -static void Got_Mapcmd(UINT8 **cp, INT32 playernum); -static void Got_ExitLevelcmd(UINT8 **cp, INT32 playernum); -static void Got_SetupVotecmd(UINT8 **cp, INT32 playernum); -static void Got_ModifyVotecmd(UINT8 **cp, INT32 playernum); -static void Got_PickVotecmd(UINT8 **cp, INT32 playernum); -static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum); -static void Got_Addfilecmd(UINT8 **cp, INT32 playernum); -static void Got_Pause(UINT8 **cp, INT32 playernum); -static void Got_RandomSeed(UINT8 **cp, INT32 playernum); -static void Got_RunSOCcmd(UINT8 **cp, INT32 playernum); -static void Got_Teamchange(UINT8 **cp, INT32 playernum); -static void Got_Clearscores(UINT8 **cp, INT32 playernum); -static void Got_DiscordInfo(UINT8 **cp, INT32 playernum); -static void Got_ScheduleTaskcmd(UINT8 **cp, INT32 playernum); -static void Got_ScheduleClearcmd(UINT8 **cp, INT32 playernum); -static void Got_Automatecmd(UINT8 **cp, INT32 playernum); -static void Got_RequestMapQueuecmd(UINT8 **cp, INT32 playernum); -static void Got_MapQueuecmd(UINT8 **cp, INT32 playernum); -static void Got_Cheat(UINT8 **cp, INT32 playernum); +static void Got_NameAndColor(const UINT8 **cp, INT32 playernum); +static void Got_WeaponPref(const UINT8 **cp, INT32 playernum); +static void Got_PartyInvite(const UINT8 **cp, INT32 playernum); +static void Got_AcceptPartyInvite(const UINT8 **cp, INT32 playernum); +static void Got_CancelPartyInvite(const UINT8 **cp, INT32 playernum); +static void Got_LeaveParty(const UINT8 **cp, INT32 playernum); +static void Got_Mapcmd(const UINT8 **cp, INT32 playernum); +static void Got_ExitLevelcmd(const UINT8 **cp, INT32 playernum); +static void Got_SetupVotecmd(const UINT8 **cp, INT32 playernum); +static void Got_ModifyVotecmd(const UINT8 **cp, INT32 playernum); +static void Got_PickVotecmd(const UINT8 **cp, INT32 playernum); +static void Got_RequestAddfilecmd(const UINT8 **cp, INT32 playernum); +static void Got_Addfilecmd(const UINT8 **cp, INT32 playernum); +static void Got_Pause(const UINT8 **cp, INT32 playernum); +static void Got_RandomSeed(const UINT8 **cp, INT32 playernum); +static void Got_RunSOCcmd(const UINT8 **cp, INT32 playernum); +static void Got_Teamchange(const UINT8 **cp, INT32 playernum); +static void Got_Clearscores(const UINT8 **cp, INT32 playernum); +static void Got_DiscordInfo(const UINT8 **cp, INT32 playernum); +static void Got_ScheduleTaskcmd(const UINT8 **cp, INT32 playernum); +static void Got_ScheduleClearcmd(const UINT8 **cp, INT32 playernum); +static void Got_Automatecmd(const UINT8 **cp, INT32 playernum); +static void Got_RequestMapQueuecmd(const UINT8 **cp, INT32 playernum); +static void Got_MapQueuecmd(const UINT8 **cp, INT32 playernum); +static void Got_Cheat(const UINT8 **cp, INT32 playernum); static void Command_Playdemo_f(void); static void Command_Timedemo_f(void); @@ -165,12 +165,12 @@ static void Command_Clearscores_f(void); // Remote Administration static void Command_Changepassword_f(void); static void Command_Login_f(void); -static void Got_Verification(UINT8 **cp, INT32 playernum); -static void Got_Removal(UINT8 **cp, INT32 playernum); +static void Got_Verification(const UINT8 **cp, INT32 playernum); +static void Got_Removal(const UINT8 **cp, INT32 playernum); static void Command_Verify_f(void); static void Command_RemoveAdmin_f(void); static void Command_MotD_f(void); -static void Got_MotD_f(UINT8 **cp, INT32 playernum); +static void Got_MotD_f(const UINT8 **cp, INT32 playernum); static void Command_ShowScores_f(void); static void Command_ShowTime_f(void); @@ -1094,7 +1094,7 @@ static void FinalisePlaystateChange(INT32 playernum) P_CheckRacers(); // also SRB2Kart } -static void Got_NameAndColor(UINT8 **cp, INT32 playernum) +static void Got_NameAndColor(const UINT8 **cp, INT32 playernum) { player_t *p = &players[playernum]; char name[MAXPLAYERNAME+1]; @@ -1278,11 +1278,12 @@ void WeaponPref_Save(UINT8 **cp, INT32 playernum) WRITEUINT8(*cp, prefs); } -void WeaponPref_Parse(UINT8 **cp, INT32 playernum) +size_t WeaponPref_Parse(const UINT8 *bufstart, INT32 playernum) { + const UINT8 *p = bufstart; player_t *player = &players[playernum]; - UINT8 prefs = READUINT8(*cp); + UINT8 prefs = READUINT8(p); player->pflags &= ~(PF_KICKSTARTACCEL|PF_SHRINKME|PF_AUTOROULETTE); @@ -1302,17 +1303,19 @@ void WeaponPref_Parse(UINT8 **cp, INT32 playernum) // so this will have to do. K_UpdateShrinkCheat(player); } + + return p - bufstart; } -static void Got_WeaponPref(UINT8 **cp,INT32 playernum) +static void Got_WeaponPref(const UINT8 **cp,INT32 playernum) { - WeaponPref_Parse(cp, playernum); + *cp += WeaponPref_Parse(*cp, playernum); // SEE ALSO g_demo.c demo_extradata[playernum] |= DXD_WEAPONPREF; } -static void Got_PartyInvite(UINT8 **cp,INT32 playernum) +static void Got_PartyInvite(const UINT8 **cp,INT32 playernum) { UINT8 invitee; @@ -1356,7 +1359,7 @@ static void Got_PartyInvite(UINT8 **cp,INT32 playernum) } } -static void Got_AcceptPartyInvite(UINT8 **cp,INT32 playernum) +static void Got_AcceptPartyInvite(const UINT8 **cp,INT32 playernum) { int invitation; @@ -1397,7 +1400,7 @@ static void Got_AcceptPartyInvite(UINT8 **cp,INT32 playernum) } } -static void Got_CancelPartyInvite(UINT8 **cp,INT32 playernum) +static void Got_CancelPartyInvite(const UINT8 **cp,INT32 playernum) { UINT8 invitee; @@ -1427,7 +1430,7 @@ static void Got_CancelPartyInvite(UINT8 **cp,INT32 playernum) } } -static void Got_LeaveParty(UINT8 **cp,INT32 playernum) +static void Got_LeaveParty(const UINT8 **cp,INT32 playernum) { (void)cp; @@ -2700,7 +2703,7 @@ static void Command_Map_f(void) * ::serverplayer or ::adminplayer. * \sa D_MapChange */ -static void Got_Mapcmd(UINT8 **cp, INT32 playernum) +static void Got_Mapcmd(const UINT8 **cp, INT32 playernum) { UINT8 flags; INT32 presetplayer = 1; @@ -3113,7 +3116,7 @@ static void Command_QueueMap_f(void) Z_Free(mapname); } -static void Got_RequestMapQueuecmd(UINT8 **cp, INT32 playernum) +static void Got_RequestMapQueuecmd(const UINT8 **cp, INT32 playernum) { UINT8 flags; boolean setencore; @@ -3158,7 +3161,7 @@ static void Got_RequestMapQueuecmd(UINT8 **cp, INT32 playernum) Handle_MapQueueSend(mapnumber, setgametype, setencore); } -static void Got_MapQueuecmd(UINT8 **cp, INT32 playernum) +static void Got_MapQueuecmd(const UINT8 **cp, INT32 playernum) { UINT8 flags, queueposition, i; boolean setencore; @@ -3260,7 +3263,7 @@ static void Command_Pause(void) CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n")); } -static void Got_Pause(UINT8 **cp, INT32 playernum) +static void Got_Pause(const UINT8 **cp, INT32 playernum) { UINT8 dedicatedpause = false; const char *playername; @@ -3321,7 +3324,7 @@ static void Got_Pause(UINT8 **cp, INT32 playernum) * \param playernum Player responsible for the message. Must be ::serverplayer. * \author Graue */ -static void Got_RandomSeed(UINT8 **cp, INT32 playernum) +static void Got_RandomSeed(const UINT8 **cp, INT32 playernum) { UINT32 seed; @@ -3358,7 +3361,7 @@ static void Command_Clearscores_f(void) * \sa XD_CLEARSCORES, Command_Clearscores_f * \author SSNTails */ -static void Got_Clearscores(UINT8 **cp, INT32 playernum) +static void Got_Clearscores(const UINT8 **cp, INT32 playernum) { INT32 i; @@ -3608,7 +3611,7 @@ void P_SetPlayerSpectator(INT32 playernum) } //todo: This and the other teamchange functions are getting too long and messy. Needs cleaning. -static void Got_Teamchange(UINT8 **cp, INT32 playernum) +static void Got_Teamchange(const UINT8 **cp, INT32 playernum) { changeteam_union NetPacket; boolean error = false, wasspectator = false; @@ -3895,7 +3898,7 @@ static void Command_Verify_f(void) SendNetXCmd(XD_VERIFIED, buf, 1); } -static void Got_Verification(UINT8 **cp, INT32 playernum) +static void Got_Verification(const UINT8 **cp, INT32 playernum) { INT16 num = READUINT8(*cp); @@ -3945,7 +3948,7 @@ static void Command_RemoveAdmin_f(void) SendNetXCmd(XD_DEMOTED, buf, 1); } -static void Got_Removal(UINT8 **cp, INT32 playernum) +static void Got_Removal(const UINT8 **cp, INT32 playernum) { UINT8 num = READUINT8(*cp); @@ -4224,7 +4227,7 @@ static void Command_MotD_f(void) Z_Free(mymotd); } -static void Got_MotD_f(UINT8 **cp, INT32 playernum) +static void Got_MotD_f(const UINT8 **cp, INT32 playernum) { char *mymotd = Z_Malloc(sizeof(motd), PU_STATIC, NULL); INT32 i; @@ -4288,7 +4291,7 @@ static void Command_RunSOC(void) SendNetXCmd(XD_RUNSOC, buf, length); } -static void Got_RunSOCcmd(UINT8 **cp, INT32 playernum) +static void Got_RunSOCcmd(const UINT8 **cp, INT32 playernum) { char filename[256]; filestatus_t ncs = FS_NOTCHECKED; @@ -4480,7 +4483,7 @@ static void Command_Addfile(void) #endif/*TESTERS*/ } -static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum) +static void Got_RequestAddfilecmd(const UINT8 **cp, INT32 playernum) { char filename[241]; filestatus_t ncs = FS_NOTCHECKED; @@ -4539,7 +4542,7 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum) COM_BufAddText(va("addfile %s\n", filename)); } -static void Got_Addfilecmd(UINT8 **cp, INT32 playernum) +static void Got_Addfilecmd(const UINT8 **cp, INT32 playernum) { char filename[241]; filestatus_t ncs = FS_NOTCHECKED; @@ -5635,7 +5638,7 @@ static void Command_ExitLevel_f(void) } } -static void Got_ExitLevelcmd(UINT8 **cp, INT32 playernum) +static void Got_ExitLevelcmd(const UINT8 **cp, INT32 playernum) { (void)cp; @@ -5657,7 +5660,7 @@ static void Got_ExitLevelcmd(UINT8 **cp, INT32 playernum) G_FinishExitLevel(); } -static void Got_SetupVotecmd(UINT8 **cp, INT32 playernum) +static void Got_SetupVotecmd(const UINT8 **cp, INT32 playernum) { INT16 newGametype = 0; boolean baseEncore = false; @@ -5732,7 +5735,7 @@ static void Got_SetupVotecmd(UINT8 **cp, INT32 playernum) Y_StartVote(); } -static void Got_ModifyVotecmd(UINT8 **cp, INT32 playernum) +static void Got_ModifyVotecmd(const UINT8 **cp, INT32 playernum) { UINT8 targetID = READUINT8(*cp); SINT8 vote = READSINT8(*cp); @@ -5778,7 +5781,7 @@ fail: } } -static void Got_PickVotecmd(UINT8 **cp, INT32 playernum) +static void Got_PickVotecmd(const UINT8 **cp, INT32 playernum) { SINT8 pick = READSINT8(*cp); SINT8 level = READSINT8(*cp); @@ -5794,7 +5797,7 @@ static void Got_PickVotecmd(UINT8 **cp, INT32 playernum) Y_SetupVoteFinish(pick, level); } -static void Got_ScheduleTaskcmd(UINT8 **cp, INT32 playernum) +static void Got_ScheduleTaskcmd(const UINT8 **cp, INT32 playernum) { char command[MAXTEXTCMD]; INT16 seconds; @@ -5824,7 +5827,7 @@ static void Got_ScheduleTaskcmd(UINT8 **cp, INT32 playernum) } } -static void Got_ScheduleClearcmd(UINT8 **cp, INT32 playernum) +static void Got_ScheduleClearcmd(const UINT8 **cp, INT32 playernum) { (void)cp; @@ -5846,7 +5849,7 @@ static void Got_ScheduleClearcmd(UINT8 **cp, INT32 playernum) } } -static void Got_Automatecmd(UINT8 **cp, INT32 playernum) +static void Got_Automatecmd(const UINT8 **cp, INT32 playernum) { UINT8 eventID; char command[MAXTEXTCMD]; @@ -5889,7 +5892,7 @@ static void Got_Automatecmd(UINT8 **cp, INT32 playernum) } } -static void Got_Cheat(UINT8 **cp, INT32 playernum) +static void Got_Cheat(const UINT8 **cp, INT32 playernum) { UINT8 targetPlayer = READUINT8(*cp); cheat_t cheat = READUINT8(*cp); @@ -7125,7 +7128,7 @@ void LiveStudioAudience_OnChange(void) livestudioaudience_timer = 90; } -void Got_DiscordInfo(UINT8 **p, INT32 playernum) +void Got_DiscordInfo(const UINT8 **p, INT32 playernum) { if (playernum != serverplayer /*&& !IsPlayerAdmin(playernum)*/) { diff --git a/src/d_netcmd.h b/src/d_netcmd.h index b3b58de8b..d1d0fa643 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -236,7 +236,7 @@ void CleanupPlayerName(INT32 playernum, const char *newname); boolean EnsurePlayerNameIsGood(char *name, INT32 playernum); void WeaponPref_Send(UINT8 ssplayer); void WeaponPref_Save(UINT8 **cp, INT32 playernum); -void WeaponPref_Parse(UINT8 **cp, INT32 playernum); +size_t WeaponPref_Parse(const UINT8 *p, INT32 playernum); void D_SendPlayerConfig(UINT8 n); void Command_ExitGame_f(void); void Command_Retry_f(void); diff --git a/src/d_netfil.h b/src/d_netfil.h index fb5a6d29a..904dc0da5 100644 --- a/src/d_netfil.h +++ b/src/d_netfil.h @@ -142,7 +142,7 @@ void RemoveLuaFileTransfer(void); void RemoveAllLuaFileTransfers(void); void SV_AbortLuaFileTransfer(INT32 node); void CL_PrepareDownloadLuaFile(void); -void Got_LuaFile(UINT8 **cp, INT32 playernum); +void Got_LuaFile(const UINT8 **cp, INT32 playernum); void StoreLuaFileCallback(INT32 id); void RemoveLuaFileCallback(INT32 id); void MakePathDirs(char *path); diff --git a/src/g_demo.c b/src/g_demo.c index 95ebc454a..d84b780a6 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -331,7 +331,7 @@ void G_ReadDemoExtraData(void) } if (extradata & DXD_WEAPONPREF) { - WeaponPref_Parse(&demobuf.p, p); + demobuf.p += WeaponPref_Parse(demobuf.p, p); //CONS_Printf("weaponpref is %d for player %d\n", i, p); } @@ -3039,7 +3039,7 @@ void G_DoPlayDemo(const char *defdemoname) } // net var data - CV_LoadDemoVars(&demobuf.p); + demobuf.p += CV_LoadDemoVars(demobuf.p); // Sigh ... it's an empty demo. if (*demobuf.p == DEMOMARKER) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 74a2a8ff0..a889702dd 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -183,7 +183,7 @@ static void Command_Sayto_f(void); static void Command_Sayteam_f(void); static void Command_CSay_f(void); static void Command_Shout(void); -static void Got_Saycmd(UINT8 **p, INT32 playernum); +static void Got_Saycmd(const UINT8 **p, INT32 playernum); void HU_LoadGraphics(void) { @@ -660,7 +660,7 @@ static void Command_Shout(void) * \sa DoSayPacket * \author Graue */ -static void Got_Saycmd(UINT8 **p, INT32 playernum) +static void Got_Saycmd(const UINT8 **p, INT32 playernum) { SINT8 target; UINT8 flags; diff --git a/src/k_zvote.c b/src/k_zvote.c index 017163c05..535508c43 100644 --- a/src/k_zvote.c +++ b/src/k_zvote.c @@ -233,7 +233,7 @@ void K_SendCallMidVote(midVoteType_e voteType, INT32 voteVariable) } /*-------------------------------------------------- - static void Got_CallZVote(UINT8 **cp, INT32 playernum) + static void Got_CallZVote(const UINT8 **cp, INT32 playernum) Callback function for XD_CALLZVOTE NetXCmd. Attempts to start a new vote using K_InitNewMidVote. @@ -245,7 +245,7 @@ void K_SendCallMidVote(midVoteType_e voteType, INT32 voteVariable) Return:- N/A --------------------------------------------------*/ -static void Got_CallZVote(UINT8 **cp, INT32 playernum) +static void Got_CallZVote(const UINT8 **cp, INT32 playernum) { midVoteType_e type = MVT__MAX; INT32 variable = 0; @@ -288,7 +288,7 @@ static void K_PlayerSendMidVote(const UINT8 id) } /*-------------------------------------------------- - static void Got_SetZVote(UINT8 **cp, INT32 playernum) + static void Got_SetZVote(const UINT8 **cp, INT32 playernum) Callback function for XD_SETZVOTE NetXCmd. Updates the vote table. @@ -300,7 +300,7 @@ static void K_PlayerSendMidVote(const UINT8 id) Return:- N/A --------------------------------------------------*/ -static void Got_SetZVote(UINT8 **cp, INT32 playernum) +static void Got_SetZVote(const UINT8 **cp, INT32 playernum) { (void)cp; diff --git a/src/lua_consolelib.c b/src/lua_consolelib.c index 98591bec9..126a75a38 100644 --- a/src/lua_consolelib.c +++ b/src/lua_consolelib.c @@ -36,7 +36,7 @@ static void clear_lua_stack(void) lua_settop(gL, 0); // clear stack } -void Got_Luacmd(UINT8 **cp, INT32 playernum) +void Got_Luacmd(const UINT8 **cp, INT32 playernum) { UINT8 i, argc, flags; char buf[256]; diff --git a/src/lua_script.h b/src/lua_script.h index 9e59d4d6d..231aa31a9 100644 --- a/src/lua_script.h +++ b/src/lua_script.h @@ -63,7 +63,7 @@ void LUA_UnArchive(savebuffer_t *save, boolean network); int LUA_PushGlobals(lua_State *L, const char *word); int LUA_WriteGlobals(lua_State *L, const char *word); -void Got_Luacmd(UINT8 **cp, INT32 playernum); // lua_consolelib.c +void Got_Luacmd(const UINT8 **cp, INT32 playernum); // lua_consolelib.c void LUA_CVarChanged(void *cvar); // lua_consolelib.c int Lua_optoption(lua_State *L, int narg, const char *def, const char *const lst[]); diff --git a/src/p_saveg.c b/src/p_saveg.c index 1ed3801b0..07373edc6 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -6929,7 +6929,7 @@ boolean P_LoadNetGame(savebuffer_t *save, boolean reloading) current_savebuffer = save; - CV_LoadNetVars(&save->p); + save->p += CV_LoadNetVars(save->p); if (!P_NetUnArchiveMisc(save, reloading)) return false; diff --git a/src/s_sound.c b/src/s_sound.c index eb5f8b020..c3cf0a64e 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -45,7 +45,7 @@ static boolean S_AdjustSoundParams(const mobj_t *listener, const mobj_t *source, static void Command_Tunes_f(void); static void Command_RestartAudio_f(void); static void Command_PlaySound(void); -static void Got_PlaySound(UINT8 **p, INT32 playernum); +static void Got_PlaySound(const UINT8 **p, INT32 playernum); static void Command_MusicDef_f(void); void Captioning_OnChange(void); @@ -2414,7 +2414,7 @@ static void Command_PlaySound(void) SendNetXCmd(XD_PLAYSOUND, buf, buf_p - buf); } -static void Got_PlaySound(UINT8 **cp, INT32 playernum) +static void Got_PlaySound(const UINT8 **cp, INT32 playernum) { INT32 sound_id = READINT32(*cp); From 10800f307ce27ff36ae60e5598361c018a785979 Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 9 Feb 2024 06:50:12 -0800 Subject: [PATCH 05/33] promote, demote: bounds checking, remove intermediate buffer - Check playernum is in range [0, MAXPLAYERS-1] - Do not copy string to intermediate buffer --- src/d_netcmd.c | 34 ++++++++++------------------------ 1 file changed, 10 insertions(+), 24 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 812de6e5d..a5f836a4c 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -3861,10 +3861,6 @@ void RemoveAdminPlayer(INT32 playernum) static void Command_Verify_f(void) { - char buf[8]; // Should be plenty - char *temp; - INT32 playernum; - if (client) { CONS_Printf(M_GetText("Only the server can use this.\n")); @@ -3883,16 +3879,13 @@ static void Command_Verify_f(void) return; } - strlcpy(buf, COM_Argv(1), sizeof (buf)); + INT32 playernum = atoi(COM_Argv(1)); - playernum = atoi(buf); - - temp = buf; - - WRITEUINT8(temp, playernum); - - if (playeringame[playernum]) + if (playernum >= 0 && playernum < MAXPLAYERS && playeringame[playernum]) + { + UINT8 buf[1] = {playernum}; SendNetXCmd(XD_VERIFIED, buf, 1); + } } static void Got_Verification(UINT8 **cp, INT32 playernum) @@ -3917,10 +3910,6 @@ static void Got_Verification(UINT8 **cp, INT32 playernum) static void Command_RemoveAdmin_f(void) { - char buf[8]; // Should be plenty - char *temp; - INT32 playernum; - if (client) { CONS_Printf(M_GetText("Only the server can use this.\n")); @@ -3933,16 +3922,13 @@ static void Command_RemoveAdmin_f(void) return; } - strlcpy(buf, COM_Argv(1), sizeof(buf)); + INT32 playernum = atoi(COM_Argv(1)); - playernum = atoi(buf); - - temp = buf; - - WRITEUINT8(temp, playernum); - - if (playeringame[playernum]) + if (playernum >= 0 && playernum < MAXPLAYERS && playeringame[playernum]) + { + UINT8 buf[1] = {playernum}; SendNetXCmd(XD_DEMOTED, buf, 1); + } } static void Got_Removal(UINT8 **cp, INT32 playernum) From 63ff2f3f661bbbfbe3fcdac186b4d8bbe0a74026 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Sun, 11 Feb 2024 15:10:51 -0600 Subject: [PATCH 06/33] Check Lua stack before pushing cons args Prevents a Lua stack overrun when executing absurd console commands for local-only lua commands. --- src/lua_consolelib.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/lua_consolelib.c b/src/lua_consolelib.c index 98591bec9..d1e5219aa 100644 --- a/src/lua_consolelib.c +++ b/src/lua_consolelib.c @@ -187,6 +187,11 @@ void COM_Lua_f(void) I_Assert(lua_isfunction(gL, -1)); lua_remove(gL, -2); // pop command info table + if (!lua_checkstack(gL, COM_Argc() + 1)) + { + CONS_Alert(CONS_WARNING, "lua command stack overflow (%d, need %s more)\n", lua_gettop(gL), sizeu1(COM_Argc() + 1)); + return; + } LUA_PushUserdata(gL, &players[playernum], META_PLAYER); for (i = 1; i < COM_Argc(); i++) lua_pushstring(gL, COM_Argv(i)); From c0a6d20cec77c32c64ed3642d6eb64f37d0412e0 Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 11 Feb 2024 15:40:04 -0800 Subject: [PATCH 07/33] Got_Luacmd: always read netxcmd data, even if command is not executed --- src/lua_consolelib.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/lua_consolelib.c b/src/lua_consolelib.c index d1e5219aa..982736ff8 100644 --- a/src/lua_consolelib.c +++ b/src/lua_consolelib.c @@ -39,8 +39,18 @@ static void clear_lua_stack(void) void Got_Luacmd(UINT8 **cp, INT32 playernum) { UINT8 i, argc, flags; + const char *argv[256]; char buf[256]; + argc = READUINT8(*cp); + argv[0] = (const char*)*cp; + SKIPSTRINGN(*cp, 255); + for (i = 1; i < argc; i++) + { + argv[i] = (const char*)*cp; + SKIPSTRINGN(*cp, 255); + } + // don't use I_Assert here, goto the deny code below // to clean up and kick people who try nefarious exploits // like sending random junk lua commands to crash the server @@ -53,8 +63,7 @@ void Got_Luacmd(UINT8 **cp, INT32 playernum) lua_getfield(gL, LUA_REGISTRYINDEX, "COM_Command"); // push COM_Command if (!lua_istable(gL, -1)) goto deny; - argc = READUINT8(*cp); - READSTRINGN(*cp, buf, 255); + strlcpy(buf, argv[0], 255); strlwr(buf); // must lowercase buffer lua_getfield(gL, -1, buf); // push command info table if (!lua_istable(gL, -1)) goto deny; @@ -90,7 +99,7 @@ void Got_Luacmd(UINT8 **cp, INT32 playernum) LUA_PushUserdata(gL, &players[playernum], META_PLAYER); for (i = 1; i < argc; i++) { - READSTRINGN(*cp, buf, 255); + strlcpy(buf, argv[i], 255); lua_pushstring(gL, buf); } LUA_Call(gL, (int)argc, 0, 1); // argc is 1-based, so this will cover the player we passed too. From 0a5baa5d3927c7979722ee86b4a771b04bc8e9a3 Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Mon, 12 Feb 2024 18:12:17 -0700 Subject: [PATCH 08/33] UFO polish --- src/objects/battle-ufo.cpp | 11 ++++++++++- src/p_inter.c | 4 ++++ src/sounds.c | 2 +- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/objects/battle-ufo.cpp b/src/objects/battle-ufo.cpp index 055567beb..e4a0dc961 100644 --- a/src/objects/battle-ufo.cpp +++ b/src/objects/battle-ufo.cpp @@ -123,6 +123,8 @@ public: ufo->sprzoff(ofs * spawner->scale()); ufo->spawner(spawner); + + ufo->extravalue1 = 0; // Lifetime } }; @@ -134,6 +136,8 @@ void Obj_BattleUFOThink(mobj_t *mobj) { UFO* ufo = static_cast(mobj); + ufo->extravalue1++; + ufo->bob(); if ((leveltime/2) & 1) @@ -141,7 +145,12 @@ void Obj_BattleUFOThink(mobj_t *mobj) ufo->spawn_beam(); } - if (!battleovertime.enabled) + if ((ufo->extravalue1 % (TICRATE*2)) == 0) + { + S_StartSound(ufo, sfx_gbrk); // for debug because it's loud af, use s3k95 probably + } + + if (!battleovertime.enabled && ufo->extravalue1 <= 5*TICRATE) { Obj_PointPlayersToXY(mobj->x, mobj->y); } diff --git a/src/p_inter.c b/src/p_inter.c index 5dae5dc82..dfe72f981 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -3163,6 +3163,10 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da Obj_EndBungee(player); K_BumperInflate(target->player); + // Explosions are explicit combo setups. + if (damagetype & DMG_EXPLODE) + player->bumperinflate = 0; + if (player->spectator == false && !(player->charflags & SF_IRONMAN)) { UINT32 skinflags = (demo.playback) diff --git a/src/sounds.c b/src/sounds.c index 1339fd384..2157cad3a 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -550,7 +550,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"s3k92", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Ghost"}, {"s3k93", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Gas release"}, {"s3k94", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spike"}, - {"s3k95", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Lava burst"}, + {"s3k95", false, 64, 16, -1, NULL, 0, -1, -1, LUMPERROR, "Lava burst"}, // Also used for bufo {"s3k96", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Landing"}, {"s3k97", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Wind"}, {"s3k98", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Falling spike"}, From c1c31c28efbe94adf7e43ba1e10c1988649fed12 Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Tue, 13 Feb 2024 00:29:40 -0700 Subject: [PATCH 09/33] Use proper sound for periodic bufo reminder --- src/objects/battle-ufo.cpp | 2 +- src/sounds.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/objects/battle-ufo.cpp b/src/objects/battle-ufo.cpp index e4a0dc961..a980eeb71 100644 --- a/src/objects/battle-ufo.cpp +++ b/src/objects/battle-ufo.cpp @@ -147,7 +147,7 @@ void Obj_BattleUFOThink(mobj_t *mobj) if ((ufo->extravalue1 % (TICRATE*2)) == 0) { - S_StartSound(ufo, sfx_gbrk); // for debug because it's loud af, use s3k95 probably + S_StartSound(ufo, sfx_s3ka5); } if (!battleovertime.enabled && ufo->extravalue1 <= 5*TICRATE) diff --git a/src/sounds.c b/src/sounds.c index 2157cad3a..f40be3c58 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -550,7 +550,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"s3k92", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Ghost"}, {"s3k93", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Gas release"}, {"s3k94", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spike"}, - {"s3k95", false, 64, 16, -1, NULL, 0, -1, -1, LUMPERROR, "Lava burst"}, // Also used for bufo + {"s3k95", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Lava burst"}, {"s3k96", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Landing"}, {"s3k97", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Wind"}, {"s3k98", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Falling spike"}, @@ -566,7 +566,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"s3ka2", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Launch"}, {"s3ka3", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Rising charge"}, {"s3ka4", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Powering up"}, - {"s3ka5", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s3ka5", false, 64, 16, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // bufo x8away {"s3ka6", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Attraction fizzle"}, {"s3ka7", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Countdown beep"}, {"s3ka8", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Energy"}, From 77617c9d31b976f310311d76fda6737be9d46b66 Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Tue, 13 Feb 2024 18:19:52 -0700 Subject: [PATCH 10/33] GL: Don't pull papersprites towards camera --- src/hardware/hw_defs.h | 1 + src/hardware/hw_main.c | 4 ++-- src/hardware/r_opengl/r_opengl.c | 3 +++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/hardware/hw_defs.h b/src/hardware/hw_defs.h index 621cb9015..36866955a 100644 --- a/src/hardware/hw_defs.h +++ b/src/hardware/hw_defs.h @@ -143,6 +143,7 @@ enum SHADER_FLOOR, SHADER_WALL, SHADER_SPRITE, + SHADER_SPRITECLIPHACK, SHADER_MODEL, SHADER_MODEL_LIGHTING, SHADER_WATER, SHADER_FOG, diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 271076b05..f2099eae4 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -3423,7 +3423,7 @@ static void HWR_SplitSprite(gl_vissprite_t *spr) if (HWR_UseShader()) { - shader = SHADER_SPRITE; + shader = (spr->mobj->frame & FF_PAPERSPRITE) ? SHADER_SPRITE : SHADER_SPRITECLIPHACK; blend |= PF_ColorMapped; } @@ -3916,7 +3916,7 @@ static void HWR_DrawSprite(gl_vissprite_t *spr) if (HWR_UseShader()) { - shader = SHADER_SPRITE; + shader = (spr->mobj->frame & FF_PAPERSPRITE) ? SHADER_SPRITE : SHADER_SPRITECLIPHACK;; blend |= PF_ColorMapped; } diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index d79be21ef..2c53e0d26 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -922,6 +922,9 @@ static struct { {GLSL_DEFAULT_VERTEX_SHADER, GLSL_SOFTWARE_FRAGMENT_SHADER}, // Sprite shader + {GLSL_DEFAULT_VERTEX_SHADER, GLSL_SOFTWARE_FRAGMENT_SHADER}, + + // Sprite clipping hack shader (for pulling things out of the floor) {GLSL_SPRITECLIP_HACK_VERTEX_SHADER, GLSL_SOFTWARE_FRAGMENT_SHADER}, // Model shader From 25ea0bf743deaaf91c92d902c7480056ed36ed64 Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Wed, 14 Feb 2024 04:14:28 -0700 Subject: [PATCH 11/33] Exclude all "3D Geometry" sprites from sprite-clip hack --- src/hardware/hw_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index f2099eae4..2beed6727 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -3423,7 +3423,7 @@ static void HWR_SplitSprite(gl_vissprite_t *spr) if (HWR_UseShader()) { - shader = (spr->mobj->frame & FF_PAPERSPRITE) ? SHADER_SPRITE : SHADER_SPRITECLIPHACK; + shader = (R_ThingIsPaperSprite(spr->mobj) || R_ThingIsFloorSprite(spr->mobj)) ? SHADER_SPRITE : SHADER_SPRITECLIPHACK; blend |= PF_ColorMapped; } @@ -3916,7 +3916,7 @@ static void HWR_DrawSprite(gl_vissprite_t *spr) if (HWR_UseShader()) { - shader = (spr->mobj->frame & FF_PAPERSPRITE) ? SHADER_SPRITE : SHADER_SPRITECLIPHACK;; + shader = (R_ThingIsPaperSprite(spr->mobj) || R_ThingIsFloorSprite(spr->mobj)) ? SHADER_SPRITE : SHADER_SPRITECLIPHACK;; blend |= PF_ColorMapped; } From d3783dec11c8eb55294f9d0cfbbb98cd5a4d9277 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Sat, 17 Feb 2024 13:04:44 -0600 Subject: [PATCH 12/33] Lose player life before P_CheckRacers on exit Fixes KartKrew/Kart#1022 by ensuring the player has 0 lives by the time P_CheckRacers indirectly calls G_BeginLevelExit. --- src/p_user.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/p_user.c b/src/p_user.c index 29cb607c3..d6fdc3a8b 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1206,14 +1206,26 @@ void P_DoPlayerExit(player_t *player, pflags_t flags) player->exiting = 1; + if (!player->spectator && (gametyperules & GTR_CIRCUIT)) // Special Race-like handling + { + K_UpdateAllPlayerPositions(); + } + + const boolean losing = K_IsPlayerLosing(player); // HEY!!!! Set it AFTER K_UpdateAllPlayerPositions!!!! + const boolean specialout = (specialstageinfo.valid == true && losing == true); + + if (G_GametypeUsesLives() && losing) + { + // Remove a life from the losing player + K_PlayerLoseLife(player); + } + if (!player->spectator) { ClearFakePlayerSkin(player); if ((gametyperules & GTR_CIRCUIT)) // Special Race-like handling { - K_UpdateAllPlayerPositions(); - if (P_CheckRacers() && !exitcountdown) { G_BeginLevelExit(); @@ -1225,17 +1237,8 @@ void P_DoPlayerExit(player_t *player, pflags_t flags) } } - const boolean losing = K_IsPlayerLosing(player); // HEY!!!! Set it AFTER K_UpdateAllPlayerPositions!!!! - const boolean specialout = (specialstageinfo.valid == true && losing == true); - K_UpdatePowerLevelsFinalize(player, false); - if (G_GametypeUsesLives() && losing) - { - // Remove a life from the losing player - K_PlayerLoseLife(player); - } - if (P_IsLocalPlayer(player) && !specialout && musiccountdown == 0) { Music_Play("finish_silence"); From ad0ced4da019e20410fd82df934b5e6bc4e6f7d2 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Sat, 17 Feb 2024 15:40:58 -0600 Subject: [PATCH 13/33] Save config to temp file and move into place Fixes KartKrew/Kart#1020 by not trying to write over ringconfig until we have successfully written the whole config out, then atomically replacing the old config with the new one using C++17 FS. --- src/m_misc.cpp | 50 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 11 deletions(-) diff --git a/src/m_misc.cpp b/src/m_misc.cpp index bda4b49f2..4a494f335 100644 --- a/src/m_misc.cpp +++ b/src/m_misc.cpp @@ -20,6 +20,8 @@ #pragma GCC diagnostic ignored "-Wclobbered" #endif +#include + #include #endif @@ -673,7 +675,7 @@ void M_FirstLoadConfig(void) void M_SaveConfig(const char *filename) { FILE *f; - char *filepath; + char tmppath[2048]; // make sure not to write back the config until it's been correctly loaded if (!gameconfig_loaded) @@ -691,17 +693,23 @@ void M_SaveConfig(const char *filename) // append srb2home to beginning of filename // but check if srb2home isn't already there, first if (!strstr(filename, srb2home)) - filepath = va(pandf,srb2home, filename); - else - filepath = Z_StrDup(filename); - - f = fopen(filepath, "w"); - // change it only if valid - if (f) - strcpy(configfile, filepath); + { + sprintf(tmppath, "%s" PATHSEP "%s.tmp", srb2home, filename); + } else { - CONS_Alert(CONS_ERROR, M_GetText("Couldn't save game config file %s\n"), filepath); + sprintf(tmppath, "%s", filename); + } + + f = fopen(tmppath, "w"); + // change it only if valid + if (f) + { + strcpy(configfile, tmppath); + } + else + { + CONS_Alert(CONS_ERROR, M_GetText("Couldn't save game config file %s\n"), tmppath); return; } } @@ -713,7 +721,9 @@ void M_SaveConfig(const char *filename) return; } - f = fopen(configfile, "w"); + sprintf(tmppath, "%s.tmp", configfile); + + f = fopen(tmppath, "w"); if (!f) { CONS_Alert(CONS_ERROR, M_GetText("Couldn't save game config file %s\n"), configfile); @@ -738,6 +748,24 @@ void M_SaveConfig(const char *filename) } fclose(f); + + { + // Atomically replace the old config once the new one has been written. + + namespace fs = std::filesystem; + + fs::path tmp{tmppath}; + fs::path real{configfile}; + + try + { + fs::rename(tmp, real); + } + catch (const fs::filesystem_error& ex) + { + CONS_Alert(CONS_ERROR, M_GetText("Failed to move temp config file to real destination\n")); + } + } } // ========================================================================== From d917a7f3947ec8db896adf3be529bc0350a5d483 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Sat, 17 Feb 2024 16:23:08 -0600 Subject: [PATCH 14/33] Ignore no-contest antigrief if no humans left Allows all-bots races to continue to intermission and advance to next level. Fixes KartKrew/Kart#1018 --- src/p_inter.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_inter.c b/src/p_inter.c index 5dae5dc82..decd5cc56 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1505,7 +1505,7 @@ boolean P_CheckRacers(void) } else { - if (griefed == true) + if (griefed == true && numHumans > 0) { // Don't do this if someone spectated eliminateLast = false; @@ -2503,7 +2503,7 @@ static boolean P_KillPlayer(player_t *player, mobj_t *inflictor, mobj_t *source, if (gametyperules & (GTR_BUMPERS|GTR_CHECKPOINTS)) { if ((player->pitblame > -1) && (player->pitblame < MAXPLAYERS) - && (playeringame[player->pitblame]) && (!players[player->pitblame].spectator) + && (playeringame[player->pitblame]) && (!players[player->pitblame].spectator) && (players[player->pitblame].mo) && (!P_MobjWasRemoved(players[player->pitblame].mo))) { P_DamageMobj(player->mo, players[player->pitblame].mo, players[player->pitblame].mo, 1, DMG_KARMA); From 9c14c599299e6231c1eef04a007738ca53db2351 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Sat, 17 Feb 2024 14:58:23 -0600 Subject: [PATCH 15/33] Fix MT_SSCANDLE initialization --- src/info.c | 6 +++--- src/p_enemy.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/info.c b/src/info.c index 430373e7a..bc5068769 100644 --- a/src/info.c +++ b/src/info.c @@ -20954,7 +20954,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // mass 0, // damage sfx_None, // activesound - MF_SCENERY|MF_RUNSPAWNFUNC|MF_NOGRAVITY, // flags + MF_RUNSPAWNFUNC|MF_NOGRAVITY, // flags S_NULL // raisestate }, { // MT_SSCANDLE_SIDE @@ -20980,7 +20980,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // mass 0, // damage sfx_None, // activesound - MF_SCENERY|MF_NOGRAVITY|MF_NOTHINK, // flags + MF_SCENERY|MF_NOGRAVITY|MF_NOTHINK|MF_DRAWFROMFARAWAY, // flags S_NULL // raisestate }, { // MT_SSCANDLE_FLAME @@ -21006,7 +21006,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // mass 0, // damage sfx_None, // activesound - MF_SCENERY|MF_NOGRAVITY, // flags + MF_SCENERY|MF_NOGRAVITY|MF_DRAWFROMFARAWAY, // flags S_NULL // raisestate }, { // MT_SS_HOLOGRAM diff --git a/src/p_enemy.c b/src/p_enemy.c index b92fbed73..3f24bc544 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -12612,7 +12612,7 @@ void A_MakeSSCandle(mobj_t* actor) P_SetTarget(&actor->tracer, fire); // Sides - for (i = 0; i < 5; i++) + for (i = 0; i < 6; i++) { fixed_t a = FixedAngle(60 * FRACUNIT) * i; fixed_t offsetx = actor->x + FixedMul(dist, FCOS(a)); From 4cab7949327aabb1d1e087dd2cf6b0fe64ec0fb3 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Sat, 17 Feb 2024 17:59:20 -0600 Subject: [PATCH 16/33] Don't reset demo.attract in D_ClearState Fixes KartKrew/Kart#1053 allowing credits to continue after demo is exited. --- src/d_main.cpp | 1 - src/g_demo.c | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index ad5276ca1..074897dae 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -1093,7 +1093,6 @@ void D_ClearState(void) memset(displayplayers, 0, sizeof(displayplayers)); memset(g_localplayers, 0, sizeof g_localplayers); consoleplayer = 0; - demo.attract = DEMO_ATTRACT_OFF; G_SetGametype(GT_RACE); // SRB2kart paused = false; diff --git a/src/g_demo.c b/src/g_demo.c index 95ebc454a..52dfcf97d 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -3793,6 +3793,8 @@ boolean G_CheckDemoStatus(void) D_StartTitle(); } + demo.attract = DEMO_ATTRACT_OFF; + return true; } From 2e60465638c15dd970a6c380c3b95060f1cc84b5 Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 17 Feb 2024 16:38:11 -0800 Subject: [PATCH 17/33] debugchallenges: unset conditionset achieved If you undo an unlock, fixes that unlock automatically unlocking itself the next time conditions are evaluated. --- src/menus/extras-challenges.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/menus/extras-challenges.c b/src/menus/extras-challenges.c index 8e6395437..0911e9632 100644 --- a/src/menus/extras-challenges.c +++ b/src/menus/extras-challenges.c @@ -792,6 +792,11 @@ boolean M_ChallengesInputs(INT32 ch) if (cv_debugchallenges.value && challengesmenu.currentunlock < MAXUNLOCKABLES && challengesmenu.unlockanim >= UNLOCKTIME && gamedata->unlocked[challengesmenu.currentunlock] == true) { gamedata->unlocked[challengesmenu.currentunlock] = gamedata->unlockpending[challengesmenu.currentunlock] = false; + UINT16 set = unlockables[challengesmenu.currentunlock].conditionset; + if (set > 0 && set <= MAXCONDITIONSETS) + { + gamedata->achieved[set - 1] = false; + } M_UpdateChallengeGridVisuals(); } From cc240600e9731f970431a77e953553476f3e5b97 Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 17 Feb 2024 16:39:05 -0800 Subject: [PATCH 18/33] M_CheckCondition: fix UCRP_PODIUMCUP GP grade - PodiumCup grade condition was completely broken and checked against the cup ID instead of the grade letter --- src/m_cond.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/m_cond.c b/src/m_cond.c index 9414e73fa..98b1548e3 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -1628,7 +1628,7 @@ boolean M_CheckCondition(condition_t *cn, player_t *player) ) return false; if (cn->extrainfo2 != 0) - return (K_PodiumGrade() >= cn->requirement); + return (K_PodiumGrade() >= cn->extrainfo1); if (cn->extrainfo1 != 0) return (player->position != 0 && player->position <= cn->extrainfo1); From b0348526cd9487136c7e99e4b41c861efb640483 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Sat, 17 Feb 2024 23:58:03 -0600 Subject: [PATCH 19/33] Rewrite gamedata format --- src/CMakeLists.txt | 1 + src/g_game.c | 1099 +------------------------------------------- src/g_gamedata.cpp | 688 +++++++++++++++++++++++++++ src/g_gamedata.h | 229 +++++++++ src/io/streams.cpp | 156 +++++++ src/io/streams.hpp | 171 +++++++ 6 files changed, 1250 insertions(+), 1094 deletions(-) create mode 100644 src/g_gamedata.cpp create mode 100644 src/g_gamedata.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d48f2b506..bdaa9bec1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -19,6 +19,7 @@ add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32 g_build_ticcmd.cpp g_demo.c g_game.c + g_gamedata.cpp g_input.c g_party.cpp am_map.c diff --git a/src/g_game.c b/src/g_game.c index 3e69e344a..b4bf60bb5 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -73,6 +73,7 @@ #include "k_roulette.h" #include "k_objects.h" #include "k_credits.h" +#include "g_gamedata.h" #ifdef HAVE_DISCORDRPC #include "discord.h" @@ -4708,652 +4709,6 @@ void G_LoadGameSettings(void) Color_cons_t[MAXSKINCOLORS].strvalue = Followercolor_cons_t[MAXSKINCOLORS+2].strvalue = NULL; } -#define GD_VERSIONCHECK 0xBA5ED123 // Change every major version, as usual -#define GD_VERSIONMINOR 10 // Change every format update - -// You can't rearrange these without a special format update -typedef enum -{ - GDEVER_ADDON = 1, - GDEVER_CREDITS = 1<<1, - GDEVER_REPLAY = 1<<2, - GDEVER_SPECIAL = 1<<3, - GDEVER_KEYTUTORIAL = 1<<4, - GDEVER_KEYMAJORSKIP = 1<<5, - GDEVER_TUTORIALSKIP = 1<<6, - GDEVER_ENTERTUTSKIP = 1<<7, - // --- Free up to 1<<23 --- // - GDEVER_GONERSHIFT = 24, // nothing above this -} gdeverdone_t; - -static const char *G_GameDataFolder(void) -{ - if (strcmp(srb2home,".")) - return srb2home; - else - return "the Ring Racers folder"; -} - -// G_LoadGameData -// Loads the main data file, which stores information such as emblems found, etc. -void G_LoadGameData(void) -{ - UINT32 i, j; - UINT32 versionID; - UINT8 versionMinor; - UINT8 rtemp; - boolean gridunusable = false; - savebuffer_t save = {0}; - - UINT16 emblemreadcount = MAXEMBLEMS; - UINT16 unlockreadcount = MAXUNLOCKABLES; - UINT16 conditionreadcount = MAXCONDITIONSETS; - size_t unlockreadsize = sizeof(UINT16); - - //For records - UINT32 numgamedataskins; - UINT32 numgamedatamapheaders; - UINT32 numgamedatacups; - - // Stop saving, until we successfully load it again. - gamedata->loaded = false; - - // Clear things so previously read gamedata doesn't transfer - // to new gamedata - // see also M_EraseDataResponse - G_ClearRecords(); // records - M_ClearStats(); // statistics - M_ClearSecrets(); // emblems, unlocks, maps visited, etc - - if (M_CheckParm("-nodata")) - { - // Don't load at all. - // The following used to be in M_ClearSecrets, but that was silly. - M_UpdateUnlockablesAndExtraEmblems(false, true); - return; - } - - if (M_CheckParm("-resetdata")) - { - // Don't load, but do save. (essentially, reset) - goto finalisegamedata; - } - - if (P_SaveBufferFromFile(&save, va(pandf, srb2home, gamedatafilename)) == false) - { - // No gamedata. We can save a new one. - goto finalisegamedata; - } - - // Version check - versionID = READUINT32(save.p); - if (versionID != GD_VERSIONCHECK) - { - const char *gdfolder = G_GameDataFolder(); - - P_SaveBufferFree(&save); - I_Error("Game data is not for Ring Racers v2.0.\nDelete %s (maybe in %s) and try again.", gamedatafilename, gdfolder); - } - - versionMinor = READUINT8(save.p); - if (versionMinor > GD_VERSIONMINOR) - { - const char *gdfolder = G_GameDataFolder(); - - P_SaveBufferFree(&save); - I_Error("Game data is from the future! (expected %d, got %d)\nRename or delete %s (maybe in %s) and try again.", GD_VERSIONMINOR, versionMinor, gamedatafilename, gdfolder); - } - else if (versionMinor < GD_VERSIONMINOR) - { - // We're converting - let'd create a backup. - FIL_WriteFile(va("%s" PATHSEP "%s.bak", srb2home, gamedatafilename), save.buffer, save.size); - } - - if ((versionMinor <= 6) -#ifdef DEVELOP - || M_CheckParm("-resetchallengegrid") -#endif - ) - { - gridunusable = true; - } - - if (versionMinor > 1) - { - gamedata->evercrashed = (boolean)READUINT8(save.p); - } - - gamedata->totalplaytime = READUINT32(save.p); - - if (versionMinor > 1) - { - gamedata->totalrings = READUINT32(save.p); - - if (versionMinor >= 9) - { - gamedata->totaltumbletime = READUINT32(save.p); - } - - for (i = 0; i < GDGT_MAX; i++) - { - gamedata->roundsplayed[i] = READUINT32(save.p); - } - - gamedata->pendingkeyrounds = READUINT32(save.p); - gamedata->pendingkeyroundoffset = READUINT8(save.p); - - if (versionMinor < 3) - { - gamedata->keyspending = READUINT8(save.p); - } - else - { - gamedata->keyspending = READUINT16(save.p); - } - - // Sanity check. - if (gamedata->pendingkeyroundoffset >= GDCONVERT_ROUNDSTOKEY) - { - gamedata->pendingkeyrounds += - (gamedata->pendingkeyroundoffset - - (GDCONVERT_ROUNDSTOKEY-1)); - gamedata->pendingkeyroundoffset = (GDCONVERT_ROUNDSTOKEY-1); - gamedata->keyspending = 0; // safe to nuke - will be recalc'd if the offset still permits - } - - gamedata->chaokeys = READUINT16(save.p); - - if (versionMinor >= 4) - { - UINT32 everflags = READUINT32(save.p); - - gamedata->everloadedaddon = !!(everflags & GDEVER_ADDON); - gamedata->everfinishedcredits = !!(everflags & GDEVER_CREDITS); - gamedata->eversavedreplay = !!(everflags & GDEVER_REPLAY); - gamedata->everseenspecial = !!(everflags & GDEVER_SPECIAL); - gamedata->chaokeytutorial = !!(everflags & GDEVER_KEYTUTORIAL); - gamedata->majorkeyskipattempted = !!(everflags & GDEVER_KEYMAJORSKIP); - gamedata->finishedtutorialchallenge = !!(everflags & GDEVER_TUTORIALSKIP); - gamedata->enteredtutorialchallenge = !!(everflags & GDEVER_ENTERTUTSKIP); - - gamedata->gonerlevel = everflags>>GDEVER_GONERSHIFT; - } - else - { - gamedata->everloadedaddon = (boolean)READUINT8(save.p); - gamedata->eversavedreplay = (boolean)READUINT8(save.p); - gamedata->everseenspecial = (boolean)READUINT8(save.p); - } - } - else - { - save.p += 4; // no direct equivalent to matchesplayed - } - - // Prison Egg Pickups - if (versionMinor >= 8) - { - gamedata->thisprisoneggpickup = READUINT16(save.p); - gamedata->prisoneggstothispickup = READUINT16(save.p); - } - - { - // Quick & dirty hash for what mod this save file is for. - UINT32 modID = READUINT32(save.p); - UINT32 expectedID = quickncasehash(timeattackfolder, 64); - - if (modID != expectedID) - { - // Aha! Someone's been screwing with the save file! - goto datacorrupt; - } - } - - if (versionMinor < 3) - { - emblemreadcount = 512; - unlockreadcount = conditionreadcount = UINT8_MAX; - unlockreadsize = sizeof(UINT8); - } - else if (versionMinor < 10) - { - emblemreadcount = 1024*2; - } - - // To save space, use one bit per collected/achieved/unlocked flag - for (i = 0; i < emblemreadcount;) - { - rtemp = READUINT8(save.p); - for (j = 0; j < 8 && j+i < emblemreadcount; ++j) - gamedata->collected[j+i] = ((rtemp >> j) & 1); - i += j; - } - for (i = 0; i < unlockreadcount;) - { - rtemp = READUINT8(save.p); - for (j = 0; j < 8 && j+i < unlockreadcount; ++j) - gamedata->unlocked[j+i] = ((rtemp >> j) & 1); - i += j; - } - for (i = 0; i < unlockreadcount;) - { - rtemp = READUINT8(save.p); - for (j = 0; j < 8 && j+i < unlockreadcount; ++j) - gamedata->unlockpending[j+i] = ((rtemp >> j) & 1); - i += j; - } - for (i = 0; i < conditionreadcount;) - { - rtemp = READUINT8(save.p); - for (j = 0; j < 8 && j+i < conditionreadcount; ++j) - gamedata->achieved[j+i] = ((rtemp >> j) & 1); - i += j; - } - - if (gridunusable) - { - UINT16 burn = READUINT16(save.p); // Previous challengegridwidth - UINT8 height = (versionMinor && versionMinor <= 6) ? 4 : CHALLENGEGRIDHEIGHT; - save.p += (burn * height * unlockreadsize); // Step over previous grid data - - gamedata->challengegridwidth = 0; - Z_Free(gamedata->challengegrid); - gamedata->challengegrid = NULL; - } - else - { - gamedata->challengegridwidth = READUINT16(save.p); - Z_Free(gamedata->challengegrid); - if (gamedata->challengegridwidth) - { - gamedata->challengegrid = Z_Malloc( - (gamedata->challengegridwidth * CHALLENGEGRIDHEIGHT * sizeof(UINT16)), - PU_STATIC, NULL); - if (unlockreadsize == sizeof(UINT8)) - { - for (i = 0; i < (gamedata->challengegridwidth * CHALLENGEGRIDHEIGHT); i++) - { - gamedata->challengegrid[i] = READUINT8(save.p); - if (gamedata->challengegrid[i] == unlockreadcount) - gamedata->challengegrid[i] = MAXUNLOCKABLES; - } - } - else - { - for (i = 0; i < (gamedata->challengegridwidth * CHALLENGEGRIDHEIGHT); i++) - { - gamedata->challengegrid[i] = READUINT16(save.p); - } - } - - M_SanitiseChallengeGrid(); - } - else - { - gamedata->challengegrid = NULL; - } - } - - gamedata->timesBeaten = READUINT32(save.p); - - // Main records - - skinreference_t *tempskinreferences = NULL; - - if (versionMinor < 3) - { - gamedata->importprofilewins = true; - numgamedataskins = 0; - } - else - { - numgamedataskins = READUINT32(save.p); - - if (numgamedataskins) - { - tempskinreferences = Z_Malloc( - numgamedataskins * sizeof (skinreference_t), - PU_STATIC, - NULL - ); - - for (i = 0; i < numgamedataskins; i++) - { - char skinname[SKINNAMESIZE+1]; - INT32 skin; - - READSTRINGN(save.p, skinname, SKINNAMESIZE); - skin = R_SkinAvailable(skinname); - - skinrecord_t dummyrecord; - - dummyrecord.wins = READUINT32(save.p); - dummyrecord._saveid = i; - - tempskinreferences[i].id = MAXSKINS; - - if (skin != -1) - { - // We found a skin, so assign the win. - - M_Memcpy(&skins[skin].records, &dummyrecord, sizeof(skinrecord_t)); - - tempskinreferences[i].id = skin; - tempskinreferences[i].unloaded = NULL; - } - else if (dummyrecord.wins) - { - // Invalid, but we don't want to lose all the juicy statistics. - // Instead, update a FILO linked list of "unloaded skins". - - unloaded_skin_t *unloadedskin = - Z_Malloc( - sizeof(unloaded_skin_t), - PU_STATIC, NULL - ); - - // Establish properties, for later retrieval on file add. - strlcpy(unloadedskin->name, skinname, sizeof(unloadedskin->name)); - unloadedskin->namehash = quickncasehash(unloadedskin->name, SKINNAMESIZE); - - // Insert at the head, just because it's convenient. - unloadedskin->next = unloadedskins; - unloadedskins = unloadedskin; - - // Finally, copy into. - M_Memcpy(&unloadedskin->records, &dummyrecord, sizeof(skinrecord_t)); - - tempskinreferences[i].unloaded = unloadedskin; - } - } - } - } - - UINT16 *tempmapidreferences = NULL; - - numgamedatamapheaders = READUINT32(save.p); - - if (numgamedatamapheaders) - { - tempmapidreferences = Z_Malloc( - numgamedatamapheaders * sizeof (UINT16), - PU_STATIC, - NULL - ); - - for (i = 0; i < numgamedatamapheaders; i++) - { - char mapname[MAXMAPLUMPNAME]; - UINT16 mapnum; - - READSTRINGL(save.p, mapname, MAXMAPLUMPNAME); - mapnum = G_MapNumber(mapname); - - tempmapidreferences[i] = (UINT16)mapnum; - - recorddata_t dummyrecord; - - dummyrecord.mapvisited = READUINT8(save.p); - dummyrecord.time = (tic_t)READUINT32(save.p); - dummyrecord.lap = (tic_t)READUINT32(save.p); - - if (mapnum < nummapheaders && mapheaderinfo[mapnum]) - { - // Valid mapheader, time to populate with record data. - - dummyrecord.mapvisited &= MV_MAX; - M_Memcpy(&mapheaderinfo[mapnum]->records, &dummyrecord, sizeof(recorddata_t)); - } - else if ( - (dummyrecord.mapvisited & MV_BEATEN) - || dummyrecord.time != 0 - || dummyrecord.lap != 0 - ) - { - // Invalid, but we don't want to lose all the juicy statistics. - // Instead, update a FILO linked list of "unloaded mapheaders". - - unloaded_mapheader_t *unloadedmap = - Z_Malloc( - sizeof(unloaded_mapheader_t), - PU_STATIC, NULL - ); - - // Establish properties, for later retrieval on file add. - unloadedmap->lumpname = Z_StrDup(mapname); - unloadedmap->lumpnamehash = quickncasehash(unloadedmap->lumpname, MAXMAPLUMPNAME); - - // Insert at the head, just because it's convenient. - unloadedmap->next = unloadedmapheaders; - unloadedmapheaders = unloadedmap; - - // Finally, copy into. - M_Memcpy(&unloadedmap->records, &dummyrecord, sizeof(recorddata_t)); - } - } - } - - if (versionMinor > 5) - { - gamedata->gotspraycans = 0; - gamedata->numspraycans = READUINT16(save.p); - Z_Free(gamedata->spraycans); - - if (gamedata->numspraycans) - { - gamedata->spraycans = Z_Malloc( - (gamedata->numspraycans * sizeof(candata_t)), - PU_STATIC, NULL); - - for (i = 0; i < gamedata->numspraycans; i++) - { - gamedata->spraycans[i].col = SKINCOLOR_NONE; - gamedata->spraycans[i].map = NEXTMAP_INVALID; - - UINT16 col = READUINT16(save.p); - UINT32 _saveid = READUINT32(save.p); - - if (col < SKINCOLOR_FIRSTFREESLOT) - { - gamedata->spraycans[i].col = col; - skincolors[col].cache_spraycan = i; - } - - if (_saveid >= numgamedatamapheaders) - { - // Can has not been grabbed on any map, this is intentional. - continue; - } - - UINT16 map = tempmapidreferences[_saveid]; - if (map >= nummapheaders || !mapheaderinfo[map]) - { - //CONS_Printf("LOAD - Can %u, color %s - id %u (unloaded header)\n", i, skincolors[col].name, _saveid); - continue; - } - - //CONS_Printf("LOAD - Can %u, color %s - id %u, map %d\n", i, skincolors[col].name, _saveid, map); - - gamedata->spraycans[i].map = map; - - if (gamedata->gotspraycans != i) - { - //CONS_Printf("LOAD - Swapping gotten can %u, color %s with prior ungotten can %u\n", i, skincolors[col].name, gamedata->gotspraycans); - - // All grabbed cans should be at the head of the list. - // Let's swap with the can the disjoint occoured at. - // This will prevent a gap from occouring on reload. - candata_t copycan = gamedata->spraycans[gamedata->gotspraycans]; - gamedata->spraycans[gamedata->gotspraycans] = gamedata->spraycans[i]; - gamedata->spraycans[i] = copycan; - - mapheaderinfo[copycan.map]->cache_spraycan = i; - } - - mapheaderinfo[map]->cache_spraycan = gamedata->gotspraycans; - - gamedata->gotspraycans++; - } - } - else - { - gamedata->spraycans = NULL; - } - } - - if (versionMinor > 1) - { - numgamedatacups = READUINT32(save.p); - - for (i = 0; i < numgamedatacups; i++) - { - char cupname[MAXCUPNAME]; - cupheader_t *cup; - - cupwindata_t dummywindata[4]; - - // Find the relevant cup. - if (versionMinor < 5) - { - // Before this version cups were called things like RING. - // Now that example cup would be called RR_RING instead. - cupname[0] = cupname[1] = 'R'; - cupname[2] = '_'; - READSTRINGL(save.p, (cupname + 3), sizeof(cupname) - 3); - } - else - { - READSTRINGL(save.p, cupname, sizeof(cupname)); - } - - UINT32 hash = quickncasehash(cupname, MAXCUPNAME); - for (cup = kartcupheaders; cup; cup = cup->next) - { - if (cup->namehash != hash) - continue; - - if (strcmp(cup->name, cupname)) - continue; - - break; - } - - // Digest its data... - for (j = 0; j < KARTGP_MAX; j++) - { - rtemp = READUINT8(save.p); - - dummywindata[j].best_placement = (rtemp & 0x0F); - dummywindata[j].best_grade = (rtemp & 0x70)>>4; - dummywindata[j].got_emerald = !!(rtemp & 0x80); - - dummywindata[j].best_skin.id = MAXSKINS; - dummywindata[j].best_skin.unloaded = NULL; - if (versionMinor >= 3) - { - UINT32 _saveid = READUINT32(save.p); - if (_saveid < numgamedataskins) - { - M_Memcpy(&dummywindata[j].best_skin, &tempskinreferences[_saveid], sizeof(dummywindata[j].best_skin)); - } - } - } - - if (versionMinor < 3) - { - // We now require backfilling of placement information. - - cupwindata_t bestwindata; - bestwindata.best_placement = 0; - - j = KARTGP_MAX; - while (j > 0) - { - j--; - - if (bestwindata.best_placement == 0) - { - if (dummywindata[j].best_placement != 0) - { - M_Memcpy(&bestwindata, &dummywindata[j], sizeof(bestwindata)); - } - continue; - } - - if (dummywindata[j].best_placement != 0) - { - if (dummywindata[j].best_placement < bestwindata.best_placement) - bestwindata.best_placement = dummywindata[j].best_placement; - - if (dummywindata[j].best_grade > bestwindata.best_grade) - bestwindata.best_grade = dummywindata[j].best_grade; - - bestwindata.got_emerald |= dummywindata[j].got_emerald; - } - - M_Memcpy(&dummywindata[j], &bestwindata, sizeof(dummywindata[j])); - } - } - - if (cup) - { - // We found a cup, so assign the windata. - - M_Memcpy(&cup->windata, &dummywindata, sizeof(cup->windata)); - } - else if (dummywindata[0].best_placement != 0) - { - // Invalid, but we don't want to lose all the juicy statistics. - // Instead, update a FILO linked list of "unloaded cupheaders". - - unloaded_cupheader_t *unloadedcup = - Z_Malloc( - sizeof(unloaded_cupheader_t), - PU_STATIC, NULL - ); - - // Establish properties, for later retrieval on file add. - strlcpy(unloadedcup->name, cupname, sizeof(unloadedcup->name)); - unloadedcup->namehash = quickncasehash(unloadedcup->name, MAXCUPNAME); - - // Insert at the head, just because it's convenient. - unloadedcup->next = unloadedcupheaders; - unloadedcupheaders = unloadedcup; - - // Finally, copy into. - M_Memcpy(&unloadedcup->windata, &dummywindata, sizeof(unloadedcup->windata)); - } - } - } - - if (tempskinreferences) - Z_Free(tempskinreferences); - if (tempmapidreferences) - Z_Free(tempmapidreferences); - - // done - P_SaveBufferFree(&save); - - finalisegamedata: - { - M_FinaliseGameData(); - - return; - } - - // Landing point for corrupt gamedata - datacorrupt: - { - const char *gdfolder = "the Ring Racers folder"; - if (strcmp(srb2home,".")) - gdfolder = srb2home; - - P_SaveBufferFree(&save); - - I_Error("Corrupt game data file.\nDelete %s(maybe in %s) and try again.", gamedatafilename, gdfolder); - } -} - // G_DirtyGameData // Modifies the gamedata as little as possible to maintain safety in a crash event, while still recording it. void G_DirtyGameData(void) @@ -5365,11 +4720,14 @@ void G_DirtyGameData(void) gamedata->evercrashed = true; //if (FIL_WriteFileOK(name)) - handle = fopen(va(pandf, srb2home, gamedatafilename), "r+"); + handle = fopen(va(pandf, srb2home, gamedatafilename), "r+b"); if (!handle) return; + // IO needs to be unbuffered too, so we try not to allocate anything. + setvbuf(handle, NULL, _IONBF, 0); + // Write a dirty byte immediately after the gamedata check + minor version. if (fseek(handle, 5, SEEK_SET) != -1) fwrite(&writebytesource, 1, 1, handle); @@ -5379,453 +4737,6 @@ void G_DirtyGameData(void) return; } -// G_SaveGameData -// Saves the main data file, which stores information such as emblems found, etc. -void G_SaveGameData(void) -{ - size_t length; - INT32 i, j; - cupheader_t *cup; - UINT8 btemp; - savebuffer_t save = {0}; - - if (gamedata == NULL || !gamedata->loaded) - return; // If never loaded (-nodata), don't save - - gamedata->deferredsave = false; - - if (usedCheats) - { -#ifdef DEVELOP - CONS_Alert(CONS_WARNING, M_GetText("Cheats used - Gamedata will not be saved.\n")); -#endif - return; - } - - length = (4+1+1+ - 4+4+4+ - (4*GDGT_MAX)+ - 4+1+2+2+ - 4+ - 2+2+ - 4+ - (MAXEMBLEMS+(MAXUNLOCKABLES*2)+MAXCONDITIONSETS)+ - 4+2); - - if (gamedata->challengegrid) - { - length += (gamedata->challengegridwidth * CHALLENGEGRIDHEIGHT) * 2; - } - - - UINT32 numgamedataskins = 0; - unloaded_skin_t *unloadedskin; - - for (i = 0; i < numskins; i++) - { - // It's safe to assume a skin with no wins will have no other data worth keeping - if (skins[i].records.wins == 0) - { - continue; - } - - numgamedataskins++; - } - - for (unloadedskin = unloadedskins; unloadedskin; unloadedskin = unloadedskin->next) - { - // Ditto, with the exception that we should warn about it. - if (unloadedskin->records.wins == 0) - { - CONS_Alert(CONS_WARNING, "Unloaded skin \"%s\" has no wins!\n", unloadedskin->name); - continue; - } - - numgamedataskins++; - } - - length += 4 + (numgamedataskins * (SKINNAMESIZE+4)); - - - UINT32 numgamedatamapheaders = 0; - unloaded_mapheader_t *unloadedmap; - - for (i = 0; i < nummapheaders; i++) - { - // No spraycan attached. - if (mapheaderinfo[i]->cache_spraycan >= gamedata->numspraycans - // It's safe to assume a level with no mapvisited will have no other data worth keeping, since you get MV_VISITED just for opening it. - && !(mapheaderinfo[i]->records.mapvisited & MV_MAX)) - { - mapheaderinfo[i]->_saveid = UINT32_MAX; - continue; - } - - mapheaderinfo[i]->_saveid = numgamedatamapheaders; - numgamedatamapheaders++; - } - - for (unloadedmap = unloadedmapheaders; unloadedmap; unloadedmap = unloadedmap->next) - { - // Ditto, with the exception that we should warn about it. - if (!(unloadedmap->records.mapvisited & MV_MAX)) - { - CONS_Alert(CONS_WARNING, "Unloaded map \"%s\" has no mapvisited!\n", unloadedmap->lumpname); - continue; - } - - // It's far off on the horizon, beyond many memory limits, but prevent a potential misery moment of losing ALL your data. - if (++numgamedatamapheaders == UINT32_MAX) - { - CONS_Alert(CONS_WARNING, "Some unloaded map record data has been dropped due to datatype limitations.\n"); - break; - } - } - - length += 4 + (numgamedatamapheaders * (MAXMAPLUMPNAME+1+4+4)); - - length += 2; - - if (gamedata->numspraycans) - { - length += (gamedata->numspraycans * (2 + 4)); - } - - - UINT32 numgamedatacups = 0; - unloaded_cupheader_t *unloadedcup; - - for (cup = kartcupheaders; cup; cup = cup->next) - { - // Results are populated downwards, so no Easy win - // means there's no important player data to save. - if (cup->windata[0].best_placement == 0) - continue; - - numgamedatacups++; - } - - for (unloadedcup = unloadedcupheaders; unloadedcup; unloadedcup = unloadedcup->next) - { - // Ditto, with the exception that we should warn about it. - if (unloadedcup->windata[0].best_placement == 0) - { - CONS_Alert(CONS_WARNING, "Unloaded cup \"%s\" has no windata!\n", unloadedcup->name); - continue; - } - - // It's far off on the horizon, beyond many memory limits, but prevent a potential misery moment of losing ALL your data. - if (++numgamedatacups == UINT32_MAX) - { - CONS_Alert(CONS_WARNING, "Some unloaded cup standings data has been dropped due to datatype limitations.\n"); - break; - } - } - - length += 4 + (numgamedatacups * (MAXCUPNAME + 4*(1+4))); - - - if (P_SaveBufferAlloc(&save, length) == false) - { - CONS_Alert(CONS_ERROR, M_GetText("No more free memory for saving game data\n")); - return; - } - - // Version test - - WRITEUINT32(save.p, GD_VERSIONCHECK); // 4 - WRITEUINT8(save.p, GD_VERSIONMINOR); // 1 - - // Crash dirtiness - // cannot move, see G_DirtyGameData - WRITEUINT8(save.p, gamedata->evercrashed); // 1 - - // Statistics - - WRITEUINT32(save.p, gamedata->totalplaytime); // 4 - WRITEUINT32(save.p, gamedata->totalrings); // 4 - WRITEUINT32(save.p, gamedata->totaltumbletime); // 4 - - for (i = 0; i < GDGT_MAX; i++) // 4 * GDGT_MAX - { - WRITEUINT32(save.p, gamedata->roundsplayed[i]); - } - - WRITEUINT32(save.p, gamedata->pendingkeyrounds); // 4 - WRITEUINT8(save.p, gamedata->pendingkeyroundoffset); // 1 - WRITEUINT16(save.p, gamedata->keyspending); // 2 - WRITEUINT16(save.p, gamedata->chaokeys); // 2 - - { - UINT32 everflags = (gamedata->gonerlevel<everloadedaddon) - everflags |= GDEVER_ADDON; - if (gamedata->everfinishedcredits) - everflags |= GDEVER_CREDITS; - if (gamedata->eversavedreplay) - everflags |= GDEVER_REPLAY; - if (gamedata->everseenspecial) - everflags |= GDEVER_SPECIAL; - if (gamedata->chaokeytutorial) - everflags |= GDEVER_KEYTUTORIAL; - if (gamedata->majorkeyskipattempted) - everflags |= GDEVER_KEYMAJORSKIP; - if (gamedata->finishedtutorialchallenge) - everflags |= GDEVER_TUTORIALSKIP; - if (gamedata->enteredtutorialchallenge) - everflags |= GDEVER_ENTERTUTSKIP; - - WRITEUINT32(save.p, everflags); // 4 - } - - // Prison Egg Pickups - WRITEUINT16(save.p, gamedata->thisprisoneggpickup); // 2 - WRITEUINT16(save.p, gamedata->prisoneggstothispickup); // 2 - - WRITEUINT32(save.p, quickncasehash(timeattackfolder, 64)); // 4 - - // To save space, use one bit per collected/achieved/unlocked flag - for (i = 0; i < MAXEMBLEMS;) // MAXEMBLEMS * 1; - { - btemp = 0; - for (j = 0; j < 8 && j+i < MAXEMBLEMS; ++j) - btemp |= (gamedata->collected[j+i] << j); - WRITEUINT8(save.p, btemp); - i += j; - } - - // MAXUNLOCKABLES * 2; - for (i = 0; i < MAXUNLOCKABLES;) - { - btemp = 0; - for (j = 0; j < 8 && j+i < MAXUNLOCKABLES; ++j) - btemp |= (gamedata->unlocked[j+i] << j); - WRITEUINT8(save.p, btemp); - i += j; - } - for (i = 0; i < MAXUNLOCKABLES;) - { - btemp = 0; - for (j = 0; j < 8 && j+i < MAXUNLOCKABLES; ++j) - btemp |= (gamedata->unlockpending[j+i] << j); - WRITEUINT8(save.p, btemp); - i += j; - } - - for (i = 0; i < MAXCONDITIONSETS;) // MAXCONDITIONSETS * 1; - { - btemp = 0; - for (j = 0; j < 8 && j+i < MAXCONDITIONSETS; ++j) - btemp |= (gamedata->achieved[j+i] << j); - WRITEUINT8(save.p, btemp); - i += j; - } - - if (gamedata->challengegrid) // 2 + (gamedata->challengegridwidth * CHALLENGEGRIDHEIGHT) * 2 - { - WRITEUINT16(save.p, gamedata->challengegridwidth); - for (i = 0; i < (gamedata->challengegridwidth * CHALLENGEGRIDHEIGHT); i++) - { - WRITEUINT16(save.p, gamedata->challengegrid[i]); - } - } - else // 2 - { - WRITEUINT16(save.p, 0); - } - - WRITEUINT32(save.p, gamedata->timesBeaten); // 4 - - // Main records - - WRITEUINT32(save.p, numgamedataskins); // 4 - - { - // numgamedataskins * (SKINNAMESIZE+4) - - UINT32 maxid = 0; - - for (i = 0; i < numskins; i++) - { - if (skins[i].records.wins == 0) - { - skins[i].records._saveid = UINT32_MAX; - continue; - } - - WRITESTRINGN(save.p, skins[i].name, SKINNAMESIZE); - - WRITEUINT32(save.p, skins[i].records.wins); - - skins[i].records._saveid = maxid; - if (++maxid == numgamedataskins) - break; - } - - if (maxid < numgamedataskins) - { - for (unloadedskin = unloadedskins; unloadedskin; unloadedskin = unloadedskin->next) - { - if (unloadedskin->records.wins == 0) - continue; - - WRITESTRINGN(save.p, unloadedskin->name, SKINNAMESIZE); - - WRITEUINT32(save.p, unloadedskin->records.wins); - - unloadedskin->records._saveid = maxid; - if (++maxid == numgamedataskins) - break; - } - } - } - -#define GETSKINREFSAVEID(ref, var) \ - { \ - if (ref.unloaded != NULL) \ - var = ref.unloaded->records._saveid;\ - else if (ref.id < numskins)\ - var = skins[ref.id].records._saveid; \ - else \ - var = UINT32_MAX; \ - } - - WRITEUINT32(save.p, numgamedatamapheaders); // 4 - - if (numgamedatamapheaders) - { - // numgamedatamapheaders * (MAXMAPLUMPNAME+1+4+4) - - for (i = 0; i < nummapheaders; i++) - { - if (mapheaderinfo[i]->cache_spraycan >= gamedata->numspraycans - && !(mapheaderinfo[i]->records.mapvisited & MV_MAX)) - continue; - - WRITESTRINGL(save.p, mapheaderinfo[i]->lumpname, MAXMAPLUMPNAME); - - UINT8 mapvisitedtemp = (mapheaderinfo[i]->records.mapvisited & MV_MAX); - - WRITEUINT8(save.p, mapvisitedtemp); - - WRITEUINT32(save.p, mapheaderinfo[i]->records.time); - WRITEUINT32(save.p, mapheaderinfo[i]->records.lap); - - if (--numgamedatamapheaders == 0) - break; - } - - if (numgamedatamapheaders) - { - for (unloadedmap = unloadedmapheaders; unloadedmap; unloadedmap = unloadedmap->next) - { - if (!(unloadedmap->records.mapvisited & MV_MAX)) - continue; - - WRITESTRINGL(save.p, unloadedmap->lumpname, MAXMAPLUMPNAME); - - WRITEUINT8(save.p, unloadedmap->records.mapvisited); - - WRITEUINT32(save.p, unloadedmap->records.time); - WRITEUINT32(save.p, unloadedmap->records.lap); - - if (--numgamedatamapheaders == 0) - break; - } - } - } - - WRITEUINT16(save.p, gamedata->numspraycans); // 2 - - // gamedata->numspraycans * (2 + 4) - - for (i = 0; i < gamedata->numspraycans; i++) - { - WRITEUINT16(save.p, gamedata->spraycans[i].col); - - UINT32 _saveid = UINT32_MAX; - - UINT16 map = gamedata->spraycans[i].map; - - if (map < nummapheaders && mapheaderinfo[map]) - { - _saveid = mapheaderinfo[map]->_saveid; - } - - //CONS_Printf("SAVE - Can %u, color %s - id %u, map %d\n", i, skincolors[gamedata->spraycans[i].col].name, _saveid, map); - - WRITEUINT32(save.p, _saveid); - } - - WRITEUINT32(save.p, numgamedatacups); // 4 - - if (numgamedatacups) - { - // numgamedatacups * (MAXCUPNAME + 4*(1+4)) - -#define WRITECUPWINDATA(maybeunloadedcup) \ - for (i = 0; i < KARTGP_MAX; i++) \ - { \ - btemp = min(maybeunloadedcup->windata[i].best_placement, 0x0F); \ - btemp |= (maybeunloadedcup->windata[i].best_grade<<4); \ - if (maybeunloadedcup->windata[i].got_emerald == true) \ - btemp |= 0x80; \ - \ - WRITEUINT8(save.p, btemp); \ - \ - GETSKINREFSAVEID(maybeunloadedcup->windata[i].best_skin, j); \ - \ - WRITEUINT32(save.p, j); \ - } - - for (cup = kartcupheaders; cup; cup = cup->next) - { - if (cup->windata[0].best_placement == 0) - continue; - - WRITESTRINGL(save.p, cup->name, MAXCUPNAME); - - WRITECUPWINDATA(cup); - - if (--numgamedatacups == 0) - break; - } - - if (numgamedatacups) - { - for (unloadedcup = unloadedcupheaders; unloadedcup; unloadedcup = unloadedcup->next) - { - if (unloadedcup->windata[0].best_placement == 0) - continue; - - WRITESTRINGL(save.p, unloadedcup->name, MAXCUPNAME); - - WRITECUPWINDATA(unloadedcup); - - if (--numgamedatacups == 0) - break; - } - } - -#undef WRITECUPWINDATA - } - -#undef GETSKINREFSAVEID - - length = save.p - save.buffer; - - FIL_WriteFile(va(pandf, srb2home, gamedatafilename), save.buffer, length); - P_SaveBufferFree(&save); - - // Also save profiles here. - PR_SaveProfiles(); - - #ifdef DEVELOP - CONS_Alert(CONS_NOTICE, M_GetText("Gamedata saved.\n")); - #endif -} - #define VERSIONSIZE 16 // diff --git a/src/g_gamedata.cpp b/src/g_gamedata.cpp new file mode 100644 index 000000000..a685742b2 --- /dev/null +++ b/src/g_gamedata.cpp @@ -0,0 +1,688 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 2024 by Ronald "Eidolon" Kinard +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- + +#include "g_gamedata.h" + +#include +#include +#include +#include + +#include + +#include "io/streams.hpp" +#include "d_main.h" +#include "m_argv.h" +#include "m_cond.h" +#include "g_game.h" +#include "r_skins.h" +#include "z_zone.h" + +namespace fs = std::filesystem; +using json = nlohmann::json; + +void srb2::save_ng_gamedata() +{ + if (gamedata == NULL || !gamedata->loaded) + return; // If never loaded (-nodata), don't save + + gamedata->deferredsave = false; + + if (usedCheats) + { +#ifdef DEVELOP + CONS_Alert(CONS_WARNING, M_GetText("Cheats used - Gamedata will not be saved.\n")); +#endif + return; + } + + GamedataJson ng{}; + + ng.playtime.total = gamedata->totalplaytime; + ng.rings.total = gamedata->totalrings; + ng.playtime.tumble = gamedata->totaltumbletime; + ng.rounds.race = gamedata->roundsplayed[GDGT_RACE]; + ng.rounds.battle = gamedata->roundsplayed[GDGT_BATTLE]; + ng.rounds.prisons = gamedata->roundsplayed[GDGT_PRISONS]; + ng.rounds.special = gamedata->roundsplayed[GDGT_SPECIAL]; + ng.rounds.custom = gamedata->roundsplayed[GDGT_CUSTOM]; + ng.challengekeys.pendingkeyrounds = gamedata->pendingkeyrounds; + ng.challengekeys.pendingkeyroundoffset = gamedata->pendingkeyroundoffset; + ng.challengekeys.keyspending = gamedata->keyspending; + ng.challengekeys.chaokeys = gamedata->chaokeys; + ng.goner.everloadedaddon = gamedata->everloadedaddon; + ng.goner.everfinishcredits = gamedata->everfinishedcredits; + ng.goner.eversavedreplay = gamedata->eversavedreplay; + ng.goner.everseenspecial = gamedata->everseenspecial; + ng.goner.chaokeytutorial = gamedata->chaokeytutorial; + ng.goner.majorkeyskipattempted = gamedata->majorkeyskipattempted; + ng.goner.finishedtutorialchallenge = gamedata->finishedtutorialchallenge; + ng.goner.enteredtutorialchallenge = gamedata->enteredtutorialchallenge; + ng.goner.level = gamedata->gonerlevel; + ng.prisons.thisprisoneggpickup = gamedata->thisprisoneggpickup; + ng.prisons.prisoneggstothispickup = gamedata->prisoneggstothispickup; + ng.tafolderhash = quickncasehash(timeattackfolder, 64); + ng.emblems.resize(MAXEMBLEMS, false); + for (int i = 0; i < MAXEMBLEMS; i++) + { + ng.emblems[i] = gamedata->collected[i]; + } + ng.unlockables.resize(MAXUNLOCKABLES, false); + for (int i = 0; i < MAXUNLOCKABLES; i++) + { + ng.unlockables[i] = gamedata->unlocked[i]; + } + ng.unlockpending.resize(MAXUNLOCKABLES, false); + for (int i = 0; i < MAXUNLOCKABLES; i++) + { + ng.unlockpending[i] = gamedata->unlockpending[i]; + } + ng.conditionsets.resize(MAXCONDITIONSETS, false); + for (int i = 0; i < MAXCONDITIONSETS; i++) + { + ng.conditionsets[i] = gamedata->achieved[i]; + } + if (gamedata->challengegrid) + { + ng.challengegrid.width = gamedata->challengegridwidth; + ng.challengegrid.grid.resize(gamedata->challengegridwidth * CHALLENGEGRIDHEIGHT, 0); + for (int i = 0; i < gamedata->challengegridwidth * CHALLENGEGRIDHEIGHT; i++) + { + ng.challengegrid.grid[i] = gamedata->challengegrid[i]; + } + } + ng.timesBeaten = gamedata->timesBeaten; + for (int i = 0; i < numskins; i++) + { + srb2::GamedataSkinJson skin; + std::string name = std::string(skins[i].name); + skin.records.wins = skins[i].records.wins; + ng.skins[name] = skin; + } + for (auto unloadedskin = unloadedskins; unloadedskin; unloadedskin = unloadedskin->next) + { + srb2::GamedataSkinJson skin; + std::string name = std::string(unloadedskin->name); + skin.records.wins = unloadedskin->records.wins; + ng.skins[name] = skin; + } + for (int i = 0; i < nummapheaders; i++) + { + srb2::GamedataMapJson map; + std::string lumpname = std::string(mapheaderinfo[i]->lumpname); + map.visited.visited = mapheaderinfo[i]->records.mapvisited & MV_VISITED; + map.visited.beaten = mapheaderinfo[i]->records.mapvisited & MV_BEATEN; + map.visited.encore = mapheaderinfo[i]->records.mapvisited & MV_ENCORE; + map.visited.spbattack = mapheaderinfo[i]->records.mapvisited & MV_SPBATTACK; + map.visited.mysticmelody = mapheaderinfo[i]->records.mapvisited & MV_MYSTICMELODY; + map.stats.besttime = mapheaderinfo[i]->records.time; + map.stats.bestlap = mapheaderinfo[i]->records.lap; + ng.maps[lumpname] = map; + } + for (auto unloadedmap = unloadedmapheaders; unloadedmap; unloadedmap = unloadedmap->next) + { + srb2::GamedataMapJson map; + std::string lumpname = std::string(unloadedmap->lumpname); + map.visited.visited = unloadedmap->records.mapvisited & MV_VISITED; + map.visited.beaten = unloadedmap->records.mapvisited & MV_BEATEN; + map.visited.encore = unloadedmap->records.mapvisited & MV_ENCORE; + map.visited.spbattack = unloadedmap->records.mapvisited & MV_SPBATTACK; + map.visited.mysticmelody = unloadedmap->records.mapvisited & MV_MYSTICMELODY; + map.stats.besttime = unloadedmap->records.time; + map.stats.bestlap = unloadedmap->records.lap; + ng.maps[lumpname] = map; + } + for (int i = 0; i < gamedata->numspraycans; i++) + { + srb2::GamedataSprayCanJson spraycan; + + candata_t* can = &gamedata->spraycans[i]; + + spraycan.color = can->col; + if (can->map >= nummapheaders) + { + continue; + } + mapheader_t* mapheader = mapheaderinfo[can->map]; + if (!mapheader) + { + continue; + } + spraycan.map = std::string(mapheader->lumpname); + ng.spraycans.push_back(spraycan); + } + for (auto cup = kartcupheaders; cup; cup = cup->next) + { + if (cup->windata[0].best_placement == 0) + { + continue; + } + srb2::GamedataCupJson cupdata; + cupdata.name = std::string(cup->name); + for (int i = 0; i < 4; i++) + { + cupdata.records[i].bestgrade = cup->windata[i].best_grade; + cupdata.records[i].bestplacement = cup->windata[i].best_placement; + cupdata.records[i].bestskin = std::string(skins[cup->windata[i].best_skin.id].name); + cupdata.records[i].emerald = cup->windata[i].got_emerald; + } + ng.cups[cupdata.name] = cupdata; + } + for (auto unloadedcup = unloadedcupheaders; unloadedcup; unloadedcup = unloadedcup->next) + { + if (unloadedcup->windata[0].best_placement == 0) + { + continue; + } + srb2::GamedataCupJson cupdata; + cupdata.name = std::string(unloadedcup->name); + for (int i = 0; i < 4; i++) + { + cupdata.records[i].bestgrade = unloadedcup->windata[i].best_grade; + cupdata.records[i].bestplacement = unloadedcup->windata[i].best_placement; + cupdata.records[i].bestskin = std::string(skins[unloadedcup->windata[i].best_skin.id].name); + cupdata.records[i].emerald = unloadedcup->windata[i].got_emerald; + } + ng.cups[cupdata.name] = cupdata; + } + + std::string gamedataname_s{gamedatafilename}; + fs::path savepath{fmt::format("{}/{}", srb2home, gamedataname_s)}; + fs::path tmpsavepath{fmt::format("{}/{}.tmp", srb2home, gamedataname_s)}; + + json ngdata_json = ng; + + try + { + std::string tmpsavepathstring = tmpsavepath.string(); + srb2::io::FileStream file {tmpsavepathstring, srb2::io::FileStreamMode::kWrite}; + srb2::io::BufferedOutputStream bos {std::move(file)}; + + // The header is necessary to validate during loading. + srb2::io::write(static_cast(0xBA5ED321), bos); // major + srb2::io::write(static_cast(0), bos); // minor/flags + srb2::io::write(static_cast(gamedata->evercrashed), bos); // dirty (crash recovery) + + std::vector ubjson = json::to_ubjson(ng); + srb2::io::write_exact(bos, tcb::as_bytes(tcb::make_span(ubjson))); + bos.flush(); + file = bos.stream(); + file.close(); + } + catch (const srb2::io::FileStreamException& ex) + { + CONS_Alert(CONS_ERROR, "NG Gamedata save failed: %s\n", ex.what()); + } + catch (...) + { + CONS_Alert(CONS_ERROR, "NG Gamedata save failed\n"); + } + + try + { + // Now that the save is written successfully, move it over the old save + fs::rename(tmpsavepath, savepath); + } + catch (const fs::filesystem_error& ex) + { + CONS_Alert(CONS_ERROR, "NG Gamedata save succeeded but did not replace old save successfully: %s\n", ex.what()); + } +} + +// G_SaveGameData +// Saves the main data file, which stores information such as emblems found, etc. +void G_SaveGameData(void) +{ + try + { + srb2::save_ng_gamedata(); + } + catch (...) + { + CONS_Alert(CONS_ERROR, "Gamedata save failed\n"); + return; + } + + // Also save profiles here. + PR_SaveProfiles(); + + #ifdef DEVELOP + CONS_Alert(CONS_NOTICE, M_GetText("Gamedata saved.\n")); + #endif +} + +static const char *G_GameDataFolder(void) +{ + if (strcmp(srb2home,".")) + return srb2home; + else + return "the Ring Racers folder"; +} + +void srb2::load_ng_gamedata() +{ + // Stop saving, until we successfully load it again. + gamedata->loaded = false; + + // Clear things so previously read gamedata doesn't transfer + // to new gamedata + // see also M_EraseDataResponse + G_ClearRecords(); // records + M_ClearStats(); // statistics + M_ClearSecrets(); // emblems, unlocks, maps visited, etc + + if (M_CheckParm("-nodata")) + { + // Don't load at all. + // The following used to be in M_ClearSecrets, but that was silly. + M_UpdateUnlockablesAndExtraEmblems(false, true); + M_FinaliseGameData(); + gamedata->loaded = true; + return; + } + + if (M_CheckParm("-resetdata")) + { + // Don't load, but do save. (essentially, reset) + M_FinaliseGameData(); + gamedata->loaded = true; + return; + } + + std::string datapath {fmt::format("{}/{}", srb2home, gamedatafilename)}; + + srb2::io::BufferedInputStream bis; + try + { + srb2::io::FileStream file {datapath, srb2::io::FileStreamMode::kRead }; + bis = srb2::io::BufferedInputStream(std::move(file)); + } + catch (const srb2::io::FileStreamException& ex) + { + M_FinaliseGameData(); + gamedata->loaded = true; + return; + } + + uint32_t majorversion; + uint8_t minorversion; + uint8_t dirty; + try + { + majorversion = srb2::io::read_uint32(bis); + minorversion = srb2::io::read_uint8(bis); + dirty = srb2::io::read_uint8(bis); + } + catch (...) + { + CONS_Alert(CONS_ERROR, "Failed to read ng gamedata header\n"); + return; + } + + if (majorversion != 0xBA5ED321) + { + const char* gdfolder = G_GameDataFolder(); + I_Error("Game data is not for Ring Racers v2.0.\nDelete %s (maybe in %s) and try again.", gamedatafilename, gdfolder); + return; + } + + std::vector remainder = srb2::io::read_to_vec(bis); + + GamedataJson js; + try + { + // safety: std::byte repr is always uint8_t 1-byte aligned + tcb::span remainder_as_u8 = tcb::span((uint8_t*)remainder.data(), remainder.size()); + json parsed = json::from_ubjson(remainder_as_u8); + js = parsed.template get(); + } + catch (...) + { + const char* gdfolder = G_GameDataFolder(); + I_Error("Game data is corrupt.\nDelete %s (maybe in %s) and try again.", gamedatafilename, gdfolder); + return; + } + + // Quick & dirty hash for what mod this save file is for. + if (js.tafolderhash != quickncasehash(timeattackfolder, 64)) + { + const char* gdfolder = G_GameDataFolder(); + I_Error("Game data is corrupt.\nDelete %s (maybe in %s) and try again.", gamedatafilename, gdfolder); + return; + } + + // Now we extract the json struct's data and put it into the C-side gamedata. + + gamedata->evercrashed = dirty; + + gamedata->totalplaytime = js.playtime.total; + gamedata->totalrings = js.rings.total; + gamedata->totaltumbletime = js.playtime.tumble; + gamedata->roundsplayed[GDGT_RACE] = js.rounds.race; + gamedata->roundsplayed[GDGT_BATTLE] = js.rounds.battle; + gamedata->roundsplayed[GDGT_PRISONS] = js.rounds.prisons; + gamedata->roundsplayed[GDGT_SPECIAL] = js.rounds.special; + gamedata->roundsplayed[GDGT_CUSTOM] = js.rounds.custom; + gamedata->pendingkeyrounds = js.challengekeys.pendingkeyrounds; + gamedata->pendingkeyroundoffset = js.challengekeys.pendingkeyroundoffset; + gamedata->keyspending = js.challengekeys.keyspending; + gamedata->chaokeys = js.challengekeys.chaokeys; + gamedata->everloadedaddon = js.goner.everloadedaddon; + gamedata->everfinishedcredits = js.goner.everfinishcredits; + gamedata->eversavedreplay = js.goner.eversavedreplay; + gamedata->everseenspecial = js.goner.everseenspecial; + gamedata->chaokeytutorial = js.goner.chaokeytutorial; + gamedata->majorkeyskipattempted = js.goner.majorkeyskipattempted; + gamedata->finishedtutorialchallenge = js.goner.finishedtutorialchallenge; + gamedata->enteredtutorialchallenge = js.goner.enteredtutorialchallenge; + gamedata->gonerlevel = js.goner.level; + gamedata->thisprisoneggpickup = js.prisons.thisprisoneggpickup; + gamedata->prisoneggstothispickup = js.prisons.prisoneggstothispickup; + + size_t emblems_size = js.emblems.size(); + for (size_t i = 0; i < std::min((size_t)MAXEMBLEMS, emblems_size); i++) + { + gamedata->collected[i] = js.emblems[i]; + } + + size_t unlocks_size = js.unlockables.size(); + for (size_t i = 0; i < std::min((size_t)MAXUNLOCKABLES, unlocks_size); i++) + { + gamedata->unlocked[i] = js.unlockables[i]; + } + + size_t pending_unlocks_size = js.unlockpending.size(); + for (size_t i = 0; i < std::min((size_t)MAXUNLOCKABLES, pending_unlocks_size); i++) + { + gamedata->unlockpending[i] = js.unlockpending[i]; + } + + size_t conditions_size = js.conditionsets.size(); + for (size_t i = 0; i < std::min((size_t)MAXCONDITIONSETS, conditions_size); i++) + { + gamedata->achieved[i] = js.conditionsets[i]; + } + + if (M_CheckParm("-resetchallengegrid")) + { + gamedata->challengegridwidth = 0; + if (gamedata->challengegrid) + { + Z_Free(gamedata->challengegrid); + gamedata->challengegrid = nullptr; + } + } + else + { + gamedata->challengegridwidth = std::min(js.challengegrid.width, (uint32_t)0); + if (gamedata->challengegrid) + { + Z_Free(gamedata->challengegrid); + gamedata->challengegrid = nullptr; + } + if (gamedata->challengegridwidth) + { + gamedata->challengegrid = static_cast(Z_Malloc( + (gamedata->challengegridwidth * CHALLENGEGRIDHEIGHT * sizeof(UINT16)), + PU_STATIC, NULL)); + for (size_t i = 0; i < std::min((size_t)(gamedata->challengegridwidth * CHALLENGEGRIDHEIGHT), js.challengegrid.grid.size()); i++) + { + int16_t gridvalue = js.challengegrid.grid[i]; + if (gridvalue < 0) + { + gamedata->challengegrid[i] = MAXUNLOCKABLES; + } + else + { + gamedata->challengegrid[i] = static_cast(gridvalue); + } + } + + M_SanitiseChallengeGrid(); + } + else + { + gamedata->challengegrid = NULL; + } + } + + gamedata->timesBeaten = js.timesBeaten; + + // Main records + + for (auto& skinpair : js.skins) + { + INT32 skin = R_SkinAvailable(skinpair.first.c_str()); + skinrecord_t dummyrecord {}; + dummyrecord.wins = skinpair.second.records.wins; + + if (skin != -1) + { + skins[skin].records = dummyrecord; + } + else if (dummyrecord.wins) + { + // Invalid, but we don't want to lose all the juicy statistics. + // Instead, update a FILO linked list of "unloaded skins". + + unloaded_skin_t *unloadedskin = + static_cast(Z_Malloc( + sizeof(unloaded_skin_t), + PU_STATIC, NULL + )); + + // Establish properties, for later retrieval on file add. + strlcpy(unloadedskin->name, skinpair.first.c_str(), sizeof(unloadedskin->name)); + unloadedskin->namehash = quickncasehash(unloadedskin->name, SKINNAMESIZE); + + // Insert at the head, just because it's convenient. + unloadedskin->next = unloadedskins; + unloadedskins = unloadedskin; + + // Finally, copy into. + unloadedskin->records = dummyrecord; + } + } + + for (auto& mappair : js.maps) + { + UINT16 mapnum = G_MapNumber(mappair.first.c_str()); + recorddata_t dummyrecord {}; + dummyrecord.mapvisited |= mappair.second.visited.visited ? MV_VISITED : 0; + dummyrecord.mapvisited |= mappair.second.visited.beaten ? MV_BEATEN : 0; + dummyrecord.mapvisited |= mappair.second.visited.encore ? MV_ENCORE : 0; + dummyrecord.mapvisited |= mappair.second.visited.spbattack ? MV_SPBATTACK : 0; + dummyrecord.mapvisited |= mappair.second.visited.mysticmelody ? MV_SPBATTACK : 0; + dummyrecord.lap = mappair.second.stats.bestlap; + dummyrecord.time = mappair.second.stats.besttime; + + if (mapnum < nummapheaders && mapheaderinfo[mapnum]) + { + // Valid mapheader, time to populate with record data. + + mapheaderinfo[mapnum]->records = dummyrecord; + } + else if (dummyrecord.mapvisited & MV_BEATEN || dummyrecord.time != 0 || dummyrecord.lap != 0) + { + // Invalid, but we don't want to lose all the juicy statistics. + // Instead, update a FILO linked list of "unloaded mapheaders". + + unloaded_mapheader_t *unloadedmap = + static_cast(Z_Malloc( + sizeof(unloaded_mapheader_t), + PU_STATIC, NULL + )); + + // Establish properties, for later retrieval on file add. + unloadedmap->lumpname = Z_StrDup(mappair.first.c_str()); + unloadedmap->lumpnamehash = quickncasehash(unloadedmap->lumpname, MAXMAPLUMPNAME); + + // Insert at the head, just because it's convenient. + unloadedmap->next = unloadedmapheaders; + unloadedmapheaders = unloadedmap; + + // Finally, copy into. + unloadedmap->records = dummyrecord; + } + } + + gamedata->gotspraycans = 0; + gamedata->numspraycans = js.spraycans.size(); + if (gamedata->spraycans) + { + Z_Free(gamedata->spraycans); + } + if (gamedata->numspraycans) + { + gamedata->spraycans = static_cast(Z_Malloc( + (gamedata->numspraycans * sizeof(candata_t)), + PU_STATIC, NULL)); + + for (size_t i = 0; i < js.spraycans.size(); i++) + { + auto& can = js.spraycans[i]; + gamedata->spraycans[i].col = can.color; + gamedata->spraycans[i].map = NEXTMAP_INVALID; + if (can.map.empty()) + { + continue; + } + UINT16 mapnum = G_MapNumber(can.map.c_str()); + if (mapnum < 0) + { + continue; + } + gamedata->spraycans[i].map = mapnum; + + if (gamedata->gotspraycans != i) + { + //CONS_Printf("LOAD - Swapping gotten can %u, color %s with prior ungotten can %u\n", i, skincolors[col].name, gamedata->gotspraycans); + + // All grabbed cans should be at the head of the list. + // Let's swap with the can the disjoint occoured at. + // This will prevent a gap from occouring on reload. + candata_t copycan = gamedata->spraycans[gamedata->gotspraycans]; + gamedata->spraycans[gamedata->gotspraycans] = gamedata->spraycans[i]; + gamedata->spraycans[i] = copycan; + + mapheaderinfo[copycan.map]->cache_spraycan = i; + } + mapheaderinfo[mapnum]->cache_spraycan = gamedata->gotspraycans; + gamedata->gotspraycans++; + } + } + else + { + gamedata->spraycans = nullptr; + } + + for (auto& cuppair : js.cups) + { + cupwindata_t dummywindata[4] {{}}; + cupheader_t* cup = nullptr; + + // Find the loaded cup + for (cup = kartcupheaders; cup; cup = cup->next) + { + std::string cupname = std::string(cup->name); + if (cupname == cuppair.first) + { + continue; + } + } + + // Digest its data... + for (size_t j = 0; j < (size_t)KARTGP_MAX; j++) + { + dummywindata[j].best_placement = cuppair.second.records[j].bestplacement; + dummywindata[j].best_grade = static_cast(cuppair.second.records[j].bestgrade); + dummywindata[j].got_emerald = cuppair.second.records[j].emerald; + + dummywindata[j].best_skin.id = MAXSKINS; + dummywindata[j].best_skin.unloaded = nullptr; + + bool skinfound = false; + for (int skin = 0; skin < numskins; skin++) + { + std::string skinname = std::string(skins[skin].name); + if (skinname == cuppair.second.records[j].bestskin) + { + skinreference_t ref {}; + ref.id = skin; + ref.unloaded = nullptr; + dummywindata[j].best_skin = ref; + skinfound = true; + break; + } + } + if (skinfound) + { + continue; + } + for (auto unloadedskin = unloadedskins; unloadedskin; unloadedskin = unloadedskin->next) + { + std::string skinname = std::string(unloadedskin->name); + if (skinname == cuppair.second.records[j].bestskin) + { + skinreference_t ref {}; + ref.id = MAXSKINS; + ref.unloaded = unloadedskin; + dummywindata[j].best_skin = ref; + skinfound = true; + break; + } + } + } + + if (cup) + { + // We found a cup, so assign the windata. + + memcpy(cup->windata, dummywindata, sizeof(cup->windata)); + } + else if (dummywindata[0].best_placement != 0) + { + // Invalid, but we don't want to lose all the juicy statistics. + // Instead, update a FILO linked list of "unloaded cupheaders". + + unloaded_cupheader_t *unloadedcup = + static_cast(Z_Malloc( + sizeof(unloaded_cupheader_t), + PU_STATIC, NULL + )); + + // Establish properties, for later retrieval on file add. + strlcpy(unloadedcup->name, cuppair.first.c_str(), sizeof(unloadedcup->name)); + unloadedcup->namehash = quickncasehash(unloadedcup->name, MAXCUPNAME); + + // Insert at the head, just because it's convenient. + unloadedcup->next = unloadedcupheaders; + unloadedcupheaders = unloadedcup; + + // Finally, copy into. + memcpy(unloadedcup->windata, dummywindata, sizeof(cup->windata)); + } + } + + M_FinaliseGameData(); +} + +// G_LoadGameData +// Loads the main data file, which stores information such as emblems found, etc. +void G_LoadGameData(void) +{ + try + { + srb2::load_ng_gamedata(); + } + catch (...) + { + CONS_Alert(CONS_ERROR, "NG Gamedata loading failed\n"); + } +} diff --git a/src/g_gamedata.h b/src/g_gamedata.h new file mode 100644 index 000000000..4b9ebeb9d --- /dev/null +++ b/src/g_gamedata.h @@ -0,0 +1,229 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 2024 by Ronald "Eidolon" Kinard +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- + +#ifndef SRB2_G_GAMEDATA_H +#define SRB2_G_GAMEDATA_H + +#ifdef __cplusplus + +#include +#include +#include +#include +#include + +#include + +namespace srb2 +{ + +struct GamedataPlaytimeJson final +{ + uint32_t total; + uint32_t tumble; + + NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataPlaytimeJson, total, tumble) +}; + +struct GamedataRingsJson final +{ + uint32_t total; + + NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataRingsJson, total) +}; + +struct GamedataRoundsJson final +{ + uint32_t race; + uint32_t battle; + uint32_t prisons; + uint32_t special; + uint32_t custom; + + NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataRoundsJson, race, battle, prisons, special, custom) +}; + +struct GamedataChallengeKeysJson final +{ + uint32_t pendingkeyrounds; + uint8_t pendingkeyroundoffset; + uint16_t keyspending; + uint16_t chaokeys; + + NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataChallengeKeysJson, pendingkeyrounds, pendingkeyroundoffset, keyspending, chaokeys) +}; + +struct GamedataGonerJson final +{ + uint32_t level; + bool everloadedaddon; + bool everfinishcredits; + bool eversavedreplay; + bool everseenspecial; + bool chaokeytutorial; + bool majorkeyskipattempted; + bool finishedtutorialchallenge; + bool enteredtutorialchallenge; + + NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT( + GamedataGonerJson, + level, + everloadedaddon, + everfinishcredits, + eversavedreplay, + everseenspecial, + chaokeytutorial, + majorkeyskipattempted, + finishedtutorialchallenge, + enteredtutorialchallenge + ) +}; + +struct GamedataPrisonEggPickupsJson final +{ + uint16_t thisprisoneggpickup; + uint16_t prisoneggstothispickup; + + NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataPrisonEggPickupsJson, thisprisoneggpickup, prisoneggstothispickup) +}; + +struct GamedataChallengeGridJson final +{ + uint32_t width; + std::vector grid; + + NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataChallengeGridJson, width, grid) +}; + +struct GamedataSkinRecordsJson final +{ + uint32_t wins; + + NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataSkinRecordsJson, wins) +}; + +struct GamedataSkinJson final +{ + GamedataSkinRecordsJson records; + + NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataSkinJson, records) +}; + +struct GamedataMapVisitedJson final +{ + bool visited; + bool beaten; + bool encore; + bool spbattack; + bool mysticmelody; + + NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataMapVisitedJson, visited, beaten, encore, spbattack, mysticmelody) +}; + +struct GamedataMapStatsJson final +{ + uint32_t besttime; + uint32_t bestlap; + + NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataMapStatsJson, besttime, bestlap) +}; + +struct GamedataMapJson final +{ + GamedataMapVisitedJson visited; + GamedataMapStatsJson stats; + + NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataMapJson, visited, stats) +}; + +struct GamedataSprayCanJson final +{ + std::string map; + uint16_t color; + + NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataSprayCanJson, map, color) +}; + +struct GamedataCupRecordsJson final +{ + uint8_t bestplacement; + uint8_t bestgrade; + uint8_t emerald; + std::string bestskin; + + NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataCupRecordsJson, bestplacement, bestgrade, emerald, bestskin) +}; + +struct GamedataCupJson final +{ + std::string name; + std::array records; + + NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataCupJson, name, records) +}; + +struct GamedataJson final +{ + GamedataPlaytimeJson playtime; + GamedataRingsJson rings; + GamedataRoundsJson rounds; + GamedataChallengeKeysJson challengekeys; + GamedataGonerJson goner; + GamedataPrisonEggPickupsJson prisons; + uint32_t tafolderhash; + std::vector emblems; + std::vector unlockables; + std::vector unlockpending; + std::vector conditionsets; + GamedataChallengeGridJson challengegrid; + uint32_t timesBeaten; + std::unordered_map skins; + std::unordered_map maps; + std::vector spraycans; + std::unordered_map cups; + + NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT( + GamedataJson, + playtime, + rings, + rounds, + challengekeys, + goner, + prisons, + tafolderhash, + emblems, + unlockables, + unlockpending, + conditionsets, + challengegrid, + timesBeaten, + skins, + maps, + spraycans, + cups + ) +}; + +void save_ng_gamedata(void); +void load_ng_gamedata(void); + +} + +extern "C" +{ +#endif // __cplusplus + +void G_SaveGameData(void); +void G_LoadGameData(void); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif // SRB2_G_GAMEDATA_H diff --git a/src/io/streams.cpp b/src/io/streams.cpp index 6ba250a24..85ef2aab2 100644 --- a/src/io/streams.cpp +++ b/src/io/streams.cpp @@ -9,5 +9,161 @@ #include "streams.hpp" +#include +#include +#include + template class srb2::io::ZlibInputStream; template class srb2::io::ZlibInputStream; +template class srb2::io::BufferedOutputStream; +template class srb2::io::BufferedInputStream; + +using namespace srb2::io; + +static FileStreamException make_exception_from_errno(int err) +{ + char* errnostr = strerror(err); + return FileStreamException(std::string(errnostr)); +} + +FileStreamException::FileStreamException(const char* msg) : msg_(msg) {} +FileStreamException::FileStreamException(const std::string& msg) : msg_(msg) {} + +FileStreamException::FileStreamException(const FileStreamException&) = default; +FileStreamException::FileStreamException(FileStreamException&& r) noexcept = default; + +FileStreamException::~FileStreamException() = default; + +FileStreamException& FileStreamException::operator=(const FileStreamException&) = default; +FileStreamException& FileStreamException::operator=(FileStreamException&&) noexcept = default; + +const char* FileStreamException::what() const noexcept +{ + return msg_.c_str(); +} + +FileStream::FileStream() noexcept = default; +FileStream::FileStream(FileStream&& r) noexcept +{ + *this = std::move(r); +}; + +FileStream::~FileStream() +{ + if (file_) + { + // We don't care about the result. Exceptions can't be thrown in destructors. + std::fclose((std::FILE*)(this->file_)); + } + file_ = nullptr; +} + +FileStream::FileStream(const std::string& path, FileStreamMode mode) : file_(nullptr), mode_(mode) +{ + const char* fopenmode = "r"; + switch (mode_) + { + case FileStreamMode::kRead: + fopenmode = "rb"; + break; + case FileStreamMode::kWrite: + fopenmode = "wb"; + break; + case FileStreamMode::kAppend: + fopenmode = "ab"; + break; + default: + throw std::invalid_argument("file stream mode unsupported"); + } + + std::FILE* file = std::fopen(path.c_str(), fopenmode); + if (file == nullptr) + { + int err = errno; + throw make_exception_from_errno(err); + } + + // We want raw, unbuffered IO for the stream. Buffering can be layered on top. + if (std::setvbuf(file, nullptr, _IONBF, 0) != 0) + { + int err = errno; + throw make_exception_from_errno(err); + } + + this->file_ = (void*) file; +} + +FileStream& FileStream::operator=(FileStream&& r) noexcept +{ + file_ = r.file_; + r.file_ = nullptr; + mode_ = r.mode_; + return *this; +}; + +StreamSize FileStream::read(tcb::span buffer) +{ + if (this->file_ == nullptr) + { + throw std::domain_error("FileStream is empty"); + } + + if (this->mode_ != FileStreamMode::kRead) + { + throw std::domain_error("FileStream is not in read mode"); + } + + void* cbuf = (void*)(buffer.data()); + std::size_t cbufsize = buffer.size_bytes(); + std::size_t bytesread = fread(cbuf, 1, cbufsize, (std::FILE*)(this->file_)); + if (std::ferror((std::FILE*)(this->file_)) != 0) + { + int err = errno; + throw make_exception_from_errno(err); + } + return bytesread; +} + +StreamSize FileStream::write(tcb::span buffer) +{ + if (this->file_ == nullptr) + { + throw std::domain_error("FileStream is empty"); + } + + if (this->mode_ == FileStreamMode::kRead) + { + throw std::domain_error("FileStream is not in writable mode"); + } + + void* cbuf = (void*)(buffer.data()); + std::size_t cbufsize = buffer.size_bytes(); + std::size_t byteswritten = std::fwrite(cbuf, 1, cbufsize, (std::FILE*)(this->file_)); + if (std::ferror((std::FILE*)(this->file_)) != 0) + { + int err = errno; + throw make_exception_from_errno(err); + } + return byteswritten; +} + +void FileStream::close() +{ + if (!file_) + { + return; + } + + if (std::fclose((std::FILE*)(this->file_)) != 0) + { + int err = errno; + throw make_exception_from_errno(err); + } + + if (std::ferror((std::FILE*)(this->file_)) != 0) + { + int err = errno; + throw make_exception_from_errno(err); + } + file_ = nullptr; +} diff --git a/src/io/streams.hpp b/src/io/streams.hpp index 39f0b6299..c4456d2d4 100644 --- a/src/io/streams.hpp +++ b/src/io/streams.hpp @@ -47,6 +47,9 @@ struct IsSeekableStream : public std::is_same().seek(std::declval(), std::declval())), StreamSize> {}; +template +struct IsFlushableStream : public std::is_same().flush()), void> {}; + template struct IsStream : public std::disjunction, IsOutputStream> {}; @@ -60,6 +63,8 @@ inline constexpr const bool IsOutputStreamV = IsOutputStream::value; template inline constexpr const bool IsSeekableStreamV = IsSeekableStream::value; template +inline constexpr const bool IsFlushableStreamV = IsFlushableStream::value; +template inline constexpr const bool IsStreamV = IsStream::value; template inline constexpr const bool IsInputOutputStreamV = IsInputOutputStream::value; @@ -570,6 +575,54 @@ inline void read_exact(VecStream& stream, tcb::span buffer) std::copy(copy_begin, copy_end, buffer.begin()); } +enum class FileStreamMode +{ + kRead, + kWrite, + kAppend, +}; + +class FileStreamException final : public std::exception +{ + std::string msg_; + +public: + explicit FileStreamException(const char* msg); + explicit FileStreamException(const std::string& msg); + FileStreamException(const FileStreamException&); + FileStreamException(FileStreamException&&) noexcept; + ~FileStreamException(); + + FileStreamException& operator=(const FileStreamException&); + FileStreamException& operator=(FileStreamException&&) noexcept; + + virtual const char* what() const noexcept override; +}; + +class FileStream final +{ + void* file_ = nullptr; // Type is omitted to avoid include cstdio + FileStreamMode mode_; + +public: + FileStream() noexcept; + FileStream(const FileStream&) = delete; + FileStream(FileStream&&) noexcept; + FileStream(const std::string& path, FileStreamMode mode = FileStreamMode::kRead); + ~FileStream(); + + FileStream& operator=(const FileStream&) = delete; + FileStream& operator=(FileStream&&) noexcept; + + StreamSize read(tcb::span buffer); + StreamSize write(tcb::span buffer); + + // not bothering with seeking for now -- apparently 64-bit file positions is not available in ansi c + // StreamSize seek(SeekFrom seek_from, StreamOffset offset); + + void close(); +}; + class ZlibException : public std::exception { int err_ {0}; std::string msg_; @@ -759,6 +812,124 @@ private: } }; +extern template class ZlibInputStream; +extern template class ZlibInputStream; + +template && std::is_move_constructible_v && + std::is_move_assignable_v>* = nullptr> +class BufferedOutputStream final +{ + O inner_; + std::vector buf_; + tcb::span::size_type cap_; + +public: + explicit BufferedOutputStream(O&& o) : inner_(std::forward(o)), buf_(), cap_(8192) {} + BufferedOutputStream(O&& o, tcb::span::size_type capacity) : inner_(std::forward(o)), buf_(), cap_(capacity) {} + BufferedOutputStream(const BufferedOutputStream&) = delete; + BufferedOutputStream(BufferedOutputStream&&) = default; + ~BufferedOutputStream() = default; + + BufferedOutputStream& operator=(const BufferedOutputStream&) = delete; + BufferedOutputStream& operator=(BufferedOutputStream&&) = default; + + StreamSize write(tcb::span buffer) + { + StreamSize totalwritten = 0; + while (buffer.size() > 0) + { + std::size_t tocopy = std::min(std::min(cap_, cap_ - buf_.size()), buffer.size()); + tcb::span copy_slice = buffer.subspan(0, tocopy); + buf_.reserve(cap_); + buf_.insert(buf_.end(), copy_slice.begin(), copy_slice.end()); + flush(); + totalwritten += copy_slice.size(); + + buffer = buffer.subspan(tocopy); + } + + return totalwritten; + } + + void flush() + { + tcb::span writebuf = tcb::make_span(buf_); + write_exact(inner_, writebuf); + buf_.resize(0); + } + + O&& stream() noexcept + { + return std::move(inner_); + } +}; + +extern template class BufferedOutputStream; + +template && std::is_move_constructible_v && + std::is_move_assignable_v>* = nullptr> +class BufferedInputStream final +{ + I inner_; + std::vector buf_; + tcb::span::size_type cap_; + +public: + template >* = nullptr> + BufferedInputStream() : inner_(), buf_(), cap_(8192) {} + + explicit BufferedInputStream(I&& i) : inner_(std::forward(i)), buf_(), cap_(8192) {} + BufferedInputStream(I&& i, tcb::span::size_type capacity) : inner_(std::forward(i)), buf_(), cap_(capacity) {} + BufferedInputStream(const BufferedInputStream&) = delete; + BufferedInputStream(BufferedInputStream&&) = default; + ~BufferedInputStream() = default; + + BufferedInputStream& operator=(const BufferedInputStream&) = delete; + BufferedInputStream& operator=(BufferedInputStream&&) = default; + + StreamSize read(tcb::span buffer) + { + StreamSize totalread = 0; + buf_.reserve(cap_); + while (buffer.size() > 0) + { + std::size_t toread = cap_ - buf_.size(); + std::size_t prereadsize = buf_.size(); + buf_.resize(prereadsize + toread); + tcb::span readspan{buf_.data() + prereadsize, buf_.data() + prereadsize + toread}; + StreamSize bytesread = inner_.read(readspan); + buf_.resize(prereadsize + bytesread); + + StreamSize tocopyfrombuf = std::min(buffer.size(), buf_.size()); + std::copy(buf_.begin(), std::next(buf_.begin(), tocopyfrombuf), buffer.begin()); + buffer = buffer.subspan(tocopyfrombuf); + totalread += tocopyfrombuf; + + // Move the remaining buffer backwards + std::size_t bufremaining = buf_.size() - tocopyfrombuf; + std::move(std::next(buf_.begin(), tocopyfrombuf), buf_.end(), buf_.begin()); + buf_.resize(bufremaining); + + // If we read 0 bytes from the stream, assume the inner stream won't return more for a while. + // The caller can read in a loop if it must (i.e. read_exact) + if (bytesread == 0) + { + break; + } + } + return totalread; + } + + I&& stream() noexcept + { + return std::move(inner_); + } +}; + +extern template class BufferedInputStream; + // Utility functions template From af7800c17b83e56033751de6a0505a076b474884 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Mon, 19 Feb 2024 19:30:58 -0600 Subject: [PATCH 20/33] C++ compat: rename tm -> g_tm This one's not even C++. It's in the ISO C standard library. :( --- src/f_finale.c | 2 +- src/k_collide.cpp | 6 +- src/lua_baselib.c | 46 +- src/lua_maplib.c | 8 +- src/lua_mobjlib.c | 30 +- src/objects/sneaker-panel.c | 8 +- src/p_enemy.c | 12 +- src/p_local.h | 2 +- src/p_map.c | 1320 +++++++++++++++++------------------ src/p_maputl.c | 50 +- src/p_mobj.c | 72 +- src/p_polyobj.c | 12 +- src/p_sight.c | 14 +- 13 files changed, 791 insertions(+), 791 deletions(-) diff --git a/src/f_finale.c b/src/f_finale.c index ab978cf56..4ddd2db2b 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -2082,7 +2082,7 @@ void F_EndTextPrompt(boolean forceexec, boolean noexec) // \todo net safety, maybe loop all player thinkers? if ((promptwasactive || forceexec) && !noexec && promptpostexectag) { - if (tm.thing) // edge case where starting an invalid prompt immediately on level load will make P_MapStart fail + if (g_tm.thing) // edge case where starting an invalid prompt immediately on level load will make P_MapStart fail P_LinedefExecute(promptpostexectag, promptmo, NULL); else { diff --git a/src/k_collide.cpp b/src/k_collide.cpp index c7d41237f..0e6963374 100644 --- a/src/k_collide.cpp +++ b/src/k_collide.cpp @@ -793,12 +793,12 @@ boolean K_BubbleShieldCollide(mobj_t *t1, mobj_t *t2) { // Counter desyncs /*mobj_t *oldthing = thing; - mobj_t *oldtm.thing = tm.thing; + mobj_t *oldg_tm.thing = g_tm.thing; - P_Thrust(tm.thing, R_PointToAngle2(thing->x, thing->y, tm.thing->x, tm.thing->y), 4*thing->scale); + P_Thrust(g_tm.thing, R_PointToAngle2(thing->x, thing->y, g_tm.thing->x, g_tm.thing->y), 4*thing->scale); thing = oldthing; - P_SetTarget(&tm.thing, oldtm.thing);*/ + P_SetTarget(&g_tm.thing, oldg_tm.thing);*/ if (K_KartBouncing(t2, t1->target) == true) { diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 93f79311a..71ad3fe75 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -986,7 +986,7 @@ static int lib_pRemoveFloorSpriteSlope(lua_State *L) static int lib_pRailThinker(lua_State *L) { mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); - tm_t ptm = tm; + tm_t ptm = g_tm; NOHUD INLEVEL if (!mobj) @@ -999,7 +999,7 @@ static int lib_pRailThinker(lua_State *L) static int lib_pXYMovement(lua_State *L) { mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); - tm_t ptm = tm; + tm_t ptm = g_tm; NOHUD INLEVEL if (!actor) @@ -1012,7 +1012,7 @@ static int lib_pXYMovement(lua_State *L) static int lib_pRingXYMovement(lua_State *L) { mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); - tm_t ptm = tm; + tm_t ptm = g_tm; NOHUD INLEVEL if (!actor) @@ -1025,7 +1025,7 @@ static int lib_pRingXYMovement(lua_State *L) static int lib_pSceneryXYMovement(lua_State *L) { mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); - tm_t ptm = tm; + tm_t ptm = g_tm; NOHUD INLEVEL if (!actor) @@ -1038,7 +1038,7 @@ static int lib_pSceneryXYMovement(lua_State *L) static int lib_pZMovement(lua_State *L) { mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); - tm_t ptm = tm; + tm_t ptm = g_tm; NOHUD INLEVEL if (!actor) @@ -1052,7 +1052,7 @@ static int lib_pZMovement(lua_State *L) static int lib_pRingZMovement(lua_State *L) { mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); - tm_t ptm = tm; + tm_t ptm = g_tm; NOHUD INLEVEL if (!actor) @@ -1066,7 +1066,7 @@ static int lib_pRingZMovement(lua_State *L) static int lib_pSceneryZMovement(lua_State *L) { mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); - tm_t ptm = tm; + tm_t ptm = g_tm; NOHUD INLEVEL if (!actor) @@ -1080,7 +1080,7 @@ static int lib_pSceneryZMovement(lua_State *L) static int lib_pPlayerZMovement(lua_State *L) { mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); - tm_t ptm = tm; + tm_t ptm = g_tm; NOHUD INLEVEL if (!actor) @@ -1235,7 +1235,7 @@ static int lib_pGivePlayerLives(lua_State *L) static int lib_pMovePlayer(lua_State *L) { player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); - tm_t ptm = tm; + tm_t ptm = g_tm; NOHUD INLEVEL if (!player) @@ -1314,7 +1314,7 @@ static int lib_pNukeEnemies(lua_State *L) static int lib_pCheckPosition(lua_State *L) { - tm_t ptm = tm; + tm_t ptm = g_tm; mobj_t *thing = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); fixed_t x = luaL_checkfixed(L, 2); fixed_t y = luaL_checkfixed(L, 3); @@ -1323,14 +1323,14 @@ static int lib_pCheckPosition(lua_State *L) if (!thing) return LUA_ErrInvalid(L, "mobj_t"); lua_pushboolean(L, P_CheckPosition(thing, x, y, NULL)); - LUA_PushUserdata(L, tm.thing, META_MOBJ); + LUA_PushUserdata(L, g_tm.thing, META_MOBJ); P_RestoreTMStruct(ptm); return 2; } static int lib_pTryMove(lua_State *L) { - tm_t ptm = tm; + tm_t ptm = g_tm; mobj_t *thing = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); fixed_t x = luaL_checkfixed(L, 2); fixed_t y = luaL_checkfixed(L, 3); @@ -1340,14 +1340,14 @@ static int lib_pTryMove(lua_State *L) if (!thing) return LUA_ErrInvalid(L, "mobj_t"); lua_pushboolean(L, P_TryMove(thing, x, y, allowdropoff, NULL)); - LUA_PushUserdata(L, tm.thing, META_MOBJ); + LUA_PushUserdata(L, g_tm.thing, META_MOBJ); P_RestoreTMStruct(ptm); return 2; } static int lib_pMove(lua_State *L) { - tm_t ptm = tm; + tm_t ptm = g_tm; mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); fixed_t speed = luaL_checkfixed(L, 2); NOHUD @@ -1355,14 +1355,14 @@ static int lib_pMove(lua_State *L) if (!actor) return LUA_ErrInvalid(L, "mobj_t"); lua_pushboolean(L, P_Move(actor, speed)); - LUA_PushUserdata(L, tm.thing, META_MOBJ); + LUA_PushUserdata(L, g_tm.thing, META_MOBJ); P_RestoreTMStruct(ptm); return 2; } static int lib_pTeleportMove(lua_State *L) { - tm_t ptm = tm; + tm_t ptm = g_tm; mobj_t *thing = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); fixed_t x = luaL_checkfixed(L, 2); fixed_t y = luaL_checkfixed(L, 3); @@ -1373,14 +1373,14 @@ static int lib_pTeleportMove(lua_State *L) return LUA_ErrInvalid(L, "mobj_t"); LUA_Deprecated(L, "P_TeleportMove", "P_SetOrigin\" or \"P_MoveOrigin"); lua_pushboolean(L, P_MoveOrigin(thing, x, y, z)); - LUA_PushUserdata(L, tm.thing, META_MOBJ); + LUA_PushUserdata(L, g_tm.thing, META_MOBJ); P_RestoreTMStruct(ptm); return 2; } static int lib_pSetOrigin(lua_State *L) { - tm_t ptm = tm; + tm_t ptm = g_tm; mobj_t *thing = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); fixed_t x = luaL_checkfixed(L, 2); fixed_t y = luaL_checkfixed(L, 3); @@ -1390,14 +1390,14 @@ static int lib_pSetOrigin(lua_State *L) if (!thing) return LUA_ErrInvalid(L, "mobj_t"); lua_pushboolean(L, P_SetOrigin(thing, x, y, z)); - LUA_PushUserdata(L, tm.thing, META_MOBJ); + LUA_PushUserdata(L, g_tm.thing, META_MOBJ); P_RestoreTMStruct(ptm); return 2; } static int lib_pMoveOrigin(lua_State *L) { - tm_t ptm = tm; + tm_t ptm = g_tm; mobj_t *thing = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); fixed_t x = luaL_checkfixed(L, 2); fixed_t y = luaL_checkfixed(L, 3); @@ -1407,7 +1407,7 @@ static int lib_pMoveOrigin(lua_State *L) if (!thing) return LUA_ErrInvalid(L, "mobj_t"); lua_pushboolean(L, P_MoveOrigin(thing, x, y, z)); - LUA_PushUserdata(L, tm.thing, META_MOBJ); + LUA_PushUserdata(L, g_tm.thing, META_MOBJ); P_RestoreTMStruct(ptm); return 2; } @@ -3850,10 +3850,10 @@ static luaL_Reg lib[] = { {"VS_GetArena", lib_vsGetArena}, {"VS_PredictAroundArena", lib_vsPredictAroundArena}, {"VS_RandomPointOnArena", lib_vsRandomPointOnArena}, - + // hu_stuff technically? {"HU_DoTitlecardCEcho", lib_startTitlecardCecho}, - + {NULL, NULL} }; diff --git a/src/lua_maplib.c b/src/lua_maplib.c index ef9043ca0..7ec807c87 100644 --- a/src/lua_maplib.c +++ b/src/lua_maplib.c @@ -796,7 +796,7 @@ static int sector_set(lua_State *L) return luaL_error(L, "sector_t field " LUA_QS " cannot be set.", sector_opt[field]); case sector_floorheight: { // floorheight boolean flag; - tm_t ptm = tm; + tm_t ptm = g_tm; fixed_t lastpos = sector->floorheight; sector->floorheight = luaL_checkfixed(L, 3); flag = P_CheckSector(sector, true); @@ -810,7 +810,7 @@ static int sector_set(lua_State *L) } case sector_ceilingheight: { // ceilingheight boolean flag; - tm_t ptm = tm; + tm_t ptm = g_tm; fixed_t lastpos = sector->ceilingheight; sector->ceilingheight = luaL_checkfixed(L, 3); flag = P_CheckSector(sector, true); @@ -2203,7 +2203,7 @@ static int ffloor_set(lua_State *L) case ffloor_topheight: { // topheight boolean flag; fixed_t lastpos = *ffloor->topheight; - tm_t ptm = tm; + tm_t ptm = g_tm; sector_t *sector = §ors[ffloor->secnum]; sector->ceilingheight = luaL_checkfixed(L, 3); flag = P_CheckSector(sector, true); @@ -2224,7 +2224,7 @@ static int ffloor_set(lua_State *L) case ffloor_bottomheight: { // bottomheight boolean flag; fixed_t lastpos = *ffloor->bottomheight; - tm_t ptm = tm; + tm_t ptm = g_tm; sector_t *sector = §ors[ffloor->secnum]; sector->floorheight = luaL_checkfixed(L, 3); flag = P_CheckSector(sector, true); diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c index 7ce40beb0..3ef2ff950 100644 --- a/src/lua_mobjlib.c +++ b/src/lua_mobjlib.c @@ -565,13 +565,13 @@ static int mobj_set(lua_State *L) case mobj_z: { // z doesn't cross sector bounds so it's okay. - tm_t ptm = tm; + tm_t ptm = g_tm; mo->z = luaL_checkfixed(L, 3); P_CheckPosition(mo, mo->x, mo->y, NULL); - mo->floorz = tm.floorz; - mo->ceilingz = tm.ceilingz; - mo->floorrover = tm.floorrover; - mo->ceilingrover = tm.ceilingrover; + mo->floorz = g_tm.floorz; + mo->ceilingz = g_tm.ceilingz; + mo->floorrover = g_tm.floorrover; + mo->ceilingrover = g_tm.ceilingrover; P_RestoreTMStruct(ptm); break; } @@ -636,29 +636,29 @@ static int mobj_set(lua_State *L) return NOSET; case mobj_radius: { - tm_t ptm = tm; + tm_t ptm = g_tm; mo->radius = luaL_checkfixed(L, 3); if (mo->radius < 0) mo->radius = 0; P_CheckPosition(mo, mo->x, mo->y, NULL); - mo->floorz = tm.floorz; - mo->ceilingz = tm.ceilingz; - mo->floorrover = tm.floorrover; - mo->ceilingrover = tm.ceilingrover; + mo->floorz = g_tm.floorz; + mo->ceilingz = g_tm.ceilingz; + mo->floorrover = g_tm.floorrover; + mo->ceilingrover = g_tm.ceilingrover; P_RestoreTMStruct(ptm); break; } case mobj_height: { - tm_t ptm = tm; + tm_t ptm = g_tm; mo->height = luaL_checkfixed(L, 3); if (mo->height < 0) mo->height = 0; P_CheckPosition(mo, mo->x, mo->y, NULL); - mo->floorz = tm.floorz; - mo->ceilingz = tm.ceilingz; - mo->floorrover = tm.floorrover; - mo->ceilingrover = tm.ceilingrover; + mo->floorz = g_tm.floorz; + mo->ceilingz = g_tm.ceilingz; + mo->floorrover = g_tm.floorrover; + mo->ceilingrover = g_tm.ceilingrover; P_RestoreTMStruct(ptm); break; } diff --git a/src/objects/sneaker-panel.c b/src/objects/sneaker-panel.c index 851c13be2..71cd48854 100644 --- a/src/objects/sneaker-panel.c +++ b/src/objects/sneaker-panel.c @@ -49,13 +49,13 @@ void Obj_SneakerPanelSetup(mobj_t *mobj, mapthing_t *mthing) { if (P_IsObjectFlipped(mobj)) { - if (tm.ceilingz <= mobj->z + mobj->height) - mobj->standingslope = tm.ceilingslope; + if (g_tm.ceilingz <= mobj->z + mobj->height) + mobj->standingslope = g_tm.ceilingslope; } else { - if (mobj->z <= tm.floorz) - mobj->standingslope = tm.floorslope; + if (mobj->z <= g_tm.floorz) + mobj->standingslope = g_tm.floorslope; } } diff --git a/src/p_enemy.c b/src/p_enemy.c index 3f24bc544..645ff3013 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -495,10 +495,10 @@ boolean P_Move(mobj_t *actor, fixed_t speed) if (!P_TryMove(actor, tryx, tryy, false, NULL)) { - if (actor->flags & MF_FLOAT && tm.floatok) + if (actor->flags & MF_FLOAT && g_tm.floatok) { // must adjust height - if (actor->z < tm.floorz) + if (actor->z < g_tm.floorz) actor->z += FixedMul(FLOATSPEED, actor->scale); else actor->z -= FixedMul(FLOATSPEED, actor->scale); @@ -9940,13 +9940,13 @@ void A_FlickyCenter(mobj_t *actor) { actor->extravalue2 = 1; P_SetOrigin(actor, actor->target->x, actor->target->y, actor->target->z); - P_SetTarget(&tm.thing, NULL); + P_SetTarget(&g_tm.thing, NULL); } else if(actor->extravalue2) { actor->extravalue2 = 0; P_SetOrigin(actor, originx, originy, originz); - P_SetTarget(&tm.thing, NULL); + P_SetTarget(&g_tm.thing, NULL); } } } @@ -12139,11 +12139,11 @@ void A_SSMineExplode(mobj_t *actor) return; delay = K_MineExplodeAttack(actor, (3*actor->info->painchance)>>1, (boolean)locvar1); - + skincolornum_t color = SKINCOLOR_KETCHUP; if (!P_MobjWasRemoved(actor->target) && actor->target->player) color = actor->target->player->skincolor; - + K_SpawnMineExplosion(actor, color, delay); } diff --git a/src/p_local.h b/src/p_local.h index b1d3416d4..f36337615 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -398,7 +398,7 @@ struct tm_t fixed_t maxstep; }; -extern tm_t tm; +extern tm_t g_tm; void P_RestoreTMStruct(tm_t tmrestore); diff --git a/src/p_map.c b/src/p_map.c index f1a20876c..cd27930ed 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -45,33 +45,33 @@ #include "m_perfstats.h" // ps_checkposition_calls -tm_t tm = {0}; +tm_t g_tm = {0}; void P_RestoreTMStruct(tm_t tmrestore) { // Reference count management // These are effectively a no-op if mobj remains the same - P_SetTarget(&tm.thing, tmrestore.thing); - P_SetTarget(&tm.floorthing, tmrestore.floorthing); - P_SetTarget(&tm.hitthing, tmrestore.hitthing); + P_SetTarget(&g_tm.thing, tmrestore.thing); + P_SetTarget(&g_tm.floorthing, tmrestore.floorthing); + P_SetTarget(&g_tm.hitthing, tmrestore.hitthing); // Restore state - tm = tmrestore; + g_tm = tmrestore; // Validation - if (tm.thing && P_MobjWasRemoved(tm.thing) == true) + if (g_tm.thing && P_MobjWasRemoved(g_tm.thing) == true) { - P_SetTarget(&tm.thing, NULL); + P_SetTarget(&g_tm.thing, NULL); } - if (tm.floorthing && P_MobjWasRemoved(tm.floorthing) == true) + if (g_tm.floorthing && P_MobjWasRemoved(g_tm.floorthing) == true) { - P_SetTarget(&tm.floorthing, NULL); + P_SetTarget(&g_tm.floorthing, NULL); } - if (tm.hitthing && P_MobjWasRemoved(tm.hitthing) == true) + if (g_tm.hitthing && P_MobjWasRemoved(g_tm.hitthing) == true) { - P_SetTarget(&tm.hitthing, NULL); + P_SetTarget(&g_tm.hitthing, NULL); } } @@ -130,10 +130,10 @@ static boolean P_TeleportMove(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z) if (P_MobjWasRemoved(thing)) return true; - thing->floorz = tm.floorz; - thing->ceilingz = tm.ceilingz; - thing->floorrover = tm.floorrover; - thing->ceilingrover = tm.ceilingrover; + thing->floorz = g_tm.floorz; + thing->ceilingz = g_tm.ceilingz; + thing->floorrover = g_tm.floorrover; + thing->ceilingrover = g_tm.ceilingrover; P_CheckSectorTransitionalEffects(thing, oldsector, startingonground); @@ -523,24 +523,24 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) fixed_t blockdist; boolean damage = false; - if (tm.thing == NULL || P_MobjWasRemoved(tm.thing) == true) - return BMIT_STOP; // func just popped our tm.thing, cannot continue. + if (g_tm.thing == NULL || P_MobjWasRemoved(g_tm.thing) == true) + return BMIT_STOP; // func just popped our g_tm.thing, cannot continue. // Ignore... things. if (thing == NULL || P_MobjWasRemoved(thing) == true) return BMIT_CONTINUE; // don't clip against self - if (thing == tm.thing) + if (thing == g_tm.thing) return BMIT_CONTINUE; // Ignore spectators - if ((tm.thing->player && tm.thing->player->spectator) + if ((g_tm.thing->player && g_tm.thing->player->spectator) || (thing->player && thing->player->spectator)) return BMIT_CONTINUE; // Ignore the collision if BOTH things are in hitlag. - if (P_MobjIsFrozen(thing) && P_MobjIsFrozen(tm.thing)) + if (P_MobjIsFrozen(thing) && P_MobjIsFrozen(g_tm.thing)) return BMIT_CONTINUE; if ((thing->flags & MF_NOCLIPTHING) || !(thing->flags & (MF_SOLID|MF_SPECIAL|MF_PAIN|MF_SHOOTABLE|MF_SPRING))) @@ -550,9 +550,9 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) if (P_MobjIsReappearing(thing)) return BMIT_CONTINUE; - blockdist = thing->radius + tm.thing->radius; + blockdist = thing->radius + g_tm.thing->radius; - if (abs(thing->x - tm.x) >= blockdist || abs(thing->y - tm.y) >= blockdist) + if (abs(thing->x - g_tm.x) >= blockdist || abs(thing->y - g_tm.y) >= blockdist) return BMIT_CONTINUE; // didn't hit it if (thing->flags & MF_PAPERCOLLISION) // CAUTION! Very easy to get stuck inside MF_SOLID objects. Giving the player MF_PAPERCOLLISION is a bad idea unless you know what you're doing. @@ -574,47 +574,47 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) junk.dx = 2*cosradius; // v2.x - v1.x; junk.dy = 2*sinradius; // v2.y - v1.y; - if (tm.thing->flags & MF_PAPERCOLLISION) // more strenuous checking to prevent clipping issues + if (g_tm.thing->flags & MF_PAPERCOLLISION) // more strenuous checking to prevent clipping issues { INT32 check1, check2, check3, check4; - fixed_t tmcosradius = FixedMul(tm.thing->radius, FINECOSINE(tm.thing->angle>>ANGLETOFINESHIFT)); - fixed_t tmsinradius = FixedMul(tm.thing->radius, FINESINE(tm.thing->angle>>ANGLETOFINESHIFT)); - if (abs(thing->x - tm.x) >= (abs(tmcosradius) + abs(cosradius)) || abs(thing->y - tm.y) >= (abs(tmsinradius) + abs(sinradius))) + fixed_t tmcosradius = FixedMul(g_tm.thing->radius, FINECOSINE(g_tm.thing->angle>>ANGLETOFINESHIFT)); + fixed_t tmsinradius = FixedMul(g_tm.thing->radius, FINESINE(g_tm.thing->angle>>ANGLETOFINESHIFT)); + if (abs(thing->x - g_tm.x) >= (abs(tmcosradius) + abs(cosradius)) || abs(thing->y - g_tm.y) >= (abs(tmsinradius) + abs(sinradius))) return BMIT_CONTINUE; // didn't hit it - check1 = P_PointOnLineSide(tm.x - tmcosradius, tm.y - tmsinradius, &junk); - check2 = P_PointOnLineSide(tm.x + tmcosradius, tm.y + tmsinradius, &junk); - check3 = P_PointOnLineSide(tm.x + tm.thing->momx - tmcosradius, tm.y + tm.thing->momy - tmsinradius, &junk); - check4 = P_PointOnLineSide(tm.x + tm.thing->momx + tmcosradius, tm.y + tm.thing->momy + tmsinradius, &junk); + check1 = P_PointOnLineSide(g_tm.x - tmcosradius, g_tm.y - tmsinradius, &junk); + check2 = P_PointOnLineSide(g_tm.x + tmcosradius, g_tm.y + tmsinradius, &junk); + check3 = P_PointOnLineSide(g_tm.x + g_tm.thing->momx - tmcosradius, g_tm.y + g_tm.thing->momy - tmsinradius, &junk); + check4 = P_PointOnLineSide(g_tm.x + g_tm.thing->momx + tmcosradius, g_tm.y + g_tm.thing->momy + tmsinradius, &junk); if ((check1 == check2) && (check2 == check3) && (check3 == check4)) return BMIT_CONTINUE; // the line doesn't cross between collider's start or end } else { - if (abs(thing->x - tm.x) >= (tm.thing->radius + abs(cosradius)) || abs(thing->y - tm.y) >= (tm.thing->radius + abs(sinradius))) + if (abs(thing->x - g_tm.x) >= (g_tm.thing->radius + abs(cosradius)) || abs(thing->y - g_tm.y) >= (g_tm.thing->radius + abs(sinradius))) return BMIT_CONTINUE; // didn't hit it - if ((P_PointOnLineSide(tm.x - tm.thing->radius, tm.y - tm.thing->radius, &junk) - == P_PointOnLineSide(tm.x + tm.thing->radius, tm.y + tm.thing->radius, &junk)) - && (P_PointOnLineSide(tm.x + tm.thing->radius, tm.y - tm.thing->radius, &junk) - == P_PointOnLineSide(tm.x - tm.thing->radius, tm.y + tm.thing->radius, &junk))) + if ((P_PointOnLineSide(g_tm.x - g_tm.thing->radius, g_tm.y - g_tm.thing->radius, &junk) + == P_PointOnLineSide(g_tm.x + g_tm.thing->radius, g_tm.y + g_tm.thing->radius, &junk)) + && (P_PointOnLineSide(g_tm.x + g_tm.thing->radius, g_tm.y - g_tm.thing->radius, &junk) + == P_PointOnLineSide(g_tm.x - g_tm.thing->radius, g_tm.y + g_tm.thing->radius, &junk))) return BMIT_CONTINUE; // the line doesn't cross between either pair of opposite corners } } - else if (tm.thing->flags & MF_PAPERCOLLISION) + else if (g_tm.thing->flags & MF_PAPERCOLLISION) { fixed_t tmcosradius, tmsinradius; vertex_t v1, v2; // fake vertexes line_t junk; // fake linedef - tmcosradius = FixedMul(tm.thing->radius, FINECOSINE(tm.thing->angle>>ANGLETOFINESHIFT)); - tmsinradius = FixedMul(tm.thing->radius, FINESINE(tm.thing->angle>>ANGLETOFINESHIFT)); + tmcosradius = FixedMul(g_tm.thing->radius, FINECOSINE(g_tm.thing->angle>>ANGLETOFINESHIFT)); + tmsinradius = FixedMul(g_tm.thing->radius, FINESINE(g_tm.thing->angle>>ANGLETOFINESHIFT)); - if (abs(thing->x - tm.x) >= (thing->radius + abs(tmcosradius)) || abs(thing->y - tm.y) >= (thing->radius + abs(tmsinradius))) + if (abs(thing->x - g_tm.x) >= (thing->radius + abs(tmcosradius)) || abs(thing->y - g_tm.y) >= (thing->radius + abs(tmsinradius))) return BMIT_CONTINUE; // didn't hit it - v1.x = tm.x - tmcosradius; - v1.y = tm.y - tmsinradius; - v2.x = tm.x + tmcosradius; - v2.y = tm.y + tmsinradius; + v1.x = g_tm.x - tmcosradius; + v1.y = g_tm.y - tmsinradius; + v2.x = g_tm.x + tmcosradius; + v2.y = g_tm.y + tmsinradius; junk.v1 = &v1; junk.v2 = &v2; @@ -630,16 +630,16 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) } { - UINT8 shouldCollide = LUA_Hook2Mobj(thing, tm.thing, MOBJ_HOOK(MobjCollide)); // checks hook for thing's type - if (P_MobjWasRemoved(tm.thing) || P_MobjWasRemoved(thing)) + UINT8 shouldCollide = LUA_Hook2Mobj(thing, g_tm.thing, MOBJ_HOOK(MobjCollide)); // checks hook for thing's type + if (P_MobjWasRemoved(g_tm.thing) || P_MobjWasRemoved(thing)) return BMIT_CONTINUE; // one of them was removed??? if (shouldCollide == 1) return BMIT_ABORT; // force collide else if (shouldCollide == 2) return BMIT_CONTINUE; // force no collide - shouldCollide = LUA_Hook2Mobj(tm.thing, thing, MOBJ_HOOK(MobjMoveCollide)); // checks hook for tm.thing's type - if (P_MobjWasRemoved(tm.thing) || P_MobjWasRemoved(thing)) + shouldCollide = LUA_Hook2Mobj(g_tm.thing, thing, MOBJ_HOOK(MobjMoveCollide)); // checks hook for g_tm.thing's type + if (P_MobjWasRemoved(g_tm.thing) || P_MobjWasRemoved(thing)) return BMIT_CONTINUE; // one of them was removed??? if (shouldCollide == 1) return BMIT_ABORT; // force collide @@ -649,42 +649,42 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) // Blend-Eye internal noclip if ((thing->type == MT_BLENDEYE_GLASS || thing->type == MT_BLENDEYE_SHIELD || thing->type == MT_BLENDEYE_EGGBEATER) - && (tm.thing->type == MT_BLENDEYE_MAIN || tm.thing->type == MT_BLENDEYE_EYE || tm.thing->type == MT_BLENDEYE_PUYO)) + && (g_tm.thing->type == MT_BLENDEYE_MAIN || g_tm.thing->type == MT_BLENDEYE_EYE || g_tm.thing->type == MT_BLENDEYE_PUYO)) return BMIT_CONTINUE; if (thing->flags & MF_PAIN) { // Player touches painful thing sitting on the floor // see if it went over / under - if (thing->z > tm.thing->z + tm.thing->height) + if (thing->z > g_tm.thing->z + g_tm.thing->height) return BMIT_CONTINUE; // overhead - if (thing->z + thing->height < tm.thing->z) + if (thing->z + thing->height < g_tm.thing->z) return BMIT_CONTINUE; // underneath - if (tm.thing->flags & MF_SHOOTABLE && thing->health > 0) + if (g_tm.thing->flags & MF_SHOOTABLE && thing->health > 0) { UINT32 damagetype = (thing->info->mass & 0xFF); - P_DamageMobj(tm.thing, thing, thing, 1, damagetype); + P_DamageMobj(g_tm.thing, thing, thing, 1, damagetype); - if (P_MobjWasRemoved(tm.thing) || P_MobjWasRemoved(thing)) + if (P_MobjWasRemoved(g_tm.thing) || P_MobjWasRemoved(thing)) return BMIT_CONTINUE; damage = true; } } - else if (tm.thing->flags & MF_PAIN && thing->player) + else if (g_tm.thing->flags & MF_PAIN && thing->player) { // Painful thing splats player in the face // see if it went over / under - if (tm.thing->z > thing->z + thing->height) + if (g_tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tm.thing->z + tm.thing->height < thing->z) + if (g_tm.thing->z + g_tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - if (thing->flags & MF_SHOOTABLE && tm.thing->health > 0) + if (thing->flags & MF_SHOOTABLE && g_tm.thing->health > 0) { - UINT32 damagetype = (tm.thing->info->mass & 0xFF); + UINT32 damagetype = (g_tm.thing->info->mass & 0xFF); - P_DamageMobj(thing, tm.thing, tm.thing, 1, damagetype); + P_DamageMobj(thing, g_tm.thing, g_tm.thing, 1, damagetype); - if (P_MobjWasRemoved(tm.thing) || P_MobjWasRemoved(thing)) + if (P_MobjWasRemoved(g_tm.thing) || P_MobjWasRemoved(thing)) return BMIT_CONTINUE; damage = true; @@ -692,16 +692,16 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) } // check for skulls slamming into things - if (tm.thing->flags2 & MF2_SKULLFLY) + if (g_tm.thing->flags2 & MF2_SKULLFLY) { // see if it went over / under - if (tm.thing->z > thing->z + thing->height) + if (g_tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tm.thing->z + tm.thing->height < thing->z) + if (g_tm.thing->z + g_tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - tm.thing->flags2 &= ~MF2_SKULLFLY; - tm.thing->momx = tm.thing->momy = tm.thing->momz = 0; + g_tm.thing->flags2 &= ~MF2_SKULLFLY; + g_tm.thing->momx = g_tm.thing->momy = g_tm.thing->momz = 0; return BMIT_ABORT; // stop moving } @@ -709,166 +709,166 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) if (thing->type == MT_DLZ_SEASAW_HITBOX) { - if (tm.thing->type == MT_PLAYER) - Obj_DLZSeasawCollide(tm.thing, thing); // all checks are performed in there. + if (g_tm.thing->type == MT_PLAYER) + Obj_DLZSeasawCollide(g_tm.thing, thing); // all checks are performed in there. return BMIT_CONTINUE; } if (thing->type == MT_GPZ_SEASAW_HITBOX) { - if (tm.thing->type == MT_PLAYER) - Obj_GPZSeasawCollide(tm.thing, thing); // all checks are performed in there. + if (g_tm.thing->type == MT_PLAYER) + Obj_GPZSeasawCollide(g_tm.thing, thing); // all checks are performed in there. return BMIT_CONTINUE; } if (thing->type == MT_DLZ_HOVER) { - if (tm.thing->type == MT_PLAYER) - Obj_DLZHoverCollide(tm.thing, thing); + if (g_tm.thing->type == MT_PLAYER) + Obj_DLZHoverCollide(g_tm.thing, thing); return BMIT_CONTINUE; } if (thing->type == MT_DLZ_RINGVACCUM) { - if (tm.thing->type == MT_FLINGRING) - Obj_DLZRingVaccumCollide(tm.thing, thing); + if (g_tm.thing->type == MT_FLINGRING) + Obj_DLZRingVaccumCollide(g_tm.thing, thing); return BMIT_CONTINUE; } - if (tm.thing->type == MT_INSTAWHIP) + if (g_tm.thing->type == MT_INSTAWHIP) { - if (tm.thing->z > thing->z + thing->height) + if (g_tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tm.thing->z + tm.thing->height < thing->z) + if (g_tm.thing->z + g_tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - K_InstaWhipCollide(tm.thing, thing); + K_InstaWhipCollide(g_tm.thing, thing); return BMIT_CONTINUE; } - if (tm.thing->type == MT_PATROLIVOBALL) + if (g_tm.thing->type == MT_PATROLIVOBALL) { if (!thing->player) return BMIT_CONTINUE; - if (tm.thing->z > thing->z + thing->height) + if (g_tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tm.thing->z + tm.thing->height < thing->z) + if (g_tm.thing->z + g_tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - Obj_PatrolIvoBallTouch(tm.thing, thing); + Obj_PatrolIvoBallTouch(g_tm.thing, thing); return BMIT_CONTINUE; } - if (thing->type == MT_BATTLEUFO && tm.thing->player) + if (thing->type == MT_BATTLEUFO && g_tm.thing->player) { if (thing->health <= 0) { return BMIT_CONTINUE; // dead } - if (tm.thing->z > thing->z + thing->height) + if (g_tm.thing->z > thing->z + thing->height) { return BMIT_CONTINUE; // overhead } - if (tm.thing->z + tm.thing->height < thing->floorz) + if (g_tm.thing->z + g_tm.thing->height < thing->floorz) { return BMIT_CONTINUE; // underneath } - if (P_PlayerInPain(tm.thing->player)) + if (P_PlayerInPain(g_tm.thing->player)) { return BMIT_CONTINUE; // spinout would cause a softlock } - if (!tm.thing->player->fastfall) + if (!g_tm.thing->player->fastfall) { fixed_t tractorHeight = 211*mapobjectscale; - fixed_t zRange = FixedDiv(thing->z - tm.thing->z, tractorHeight); + fixed_t zRange = FixedDiv(thing->z - g_tm.thing->z, tractorHeight); fixed_t momZ = max(zRange, FRACUNIT/16); - if (tm.thing->eflags & MFE_UNDERWATER) + if (g_tm.thing->eflags & MFE_UNDERWATER) { momZ = (117 * momZ) / 200; } - P_SetObjectMomZ(tm.thing, momZ, true); + P_SetObjectMomZ(g_tm.thing, momZ, true); } fixed_t friction = 33*FRACUNIT/35; - tm.thing->momx = FixedMul(tm.thing->momx, friction); - tm.thing->momy = FixedMul(tm.thing->momy, friction); + g_tm.thing->momx = FixedMul(g_tm.thing->momx, friction); + g_tm.thing->momy = FixedMul(g_tm.thing->momy, friction); return BMIT_CONTINUE; } if (thing->type == MT_BLENDEYE_EGGBEATER - && tm.thing->type == MT_PLAYER && tm.thing->player) + && g_tm.thing->type == MT_PLAYER && g_tm.thing->player) { - if (tm.thing->z > thing->z + thing->height) + if (g_tm.thing->z > thing->z + thing->height) { return BMIT_CONTINUE; // overhead } - if (tm.thing->z + tm.thing->height < thing->z) + if (g_tm.thing->z + g_tm.thing->height < thing->z) { return BMIT_CONTINUE; // underneath } - VS_BlendEye_Eggbeater_Touched(thing, tm.thing); + VS_BlendEye_Eggbeater_Touched(thing, g_tm.thing); } if (thing->type == MT_SPB) { - if (tm.thing->type != MT_PLAYER - && thing->tracer != tm.thing) + if (g_tm.thing->type != MT_PLAYER + && thing->tracer != g_tm.thing) { // Needs to be a player or the // thing that we're chasing. return BMIT_CONTINUE; } - if (tm.thing->z > thing->z + thing->height) + if (g_tm.thing->z > thing->z + thing->height) { return BMIT_CONTINUE; // overhead } - if (tm.thing->z + tm.thing->height < thing->z) + if (g_tm.thing->z + g_tm.thing->height < thing->z) { return BMIT_CONTINUE; // underneath } - Obj_SPBTouch(thing, tm.thing); + Obj_SPBTouch(thing, g_tm.thing); return BMIT_CONTINUE; } - else if (tm.thing->type == MT_SPB) + else if (g_tm.thing->type == MT_SPB) { if (thing->type != MT_PLAYER - && tm.thing->tracer != thing) + && g_tm.thing->tracer != thing) { // Needs to be a player or the // thing that we're chasing. return BMIT_CONTINUE; } - if (tm.thing->z > thing->z + thing->height) + if (g_tm.thing->z > thing->z + thing->height) { return BMIT_CONTINUE; // overhead } - if (tm.thing->z + tm.thing->height < thing->z) + if (g_tm.thing->z + g_tm.thing->height < thing->z) { return BMIT_CONTINUE; // underneath } - Obj_SPBTouch(tm.thing, thing); + Obj_SPBTouch(g_tm.thing, thing); return BMIT_CONTINUE; } if (thing->type == MT_SHRINK_GUN || thing->type == MT_SHRINK_PARTICLE) { - if (tm.thing->type != MT_PLAYER) + if (g_tm.thing->type != MT_PLAYER) { return BMIT_CONTINUE; } @@ -878,160 +878,160 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) // Use special collision for the laser gun. // The laser sprite itself is just a visual, // the gun itself does the colliding for us. - if (tm.thing->z > thing->z) + if (g_tm.thing->z > thing->z) { return BMIT_CONTINUE; // overhead } - if (tm.thing->z + tm.thing->height < thing->floorz) + if (g_tm.thing->z + g_tm.thing->height < thing->floorz) { return BMIT_CONTINUE; // underneath } } else { - if (tm.thing->z > thing->z + thing->height) + if (g_tm.thing->z > thing->z + thing->height) { return BMIT_CONTINUE; // overhead } - if (tm.thing->z + tm.thing->height < thing->z) + if (g_tm.thing->z + g_tm.thing->height < thing->z) { return BMIT_CONTINUE; // underneath } } - return Obj_ShrinkLaserCollide(thing, tm.thing) ? BMIT_CONTINUE : BMIT_ABORT; + return Obj_ShrinkLaserCollide(thing, g_tm.thing) ? BMIT_CONTINUE : BMIT_ABORT; } - else if (tm.thing->type == MT_SHRINK_GUN || tm.thing->type == MT_SHRINK_PARTICLE) + else if (g_tm.thing->type == MT_SHRINK_GUN || g_tm.thing->type == MT_SHRINK_PARTICLE) { if (thing->type != MT_PLAYER) { return BMIT_CONTINUE; } - if (tm.thing->type == MT_SHRINK_GUN) + if (g_tm.thing->type == MT_SHRINK_GUN) { // Use special collision for the laser gun. // The laser sprite itself is just a visual, // the gun itself does the colliding for us. - if (thing->z > tm.thing->z) + if (thing->z > g_tm.thing->z) { return BMIT_CONTINUE; // overhead } - if (thing->z + thing->height < tm.thing->floorz) + if (thing->z + thing->height < g_tm.thing->floorz) { return BMIT_CONTINUE; // underneath } } else { - if (tm.thing->z > thing->z + thing->height) + if (g_tm.thing->z > thing->z + thing->height) { return BMIT_CONTINUE; // overhead } - if (tm.thing->z + tm.thing->height < thing->z) + if (g_tm.thing->z + g_tm.thing->height < thing->z) { return BMIT_CONTINUE; // underneath } } - return Obj_ShrinkLaserCollide(tm.thing, thing) ? BMIT_CONTINUE : BMIT_ABORT; + return Obj_ShrinkLaserCollide(g_tm.thing, thing) ? BMIT_CONTINUE : BMIT_ABORT; } - if (tm.thing->type == MT_EGGMANITEM || tm.thing->type == MT_EGGMANITEM_SHIELD) + if (g_tm.thing->type == MT_EGGMANITEM || g_tm.thing->type == MT_EGGMANITEM_SHIELD) { // see if it went over / under - if (tm.thing->z > thing->z + thing->height) + if (g_tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tm.thing->z + tm.thing->height < thing->z) + if (g_tm.thing->z + g_tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - return K_EggItemCollide(tm.thing, thing) ? BMIT_CONTINUE : BMIT_ABORT; + return K_EggItemCollide(g_tm.thing, thing) ? BMIT_CONTINUE : BMIT_ABORT; } else if (thing->type == MT_EGGMANITEM || thing->type == MT_EGGMANITEM_SHIELD) { // see if it went over / under - if (tm.thing->z > thing->z + thing->height) + if (g_tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tm.thing->z + tm.thing->height < thing->z) + if (g_tm.thing->z + g_tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - return K_EggItemCollide(thing, tm.thing) ? BMIT_CONTINUE : BMIT_ABORT; + return K_EggItemCollide(thing, g_tm.thing) ? BMIT_CONTINUE : BMIT_ABORT; } - if (tm.thing->type == MT_RANDOMITEM) + if (g_tm.thing->type == MT_RANDOMITEM) return BMIT_CONTINUE; - if (tm.thing->type != MT_PLAYER && thing->player && K_PlayerGuard(thing->player) && K_BubbleShieldCanReflect(thing, tm.thing)) + if (g_tm.thing->type != MT_PLAYER && thing->player && K_PlayerGuard(thing->player) && K_BubbleShieldCanReflect(thing, g_tm.thing)) { // see if it went over / under - if (tm.thing->z > thing->z + thing->height) + if (g_tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tm.thing->z + tm.thing->height < thing->z) + if (g_tm.thing->z + g_tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - return K_BubbleShieldReflect(thing, tm.thing) ? BMIT_CONTINUE : BMIT_ABORT; + return K_BubbleShieldReflect(thing, g_tm.thing) ? BMIT_CONTINUE : BMIT_ABORT; } - else if (thing->type != MT_PLAYER && tm.thing->player && K_PlayerGuard(tm.thing->player) && K_BubbleShieldCanReflect(tm.thing, thing)) + else if (thing->type != MT_PLAYER && g_tm.thing->player && K_PlayerGuard(g_tm.thing->player) && K_BubbleShieldCanReflect(g_tm.thing, thing)) { // see if it went over / under - if (tm.thing->z > thing->z + thing->height) + if (g_tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tm.thing->z + tm.thing->height < thing->z) + if (g_tm.thing->z + g_tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - return K_BubbleShieldReflect(tm.thing, thing) ? BMIT_CONTINUE : BMIT_ABORT; + return K_BubbleShieldReflect(g_tm.thing, thing) ? BMIT_CONTINUE : BMIT_ABORT; } // Bubble Shield reflect if (thing->type == MT_BUBBLESHIELD && !P_MobjWasRemoved(thing->target) && thing->target->player && thing->target->player->bubbleblowup) { // see if it went over / under - if (tm.thing->z > thing->z + thing->height) + if (g_tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tm.thing->z + tm.thing->height < thing->z) + if (g_tm.thing->z + g_tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - return K_BubbleShieldCollide(thing, tm.thing) ? BMIT_CONTINUE : BMIT_ABORT; + return K_BubbleShieldCollide(thing, g_tm.thing) ? BMIT_CONTINUE : BMIT_ABORT; } - else if (tm.thing->type == MT_BUBBLESHIELD && !P_MobjWasRemoved(tm.thing->target) && tm.thing->target->player && tm.thing->target->player->bubbleblowup) + else if (g_tm.thing->type == MT_BUBBLESHIELD && !P_MobjWasRemoved(g_tm.thing->target) && g_tm.thing->target->player && g_tm.thing->target->player->bubbleblowup) { // see if it went over / under - if (tm.thing->z > thing->z + thing->height) + if (g_tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tm.thing->z + tm.thing->height < thing->z) + if (g_tm.thing->z + g_tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - return K_BubbleShieldCollide(tm.thing, thing) ? BMIT_CONTINUE : BMIT_ABORT; + return K_BubbleShieldCollide(g_tm.thing, thing) ? BMIT_CONTINUE : BMIT_ABORT; } // double make sure bubbles won't collide with anything else - if (thing->type == MT_BUBBLESHIELD || tm.thing->type == MT_BUBBLESHIELD) + if (thing->type == MT_BUBBLESHIELD || g_tm.thing->type == MT_BUBBLESHIELD) return BMIT_CONTINUE; // Droptarget reflect if ((thing->type == MT_DROPTARGET || thing->type == MT_DROPTARGET_SHIELD) - && (tm.thing->type == MT_ORBINAUT || tm.thing->type == MT_JAWZ || tm.thing->type == MT_GACHABOM - || tm.thing->type == MT_BANANA || tm.thing->type == MT_EGGMANITEM || tm.thing->type == MT_BALLHOG - || tm.thing->type == MT_SSMINE || tm.thing->type == MT_LANDMINE || tm.thing->type == MT_SINK - || tm.thing->type == MT_GARDENTOP - || tm.thing->type == MT_MONITOR - || tm.thing->type == MT_BATTLECAPSULE - || tm.thing->type == MT_KART_LEFTOVER - || (tm.thing->type == MT_PLAYER))) + && (g_tm.thing->type == MT_ORBINAUT || g_tm.thing->type == MT_JAWZ || g_tm.thing->type == MT_GACHABOM + || g_tm.thing->type == MT_BANANA || g_tm.thing->type == MT_EGGMANITEM || g_tm.thing->type == MT_BALLHOG + || g_tm.thing->type == MT_SSMINE || g_tm.thing->type == MT_LANDMINE || g_tm.thing->type == MT_SINK + || g_tm.thing->type == MT_GARDENTOP + || g_tm.thing->type == MT_MONITOR + || g_tm.thing->type == MT_BATTLECAPSULE + || g_tm.thing->type == MT_KART_LEFTOVER + || (g_tm.thing->type == MT_PLAYER))) { // see if it went over / under - if (tm.thing->z > thing->z + thing->height) + if (g_tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tm.thing->z + tm.thing->height < thing->z) + if (g_tm.thing->z + g_tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - return K_DropTargetCollide(thing, tm.thing) ? BMIT_CONTINUE : BMIT_ABORT; + return K_DropTargetCollide(thing, g_tm.thing) ? BMIT_CONTINUE : BMIT_ABORT; } - else if ((tm.thing->type == MT_DROPTARGET || tm.thing->type == MT_DROPTARGET_SHIELD) + else if ((g_tm.thing->type == MT_DROPTARGET || g_tm.thing->type == MT_DROPTARGET_SHIELD) && (thing->type == MT_ORBINAUT || thing->type == MT_JAWZ || thing->type == MT_GACHABOM || thing->type == MT_BANANA || thing->type == MT_EGGMANITEM || thing->type == MT_BALLHOG || thing->type == MT_SSMINE || thing->type == MT_LANDMINE || thing->type == MT_SINK @@ -1042,175 +1042,175 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) || (thing->type == MT_PLAYER))) { // see if it went over / under - if (tm.thing->z > thing->z + thing->height) + if (g_tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tm.thing->z + tm.thing->height < thing->z) + if (g_tm.thing->z + g_tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - return K_DropTargetCollide(tm.thing, thing) ? BMIT_CONTINUE : BMIT_ABORT; + return K_DropTargetCollide(g_tm.thing, thing) ? BMIT_CONTINUE : BMIT_ABORT; } // double make sure drop targets won't collide with anything else - if (thing->type == MT_DROPTARGET || tm.thing->type == MT_DROPTARGET - || thing->type == MT_DROPTARGET_SHIELD || tm.thing->type == MT_DROPTARGET_SHIELD) + if (thing->type == MT_DROPTARGET || g_tm.thing->type == MT_DROPTARGET + || thing->type == MT_DROPTARGET_SHIELD || g_tm.thing->type == MT_DROPTARGET_SHIELD) return BMIT_CONTINUE; - if (tm.thing->type == MT_ORBINAUT || tm.thing->type == MT_JAWZ || tm.thing->type == MT_GACHABOM - || tm.thing->type == MT_ORBINAUT_SHIELD || tm.thing->type == MT_JAWZ_SHIELD - || tm.thing->type == MT_GARDENTOP) + if (g_tm.thing->type == MT_ORBINAUT || g_tm.thing->type == MT_JAWZ || g_tm.thing->type == MT_GACHABOM + || g_tm.thing->type == MT_ORBINAUT_SHIELD || g_tm.thing->type == MT_JAWZ_SHIELD + || g_tm.thing->type == MT_GARDENTOP) { // see if it went over / under - if (tm.thing->z > thing->z + thing->height) + if (g_tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tm.thing->z + tm.thing->height < thing->z) + if (g_tm.thing->z + g_tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - return Obj_OrbinautJawzCollide(tm.thing, thing) ? BMIT_CONTINUE : BMIT_ABORT; + return Obj_OrbinautJawzCollide(g_tm.thing, thing) ? BMIT_CONTINUE : BMIT_ABORT; } else if (thing->type == MT_ORBINAUT || thing->type == MT_JAWZ || thing->type == MT_GACHABOM || thing->type == MT_ORBINAUT_SHIELD || thing->type == MT_JAWZ_SHIELD || thing->type == MT_GARDENTOP) { // see if it went over / under - if (tm.thing->z > thing->z + thing->height) + if (g_tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tm.thing->z + tm.thing->height < thing->z) + if (g_tm.thing->z + g_tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - return Obj_OrbinautJawzCollide(thing, tm.thing) ? BMIT_CONTINUE : BMIT_ABORT; + return Obj_OrbinautJawzCollide(thing, g_tm.thing) ? BMIT_CONTINUE : BMIT_ABORT; } - if (tm.thing->type == MT_BANANA || tm.thing->type == MT_BANANA_SHIELD || tm.thing->type == MT_BALLHOG) + if (g_tm.thing->type == MT_BANANA || g_tm.thing->type == MT_BANANA_SHIELD || g_tm.thing->type == MT_BALLHOG) { // see if it went over / under - if (tm.thing->z > thing->z + thing->height) + if (g_tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tm.thing->z + tm.thing->height < thing->z) + if (g_tm.thing->z + g_tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - return K_BananaBallhogCollide(tm.thing, thing) ? BMIT_CONTINUE : BMIT_ABORT; + return K_BananaBallhogCollide(g_tm.thing, thing) ? BMIT_CONTINUE : BMIT_ABORT; } else if (thing->type == MT_BANANA || thing->type == MT_BANANA_SHIELD || thing->type == MT_BALLHOG) { // see if it went over / under - if (tm.thing->z > thing->z + thing->height) + if (g_tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tm.thing->z + tm.thing->height < thing->z) + if (g_tm.thing->z + g_tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - return K_BananaBallhogCollide(thing, tm.thing) ? BMIT_CONTINUE : BMIT_ABORT; + return K_BananaBallhogCollide(thing, g_tm.thing) ? BMIT_CONTINUE : BMIT_ABORT; } - if (tm.thing->type == MT_SSMINE || tm.thing->type == MT_SSMINE_SHIELD) + if (g_tm.thing->type == MT_SSMINE || g_tm.thing->type == MT_SSMINE_SHIELD) { // see if it went over / under - if (tm.thing->z > thing->z + thing->height) + if (g_tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tm.thing->z + tm.thing->height < thing->z) + if (g_tm.thing->z + g_tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - return K_MineCollide(tm.thing, thing) ? BMIT_CONTINUE : BMIT_ABORT; + return K_MineCollide(g_tm.thing, thing) ? BMIT_CONTINUE : BMIT_ABORT; } else if (thing->type == MT_SSMINE || thing->type == MT_SSMINE_SHIELD) { // see if it went over / under - if (tm.thing->z > thing->z + thing->height) + if (g_tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tm.thing->z + tm.thing->height < thing->z) + if (g_tm.thing->z + g_tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - return K_MineCollide(thing, tm.thing) ? BMIT_CONTINUE : BMIT_ABORT; + return K_MineCollide(thing, g_tm.thing) ? BMIT_CONTINUE : BMIT_ABORT; } - if (tm.thing->type == MT_LANDMINE) + if (g_tm.thing->type == MT_LANDMINE) { // see if it went over / under - if (tm.thing->z > thing->z + thing->height) + if (g_tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tm.thing->z + tm.thing->height < thing->z) + if (g_tm.thing->z + g_tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - return K_LandMineCollide(tm.thing, thing) ? BMIT_CONTINUE : BMIT_ABORT; + return K_LandMineCollide(g_tm.thing, thing) ? BMIT_CONTINUE : BMIT_ABORT; } else if (thing->type == MT_LANDMINE) { // see if it went over / under - if (tm.thing->z > thing->z + thing->height) + if (g_tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tm.thing->z + tm.thing->height < thing->z) + if (g_tm.thing->z + g_tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - return K_LandMineCollide(thing, tm.thing) ? BMIT_CONTINUE : BMIT_ABORT; + return K_LandMineCollide(thing, g_tm.thing) ? BMIT_CONTINUE : BMIT_ABORT; } - if (tm.thing->type == MT_SINK) + if (g_tm.thing->type == MT_SINK) { // see if it went over / under - if (tm.thing->z > thing->z + thing->height) + if (g_tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tm.thing->z + tm.thing->height < thing->z) + if (g_tm.thing->z + g_tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - return K_KitchenSinkCollide(tm.thing, thing) ? BMIT_CONTINUE : BMIT_ABORT; + return K_KitchenSinkCollide(g_tm.thing, thing) ? BMIT_CONTINUE : BMIT_ABORT; } else if (thing->type == MT_SINK) { // see if it went over / under - if (tm.thing->z > thing->z + thing->height) + if (g_tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tm.thing->z + tm.thing->height < thing->z) + if (g_tm.thing->z + g_tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - return K_KitchenSinkCollide(thing, tm.thing) ? BMIT_CONTINUE : BMIT_ABORT; + return K_KitchenSinkCollide(thing, g_tm.thing) ? BMIT_CONTINUE : BMIT_ABORT; } - if (tm.thing->type == MT_FALLINGROCK) + if (g_tm.thing->type == MT_FALLINGROCK) { // see if it went over / under - if (tm.thing->z > thing->z + thing->height) + if (g_tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tm.thing->z + tm.thing->height < thing->z) + if (g_tm.thing->z + g_tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - return K_FallingRockCollide(tm.thing, thing) ? BMIT_CONTINUE : BMIT_ABORT; + return K_FallingRockCollide(g_tm.thing, thing) ? BMIT_CONTINUE : BMIT_ABORT; } else if (thing->type == MT_FALLINGROCK) { // see if it went over / under - if (tm.thing->z > thing->z + thing->height) + if (g_tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tm.thing->z + tm.thing->height < thing->z) + if (g_tm.thing->z + g_tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - return K_FallingRockCollide(thing, tm.thing) ? BMIT_CONTINUE : BMIT_ABORT; + return K_FallingRockCollide(thing, g_tm.thing) ? BMIT_CONTINUE : BMIT_ABORT; } if (thing->type == MT_SNEAKERPANEL) { - Obj_SneakerPanelCollide(thing, tm.thing); + Obj_SneakerPanelCollide(thing, g_tm.thing); return BMIT_CONTINUE; } - else if (tm.thing->type == MT_SNEAKERPANEL) + else if (g_tm.thing->type == MT_SNEAKERPANEL) { - Obj_SneakerPanelCollide(tm.thing, thing); + Obj_SneakerPanelCollide(g_tm.thing, thing); return BMIT_CONTINUE; } // missiles can hit other things - if ((tm.thing->flags & MF_MISSILE) && !damage) // if something was already damaged, don't run this + if ((g_tm.thing->flags & MF_MISSILE) && !damage) // if something was already damaged, don't run this { - UINT8 damagetype = (tm.thing->info->mass ^ DMG_WOMBO); + UINT8 damagetype = (g_tm.thing->info->mass ^ DMG_WOMBO); // see if it went over / under - if (tm.thing->z > thing->z + thing->height) + if (g_tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tm.thing->z + tm.thing->height < thing->z) + if (g_tm.thing->z + g_tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - if (tm.thing->target && tm.thing->target->type == thing->type) + if (g_tm.thing->target && g_tm.thing->target->type == thing->type) { // Don't hit same species as originator. - if (thing == tm.thing->target) + if (thing == g_tm.thing->target) return BMIT_CONTINUE; if (thing->type != MT_PLAYER) @@ -1228,40 +1228,40 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) } // damage / explode - P_DamageMobj(thing, tm.thing, tm.thing->target, 1, damagetype); + P_DamageMobj(thing, g_tm.thing, g_tm.thing->target, 1, damagetype); // don't traverse any more return BMIT_ABORT; } - if (thing->flags & MF_PUSHABLE && (tm.thing->player || tm.thing->flags & MF_PUSHABLE) - && tm.thing->z + tm.thing->height > thing->z && tm.thing->z < thing->z + thing->height - && !(netgame && tm.thing->player && tm.thing->player->spectator)) // Push thing! + if (thing->flags & MF_PUSHABLE && (g_tm.thing->player || g_tm.thing->flags & MF_PUSHABLE) + && g_tm.thing->z + g_tm.thing->height > thing->z && g_tm.thing->z < thing->z + thing->height + && !(netgame && g_tm.thing->player && g_tm.thing->player->spectator)) // Push thing! { if (thing->flags2 & MF2_SLIDEPUSH) // Make it slide { - if (tm.thing->momy > 0 && tm.thing->momy > FixedMul(4*FRACUNIT, thing->scale) && tm.thing->momy > thing->momy) + if (g_tm.thing->momy > 0 && g_tm.thing->momy > FixedMul(4*FRACUNIT, thing->scale) && g_tm.thing->momy > thing->momy) { thing->momy += FixedMul(PUSHACCEL, thing->scale); - tm.thing->momy -= FixedMul(PUSHACCEL, thing->scale); + g_tm.thing->momy -= FixedMul(PUSHACCEL, thing->scale); } - else if (tm.thing->momy < 0 && tm.thing->momy < FixedMul(-4*FRACUNIT, thing->scale) - && tm.thing->momy < thing->momy) + else if (g_tm.thing->momy < 0 && g_tm.thing->momy < FixedMul(-4*FRACUNIT, thing->scale) + && g_tm.thing->momy < thing->momy) { thing->momy -= FixedMul(PUSHACCEL, thing->scale); - tm.thing->momy += FixedMul(PUSHACCEL, thing->scale); + g_tm.thing->momy += FixedMul(PUSHACCEL, thing->scale); } - if (tm.thing->momx > 0 && tm.thing->momx > FixedMul(4*FRACUNIT, thing->scale) - && tm.thing->momx > thing->momx) + if (g_tm.thing->momx > 0 && g_tm.thing->momx > FixedMul(4*FRACUNIT, thing->scale) + && g_tm.thing->momx > thing->momx) { thing->momx += FixedMul(PUSHACCEL, thing->scale); - tm.thing->momx -= FixedMul(PUSHACCEL, thing->scale); + g_tm.thing->momx -= FixedMul(PUSHACCEL, thing->scale); } - else if (tm.thing->momx < 0 && tm.thing->momx < FixedMul(-4*FRACUNIT, thing->scale) - && tm.thing->momx < thing->momx) + else if (g_tm.thing->momx < 0 && g_tm.thing->momx < FixedMul(-4*FRACUNIT, thing->scale) + && g_tm.thing->momx < thing->momx) { thing->momx -= FixedMul(PUSHACCEL, thing->scale); - tm.thing->momx += FixedMul(PUSHACCEL, thing->scale); + g_tm.thing->momx += FixedMul(PUSHACCEL, thing->scale); } if (thing->momx > FixedMul(thing->info->speed, thing->scale)) @@ -1275,190 +1275,190 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) } else { - if (tm.thing->momx > FixedMul(4*FRACUNIT, thing->scale)) - tm.thing->momx = FixedMul(4*FRACUNIT, thing->scale); - else if (tm.thing->momx < FixedMul(-4*FRACUNIT, thing->scale)) - tm.thing->momx = FixedMul(-4*FRACUNIT, thing->scale); - if (tm.thing->momy > FixedMul(4*FRACUNIT, thing->scale)) - tm.thing->momy = FixedMul(4*FRACUNIT, thing->scale); - else if (tm.thing->momy < FixedMul(-4*FRACUNIT, thing->scale)) - tm.thing->momy = FixedMul(-4*FRACUNIT, thing->scale); + if (g_tm.thing->momx > FixedMul(4*FRACUNIT, thing->scale)) + g_tm.thing->momx = FixedMul(4*FRACUNIT, thing->scale); + else if (g_tm.thing->momx < FixedMul(-4*FRACUNIT, thing->scale)) + g_tm.thing->momx = FixedMul(-4*FRACUNIT, thing->scale); + if (g_tm.thing->momy > FixedMul(4*FRACUNIT, thing->scale)) + g_tm.thing->momy = FixedMul(4*FRACUNIT, thing->scale); + else if (g_tm.thing->momy < FixedMul(-4*FRACUNIT, thing->scale)) + g_tm.thing->momy = FixedMul(-4*FRACUNIT, thing->scale); - thing->momx = tm.thing->momx; - thing->momy = tm.thing->momy; + thing->momx = g_tm.thing->momx; + thing->momy = g_tm.thing->momy; } if (thing->type != MT_GARGOYLE || P_IsObjectOnGround(thing)) S_StartSound(thing, thing->info->activesound); - P_SetTarget(&thing->target, tm.thing); + P_SetTarget(&thing->target, g_tm.thing); } // check for special pickup - if (thing->flags & MF_SPECIAL && tm.thing->player) + if (thing->flags & MF_SPECIAL && g_tm.thing->player) { - P_TouchSpecialThing(thing, tm.thing, true); // can remove thing + P_TouchSpecialThing(thing, g_tm.thing, true); // can remove thing return BMIT_CONTINUE; } // check again for special pickup - if (tm.thing->flags & MF_SPECIAL && thing->player) + if (g_tm.thing->flags & MF_SPECIAL && thing->player) { - P_TouchSpecialThing(tm.thing, thing, true); // can remove thing + P_TouchSpecialThing(g_tm.thing, thing, true); // can remove thing return BMIT_CONTINUE; } // Sprite Spikes! - if ((tm.thing->type == MT_SPIKE || tm.thing->type == MT_WALLSPIKE) && (tm.thing->flags & MF_SOLID)) // spike pops up + if ((g_tm.thing->type == MT_SPIKE || g_tm.thing->type == MT_WALLSPIKE) && (g_tm.thing->flags & MF_SOLID)) // spike pops up { // see if it went over / under - if (tm.thing->z > thing->z + thing->height) + if (g_tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tm.thing->z + tm.thing->height < thing->z) + if (g_tm.thing->z + g_tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath if (thing->flags & MF_SHOOTABLE) { - if (P_MobjFlip(thing) == P_MobjFlip(tm.thing)) + if (P_MobjFlip(thing) == P_MobjFlip(g_tm.thing)) { - if (P_DamageMobj(thing, tm.thing, tm.thing, 1, DMG_TUMBLE)) + if (P_DamageMobj(thing, g_tm.thing, g_tm.thing, 1, DMG_TUMBLE)) { // FIXME: None of this is correct for wall spikes, // but I don't feel like testing that right now. // Increase vertical momentum for a strong effect - thing->momz += (tm.thing->height / 2) * P_MobjFlip(tm.thing); + thing->momz += (g_tm.thing->height / 2) * P_MobjFlip(g_tm.thing); // Teleport on top of the spikes P_MoveOrigin( thing, thing->x, thing->y, - tm.thing->z + (P_MobjFlip(thing) > 0 ? tm.thing->height : -thing->height) + g_tm.thing->z + (P_MobjFlip(thing) > 0 ? g_tm.thing->height : -thing->height) ); } } else { - P_DamageMobj(thing, tm.thing, tm.thing, 1, DMG_NORMAL); + P_DamageMobj(thing, g_tm.thing, g_tm.thing, 1, DMG_NORMAL); } } return BMIT_CONTINUE; } else if ((thing->type == MT_SPIKE || thing->type == MT_WALLSPIKE) && - (thing->flags & MF_SOLID) && (tm.thing->flags & MF_SHOOTABLE)) // stationary spike + (thing->flags & MF_SOLID) && (g_tm.thing->flags & MF_SHOOTABLE)) // stationary spike { // see if it went over / under - if (tm.thing->z > thing->z + thing->height) + if (g_tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tm.thing->z + tm.thing->height < thing->z) + if (g_tm.thing->z + g_tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - if (tm.thing->player && tm.thing->player && tm.thing->player->tumbleBounces > 0) + if (g_tm.thing->player && g_tm.thing->player && g_tm.thing->player->tumbleBounces > 0) { return BMIT_CONTINUE; } - if (!P_IsObjectOnGround(tm.thing) && tm.thing->momz * P_MobjFlip(tm.thing) < 0) // fell into it + if (!P_IsObjectOnGround(g_tm.thing) && g_tm.thing->momz * P_MobjFlip(g_tm.thing) < 0) // fell into it { - P_DamageMobj(tm.thing, thing, thing, 1, DMG_TUMBLE); + P_DamageMobj(g_tm.thing, thing, thing, 1, DMG_TUMBLE); return BMIT_CONTINUE; } else { // Do not return because solidity code comes below. - P_DamageMobj(tm.thing, thing, thing, 1, DMG_NORMAL); + P_DamageMobj(g_tm.thing, thing, thing, 1, DMG_NORMAL); } } if (thing->flags & MF_PUSHABLE) { - if (tm.thing->type == MT_STEAM) - P_DoFanAndGasJet(tm.thing, thing); + if (g_tm.thing->type == MT_STEAM) + P_DoFanAndGasJet(g_tm.thing, thing); } - if (tm.thing->flags & MF_PUSHABLE) + if (g_tm.thing->flags & MF_PUSHABLE) { if (thing->type == MT_STEAM) { - P_DoFanAndGasJet(thing, tm.thing); + P_DoFanAndGasJet(thing, g_tm.thing); return BMIT_CONTINUE; } else if (thing->flags & MF_SPRING) { - if ( thing->z <= tm.thing->z + tm.thing->height - && tm.thing->z <= thing->z + thing->height) - if (P_DoSpring(thing, tm.thing)) + if ( thing->z <= g_tm.thing->z + g_tm.thing->height + && g_tm.thing->z <= thing->z + thing->height) + if (P_DoSpring(thing, g_tm.thing)) return BMIT_ABORT; return BMIT_CONTINUE; } } // thanks to sal for solidenemies dot lua - if (thing->flags & (MF_ENEMY|MF_BOSS) && tm.thing->flags & (MF_ENEMY|MF_BOSS)) + if (thing->flags & (MF_ENEMY|MF_BOSS) && g_tm.thing->flags & (MF_ENEMY|MF_BOSS)) { - if ((thing->z + thing->height >= tm.thing->z) - && (tm.thing->z + tm.thing->height >= thing->z)) + if ((thing->z + thing->height >= g_tm.thing->z) + && (g_tm.thing->z + g_tm.thing->height >= thing->z)) return BMIT_ABORT; } if (thing->player) { - if (tm.thing->type == MT_STEAM) - P_DoFanAndGasJet(tm.thing, thing); + if (g_tm.thing->type == MT_STEAM) + P_DoFanAndGasJet(g_tm.thing, thing); } - if (tm.thing->player) // Is the moving/interacting object the player? + if (g_tm.thing->player) // Is the moving/interacting object the player? { - if (!tm.thing->health) + if (!g_tm.thing->health) return BMIT_CONTINUE; if (thing->type == MT_STEAM) - P_DoFanAndGasJet(thing, tm.thing); + P_DoFanAndGasJet(thing, g_tm.thing); else if (thing->flags & MF_SPRING) { - if ( thing->z <= tm.thing->z + tm.thing->height - && tm.thing->z <= thing->z + thing->height) - if (P_DoSpring(thing, tm.thing)) + if ( thing->z <= g_tm.thing->z + g_tm.thing->height + && g_tm.thing->z <= thing->z + thing->height) + if (P_DoSpring(thing, g_tm.thing)) return BMIT_ABORT; return BMIT_CONTINUE; } else if (thing->player) // bounce when players collide { // see if it went over / under - if (tm.thing->z > thing->z + thing->height) + if (g_tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tm.thing->z + tm.thing->height < thing->z) + if (g_tm.thing->z + g_tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - if (thing->player->hyudorotimer || tm.thing->player->hyudorotimer) + if (thing->player->hyudorotimer || g_tm.thing->player->hyudorotimer) { return BMIT_CONTINUE; } - if (!P_MobjWasRemoved(thing) && !P_MobjWasRemoved(tm.thing)) + if (!P_MobjWasRemoved(thing) && !P_MobjWasRemoved(g_tm.thing)) { if (thing->player->eggmanexplode) { - K_EggmanTransfer(thing->player, tm.thing->player); - } else if (tm.thing->player->eggmanexplode) + K_EggmanTransfer(thing->player, g_tm.thing->player); + } else if (g_tm.thing->player->eggmanexplode) { - K_EggmanTransfer(tm.thing->player, thing->player); + K_EggmanTransfer(g_tm.thing->player, thing->player); } } // The bump has to happen last - if (P_IsObjectOnGround(thing) && tm.thing->momz < 0 && tm.thing->player->trickpanel) + if (P_IsObjectOnGround(thing) && g_tm.thing->momz < 0 && g_tm.thing->player->trickpanel) { - P_DamageMobj(thing, tm.thing, tm.thing, 1, DMG_TUMBLE); + P_DamageMobj(thing, g_tm.thing, g_tm.thing, 1, DMG_TUMBLE); } - else if (P_IsObjectOnGround(tm.thing) && thing->momz < 0 && thing->player->trickpanel) + else if (P_IsObjectOnGround(g_tm.thing) && thing->momz < 0 && thing->player->trickpanel) { - P_DamageMobj(tm.thing, thing, thing, 1, DMG_TUMBLE); + P_DamageMobj(g_tm.thing, thing, thing, 1, DMG_TUMBLE); } - if (K_KartBouncing(tm.thing, thing) == true) + if (K_KartBouncing(g_tm.thing, thing) == true) { - K_PvPTouchDamage(tm.thing, thing); + K_PvPTouchDamage(g_tm.thing, thing); } return BMIT_CONTINUE; @@ -1467,94 +1467,94 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) { if (!(thing->flags & MF_SPECIAL)) { - Obj_PlayerUFOCollide(thing, tm.thing); + Obj_PlayerUFOCollide(thing, g_tm.thing); return BMIT_CONTINUE; } } else if (thing->type == MT_BLUEROBRA_HEAD || thing->type == MT_BLUEROBRA_JOINT) { // see if it went over / under - if (tm.thing->z > thing->z + thing->height) + if (g_tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tm.thing->z + tm.thing->height < thing->z) + if (g_tm.thing->z + g_tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath if (!thing->health) return BMIT_CONTINUE; // dead - if (tm.thing->player->invincibilitytimer > 0 - || K_IsBigger(tm.thing, thing) == true) + if (g_tm.thing->player->invincibilitytimer > 0 + || K_IsBigger(g_tm.thing, thing) == true) { if (thing->type == MT_BLUEROBRA_JOINT) - P_KillMobj(thing->target, tm.thing, tm.thing, DMG_NORMAL); + P_KillMobj(thing->target, g_tm.thing, g_tm.thing, DMG_NORMAL); else - P_KillMobj(thing, tm.thing, tm.thing, DMG_NORMAL); + P_KillMobj(thing, g_tm.thing, g_tm.thing, DMG_NORMAL); return BMIT_CONTINUE; } else { - K_KartSolidBounce(tm.thing, thing); + K_KartSolidBounce(g_tm.thing, thing); return BMIT_CONTINUE; } } else if (thing->type == MT_KART_LEFTOVER) { // see if it went over / under - if (tm.thing->z > thing->z + thing->height) + if (g_tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tm.thing->z + tm.thing->height < thing->z) + if (g_tm.thing->z + g_tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - if (K_PlayerCanPunt(tm.thing->player)) + if (K_PlayerCanPunt(g_tm.thing->player)) { - P_DamageMobj(thing, tm.thing, tm.thing, 1, DMG_NORMAL); + P_DamageMobj(thing, g_tm.thing, g_tm.thing, 1, DMG_NORMAL); } else { - K_KartBouncing(tm.thing, thing); + K_KartBouncing(g_tm.thing, thing); } return BMIT_CONTINUE; } else if (thing->type == MT_MONITOR) { // see if it went over / under - if (tm.thing->z > thing->z + thing->height) + if (g_tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tm.thing->z + tm.thing->height < thing->z) + if (g_tm.thing->z + g_tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - P_DamageMobj(thing, tm.thing, tm.thing, 1, DMG_NORMAL); - K_KartBouncing(tm.thing, thing); + P_DamageMobj(thing, g_tm.thing, g_tm.thing, 1, DMG_NORMAL); + K_KartBouncing(g_tm.thing, thing); return BMIT_CONTINUE; } - else if ((thing->flags & MF_SHOOTABLE) && K_PlayerCanPunt(tm.thing->player)) + else if ((thing->flags & MF_SHOOTABLE) && K_PlayerCanPunt(g_tm.thing->player)) { // see if it went over / under - if (tm.thing->z > thing->z + thing->height) + if (g_tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tm.thing->z + tm.thing->height < thing->z) + if (g_tm.thing->z + g_tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - P_DamageMobj(thing, tm.thing, tm.thing, 1, DMG_NORMAL); + P_DamageMobj(thing, g_tm.thing, g_tm.thing, 1, DMG_NORMAL); return BMIT_CONTINUE; } else if (thing->flags & MF_SOLID) { // see if it went over / under - if (tm.thing->z > thing->z + thing->height) + if (g_tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tm.thing->z + tm.thing->height < thing->z) + if (g_tm.thing->z + g_tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - if (!K_PuntCollide(thing, tm.thing)) + if (!K_PuntCollide(thing, g_tm.thing)) { - K_KartSolidBounce(tm.thing, thing); + K_KartSolidBounce(g_tm.thing, thing); } return BMIT_CONTINUE; } } - switch (tm.thing->type) + switch (g_tm.thing->type) { case MT_SA2_CRATE: case MT_ICECAPBLOCK: @@ -1563,13 +1563,13 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) if (thing->flags & MF_SOLID) { fixed_t thingtop = thing->z + thing->height; - if (tm.thing->z > thing->z && thingtop > tm.floorz) + if (g_tm.thing->z > thing->z && thingtop > g_tm.floorz) { - tm.floorz = thingtop; - tm.floorrover = NULL; - tm.floorslope = NULL; - tm.floorpic = -1; - tm.floorstep = 0; + g_tm.floorz = thingtop; + g_tm.floorrover = NULL; + g_tm.floorslope = NULL; + g_tm.floorpic = -1; + g_tm.floorstep = 0; return BMIT_CONTINUE; } } @@ -1584,28 +1584,28 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) // bring back this code for a moving platform-style // object, separate it properly. #if 0 - if ((tm.thing->flags & MF_SPRING || tm.thing->type == MT_STEAM || tm.thing->type == MT_SPIKE || tm.thing->type == MT_WALLSPIKE) && (thing->player)) + if ((g_tm.thing->flags & MF_SPRING || g_tm.thing->type == MT_STEAM || g_tm.thing->type == MT_SPIKE || g_tm.thing->type == MT_WALLSPIKE) && (thing->player)) ; // springs, gas jets and springs should never be able to step up onto a player // z checking at last // Treat noclip things as non-solid! else if ((thing->flags & (MF_SOLID|MF_NOCLIP)) == MF_SOLID - && (tm.thing->flags & (MF_SOLID|MF_NOCLIP)) == MF_SOLID) + && (g_tm.thing->flags & (MF_SOLID|MF_NOCLIP)) == MF_SOLID) { fixed_t topz, tmtopz; - if (tm.thing->eflags & MFE_VERTICALFLIP) + if (g_tm.thing->eflags & MFE_VERTICALFLIP) { // pass under - tmtopz = tm.thing->z; + tmtopz = g_tm.thing->z; if (tmtopz > thing->z + thing->height) { - if (thing->z + thing->height > tm.floorz) + if (thing->z + thing->height > g_tm.floorz) { - tm.floorz = thing->z + thing->height; - tm.floorrover = NULL; - tm.floorslope = NULL; - tm.floorpic = -1; + g_tm.floorz = thing->z + thing->height; + g_tm.floorrover = NULL; + g_tm.floorslope = NULL; + g_tm.floorpic = -1; } return BMIT_CONTINUE; } @@ -1616,40 +1616,40 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) // (dont climb max. 24units while already in air) // since return false doesn't handle momentum properly, // we lie to P_TryMove() so it's always too high - if (tm.thing->player && tm.thing->z + tm.thing->height > topz - && tm.thing->z + tm.thing->height < tm.thing->ceilingz) + if (g_tm.thing->player && g_tm.thing->z + g_tm.thing->height > topz + && g_tm.thing->z + g_tm.thing->height < g_tm.thing->ceilingz) { if (thing->flags & MF_GRENADEBOUNCE && (thing->flags & MF_MONITOR || thing->info->flags & MF_MONITOR)) // Gold monitor hack... return BMIT_ABORT; - tm.floorz = tm.ceilingz = topz; // block while in air - tm.ceilingrover = NULL; - tm.ceilingslope = NULL; - tm.ceilingpic = -1; - P_SetTarget(&tm.floorthing, thing); // needed for side collision + g_tm.floorz = g_tm.ceilingz = topz; // block while in air + g_tm.ceilingrover = NULL; + g_tm.ceilingslope = NULL; + g_tm.ceilingpic = -1; + P_SetTarget(&g_tm.floorthing, thing); // needed for side collision } - else if (topz < tm.ceilingz && tm.thing->z <= thing->z+thing->height) + else if (topz < g_tm.ceilingz && g_tm.thing->z <= thing->z+thing->height) { - tm.ceilingz = topz; - tm.ceilingrover = NULL; - tm.ceilingslope = NULL; - tm.ceilingpic = -1; - P_SetTarget(&tm.floorthing, thing); // thing we may stand on + g_tm.ceilingz = topz; + g_tm.ceilingrover = NULL; + g_tm.ceilingslope = NULL; + g_tm.ceilingpic = -1; + P_SetTarget(&g_tm.floorthing, thing); // thing we may stand on } } else { // pass under - tmtopz = tm.thing->z + tm.thing->height; + tmtopz = g_tm.thing->z + g_tm.thing->height; if (tmtopz < thing->z) { - if (thing->z < tm.ceilingz) + if (thing->z < g_tm.ceilingz) { - tm.ceilingz = thing->z; - tm.ceilingrover = NULL; - tm.ceilingslope = NULL; - tm.ceilingpic = -1; + g_tm.ceilingz = thing->z; + g_tm.ceilingrover = NULL; + g_tm.ceilingslope = NULL; + g_tm.ceilingpic = -1; } return BMIT_CONTINUE; } @@ -1660,25 +1660,25 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) // (dont climb max. 24units while already in air) // since return false doesn't handle momentum properly, // we lie to P_TryMove() so it's always too high - if (tm.thing->player && tm.thing->z < topz - && tm.thing->z > tm.thing->floorz) + if (g_tm.thing->player && g_tm.thing->z < topz + && g_tm.thing->z > g_tm.thing->floorz) { if (thing->flags & MF_GRENADEBOUNCE && (thing->flags & MF_MONITOR || thing->info->flags & MF_MONITOR)) // Gold monitor hack... return BMIT_ABORT; - tm.floorz = tm.ceilingz = topz; // block while in air - tm.floorrover = NULL; - tm.floorslope = NULL; - tm.floorpic = -1; - P_SetTarget(&tm.floorthing, thing); // needed for side collision + g_tm.floorz = g_tm.ceilingz = topz; // block while in air + g_tm.floorrover = NULL; + g_tm.floorslope = NULL; + g_tm.floorpic = -1; + P_SetTarget(&g_tm.floorthing, thing); // needed for side collision } - else if (topz > tm.floorz && tm.thing->z+tm.thing->height >= thing->z) + else if (topz > g_tm.floorz && g_tm.thing->z+g_tm.thing->height >= thing->z) { - tm.floorz = topz; - tm.floorrover = NULL; - tm.floorslope = NULL; - tm.floorpic = -1; - P_SetTarget(&tm.floorthing, thing); // thing we may stand on + g_tm.floorz = topz; + g_tm.floorrover = NULL; + g_tm.floorslope = NULL; + g_tm.floorpic = -1; + P_SetTarget(&g_tm.floorthing, thing); // thing we may stand on } } } @@ -1689,7 +1689,7 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) } // PIT_CheckCameraLine -// Adjusts tm.floorz and tm.ceilingz as lines are contacted - FOR CAMERA ONLY +// Adjusts g_tm.floorz and g_tm.ceilingz as lines are contacted - FOR CAMERA ONLY static BlockItReturn_t PIT_CheckCameraLine(line_t *ld) { opening_t open = {0}; @@ -1697,13 +1697,13 @@ static BlockItReturn_t PIT_CheckCameraLine(line_t *ld) if (ld->polyobj && !(ld->polyobj->flags & POF_SOLID)) return BMIT_CONTINUE; - if (tm.bbox[BOXRIGHT] <= ld->bbox[BOXLEFT] || tm.bbox[BOXLEFT] >= ld->bbox[BOXRIGHT] - || tm.bbox[BOXTOP] <= ld->bbox[BOXBOTTOM] || tm.bbox[BOXBOTTOM] >= ld->bbox[BOXTOP]) + if (g_tm.bbox[BOXRIGHT] <= ld->bbox[BOXLEFT] || g_tm.bbox[BOXLEFT] >= ld->bbox[BOXRIGHT] + || g_tm.bbox[BOXTOP] <= ld->bbox[BOXBOTTOM] || g_tm.bbox[BOXBOTTOM] >= ld->bbox[BOXTOP]) { return BMIT_CONTINUE; } - if (P_BoxOnLineSide(tm.bbox, ld) != -1) + if (P_BoxOnLineSide(g_tm.bbox, ld) != -1) return BMIT_CONTINUE; // A line has been hit @@ -1729,22 +1729,22 @@ static BlockItReturn_t PIT_CheckCameraLine(line_t *ld) P_CameraLineOpening(ld, &open); // adjust floor / ceiling heights - if (open.ceiling < tm.ceilingz) + if (open.ceiling < g_tm.ceilingz) { - tm.ceilingz = open.ceiling; - tm.ceilingline = ld; + g_tm.ceilingz = open.ceiling; + g_tm.ceilingline = ld; } - if (open.floor > tm.floorz) + if (open.floor > g_tm.floorz) { - tm.floorz = open.floor; + g_tm.floorz = open.floor; } - if (open.highceiling > tm.drpoffceilz) - tm.drpoffceilz = open.highceiling; + if (open.highceiling > g_tm.drpoffceilz) + g_tm.drpoffceilz = open.highceiling; - if (open.lowfloor < tm.dropoffz) - tm.dropoffz = open.lowfloor; + if (open.lowfloor < g_tm.dropoffz) + g_tm.dropoffz = open.lowfloor; return BMIT_CONTINUE; } @@ -1806,45 +1806,45 @@ static boolean P_UsingStepUp(mobj_t *thing) // // PIT_CheckLine -// Adjusts tm.floorz and tm.ceilingz as lines are contacted +// Adjusts g_tm.floorz and g_tm.ceilingz as lines are contacted // static BlockItReturn_t PIT_CheckLine(line_t *ld) { - const fixed_t thingtop = tm.thing->z + tm.thing->height; + const fixed_t thingtop = g_tm.thing->z + g_tm.thing->height; opening_t open = {0}; if (ld->polyobj && !(ld->polyobj->flags & POF_SOLID)) return BMIT_CONTINUE; - if (tm.bbox[BOXRIGHT] <= ld->bbox[BOXLEFT] || tm.bbox[BOXLEFT] >= ld->bbox[BOXRIGHT] - || tm.bbox[BOXTOP] <= ld->bbox[BOXBOTTOM] || tm.bbox[BOXBOTTOM] >= ld->bbox[BOXTOP]) + if (g_tm.bbox[BOXRIGHT] <= ld->bbox[BOXLEFT] || g_tm.bbox[BOXLEFT] >= ld->bbox[BOXRIGHT] + || g_tm.bbox[BOXTOP] <= ld->bbox[BOXBOTTOM] || g_tm.bbox[BOXBOTTOM] >= ld->bbox[BOXTOP]) return BMIT_CONTINUE; - if (P_BoxOnLineSide(tm.bbox, ld) != -1) + if (P_BoxOnLineSide(g_tm.bbox, ld) != -1) return BMIT_CONTINUE; - if (tm.thing->flags & MF_PAPERCOLLISION) // Caution! Turning whilst up against a wall will get you stuck. You probably shouldn't give the player this flag. + if (g_tm.thing->flags & MF_PAPERCOLLISION) // Caution! Turning whilst up against a wall will get you stuck. You probably shouldn't give the player this flag. { fixed_t cosradius, sinradius; - cosradius = FixedMul(tm.thing->radius, FINECOSINE(tm.thing->angle>>ANGLETOFINESHIFT)); - sinradius = FixedMul(tm.thing->radius, FINESINE(tm.thing->angle>>ANGLETOFINESHIFT)); - if (P_PointOnLineSide(tm.x - cosradius, tm.y - sinradius, ld) - == P_PointOnLineSide(tm.x + cosradius, tm.y + sinradius, ld)) + cosradius = FixedMul(g_tm.thing->radius, FINECOSINE(g_tm.thing->angle>>ANGLETOFINESHIFT)); + sinradius = FixedMul(g_tm.thing->radius, FINESINE(g_tm.thing->angle>>ANGLETOFINESHIFT)); + if (P_PointOnLineSide(g_tm.x - cosradius, g_tm.y - sinradius, ld) + == P_PointOnLineSide(g_tm.x + cosradius, g_tm.y + sinradius, ld)) return BMIT_CONTINUE; // the line doesn't cross between collider's start or end #ifdef PAPER_COLLISIONCORRECTION { fixed_t dist; vertex_t result; angle_t langle; - P_ClosestPointOnLine(tm.x, tm.y, ld, &result); + P_ClosestPointOnLine(g_tm.x, g_tm.y, ld, &result); langle = R_PointToAngle2(ld->v1->x, ld->v1->y, ld->v2->x, ld->v2->y); - langle += ANGLE_90*(P_PointOnLineSide(tm.x, tm.y, ld) ? -1 : 1); - dist = abs(FixedMul(tm.thing->radius, FINECOSINE((tm.thing->angle - langle)>>ANGLETOFINESHIFT))); + langle += ANGLE_90*(P_PointOnLineSide(g_tm.x, g_tm.y, ld) ? -1 : 1); + dist = abs(FixedMul(g_tm.thing->radius, FINECOSINE((g_tm.thing->angle - langle)>>ANGLETOFINESHIFT))); cosradius = FixedMul(dist, FINECOSINE(langle>>ANGLETOFINESHIFT)); sinradius = FixedMul(dist, FINESINE(langle>>ANGLETOFINESHIFT)); - tm.thing->flags |= MF_NOCLIP; - P_MoveOrigin(tm.thing, result.x + cosradius - tm.thing->momx, result.y + sinradius - tm.thing->momy, tm.thing->z); - tm.thing->flags &= ~MF_NOCLIP; + g_tm.thing->flags |= MF_NOCLIP; + P_MoveOrigin(g_tm.thing, result.x + cosradius - g_tm.thing->momx, result.y + sinradius - g_tm.thing->momy, g_tm.thing->z); + g_tm.thing->flags &= ~MF_NOCLIP; } #endif } @@ -1863,16 +1863,16 @@ static BlockItReturn_t PIT_CheckLine(line_t *ld) // this line is out of the if so upper and lower textures can be hit by a splat { - UINT8 shouldCollide = LUA_HookMobjLineCollide(tm.thing, ld); // checks hook for thing's type - if (P_MobjWasRemoved(tm.thing)) + UINT8 shouldCollide = LUA_HookMobjLineCollide(g_tm.thing, ld); // checks hook for thing's type + if (P_MobjWasRemoved(g_tm.thing)) return BMIT_CONTINUE; // one of them was removed??? if (shouldCollide == 1) { - if (tm.sweep) + if (g_tm.sweep) { P_TestLine(ld); } - tm.blocking = true; // force collide + g_tm.blocking = true; // force collide return BMIT_CONTINUE; } else if (shouldCollide == 2) @@ -1881,50 +1881,50 @@ static BlockItReturn_t PIT_CheckLine(line_t *ld) if (!ld->backsector) // one sided line { - if (P_PointOnLineSide(tm.thing->x, tm.thing->y, ld)) + if (P_PointOnLineSide(g_tm.thing->x, g_tm.thing->y, ld)) return BMIT_CONTINUE; // don't hit the back side - if (tm.sweep) + if (g_tm.sweep) { P_TestLine(ld); } - tm.blocking = true; + g_tm.blocking = true; return BMIT_CONTINUE; } - if (P_IsLineBlocking(ld, tm.thing)) + if (P_IsLineBlocking(ld, g_tm.thing)) { - if (tm.sweep) + if (g_tm.sweep) { P_TestLine(ld); } - tm.blocking = true; + g_tm.blocking = true; return BMIT_CONTINUE; } // set openrange, opentop, openbottom - P_LineOpening(ld, tm.thing, &open); + P_LineOpening(ld, g_tm.thing, &open); - if (tm.sweep && P_UsingStepUp(tm.thing)) + if (g_tm.sweep && P_UsingStepUp(g_tm.thing)) { // copied from P_TryMove // TODO: refactor this into one place - if (open.range < tm.thing->height) + if (open.range < g_tm.thing->height) { P_TestLine(ld); } - else if (tm.maxstep > 0) + else if (g_tm.maxstep > 0) { - if (tm.thing->z < open.floor) + if (g_tm.thing->z < open.floor) { - if (open.floorstep > tm.maxstep) + if (open.floorstep > g_tm.maxstep) { P_TestLine(ld); } } - else if (open.ceiling < tm.thing->z + tm.thing->height) + else if (open.ceiling < g_tm.thing->z + g_tm.thing->height) { - if (open.ceilingstep > tm.maxstep) + if (open.ceilingstep > g_tm.maxstep) { P_TestLine(ld); } @@ -1933,38 +1933,38 @@ static BlockItReturn_t PIT_CheckLine(line_t *ld) } // adjust floor / ceiling heights - if (open.ceiling < tm.ceilingz) + if (open.ceiling < g_tm.ceilingz) { - tm.ceilingz = open.ceiling; - tm.ceilingline = ld; - tm.ceilingrover = open.ceilingrover; - tm.ceilingslope = open.ceilingslope; - tm.ceilingpic = open.ceilingpic; - tm.ceilingstep = open.ceilingstep; - if (thingtop == tm.thing->ceilingz) + g_tm.ceilingz = open.ceiling; + g_tm.ceilingline = ld; + g_tm.ceilingrover = open.ceilingrover; + g_tm.ceilingslope = open.ceilingslope; + g_tm.ceilingpic = open.ceilingpic; + g_tm.ceilingstep = open.ceilingstep; + if (thingtop == g_tm.thing->ceilingz) { - tm.thing->ceilingdrop = open.ceilingdrop; + g_tm.thing->ceilingdrop = open.ceilingdrop; } } - if (open.floor > tm.floorz) + if (open.floor > g_tm.floorz) { - tm.floorz = open.floor; - tm.floorrover = open.floorrover; - tm.floorslope = open.floorslope; - tm.floorpic = open.floorpic; - tm.floorstep = open.floorstep; - if (tm.thing->z == tm.thing->floorz) + g_tm.floorz = open.floor; + g_tm.floorrover = open.floorrover; + g_tm.floorslope = open.floorslope; + g_tm.floorpic = open.floorpic; + g_tm.floorstep = open.floorstep; + if (g_tm.thing->z == g_tm.thing->floorz) { - tm.thing->floordrop = open.floordrop; + g_tm.thing->floordrop = open.floordrop; } } - if (open.highceiling > tm.drpoffceilz) - tm.drpoffceilz = open.highceiling; + if (open.highceiling > g_tm.drpoffceilz) + g_tm.drpoffceilz = open.highceiling; - if (open.lowfloor < tm.dropoffz) - tm.dropoffz = open.lowfloor; + if (open.lowfloor < g_tm.dropoffz) + g_tm.dropoffz = open.lowfloor; // we've crossed the line if (P_SpecialIsLinedefCrossType(ld)) @@ -1975,14 +1975,14 @@ static BlockItReturn_t PIT_CheckLine(line_t *ld) { fixed_t textop, texbottom; - P_GetMidtextureTopBottom(ld, tm.x, tm.y, + P_GetMidtextureTopBottom(ld, g_tm.x, g_tm.y, &textop, &texbottom); /* The effect handling is done later but it won't know the height values anymore. So don't even add this line to the list unless this thing clips the tripwire's midtexture. */ - if (tm.thing->z <= textop && thingtop >= texbottom) + if (g_tm.thing->z <= textop && thingtop >= texbottom) add_spechit(ld); } @@ -2009,20 +2009,20 @@ static BlockItReturn_t PIT_CheckLine(line_t *ld) // // out: // newsubsec -// tm.floorz -// tm.ceilingz -// tm.dropoffz -// tm.drpoffceilz +// g_tm.floorz +// g_tm.ceilingz +// g_tm.dropoffz +// g_tm.drpoffceilz // the lowest point contacted // (monsters won't move to a dropoff) // speciallines[] // numspeciallines // -// tm.floorz -// the nearest floor or thing's top under tm.thing -// tm.ceilingz -// the nearest ceiling or thing's bottom over tm.thing +// g_tm.floorz +// the nearest floor or thing's top under g_tm.thing +// g_tm.ceilingz +// the nearest ceiling or thing's bottom over g_tm.thing // boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y, TryMoveResult_t *result) { @@ -2039,36 +2039,36 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y, TryMoveResult_t *re I_Error("Previously-removed Thing of type %u crashes P_CheckPosition!", thing->type); #endif - P_SetTarget(&tm.thing, thing); - tm.flags = thing->flags; + P_SetTarget(&g_tm.thing, thing); + g_tm.flags = thing->flags; - tm.x = x; - tm.y = y; + g_tm.x = x; + g_tm.y = y; - tm.bbox[BOXTOP] = y + tm.thing->radius; - tm.bbox[BOXBOTTOM] = y - tm.thing->radius; - tm.bbox[BOXRIGHT] = x + tm.thing->radius; - tm.bbox[BOXLEFT] = x - tm.thing->radius; + g_tm.bbox[BOXTOP] = y + g_tm.thing->radius; + g_tm.bbox[BOXBOTTOM] = y - g_tm.thing->radius; + g_tm.bbox[BOXRIGHT] = x + g_tm.thing->radius; + g_tm.bbox[BOXLEFT] = x - g_tm.thing->radius; newsubsec = R_PointInSubsector(x, y); - tm.ceilingline = NULL; - tm.blocking = false; + g_tm.ceilingline = NULL; + g_tm.blocking = false; // The base floor / ceiling is from the subsector // that contains the point. // Any contacted lines the step closer together // will adjust them. - tm.floorz = tm.dropoffz = P_GetFloorZ(thing, newsubsec->sector, x, y, NULL); //newsubsec->sector->floorheight; - tm.ceilingz = P_GetCeilingZ(thing, newsubsec->sector, x, y, NULL); //newsubsec->sector->ceilingheight; - tm.floorrover = NULL; - tm.ceilingrover = NULL; - tm.floorslope = newsubsec->sector->f_slope; - tm.ceilingslope = newsubsec->sector->c_slope; - tm.floorpic = newsubsec->sector->floorpic; - tm.ceilingpic = newsubsec->sector->ceilingpic; + g_tm.floorz = g_tm.dropoffz = P_GetFloorZ(thing, newsubsec->sector, x, y, NULL); //newsubsec->sector->floorheight; + g_tm.ceilingz = P_GetCeilingZ(thing, newsubsec->sector, x, y, NULL); //newsubsec->sector->ceilingheight; + g_tm.floorrover = NULL; + g_tm.ceilingrover = NULL; + g_tm.floorslope = newsubsec->sector->f_slope; + g_tm.ceilingslope = newsubsec->sector->c_slope; + g_tm.floorpic = newsubsec->sector->floorpic; + g_tm.ceilingpic = newsubsec->sector->ceilingpic; - tm.floorstep = 0; - tm.ceilingstep = 0; + g_tm.floorstep = 0; + g_tm.ceilingstep = 0; if (thingtop < thing->ceilingz) { @@ -2080,7 +2080,7 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y, TryMoveResult_t *re thing->floordrop = 0; } - // Check list of fake floors and see if tm.floorz/tm.ceilingz need to be altered. + // Check list of fake floors and see if g_tm.floorz/g_tm.ceilingz need to be altered. if (newsubsec->sector->ffloors) { ffloor_t *rover; @@ -2115,22 +2115,22 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y, TryMoveResult_t *re // Land on the top or the bottom, depending on gravity flip. if (!(thing->eflags & MFE_VERTICALFLIP) && thing->z >= topheight - sinklevel && thing->momz <= 0) { - if (tm.floorz < topheight - sinklevel) + if (g_tm.floorz < topheight - sinklevel) { - tm.floorz = topheight - sinklevel; - tm.floorrover = rover; - tm.floorslope = *rover->t_slope; - tm.floorpic = *rover->toppic; + g_tm.floorz = topheight - sinklevel; + g_tm.floorrover = rover; + g_tm.floorslope = *rover->t_slope; + g_tm.floorpic = *rover->toppic; } } else if (thing->eflags & MFE_VERTICALFLIP && thingtop <= bottomheight + sinklevel && thing->momz >= 0) { - if (tm.ceilingz > bottomheight + sinklevel) + if (g_tm.ceilingz > bottomheight + sinklevel) { - tm.ceilingz = bottomheight + sinklevel; - tm.ceilingrover = rover; - tm.ceilingslope = *rover->b_slope; - tm.ceilingpic = *rover->bottompic; + g_tm.ceilingz = bottomheight + sinklevel; + g_tm.ceilingrover = rover; + g_tm.ceilingslope = *rover->b_slope; + g_tm.ceilingpic = *rover->bottompic; } } } @@ -2148,12 +2148,12 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y, TryMoveResult_t *re { if (thing->z < topheight && bottomheight < thingtop) { - if (tm.floorz < thing->z) + if (g_tm.floorz < thing->z) { - tm.floorz = thing->z; - tm.floorrover = rover; - tm.floorslope = NULL; - tm.floorpic = *rover->toppic; + g_tm.floorz = thing->z; + g_tm.floorrover = rover; + g_tm.floorslope = NULL; + g_tm.floorpic = *rover->toppic; } } // Quicksand blocks never change heights otherwise. @@ -2165,22 +2165,22 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y, TryMoveResult_t *re delta2 = thingtop - (bottomheight + ((topheight - bottomheight)/2)); - if (topheight > tm.floorz && abs(delta1) < abs(delta2) + if (topheight > g_tm.floorz && abs(delta1) < abs(delta2) && !(rover->fofflags & FOF_REVERSEPLATFORM)) { - tm.floorz = tm.dropoffz = topheight; - tm.floorrover = rover; - tm.floorslope = *rover->t_slope; - tm.floorpic = *rover->toppic; + g_tm.floorz = g_tm.dropoffz = topheight; + g_tm.floorrover = rover; + g_tm.floorslope = *rover->t_slope; + g_tm.floorpic = *rover->toppic; } - if (bottomheight < tm.ceilingz && abs(delta1) >= abs(delta2) + if (bottomheight < g_tm.ceilingz && abs(delta1) >= abs(delta2) && !(rover->fofflags & FOF_PLATFORM)) { - tm.ceilingz = tm.drpoffceilz = bottomheight; - tm.ceilingrover = rover; - tm.ceilingslope = *rover->b_slope; - tm.ceilingpic = *rover->bottompic; + g_tm.ceilingz = g_tm.drpoffceilz = bottomheight; + g_tm.ceilingrover = rover; + g_tm.ceilingslope = *rover->b_slope; + g_tm.ceilingpic = *rover->bottompic; } } } @@ -2190,14 +2190,14 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y, TryMoveResult_t *re // based on their origin point, and can overlap // into adjacent blocks by up to MAXRADIUS units. - xl = (unsigned)(tm.bbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT; - xh = (unsigned)(tm.bbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT; - yl = (unsigned)(tm.bbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT; - yh = (unsigned)(tm.bbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT; + xl = (unsigned)(g_tm.bbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT; + xh = (unsigned)(g_tm.bbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT; + yl = (unsigned)(g_tm.bbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT; + yh = (unsigned)(g_tm.bbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT; BMBOUNDFIX(xl, xh, yl, yh); - // Check polyobjects and see if tm.floorz/tm.ceilingz need to be altered + // Check polyobjects and see if g_tm.floorz/g_tm.ceilingz need to be altered { validcount++; @@ -2228,7 +2228,7 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y, TryMoveResult_t *re po->validcount = validcount; - if (!P_BBoxInsidePolyobj(po, tm.bbox) + if (!P_BBoxInsidePolyobj(po, g_tm.bbox) || !(po->flags & POF_SOLID)) { plink = (polymaplink_t *)(plink->link.next); @@ -2252,20 +2252,20 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y, TryMoveResult_t *re delta1 = thing->z - (polybottom + ((polytop - polybottom)/2)); delta2 = thingtop - (polybottom + ((polytop - polybottom)/2)); - if (polytop > tm.floorz && abs(delta1) < abs(delta2)) + if (polytop > g_tm.floorz && abs(delta1) < abs(delta2)) { - tm.floorz = tm.dropoffz = polytop; - tm.floorslope = NULL; - tm.floorrover = NULL; - tm.floorpic = polysec->ceilingpic; + g_tm.floorz = g_tm.dropoffz = polytop; + g_tm.floorslope = NULL; + g_tm.floorrover = NULL; + g_tm.floorpic = polysec->ceilingpic; } - if (polybottom < tm.ceilingz && abs(delta1) >= abs(delta2)) + if (polybottom < g_tm.ceilingz && abs(delta1) >= abs(delta2)) { - tm.ceilingz = tm.drpoffceilz = polybottom; - tm.ceilingslope = NULL; - tm.ceilingrover = NULL; - tm.ceilingpic = polysec->floorpic; + g_tm.ceilingz = g_tm.drpoffceilz = polybottom; + g_tm.ceilingslope = NULL; + g_tm.ceilingrover = NULL; + g_tm.ceilingpic = polysec->floorpic; } } plink = (polymaplink_t *)(plink->link.next); @@ -2274,9 +2274,9 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y, TryMoveResult_t *re } } - // tm.floorthing is set when tm.floorz comes from a thing's top - P_SetTarget(&tm.floorthing, NULL); - P_SetTarget(&tm.hitthing, NULL); + // g_tm.floorthing is set when g_tm.floorz comes from a thing's top + P_SetTarget(&g_tm.floorthing, NULL); + P_SetTarget(&g_tm.hitthing, NULL); validcount++; @@ -2299,10 +2299,10 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y, TryMoveResult_t *re } else { - P_SetTarget(&tm.hitthing, tm.floorthing); + P_SetTarget(&g_tm.hitthing, g_tm.floorthing); } - if (P_MobjWasRemoved(tm.thing)) + if (P_MobjWasRemoved(g_tm.thing)) { return false; } @@ -2310,7 +2310,7 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y, TryMoveResult_t *re } } - if (tm.flags & MF_NOCLIP) + if (g_tm.flags & MF_NOCLIP) { // Sal 12/19/2022 -- PIT_CheckThing code will still run // with MF_NOCLIP enabled, but they won't be blocked @@ -2333,7 +2333,7 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y, TryMoveResult_t *re } } - if (tm.blocking) + if (g_tm.blocking) { blockval = false; } @@ -2341,14 +2341,14 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y, TryMoveResult_t *re if (result != NULL) { result->line = NULL; - result->mo = tm.hitthing; + result->mo = g_tm.hitthing; } else { P_ClearTestLines(); } - tm.sweep = false; + g_tm.sweep = false; return blockval; } @@ -2388,23 +2388,23 @@ boolean P_CheckCameraPosition(fixed_t x, fixed_t y, camera_t *thiscam) INT32 xl, xh, yl, yh, bx, by; subsector_t *newsubsec; - tm.x = x; - tm.y = y; + g_tm.x = x; + g_tm.y = y; - tm.bbox[BOXTOP] = y + thiscam->radius; - tm.bbox[BOXBOTTOM] = y - thiscam->radius; - tm.bbox[BOXRIGHT] = x + thiscam->radius; - tm.bbox[BOXLEFT] = x - thiscam->radius; + g_tm.bbox[BOXTOP] = y + thiscam->radius; + g_tm.bbox[BOXBOTTOM] = y - thiscam->radius; + g_tm.bbox[BOXRIGHT] = x + thiscam->radius; + g_tm.bbox[BOXLEFT] = x - thiscam->radius; newsubsec = R_PointInSubsector(x, y); - tm.ceilingline = NULL; + g_tm.ceilingline = NULL; mapcampointer = thiscam; if (newsubsec->sector->flags & MSF_NOCLIPCAMERA) { // Camera noclip on entire sector. - tm.floorz = tm.dropoffz = thiscam->z; - tm.ceilingz = tm.drpoffceilz = thiscam->z + thiscam->height; + g_tm.floorz = g_tm.dropoffz = thiscam->z; + g_tm.ceilingz = g_tm.drpoffceilz = thiscam->z + thiscam->height; return true; } @@ -2412,26 +2412,26 @@ boolean P_CheckCameraPosition(fixed_t x, fixed_t y, camera_t *thiscam) // that contains the point. // Any contacted lines the step closer together // will adjust them. - tm.floorz = tm.dropoffz = P_CameraGetFloorZ(thiscam, newsubsec->sector, x, y, NULL); + g_tm.floorz = g_tm.dropoffz = P_CameraGetFloorZ(thiscam, newsubsec->sector, x, y, NULL); - tm.ceilingz = P_CameraGetCeilingZ(thiscam, newsubsec->sector, x, y, NULL); + g_tm.ceilingz = P_CameraGetCeilingZ(thiscam, newsubsec->sector, x, y, NULL); // Cameras use the heightsec's heights rather then the actual sector heights. // If you can see through it, why not move the camera through it too? if (newsubsec->sector->heightsec >= 0) { - tm.floorz = tm.dropoffz = sectors[newsubsec->sector->heightsec].floorheight; - tm.ceilingz = tm.drpoffceilz = sectors[newsubsec->sector->heightsec].ceilingheight; + g_tm.floorz = g_tm.dropoffz = sectors[newsubsec->sector->heightsec].floorheight; + g_tm.ceilingz = g_tm.drpoffceilz = sectors[newsubsec->sector->heightsec].ceilingheight; } // Use preset camera clipping heights if set with Sector Special Parameters whose control sector has Camera Intangible special -Red if (newsubsec->sector->camsec >= 0) { - tm.floorz = tm.dropoffz = sectors[newsubsec->sector->camsec].floorheight; - tm.ceilingz = tm.drpoffceilz = sectors[newsubsec->sector->camsec].ceilingheight; + g_tm.floorz = g_tm.dropoffz = sectors[newsubsec->sector->camsec].floorheight; + g_tm.ceilingz = g_tm.drpoffceilz = sectors[newsubsec->sector->camsec].ceilingheight; } - // Check list of fake floors and see if tm.floorz/tm.ceilingz need to be altered. + // Check list of fake floors and see if g_tm.floorz/g_tm.ceilingz need to be altered. if (newsubsec->sector->ffloors) { ffloor_t *rover; @@ -2451,13 +2451,13 @@ boolean P_CheckCameraPosition(fixed_t x, fixed_t y, camera_t *thiscam) + ((topheight - bottomheight)/2)); delta2 = thingtop - (bottomheight + ((topheight - bottomheight)/2)); - if (topheight > tm.floorz && abs(delta1) < abs(delta2)) + if (topheight > g_tm.floorz && abs(delta1) < abs(delta2)) { - tm.floorz = tm.dropoffz = topheight; + g_tm.floorz = g_tm.dropoffz = topheight; } - if (bottomheight < tm.ceilingz && abs(delta1) >= abs(delta2)) + if (bottomheight < g_tm.ceilingz && abs(delta1) >= abs(delta2)) { - tm.ceilingz = tm.drpoffceilz = bottomheight; + g_tm.ceilingz = g_tm.drpoffceilz = bottomheight; } } } @@ -2467,14 +2467,14 @@ boolean P_CheckCameraPosition(fixed_t x, fixed_t y, camera_t *thiscam) // based on their origin point, and can overlap // into adjacent blocks by up to MAXRADIUS units. - xl = (unsigned)(tm.bbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT; - xh = (unsigned)(tm.bbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT; - yl = (unsigned)(tm.bbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT; - yh = (unsigned)(tm.bbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT; + xl = (unsigned)(g_tm.bbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT; + xh = (unsigned)(g_tm.bbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT; + yl = (unsigned)(g_tm.bbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT; + yh = (unsigned)(g_tm.bbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT; BMBOUNDFIX(xl, xh, yl, yh); - // Check polyobjects and see if tm.floorz/tm.ceilingz need to be altered + // Check polyobjects and see if g_tm.floorz/g_tm.ceilingz need to be altered { validcount++; @@ -2534,11 +2534,11 @@ boolean P_CheckCameraPosition(fixed_t x, fixed_t y, camera_t *thiscam) delta1 = thiscam->z - (polybottom + ((polytop - polybottom)/2)); delta2 = thingtop - (polybottom + ((polytop - polybottom)/2)); - if (polytop > tm.floorz && abs(delta1) < abs(delta2)) - tm.floorz = tm.dropoffz = polytop; + if (polytop > g_tm.floorz && abs(delta1) < abs(delta2)) + g_tm.floorz = g_tm.dropoffz = polytop; - if (polybottom < tm.ceilingz && abs(delta1) >= abs(delta2)) - tm.ceilingz = tm.drpoffceilz = polybottom; + if (polybottom < g_tm.ceilingz && abs(delta1) >= abs(delta2)) + g_tm.ceilingz = g_tm.drpoffceilz = polybottom; } plink = (polymaplink_t *)(plink->link.next); } @@ -2571,7 +2571,7 @@ boolean P_TryCameraMove(fixed_t x, fixed_t y, camera_t *thiscam) UINT8 i; - tm.floatok = false; + g_tm.floatok = false; for (i = 0; i <= r_splitscreen; i++) { @@ -2595,7 +2595,7 @@ boolean P_TryCameraMove(fixed_t x, fixed_t y, camera_t *thiscam) if (!(players[displayplayers[i]].pflags & PF_NOCONTEST)) // Time Over should not clip through walls { - tm.floatok = true; + g_tm.floatok = true; thiscam->floorz = thiscam->z; thiscam->ceilingz = thiscam->z + thiscam->height; thiscam->x = x; @@ -2621,18 +2621,18 @@ boolean P_TryCameraMove(fixed_t x, fixed_t y, camera_t *thiscam) if (!P_CheckCameraPosition(tryx, tryy, thiscam)) return false; // solid wall or thing - if (tm.ceilingz - tm.floorz < thiscam->height) + if (g_tm.ceilingz - g_tm.floorz < thiscam->height) return false; // doesn't fit - tm.floatok = true; + g_tm.floatok = true; - if (tm.ceilingz - thiscam->z < thiscam->height) + if (g_tm.ceilingz - thiscam->z < thiscam->height) { - if (s == thiscam->subsector && tm.ceilingz >= thiscam->z) + if (s == thiscam->subsector && g_tm.ceilingz >= thiscam->z) { - tm.floatok = true; - thiscam->floorz = tm.floorz; - thiscam->ceilingz = tm.floorz + thiscam->height; + g_tm.floatok = true; + thiscam->floorz = g_tm.floorz; + thiscam->ceilingz = g_tm.floorz + thiscam->height; thiscam->x = x; thiscam->y = y; thiscam->subsector = s; @@ -2642,21 +2642,21 @@ boolean P_TryCameraMove(fixed_t x, fixed_t y, camera_t *thiscam) return false; // mobj must lower itself to fit } - if ((tm.floorz - thiscam->z > MAXCAMERASTEPMOVE)) + if ((g_tm.floorz - thiscam->z > MAXCAMERASTEPMOVE)) return false; // too big a step up } while(tryx != x || tryy != y); } else { - tm.floorz = P_CameraGetFloorZ(thiscam, thiscam->subsector->sector, x, y, NULL); - tm.ceilingz = P_CameraGetCeilingZ(thiscam, thiscam->subsector->sector, x, y, NULL); + g_tm.floorz = P_CameraGetFloorZ(thiscam, thiscam->subsector->sector, x, y, NULL); + g_tm.ceilingz = P_CameraGetCeilingZ(thiscam, thiscam->subsector->sector, x, y, NULL); } // the move is ok, // so link the thing into its new position - thiscam->floorz = tm.floorz; - thiscam->ceilingz = tm.ceilingz; + thiscam->floorz = g_tm.floorz; + thiscam->ceilingz = g_tm.ceilingz; thiscam->x = x; thiscam->y = y; thiscam->subsector = s; @@ -2708,7 +2708,7 @@ BlockItReturn_t PIT_PushableMoved(mobj_t *thing) // These are all non-static map variables that are changed for each and every single mobj // See, changing player's momx/y would possibly trigger stuff as if the player were running somehow, so this must be done to keep the player standing // All this so players can ride gargoyles! - tm_t oldtm = tm; + tm_t oldtm = g_tm; // Move the player P_TryMove(thing, thing->x + stand->momx, thing->y + stand->momy, true, NULL); @@ -2785,7 +2785,7 @@ increment_move fixed_t radius = thing->radius; fixed_t thingtop; fixed_t stairjank = 0; - tm.floatok = false; + g_tm.floatok = false; // reset this to 0 at the start of each trymove call as it's only used here numspechitint = 0U; @@ -2825,12 +2825,12 @@ increment_move if (P_UsingStepUp(thing)) { - tm.maxstep = P_GetThingStepUp(thing, tryx, tryy); + g_tm.maxstep = P_GetThingStepUp(thing, tryx, tryy); } if (result) { - tm.sweep = true; + g_tm.sweep = true; } boolean move_ok = P_CheckPosition(thing, tryx, tryy, result); @@ -2858,17 +2858,17 @@ increment_move // All things are affected by their scale. fixed_t maxstep = P_GetThingStepUp(thing, tryx, tryy); - if (tm.ceilingz - tm.floorz < thing->height) + if (g_tm.ceilingz - g_tm.floorz < thing->height) { - if (tm.floorthing != NULL) + if (g_tm.floorthing != NULL) { - P_SetTarget(&tm.hitthing, tm.floorthing); + P_SetTarget(&g_tm.hitthing, g_tm.floorthing); } return false; // doesn't fit } - tm.floatok = true; + g_tm.floatok = true; if (maxstep > 0) { @@ -2878,15 +2878,15 @@ increment_move thingtop = thing->z + thing->height; // Step up - if (thing->z < tm.floorz) + if (thing->z < g_tm.floorz) { - if (tm.floorstep <= maxstep) + if (g_tm.floorstep <= maxstep) { if (!flipped) - stairjank = tm.floorstep; + stairjank = g_tm.floorstep; - thing->z = thing->floorz = tm.floorz; - thing->floorrover = tm.floorrover; + thing->z = thing->floorz = g_tm.floorz; + thing->floorrover = g_tm.floorrover; thing->eflags |= MFE_JUSTSTEPPEDDOWN; } else @@ -2894,15 +2894,15 @@ increment_move return false; // mobj must raise itself to fit } } - else if (tm.ceilingz < thingtop) + else if (g_tm.ceilingz < thingtop) { - if (tm.ceilingstep <= maxstep) + if (g_tm.ceilingstep <= maxstep) { if (flipped) - stairjank = tm.ceilingstep; + stairjank = g_tm.ceilingstep; - thing->z = ( thing->ceilingz = tm.ceilingz ) - thing->height; - thing->ceilingrover = tm.ceilingrover; + thing->z = ( thing->ceilingz = g_tm.ceilingz ) - thing->height; + thing->ceilingrover = g_tm.ceilingrover; thing->eflags |= MFE_JUSTSTEPPEDDOWN; } else @@ -2917,37 +2917,37 @@ increment_move // If the floor difference is MAXSTEPMOVE or less, and the sector isn't Section1:14, ALWAYS // step down! Formerly required a Section1:13 sector for the full MAXSTEPMOVE, but no more. - if (thingtop == thing->ceilingz && tm.ceilingz > thingtop && tm.ceilingz - thingtop <= maxstep) + if (thingtop == thing->ceilingz && g_tm.ceilingz > thingtop && g_tm.ceilingz - thingtop <= maxstep) { if (flipped) - stairjank = (tm.ceilingz - thingtop); + stairjank = (g_tm.ceilingz - thingtop); - thing->z = (thing->ceilingz = tm.ceilingz) - thing->height; - thing->ceilingrover = tm.ceilingrover; + thing->z = (thing->ceilingz = g_tm.ceilingz) - thing->height; + thing->ceilingrover = g_tm.ceilingrover; thing->eflags |= MFE_JUSTSTEPPEDDOWN; thing->ceilingdrop = 0; } - else if (thing->z == thing->floorz && tm.floorz < thing->z && thing->z - tm.floorz <= maxstep) + else if (thing->z == thing->floorz && g_tm.floorz < thing->z && thing->z - g_tm.floorz <= maxstep) { if (!flipped) - stairjank = (thing->z - tm.floorz); + stairjank = (thing->z - g_tm.floorz); - thing->z = thing->floorz = tm.floorz; - thing->floorrover = tm.floorrover; + thing->z = thing->floorz = g_tm.floorz; + thing->floorrover = g_tm.floorrover; thing->eflags |= MFE_JUSTSTEPPEDDOWN; thing->floordrop = 0; } } } - if (!allowdropoff && !(thing->flags & MF_FLOAT) && !tm.floorthing) + if (!allowdropoff && !(thing->flags & MF_FLOAT) && !g_tm.floorthing) { if (thing->eflags & MFE_VERTICALFLIP) { - if (tm.drpoffceilz - tm.ceilingz > maxstep) + if (g_tm.drpoffceilz - g_tm.ceilingz > maxstep) return false; } - else if (tm.floorz - tm.dropoffz > maxstep) + else if (g_tm.floorz - g_tm.dropoffz > maxstep) return false; // don't stand over a dropoff } } @@ -3027,21 +3027,21 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff, Try // Link the thing into its new position P_UnsetThingPosition(thing); - thing->floorz = tm.floorz; - thing->ceilingz = tm.ceilingz; - thing->floorrover = tm.floorrover; - thing->ceilingrover = tm.ceilingrover; + thing->floorz = g_tm.floorz; + thing->ceilingz = g_tm.ceilingz; + thing->floorrover = g_tm.floorrover; + thing->ceilingrover = g_tm.ceilingrover; if (!(thing->flags & MF_NOCLIPHEIGHT)) { // Assign thing's standingslope if needed - if (thing->z <= tm.floorz && !(thing->eflags & MFE_VERTICALFLIP)) + if (thing->z <= g_tm.floorz && !(thing->eflags & MFE_VERTICALFLIP)) { - K_UpdateMobjTerrain(thing, tm.floorpic); + K_UpdateMobjTerrain(thing, g_tm.floorpic); - if (!startingonground && tm.floorslope) + if (!startingonground && g_tm.floorslope) { - P_HandleSlopeLanding(thing, tm.floorslope); + P_HandleSlopeLanding(thing, g_tm.floorslope); } if (thing->momz <= 0) @@ -3049,7 +3049,7 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff, Try angle_t oldPitch = thing->pitch; angle_t oldRoll = thing->roll; - thing->standingslope = tm.floorslope; + thing->standingslope = g_tm.floorslope; P_SetPitchRollFromSlope(thing, thing->standingslope); if (thing->player) @@ -3058,13 +3058,13 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff, Try } } } - else if (thing->z+thing->height >= tm.ceilingz && (thing->eflags & MFE_VERTICALFLIP)) + else if (thing->z+thing->height >= g_tm.ceilingz && (thing->eflags & MFE_VERTICALFLIP)) { - K_UpdateMobjTerrain(thing, tm.ceilingpic); + K_UpdateMobjTerrain(thing, g_tm.ceilingpic); - if (!startingonground && tm.ceilingslope) + if (!startingonground && g_tm.ceilingslope) { - P_HandleSlopeLanding(thing, tm.ceilingslope); + P_HandleSlopeLanding(thing, g_tm.ceilingslope); } if (thing->momz >= 0) @@ -3072,7 +3072,7 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff, Try angle_t oldPitch = thing->pitch; angle_t oldRoll = thing->roll; - thing->standingslope = tm.ceilingslope; + thing->standingslope = g_tm.ceilingslope; P_SetPitchRollFromSlope(thing, thing->standingslope); if (thing->player) @@ -3121,7 +3121,7 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff, Try thing->x = x; thing->y = y; - if (tm.floorthing) + if (g_tm.floorthing) thing->eflags &= ~MFE_ONGROUND; // not on real floor else thing->eflags |= MFE_ONGROUND; @@ -3195,13 +3195,13 @@ boolean P_SceneryTryMove(mobj_t *thing, fixed_t x, fixed_t y, TryMoveResult_t *r { const fixed_t maxstep = P_BaseStepUp(); - if (tm.ceilingz - tm.floorz < thing->height) + if (g_tm.ceilingz - g_tm.floorz < thing->height) return false; // doesn't fit - if (tm.ceilingz - thing->z < thing->height) + if (g_tm.ceilingz - thing->z < thing->height) return false; // mobj must lower itself to fit - if (tm.floorz - thing->z > maxstep) + if (g_tm.floorz - thing->z > maxstep) return false; // too big a step up } } while(tryx != x || tryy != y); @@ -3210,14 +3210,14 @@ boolean P_SceneryTryMove(mobj_t *thing, fixed_t x, fixed_t y, TryMoveResult_t *r // so link the thing into its new position P_UnsetThingPosition(thing); - thing->floorz = tm.floorz; - thing->ceilingz = tm.ceilingz; - thing->floorrover = tm.floorrover; - thing->ceilingrover = tm.ceilingrover; + thing->floorz = g_tm.floorz; + thing->ceilingz = g_tm.ceilingz; + thing->floorrover = g_tm.floorrover; + thing->ceilingrover = g_tm.ceilingrover; thing->x = x; thing->y = y; - if (tm.floorthing) + if (g_tm.floorthing) thing->eflags &= ~MFE_ONGROUND; // not on real floor else thing->eflags |= MFE_ONGROUND; @@ -3345,17 +3345,17 @@ static boolean P_ThingHeightClip(mobj_t *thing) if (P_MobjWasRemoved(thing)) return true; - floormoved = (thing->eflags & MFE_VERTICALFLIP && tm.ceilingz != thing->ceilingz) - || (!(thing->eflags & MFE_VERTICALFLIP) && tm.floorz != thing->floorz); + floormoved = (thing->eflags & MFE_VERTICALFLIP && g_tm.ceilingz != thing->ceilingz) + || (!(thing->eflags & MFE_VERTICALFLIP) && g_tm.floorz != thing->floorz); - thing->floorz = tm.floorz; - thing->ceilingz = tm.ceilingz; - thing->floorrover = tm.floorrover; - thing->ceilingrover = tm.ceilingrover; + thing->floorz = g_tm.floorz; + thing->ceilingz = g_tm.ceilingz; + thing->floorrover = g_tm.floorrover; + thing->ceilingrover = g_tm.ceilingrover; // Ugly hack?!?! As long as just ceilingz is the lowest, // you'll still get crushed, right? - if (tm.floorz > oldfloorz+thing->height) + if (g_tm.floorz > oldfloorz+thing->height) return true; if (onfloor && !(thing->flags & MF_NOGRAVITY) && floormoved) @@ -3379,15 +3379,15 @@ static boolean P_ThingHeightClip(mobj_t *thing) thing->z = thing->floorz; } } - else if (!tm.floorthing) + else if (!g_tm.floorthing) { // don't adjust a floating monster unless forced to if (thing->eflags & MFE_VERTICALFLIP) { - if (!onfloor && thing->z < tm.floorz) + if (!onfloor && thing->z < g_tm.floorz) thing->z = thing->floorz; } - else if (!onfloor && thing->z + thing->height > tm.ceilingz) + else if (!onfloor && thing->z + thing->height > g_tm.ceilingz) thing->z = thing->ceilingz - thing->height; } @@ -4833,13 +4833,13 @@ void P_DelPrecipSeclist(mprecipsecnode_t *node) static inline BlockItReturn_t PIT_GetSectors(line_t *ld) { - if (tm.bbox[BOXRIGHT] <= ld->bbox[BOXLEFT] || - tm.bbox[BOXLEFT] >= ld->bbox[BOXRIGHT] || - tm.bbox[BOXTOP] <= ld->bbox[BOXBOTTOM] || - tm.bbox[BOXBOTTOM] >= ld->bbox[BOXTOP]) + if (g_tm.bbox[BOXRIGHT] <= ld->bbox[BOXLEFT] || + g_tm.bbox[BOXLEFT] >= ld->bbox[BOXRIGHT] || + g_tm.bbox[BOXTOP] <= ld->bbox[BOXBOTTOM] || + g_tm.bbox[BOXBOTTOM] >= ld->bbox[BOXTOP]) return BMIT_CONTINUE; - if (P_BoxOnLineSide(tm.bbox, ld) != -1) + if (P_BoxOnLineSide(g_tm.bbox, ld) != -1) return BMIT_CONTINUE; if (ld->polyobj) // line belongs to a polyobject, don't add it @@ -4852,7 +4852,7 @@ static inline BlockItReturn_t PIT_GetSectors(line_t *ld) // allowed to move to this position, then the sector_list // will be attached to the Thing's mobj_t at touching_sectorlist. - sector_list = P_AddSecnode(ld->frontsector,tm.thing,sector_list); + sector_list = P_AddSecnode(ld->frontsector,g_tm.thing,sector_list); // Don't assume all lines are 2-sided, since some Things // like MT_TFOG are allowed regardless of whether their radius takes @@ -4860,7 +4860,7 @@ static inline BlockItReturn_t PIT_GetSectors(line_t *ld) // Use sidedefs instead of 2s flag to determine two-sidedness. if (ld->backsector) - sector_list = P_AddSecnode(ld->backsector, tm.thing, sector_list); + sector_list = P_AddSecnode(ld->backsector, g_tm.thing, sector_list); return BMIT_CONTINUE; } @@ -4868,13 +4868,13 @@ static inline BlockItReturn_t PIT_GetSectors(line_t *ld) // Tails 08-25-2002 static inline BlockItReturn_t PIT_GetPrecipSectors(line_t *ld) { - if (tm.precipbbox[BOXRIGHT] <= ld->bbox[BOXLEFT] || - tm.precipbbox[BOXLEFT] >= ld->bbox[BOXRIGHT] || - tm.precipbbox[BOXTOP] <= ld->bbox[BOXBOTTOM] || - tm.precipbbox[BOXBOTTOM] >= ld->bbox[BOXTOP]) + if (g_tm.precipbbox[BOXRIGHT] <= ld->bbox[BOXLEFT] || + g_tm.precipbbox[BOXLEFT] >= ld->bbox[BOXRIGHT] || + g_tm.precipbbox[BOXTOP] <= ld->bbox[BOXBOTTOM] || + g_tm.precipbbox[BOXBOTTOM] >= ld->bbox[BOXTOP]) return BMIT_CONTINUE; - if (P_BoxOnLineSide(tm.precipbbox, ld) != -1) + if (P_BoxOnLineSide(g_tm.precipbbox, ld) != -1) return BMIT_CONTINUE; if (ld->polyobj) // line belongs to a polyobject, don't add it @@ -4887,7 +4887,7 @@ static inline BlockItReturn_t PIT_GetPrecipSectors(line_t *ld) // allowed to move to this position, then the sector_list // will be attached to the Thing's mobj_t at touching_sectorlist. - precipsector_list = P_AddPrecipSecnode(ld->frontsector, tm.precipthing, precipsector_list); + precipsector_list = P_AddPrecipSecnode(ld->frontsector, g_tm.precipthing, precipsector_list); // Don't assume all lines are 2-sided, since some Things // like MT_TFOG are allowed regardless of whether their radius takes @@ -4895,7 +4895,7 @@ static inline BlockItReturn_t PIT_GetPrecipSectors(line_t *ld) // Use sidedefs instead of 2s flag to determine two-sidedness. if (ld->backsector) - precipsector_list = P_AddPrecipSecnode(ld->backsector, tm.precipthing, precipsector_list); + precipsector_list = P_AddPrecipSecnode(ld->backsector, g_tm.precipthing, precipsector_list); return BMIT_CONTINUE; } @@ -4907,7 +4907,7 @@ void P_CreateSecNodeList(mobj_t *thing, fixed_t x, fixed_t y) { INT32 xl, xh, yl, yh, bx, by; msecnode_t *node = sector_list; - tm_t ptm = tm; /* cph - see comment at func end */ + tm_t ptm = g_tm; /* cph - see comment at func end */ // First, clear out the existing m_thing fields. As each node is // added or verified as needed, m_thing will be set properly. When @@ -4920,23 +4920,23 @@ void P_CreateSecNodeList(mobj_t *thing, fixed_t x, fixed_t y) node = node->m_sectorlist_next; } - P_SetTarget(&tm.thing, thing); - tm.flags = thing->flags; + P_SetTarget(&g_tm.thing, thing); + g_tm.flags = thing->flags; - tm.x = x; - tm.y = y; + g_tm.x = x; + g_tm.y = y; - tm.bbox[BOXTOP] = y + tm.thing->radius; - tm.bbox[BOXBOTTOM] = y - tm.thing->radius; - tm.bbox[BOXRIGHT] = x + tm.thing->radius; - tm.bbox[BOXLEFT] = x - tm.thing->radius; + g_tm.bbox[BOXTOP] = y + g_tm.thing->radius; + g_tm.bbox[BOXBOTTOM] = y - g_tm.thing->radius; + g_tm.bbox[BOXRIGHT] = x + g_tm.thing->radius; + g_tm.bbox[BOXLEFT] = x - g_tm.thing->radius; validcount++; // used to make sure we only process a line once - xl = (unsigned)(tm.bbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT; - xh = (unsigned)(tm.bbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT; - yl = (unsigned)(tm.bbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT; - yh = (unsigned)(tm.bbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT; + xl = (unsigned)(g_tm.bbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT; + xh = (unsigned)(g_tm.bbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT; + yl = (unsigned)(g_tm.bbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT; + yh = (unsigned)(g_tm.bbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT; BMBOUNDFIX(xl, xh, yl, yh); @@ -4963,10 +4963,10 @@ void P_CreateSecNodeList(mobj_t *thing, fixed_t x, fixed_t y) } /* cph - - * This is the strife we get into for using global variables. tm.thing + * This is the strife we get into for using global variables. g_tm.thing * is being used by several different functions calling * P_BlockThingIterator, including functions that can be called *from* - * P_BlockThingIterator. Using a global tm.thing is not reentrant. + * P_BlockThingIterator. Using a global g_tm.thing is not reentrant. * OTOH for Boom/MBF demos we have to preserve the buggy behavior. * Fun. We restore its previous value unless we're in a Boom/MBF demo. */ @@ -4978,7 +4978,7 @@ void P_CreatePrecipSecNodeList(precipmobj_t *thing,fixed_t x,fixed_t y) { INT32 xl, xh, yl, yh, bx, by; mprecipsecnode_t *node = precipsector_list; - tm_t ptm = tm; /* cph - see comment at func end */ + tm_t ptm = g_tm; /* cph - see comment at func end */ // First, clear out the existing m_thing fields. As each node is // added or verified as needed, m_thing will be set properly. When @@ -4991,19 +4991,19 @@ void P_CreatePrecipSecNodeList(precipmobj_t *thing,fixed_t x,fixed_t y) node = node->m_sectorlist_next; } - tm.precipthing = thing; + g_tm.precipthing = thing; - tm.precipbbox[BOXTOP] = y + 2*FRACUNIT; - tm.precipbbox[BOXBOTTOM] = y - 2*FRACUNIT; - tm.precipbbox[BOXRIGHT] = x + 2*FRACUNIT; - tm.precipbbox[BOXLEFT] = x - 2*FRACUNIT; + g_tm.precipbbox[BOXTOP] = y + 2*FRACUNIT; + g_tm.precipbbox[BOXBOTTOM] = y - 2*FRACUNIT; + g_tm.precipbbox[BOXRIGHT] = x + 2*FRACUNIT; + g_tm.precipbbox[BOXLEFT] = x - 2*FRACUNIT; validcount++; // used to make sure we only process a line once - xl = (unsigned)(tm.precipbbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT; - xh = (unsigned)(tm.precipbbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT; - yl = (unsigned)(tm.precipbbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT; - yh = (unsigned)(tm.precipbbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT; + xl = (unsigned)(g_tm.precipbbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT; + xh = (unsigned)(g_tm.precipbbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT; + yl = (unsigned)(g_tm.precipbbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT; + yh = (unsigned)(g_tm.precipbbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT; BMBOUNDFIX(xl, xh, yl, yh); @@ -5030,10 +5030,10 @@ void P_CreatePrecipSecNodeList(precipmobj_t *thing,fixed_t x,fixed_t y) } /* cph - - * This is the strife we get into for using global variables. tm.thing + * This is the strife we get into for using global variables. g_tm.thing * is being used by several different functions calling * P_BlockThingIterator, including functions that can be called *from* - * P_BlockThingIterator. Using a global tm.thing is not reentrant. + * P_BlockThingIterator. Using a global g_tm.thing is not reentrant. * OTOH for Boom/MBF demos we have to preserve the buggy behavior. * Fun. We restore its previous value unless we're in a Boom/MBF demo. */ @@ -5041,16 +5041,16 @@ void P_CreatePrecipSecNodeList(precipmobj_t *thing,fixed_t x,fixed_t y) } /* cphipps 2004/08/30 - - * Must clear tm.thing at tic end, as it might contain a pointer to a removed thinker, or the level might have ended/been ended and we clear the objects it was pointing too. Hopefully we don't need to carry this between tics for sync. */ + * Must clear g_tm.thing at tic end, as it might contain a pointer to a removed thinker, or the level might have ended/been ended and we clear the objects it was pointing too. Hopefully we don't need to carry this between tics for sync. */ void P_MapStart(void) { - if (tm.thing) - I_Error("P_MapStart: tm.thing set!"); + if (g_tm.thing) + I_Error("P_MapStart: g_tm.thing set!"); } void P_MapEnd(void) { - P_SetTarget(&tm.thing, NULL); + P_SetTarget(&g_tm.thing, NULL); } // P_FloorzAtPos diff --git a/src/p_maputl.c b/src/p_maputl.c index ffde6ae40..3ba869270 100644 --- a/src/p_maputl.c +++ b/src/p_maputl.c @@ -375,8 +375,8 @@ void P_CameraLineOpening(line_t *linedef, opening_t *open) } else { - frontfloor = P_CameraGetFloorZ (mapcampointer, front, tm.x, tm.y, linedef); - frontceiling = P_CameraGetCeilingZ(mapcampointer, front, tm.x, tm.y, linedef); + frontfloor = P_CameraGetFloorZ (mapcampointer, front, g_tm.x, g_tm.y, linedef); + frontceiling = P_CameraGetCeilingZ(mapcampointer, front, g_tm.x, g_tm.y, linedef); } if (back->camsec >= 0) @@ -393,8 +393,8 @@ void P_CameraLineOpening(line_t *linedef, opening_t *open) } else { - backfloor = P_CameraGetFloorZ (mapcampointer, back, tm.x, tm.y, linedef); - backceiling = P_CameraGetCeilingZ(mapcampointer, back, tm.x, tm.y, linedef); + backfloor = P_CameraGetFloorZ (mapcampointer, back, g_tm.x, g_tm.y, linedef); + backceiling = P_CameraGetCeilingZ(mapcampointer, back, g_tm.x, g_tm.y, linedef); } thingtop = mapcampointer->z + mapcampointer->height; @@ -435,8 +435,8 @@ void P_CameraLineOpening(line_t *linedef, opening_t *open) if (!(rover->fofflags & FOF_BLOCKOTHERS) || !(rover->fofflags & FOF_RENDERALL) || !(rover->fofflags & FOF_EXISTS) || (rover->master->frontsector->flags & MSF_NOCLIPCAMERA)) continue; - topheight = P_CameraGetFOFTopZ(mapcampointer, front, rover, tm.x, tm.y, linedef); - bottomheight = P_CameraGetFOFBottomZ(mapcampointer, front, rover, tm.x, tm.y, linedef); + topheight = P_CameraGetFOFTopZ(mapcampointer, front, rover, g_tm.x, g_tm.y, linedef); + bottomheight = P_CameraGetFOFBottomZ(mapcampointer, front, rover, g_tm.x, g_tm.y, linedef); delta1 = abs(mapcampointer->z - (bottomheight + ((topheight - bottomheight)/2))); delta2 = abs(thingtop - (bottomheight + ((topheight - bottomheight)/2))); @@ -459,8 +459,8 @@ void P_CameraLineOpening(line_t *linedef, opening_t *open) if (!(rover->fofflags & FOF_BLOCKOTHERS) || !(rover->fofflags & FOF_RENDERALL) || !(rover->fofflags & FOF_EXISTS) || (rover->master->frontsector->flags & MSF_NOCLIPCAMERA)) continue; - topheight = P_CameraGetFOFTopZ(mapcampointer, back, rover, tm.x, tm.y, linedef); - bottomheight = P_CameraGetFOFBottomZ(mapcampointer, back, rover, tm.x, tm.y, linedef); + topheight = P_CameraGetFOFTopZ(mapcampointer, back, rover, g_tm.x, g_tm.y, linedef); + bottomheight = P_CameraGetFOFBottomZ(mapcampointer, back, rover, g_tm.x, g_tm.y, linedef); delta1 = abs(mapcampointer->z - (bottomheight + ((topheight - bottomheight)/2))); delta2 = abs(thingtop - (bottomheight + ((topheight - bottomheight)/2))); @@ -617,7 +617,7 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj, opening_t *open) return; } - P_ClosestPointOnLine(tm.x, tm.y, linedef, &cross); + P_ClosestPointOnLine(g_tm.x, g_tm.y, linedef, &cross); // Treat polyobjects kind of like 3D Floors if (linedef->polyobj && (linedef->polyobj->flags & POF_TESTHEIGHT)) @@ -645,8 +645,8 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj, opening_t *open) fixed_t height[2]; const sector_t * sector[2] = { front, back }; - height[FRONT] = P_GetCeilingZ(mobj, front, tm.x, tm.y, linedef); - height[BACK] = P_GetCeilingZ(mobj, back, tm.x, tm.y, linedef); + height[FRONT] = P_GetCeilingZ(mobj, front, g_tm.x, g_tm.y, linedef); + height[BACK] = P_GetCeilingZ(mobj, back, g_tm.x, g_tm.y, linedef); hi = ( height[0] < height[1] ); lo = ! hi; @@ -665,8 +665,8 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj, opening_t *open) open->ceilingdrop = ( topedge[hi] - topedge[lo] ); } - height[FRONT] = P_GetFloorZ(mobj, front, tm.x, tm.y, linedef); - height[BACK] = P_GetFloorZ(mobj, back, tm.x, tm.y, linedef); + height[FRONT] = P_GetFloorZ(mobj, front, g_tm.x, g_tm.y, linedef); + height[BACK] = P_GetFloorZ(mobj, back, g_tm.x, g_tm.y, linedef); hi = ( height[0] < height[1] ); lo = ! hi; @@ -855,8 +855,8 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj, opening_t *open) } else { - topheight = P_GetFOFTopZ(mobj, front, rover, tm.x, tm.y, linedef); - bottomheight = P_GetFOFBottomZ(mobj, front, rover, tm.x, tm.y, linedef); + topheight = P_GetFOFTopZ(mobj, front, rover, g_tm.x, g_tm.y, linedef); + bottomheight = P_GetFOFBottomZ(mobj, front, rover, g_tm.x, g_tm.y, linedef); } switch (open->fofType) @@ -947,8 +947,8 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj, opening_t *open) } else { - topheight = P_GetFOFTopZ(mobj, back, rover, tm.x, tm.y, linedef); - bottomheight = P_GetFOFBottomZ(mobj, back, rover, tm.x, tm.y, linedef); + topheight = P_GetFOFTopZ(mobj, back, rover, g_tm.x, g_tm.y, linedef); + bottomheight = P_GetFOFBottomZ(mobj, back, rover, g_tm.x, g_tm.y, linedef); } switch (open->fofType) @@ -1754,16 +1754,16 @@ boolean P_RadiusLinesCheck(fixed_t radius, fixed_t x, fixed_t y, INT32 xl, xh, yl, yh; INT32 bx, by; - tm.bbox[BOXTOP] = y + radius; - tm.bbox[BOXBOTTOM] = y - radius; - tm.bbox[BOXRIGHT] = x + radius; - tm.bbox[BOXLEFT] = x - radius; + g_tm.bbox[BOXTOP] = y + radius; + g_tm.bbox[BOXBOTTOM] = y - radius; + g_tm.bbox[BOXRIGHT] = x + radius; + g_tm.bbox[BOXLEFT] = x - radius; // check lines - xl = (unsigned)(tm.bbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT; - xh = (unsigned)(tm.bbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT; - yl = (unsigned)(tm.bbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT; - yh = (unsigned)(tm.bbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT; + xl = (unsigned)(g_tm.bbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT; + xh = (unsigned)(g_tm.bbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT; + yl = (unsigned)(g_tm.bbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT; + yh = (unsigned)(g_tm.bbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT; for (bx = xl; bx <= xh; bx++) for (by = yl; by <= yh; by++) diff --git a/src/p_mobj.c b/src/p_mobj.c index 6bd3924fc..dabd3ff6a 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1558,12 +1558,12 @@ bustupdone: // static boolean P_CheckSkyHit(mobj_t *mo) { - if (tm.ceilingline && tm.ceilingline->backsector - && tm.ceilingline->backsector->ceilingpic == skyflatnum - && tm.ceilingline->frontsector - && tm.ceilingline->frontsector->ceilingpic == skyflatnum - && (mo->z >= tm.ceilingline->frontsector->ceilingheight - || mo->z >= tm.ceilingline->backsector->ceilingheight)) + if (g_tm.ceilingline && g_tm.ceilingline->backsector + && g_tm.ceilingline->backsector->ceilingpic == skyflatnum + && g_tm.ceilingline->frontsector + && g_tm.ceilingline->frontsector->ceilingpic == skyflatnum + && (mo->z >= g_tm.ceilingline->frontsector->ceilingheight + || mo->z >= g_tm.ceilingline->backsector->ceilingheight)) return true; return false; } @@ -1668,7 +1668,7 @@ void P_XYMovement(mobj_t *mo) // blocked move moved = false; - if (LUA_HookMobjMoveBlocked(mo, tm.hitthing, result.line)) + if (LUA_HookMobjMoveBlocked(mo, g_tm.hitthing, result.line)) { if (P_MobjWasRemoved(mo)) return; @@ -1695,7 +1695,7 @@ void P_XYMovement(mobj_t *mo) // draw damage on wall //SPLAT TEST ---------------------------------------------------------- #ifdef WALLSPLATS - if (tm.blockingline && mo->type != MT_REDRING && mo->type != MT_FIREBALL + if (g_tm.blockingline && mo->type != MT_REDRING && mo->type != MT_FIREBALL && !(mo->flags2 & (MF2_AUTOMATIC|MF2_RAILRING|MF2_BOUNCERING|MF2_EXPLOSION|MF2_SCATTER))) // set by last P_TryMove() that failed { @@ -1703,13 +1703,13 @@ void P_XYMovement(mobj_t *mo) divline_t misl; fixed_t frac; - P_MakeDivline(tm.blockingline, &divl); + P_MakeDivline(g_tm.blockingline, &divl); misl.x = mo->x; misl.y = mo->y; misl.dx = mo->momx; misl.dy = mo->momy; frac = P_InterceptVector(&divl, &misl); - R_AddWallSplat(tm.blockingline, P_PointOnLineSide(mo->x,mo->y,tm.blockingline), + R_AddWallSplat(g_tm.blockingline, P_PointOnLineSide(mo->x,mo->y,g_tm.blockingline), "A_DMG3", mo->z, frac, SPLATDRAWMODE_SHADE); } #endif @@ -2367,11 +2367,11 @@ boolean P_ZMovement(mobj_t *mo) mom.y = mo->momy; mom.z = mo->momz; - K_UpdateMobjTerrain(mo, ((mo->eflags & MFE_VERTICALFLIP) ? tm.ceilingpic : tm.floorpic)); + K_UpdateMobjTerrain(mo, ((mo->eflags & MFE_VERTICALFLIP) ? g_tm.ceilingpic : g_tm.floorpic)); - if (((mo->eflags & MFE_VERTICALFLIP) ? tm.ceilingslope : tm.floorslope) && (mo->type != MT_STEAM)) + if (((mo->eflags & MFE_VERTICALFLIP) ? g_tm.ceilingslope : g_tm.floorslope) && (mo->type != MT_STEAM)) { - mo->standingslope = (mo->eflags & MFE_VERTICALFLIP) ? tm.ceilingslope : tm.floorslope; + mo->standingslope = (mo->eflags & MFE_VERTICALFLIP) ? g_tm.ceilingslope : g_tm.floorslope; P_SetPitchRollFromSlope(mo, mo->standingslope); P_ReverseQuantizeMomentumToSlope(&mom, mo->standingslope); } @@ -2598,11 +2598,11 @@ boolean P_ZMovement(mobj_t *mo) } } else - mom.z = (tm.floorthing ? tm.floorthing->momz : 0); + mom.z = (g_tm.floorthing ? g_tm.floorthing->momz : 0); } - else if (tm.floorthing) - mom.z = tm.floorthing->momz; + else if (g_tm.floorthing) + mom.z = g_tm.floorthing->momz; if (mo->standingslope) { // MT_STEAM will never have a standingslope, see above. P_QuantizeMomentumToSlope(&mom, mo->standingslope); @@ -2843,7 +2843,7 @@ void P_PlayerZMovement(mobj_t *mo) mo->z = mo->floorz; } - K_UpdateMobjTerrain(mo, (mo->eflags & MFE_VERTICALFLIP ? tm.ceilingpic : tm.floorpic)); + K_UpdateMobjTerrain(mo, (mo->eflags & MFE_VERTICALFLIP ? g_tm.ceilingpic : g_tm.floorpic)); // Get up if you fell. if (mo->player->panim == PA_HURT && mo->player->spinouttimer == 0 && mo->player->tumbleBounces == 0) @@ -2851,10 +2851,10 @@ void P_PlayerZMovement(mobj_t *mo) P_SetPlayerMobjState(mo, S_KART_STILL); } - if (!mo->standingslope && (mo->eflags & MFE_VERTICALFLIP ? tm.ceilingslope : tm.floorslope)) + if (!mo->standingslope && (mo->eflags & MFE_VERTICALFLIP ? g_tm.ceilingslope : g_tm.floorslope)) { // Handle landing on slope during Z movement - P_HandleSlopeLanding(mo, (mo->eflags & MFE_VERTICALFLIP ? tm.ceilingslope : tm.floorslope)); + P_HandleSlopeLanding(mo, (mo->eflags & MFE_VERTICALFLIP ? g_tm.ceilingslope : g_tm.floorslope)); } if (P_MobjFlip(mo) * mo->momz < 0) // falling @@ -2869,12 +2869,12 @@ void P_PlayerZMovement(mobj_t *mo) if (clipmomz) { - mo->momz = (tm.floorthing ? tm.floorthing->momz : 0); + mo->momz = (g_tm.floorthing ? g_tm.floorthing->momz : 0); } } - else if (tm.floorthing) + else if (g_tm.floorthing) { - mo->momz = tm.floorthing->momz; + mo->momz = g_tm.floorthing->momz; } } else @@ -3124,9 +3124,9 @@ boolean P_SceneryZMovement(mobj_t *mo) { mo->eflags |= MFE_JUSTHITFLOOR; // Spin Attack - if (tm.floorthing) - mo->momz = tm.floorthing->momz; - else if (!tm.floorthing) + if (g_tm.floorthing) + mo->momz = g_tm.floorthing->momz; + else if (!g_tm.floorthing) mo->momz = 0; } } @@ -3868,8 +3868,8 @@ boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled } thiscam->subsector = R_PointInSubsector(thiscam->x, thiscam->y); - thiscam->floorz = tm.floorz; - thiscam->ceilingz = tm.ceilingz; + thiscam->floorz = g_tm.floorz; + thiscam->ceilingz = g_tm.ceilingz; if (thiscam->momz || thiscam->pmomz) { @@ -4029,8 +4029,8 @@ static void P_PlayerMobjThinker(mobj_t *mobj) mobj->z += mobj->momz; P_SetThingPosition(mobj); P_CheckPosition(mobj, mobj->x, mobj->y, NULL); - mobj->floorz = tm.floorz; - mobj->ceilingz = tm.ceilingz; + mobj->floorz = g_tm.floorz; + mobj->ceilingz = g_tm.ceilingz; mobj->terrain = NULL; goto animonly; } @@ -7159,7 +7159,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj) // the backdrop can also go transparent. EUUUAUUAUUAAAUUUUGGGHGHHHHHHHGSSS if (mobj->extravalue1 > 0) mobj->extravalue1--; - + break; } case MT_ITEMCAPSULE: @@ -10166,8 +10166,8 @@ void P_MobjThinker(mobj_t *mobj) mobj->eflags &= ~(MFE_PUSHED|MFE_SPRUNG|MFE_JUSTBOUNCEDWALL|MFE_DAMAGEHITLAG|MFE_SLOPELAUNCHED); // sal: what the hell? is there any reason this isn't done, like, literally ANYWHERE else? - P_SetTarget(&tm.floorthing, NULL); - P_SetTarget(&tm.hitthing, NULL); + P_SetTarget(&g_tm.floorthing, NULL); + P_SetTarget(&g_tm.hitthing, NULL); if (udmf) { @@ -10520,10 +10520,10 @@ void P_SceneryThinker(mobj_t *mobj) P_CheckPosition(mobj, mobj->x, mobj->y, NULL); // Need this to pick up objects! if (P_MobjWasRemoved(mobj)) return; - mobj->floorz = tm.floorz; - mobj->ceilingz = tm.ceilingz; - mobj->floorrover = tm.floorrover; - mobj->ceilingrover = tm.ceilingrover; + mobj->floorz = g_tm.floorz; + mobj->ceilingz = g_tm.ceilingz; + mobj->floorrover = g_tm.floorrover; + mobj->ceilingrover = g_tm.ceilingrover; } else { diff --git a/src/p_polyobj.c b/src/p_polyobj.c index c6cbe9ee3..a27b2d847 100644 --- a/src/p_polyobj.c +++ b/src/p_polyobj.c @@ -763,7 +763,7 @@ static void Polyobj_removeFromBlockmap(polyobj_t *po) // Movement functions // A version of Lee's routine from p_maputl.c that accepts an mobj pointer -// argument instead of using tm.thing. Returns true if the line isn't contacted +// argument instead of using g_tm.thing. Returns true if the line isn't contacted // and false otherwise. static inline boolean Polyobj_untouched(line_t *ld, mobj_t *mo) { @@ -807,10 +807,10 @@ static void Polyobj_pushThing(polyobj_t *po, line_t *line, mobj_t *mo) if (po->damage && (mo->flags & MF_SHOOTABLE)) { P_CheckPosition(mo, mo->x + momx, mo->y + momy, NULL); - mo->floorz = tm.floorz; - mo->ceilingz = tm.ceilingz; - mo->floorrover = tm.floorrover; - mo->ceilingrover = tm.ceilingrover; + mo->floorz = g_tm.floorz; + mo->ceilingz = g_tm.ceilingz; + mo->floorrover = g_tm.floorrover; + mo->ceilingrover = g_tm.ceilingrover; } } @@ -2199,7 +2199,7 @@ boolean EV_DoPolyObjWaypoint(polywaypointdata_t *pwdata) R_CreateInterpolator_Polyobj(&th->thinker, po); // T_PolyObjWaypoint is the only polyobject movement // that can adjust z, so we add these ones too. - R_CreateInterpolator_SectorPlane(&th->thinker, po->lines[0]->backsector, false); + R_CreateInterpolator_SectorPlane(&th->thinker, po->lines[0]->backsector, false); R_CreateInterpolator_SectorPlane(&th->thinker, po->lines[0]->backsector, true); // Most other polyobject functions handle children by recursively diff --git a/src/p_sight.c b/src/p_sight.c index 20d94484d..2b973a3a6 100644 --- a/src/p_sight.c +++ b/src/p_sight.c @@ -380,13 +380,13 @@ static boolean P_CanBotTraverse(seg_t *seg, divline_t *divl, register los_t *los frac = P_InterceptVector2(&los->strace, divl); // calculate position at intercept - tm.x = los->strace.x + FixedMul(los->strace.dx, frac); - tm.y = los->strace.y + FixedMul(los->strace.dy, frac); + g_tm.x = los->strace.x + FixedMul(los->strace.dx, frac); + g_tm.y = los->strace.y + FixedMul(los->strace.dy, frac); // set openrange, opentop, openbottom open.fofType = (flip ? LO_FOF_CEILINGS : LO_FOF_FLOORS); P_LineOpening(line, los->t1, &open); - maxstep = P_GetThingStepUp(los->t1, tm.x, tm.y); + maxstep = P_GetThingStepUp(los->t1, g_tm.x, g_tm.y); if (open.range < los->t1->height) { @@ -408,7 +408,7 @@ static boolean P_CanBotTraverse(seg_t *seg, divline_t *divl, register los_t *los UINT8 side = P_DivlineSide(los->t2x, los->t2y, divl) & 1; sector_t *sector = (side == 1) ? seg->backsector : seg->frontsector; - if (K_BotHatesThisSector(los->t1->player, sector, tm.x, tm.y)) + if (K_BotHatesThisSector(los->t1->player, sector, g_tm.x, g_tm.y)) { // This line does not block us, but we don't want to cross it regardless. return false; @@ -448,13 +448,13 @@ static boolean P_CanWaypointTraverse(seg_t *seg, divline_t *divl, register los_t frac = P_InterceptVector2(&los->strace, divl); // calculate position at intercept - tm.x = los->strace.x + FixedMul(los->strace.dx, frac); - tm.y = los->strace.y + FixedMul(los->strace.dy, frac); + g_tm.x = los->strace.x + FixedMul(los->strace.dx, frac); + g_tm.y = los->strace.y + FixedMul(los->strace.dy, frac); // set openrange, opentop, openbottom open.fofType = (flip ? LO_FOF_CEILINGS : LO_FOF_FLOORS); P_LineOpening(line, los->t1, &open); - maxstep = P_GetThingStepUp(los->t1, tm.x, tm.y); + maxstep = P_GetThingStepUp(los->t1, g_tm.x, g_tm.y); #if 0 if (los->t2->type == MT_WAYPOINT) From 6f2a73e911770072a294aa72eb197bf07ad80b2f Mon Sep 17 00:00:00 2001 From: SteelT Date: Mon, 19 Feb 2024 21:52:37 -0500 Subject: [PATCH 21/33] streams.cpp: include cstring for strerror --- src/io/streams.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/io/streams.cpp b/src/io/streams.cpp index 85ef2aab2..bfcadb84f 100644 --- a/src/io/streams.cpp +++ b/src/io/streams.cpp @@ -11,6 +11,7 @@ #include #include +#include #include template class srb2::io::ZlibInputStream; From a5b870a0b394a8c30bcf49dd3d36c3a8a60f8c59 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Tue, 20 Feb 2024 01:26:00 -0600 Subject: [PATCH 22/33] io: Always discard file_ pointer on close() --- src/io/streams.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/io/streams.cpp b/src/io/streams.cpp index bfcadb84f..17d03e0ad 100644 --- a/src/io/streams.cpp +++ b/src/io/streams.cpp @@ -157,14 +157,12 @@ void FileStream::close() if (std::fclose((std::FILE*)(this->file_)) != 0) { + // The FILE is now invalid even though fclose failed. + // There is nothing we can do but abandon the pointer. + file_ = nullptr; int err = errno; throw make_exception_from_errno(err); } - if (std::ferror((std::FILE*)(this->file_)) != 0) - { - int err = errno; - throw make_exception_from_errno(err); - } file_ = nullptr; } From ec1041eaa22819bc123624e3d9ace7e1983c4dba Mon Sep 17 00:00:00 2001 From: Eidolon Date: Tue, 20 Feb 2024 19:29:41 -0600 Subject: [PATCH 23/33] Add support for spb attack records in json gamedata --- src/g_gamedata.cpp | 16 ++++++++++------ src/g_gamedata.h | 20 ++++++++++++++++++-- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/g_gamedata.cpp b/src/g_gamedata.cpp index a685742b2..32cef1dc1 100644 --- a/src/g_gamedata.cpp +++ b/src/g_gamedata.cpp @@ -121,8 +121,10 @@ void srb2::save_ng_gamedata() map.visited.encore = mapheaderinfo[i]->records.mapvisited & MV_ENCORE; map.visited.spbattack = mapheaderinfo[i]->records.mapvisited & MV_SPBATTACK; map.visited.mysticmelody = mapheaderinfo[i]->records.mapvisited & MV_MYSTICMELODY; - map.stats.besttime = mapheaderinfo[i]->records.time; - map.stats.bestlap = mapheaderinfo[i]->records.lap; + map.stats.timeattack.besttime = mapheaderinfo[i]->records.time; + map.stats.timeattack.bestlap = mapheaderinfo[i]->records.lap; + map.stats.spbattack.besttime = 0; + map.stats.spbattack.bestlap = 0; ng.maps[lumpname] = map; } for (auto unloadedmap = unloadedmapheaders; unloadedmap; unloadedmap = unloadedmap->next) @@ -134,8 +136,10 @@ void srb2::save_ng_gamedata() map.visited.encore = unloadedmap->records.mapvisited & MV_ENCORE; map.visited.spbattack = unloadedmap->records.mapvisited & MV_SPBATTACK; map.visited.mysticmelody = unloadedmap->records.mapvisited & MV_MYSTICMELODY; - map.stats.besttime = unloadedmap->records.time; - map.stats.bestlap = unloadedmap->records.lap; + map.stats.timeattack.besttime = unloadedmap->records.time; + map.stats.timeattack.bestlap = unloadedmap->records.lap; + map.stats.spbattack.besttime = 0; + map.stats.spbattack.bestlap = 0; ng.maps[lumpname] = map; } for (int i = 0; i < gamedata->numspraycans; i++) @@ -499,8 +503,8 @@ void srb2::load_ng_gamedata() dummyrecord.mapvisited |= mappair.second.visited.encore ? MV_ENCORE : 0; dummyrecord.mapvisited |= mappair.second.visited.spbattack ? MV_SPBATTACK : 0; dummyrecord.mapvisited |= mappair.second.visited.mysticmelody ? MV_SPBATTACK : 0; - dummyrecord.lap = mappair.second.stats.bestlap; - dummyrecord.time = mappair.second.stats.besttime; + dummyrecord.time = mappair.second.stats.timeattack.besttime; + dummyrecord.lap = mappair.second.stats.timeattack.bestlap; if (mapnum < nummapheaders && mapheaderinfo[mapnum]) { diff --git a/src/g_gamedata.h b/src/g_gamedata.h index 4b9ebeb9d..b3412329c 100644 --- a/src/g_gamedata.h +++ b/src/g_gamedata.h @@ -126,12 +126,28 @@ struct GamedataMapVisitedJson final NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataMapVisitedJson, visited, beaten, encore, spbattack, mysticmelody) }; -struct GamedataMapStatsJson final +struct GamedataMapStatsTimeAttackJson final { uint32_t besttime; uint32_t bestlap; - NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataMapStatsJson, besttime, bestlap) + NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataMapStatsTimeAttackJson, besttime, bestlap) +}; + +struct GamedataMapStatsSpbAttackJson final +{ + uint32_t besttime; + uint32_t bestlap; + + NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataMapStatsSpbAttackJson, besttime, bestlap) +}; + +struct GamedataMapStatsJson final +{ + GamedataMapStatsTimeAttackJson timeattack; + GamedataMapStatsSpbAttackJson spbattack; + + NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataMapStatsJson, timeattack, spbattack) }; struct GamedataMapJson final From 266fe6d65d28468ea783107ba2a13b6924800f2d Mon Sep 17 00:00:00 2001 From: Eidolon Date: Tue, 20 Feb 2024 21:28:53 -0600 Subject: [PATCH 24/33] Fix cup data loading from json --- src/g_gamedata.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_gamedata.cpp b/src/g_gamedata.cpp index 32cef1dc1..645c3e96d 100644 --- a/src/g_gamedata.cpp +++ b/src/g_gamedata.cpp @@ -597,7 +597,7 @@ void srb2::load_ng_gamedata() std::string cupname = std::string(cup->name); if (cupname == cuppair.first) { - continue; + break; } } From ce6b76b0cfa26039f6e300a7f764cfbeace8a4d0 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Wed, 21 Feb 2024 08:35:15 -0600 Subject: [PATCH 25/33] Fix spraycans on JSON, store can color name --- src/g_gamedata.cpp | 50 ++++++++++++++++++++++++++++++++++++++-------- src/g_gamedata.h | 2 +- 2 files changed, 43 insertions(+), 9 deletions(-) diff --git a/src/g_gamedata.cpp b/src/g_gamedata.cpp index 645c3e96d..ee0c53706 100644 --- a/src/g_gamedata.cpp +++ b/src/g_gamedata.cpp @@ -148,11 +148,24 @@ void srb2::save_ng_gamedata() candata_t* can = &gamedata->spraycans[i]; - spraycan.color = can->col; + if (can->col >= numskincolors) + { + continue; + } + spraycan.color = std::string(skincolors[can->col].name); + + if (can->map == NEXTMAP_INVALID) + { + spraycan.map = ""; + ng.spraycans.emplace_back(std::move(spraycan)); + continue; + } + if (can->map >= nummapheaders) { continue; } + mapheader_t* mapheader = mapheaderinfo[can->map]; if (!mapheader) { @@ -548,21 +561,42 @@ void srb2::load_ng_gamedata() (gamedata->numspraycans * sizeof(candata_t)), PU_STATIC, NULL)); - for (size_t i = 0; i < js.spraycans.size(); i++) + for (size_t i = 0; i < gamedata->numspraycans; i++) { auto& can = js.spraycans[i]; - gamedata->spraycans[i].col = can.color; - gamedata->spraycans[i].map = NEXTMAP_INVALID; - if (can.map.empty()) + + // Find the skin color index for the name + bool foundcolor = false; + for (size_t j = 0; j < numskincolors; j++) { + if (can.color == skincolors[j].name) + { + gamedata->spraycans[i].col = j; + foundcolor = true; + break; + } + } + if (!foundcolor) + { + // Invalid color name? Ignore the spraycan + gamedata->numspraycans -= 1; + i -= 1; continue; } - UINT16 mapnum = G_MapNumber(can.map.c_str()); - if (mapnum < 0) + + gamedata->spraycans[i].map = NEXTMAP_INVALID; + + UINT16 mapnum = NEXTMAP_INVALID; + if (!can.map.empty()) { - continue; + mapnum = G_MapNumber(can.map.c_str()); } gamedata->spraycans[i].map = mapnum; + if (mapnum >= nummapheaders) + { + // Can has not been grabbed on any map, this is intentional. + continue; + } if (gamedata->gotspraycans != i) { diff --git a/src/g_gamedata.h b/src/g_gamedata.h index b3412329c..eb759fd59 100644 --- a/src/g_gamedata.h +++ b/src/g_gamedata.h @@ -161,7 +161,7 @@ struct GamedataMapJson final struct GamedataSprayCanJson final { std::string map; - uint16_t color; + std::string color; NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataSprayCanJson, map, color) }; From ee064b53954fc45585f743bf384b1abd903b61ef Mon Sep 17 00:00:00 2001 From: Eidolon Date: Wed, 21 Feb 2024 17:11:35 -0600 Subject: [PATCH 26/33] Set stats menu music to EXSTAT --- src/menus/extras-challenges.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/menus/extras-challenges.c b/src/menus/extras-challenges.c index 0911e9632..6fe8ac330 100644 --- a/src/menus/extras-challenges.c +++ b/src/menus/extras-challenges.c @@ -47,7 +47,7 @@ menu_t MISC_StatisticsDef = { 280, 185, 0, 0, 0, - "EXTRAS", + "EXSTAT", 98, 0, M_DrawStatistics, M_DrawExtrasBack, @@ -526,7 +526,7 @@ void M_ChallengesTick(void) challengesmenu.chaokeyhold++; UINT32 chaohold_duration = - CHAOHOLD_PADDING + CHAOHOLD_PADDING + ((unlockables[challengesmenu.currentunlock].majorunlock == true) ? CHAOHOLD_MAJOR : CHAOHOLD_STANDARD From 38940ee56876da313122fddfc1110c83ee95f42b Mon Sep 17 00:00:00 2001 From: Eidolon Date: Wed, 21 Feb 2024 17:51:53 -0600 Subject: [PATCH 27/33] Rename goner gamedata struct to milestones --- src/g_gamedata.cpp | 36 ++++++++++++++++++------------------ src/g_gamedata.h | 12 ++++++------ 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/g_gamedata.cpp b/src/g_gamedata.cpp index ee0c53706..56a126e8e 100644 --- a/src/g_gamedata.cpp +++ b/src/g_gamedata.cpp @@ -56,15 +56,15 @@ void srb2::save_ng_gamedata() ng.challengekeys.pendingkeyroundoffset = gamedata->pendingkeyroundoffset; ng.challengekeys.keyspending = gamedata->keyspending; ng.challengekeys.chaokeys = gamedata->chaokeys; - ng.goner.everloadedaddon = gamedata->everloadedaddon; - ng.goner.everfinishcredits = gamedata->everfinishedcredits; - ng.goner.eversavedreplay = gamedata->eversavedreplay; - ng.goner.everseenspecial = gamedata->everseenspecial; - ng.goner.chaokeytutorial = gamedata->chaokeytutorial; - ng.goner.majorkeyskipattempted = gamedata->majorkeyskipattempted; - ng.goner.finishedtutorialchallenge = gamedata->finishedtutorialchallenge; - ng.goner.enteredtutorialchallenge = gamedata->enteredtutorialchallenge; - ng.goner.level = gamedata->gonerlevel; + ng.milestones.everloadedaddon = gamedata->everloadedaddon; + ng.milestones.everfinishcredits = gamedata->everfinishedcredits; + ng.milestones.eversavedreplay = gamedata->eversavedreplay; + ng.milestones.everseenspecial = gamedata->everseenspecial; + ng.milestones.chaokeytutorial = gamedata->chaokeytutorial; + ng.milestones.majorkeyskipattempted = gamedata->majorkeyskipattempted; + ng.milestones.finishedtutorialchallenge = gamedata->finishedtutorialchallenge; + ng.milestones.enteredtutorialchallenge = gamedata->enteredtutorialchallenge; + ng.milestones.gonerlevel = gamedata->gonerlevel; ng.prisons.thisprisoneggpickup = gamedata->thisprisoneggpickup; ng.prisons.prisoneggstothispickup = gamedata->prisoneggstothispickup; ng.tafolderhash = quickncasehash(timeattackfolder, 64); @@ -390,15 +390,15 @@ void srb2::load_ng_gamedata() gamedata->pendingkeyroundoffset = js.challengekeys.pendingkeyroundoffset; gamedata->keyspending = js.challengekeys.keyspending; gamedata->chaokeys = js.challengekeys.chaokeys; - gamedata->everloadedaddon = js.goner.everloadedaddon; - gamedata->everfinishedcredits = js.goner.everfinishcredits; - gamedata->eversavedreplay = js.goner.eversavedreplay; - gamedata->everseenspecial = js.goner.everseenspecial; - gamedata->chaokeytutorial = js.goner.chaokeytutorial; - gamedata->majorkeyskipattempted = js.goner.majorkeyskipattempted; - gamedata->finishedtutorialchallenge = js.goner.finishedtutorialchallenge; - gamedata->enteredtutorialchallenge = js.goner.enteredtutorialchallenge; - gamedata->gonerlevel = js.goner.level; + gamedata->everloadedaddon = js.milestones.everloadedaddon; + gamedata->everfinishedcredits = js.milestones.everfinishcredits; + gamedata->eversavedreplay = js.milestones.eversavedreplay; + gamedata->everseenspecial = js.milestones.everseenspecial; + gamedata->chaokeytutorial = js.milestones.chaokeytutorial; + gamedata->majorkeyskipattempted = js.milestones.majorkeyskipattempted; + gamedata->finishedtutorialchallenge = js.milestones.finishedtutorialchallenge; + gamedata->enteredtutorialchallenge = js.milestones.enteredtutorialchallenge; + gamedata->gonerlevel = js.milestones.gonerlevel; gamedata->thisprisoneggpickup = js.prisons.thisprisoneggpickup; gamedata->prisoneggstothispickup = js.prisons.prisoneggstothispickup; diff --git a/src/g_gamedata.h b/src/g_gamedata.h index eb759fd59..385e83f38 100644 --- a/src/g_gamedata.h +++ b/src/g_gamedata.h @@ -59,9 +59,9 @@ struct GamedataChallengeKeysJson final NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataChallengeKeysJson, pendingkeyrounds, pendingkeyroundoffset, keyspending, chaokeys) }; -struct GamedataGonerJson final +struct GamedataMilestonesJson final { - uint32_t level; + uint32_t gonerlevel; bool everloadedaddon; bool everfinishcredits; bool eversavedreplay; @@ -72,8 +72,8 @@ struct GamedataGonerJson final bool enteredtutorialchallenge; NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT( - GamedataGonerJson, - level, + GamedataMilestonesJson, + gonerlevel, everloadedaddon, everfinishcredits, eversavedreplay, @@ -190,7 +190,7 @@ struct GamedataJson final GamedataRingsJson rings; GamedataRoundsJson rounds; GamedataChallengeKeysJson challengekeys; - GamedataGonerJson goner; + GamedataMilestonesJson milestones; GamedataPrisonEggPickupsJson prisons; uint32_t tafolderhash; std::vector emblems; @@ -210,7 +210,7 @@ struct GamedataJson final rings, rounds, challengekeys, - goner, + milestones, prisons, tafolderhash, emblems, From fdff7bbe9f3c7aa293bc3744077e0b6a7b3807e5 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Wed, 21 Feb 2024 18:20:00 -0600 Subject: [PATCH 28/33] Clean up risky default-init of gamedata structs --- src/g_gamedata.cpp | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/g_gamedata.cpp b/src/g_gamedata.cpp index 56a126e8e..6daf1f21a 100644 --- a/src/g_gamedata.cpp +++ b/src/g_gamedata.cpp @@ -42,7 +42,7 @@ void srb2::save_ng_gamedata() return; } - GamedataJson ng{}; + GamedataJson ng {}; ng.playtime.total = gamedata->totalplaytime; ng.rings.total = gamedata->totalrings; @@ -100,21 +100,21 @@ void srb2::save_ng_gamedata() ng.timesBeaten = gamedata->timesBeaten; for (int i = 0; i < numskins; i++) { - srb2::GamedataSkinJson skin; + srb2::GamedataSkinJson skin {}; std::string name = std::string(skins[i].name); skin.records.wins = skins[i].records.wins; - ng.skins[name] = skin; + ng.skins[name] = std::move(skin); } for (auto unloadedskin = unloadedskins; unloadedskin; unloadedskin = unloadedskin->next) { - srb2::GamedataSkinJson skin; + srb2::GamedataSkinJson skin {}; std::string name = std::string(unloadedskin->name); skin.records.wins = unloadedskin->records.wins; - ng.skins[name] = skin; + ng.skins[name] = std::move(skin); } for (int i = 0; i < nummapheaders; i++) { - srb2::GamedataMapJson map; + srb2::GamedataMapJson map {}; std::string lumpname = std::string(mapheaderinfo[i]->lumpname); map.visited.visited = mapheaderinfo[i]->records.mapvisited & MV_VISITED; map.visited.beaten = mapheaderinfo[i]->records.mapvisited & MV_BEATEN; @@ -125,11 +125,11 @@ void srb2::save_ng_gamedata() map.stats.timeattack.bestlap = mapheaderinfo[i]->records.lap; map.stats.spbattack.besttime = 0; map.stats.spbattack.bestlap = 0; - ng.maps[lumpname] = map; + ng.maps[lumpname] = std::move(map); } for (auto unloadedmap = unloadedmapheaders; unloadedmap; unloadedmap = unloadedmap->next) { - srb2::GamedataMapJson map; + srb2::GamedataMapJson map {}; std::string lumpname = std::string(unloadedmap->lumpname); map.visited.visited = unloadedmap->records.mapvisited & MV_VISITED; map.visited.beaten = unloadedmap->records.mapvisited & MV_BEATEN; @@ -140,11 +140,11 @@ void srb2::save_ng_gamedata() map.stats.timeattack.bestlap = unloadedmap->records.lap; map.stats.spbattack.besttime = 0; map.stats.spbattack.bestlap = 0; - ng.maps[lumpname] = map; + ng.maps[lumpname] = std::move(map); } for (int i = 0; i < gamedata->numspraycans; i++) { - srb2::GamedataSprayCanJson spraycan; + srb2::GamedataSprayCanJson spraycan {}; candata_t* can = &gamedata->spraycans[i]; @@ -172,7 +172,7 @@ void srb2::save_ng_gamedata() continue; } spraycan.map = std::string(mapheader->lumpname); - ng.spraycans.push_back(spraycan); + ng.spraycans.emplace_back(std::move(spraycan)); } for (auto cup = kartcupheaders; cup; cup = cup->next) { @@ -180,7 +180,7 @@ void srb2::save_ng_gamedata() { continue; } - srb2::GamedataCupJson cupdata; + srb2::GamedataCupJson cupdata {}; cupdata.name = std::string(cup->name); for (int i = 0; i < 4; i++) { @@ -189,7 +189,7 @@ void srb2::save_ng_gamedata() cupdata.records[i].bestskin = std::string(skins[cup->windata[i].best_skin.id].name); cupdata.records[i].emerald = cup->windata[i].got_emerald; } - ng.cups[cupdata.name] = cupdata; + ng.cups[cupdata.name] = std::move(cupdata); } for (auto unloadedcup = unloadedcupheaders; unloadedcup; unloadedcup = unloadedcup->next) { @@ -197,7 +197,7 @@ void srb2::save_ng_gamedata() { continue; } - srb2::GamedataCupJson cupdata; + srb2::GamedataCupJson cupdata {}; cupdata.name = std::string(unloadedcup->name); for (int i = 0; i < 4; i++) { @@ -206,12 +206,12 @@ void srb2::save_ng_gamedata() cupdata.records[i].bestskin = std::string(skins[unloadedcup->windata[i].best_skin.id].name); cupdata.records[i].emerald = unloadedcup->windata[i].got_emerald; } - ng.cups[cupdata.name] = cupdata; + ng.cups[cupdata.name] = std::move(cupdata); } - std::string gamedataname_s{gamedatafilename}; - fs::path savepath{fmt::format("{}/{}", srb2home, gamedataname_s)}; - fs::path tmpsavepath{fmt::format("{}/{}.tmp", srb2home, gamedataname_s)}; + std::string gamedataname_s {gamedatafilename}; + fs::path savepath {fmt::format("{}/{}", srb2home, gamedataname_s)}; + fs::path tmpsavepath {fmt::format("{}/{}.tmp", srb2home, gamedataname_s)}; json ngdata_json = ng; @@ -465,7 +465,7 @@ void srb2::load_ng_gamedata() } else { - gamedata->challengegrid = NULL; + gamedata->challengegrid = nullptr; } } From 4824b5d434c48ecfa5d1c19414081d066d03147c Mon Sep 17 00:00:00 2001 From: Eidolon Date: Wed, 21 Feb 2024 18:40:35 -0600 Subject: [PATCH 29/33] Allow cup records in gamedata to be flexibly-sized --- src/g_gamedata.cpp | 10 +++++----- src/g_gamedata.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/g_gamedata.cpp b/src/g_gamedata.cpp index 6daf1f21a..9268f6b98 100644 --- a/src/g_gamedata.cpp +++ b/src/g_gamedata.cpp @@ -182,7 +182,7 @@ void srb2::save_ng_gamedata() } srb2::GamedataCupJson cupdata {}; cupdata.name = std::string(cup->name); - for (int i = 0; i < 4; i++) + for (size_t i = 0; i < std::min(KARTGP_MAX, cupdata.records.size()); i++) { cupdata.records[i].bestgrade = cup->windata[i].best_grade; cupdata.records[i].bestplacement = cup->windata[i].best_placement; @@ -622,7 +622,7 @@ void srb2::load_ng_gamedata() for (auto& cuppair : js.cups) { - cupwindata_t dummywindata[4] {{}}; + std::array dummywindata {{}}; cupheader_t* cup = nullptr; // Find the loaded cup @@ -636,7 +636,7 @@ void srb2::load_ng_gamedata() } // Digest its data... - for (size_t j = 0; j < (size_t)KARTGP_MAX; j++) + for (size_t j = 0; j < std::min(KARTGP_MAX, cuppair.second.records.size()); j++) { dummywindata[j].best_placement = cuppair.second.records[j].bestplacement; dummywindata[j].best_grade = static_cast(cuppair.second.records[j].bestgrade); @@ -682,7 +682,7 @@ void srb2::load_ng_gamedata() { // We found a cup, so assign the windata. - memcpy(cup->windata, dummywindata, sizeof(cup->windata)); + memcpy(cup->windata, dummywindata.data(), sizeof(cup->windata)); } else if (dummywindata[0].best_placement != 0) { @@ -704,7 +704,7 @@ void srb2::load_ng_gamedata() unloadedcupheaders = unloadedcup; // Finally, copy into. - memcpy(unloadedcup->windata, dummywindata, sizeof(cup->windata)); + memcpy(unloadedcup->windata, dummywindata.data(), sizeof(cup->windata)); } } diff --git a/src/g_gamedata.h b/src/g_gamedata.h index 385e83f38..72fac373c 100644 --- a/src/g_gamedata.h +++ b/src/g_gamedata.h @@ -179,7 +179,7 @@ struct GamedataCupRecordsJson final struct GamedataCupJson final { std::string name; - std::array records; + std::vector records; NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataCupJson, name, records) }; From b1cf0207bfd619146340fd7d70555437e1334c05 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Wed, 21 Feb 2024 18:44:44 -0600 Subject: [PATCH 30/33] Remove unused _saveid fields from in-mem gamedata --- src/doomstat.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/doomstat.h b/src/doomstat.h index d0f8d35bf..204dce155 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -121,9 +121,6 @@ extern preciptype_t curWeather; struct skinrecord_t { UINT32 wins; - - // Purely assistive in gamedata save processes - UINT32 _saveid; }; struct unloaded_skin_t @@ -555,7 +552,6 @@ struct mapheader_t mobjtype_t destroyforchallenge[MAXDESTRUCTIBLES]; ///< Assistive for UCRP_MAPDESTROYOBJECTS UINT8 destroyforchallenge_size; ///< Number for above - UINT32 _saveid; ///< Purely assistive in gamedata save processes UINT16 cache_spraycan; ///< Cached Spraycan ID UINT16 cache_maplock; ///< Cached Unlockable ID From ec6e96ca4925a7dfcb1deedd5c1d9320125f8892 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Wed, 21 Feb 2024 18:44:58 -0600 Subject: [PATCH 31/33] Rename cup emerald field to gotemerald, make bool --- src/g_gamedata.cpp | 6 +++--- src/g_gamedata.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/g_gamedata.cpp b/src/g_gamedata.cpp index 9268f6b98..ca28d6a01 100644 --- a/src/g_gamedata.cpp +++ b/src/g_gamedata.cpp @@ -187,7 +187,7 @@ void srb2::save_ng_gamedata() cupdata.records[i].bestgrade = cup->windata[i].best_grade; cupdata.records[i].bestplacement = cup->windata[i].best_placement; cupdata.records[i].bestskin = std::string(skins[cup->windata[i].best_skin.id].name); - cupdata.records[i].emerald = cup->windata[i].got_emerald; + cupdata.records[i].gotemerald = cup->windata[i].got_emerald; } ng.cups[cupdata.name] = std::move(cupdata); } @@ -204,7 +204,7 @@ void srb2::save_ng_gamedata() cupdata.records[i].bestgrade = unloadedcup->windata[i].best_grade; cupdata.records[i].bestplacement = unloadedcup->windata[i].best_placement; cupdata.records[i].bestskin = std::string(skins[unloadedcup->windata[i].best_skin.id].name); - cupdata.records[i].emerald = unloadedcup->windata[i].got_emerald; + cupdata.records[i].gotemerald = unloadedcup->windata[i].got_emerald; } ng.cups[cupdata.name] = std::move(cupdata); } @@ -640,7 +640,7 @@ void srb2::load_ng_gamedata() { dummywindata[j].best_placement = cuppair.second.records[j].bestplacement; dummywindata[j].best_grade = static_cast(cuppair.second.records[j].bestgrade); - dummywindata[j].got_emerald = cuppair.second.records[j].emerald; + dummywindata[j].got_emerald = cuppair.second.records[j].gotemerald; dummywindata[j].best_skin.id = MAXSKINS; dummywindata[j].best_skin.unloaded = nullptr; diff --git a/src/g_gamedata.h b/src/g_gamedata.h index 72fac373c..d476f2e46 100644 --- a/src/g_gamedata.h +++ b/src/g_gamedata.h @@ -170,10 +170,10 @@ struct GamedataCupRecordsJson final { uint8_t bestplacement; uint8_t bestgrade; - uint8_t emerald; + bool gotemerald; std::string bestskin; - NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataCupRecordsJson, bestplacement, bestgrade, emerald, bestskin) + NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataCupRecordsJson, bestplacement, bestgrade, gotemerald, bestskin) }; struct GamedataCupJson final From 6dc6bb63a79bc862083d09b2310fbb49dd6347ae Mon Sep 17 00:00:00 2001 From: Eidolon Date: Wed, 21 Feb 2024 17:36:03 -0600 Subject: [PATCH 32/33] Play TIMENT for mode attack intermission --- src/g_game.c | 2 +- src/music.cpp | 14 ++++++++++++++ src/music.h | 4 ++++ src/s_sound.c | 2 +- src/y_inter.c | 4 +++- 5 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 3e69e344a..710a40a91 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1984,7 +1984,7 @@ void G_Ticker(boolean run) musiccountdown--; if (musiccountdown == 1) { - Music_Play("intermission"); + Music_PlayIntermission(); } else if (musiccountdown == MUSIC_COUNTDOWN_MAX - K_TallyDelay()) { diff --git a/src/music.cpp b/src/music.cpp index 4ed22d76c..953f20071 100644 --- a/src/music.cpp +++ b/src/music.cpp @@ -216,6 +216,20 @@ void Music_Play(const char* id) } } +void Music_PlayIntermission(void) +{ + // why aren't the ATTACK_ enums declared alongside modeattacking? + if (modeattacking != 0) + { + Music_Remap("intermission", "timent"); + } + else + { + Music_Remap("intermission", "racent"); + } + Music_Play("intermission"); +} + void Music_DelayEnd(const char* id, tic_t duration) { Tune* tune = g_tunes.find(id); diff --git a/src/music.h b/src/music.h index 2265639ea..9661ce056 100644 --- a/src/music.h +++ b/src/music.h @@ -59,6 +59,10 @@ const char *Music_CurrentId(void); // back to the start.) void Music_Play(const char *id); +// Same as Music_Play, but a convenience for remapping intermission +// based on game state. +void Music_PlayIntermission(void); + // Postpone the end of this tune until N tics from now. The // tune should already be playing before calling this. void Music_DelayEnd(const char *id, tic_t duration); diff --git a/src/s_sound.c b/src/s_sound.c index c3cf0a64e..265deef97 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -1217,7 +1217,7 @@ void S_AttemptToRestoreMusic(void) } // FALLTHRU case GS_INTERMISSION: - Music_Play("intermission"); + Music_PlayIntermission(); break; case GS_CEREMONY: Music_Play("level"); diff --git a/src/y_inter.c b/src/y_inter.c index 62c08ee29..26160eb7c 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -2132,7 +2132,9 @@ void Y_StartIntermission(void) G_SetGamestate(GS_INTERMISSION); if (musiccountdown == 0) - Music_Play("intermission"); + { + Music_PlayIntermission(); + } S_ShowMusicCredit(); // Always call From 31272cafa06774c017982b6534bae86dc14d6a54 Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Wed, 21 Feb 2024 21:55:08 -0700 Subject: [PATCH 33/33] AddMessage fixes --- src/k_hud.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/k_hud.cpp b/src/k_hud.cpp index acfa84f7b..7eb39841f 100644 --- a/src/k_hud.cpp +++ b/src/k_hud.cpp @@ -5874,6 +5874,7 @@ static void K_DrawMessageFeed(void) Draw::TextElement text(submsg); text.font(Draw::Font::kMenu); + submsg = text.parse(submsg).string(); UINT8 x = 160; UINT8 y = 10; @@ -5899,7 +5900,7 @@ static void K_DrawMessageFeed(void) if (i >= 1) y += BASEVIDHEIGHT / 2; } - UINT8 sw = text.width(); + UINT16 sw = text.width(); K_DrawSticker(x - sw/2, y, sw, 0, true); Draw(x, y+shift).align(Draw::Align::kCenter).text(text);