Merge branch 'next' into public_next

This commit is contained in:
Monster Iestyn 2017-05-31 15:09:37 +01:00
commit 5264f4ce08
17 changed files with 274 additions and 106 deletions

View file

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.0) cmake_minimum_required(VERSION 3.0)
project(SRB2 project(SRB2
VERSION 2.1.18 VERSION 2.1.19
LANGUAGES C) LANGUAGES C)
if(${PROJECT_SOURCE_DIR} MATCHES ${PROJECT_BINARY_DIR}) if(${PROJECT_SOURCE_DIR} MATCHES ${PROJECT_BINARY_DIR})

View file

@ -1,4 +1,4 @@
version: 2.1.18.{branch}-{build} version: 2.1.19.{branch}-{build}
os: MinGW os: MinGW
environment: environment:

View file

@ -511,13 +511,11 @@ OBJS:=$(i_main_o) \
# For reference, this is the command I use to build a srb2.pot file from the source code. # For reference, this is the command I use to build a srb2.pot file from the source code.
# (The listed source files are the ones containing translated strings). # (The listed source files are the ones containing translated strings).
# FILES=""; for file in `find ./ | grep "\.c" | grep -v svn`; do [ "`grep "M_GetText(" $file`" ] && FILES="$FILES $file"; done; xgettext -d srb2 -o locale/srb2.pot -kM_GetText -F --no-wrap $FILES # FILES=""; for file in `find ./ | grep "\.c" | grep -v svn`; do [ "`grep "M_GetText(" $file`" ] && FILES="$FILES $file"; done; xgettext -d srb2 -o locale/srb2.pot -kM_GetText -F --no-wrap $FILES
ifndef NOGETTEXT
ifdef GETTEXT ifdef GETTEXT
POS:=$(BIN)/en.mo POS:=$(BIN)/en.mo
OPTS+=-DGETTEXT OPTS+=-DGETTEXT
endif endif
endif
ifdef DJGPPDOS ifdef DJGPPDOS
all: pre-build $(BIN)/$(EXENAME) all: pre-build $(BIN)/$(EXENAME)

View file

@ -283,9 +283,6 @@ else
ifdef LINUX ifdef LINUX
NASMFORMAT=elf -DLINUX NASMFORMAT=elf -DLINUX
SDL=1 SDL=1
ifndef NOGETTEXT
GETTEXT=1
endif
ifdef LINUX64 ifdef LINUX64
OBJDIR:=$(OBJDIR)/Linux64 OBJDIR:=$(OBJDIR)/Linux64
BIN:=$(BIN)/Linux64 BIN:=$(BIN)/Linux64
@ -321,9 +318,6 @@ else
ifdef MINGW64 ifdef MINGW64
INTERFACE=win32 INTERFACE=win32
#NASMFORMAT=win64 #NASMFORMAT=win64
ifndef NOGETTEXT
#GETTEXT=1
endif
OBJDIR:=$(OBJDIR)/Mingw64 OBJDIR:=$(OBJDIR)/Mingw64
BIN:=$(BIN)/Mingw64 BIN:=$(BIN)/Mingw64
else else
@ -354,9 +348,6 @@ else
ifdef MINGW ifdef MINGW
INTERFACE=win32 INTERFACE=win32
NASMFORMAT=win32 NASMFORMAT=win32
ifndef NOGETTEXT
GETTEXT=1
endif
OBJDIR:=$(OBJDIR)/Mingw OBJDIR:=$(OBJDIR)/Mingw
BIN:=$(BIN)/Mingw BIN:=$(BIN)/Mingw
else else

View file

@ -1733,9 +1733,7 @@ static boolean CL_ServerConnectionSearchTicker(boolean viams, tic_t *asksent)
{ {
#ifndef NONET #ifndef NONET
INT32 i; INT32 i;
#endif
#ifndef NONET
// serverlist is updated by GetPacket function // serverlist is updated by GetPacket function
if (serverlistcount > 0) if (serverlistcount > 0)
{ {
@ -1769,7 +1767,20 @@ static boolean CL_ServerConnectionSearchTicker(boolean viams, tic_t *asksent)
serverlist[i].info.fileneeded); serverlist[i].info.fileneeded);
CONS_Printf(M_GetText("Checking files...\n")); CONS_Printf(M_GetText("Checking files...\n"));
i = CL_CheckFiles(); i = CL_CheckFiles();
if (i == 2) // cannot join for some reason if (i == 3) // too many files
{
D_QuitNetGame();
CL_Reset();
D_StartTitle();
M_StartMessage(M_GetText(
"You have too many WAD files loaded\n"
"to add ones the server is using.\n"
"Please restart SRB2 before connecting.\n\n"
"Press ESC\n"
), NULL, MM_NOTHING);
return false;
}
else if (i == 2) // cannot join for some reason
{ {
D_QuitNetGame(); D_QuitNetGame();
CL_Reset(); CL_Reset();
@ -3402,17 +3413,42 @@ static void HandlePacketFromAwayNode(SINT8 node)
if (node != servernode) if (node != servernode)
DEBFILE(va("Received packet from unknown host %d\n", node)); DEBFILE(va("Received packet from unknown host %d\n", node));
// macro for packets that should only be sent by the server
// if it is NOT from the server, bail out and close the connection!
#define SERVERONLY \
if (node != servernode) \
{ \
Net_CloseConnection(node); \
break; \
}
switch (netbuffer->packettype) switch (netbuffer->packettype)
{ {
case PT_ASKINFOVIAMS: case PT_ASKINFOVIAMS:
#if 0
if (server && serverrunning) if (server && serverrunning)
{ {
INT32 clientnode = I_NetMakeNode(netbuffer->u.msaskinfo.clientaddr); INT32 clientnode;
SV_SendServerInfo(clientnode, (tic_t)LONG(netbuffer->u.msaskinfo.time)); if (ms_RoomId < 0) // ignore if we're not actually on the MS right now
SV_SendPlayerInfo(clientnode); // Send extra info {
Net_CloseConnection(clientnode); Net_CloseConnection(node); // and yes, close connection
// Don't close connection to MS. return;
}
clientnode = I_NetMakeNode(netbuffer->u.msaskinfo.clientaddr);
if (clientnode != -1)
{
SV_SendServerInfo(clientnode, (tic_t)LONG(netbuffer->u.msaskinfo.time));
SV_SendPlayerInfo(clientnode); // Send extra info
Net_CloseConnection(clientnode);
// Don't close connection to MS...
}
else
Net_CloseConnection(node); // ...unless the IP address is not valid
} }
else
Net_CloseConnection(node); // you're not supposed to get it, so ignore it
#else
Net_CloseConnection(node);
#endif
break; break;
case PT_ASKINFO: case PT_ASKINFO:
@ -3420,8 +3456,8 @@ static void HandlePacketFromAwayNode(SINT8 node)
{ {
SV_SendServerInfo(node, (tic_t)LONG(netbuffer->u.askinfo.time)); SV_SendServerInfo(node, (tic_t)LONG(netbuffer->u.askinfo.time));
SV_SendPlayerInfo(node); // Send extra info SV_SendPlayerInfo(node); // Send extra info
Net_CloseConnection(node);
} }
Net_CloseConnection(node);
break; break;
case PT_SERVERREFUSE: // Negative response of client join request case PT_SERVERREFUSE: // Negative response of client join request
@ -3430,6 +3466,7 @@ static void HandlePacketFromAwayNode(SINT8 node)
Net_CloseConnection(node); Net_CloseConnection(node);
break; break;
} }
SERVERONLY
if (cl_mode == CL_WAITJOINRESPONSE) if (cl_mode == CL_WAITJOINRESPONSE)
{ {
// Save the reason so it can be displayed after quitting the netgame // Save the reason so it can be displayed after quitting the netgame
@ -3461,6 +3498,7 @@ static void HandlePacketFromAwayNode(SINT8 node)
Net_CloseConnection(node); Net_CloseConnection(node);
break; break;
} }
SERVERONLY
/// \note how would this happen? and is it doing the right thing if it does? /// \note how would this happen? and is it doing the right thing if it does?
if (cl_mode != CL_WAITJOINRESPONSE) if (cl_mode != CL_WAITJOINRESPONSE)
break; break;
@ -3524,13 +3562,18 @@ static void HandlePacketFromAwayNode(SINT8 node)
Net_CloseConnection(node); Net_CloseConnection(node);
break; break;
} }
else SERVERONLY
Got_Filetxpak(); Got_Filetxpak();
break; break;
case PT_REQUESTFILE: case PT_REQUESTFILE:
if (server) if (server)
Got_RequestFilePak(node); {
if (!cv_downloading.value || !Got_RequestFilePak(node))
Net_CloseConnection(node); // close connection if one of the requested files could not be sent, or you disabled downloading anyway
}
else
Net_CloseConnection(node); // nope
break; break;
case PT_NODETIMEOUT: case PT_NODETIMEOUT:
@ -3553,6 +3596,7 @@ static void HandlePacketFromAwayNode(SINT8 node)
break; // Ignore it break; // Ignore it
} }
#undef SERVERONLY
} }
/** Handles a packet received from a node that is in game /** Handles a packet received from a node that is in game
@ -3585,6 +3629,8 @@ FILESTAMP
{ {
// -------------------------------------------- SERVER RECEIVE ---------- // -------------------------------------------- SERVER RECEIVE ----------
case PT_RESYNCHGET: case PT_RESYNCHGET:
if (client)
break;
SV_AcknowledgeResynchAck(netconsole, netbuffer->u.resynchgot); SV_AcknowledgeResynchAck(netconsole, netbuffer->u.resynchgot);
break; break;
case PT_CLIENTCMD: case PT_CLIENTCMD:
@ -3651,7 +3697,8 @@ FILESTAMP
} }
// Splitscreen cmd // Splitscreen cmd
if (netbuffer->packettype == PT_CLIENT2CMD && nodetoplayer2[node] >= 0) if ((netbuffer->packettype == PT_CLIENT2CMD || netbuffer->packettype == PT_CLIENT2MIS)
&& nodetoplayer2[node] >= 0)
G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][(UINT8)nodetoplayer2[node]], G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][(UINT8)nodetoplayer2[node]],
&netbuffer->u.client2pak.cmd2, 1); &netbuffer->u.client2pak.cmd2, 1);
@ -3710,6 +3757,27 @@ FILESTAMP
tic_t tic = maketic; tic_t tic = maketic;
UINT8 *textcmd; UINT8 *textcmd;
// ignore if the textcmd has a reported size of zero
// this shouldn't be sent at all
if (!netbuffer->u.textcmd[0])
{
DEBFILE(va("GetPacket: Textcmd with size 0 detected! (node %u, player %d)\n",
node, netconsole));
Net_UnAcknowledgePacket(node);
break;
}
// ignore if the textcmd size var is actually larger than it should be
// BASEPACKETSIZE + 1 (for size) + textcmd[0] should == datalength
if (netbuffer->u.textcmd[0] > (size_t)doomcom->datalength-BASEPACKETSIZE-1)
{
DEBFILE(va("GetPacket: Bad Textcmd packet size! (expected %d, actual %s, node %u, player %d)\n",
netbuffer->u.textcmd[0], sizeu1((size_t)doomcom->datalength-BASEPACKETSIZE-1),
node, netconsole));
Net_UnAcknowledgePacket(node);
break;
}
// check if tic that we are making isn't too large else we cannot send it :( // check if tic that we are making isn't too large else we cannot send it :(
// doomcom->numslots+1 "+1" since doomcom->numslots can change within this time and sent time // doomcom->numslots+1 "+1" since doomcom->numslots can change within this time and sent time
j = software_MAXPACKETLENGTH j = software_MAXPACKETLENGTH
@ -3913,6 +3981,21 @@ FILESTAMP
case PT_SERVERCFG: case PT_SERVERCFG:
break; break;
case PT_FILEFRAGMENT: case PT_FILEFRAGMENT:
// Only accept PT_FILEFRAGMENT from the server.
if (node != servernode)
{
CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_FILEFRAGMENT", node);
if (server)
{
XBOXSTATIC UINT8 buf[2];
buf[0] = (UINT8)node;
buf[1] = KICK_MSG_CON_FAIL;
SendNetXCmd(XD_KICK, &buf, 2);
}
break;
}
if (client) if (client)
Got_Filetxpak(); Got_Filetxpak();
break; break;

View file

@ -711,6 +711,13 @@ void Net_CloseConnection(INT32 node)
#else #else
INT32 i; INT32 i;
boolean forceclose = (node & FORCECLOSE) != 0; boolean forceclose = (node & FORCECLOSE) != 0;
if (node == -1)
{
DEBFILE(M_GetText("Net_CloseConnection: node -1 detected!\n"));
return; // nope, just ignore it
}
node &= ~FORCECLOSE; node &= ~FORCECLOSE;
if (!node) if (!node)
@ -718,7 +725,7 @@ void Net_CloseConnection(INT32 node)
if (node < 0 || node >= MAXNETNODES) // prevent invalid nodes from crashing the game if (node < 0 || node >= MAXNETNODES) // prevent invalid nodes from crashing the game
{ {
CONS_Alert(CONS_WARNING, M_GetText("Net_CloseConnection: invalid node %d detected!\n"), node); DEBFILE(va(M_GetText("Net_CloseConnection: invalid node %d detected!\n"), node));
return; return;
} }

View file

@ -1569,8 +1569,13 @@ void D_MapChange(INT32 mapnum, INT32 newgametype, boolean pultmode, boolean rese
mapchangepending = 0; mapchangepending = 0;
// spawn the server if needed // spawn the server if needed
// reset players if there is a new one // reset players if there is a new one
if (!(adminplayer == consoleplayer) && SV_SpawnServer()) if (!(adminplayer == consoleplayer))
buf[0] &= ~(1<<1); {
if (SV_SpawnServer())
buf[0] &= ~(1<<1);
if (!Playing()) // you failed to start a server somehow, so cancel the map change
return;
}
// Kick bot from special stages // Kick bot from special stages
if (botskin) if (botskin)
@ -3078,7 +3083,13 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum)
filestatus_t ncs = FS_NOTFOUND; filestatus_t ncs = FS_NOTFOUND;
UINT8 md5sum[16]; UINT8 md5sum[16];
boolean kick = false; boolean kick = false;
boolean toomany = false;
INT32 i; INT32 i;
size_t packetsize = 0;
serverinfo_pak *dummycheck = NULL;
// Shut the compiler up.
(void)dummycheck;
READSTRINGN(*cp, filename, 240); READSTRINGN(*cp, filename, 240);
READMEM(*cp, md5sum, 16); READMEM(*cp, md5sum, 16);
@ -3104,13 +3115,25 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum)
return; return;
} }
ncs = findfile(filename,md5sum,true); // See W_LoadWadFile in w_wad.c
for (i = 0; i < numwadfiles; i++)
packetsize += nameonlylength(wadfiles[i]->filename) + 22;
if (ncs != FS_FOUND) packetsize += nameonlylength(filename) + 22;
if ((numwadfiles >= MAX_WADFILES)
|| (packetsize > sizeof(dummycheck->fileneeded)))
toomany = true;
else
ncs = findfile(filename,md5sum,true);
if (ncs != FS_FOUND || toomany)
{ {
char message[256]; char message[256];
if (ncs == FS_NOTFOUND) if (toomany)
sprintf(message, M_GetText("Too many files loaded to add %s\n"), filename);
else if (ncs == FS_NOTFOUND)
sprintf(message, M_GetText("The server doesn't have %s\n"), filename); sprintf(message, M_GetText("The server doesn't have %s\n"), filename);
else if (ncs == FS_MD5SUMBAD) else if (ncs == FS_MD5SUMBAD)
sprintf(message, M_GetText("Checksum mismatch on %s\n"), filename); sprintf(message, M_GetText("Checksum mismatch on %s\n"), filename);
@ -3180,10 +3203,15 @@ static void Got_Addfilecmd(UINT8 **cp, INT32 playernum)
ncs = findfile(filename,md5sum,true); ncs = findfile(filename,md5sum,true);
if (ncs != FS_FOUND) if (ncs != FS_FOUND || !P_AddWadFile(filename, NULL))
{ {
Command_ExitGame_f(); Command_ExitGame_f();
if (ncs == FS_NOTFOUND) if (ncs == FS_FOUND)
{
CONS_Printf(M_GetText("The server tried to add %s,\nbut you have too many files added.\nRestart the game to clear loaded files\nand play on this server."), filename);
M_StartMessage(va("The server added a file \n(%s)\nbut you have too many files added.\nRestart the game to clear loaded files.\n\nPress ESC\n",filename), NULL, MM_NOTHING);
}
else if (ncs == FS_NOTFOUND)
{ {
CONS_Printf(M_GetText("The server tried to add %s,\nbut you don't have this file.\nYou need to find it in order\nto play on this server."), filename); CONS_Printf(M_GetText("The server tried to add %s,\nbut you don't have this file.\nYou need to find it in order\nto play on this server."), filename);
M_StartMessage(va("The server added a file \n(%s)\nthat you do not have.\n\nPress ESC\n",filename), NULL, MM_NOTHING); M_StartMessage(va("The server added a file \n(%s)\nthat you do not have.\n\nPress ESC\n",filename), NULL, MM_NOTHING);
@ -3201,7 +3229,6 @@ static void Got_Addfilecmd(UINT8 **cp, INT32 playernum)
return; return;
} }
P_AddWadFile(filename, NULL);
G_SetGameModified(true); G_SetGameModified(true);
} }

View file

@ -62,7 +62,8 @@
#include <errno.h> #include <errno.h>
static void SV_SendFile(INT32 node, const char *filename, UINT8 fileid); // Prototypes
static boolean SV_SendFile(INT32 node, const char *filename, UINT8 fileid);
// Sender structure // Sender structure
typedef struct filetx_s typedef struct filetx_s
@ -303,7 +304,8 @@ boolean CL_SendRequestFile(void)
} }
// get request filepak and put it on the send queue // get request filepak and put it on the send queue
void Got_RequestFilePak(INT32 node) // returns false if a requested file was not found or cannot be sent
boolean Got_RequestFilePak(INT32 node)
{ {
char wad[MAX_WADPATH+1]; char wad[MAX_WADPATH+1];
UINT8 *p = netbuffer->u.textcmd; UINT8 *p = netbuffer->u.textcmd;
@ -314,8 +316,13 @@ void Got_RequestFilePak(INT32 node)
if (id == 0xFF) if (id == 0xFF)
break; break;
READSTRINGN(p, wad, MAX_WADPATH); READSTRINGN(p, wad, MAX_WADPATH);
SV_SendFile(node, wad, id); if (!SV_SendFile(node, wad, id))
{
SV_AbortSendFiles(node);
return false; // don't read the rest of the files
}
} }
return true; // no problems with any files
} }
/** Checks if the files needed aren't already loaded or on the disk /** Checks if the files needed aren't already loaded or on the disk
@ -330,6 +337,12 @@ INT32 CL_CheckFiles(void)
INT32 i, j; INT32 i, j;
char wadfilename[MAX_WADPATH]; char wadfilename[MAX_WADPATH];
INT32 ret = 1; INT32 ret = 1;
size_t packetsize = 0;
size_t filestoget = 0;
serverinfo_pak *dummycheck = NULL;
// Shut the compiler up.
(void)dummycheck;
// if (M_CheckParm("-nofiles")) // if (M_CheckParm("-nofiles"))
// return 1; // return 1;
@ -378,6 +391,10 @@ INT32 CL_CheckFiles(void)
return 1; return 1;
} }
// See W_LoadWadFile in w_wad.c
for (i = 0; i < numwadfiles; i++)
packetsize += nameonlylength(wadfiles[i]->filename) + 22;
for (i = 1; i < fileneedednum; i++) for (i = 1; i < fileneedednum; i++)
{ {
CONS_Debug(DBG_NETPLAY, "searching for '%s' ", fileneeded[i].filename); CONS_Debug(DBG_NETPLAY, "searching for '%s' ", fileneeded[i].filename);
@ -397,6 +414,14 @@ INT32 CL_CheckFiles(void)
if (fileneeded[i].status != FS_NOTFOUND || !fileneeded[i].important) if (fileneeded[i].status != FS_NOTFOUND || !fileneeded[i].important)
continue; continue;
packetsize += nameonlylength(fileneeded[i].filename) + 22;
if ((numwadfiles+filestoget >= MAX_WADFILES)
|| (packetsize > sizeof(dummycheck->fileneeded)))
return 3;
filestoget++;
fileneeded[i].status = findfile(fileneeded[i].filename, fileneeded[i].md5sum, true); fileneeded[i].status = findfile(fileneeded[i].filename, fileneeded[i].md5sum, true);
CONS_Debug(DBG_NETPLAY, "found %d\n", fileneeded[i].status); CONS_Debug(DBG_NETPLAY, "found %d\n", fileneeded[i].status);
if (fileneeded[i].status != FS_FOUND) if (fileneeded[i].status != FS_FOUND)
@ -480,7 +505,7 @@ static INT32 filestosend = 0;
* \sa SV_SendRam * \sa SV_SendRam
* *
*/ */
static void SV_SendFile(INT32 node, const char *filename, UINT8 fileid) static boolean SV_SendFile(INT32 node, const char *filename, UINT8 fileid)
{ {
filetx_t **q; // A pointer to the "next" field of the last file in the list filetx_t **q; // A pointer to the "next" field of the last file in the list
filetx_t *p; // The new file request filetx_t *p; // The new file request
@ -488,7 +513,7 @@ static void SV_SendFile(INT32 node, const char *filename, UINT8 fileid)
char wadfilename[MAX_WADPATH]; char wadfilename[MAX_WADPATH];
if (cv_noticedownload.value) if (cv_noticedownload.value)
CONS_Printf("Sending file \"%s\" to node %d\n", filename, node); CONS_Printf("Sending file \"%s\" to node %d (%s)\n", filename, node, I_GetNodeAddress(node));
// Find the last file in the list and set a pointer to its "next" field // Find the last file in the list and set a pointer to its "next" field
q = &transfer[node].txlist; q = &transfer[node].txlist;
@ -537,7 +562,7 @@ static void SV_SendFile(INT32 node, const char *filename, UINT8 fileid)
free(p->id.filename); free(p->id.filename);
free(p); free(p);
*q = NULL; *q = NULL;
return; return false; // cancel the rest of the requests
} }
// Handle huge file requests (i.e. bigger than cv_maxsend.value KB) // Handle huge file requests (i.e. bigger than cv_maxsend.value KB)
@ -549,7 +574,7 @@ static void SV_SendFile(INT32 node, const char *filename, UINT8 fileid)
free(p->id.filename); free(p->id.filename);
free(p); free(p);
*q = NULL; *q = NULL;
return; return false; // cancel the rest of the requests
} }
DEBFILE(va("Sending file %s (id=%d) to %d\n", filename, fileid, node)); DEBFILE(va("Sending file %s (id=%d) to %d\n", filename, fileid, node));
@ -557,6 +582,7 @@ static void SV_SendFile(INT32 node, const char *filename, UINT8 fileid)
p->fileid = fileid; p->fileid = fileid;
p->next = NULL; // End of list p->next = NULL; // End of list
filestosend++; filestosend++;
return true;
} }
/** Adds a memory block to the file list for a node /** Adds a memory block to the file list for a node

View file

@ -69,7 +69,7 @@ boolean SV_SendingFile(INT32 node);
boolean CL_CheckDownloadable(void); boolean CL_CheckDownloadable(void);
boolean CL_SendRequestFile(void); boolean CL_SendRequestFile(void);
void Got_RequestFilePak(INT32 node); boolean Got_RequestFilePak(INT32 node);
void SV_AbortSendFiles(INT32 node); void SV_AbortSendFiles(INT32 node);
void CloseNetFile(void); void CloseNetFile(void);

View file

@ -150,9 +150,9 @@ extern FILE *logstream;
// we use comprevision and compbranch instead. // we use comprevision and compbranch instead.
#else #else
#define VERSION 201 // Game version #define VERSION 201 // Game version
#define SUBVERSION 18 // more precise version number #define SUBVERSION 19 // more precise version number
#define VERSIONSTRING "v2.1.18" #define VERSIONSTRING "v2.1.19"
#define VERSIONSTRINGW L"v2.1.18" #define VERSIONSTRINGW L"v2.1.19"
// Hey! If you change this, add 1 to the MODVERSION below! // Hey! If you change this, add 1 to the MODVERSION below!
// Otherwise we can't force updates! // Otherwise we can't force updates!
#endif #endif
@ -214,7 +214,7 @@ extern FILE *logstream;
// it's only for detection of the version the player is using so the MS can alert them of an update. // it's only for detection of the version the player is using so the MS can alert them of an update.
// Only set it higher, not lower, obviously. // Only set it higher, not lower, obviously.
// Note that we use this to help keep internal testing in check; this is why v2.1.0 is not version "1". // Note that we use this to help keep internal testing in check; this is why v2.1.0 is not version "1".
#define MODVERSION 23 #define MODVERSION 24
// ========================================================================= // =========================================================================

View file

@ -16,84 +16,118 @@
#include "lua_script.h" #include "lua_script.h"
#include "lua_libs.h" #include "lua_libs.h"
#define META_ITERATIONSTATE "iteration state"
static const char *const iter_opt[] = { static const char *const iter_opt[] = {
"all", "all",
"mobj", "mobj",
NULL}; NULL};
static const actionf_p1 iter_funcs[] = {
NULL,
(actionf_p1)P_MobjThinker
};
struct iterationState {
actionf_p1 filter;
int next;
};
static int iterationState_gc(lua_State *L)
{
struct iterationState *it = luaL_checkudata(L, -1, META_ITERATIONSTATE);
if (it->next != LUA_REFNIL)
{
luaL_unref(L, LUA_REGISTRYINDEX, it->next);
it->next = LUA_REFNIL;
}
return 0;
}
#define push_thinker(th) {\
if ((th)->function.acp1 == (actionf_p1)P_MobjThinker) \
LUA_PushUserdata(L, (th), META_MOBJ); \
else \
lua_pushlightuserdata(L, (th)); \
}
static int lib_iterateThinkers(lua_State *L) static int lib_iterateThinkers(lua_State *L)
{ {
int state = luaL_checkoption(L, 1, "mobj", iter_opt); thinker_t *th = NULL, *next = NULL;
struct iterationState *it = luaL_checkudata(L, 1, META_ITERATIONSTATE);
thinker_t *th = NULL;
actionf_p1 searchFunc;
const char *searchMeta;
lua_settop(L, 2); lua_settop(L, 2);
lua_remove(L, 1); // remove state now.
switch(state) if (lua_isnil(L, 2))
th = &thinkercap;
else if (lua_isuserdata(L, 2))
{ {
case 0: if (lua_islightuserdata(L, 2))
searchFunc = NULL; th = lua_touserdata(L, 2);
searchMeta = NULL; else
break; {
case 1: th = *(thinker_t **)lua_touserdata(L, -1);
default: if (!th)
searchFunc = (actionf_p1)P_MobjThinker; {
searchMeta = META_MOBJ; if (it->next == LUA_REFNIL)
break; return 0;
lua_rawgeti(L, LUA_REGISTRYINDEX, it->next);
if (lua_islightuserdata(L, -1))
next = lua_touserdata(L, -1);
else
next = *(thinker_t **)lua_touserdata(L, -1);
}
}
} }
if (!lua_isnil(L, 1)) { luaL_unref(L, LUA_REGISTRYINDEX, it->next);
if (lua_islightuserdata(L, 1)) it->next = LUA_REFNIL;
th = (thinker_t *)lua_touserdata(L, 1);
else if (searchMeta)
th = *((thinker_t **)luaL_checkudata(L, 1, searchMeta));
else
th = *((thinker_t **)lua_touserdata(L, 1));
} else
th = &thinkercap;
if (!th) // something got our userdata invalidated! if (th && !next)
return 0; next = th->next;
if (!next)
return luaL_error(L, "next thinker invalidated during iteration");
if (searchFunc == NULL) for (; next != &thinkercap; next = next->next)
{ if (!it->filter || next->function.acp1 == it->filter)
if ((th = th->next) != &thinkercap)
{ {
if (th->function.acp1 == (actionf_p1)P_MobjThinker) push_thinker(next);
LUA_PushUserdata(L, th, META_MOBJ); if (next->next != &thinkercap)
else {
lua_pushlightuserdata(L, th); push_thinker(next->next);
it->next = luaL_ref(L, LUA_REGISTRYINDEX);
}
return 1; return 1;
} }
return 0;
}
for (th = th->next; th != &thinkercap; th = th->next)
{
if (th->function.acp1 != searchFunc)
continue;
LUA_PushUserdata(L, th, searchMeta);
return 1;
}
return 0; return 0;
} }
static int lib_startIterate(lua_State *L) static int lib_startIterate(lua_State *L)
{ {
luaL_checkoption(L, 1, iter_opt[0], iter_opt); struct iterationState *it;
lua_pushcfunction(L, lib_iterateThinkers);
lua_pushvalue(L, 1); lua_pushvalue(L, lua_upvalueindex(1));
it = lua_newuserdata(L, sizeof(struct iterationState));
luaL_getmetatable(L, META_ITERATIONSTATE);
lua_setmetatable(L, -2);
it->filter = iter_funcs[luaL_checkoption(L, 1, "mobj", iter_opt)];
it->next = LUA_REFNIL;
return 2; return 2;
} }
#undef push_thinker
int LUA_ThinkerLib(lua_State *L) int LUA_ThinkerLib(lua_State *L)
{ {
luaL_newmetatable(L, META_ITERATIONSTATE);
lua_pushcfunction(L, iterationState_gc);
lua_setfield(L, -2, "__gc");
lua_pop(L, 1);
lua_createtable(L, 0, 1); lua_createtable(L, 0, 1);
lua_pushcfunction(L, lib_startIterate); lua_pushcfunction(L, lib_iterateThinkers);
lua_pushcclosure(L, lib_startIterate, 1);
lua_setfield(L, -2, "iterate"); lua_setfield(L, -2, "iterate");
lua_setglobal(L, "thinkers"); lua_setglobal(L, "thinkers");
return 0; return 0;

View file

@ -2363,7 +2363,7 @@ static boolean P_ZMovement(mobj_t *mo)
mo->z = mo->floorz; mo->z = mo->floorz;
#ifdef ESLOPE #ifdef ESLOPE
if (mo->standingslope) // You're still on the ground; why are we here? if (!(mo->flags & MF_MISSILE) && mo->standingslope) // You're still on the ground; why are we here?
{ {
mo->momz = 0; mo->momz = 0;
return true; return true;
@ -7807,6 +7807,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
break; break;
case MT_EGGCAPSULE: case MT_EGGCAPSULE:
mobj->extravalue1 = -1; // timer for how long a player has been at the capsule mobj->extravalue1 = -1; // timer for how long a player has been at the capsule
break;
case MT_REDTEAMRING: case MT_REDTEAMRING:
mobj->color = skincolor_redteam; mobj->color = skincolor_redteam;
break; break;

View file

@ -1214,7 +1214,7 @@
C01FCF4B08A954540054247B /* Debug */ = { C01FCF4B08A954540054247B /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CURRENT_PROJECT_VERSION = 2.1.18; CURRENT_PROJECT_VERSION = 2.1.19;
GCC_PREPROCESSOR_DEFINITIONS = ( GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)", "$(inherited)",
NORMALSRB2, NORMALSRB2,
@ -1226,7 +1226,7 @@
C01FCF4C08A954540054247B /* Release */ = { C01FCF4C08A954540054247B /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CURRENT_PROJECT_VERSION = 2.1.18; CURRENT_PROJECT_VERSION = 2.1.19;
GCC_ENABLE_FIX_AND_CONTINUE = NO; GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_PREPROCESSOR_DEFINITIONS = ( GCC_PREPROCESSOR_DEFINITIONS = (

View file

@ -1214,7 +1214,7 @@
C01FCF4B08A954540054247B /* Debug */ = { C01FCF4B08A954540054247B /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CURRENT_PROJECT_VERSION = 2.1.18; CURRENT_PROJECT_VERSION = 2.1.19;
GCC_PREPROCESSOR_DEFINITIONS = ( GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)", "$(inherited)",
NORMALSRB2, NORMALSRB2,
@ -1226,7 +1226,7 @@
C01FCF4C08A954540054247B /* Release */ = { C01FCF4C08A954540054247B /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CURRENT_PROJECT_VERSION = 2.1.18; CURRENT_PROJECT_VERSION = 2.1.19;
GCC_ENABLE_FIX_AND_CONTINUE = NO; GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_PREPROCESSOR_DEFINITIONS = ( GCC_PREPROCESSOR_DEFINITIONS = (

View file

@ -180,9 +180,9 @@ static LPSTR hms(UINT seconds)
hours = minutes / 60; hours = minutes / 60;
minutes %= 60; minutes %= 60;
if (hours > 0) if (hours > 0)
sprintf (s, "%lu:%02lu:%02lu", hours, minutes, seconds); sprintf (s, "%lu:%02lu:%02lu", (long unsigned int)hours, (long unsigned int)minutes, (long unsigned int)seconds);
else else
sprintf (s, "%2lu:%02lu", minutes, seconds); sprintf (s, "%2lu:%02lu", (long unsigned int)minutes, (long unsigned int)seconds);
return s; return s;
} }

View file

@ -470,7 +470,7 @@ static inline BOOL tlErrorMessage(const TCHAR *err)
// //
// warn user if there is one // warn user if there is one
// //
printf("Error %Ts..\n", err); printf("Error %s..\n", err);
fflush(stdout); fflush(stdout);
MessageBox(hWndMain, err, TEXT("ERROR"), MB_OK); MessageBox(hWndMain, err, TEXT("ERROR"), MB_OK);

View file

@ -965,7 +965,8 @@ void Y_StartIntermission(void)
} }
// We couldn't display the intermission even if we wanted to. // We couldn't display the intermission even if we wanted to.
if (dedicated) return; // But we still need to give the players their score bonuses, dummy.
//if (dedicated) return;
// This should always exist, but just in case... // This should always exist, but just in case...
if(!mapheaderinfo[prevmap]) if(!mapheaderinfo[prevmap])