mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
Merge branch 'master' of https://git.do.srb2.org/KartKrew/Kart into separate-spb-attack-records
# Conflicts: # src/g_game.c
This commit is contained in:
commit
7e217b74f5
52 changed files with 2400 additions and 2113 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
155
src/d_netcmd.c
155
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 <graue@oceanbase.org>
|
||||
*/
|
||||
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 <http://www.ssntails.org>
|
||||
*/
|
||||
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;
|
||||
|
|
@ -3861,10 +3864,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,19 +3882,16 @@ 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)
|
||||
static void Got_Verification(const UINT8 **cp, INT32 playernum)
|
||||
{
|
||||
INT16 num = READUINT8(*cp);
|
||||
|
||||
|
|
@ -3917,10 +3913,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,19 +3925,16 @@ 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)
|
||||
static void Got_Removal(const UINT8 **cp, INT32 playernum)
|
||||
{
|
||||
UINT8 num = READUINT8(*cp);
|
||||
|
||||
|
|
@ -4224,7 +4213,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 +4277,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 +4469,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 +4528,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 +5624,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 +5646,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 +5721,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 +5767,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 +5783,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 +5813,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 +5835,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 +5878,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 +7114,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)*/)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -561,7 +558,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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -334,7 +334,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);
|
||||
}
|
||||
|
|
@ -3060,7 +3060,7 @@ void G_DoPlayDemo(const char *defdemoname)
|
|||
}
|
||||
|
||||
// net var data
|
||||
CV_LoadDemoVars(&demobuf.p);
|
||||
demobuf.p += CV_LoadDemoVars(demobuf.p);
|
||||
|
||||
memset(&grandprixinfo, 0, sizeof grandprixinfo);
|
||||
if ((demoflags & DF_GRANDPRIX))
|
||||
|
|
@ -3836,6 +3836,8 @@ boolean G_CheckDemoStatus(void)
|
|||
D_StartTitle();
|
||||
}
|
||||
|
||||
demo.attract = DEMO_ATTRACT_OFF;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
1117
src/g_game.c
1117
src/g_game.c
File diff suppressed because it is too large
Load diff
730
src/g_gamedata.cpp
Normal file
730
src/g_gamedata.cpp
Normal file
|
|
@ -0,0 +1,730 @@
|
|||
// 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 <algorithm>
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <filesystem>
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#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.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);
|
||||
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] = std::move(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] = std::move(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.timeattack.besttime = mapheaderinfo[i]->records.timeattack.time;
|
||||
map.stats.timeattack.bestlap = mapheaderinfo[i]->records.timeattack.lap;
|
||||
map.stats.spbattack.besttime = mapheaderinfo[i]->records.spbattack.time;
|
||||
map.stats.spbattack.bestlap = mapheaderinfo[i]->records.spbattack.lap;
|
||||
ng.maps[lumpname] = std::move(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.timeattack.besttime = unloadedmap->records.timeattack.time;
|
||||
map.stats.timeattack.bestlap = unloadedmap->records.timeattack.lap;
|
||||
map.stats.spbattack.besttime = unloadedmap->records.spbattack.time;
|
||||
map.stats.spbattack.bestlap = unloadedmap->records.spbattack.lap;
|
||||
ng.maps[lumpname] = std::move(map);
|
||||
}
|
||||
for (int i = 0; i < gamedata->numspraycans; i++)
|
||||
{
|
||||
srb2::GamedataSprayCanJson spraycan {};
|
||||
|
||||
candata_t* can = &gamedata->spraycans[i];
|
||||
|
||||
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)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
spraycan.map = std::string(mapheader->lumpname);
|
||||
ng.spraycans.emplace_back(std::move(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 (size_t i = 0; i < std::min<size_t>(KARTGP_MAX, cupdata.records.size()); 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].gotemerald = cup->windata[i].got_emerald;
|
||||
}
|
||||
ng.cups[cupdata.name] = std::move(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].gotemerald = unloadedcup->windata[i].got_emerald;
|
||||
}
|
||||
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)};
|
||||
|
||||
json ngdata_json = ng;
|
||||
|
||||
try
|
||||
{
|
||||
std::string tmpsavepathstring = tmpsavepath.string();
|
||||
srb2::io::FileStream file {tmpsavepathstring, srb2::io::FileStreamMode::kWrite};
|
||||
srb2::io::BufferedOutputStream<srb2::io::FileStream> bos {std::move(file)};
|
||||
|
||||
// The header is necessary to validate during loading.
|
||||
srb2::io::write(static_cast<uint32_t>(0xBA5ED321), bos); // major
|
||||
srb2::io::write(static_cast<uint8_t>(0), bos); // minor/flags
|
||||
srb2::io::write(static_cast<uint8_t>(gamedata->evercrashed), bos); // dirty (crash recovery)
|
||||
|
||||
std::vector<uint8_t> 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<srb2::io::FileStream> 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<std::byte> remainder = srb2::io::read_to_vec(bis);
|
||||
|
||||
GamedataJson js;
|
||||
try
|
||||
{
|
||||
// safety: std::byte repr is always uint8_t 1-byte aligned
|
||||
tcb::span<uint8_t> remainder_as_u8 = tcb::span((uint8_t*)remainder.data(), remainder.size());
|
||||
json parsed = json::from_ubjson(remainder_as_u8);
|
||||
js = parsed.template get<GamedataJson>();
|
||||
}
|
||||
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.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;
|
||||
|
||||
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<uint16_t*>(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<uint8_t>(gridvalue);
|
||||
}
|
||||
}
|
||||
|
||||
M_SanitiseChallengeGrid();
|
||||
}
|
||||
else
|
||||
{
|
||||
gamedata->challengegrid = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
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<unloaded_skin_t*>(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.timeattack.time = mappair.second.stats.timeattack.besttime;
|
||||
dummyrecord.timeattack.lap = mappair.second.stats.timeattack.bestlap;
|
||||
dummyrecord.spbattack.time = mappair.second.stats.spbattack.besttime;
|
||||
dummyrecord.spbattack.lap = mappair.second.stats.spbattack.bestlap;
|
||||
|
||||
if (mapnum < nummapheaders && mapheaderinfo[mapnum])
|
||||
{
|
||||
// Valid mapheader, time to populate with record data.
|
||||
|
||||
mapheaderinfo[mapnum]->records = dummyrecord;
|
||||
}
|
||||
else if (dummyrecord.mapvisited & MV_BEATEN
|
||||
|| dummyrecord.timeattack.time != 0 || dummyrecord.timeattack.lap != 0
|
||||
|| dummyrecord.spbattack.time != 0 || dummyrecord.spbattack.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<unloaded_mapheader_t*>(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<candata_t*>(Z_Malloc(
|
||||
(gamedata->numspraycans * sizeof(candata_t)),
|
||||
PU_STATIC, NULL));
|
||||
|
||||
for (size_t i = 0; i < gamedata->numspraycans; i++)
|
||||
{
|
||||
auto& can = js.spraycans[i];
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
gamedata->spraycans[i].map = NEXTMAP_INVALID;
|
||||
|
||||
UINT16 mapnum = NEXTMAP_INVALID;
|
||||
if (!can.map.empty())
|
||||
{
|
||||
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)
|
||||
{
|
||||
//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)
|
||||
{
|
||||
std::array<cupwindata_t, KARTGP_MAX> dummywindata {{}};
|
||||
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)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Digest its data...
|
||||
for (size_t j = 0; j < std::min<size_t>(KARTGP_MAX, cuppair.second.records.size()); j++)
|
||||
{
|
||||
dummywindata[j].best_placement = cuppair.second.records[j].bestplacement;
|
||||
dummywindata[j].best_grade = static_cast<gp_rank_e>(cuppair.second.records[j].bestgrade);
|
||||
dummywindata[j].got_emerald = cuppair.second.records[j].gotemerald;
|
||||
|
||||
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.data(), 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<unloaded_cupheader_t*>(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.data(), 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");
|
||||
}
|
||||
}
|
||||
245
src/g_gamedata.h
Normal file
245
src/g_gamedata.h
Normal file
|
|
@ -0,0 +1,245 @@
|
|||
// 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 <array>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
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 GamedataMilestonesJson final
|
||||
{
|
||||
uint32_t gonerlevel;
|
||||
bool everloadedaddon;
|
||||
bool everfinishcredits;
|
||||
bool eversavedreplay;
|
||||
bool everseenspecial;
|
||||
bool chaokeytutorial;
|
||||
bool majorkeyskipattempted;
|
||||
bool finishedtutorialchallenge;
|
||||
bool enteredtutorialchallenge;
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(
|
||||
GamedataMilestonesJson,
|
||||
gonerlevel,
|
||||
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<int16_t> 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 GamedataMapStatsTimeAttackJson final
|
||||
{
|
||||
uint32_t besttime;
|
||||
uint32_t 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
|
||||
{
|
||||
GamedataMapVisitedJson visited;
|
||||
GamedataMapStatsJson stats;
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataMapJson, visited, stats)
|
||||
};
|
||||
|
||||
struct GamedataSprayCanJson final
|
||||
{
|
||||
std::string map;
|
||||
std::string color;
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataSprayCanJson, map, color)
|
||||
};
|
||||
|
||||
struct GamedataCupRecordsJson final
|
||||
{
|
||||
uint8_t bestplacement;
|
||||
uint8_t bestgrade;
|
||||
bool gotemerald;
|
||||
std::string bestskin;
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataCupRecordsJson, bestplacement, bestgrade, gotemerald, bestskin)
|
||||
};
|
||||
|
||||
struct GamedataCupJson final
|
||||
{
|
||||
std::string name;
|
||||
std::vector<GamedataCupRecordsJson> records;
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataCupJson, name, records)
|
||||
};
|
||||
|
||||
struct GamedataJson final
|
||||
{
|
||||
GamedataPlaytimeJson playtime;
|
||||
GamedataRingsJson rings;
|
||||
GamedataRoundsJson rounds;
|
||||
GamedataChallengeKeysJson challengekeys;
|
||||
GamedataMilestonesJson milestones;
|
||||
GamedataPrisonEggPickupsJson prisons;
|
||||
uint32_t tafolderhash;
|
||||
std::vector<bool> emblems;
|
||||
std::vector<bool> unlockables;
|
||||
std::vector<bool> unlockpending;
|
||||
std::vector<bool> conditionsets;
|
||||
GamedataChallengeGridJson challengegrid;
|
||||
uint32_t timesBeaten;
|
||||
std::unordered_map<std::string, GamedataSkinJson> skins;
|
||||
std::unordered_map<std::string, GamedataMapJson> maps;
|
||||
std::vector<GamedataSprayCanJson> spraycans;
|
||||
std::unordered_map<std::string, GamedataCupJson> cups;
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(
|
||||
GamedataJson,
|
||||
playtime,
|
||||
rings,
|
||||
rounds,
|
||||
challengekeys,
|
||||
milestones,
|
||||
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
|
||||
|
|
@ -143,6 +143,7 @@ enum
|
|||
SHADER_FLOOR,
|
||||
SHADER_WALL,
|
||||
SHADER_SPRITE,
|
||||
SHADER_SPRITECLIPHACK,
|
||||
SHADER_MODEL, SHADER_MODEL_LIGHTING,
|
||||
SHADER_WATER,
|
||||
SHADER_FOG,
|
||||
|
|
|
|||
|
|
@ -3423,7 +3423,7 @@ static void HWR_SplitSprite(gl_vissprite_t *spr)
|
|||
|
||||
if (HWR_UseShader())
|
||||
{
|
||||
shader = SHADER_SPRITE;
|
||||
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 = SHADER_SPRITE;
|
||||
shader = (R_ThingIsPaperSprite(spr->mobj) || R_ThingIsFloorSprite(spr->mobj)) ? SHADER_SPRITE : SHADER_SPRITECLIPHACK;;
|
||||
blend |= PF_ColorMapped;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,11 +660,12 @@ static void Command_Shout(void)
|
|||
* \sa DoSayPacket
|
||||
* \author Graue <graue@oceanbase.org>
|
||||
*/
|
||||
static void Got_Saycmd(UINT8 **p, INT32 playernum)
|
||||
static void Got_Saycmd(const 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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -9,5 +9,160 @@
|
|||
|
||||
#include "streams.hpp"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
|
||||
template class srb2::io::ZlibInputStream<srb2::io::SpanStream>;
|
||||
template class srb2::io::ZlibInputStream<srb2::io::VecStream>;
|
||||
template class srb2::io::BufferedOutputStream<srb2::io::FileStream>;
|
||||
template class srb2::io::BufferedInputStream<srb2::io::FileStream>;
|
||||
|
||||
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<std::byte> 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<const std::byte> 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)
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
|
||||
file_ = nullptr;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,6 +47,9 @@ struct IsSeekableStream
|
|||
: public std::is_same<decltype(std::declval<T&>().seek(std::declval<SeekFrom>(), std::declval<StreamOffset>())),
|
||||
StreamSize> {};
|
||||
|
||||
template <typename T>
|
||||
struct IsFlushableStream : public std::is_same<decltype(std::declval<T&>().flush()), void> {};
|
||||
|
||||
template <typename T>
|
||||
struct IsStream : public std::disjunction<IsInputStream<T>, IsOutputStream<T>> {};
|
||||
|
||||
|
|
@ -60,6 +63,8 @@ inline constexpr const bool IsOutputStreamV = IsOutputStream<T>::value;
|
|||
template <typename T>
|
||||
inline constexpr const bool IsSeekableStreamV = IsSeekableStream<T>::value;
|
||||
template <typename T>
|
||||
inline constexpr const bool IsFlushableStreamV = IsFlushableStream<T>::value;
|
||||
template <typename T>
|
||||
inline constexpr const bool IsStreamV = IsStream<T>::value;
|
||||
template <typename T>
|
||||
inline constexpr const bool IsInputOutputStreamV = IsInputOutputStream<T>::value;
|
||||
|
|
@ -570,6 +575,54 @@ inline void read_exact(VecStream& stream, tcb::span<std::byte> 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<std::byte> buffer);
|
||||
StreamSize write(tcb::span<const std::byte> 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<SpanStream>;
|
||||
extern template class ZlibInputStream<VecStream>;
|
||||
|
||||
template <typename O,
|
||||
typename std::enable_if_t<IsOutputStreamV<O> && std::is_move_constructible_v<O> &&
|
||||
std::is_move_assignable_v<O>>* = nullptr>
|
||||
class BufferedOutputStream final
|
||||
{
|
||||
O inner_;
|
||||
std::vector<std::byte> buf_;
|
||||
tcb::span<const std::byte>::size_type cap_;
|
||||
|
||||
public:
|
||||
explicit BufferedOutputStream(O&& o) : inner_(std::forward<O>(o)), buf_(), cap_(8192) {}
|
||||
BufferedOutputStream(O&& o, tcb::span<const std::byte>::size_type capacity) : inner_(std::forward<O>(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<const std::byte> buffer)
|
||||
{
|
||||
StreamSize totalwritten = 0;
|
||||
while (buffer.size() > 0)
|
||||
{
|
||||
std::size_t tocopy = std::min(std::min(cap_, cap_ - buf_.size()), buffer.size());
|
||||
tcb::span<const std::byte> 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<const std::byte> writebuf = tcb::make_span(buf_);
|
||||
write_exact(inner_, writebuf);
|
||||
buf_.resize(0);
|
||||
}
|
||||
|
||||
O&& stream() noexcept
|
||||
{
|
||||
return std::move(inner_);
|
||||
}
|
||||
};
|
||||
|
||||
extern template class BufferedOutputStream<FileStream>;
|
||||
|
||||
template <typename I,
|
||||
typename std::enable_if_t<IsInputStreamV<I> && std::is_move_constructible_v<I> &&
|
||||
std::is_move_assignable_v<I>>* = nullptr>
|
||||
class BufferedInputStream final
|
||||
{
|
||||
I inner_;
|
||||
std::vector<std::byte> buf_;
|
||||
tcb::span<std::byte>::size_type cap_;
|
||||
|
||||
public:
|
||||
template <typename std::enable_if_t<std::is_default_constructible_v<I>>* = nullptr>
|
||||
BufferedInputStream() : inner_(), buf_(), cap_(8192) {}
|
||||
|
||||
explicit BufferedInputStream(I&& i) : inner_(std::forward<I>(i)), buf_(), cap_(8192) {}
|
||||
BufferedInputStream(I&& i, tcb::span<std::byte>::size_type capacity) : inner_(std::forward<I>(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<std::byte> 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<std::byte> 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<FileStream>;
|
||||
|
||||
// Utility functions
|
||||
|
||||
template <typename I, typename O>
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -30,11 +30,27 @@ return luaL_error(L, "HUD rendering code should not call this function!");
|
|||
|
||||
static consvar_t *this_cvar;
|
||||
|
||||
void Got_Luacmd(UINT8 **cp, INT32 playernum)
|
||||
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(const 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
|
||||
|
|
@ -47,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;
|
||||
|
|
@ -74,10 +89,17 @@ 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++)
|
||||
{
|
||||
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.
|
||||
|
|
@ -85,8 +107,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)
|
||||
|
|
@ -175,6 +196,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));
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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[]);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@
|
|||
#pragma GCC diagnostic ignored "-Wclobbered"
|
||||
#endif
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
#include <unistd.h>
|
||||
#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"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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<UFO*>(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_s3ka5);
|
||||
}
|
||||
|
||||
if (!battleovertime.enabled && ufo->extravalue1 <= 5*TICRATE)
|
||||
{
|
||||
Obj_PointPlayersToXY(mobj->x, mobj->y);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
1320
src/p_map.c
1320
src/p_map.c
File diff suppressed because it is too large
Load diff
|
|
@ -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++)
|
||||
|
|
|
|||
72
src/p_mobj.c
72
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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -6937,7 +6937,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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
25
src/p_user.c
25
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");
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
@ -1217,7 +1217,7 @@ void S_AttemptToRestoreMusic(void)
|
|||
}
|
||||
// FALLTHRU
|
||||
case GS_INTERMISSION:
|
||||
Music_Play("intermission");
|
||||
Music_PlayIntermission();
|
||||
break;
|
||||
case GS_CEREMONY:
|
||||
Music_Play("level");
|
||||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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"},
|
||||
|
|
|
|||
|
|
@ -2132,7 +2132,9 @@ void Y_StartIntermission(void)
|
|||
G_SetGamestate(GS_INTERMISSION);
|
||||
|
||||
if (musiccountdown == 0)
|
||||
Music_Play("intermission");
|
||||
{
|
||||
Music_PlayIntermission();
|
||||
}
|
||||
|
||||
S_ShowMusicCredit(); // Always call
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue