Merge remote-tracking branch 'upstream/next' into viewroll

This commit is contained in:
fickleheart 2020-01-26 18:01:58 -06:00
commit bea7ad2185
34 changed files with 769 additions and 667 deletions

View File

@ -83,7 +83,14 @@ before_build:
- ccache -V
- ccache -s
- if [%NOUPX%] == [1] ( set "NOUPX=NOUPX=1" ) else ( set "NOUPX=" )
- set "SRB2_MFLAGS=-C src WARNINGMODE=1 CCACHE=1 NOOBJDUMP=1 %NOUPX%"
- if defined [%APPVEYOR_PULL_REQUEST_HEAD_COMMIT%] ( set "COMMIT=%APPVEYOR_PULL_REQUEST_HEAD_COMMIT%" ) else ( set "COMMIT=%APPVEYOR_REPO_COMMIT%" )
- cmd: git rev-parse --short %COMMIT%>%TMP%/gitshort.txt
- cmd: set /P GITSHORT=<%TMP%/gitshort.txt
# for pull requests, take the owner's name only, if this isn't the same repo of course
- set "REPO=%APPVEYOR_REPO_BRANCH%"
- if not [%APPVEYOR_PULL_REQUEST_HEAD_REPO_NAME%] == [] ( if not [%APPVEYOR_PULL_REQUEST_HEAD_REPO_NAME%] == [%APPVEYOR_REPO_NAME%] ( for /f "delims=/" %%a in ("%APPVEYOR_PULL_REQUEST_HEAD_REPO_NAME%") do set "REPO=%%a-%APPVEYOR_PULL_REQUEST_HEAD_REPO_BRANCH%" ) )
- set "EXENAME=EXENAME=srb2win-%REPO%-%GITSHORT%.exe"
- set "SRB2_MFLAGS=-C src WARNINGMODE=1 CCACHE=1 NOOBJDUMP=1 %NOUPX% %EXENAME%"
- if [%X86_64%] == [1] ( set "MINGW_FLAGS=MINGW64=1 X86_64=1 GCC81=1" ) else ( set "MINGW_FLAGS=MINGW=1 GCC91=1" )
- set "SRB2_MFLAGS=%SRB2_MFLAGS% %MINGW_FLAGS% %CONFIGURATION%=1"
@ -99,10 +106,8 @@ after_build:
)
- if [%X86_64%] == [1] ( set "CONFIGURATION=%CONFIGURATION%64" )
- ccache -s
- cmd: git rev-parse --short %APPVEYOR_REPO_COMMIT%>%TMP%/gitshort.txt
- cmd: set /P GITSHORT=<%TMP%/gitshort.txt
- set BUILD_ARCHIVE=%APPVEYOR_REPO_BRANCH%-%GITSHORT%-%CONFIGURATION%.7z
- set BUILDSARCHIVE=%APPVEYOR_REPO_BRANCH%-%CONFIGURATION%.7z
- set BUILD_ARCHIVE=%REPO%-%GITSHORT%-%CONFIGURATION%.7z
- set BUILDSARCHIVE=%REPO%-%CONFIGURATION%.7z
- cmd: 7z a %BUILD_ARCHIVE% %BUILD_PATH% -xr!.gitignore
- appveyor PushArtifact %BUILD_ARCHIVE%
- cmd: copy %BUILD_ARCHIVE% %BUILDSARCHIVE%

View File

@ -1458,7 +1458,7 @@ static void Got_NetVar(UINT8 **p, INT32 playernum)
// not from server or remote admin, must be hacked/buggy client
CONS_Alert(CONS_WARNING, M_GetText("Illegal netvar command received from %s\n"), player_names[playernum]);
if (server)
SendKick(playernum, KICK_MSG_CON_FAIL);
SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
return;
}
netid = READUINT16(*p);

View File

@ -21,6 +21,7 @@
#include "d_net.h"
#include "d_main.h"
#include "g_game.h"
#include "st_stuff.h"
#include "hu_stuff.h"
#include "keys.h"
#include "g_input.h" // JOY1
@ -76,6 +77,7 @@ char motd[254], server_context[8]; // Message of the Day, Unique Context (even w
// Server specific vars
UINT8 playernode[MAXPLAYERS];
char playeraddress[MAXPLAYERS][64];
// Minimum timeout for sending the savegame
// The actual timeout will be longer depending on the savegame length
@ -391,7 +393,7 @@ static void ExtraDataTicker(void)
{
if (server)
{
SendKick(i, KICK_MSG_CON_FAIL);
SendKick(i, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
DEBFILE(va("player %d kicked [gametic=%u] reason as follows:\n", i, gametic));
}
CONS_Alert(CONS_WARNING, M_GetText("Got unknown net command [%s]=%d (max %d)\n"), sizeu1(curpos - bufferstart), *curpos, bufferstart[0]);
@ -437,6 +439,9 @@ void SendKick(UINT8 playernum, UINT8 msg)
{
UINT8 buf[2];
if (!(server && cv_rejointimeout.value))
msg &= ~KICK_MSG_KEEP_BODY;
buf[0] = playernum;
buf[1] = msg;
SendNetXCmd(XD_KICK, &buf, 2);
@ -1058,7 +1063,7 @@ static void SV_SendResynch(INT32 node)
if (resynch_score[node] > (unsigned)cv_resynchattempts.value*250)
{
SendKick(nodetoplayer[node], KICK_MSG_CON_FAIL);
SendKick(nodetoplayer[node], KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
resynch_score[node] = 0;
}
}
@ -2413,6 +2418,7 @@ void CL_ClearPlayer(INT32 playernum)
if (players[playernum].mo)
P_RemoveMobj(players[playernum].mo);
memset(&players[playernum], 0, sizeof (player_t));
memset(playeraddress[playernum], 0, sizeof(*playeraddress));
}
//
@ -2420,7 +2426,7 @@ void CL_ClearPlayer(INT32 playernum)
//
// Removes a player from the current game
//
static void CL_RemovePlayer(INT32 playernum, INT32 reason)
static void CL_RemovePlayer(INT32 playernum, kickreason_t reason)
{
// Sanity check: exceptional cases (i.e. c-fails) can cause multiple
// kick commands to be issued for the same player.
@ -2433,9 +2439,6 @@ static void CL_RemovePlayer(INT32 playernum, INT32 reason)
playerpernode[node]--;
if (playerpernode[node] <= 0)
{
// If a resynch was in progress, well, it no longer needs to be.
SV_InitResynchVars(playernode[playernum]);
nodeingame[playernode[playernum]] = false;
Net_CloseConnection(playernode[playernum]);
ResetNode(node);
@ -2557,6 +2560,7 @@ void CL_Reset(void)
multiplayer = false;
servernode = 0;
server = true;
resynch_local_inprogress = false;
doomcom->numnodes = 1;
doomcom->numslots = 1;
SV_StopServer();
@ -2830,9 +2834,12 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum)
char buf[3 + MAX_REASONLENGTH];
char *reason = buf;
kickreason_t kickreason = KR_KICK;
boolean keepbody;
pnum = READUINT8(*p);
msg = READUINT8(*p);
keepbody = (msg & KICK_MSG_KEEP_BODY) != 0;
msg &= ~KICK_MSG_KEEP_BODY;
if (pnum == serverplayer && IsPlayerAdmin(playernum))
{
@ -2892,6 +2899,7 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum)
*/
pnum = playernum;
msg = KICK_MSG_CON_FAIL;
keepbody = true;
}
//CONS_Printf("\x82%s ", player_names[pnum]);
@ -2911,7 +2919,8 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum)
switch (msg)
{
case KICK_MSG_GO_AWAY:
HU_AddChatText(va("\x82*%s has been kicked (Go away)", player_names[pnum]), false);
if (!players[pnum].quittime)
HU_AddChatText(va("\x82*%s has been kicked (Go away)", player_names[pnum]), false);
kickreason = KR_KICK;
break;
case KICK_MSG_PING_HIGH:
@ -2960,7 +2969,7 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum)
kickreason = KR_TIMEOUT;
break;
case KICK_MSG_PLAYER_QUIT:
if (netgame) // not splitscreen/bots
if (netgame && !players[pnum].quittime) // not splitscreen/bots or soulless body
HU_AddChatText(va("\x82*%s left the game", player_names[pnum]), false);
kickreason = KR_LEAVE;
break;
@ -3001,6 +3010,24 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum)
else
M_StartMessage(M_GetText("You have been kicked by the server\n\nPress ESC\n"), NULL, MM_NOTHING);
}
else if (keepbody)
{
if (server && !demoplayback)
{
INT32 node = playernode[pnum];
playerpernode[node]--;
if (playerpernode[node] <= 0)
{
nodeingame[node] = false;
Net_CloseConnection(node);
ResetNode(node);
}
}
playernode[pnum] = UINT8_MAX;
players[pnum].quittime = 1;
}
else
CL_RemovePlayer(pnum, kickreason);
}
@ -3009,6 +3036,9 @@ consvar_t cv_allownewplayer = {"allowjoin", "On", CV_NETVAR, CV_OnOff, NULL, 0,
consvar_t cv_joinnextround = {"joinnextround", "Off", CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; /// \todo not done
static CV_PossibleValue_t maxplayers_cons_t[] = {{2, "MIN"}, {32, "MAX"}, {0, NULL}};
consvar_t cv_maxplayers = {"maxplayers", "8", CV_SAVE, maxplayers_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
static CV_PossibleValue_t rejointimeout_cons_t[] = {{1, "MIN"}, {60 * FRACUNIT, "MAX"}, {0, "Off"}, {0, NULL}};
consvar_t cv_rejointimeout = {"rejointimeout", "Off", CV_SAVE|CV_FLOAT, rejointimeout_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
static CV_PossibleValue_t resynchattempts_cons_t[] = {{1, "MIN"}, {20, "MAX"}, {0, "No"}, {0, NULL}};
consvar_t cv_resynchattempts = {"resynchattempts", "10", CV_SAVE, resynchattempts_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL };
consvar_t cv_blamecfail = {"blamecfail", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL };
@ -3078,6 +3108,7 @@ static void ResetNode(INT32 node)
nodewaiting[node] = 0;
playerpernode[node] = 0;
sendingsavegame[node] = false;
SV_InitResynchVars(node);
}
void SV_ResetServer(void)
@ -3093,13 +3124,8 @@ void SV_ResetServer(void)
tictoclear = maketic;
for (i = 0; i < MAXNETNODES; i++)
{
ResetNode(i);
// Make sure resynch status doesn't get carried over!
SV_InitResynchVars(i);
}
for (i = 0; i < MAXPLAYERS; i++)
{
#ifdef HAVE_BLUA
@ -3107,6 +3133,7 @@ void SV_ResetServer(void)
#endif
playeringame[i] = false;
playernode[i] = UINT8_MAX;
memset(playeraddress[i], 0, sizeof(*playeraddress));
sprintf(player_names[i], "Player %d", i + 1);
adminplayers[i] = -1; // Populate the entire adminplayers array with -1.
}
@ -3197,6 +3224,37 @@ void D_QuitNetGame(void)
#endif
}
static INT32 FindRejoinerNum(SINT8 node)
{
char strippednodeaddress[64];
const char *nodeaddress;
char *port;
INT32 i;
// Make sure there is no dead dress before proceeding to the stripping
if (!I_GetNodeAddress)
return -1;
nodeaddress = I_GetNodeAddress(node);
if (!nodeaddress)
return -1;
// Strip the address of its port
strcpy(strippednodeaddress, nodeaddress);
port = strchr(strippednodeaddress, ':');
if (port)
*port = '\0';
// Check if any player matches the stripped address
for (i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i] && playeraddress[i][0] && playernode[i] == UINT8_MAX
&& !strcmp(playeraddress[i], strippednodeaddress))
return i;
}
return -1;
}
// Adds a node to the game (player will follow at map change or at savegame....)
static inline void SV_AddNode(INT32 node)
{
@ -3213,13 +3271,16 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum)
{
INT16 node, newplayernum;
boolean splitscreenplayer;
boolean rejoined;
player_t *newplayer;
char *port;
if (playernum != serverplayer && !IsPlayerAdmin(playernum))
{
// protect against hacked/buggy client
CONS_Alert(CONS_WARNING, M_GetText("Illegal add player command received from %s\n"), player_names[playernum]);
if (server)
SendKick(playernum, KICK_MSG_CON_FAIL);
SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
return;
}
@ -3228,15 +3289,34 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum)
splitscreenplayer = newplayernum & 0x80;
newplayernum &= ~0x80;
// Clear player before joining, lest some things get set incorrectly
// HACK: don't do this for splitscreen, it relies on preset values
if (!splitscreen && !botingame)
CL_ClearPlayer(newplayernum);
playeringame[newplayernum] = true;
rejoined = playeringame[newplayernum];
if (!rejoined)
{
// Clear player before joining, lest some things get set incorrectly
// HACK: don't do this for splitscreen, it relies on preset values
if (!splitscreen && !botingame)
CL_ClearPlayer(newplayernum);
playeringame[newplayernum] = true;
G_AddPlayer(newplayernum);
if (newplayernum+1 > doomcom->numslots)
doomcom->numslots = (INT16)(newplayernum+1);
if (server && I_GetNodeAddress)
{
strcpy(playeraddress[newplayernum], I_GetNodeAddress(node));
port = strchr(playeraddress[newplayernum], ':');
if (port)
*port = '\0';
}
}
newplayer = &players[newplayernum];
newplayer->jointime = 0;
newplayer->quittime = 0;
READSTRINGN(*p, player_names[newplayernum], MAXPLAYERNAME);
G_AddPlayer(newplayernum);
if (newplayernum+1 > doomcom->numslots)
doomcom->numslots = (INT16)(newplayernum+1);
// the server is creating my player
if (node == mynode)
@ -3254,29 +3334,67 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum)
secondarydisplayplayer = newplayernum;
DEBFILE("spawning my brother\n");
if (botingame)
players[newplayernum].bot = 1;
newplayer->bot = 1;
}
D_SendPlayerConfig();
addedtogame = true;
if (rejoined)
{
if (newplayer->mo)
{
if (!splitscreenplayer)
localangle = newplayer->mo->angle;
else
localangle2 = newplayer->mo->angle;
newplayer->viewheight = 41*newplayer->height/48;
if (newplayer->mo->eflags & MFE_VERTICALFLIP)
newplayer->viewz = newplayer->mo->z + newplayer->mo->height - newplayer->viewheight;
else
newplayer->viewz = newplayer->mo->z + newplayer->viewheight;
}
// wake up the status bar
ST_Start();
// wake up the heads up text
HU_Start();
if (camera.chase && !splitscreenplayer)
P_ResetCamera(newplayer, &camera);
if (camera2.chase && splitscreenplayer)
P_ResetCamera(newplayer, &camera2);
}
}
if (netgame)
{
if (server && cv_showjoinaddress.value)
{
const char *address;
if (I_GetNodeAddress && (address = I_GetNodeAddress(node)) != NULL)
HU_AddChatText(va("\x82*%s has joined the game (player %d) (%s)", player_names[newplayernum], newplayernum, address), false); // merge join notification + IP to avoid clogging console/chat.
}
char joinmsg[256];
if (rejoined)
strcpy(joinmsg, M_GetText("\x82*%s has rejoined the game (player %d)"));
else
HU_AddChatText(va("\x82*%s has joined the game (player %d)", player_names[newplayernum], newplayernum), false); // if you don't wanna see the join address.
strcpy(joinmsg, M_GetText("\x82*%s has joined the game (player %d)"));
strcpy(joinmsg, va(joinmsg, player_names[newplayernum], newplayernum));
// Merge join notification + IP to avoid clogging console/chat
if (server && cv_showjoinaddress.value && I_GetNodeAddress)
{
const char *address = I_GetNodeAddress(node);
if (address)
strcat(joinmsg, va(" (%s)", address));
}
HU_AddChatText(joinmsg, false);
}
if (server && multiplayer && motd[0] != '\0')
COM_BufAddText(va("sayto %d %s\n", newplayernum, motd));
#ifdef HAVE_BLUA
LUAh_PlayerJoin(newplayernum);
if (!rejoined)
LUAh_PlayerJoin(newplayernum);
#endif
}
@ -3285,11 +3403,7 @@ static boolean SV_AddWaitingPlayers(const char *name, const char *name2)
INT32 node, n, newplayer = false;
UINT8 buf[2 + MAXPLAYERNAME];
UINT8 *p;
UINT8 newplayernum = 0;
// What is the reason for this? Why can't newplayernum always be 0?
if (dedicated)
newplayernum = 1;
INT32 newplayernum;
for (node = 0; node < MAXNETNODES; node++)
{
@ -3298,68 +3412,22 @@ static boolean SV_AddWaitingPlayers(const char *name, const char *name2)
{
newplayer = true;
if (netgame)
// !!!!!!!!! EXTREMELY SUPER MEGA GIGA ULTRA ULTIMATELY TERRIBLY IMPORTANT !!!!!!!!!
//
// The line just after that comment is an awful, horrible, terrible, TERRIBLE hack.
//
// Basically, the fix I did in order to fix the download freezes happens
// to cause situations in which a player number does not match
// the node number associated to that player.
// That is totally normal, there is absolutely *nothing* wrong with that.
// Really. Player 7 being tied to node 29, for instance, is totally fine.
//
// HOWEVER. A few (broken) parts of the netcode do the TERRIBLE mistake
// of mixing up the concepts of node and player, resulting in
// incorrect handling of cases where a player is tied to a node that has
// a different number (which is a totally normal case, or at least should be).
// This incorrect handling can go as far as literally
// anyone from joining your server at all, forever.
//
// Given those two facts, there are two options available
// in order to let this download freeze fix be:
// 1) Fix the broken parts that assume a node is a player or similar bullshit.
// 2) Change the part this comment is located at, so that any player who joins
// is given the same number as their associated node.
//
// No need to say, 1) is by far the obvious best, whereas 2) is a terrible hack.
// Unfortunately, after trying 1), I most likely didn't manage to find all
// of those broken parts, and thus 2) has become the only safe option that remains.
//
// So I did this hack.
//
// If it isn't clear enough, in order to get rid of this ugly hack,
// you will have to fix all parts of the netcode that
// make a confusion between nodes and players.
//
// And if it STILL isn't clear enough, a node and a player
// is NOT the same thing. Never. NEVER. *NEVER*.
//
// And if someday you make the terrible mistake of
// daring to have the unforgivable idea to try thinking
// that a node might possibly be the same as a player,
// or that a player should have the same number as its node,
// be sure that I will somehow know about it and
// hunt you down tirelessly and make you regret it,
// even if you live on the other side of the world.
//
// TODO: vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
// \todo >>>>>>>>>> Remove this horrible hack as soon as possible <<<<<<<<<<
// TODO: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//
// !!!!!!!!! EXTREMELY SUPER MEGA GIGA ULTRA ULTIMATELY TERRIBLY IMPORTANT !!!!!!!!!
newplayernum = node; // OMFG SAY WELCOME TO TEH NEW HACK FOR FIX FIL DOWNLOAD!!1!
else // Don't use the hack if we don't have to
newplayernum = FindRejoinerNum(node);
if (newplayernum == -1)
{
// search for a free playernum
// we can't use playeringame since it is not updated here
for (; newplayernum < MAXPLAYERS; newplayernum++)
for (newplayernum = dedicated ? 1 : 0; newplayernum < MAXPLAYERS; newplayernum++)
{
if (playeringame[newplayernum])
continue;
for (n = 0; n < MAXNETNODES; n++)
if (nodetoplayer[n] == newplayernum || nodetoplayer2[n] == newplayernum)
break;
if (n == MAXNETNODES)
break;
}
}
// should never happen since we check the playernum
// before accepting the join
@ -3386,8 +3454,6 @@ static boolean SV_AddWaitingPlayers(const char *name, const char *name2)
SendNetXCmd(XD_ADDPLAYER, &buf, p - buf);
DEBFILE(va("Server added player %d node %d\n", newplayernum, node));
// use the next free slot (we can't put playeringame[newplayernum] = true here)
newplayernum++;
}
}
@ -3513,8 +3579,11 @@ static size_t TotalTextCmdPerTic(tic_t tic)
static void HandleConnect(SINT8 node)
{
char names[MAXSPLITSCREENPLAYERS][MAXPLAYERNAME + 1];
INT32 rejoinernum;
INT32 i;
rejoinernum = FindRejoinerNum(node);
if (bannednode && bannednode[node])
SV_SendRefuse(node, M_GetText("You have been banned\nfrom the server"));
else if (netbuffer->u.clientcfg._255 != 255 ||
@ -3526,9 +3595,9 @@ static void HandleConnect(SINT8 node)
else if (netbuffer->u.clientcfg.version != VERSION
|| netbuffer->u.clientcfg.subversion != SUBVERSION)
SV_SendRefuse(node, va(M_GetText("Different SRB2 versions cannot\nplay a netgame!\n(server version %d.%d.%d)"), VERSION/100, VERSION%100, SUBVERSION));
else if (!cv_allownewplayer.value && node)
else if (!cv_allownewplayer.value && node && rejoinernum == -1)
SV_SendRefuse(node, M_GetText("The server is not accepting\njoins for the moment"));
else if (D_NumPlayers() >= cv_maxplayers.value)
else if (D_NumPlayers() >= cv_maxplayers.value && rejoinernum == -1)
SV_SendRefuse(node, va(M_GetText("Maximum players reached: %d"), cv_maxplayers.value));
else if (netgame && netbuffer->u.clientcfg.localplayers > 1) // Hacked client?
SV_SendRefuse(node, M_GetText("Too many players from\nthis node."));
@ -3543,7 +3612,7 @@ static void HandleConnect(SINT8 node)
for (i = 0; i < netbuffer->u.clientcfg.localplayers - playerpernode[node]; i++)
{
strlcpy(names[i], netbuffer->u.clientcfg.names[i], MAXPLAYERNAME + 1);
if (!EnsurePlayerNameIsGood(names[i], -1))
if (!EnsurePlayerNameIsGood(names[i], rejoinernum))
{
SV_SendRefuse(node, "Bad player name");
return;
@ -3984,7 +4053,7 @@ static void HandlePacketFromPlayer(SINT8 node)
}
else
{
SendKick(netconsole, KICK_MSG_CON_FAIL);
SendKick(netconsole, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
DEBFILE(va("player %d kicked (synch failure) [%u] %d!=%d\n",
netconsole, realstart, consistancy[realstart%BACKUPTICS],
SHORT(netbuffer->u.clientpak.consistancy)));
@ -4103,6 +4172,7 @@ static void HandlePacketFromPlayer(SINT8 node)
kickmsg = KICK_MSG_TIMEOUT;
else
kickmsg = KICK_MSG_PLAYER_QUIT;
kickmsg |= KICK_MSG_KEEP_BODY;
SendKick(netconsole, kickmsg);
nodetoplayer[node] = -1;
@ -4124,7 +4194,7 @@ static void HandlePacketFromPlayer(SINT8 node)
{
CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_RESYNCHEND", node);
if (server)
SendKick(netconsole, KICK_MSG_CON_FAIL);
SendKick(netconsole, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
break;
}
resynch_local_inprogress = false;
@ -4142,7 +4212,7 @@ static void HandlePacketFromPlayer(SINT8 node)
{
CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_SERVERTICS", node);
if (server)
SendKick(netconsole, KICK_MSG_CON_FAIL);
SendKick(netconsole, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
break;
}
@ -4202,7 +4272,7 @@ static void HandlePacketFromPlayer(SINT8 node)
{
CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_RESYNCHING", node);
if (server)
SendKick(netconsole, KICK_MSG_CON_FAIL);
SendKick(netconsole, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
break;
}
resynch_local_inprogress = true;
@ -4214,7 +4284,7 @@ static void HandlePacketFromPlayer(SINT8 node)
{
CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_PING", node);
if (server)
SendKick(netconsole, KICK_MSG_CON_FAIL);
SendKick(netconsole, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
break;
}
@ -4238,7 +4308,7 @@ static void HandlePacketFromPlayer(SINT8 node)
{
CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_FILEFRAGMENT", node);
if (server)
SendKick(netconsole, KICK_MSG_CON_FAIL);
SendKick(netconsole, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
break;
}
if (client)
@ -4434,7 +4504,7 @@ static void CL_SendClientCmd(void)
packetsize = sizeof (clientcmd_pak) - sizeof (ticcmd_t) - sizeof (INT16);
HSendPacket(servernode, false, 0, packetsize);
}
else if (gamestate != GS_NULL)
else if (gamestate != GS_NULL && addedtogame)
{
G_MoveTiccmd(&netbuffer->u.clientpak.cmd, &localcmds, 1);
netbuffer->u.clientpak.consistancy = SHORT(consistancy[gametic%BACKUPTICS]);
@ -4610,6 +4680,11 @@ static void Local_Maketic(INT32 realtics)
localcmds.angleturn |= TICCMD_RECEIVED;
}
// This function is utter bullshit and is responsible for
// the random desynch that happens when a player spawns.
// This is because ticcmds are resent to clients if a packet
// was dropped, and thus modifying them can lead to several
// clients having their ticcmds set to different values.
void SV_SpawnPlayer(INT32 playernum, INT32 x, INT32 y, angle_t angle)
{
tic_t tic;
@ -4643,28 +4718,36 @@ void SV_SpawnPlayer(INT32 playernum, INT32 x, INT32 y, angle_t angle)
// create missed tic
static void SV_Maketic(void)
{
INT32 j;
INT32 i;
for (j = 0; j < MAXNETNODES; j++)
if (playerpernode[j])
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i])
continue;
// We didn't receive this tic
if ((netcmds[maketic % BACKUPTICS][i].angleturn & TICCMD_RECEIVED) == 0)
{
INT32 player = nodetoplayer[j];
if ((netcmds[maketic%BACKUPTICS][player].angleturn & TICCMD_RECEIVED) == 0)
{ // we didn't receive this tic
INT32 i;
ticcmd_t * ticcmd = &netcmds[(maketic ) % BACKUPTICS][i];
ticcmd_t *prevticcmd = &netcmds[(maketic - 1) % BACKUPTICS][i];
DEBFILE(va("MISS tic%4d for node %d\n", maketic, j));
#if defined(PARANOIA) && 0
CONS_Debug(DBG_NETPLAY, "Client Misstic %d\n", maketic);
#endif
// copy the old tic
for (i = 0; i < playerpernode[j]; i++, player = nodetoplayer2[j])
{
netcmds[maketic%BACKUPTICS][player] = netcmds[(maketic-1)%BACKUPTICS][player];
netcmds[maketic%BACKUPTICS][player].angleturn &= ~TICCMD_RECEIVED;
}
if (players[i].quittime)
{
// Copy the angle/aiming from the previous tic
// and empty the other inputs
memset(ticcmd, 0, sizeof(netcmds[0][0]));
ticcmd->angleturn = prevticcmd->angleturn | TICCMD_RECEIVED;
ticcmd->aiming = prevticcmd->aiming;
}
else
{
DEBFILE(va("MISS tic%4d for player %d\n", maketic, i));
// Copy the input from the previous tic
*ticcmd = *prevticcmd;
ticcmd->angleturn &= ~TICCMD_RECEIVED;
}
}
}
// all tic are now proceed make the next
maketic++;
@ -4786,7 +4869,7 @@ static inline void PingUpdate(void)
// ok your net has been bad for too long, you deserve to die.
{
pingtimeout[i] = 0;
SendKick(i, KICK_MSG_PING_HIGH);
SendKick(i, KICK_MSG_PING_HIGH | KICK_MSG_KEEP_BODY);
}
}
/*

View File

@ -485,6 +485,7 @@ extern consvar_t cv_playbackspeed;
#define KICK_MSG_PING_HIGH 6
#define KICK_MSG_CUSTOM_KICK 7
#define KICK_MSG_CUSTOM_BAN 8
#define KICK_MSG_KEEP_BODY 0x80
typedef enum
{
@ -512,7 +513,9 @@ extern UINT32 realpingtable[MAXPLAYERS];
extern UINT32 playerpingtable[MAXPLAYERS];
extern tic_t servermaxping;
extern consvar_t cv_joinnextround, cv_allownewplayer, cv_maxplayers, cv_resynchattempts, cv_blamecfail, cv_maxsend, cv_noticedownload, cv_downloadspeed;
extern consvar_t cv_allownewplayer, cv_joinnextround, cv_maxplayers, cv_rejointimeout;
extern consvar_t cv_resynchattempts, cv_blamecfail;
extern consvar_t cv_maxsend, cv_noticedownload, cv_downloadspeed;
// Used in d_net, the only dependence
tic_t ExpandTics(INT32 low);

View File

@ -657,8 +657,14 @@ void D_SRB2Loop(void)
// hack to start on a nice clear console screen.
COM_ImmedExecute("cls;version");
V_DrawScaledPatch(0, 0, 0, W_CachePatchNum(W_GetNumForName("CONSBACK"), PU_CACHE));
I_FinishUpdate(); // page flip or blit buffer
/*
LMFAO this was showing garbage under OpenGL
because I_FinishUpdate was called afterward
*/
/* Smells like a hack... Don't fade Sonic's ass into the title screen. */
if (gamestate != GS_TITLESCREEN)
V_DrawScaledPatch(0, 0, 0, W_CachePatchNum(W_GetNumForName("CONSBACK"), PU_CACHE));
for (;;)
{

View File

@ -579,6 +579,7 @@ void D_RegisterServerCommands(void)
// d_clisrv
CV_RegisterVar(&cv_maxplayers);
CV_RegisterVar(&cv_rejointimeout);
CV_RegisterVar(&cv_resynchattempts);
CV_RegisterVar(&cv_maxsend);
CV_RegisterVar(&cv_noticedownload);
@ -1124,7 +1125,7 @@ static void SetPlayerName(INT32 playernum, char *newname)
{
CONS_Printf(M_GetText("Player %d sent a bad name change\n"), playernum+1);
if (server && netgame)
SendKick(playernum, KICK_MSG_CON_FAIL);
SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
}
}
@ -1482,7 +1483,7 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum)
if (kick)
{
CONS_Alert(CONS_WARNING, M_GetText("Illegal color change received from %s (team: %d), color: %d)\n"), player_names[playernum], p->ctfteam, p->skincolor);
SendKick(playernum, KICK_MSG_CON_FAIL);
SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
return;
}
}
@ -2022,7 +2023,7 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum)
{
CONS_Alert(CONS_WARNING, M_GetText("Illegal map change received from %s\n"), player_names[playernum]);
if (server)
SendKick(playernum, KICK_MSG_CON_FAIL);
SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
return;
}
@ -2133,7 +2134,7 @@ static void Got_Pause(UINT8 **cp, INT32 playernum)
{
CONS_Alert(CONS_WARNING, M_GetText("Illegal pause command received from %s\n"), player_names[playernum]);
if (server)
SendKick(playernum, KICK_MSG_CON_FAIL);
SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
return;
}
@ -2208,7 +2209,7 @@ static void Got_Suicide(UINT8 **cp, INT32 playernum)
{
CONS_Alert(CONS_WARNING, M_GetText("Illegal suicide command received from %s\n"), player_names[playernum]);
if (server)
SendKick(playernum, KICK_MSG_CON_FAIL);
SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
return;
}
@ -2271,7 +2272,7 @@ static void Got_Clearscores(UINT8 **cp, INT32 playernum)
{
CONS_Alert(CONS_WARNING, M_GetText("Illegal clear scores command received from %s\n"), player_names[playernum]);
if (server)
SendKick(playernum, KICK_MSG_CON_FAIL);
SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
return;
}
@ -2618,7 +2619,7 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum)
// this should never happen unless the client is hacked/buggy
CONS_Alert(CONS_WARNING, M_GetText("Illegal team change received from player %s\n"), player_names[playernum]);
if (server)
SendKick(playernum, KICK_MSG_CON_FAIL);
SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
}
if (NetPacket.packet.verification) // Special marker that the server sent the request
@ -2627,7 +2628,7 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum)
{
CONS_Alert(CONS_WARNING, M_GetText("Illegal team change received from player %s\n"), player_names[playernum]);
if (server)
SendKick(playernum, KICK_MSG_CON_FAIL);
SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
return;
}
playernum = NetPacket.packet.playernum;
@ -2660,7 +2661,7 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum)
{
CONS_Alert(CONS_WARNING, M_GetText("Illegal team change received from player %s\n"), player_names[playernum]);
if (server)
SendKick(playernum, KICK_MSG_CON_FAIL);
SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
}
return;
}
@ -2719,7 +2720,7 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum)
if (server && ((NetPacket.packet.newteam < 0 || NetPacket.packet.newteam > 3) || error))
{
CONS_Alert(CONS_WARNING, M_GetText("Illegal team change received from player %s\n"), player_names[playernum]);
SendKick(playernum, KICK_MSG_CON_FAIL);
SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
}
//Safety first!
@ -3011,7 +3012,7 @@ static void Got_Verification(UINT8 **cp, INT32 playernum)
{
CONS_Alert(CONS_WARNING, M_GetText("Illegal verification received from %s (serverplayer is %s)\n"), player_names[playernum], player_names[serverplayer]);
if (server)
SendKick(playernum, KICK_MSG_CON_FAIL);
SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
return;
}
@ -3061,7 +3062,7 @@ static void Got_Removal(UINT8 **cp, INT32 playernum)
{
CONS_Alert(CONS_WARNING, M_GetText("Illegal demotion received from %s (serverplayer is %s)\n"), player_names[playernum], player_names[serverplayer]);
if (server)
SendKick(playernum, KICK_MSG_CON_FAIL);
SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
return;
}
@ -3135,7 +3136,7 @@ static void Got_MotD_f(UINT8 **cp, INT32 playernum)
{
CONS_Alert(CONS_WARNING, M_GetText("Illegal motd change received from %s\n"), player_names[playernum]);
if (server)
SendKick(playernum, KICK_MSG_CON_FAIL);
SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
Z_Free(mymotd);
return;
}
@ -3191,7 +3192,7 @@ static void Got_RunSOCcmd(UINT8 **cp, INT32 playernum)
{
CONS_Alert(CONS_WARNING, M_GetText("Illegal runsoc command received from %s\n"), player_names[playernum]);
if (server)
SendKick(playernum, KICK_MSG_CON_FAIL);
SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
return;
}
@ -3349,7 +3350,7 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum)
if ((playernum != serverplayer && !IsPlayerAdmin(playernum)) || kick)
{
CONS_Alert(CONS_WARNING, M_GetText("Illegal addfile command received from %s\n"), player_names[playernum]);
SendKick(playernum, KICK_MSG_CON_FAIL);
SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
return;
}
@ -3398,7 +3399,7 @@ static void Got_Addfilecmd(UINT8 **cp, INT32 playernum)
{
CONS_Alert(CONS_WARNING, M_GetText("Illegal addfile command received from %s\n"), player_names[playernum]);
if (server)
SendKick(playernum, KICK_MSG_CON_FAIL);
SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
return;
}
@ -4191,7 +4192,7 @@ static void Got_ExitLevelcmd(UINT8 **cp, INT32 playernum)
{
CONS_Alert(CONS_WARNING, M_GetText("Illegal exitlevel command received from %s\n"), player_names[playernum]);
if (server)
SendKick(playernum, KICK_MSG_CON_FAIL);
SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
return;
}

View File

@ -512,6 +512,7 @@ typedef struct player_s
UINT8 bot;
tic_t jointime; // Timer when player joins game to change skin/color
tic_t quittime; // Time elapsed since user disconnected, zero if connected
#ifdef HWRENDER
fixed_t fovadd; // adjust FOV for hw rendering
#endif

View File

@ -8847,7 +8847,7 @@ static const char *const MOBJEFLAG_LIST[] = {
#ifdef HAVE_BLUA
static const char *const MAPTHINGFLAG_LIST[4] = {
NULL,
"EXTRA", // Extra flag for objects.
"OBJECTFLIP", // Reverse gravity flag for objects.
"OBJECTSPECIAL", // Special flag used with certain objects.
"AMBUSH" // Deaf monsters/do not react to sound.
@ -9427,7 +9427,7 @@ struct {
{"SH_FORCE",SH_FORCE},
{"SH_FORCEHP",SH_FORCEHP}, // to be used as a bitmask only
// Mostly for use with Mario mode.
{"SH_FIREFLOWER", SH_FIREFLOWER},
{"SH_FIREFLOWER",SH_FIREFLOWER},
{"SH_STACK",SH_STACK},
{"SH_NOSTACK",SH_NOSTACK},
@ -9442,7 +9442,7 @@ struct {
{"CR_ROPEHANG",CR_ROPEHANG},
{"CR_MACESPIN",CR_MACESPIN},
{"CR_MINECART",CR_MINECART},
{"CR_ROLLOUT", CR_ROLLOUT},
{"CR_ROLLOUT",CR_ROLLOUT},
{"CR_PTERABYTE",CR_PTERABYTE},
// Ring weapons (ringweapons_t)
@ -9609,7 +9609,7 @@ struct {
{"NUM_WEAPONS",NUM_WEAPONS},
// Value for infinite lives
{"INFLIVES", INFLIVES},
{"INFLIVES",INFLIVES},
// Got Flags, for player->gotflag!
// Used to be MF_ for some stupid reason, now they're GF_ to stop them looking like mobjflags
@ -9671,9 +9671,10 @@ struct {
{"FF_PLATFORM",FF_PLATFORM}, ///< You can jump up through this to the top.
{"FF_REVERSEPLATFORM",FF_REVERSEPLATFORM}, ///< A fall-through floor in normal gravity, a platform in reverse gravity.
{"FF_INTANGIBLEFLATS",FF_INTANGIBLEFLATS}, ///< Both flats are intangible, but the sides are still solid.
{"FF_INTANGABLEFLATS",FF_INTANGIBLEFLATS}, ///< Both flats are intangable, but the sides are still solid.
{"FF_SHATTER",FF_SHATTER}, ///< Used with ::FF_BUSTUP. Bustable on mere touch.
{"FF_SPINBUST",FF_SPINBUST}, ///< Used with ::FF_BUSTUP. Also bustable if you're in your spinning frames.
{"FF_STRONGBUST",FF_STRONGBUST }, ///< Used with ::FF_BUSTUP. Only bustable by "strong" characters (Knuckles) and abilities (bouncing, twinspin, melee).
{"FF_STRONGBUST",FF_STRONGBUST}, ///< Used with ::FF_BUSTUP. Only bustable by "strong" characters (Knuckles) and abilities (bouncing, twinspin, melee).
{"FF_RIPPLE",FF_RIPPLE}, ///< Ripple the flats
{"FF_COLORMAPONLY",FF_COLORMAPONLY}, ///< Only copy the colormap, not the lightlevel
{"FF_GOOWATER",FF_GOOWATER}, ///< Used with ::FF_SWIMMABLE. Makes thick bouncey goop.

View File

@ -1165,6 +1165,7 @@ static const char *credits[] = {
"Tasos \"tatokis\" Sahanidis", // Corrected C FixedMul, making 64-bit builds netplay compatible
"Wessel \"sphere\" Smit",
"Ben \"Cue\" Woodford",
"Ikaro \"Tatsuru\" Vinhas",
// Git contributors with 5+ approved merges of substantive quality,
// or contributors with at least one groundbreaking merge, may be named.
// Everyone else is acknowledged under "Special Thanks > SRB2 Community Contributors".

View File

@ -1140,7 +1140,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
INT32 *myaiming = (ssplayer == 1 ? &localaiming : &localaiming2);
angle_t drawangleoffset = (player->powers[pw_carry] == CR_ROLLOUT) ? ANGLE_180 : 0;
INT32 chasecam, chasefreelook, alwaysfreelook, usejoystick, invertmouse, mousemove;
INT32 chasecam, chasefreelook, alwaysfreelook, usejoystick, invertmouse, turnmultiplier, mousemove;
controlstyle_e controlstyle = G_ControlStyle(ssplayer);
INT32 *mx; INT32 *my; INT32 *mly;
@ -1163,6 +1163,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
alwaysfreelook = cv_alwaysfreelook.value;
usejoystick = cv_usejoystick.value;
invertmouse = cv_invertmouse.value;
turnmultiplier = cv_cam_turnmultiplier.value;
mousemove = cv_mousemove.value;
mx = &mousex;
my = &mousey;
@ -1176,6 +1177,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
alwaysfreelook = cv_alwaysfreelook2.value;
usejoystick = cv_usejoystick2.value;
invertmouse = cv_invertmouse2.value;
turnmultiplier = cv_cam2_turnmultiplier.value;
mousemove = cv_mousemove2.value;
mx = &mouse2x;
my = &mouse2y;
@ -1293,14 +1295,14 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
{
if (turnright && turnleft);
else if (turnright)
cmd->angleturn = (INT16)(cmd->angleturn - ((angleturn[tspeed] * cv_cam_turnmultiplier.value)>>FRACBITS));
cmd->angleturn = (INT16)(cmd->angleturn - ((angleturn[tspeed] * turnmultiplier)>>FRACBITS));
else if (turnleft)
cmd->angleturn = (INT16)(cmd->angleturn + ((angleturn[tspeed] * cv_cam_turnmultiplier.value)>>FRACBITS));
cmd->angleturn = (INT16)(cmd->angleturn + ((angleturn[tspeed] * turnmultiplier)>>FRACBITS));
if (analogjoystickmove && lookjoystickvector.xaxis != 0)
{
// JOYAXISRANGE should be 1023 (divide by 1024)
cmd->angleturn = (INT16)(cmd->angleturn - ((((lookjoystickvector.xaxis * angleturn[1]) >> 10) * cv_cam_turnmultiplier.value)>>FRACBITS)); // ANALOG!
cmd->angleturn = (INT16)(cmd->angleturn - ((((lookjoystickvector.xaxis * angleturn[1]) >> 10) * turnmultiplier)>>FRACBITS)); // ANALOG!
}
if (turnright || turnleft || abs(cmd->angleturn) > angleturn[2])
@ -2412,6 +2414,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
INT32 skin;
UINT32 availabilities;
tic_t jointime;
tic_t quittime;
boolean spectator;
boolean outofcoop;
INT16 bot;
@ -2425,6 +2428,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
ctfteam = players[player].ctfteam;
exiting = players[player].exiting;
jointime = players[player].jointime;
quittime = players[player].quittime;
spectator = players[player].spectator;
outofcoop = players[player].outofcoop;
pflags = (players[player].pflags & (PF_FLIPCAM|PF_ANALOGMODE|PF_DIRECTIONCHAR|PF_AUTOBRAKE|PF_TAGIT|PF_GAMETYPEOVER));
@ -2496,6 +2500,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
p->pflags = pflags;
p->ctfteam = ctfteam;
p->jointime = jointime;
p->quittime = quittime;
p->spectator = spectator;
p->outofcoop = outofcoop;
@ -2649,73 +2654,24 @@ static boolean G_CheckSpot(INT32 playernum, mapthing_t *mthing)
// or a not-so-appropriate spot, if it initially fails
// due to a lack of starts open or something.
//
void G_SpawnPlayer(INT32 playernum, boolean starpost)
void G_SpawnPlayer(INT32 playernum)
{
mapthing_t *spawnpoint;
if (!playeringame[playernum])
return;
P_SpawnPlayer(playernum);
if (starpost) //Don't even bother with looking for a place to spawn.
{
P_MovePlayerToStarpost(playernum);
#ifdef HAVE_BLUA
LUAh_PlayerSpawn(&players[playernum]); // Lua hook for player spawning :)
#endif
return;
}
// -- CTF --
// Order: CTF->DM->Coop
if ((gametyperules & (GTR_TEAMFLAGS|GTR_TEAMS)) && players[playernum].ctfteam)
{
if (!(spawnpoint = G_FindCTFStart(playernum)) // find a CTF start
&& !(spawnpoint = G_FindMatchStart(playernum))) // find a DM start
spawnpoint = G_FindCoopStart(playernum); // fallback
}
// -- DM/Tag/CTF-spectator/etc --
// Order: DM->CTF->Coop
else if ((gametyperules & GTR_DEATHMATCHSTARTS) && !(players[playernum].pflags & PF_TAGIT))
{
if (!(spawnpoint = G_FindMatchStart(playernum)) // find a DM start
&& !(spawnpoint = G_FindCTFStart(playernum))) // find a CTF start
spawnpoint = G_FindCoopStart(playernum); // fallback
}
// -- Other game modes --
// Order: Coop->DM->CTF
else
{
if (!(spawnpoint = G_FindCoopStart(playernum)) // find a Co-op start
&& !(spawnpoint = G_FindMatchStart(playernum))) // find a DM start
spawnpoint = G_FindCTFStart(playernum); // fallback
}
//No spawns found. ANYWHERE.
if (!spawnpoint)
{
if (nummapthings)
{
if (playernum == consoleplayer || (splitscreen && playernum == secondarydisplayplayer))
CONS_Alert(CONS_ERROR, M_GetText("No player spawns found, spawning at the first mapthing!\n"));
spawnpoint = &mapthings[0];
}
else
{
if (playernum == consoleplayer || (splitscreen && playernum == secondarydisplayplayer))
CONS_Alert(CONS_ERROR, M_GetText("No player spawns found, spawning at the origin!\n"));
//P_MovePlayerToSpawn handles this fine if the spawnpoint is NULL.
}
}
P_MovePlayerToSpawn(playernum, spawnpoint);
G_MovePlayerToSpawnOrStarpost(playernum);
#ifdef HAVE_BLUA
LUAh_PlayerSpawn(&players[playernum]); // Lua hook for player spawning :)
#endif
}
void G_MovePlayerToSpawnOrStarpost(INT32 playernum)
{
if (players[playernum].starposttime)
P_MovePlayerToStarpost(playernum);
else
P_MovePlayerToSpawn(playernum, G_FindMapStart(playernum));
}
mapthing_t *G_FindCTFStart(INT32 playernum)
@ -2812,6 +2768,59 @@ mapthing_t *G_FindCoopStart(INT32 playernum)
return NULL;
}
mapthing_t *G_FindMapStart(INT32 playernum)
{
mapthing_t *spawnpoint;
if (!playeringame[playernum])
return NULL;
// -- CTF --
// Order: CTF->DM->Coop
if ((gametyperules & (GTR_TEAMFLAGS|GTR_TEAMS)) && players[playernum].ctfteam)
{
if (!(spawnpoint = G_FindCTFStart(playernum)) // find a CTF start
&& !(spawnpoint = G_FindMatchStart(playernum))) // find a DM start
spawnpoint = G_FindCoopStart(playernum); // fallback
}
// -- DM/Tag/CTF-spectator/etc --
// Order: DM->CTF->Coop
else if ((gametyperules & GTR_DEATHMATCHSTARTS) && !(players[playernum].pflags & PF_TAGIT))
{
if (!(spawnpoint = G_FindMatchStart(playernum)) // find a DM start
&& !(spawnpoint = G_FindCTFStart(playernum))) // find a CTF start
spawnpoint = G_FindCoopStart(playernum); // fallback
}
// -- Other game modes --
// Order: Coop->DM->CTF
else
{
if (!(spawnpoint = G_FindCoopStart(playernum)) // find a Co-op start
&& !(spawnpoint = G_FindMatchStart(playernum))) // find a DM start
spawnpoint = G_FindCTFStart(playernum); // fallback
}
//No spawns found. ANYWHERE.
if (!spawnpoint)
{
if (nummapthings)
{
if (playernum == consoleplayer || (splitscreen && playernum == secondarydisplayplayer))
CONS_Alert(CONS_ERROR, M_GetText("No player spawns found, spawning at the first mapthing!\n"));
spawnpoint = &mapthings[0];
}
else
{
if (playernum == consoleplayer || (splitscreen && playernum == secondarydisplayplayer))
CONS_Alert(CONS_ERROR, M_GetText("No player spawns found, spawning at the origin!\n"));
}
}
return spawnpoint;
}
// Go back through all the projectiles and remove all references to the old
// player mobj, replacing them with the new one.
void G_ChangePlayerReferences(mobj_t *oldmo, mobj_t *newmo)
@ -2990,7 +2999,7 @@ void G_DoReborn(INT32 playernum)
{
if (!playeringame[i])
continue;
G_SpawnPlayer(i, (players[i].starposttime));
G_SpawnPlayer(i);
}
// restore time in netgame (see also p_setup.c)
@ -3036,7 +3045,7 @@ void G_DoReborn(INT32 playernum)
P_RemoveMobj(player->mo);
}
G_SpawnPlayer(playernum, (player->starposttime));
G_SpawnPlayer(playernum);
if (oldmo)
G_ChangePlayerReferences(oldmo, players[playernum].mo);
}
@ -3078,7 +3087,6 @@ void G_AddPlayer(INT32 playernum)
}
}
p->jointime = 0;
p->playerstate = PST_REBORN;
p->height = mobjinfo[MT_PLAYER].height;
@ -3101,6 +3109,8 @@ boolean G_EnoughPlayersFinished(void)
{
if (!playeringame[i] || players[i].spectator || players[i].bot)
continue;
if (players[i].quittime > 30 * TICRATE)
continue;
if (players[i].lives <= 0)
continue;

View File

@ -161,7 +161,9 @@ INT32 G_FindMapByNameOrCode(const char *query, char **foundmapnamep);
mapthing_t *G_FindCTFStart(INT32 playernum);
mapthing_t *G_FindMatchStart(INT32 playernum);
mapthing_t *G_FindCoopStart(INT32 playernum);
void G_SpawnPlayer(INT32 playernum, boolean starpost);
mapthing_t *G_FindMapStart(INT32 playernum);
void G_MovePlayerToSpawnOrStarpost(INT32 playernum);
void G_SpawnPlayer(INT32 playernum);
// Can be called by the startup code or M_Responder.
// A normal game starts at map 1, but a warp test can start elsewhere

View File

@ -662,7 +662,13 @@ INT32 G_KeyStringtoNum(const char *keystr)
return keystr[0];
if (!strncmp(keystr, "KEY", 3) && keystr[3] >= '0' && keystr[3] <= '9')
return atoi(&keystr[3]);
{
/* what if we out of range bruh? */
j = atoi(&keystr[3]);
if (j < NUMINPUTS)
return j;
return 0;
}
for (j = 0; j < NUMKEYNAMES; j++)
if (!stricmp(keynames[j].name, keystr))

View File

@ -41,6 +41,7 @@
#include "../i_system.h"
#include "../m_cheat.h"
#include "../f_finale.h"
#include "../r_things.h" // R_GetShadowZ
#ifdef ESLOPE
#include "../p_slopes.h"
#endif
@ -4050,39 +4051,6 @@ static gr_vissprite_t *HWR_NewVisSprite(void)
return HWR_GetVisSprite(gr_visspritecount++);
}
#ifdef GLBADSHADOWS
// Finds a floor through which light does not pass.
static fixed_t HWR_OpaqueFloorAtPos(fixed_t x, fixed_t y, fixed_t z, fixed_t height)
{
const sector_t *sec = R_PointInSubsector(x, y)->sector;
fixed_t floorz = sec->floorheight;
if (sec->ffloors)
{
ffloor_t *rover;
fixed_t delta1, delta2;
const fixed_t thingtop = z + height;
for (rover = sec->ffloors; rover; rover = rover->next)
{
if (!(rover->flags & FF_EXISTS)
|| !(rover->flags & FF_RENDERPLANES)
|| rover->flags & FF_TRANSLUCENT
|| rover->flags & FF_FOG
|| rover->flags & FF_INVERTPLANES)
continue;
delta1 = z - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2));
delta2 = thingtop - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2));
if (*rover->topheight > floorz && abs(delta1) < abs(delta2))
floorz = *rover->topheight;
}
}
return floorz;
}
#endif //#ifdef GLBADSHADOWS
//
// HWR_DoCulling
// Hardware version of R_DoCulling
@ -4123,180 +4091,123 @@ static boolean HWR_DoCulling(line_t *cullheight, line_t *viewcullheight, float v
return false;
}
#ifdef GLBADSHADOWS
static void HWR_DrawSpriteShadow(gr_vissprite_t *spr, GLPatch_t *gpatch, float this_scale)
static void HWR_DrawDropShadow(mobj_t *thing, gr_vissprite_t *spr, fixed_t scale)
{
FOutVector swallVerts[4];
GLPatch_t *gpatch;
FOutVector shadowVerts[4];
FSurfaceInfo sSurf;
fixed_t floorheight, mobjfloor;
float offset = 0;
float fscale; float fx; float fy; float offset;
UINT8 lightlevel = 255;
extracolormap_t *colormap = NULL;
UINT8 i;
mobjfloor = HWR_OpaqueFloorAtPos(
spr->mobj->x, spr->mobj->y,
spr->mobj->z, spr->mobj->height);
if (cv_shadowoffs.value)
{
angle_t shadowdir;
INT32 light;
fixed_t scalemul;
UINT16 alpha;
fixed_t floordiff;
fixed_t floorz;
fixed_t slopez;
pslope_t *floorslope;
// Set direction
if (splitscreen && stplyr == &players[secondarydisplayplayer])
shadowdir = localangle2 + FixedAngle(cv_cam2_rotate.value);
else
shadowdir = localangle + FixedAngle(cv_cam_rotate.value);
floorz = R_GetShadowZ(thing, &floorslope);
// Find floorheight
floorheight = HWR_OpaqueFloorAtPos(
spr->mobj->x + P_ReturnThrustX(spr->mobj, shadowdir, spr->mobj->z - mobjfloor),
spr->mobj->y + P_ReturnThrustY(spr->mobj, shadowdir, spr->mobj->z - mobjfloor),
spr->mobj->z, spr->mobj->height);
//if (abs(floorz - gr_viewz) / tz > 4) return; // Prevent stretchy shadows and possible crashes
// The shadow is falling ABOVE it's mobj?
// Don't draw it, then!
if (spr->mobj->z < floorheight)
return;
else
{
fixed_t floorz;
floorz = HWR_OpaqueFloorAtPos(
spr->mobj->x + P_ReturnThrustX(spr->mobj, shadowdir, spr->mobj->z - floorheight),
spr->mobj->y + P_ReturnThrustY(spr->mobj, shadowdir, spr->mobj->z - floorheight),
spr->mobj->z, spr->mobj->height);
// The shadow would be falling on a wall? Don't draw it, then.
// Would draw midair otherwise.
if (floorz < floorheight)
return;
}
floordiff = abs(thing->z - floorz);
floorheight = FixedInt(spr->mobj->z - floorheight);
alpha = floordiff / (4*FRACUNIT) + 75;
if (alpha >= 255) return;
alpha = 255 - alpha;
offset = floorheight;
}
else
floorheight = FixedInt(spr->mobj->z - mobjfloor);
gpatch = (GLPatch_t *)W_CachePatchName("DSHADOW", PU_CACHE);
if (!(gpatch && gpatch->mipmap->grInfo.format)) return;
HWR_GetPatch(gpatch);
scalemul = FixedMul(FRACUNIT - floordiff/640, scale);
scalemul = FixedMul(scalemul, (thing->radius*2) / gpatch->height);
fscale = FIXED_TO_FLOAT(scalemul);
fx = FIXED_TO_FLOAT(thing->x);
fy = FIXED_TO_FLOAT(thing->y);
// create the sprite billboard
//
// 3--2
// | /|
// |/ |
// 0--1
// x1/x2 were already scaled in HWR_ProjectSprite
// First match the normal sprite
swallVerts[0].x = swallVerts[3].x = spr->x1;
swallVerts[2].x = swallVerts[1].x = spr->x2;
swallVerts[0].z = swallVerts[3].z = spr->z1;
swallVerts[2].z = swallVerts[1].z = spr->z2;
if (thing && fabsf(fscale - 1.0f) > 1.0E-36f)
offset = (gpatch->height/2) * fscale;
else
offset = (float)(gpatch->height/2);
if (spr->mobj && fabsf(this_scale - 1.0f) > 1.0E-36f)
shadowVerts[0].x = shadowVerts[3].x = fx - offset;
shadowVerts[2].x = shadowVerts[1].x = fx + offset;
shadowVerts[0].z = shadowVerts[1].z = fy - offset;
shadowVerts[3].z = shadowVerts[2].z = fy + offset;
if (floorslope)
{
// Always a pixel above the floor, perfectly flat.
swallVerts[0].y = swallVerts[1].y = swallVerts[2].y = swallVerts[3].y = spr->ty - gpatch->topoffset * this_scale - (floorheight+3);
// Now transform the TOP vertices along the floor in the direction of the camera
swallVerts[3].x = spr->x1 + ((gpatch->height * this_scale) + offset) * gr_viewcos;
swallVerts[2].x = spr->x2 + ((gpatch->height * this_scale) + offset) * gr_viewcos;
swallVerts[3].z = spr->z1 + ((gpatch->height * this_scale) + offset) * gr_viewsin;
swallVerts[2].z = spr->z2 + ((gpatch->height * this_scale) + offset) * gr_viewsin;
for (i = 0; i < 4; i++)
{
slopez = P_GetZAt(floorslope, FLOAT_TO_FIXED(shadowVerts[i].x), FLOAT_TO_FIXED(shadowVerts[i].z));
shadowVerts[i].y = FIXED_TO_FLOAT(slopez) + 0.05f;
}
}
else
{
// Always a pixel above the floor, perfectly flat.
swallVerts[0].y = swallVerts[1].y = swallVerts[2].y = swallVerts[3].y = spr->ty - gpatch->topoffset - (floorheight+3);
// Now transform the TOP vertices along the floor in the direction of the camera
swallVerts[3].x = spr->x1 + (gpatch->height + offset) * gr_viewcos;
swallVerts[2].x = spr->x2 + (gpatch->height + offset) * gr_viewcos;
swallVerts[3].z = spr->z1 + (gpatch->height + offset) * gr_viewsin;
swallVerts[2].z = spr->z2 + (gpatch->height + offset) * gr_viewsin;
}
// We also need to move the bottom ones away when shadowoffs is on
if (cv_shadowoffs.value)
{
swallVerts[0].x = spr->x1 + offset * gr_viewcos;
swallVerts[1].x = spr->x2 + offset * gr_viewcos;
swallVerts[0].z = spr->z1 + offset * gr_viewsin;
swallVerts[1].z = spr->z2 + offset * gr_viewsin;
for (i = 0; i < 4; i++)
shadowVerts[i].y = FIXED_TO_FLOAT(floorz) + 0.05f;
}
if (spr->flip)
{
swallVerts[0].sow = swallVerts[3].sow = gpatch->max_s;
swallVerts[2].sow = swallVerts[1].sow = 0;
shadowVerts[0].sow = shadowVerts[3].sow = gpatch->max_s;
shadowVerts[2].sow = shadowVerts[1].sow = 0;
}
else
{
swallVerts[0].sow = swallVerts[3].sow = 0;
swallVerts[2].sow = swallVerts[1].sow = gpatch->max_s;
shadowVerts[0].sow = shadowVerts[3].sow = 0;
shadowVerts[2].sow = shadowVerts[1].sow = gpatch->max_s;
}
// flip the texture coords (look familiar?)
if (spr->vflip)
{
swallVerts[3].tow = swallVerts[2].tow = gpatch->max_t;
swallVerts[0].tow = swallVerts[1].tow = 0;
shadowVerts[3].tow = shadowVerts[2].tow = gpatch->max_t;
shadowVerts[0].tow = shadowVerts[1].tow = 0;
}
else
{
swallVerts[3].tow = swallVerts[2].tow = 0;
swallVerts[0].tow = swallVerts[1].tow = gpatch->max_t;
shadowVerts[3].tow = shadowVerts[2].tow = 0;
shadowVerts[0].tow = shadowVerts[1].tow = gpatch->max_t;
}
sSurf.FlatColor.s.red = 0x00;
sSurf.FlatColor.s.blue = 0x00;
sSurf.FlatColor.s.green = 0x00;
/*if (spr->mobj->frame & FF_TRANSMASK || spr->mobj->flags2 & MF2_SHADOW)
if (thing->subsector->sector->numlights)
{
sector_t *sector = spr->mobj->subsector->sector;
UINT8 lightlevel = 255;
extracolormap_t *colormap = sector->extra_colormap;
light = R_GetPlaneLight(thing->subsector->sector, floorz, false); // Always use the light at the top instead of whatever I was doing before
if (sector->numlights)
{
INT32 light = R_GetPlaneLight(sector, spr->mobj->floorz, false);
lightlevel = *thing->subsector->sector->lightlist[light].lightlevel;
if (!(spr->mobj->frame & FF_FULLBRIGHT))
lightlevel = *sector->lightlist[light].lightlevel;
if (*sector->lightlist[light].extra_colormap)
colormap = *sector->lightlist[light].extra_colormap;
}
else
{
lightlevel = sector->lightlevel;
if (sector->extra_colormap)
colormap = sector->extra_colormap;
}
if (colormap)
sSurf.FlatColor.rgba = HWR_Lighting(lightlevel/2, colormap->rgba, colormap->fadergba, false, true);
else
sSurf.FlatColor.rgba = HWR_Lighting(lightlevel/2, NORMALFOG, FADEFOG, false, true);
}*/
// shadow is always half as translucent as the sprite itself
if (!cv_translucency.value) // use default translucency (main sprite won't have any translucency)
sSurf.FlatColor.s.alpha = 0x80; // default
else if (spr->mobj->flags2 & MF2_SHADOW)
sSurf.FlatColor.s.alpha = 0x20;
else if (spr->mobj->frame & FF_TRANSMASK)
{
HWR_TranstableToAlpha((spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT, &sSurf);
sSurf.FlatColor.s.alpha /= 2; //cut alpha in half!
if (*thing->subsector->sector->lightlist[light].extra_colormap)
colormap = *thing->subsector->sector->lightlist[light].extra_colormap;
}
else
sSurf.FlatColor.s.alpha = 0x80; // default
if (sSurf.FlatColor.s.alpha > floorheight/4)
{
sSurf.FlatColor.s.alpha = (UINT8)(sSurf.FlatColor.s.alpha - floorheight/4);
HWD.pfnDrawPolygon(&sSurf, swallVerts, 4, PF_Translucent|PF_Modulated|PF_Clip);
lightlevel = thing->subsector->sector->lightlevel;
if (thing->subsector->sector->extra_colormap)
colormap = thing->subsector->sector->extra_colormap;
}
if (colormap)
sSurf.FlatColor.rgba = HWR_Lighting(lightlevel, colormap->rgba, colormap->fadergba, false, false);
else
sSurf.FlatColor.rgba = HWR_Lighting(lightlevel, NORMALFOG, FADEFOG, false, false);
sSurf.FlatColor.s.alpha = alpha;
HWD.pfnDrawPolygon(&sSurf, shadowVerts, 4, PF_Translucent|PF_Modulated|PF_Clip);
}
#endif //#ifdef GLBADSHADOWS
// This is expecting a pointer to an array containing 4 wallVerts for a sprite
static void HWR_RotateSpritePolyToAim(gr_vissprite_t *spr, FOutVector *wallVerts)
@ -4372,24 +4283,6 @@ static void HWR_SplitSprite(gr_vissprite_t *spr)
//Hurdler: 25/04/2000: now support colormap in hardware mode
HWR_GetMappedPatch(gpatch, spr->colormap);
#ifdef GLBADSHADOWS
// Draw shadow BEFORE sprite
if (cv_shadow.value // Shadows enabled
&& (spr->mobj->flags & (MF_SCENERY|MF_SPAWNCEILING|MF_NOGRAVITY)) != (MF_SCENERY|MF_SPAWNCEILING|MF_NOGRAVITY) // Ceiling scenery have no shadow.
&& !(spr->mobj->flags2 & MF2_DEBRIS) // Debris have no corona or shadow.
#ifdef ALAM_LIGHTING
&& !(t_lspr[spr->mobj->sprite]->type // Things with dynamic lights have no shadow.
&& (!spr->mobj->player || spr->mobj->player->powers[pw_super])) // Except for non-super players.
#endif
&& (spr->mobj->z >= spr->mobj->floorz)) // Without this, your shadow shows on the floor, even after you die and fall through the ground.
{
////////////////////
// SHADOW SPRITE! //
////////////////////
HWR_DrawSpriteShadow(spr, gpatch, this_scale);
}
#endif //#ifdef GLBADSHADOWS
baseWallVerts[0].x = baseWallVerts[3].x = spr->x1;
baseWallVerts[2].x = baseWallVerts[1].x = spr->x2;
baseWallVerts[0].z = baseWallVerts[3].z = spr->z1;
@ -4776,24 +4669,6 @@ static void HWR_DrawSprite(gr_vissprite_t *spr)
//Hurdler: 25/04/2000: now support colormap in hardware mode
HWR_GetMappedPatch(gpatch, spr->colormap);
#ifdef GLBADSHADOWS
// Draw shadow BEFORE sprite
if (cv_shadow.value // Shadows enabled
&& (spr->mobj->flags & (MF_SCENERY|MF_SPAWNCEILING|MF_NOGRAVITY)) != (MF_SCENERY|MF_SPAWNCEILING|MF_NOGRAVITY) // Ceiling scenery have no shadow.
&& !(spr->mobj->flags2 & MF2_DEBRIS) // Debris have no corona or shadow.
#ifdef ALAM_LIGHTING
&& !(t_lspr[spr->mobj->sprite]->type // Things with dynamic lights have no shadow.
&& (!spr->mobj->player || spr->mobj->player->powers[pw_super])) // Except for non-super players.
#endif
&& (spr->mobj->z >= spr->mobj->floorz)) // Without this, your shadow shows on the floor, even after you die and fall through the ground.
{
////////////////////
// SHADOW SPRITE! //
////////////////////
HWR_DrawSpriteShadow(spr, gpatch, this_scale);
}
#endif //#ifdef GLBADSHADOWS
// if it has a dispoffset, push it a little towards the camera
if (spr->dispoffset) {
float co = -gr_viewcos*(0.05f*spr->dispoffset);
@ -5407,6 +5282,12 @@ static void HWR_DrawSprites(void)
HWR_DrawPrecipitationSprite(spr);
else
#endif
{
if (spr->mobj && spr->mobj->shadowscale && cv_shadow.value)
{
HWR_DrawDropShadow(spr->mobj, spr, spr->mobj->shadowscale);
}
if (spr->mobj && spr->mobj->skin && spr->mobj->sprite == SPR_PLAY)
{
if (!cv_grmodels.value || md2_playermodels[(skin_t*)spr->mobj->skin-skins].notfound || md2_playermodels[(skin_t*)spr->mobj->skin-skins].scale < 0.0f)
@ -5427,6 +5308,7 @@ static void HWR_DrawSprites(void)
HWR_DrawSprite(spr);
}
}
}
}
}
}

View File

@ -654,7 +654,7 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
M_GetText("Illegal say command received from %s while muted\n") : M_GetText("Illegal csay command received from non-admin %s\n"),
player_names[playernum]);
if (server)
SendKick(playernum, KICK_MSG_CON_FAIL);
SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
return;
}
@ -668,7 +668,7 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
{
CONS_Alert(CONS_WARNING, M_GetText("Illegal say command received from %s containing invalid characters\n"), player_names[playernum]);
if (server)
SendKick(playernum, KICK_MSG_CON_FAIL);
SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
return;
}
}
@ -2369,7 +2369,7 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I
if (!splitscreen) // don't draw it on splitscreen,
{
if (!(tab[i].num == serverplayer))
if (!(tab[i].num == serverplayer || players[tab[i].num].quittime))
HU_drawPing(x+ 253, y, playerpingtable[tab[i].num], false, 0);
//else
// V_DrawSmallString(x+ 246, y+4, V_YELLOWMAP, "SERVER");
@ -2568,7 +2568,7 @@ static void HU_Draw32TeamTabRankings(playersort_t *tab, INT32 whiteplayer)
V_DrawRightAlignedThinString(x+128, y, ((players[tab[i].num].spectator || players[tab[i].num].playerstate == PST_DEAD) ? 0 : V_TRANSLUCENT), va("%u", tab[i].count));
if (!splitscreen)
{
if (!(tab[i].num == serverplayer))
if (!(tab[i].num == serverplayer || players[tab[i].num].quittime))
HU_drawPing(x+ 135, y+1, playerpingtable[tab[i].num], true, 0);
//else
//V_DrawSmallString(x+ 129, y+4, V_YELLOWMAP, "HOST");
@ -2692,7 +2692,7 @@ void HU_DrawTeamTabRankings(playersort_t *tab, INT32 whiteplayer)
V_DrawRightAlignedThinString(x+100, y, (greycheck ? V_TRANSLUCENT : 0), va("%u", tab[i].count));
if (!splitscreen)
{
if (!(tab[i].num == serverplayer))
if (!(tab[i].num == serverplayer || players[tab[i].num].quittime))
HU_drawPing(x+ 113, y, playerpingtable[tab[i].num], false, 0);
//else
// V_DrawSmallString(x+ 94, y+4, V_YELLOWMAP, "SERVER");
@ -2723,7 +2723,7 @@ void HU_DrawDualTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scoreline
supercheck = supercheckdef;
strlcpy(name, tab[i].name, 7);
if (!(tab[i].num == serverplayer))
if (!(tab[i].num == serverplayer || players[tab[i].num].quittime))
HU_drawPing(x+ 113, y, playerpingtable[tab[i].num], false, 0);
//else
// V_DrawSmallString(x+ 94, y+4, V_YELLOWMAP, "SERVER");
@ -2831,7 +2831,7 @@ static void HU_Draw32TabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scor
strlcpy(name, tab[i].name, 7);
if (!splitscreen) // don't draw it on splitscreen,
{
if (!(tab[i].num == serverplayer))
if (!(tab[i].num == serverplayer || players[tab[i].num].quittime))
HU_drawPing(x+ 135, y+1, playerpingtable[tab[i].num], true, 0);
//else
// V_DrawSmallString(x+ 129, y+4, V_YELLOWMAP, "HOST");

View File

@ -2193,11 +2193,11 @@ static int lib_rPointInSubsector(lua_State *L)
return 1;
}
static int lib_rIsPointInSubsector(lua_State *L)
static int lib_rPointInSubsectorOrNil(lua_State *L)
{
fixed_t x = luaL_checkfixed(L, 1);
fixed_t y = luaL_checkfixed(L, 2);
subsector_t *sub = R_IsPointInSubsector(x, y);
subsector_t *sub = R_PointInSubsectorOrNull(x, y);
//HUDSAFE
INLEVEL
if (sub)
@ -3141,7 +3141,7 @@ static luaL_Reg lib[] = {
{"R_PointToDist",lib_rPointToDist},
{"R_PointToDist2",lib_rPointToDist2},
{"R_PointInSubsector",lib_rPointInSubsector},
{"R_IsPointInSubsector",lib_rIsPointInSubsector},
{"R_PointInSubsectorOrNil",lib_rPointInSubsectorOrNil},
// r_things (sprite)
{"R_Char2Frame",lib_rChar2Frame},

View File

@ -87,7 +87,7 @@ deny:
CONS_Alert(CONS_WARNING, M_GetText("Illegal lua command received from %s\n"), player_names[playernum]);
if (server)
SendKick(playernum, KICK_MSG_CON_FAIL);
SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
}
// Wrapper for COM_AddCommand commands

View File

@ -102,7 +102,7 @@ boolean LUAh_HurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source, UINT8
boolean LUAh_MapThingSpawn(mobj_t *mo, mapthing_t *mthing); // Hook for P_SpawnMapThing by mobj type
boolean LUAh_FollowMobj(player_t *player, mobj_t *mobj); // Hook for P_PlayerAfterThink Smiles mobj-following
UINT8 LUAh_PlayerCanDamage(player_t *player, mobj_t *mobj); // Hook for P_PlayerCanDamage
void LUAh_PlayerQuit(player_t *plr, int reason); // Hook for player quitting
void LUAh_PlayerQuit(player_t *plr, kickreason_t reason); // Hook for player quitting
void LUAh_IntermissionThinker(void); // Hook for Y_Ticker
boolean LUAh_TeamSwitch(player_t *player, int newteam, boolean fromspectators, boolean tryingautobalance, boolean tryingscramble); // Hook for team switching in... uh....
UINT8 LUAh_ViewpointSwitch(player_t *player, player_t *newdisplayplayer, boolean forced); // Hook for spy mode

View File

@ -1439,7 +1439,7 @@ UINT8 LUAh_PlayerCanDamage(player_t *player, mobj_t *mobj)
return shouldCollide;
}
void LUAh_PlayerQuit(player_t *plr, int reason)
void LUAh_PlayerQuit(player_t *plr, kickreason_t reason)
{
hook_p hookp;
if (!gL || !(hooksAvailable[hook_PlayerQuit/8] & (1<<(hook_PlayerQuit%8))))

View File

@ -364,6 +364,8 @@ static int player_get(lua_State *L)
lua_pushinteger(L, plr->bot);
else if (fastcmp(field,"jointime"))
lua_pushinteger(L, plr->jointime);
else if (fastcmp(field,"quittime"))
lua_pushinteger(L, plr->quittime);
#ifdef HWRENDER
else if (fastcmp(field,"fovadd"))
lua_pushfixed(L, plr->fovadd);
@ -705,6 +707,8 @@ static int player_set(lua_State *L)
return NOSET;
else if (fastcmp(field,"jointime"))
plr->jointime = (tic_t)luaL_checkinteger(L, 3);
else if (fastcmp(field,"quittime"))
plr->quittime = (tic_t)luaL_checkinteger(L, 3);
#ifdef HWRENDER
else if (fastcmp(field,"fovadd"))
plr->fovadd = luaL_checkfixed(L, 3);

View File

@ -452,7 +452,7 @@ void Command_RTeleport_f(void)
else
inty = 0;
ss = R_IsPointInSubsector(p->mo->x + intx*FRACUNIT, p->mo->y + inty*FRACUNIT);
ss = R_PointInSubsectorOrNull(p->mo->x + intx*FRACUNIT, p->mo->y + inty*FRACUNIT);
if (!ss || ss->sector->ceilingheight - ss->sector->floorheight < p->mo->height)
{
CONS_Alert(CONS_NOTICE, M_GetText("Not a valid location.\n"));
@ -530,7 +530,7 @@ void Command_Teleport_f(void)
inty = mt->y<<FRACBITS;
offset = mt->z<<FRACBITS;
ss = R_IsPointInSubsector(intx, inty);
ss = R_PointInSubsectorOrNull(intx, inty);
if (!ss || ss->sector->ceilingheight - ss->sector->floorheight < p->mo->height)
{
CONS_Alert(CONS_NOTICE, M_GetText("Spawnpoint not in a valid location.\n"));
@ -597,7 +597,7 @@ void Command_Teleport_f(void)
return;
}
ss = R_IsPointInSubsector(mo2->x, mo2->y);
ss = R_PointInSubsectorOrNull(mo2->x, mo2->y);
if (!ss || ss->sector->ceilingheight - ss->sector->floorheight < p->mo->height)
{
CONS_Alert(CONS_NOTICE, M_GetText("Starpost not in a valid location.\n"));
@ -653,7 +653,7 @@ void Command_Teleport_f(void)
}
}
ss = R_IsPointInSubsector(intx, inty);
ss = R_PointInSubsectorOrNull(intx, inty);
if (!ss || ss->sector->ceilingheight - ss->sector->floorheight < p->mo->height)
{
CONS_Alert(CONS_NOTICE, M_GetText("Not a valid location.\n"));

View File

@ -1584,32 +1584,33 @@ static menuitem_t OP_ServerOptionsMenu[] =
{IT_STRING | IT_CVAR, NULL, "Players required for exit", &cv_playersforexit, 96},
{IT_STRING | IT_CVAR, NULL, "Starposts", &cv_coopstarposts, 101},
{IT_STRING | IT_CVAR, NULL, "Life sharing", &cv_cooplives, 106},
{IT_STRING | IT_CVAR, NULL, "Post-goal free roaming", &cv_exitmove, 111},
{IT_HEADER, NULL, "Race, Competition", NULL, 115},
{IT_STRING | IT_CVAR, NULL, "Level completion countdown", &cv_countdowntime, 121},
{IT_STRING | IT_CVAR, NULL, "Item Monitors", &cv_competitionboxes, 126},
{IT_HEADER, NULL, "Race, Competition", NULL, 120},
{IT_STRING | IT_CVAR, NULL, "Level completion countdown", &cv_countdowntime, 126},
{IT_STRING | IT_CVAR, NULL, "Item Monitors", &cv_competitionboxes, 131},
{IT_HEADER, NULL, "Ringslinger (Match, CTF, Tag, H&S)", NULL, 135},
{IT_STRING | IT_CVAR, NULL, "Time Limit", &cv_timelimit, 141},
{IT_STRING | IT_CVAR, NULL, "Score Limit", &cv_pointlimit, 146},
{IT_STRING | IT_CVAR, NULL, "Overtime on Tie", &cv_overtime, 151},
{IT_STRING | IT_CVAR, NULL, "Player respawn delay", &cv_respawntime, 156},
{IT_HEADER, NULL, "Ringslinger (Match, CTF, Tag, H&S)", NULL, 140},
{IT_STRING | IT_CVAR, NULL, "Time Limit", &cv_timelimit, 146},
{IT_STRING | IT_CVAR, NULL, "Score Limit", &cv_pointlimit, 151},
{IT_STRING | IT_CVAR, NULL, "Overtime on Tie", &cv_overtime, 156},
{IT_STRING | IT_CVAR, NULL, "Player respawn delay", &cv_respawntime, 161},
{IT_STRING | IT_CVAR, NULL, "Item Monitors", &cv_matchboxes, 166},
{IT_STRING | IT_CVAR, NULL, "Weapon Rings", &cv_specialrings, 171},
{IT_STRING | IT_CVAR, NULL, "Power Stones", &cv_powerstones, 176},
{IT_STRING | IT_CVAR, NULL, "Item Monitors", &cv_matchboxes, 171},
{IT_STRING | IT_CVAR, NULL, "Weapon Rings", &cv_specialrings, 176},
{IT_STRING | IT_CVAR, NULL, "Power Stones", &cv_powerstones, 181},
{IT_STRING | IT_CVAR, NULL, "Flag respawn delay", &cv_flagtime, 186},
{IT_STRING | IT_CVAR, NULL, "Hiding time", &cv_hidetime, 191},
{IT_STRING | IT_CVAR, NULL, "Flag respawn delay", &cv_flagtime, 191},
{IT_STRING | IT_CVAR, NULL, "Hiding time", &cv_hidetime, 196},
{IT_HEADER, NULL, "Teams", NULL, 200},
{IT_STRING | IT_CVAR, NULL, "Autobalance sizes", &cv_autobalance, 206},
{IT_STRING | IT_CVAR, NULL, "Scramble on Map Change", &cv_scrambleonchange, 211},
{IT_HEADER, NULL, "Teams", NULL, 205},
{IT_STRING | IT_CVAR, NULL, "Autobalance sizes", &cv_autobalance, 211},
{IT_STRING | IT_CVAR, NULL, "Scramble on Map Change", &cv_scrambleonchange, 216},
#ifndef NONET
{IT_HEADER, NULL, "Advanced", NULL, 220},
{IT_STRING | IT_CVAR | IT_CV_STRING, NULL, "Master server", &cv_masterserver, 226},
{IT_STRING | IT_CVAR, NULL, "Attempts to resynchronise", &cv_resynchattempts, 240},
{IT_HEADER, NULL, "Advanced", NULL, 225},
{IT_STRING | IT_CVAR | IT_CV_STRING, NULL, "Master server", &cv_masterserver, 231},
{IT_STRING | IT_CVAR, NULL, "Attempts to resynchronise", &cv_resynchattempts, 245},
#endif
};
@ -3757,6 +3758,12 @@ void M_SetupNextMenu(menu_t *menudef)
hidetitlemap = false;
}
// Guess I'll put this here, idk
boolean M_MouseNeeded(void)
{
return (currentMenu == &MessageDef && currentMenu->prevMenu == &OP_ChangeControlsDef);
}
//
// M_Ticker
//
@ -10632,8 +10639,8 @@ static void M_ServerOptions(INT32 choice)
OP_ServerOptionsMenu[ 2].status = IT_GRAYEDOUT; // Max players
OP_ServerOptionsMenu[ 3].status = IT_GRAYEDOUT; // Allow add-on downloading
OP_ServerOptionsMenu[ 4].status = IT_GRAYEDOUT; // Allow players to join
OP_ServerOptionsMenu[34].status = IT_GRAYEDOUT; // Master server
OP_ServerOptionsMenu[35].status = IT_GRAYEDOUT; // Attempts to resynchronise
OP_ServerOptionsMenu[35].status = IT_GRAYEDOUT; // Master server
OP_ServerOptionsMenu[36].status = IT_GRAYEDOUT; // Attempts to resynchronise
}
else
{
@ -10641,10 +10648,10 @@ static void M_ServerOptions(INT32 choice)
OP_ServerOptionsMenu[ 2].status = IT_STRING | IT_CVAR;
OP_ServerOptionsMenu[ 3].status = IT_STRING | IT_CVAR;
OP_ServerOptionsMenu[ 4].status = IT_STRING | IT_CVAR;
OP_ServerOptionsMenu[34].status = (netgame
OP_ServerOptionsMenu[35].status = (netgame
? IT_GRAYEDOUT
: (IT_STRING | IT_CVAR | IT_CV_STRING));
OP_ServerOptionsMenu[35].status = IT_STRING | IT_CVAR;
OP_ServerOptionsMenu[36].status = IT_STRING | IT_CVAR;
}
#endif

View File

@ -322,6 +322,9 @@ typedef struct menu_s
void M_SetupNextMenu(menu_t *menudef);
void M_ClearMenus(boolean callexitmenufunc);
// Maybe this goes here????? Who knows.
boolean M_MouseNeeded(void);
extern menu_t *currentMenu;
extern menu_t MainDef;

View File

@ -746,6 +746,9 @@ boolean P_LookForPlayers(mobj_t *actor, boolean allaround, boolean tracer, fixed
if (player->bot)
continue; // ignore bots
if (player->quittime)
continue; // Ignore uncontrolled bodies
if (dist > 0
&& P_AproxDistance(P_AproxDistance(player->mo->x - actor->x, player->mo->y - actor->y), player->mo->z - actor->z) > dist)
continue; // Too far away

View File

@ -2257,9 +2257,9 @@ void P_CheckSurvivors(void)
{
if (players[i].spectator)
spectators++;
else if (players[i].pflags & PF_TAGIT)
else if ((players[i].pflags & PF_TAGIT) && players[i].quittime < 30 * TICRATE)
taggers++;
else if (!(players[i].pflags & PF_GAMETYPEOVER))
else if (!(players[i].pflags & PF_GAMETYPEOVER) && players[i].quittime < 30 * TICRATE)
{
survivorarray[survivors] = i;
survivors++;

View File

@ -3396,7 +3396,7 @@ void P_MobjCheckWater(mobj_t *mobj)
if (!((p->powers[pw_super]) || (p->powers[pw_invulnerability])))
{
boolean electric = !!(p->powers[pw_shield] & SH_PROTECTELECTRIC);
if (electric || ((p->powers[pw_shield] & SH_PROTECTFIRE) && !(p->powers[pw_shield] & SH_PROTECTWATER)))
if (electric || ((p->powers[pw_shield] & SH_PROTECTFIRE) && !(p->powers[pw_shield] & SH_PROTECTWATER) && !(mobj->eflags & MFE_TOUCHLAVA)))
{ // Water removes electric and non-water fire shields...
P_FlashPal(p,
electric
@ -11114,7 +11114,7 @@ void P_SpawnPrecipitation(void)
x = basex + ((M_RandomKey(MAPBLOCKUNITS<<3)<<FRACBITS)>>3);
y = basey + ((M_RandomKey(MAPBLOCKUNITS<<3)<<FRACBITS)>>3);
precipsector = R_IsPointInSubsector(x, y);
precipsector = R_PointInSubsectorOrNull(x, y);
// No sector? Stop wasting time,
// move on to the next entry in the blockmap

View File

@ -256,6 +256,7 @@ static void P_NetArchivePlayers(void)
WRITEINT32(save_p, players[i].onconveyor);
WRITEUINT32(save_p, players[i].jointime);
WRITEUINT32(save_p, players[i].quittime);
WRITEUINT16(save_p, flags);
@ -448,6 +449,7 @@ static void P_NetUnArchivePlayers(void)
players[i].onconveyor = READINT32(save_p);
players[i].jointime = READUINT32(save_p);
players[i].quittime = READUINT32(save_p);
flags = READUINT16(save_p);

View File

@ -411,7 +411,7 @@ levelflat refers to an array of level flats,
or NULL if we want to allocate it now.
*/
static INT32
Ploadflat (levelflat_t *levelflat, const char *flatname)
Ploadflat (levelflat_t *levelflat, const char *flatname, boolean resize)
{
#ifndef NO_PNG_LUMPS
UINT8 buffer[8];
@ -422,31 +422,26 @@ Ploadflat (levelflat_t *levelflat, const char *flatname)
size_t i;
if (levelflat)
// Scan through the already found flats, return if it matches.
for (i = 0; i < numlevelflats; i++)
{
// Scan through the already found flats, return if it matches.
for (i = 0; i < numlevelflats; i++)
{
if (strnicmp(levelflat[i].name, flatname, 8) == 0)
return i;
}
if (strnicmp(levelflat[i].name, flatname, 8) == 0)
return i;
}
#ifndef ZDEBUG
CONS_Debug(DBG_SETUP, "flat #%03d: %s\n", atoi(sizeu1(numlevelflats)), levelflat->name);
#endif
if (numlevelflats >= MAXLEVELFLATS)
I_Error("Too many flats in level\n");
if (levelflat)
levelflat += numlevelflats;
else
if (resize)
{
// allocate new flat memory
levelflats = Z_Realloc(levelflats, (numlevelflats + 1) * sizeof(*levelflats), PU_LEVEL, NULL);
levelflat = levelflats + numlevelflats;
}
else
{
if (numlevelflats >= MAXLEVELFLATS)
I_Error("Too many flats in level\n");
levelflat += numlevelflats;
}
// Store the name.
strlcpy(levelflat->name, flatname, sizeof (levelflat->name));
@ -501,6 +496,10 @@ flatfound:
levelflat->u.flat.baselumpnum = LUMPERROR;
}
#ifndef ZDEBUG
CONS_Debug(DBG_SETUP, "flat #%03d: %s\n", atoi(sizeu1(numlevelflats)), levelflat->name);
#endif
return ( numlevelflats++ );
}
@ -508,7 +507,7 @@ flatfound:
// allocate an id for it, and set the levelflat (to speedup search)
INT32 P_AddLevelFlat(const char *flatname, levelflat_t *levelflat)
{
return Ploadflat(levelflat, flatname);
return Ploadflat(levelflat, flatname, false);
}
// help function for Lua and $$$.sav reading
@ -517,7 +516,7 @@ INT32 P_AddLevelFlat(const char *flatname, levelflat_t *levelflat)
//
INT32 P_AddLevelFlatRuntime(const char *flatname)
{
return Ploadflat(levelflats, flatname);
return Ploadflat(levelflats, flatname, true);
}
// help function for $$$.sav checking
@ -3097,7 +3096,7 @@ static void P_InitTagGametype(void)
//Also, you'd never have to loop through all 32 players slots to find anything ever again.
for (i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i] && !players[i].spectator)
if (playeringame[i] && !(players[i].spectator && players[i].quittime))
{
playersactive[realnumplayers] = i; //stores the player's node in the array.
realnumplayers++;
@ -3119,7 +3118,7 @@ static void P_InitTagGametype(void)
if (players[playersactive[i]].mo)
P_RemoveMobj(players[playersactive[i]].mo);
G_SpawnPlayer(playersactive[i], false); //respawn the lucky player in his dedicated spawn location.
G_SpawnPlayer(playersactive[i]); //respawn the lucky player in his dedicated spawn location.
}
static void P_SetupCamera(void)
@ -3297,7 +3296,7 @@ static void P_InitPlayers(void)
G_DoReborn(i);
else // gametype is GT_COOP or GT_RACE
{
G_SpawnPlayer(i, players[i].starposttime);
G_SpawnPlayer(i);
if (players[i].starposttime)
P_ClearStarPost(players[i].starpostnum);
}

View File

@ -4426,10 +4426,18 @@ void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *rovers
case 6: // Death Pit (Camera Mod)
case 7: // Death Pit (No Camera Mod)
if (roversector || P_MobjReadyToTrigger(player->mo, sector))
P_DamageMobj(player->mo, NULL, NULL, 1, DMG_DEATHPIT);
{
if (player->quittime)
G_MovePlayerToSpawnOrStarpost(player - players);
else
P_DamageMobj(player->mo, NULL, NULL, 1, DMG_DEATHPIT);
}
break;
case 8: // Instant Kill
P_DamageMobj(player->mo, NULL, NULL, 1, DMG_INSTAKILL);
if (player->quittime)
G_MovePlayerToSpawnOrStarpost(player - players);
else
P_DamageMobj(player->mo, NULL, NULL, 1, DMG_INSTAKILL);
break;
case 9: // Ring Drainer (Floor Touch)
case 10: // Ring Drainer (No Floor Touch)

View File

@ -590,10 +590,24 @@ void P_Ticker(boolean run)
{
INT32 i;
//Increment jointime even if paused.
// Increment jointime and quittime even if paused
for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i])
++players[i].jointime;
{
players[i].jointime++;
if (players[i].quittime)
{
players[i].quittime++;
if (players[i].quittime == 30 * TICRATE)
P_CheckSurvivors();
if (server && players[i].quittime >= (tic_t)FixedMul(cv_rejointimeout.value, 60 * TICRATE)
&& !(players[i].quittime % TICRATE))
SendKick(i, KICK_MSG_PLAYER_QUIT);
}
}
if (objectplacing)
{

View File

@ -3160,7 +3160,7 @@ static void P_DoClimbing(player_t *player)
platx = P_ReturnThrustX(player->mo, player->mo->angle, player->mo->radius + FixedMul(8*FRACUNIT, player->mo->scale));
platy = P_ReturnThrustY(player->mo, player->mo->angle, player->mo->radius + FixedMul(8*FRACUNIT, player->mo->scale));
glidesector = R_IsPointInSubsector(player->mo->x + platx, player->mo->y + platy);
glidesector = R_PointInSubsectorOrNull(player->mo->x + platx, player->mo->y + platy);
{
boolean floorclimb = false;
@ -10237,7 +10237,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
}
// move camera down to move under lower ceilings
newsubsec = R_IsPointInSubsector(((mo->x>>FRACBITS) + (thiscam->x>>FRACBITS))<<(FRACBITS-1), ((mo->y>>FRACBITS) + (thiscam->y>>FRACBITS))<<(FRACBITS-1));
newsubsec = R_PointInSubsectorOrNull(((mo->x>>FRACBITS) + (thiscam->x>>FRACBITS))<<(FRACBITS-1), ((mo->y>>FRACBITS) + (thiscam->y>>FRACBITS))<<(FRACBITS-1));
if (!newsubsec)
newsubsec = thiscam->subsector;
@ -11758,6 +11758,8 @@ void P_PlayerThink(player_t *player)
{
if (!playeringame[i] || players[i].spectator || players[i].bot)
continue;
if (players[i].quittime > 30 * TICRATE)
continue;
if (players[i].lives <= 0)
continue;
@ -12210,6 +12212,11 @@ void P_PlayerThink(player_t *player)
player->pflags &= ~PF_USEDOWN;
}
// IF PLAYER NOT HERE THEN FLASH END IF
if (player->quittime && player->powers[pw_flashing] < flashingtics - 1
&& !(G_TagGametype() && !(player->pflags & PF_TAGIT)) && !player->gotflag)
player->powers[pw_flashing] = flashingtics - 1;
// Counters, time dependent power ups.
// Time Bonus & Ring Bonus count settings
@ -12253,12 +12260,12 @@ void P_PlayerThink(player_t *player)
else
player->powers[pw_underwater] = 0;
}
else if (player->powers[pw_underwater] && !(maptol & TOL_NIGHTS) && !((netgame || multiplayer) && player->spectator)) // underwater timer
else if (player->powers[pw_underwater] && !(maptol & TOL_NIGHTS) && !((netgame || multiplayer) && (player->spectator || player->quittime))) // underwater timer
player->powers[pw_underwater]--;
if (player->powers[pw_spacetime] && (player->pflags & PF_GODMODE || (player->powers[pw_shield] & SH_PROTECTWATER)))
player->powers[pw_spacetime] = 0;
else if (player->powers[pw_spacetime] && !(maptol & TOL_NIGHTS) && !((netgame || multiplayer) && player->spectator)) // underwater timer
else if (player->powers[pw_spacetime] && !(maptol & TOL_NIGHTS) && !((netgame || multiplayer) && (player->spectator || player->quittime))) // underwater timer
player->powers[pw_spacetime]--;
if (player->powers[pw_gravityboots] && player->powers[pw_gravityboots] < UINT16_MAX)

View File

@ -129,9 +129,6 @@ consvar_t cv_flipcam = {"flipcam", "No", CV_SAVE|CV_CALL|CV_NOINIT, CV_YesNo, Fl
consvar_t cv_flipcam2 = {"flipcam2", "No", CV_SAVE|CV_CALL|CV_NOINIT, CV_YesNo, FlipCam2_OnChange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_shadow = {"shadow", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
#ifdef GLBADSHADOWS
consvar_t cv_shadowoffs = {"offsetshadows", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
#endif //#ifdef GLBADSHADOWS
consvar_t cv_skybox = {"skybox", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_allowmlook = {"allowmlook", "Yes", CV_NETVAR, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_showhud = {"showhud", "Yes", CV_CALL, CV_YesNo, R_SetViewSize, 0, NULL, NULL, 0, 0, NULL};
@ -1001,9 +998,9 @@ subsector_t *R_PointInSubsector(fixed_t x, fixed_t y)
}
//
// R_IsPointInSubsector, same as above but returns 0 if not in subsector
// R_PointInSubsectorOrNull, same as above but returns 0 if not in subsector
//
subsector_t *R_IsPointInSubsector(fixed_t x, fixed_t y)
subsector_t *R_PointInSubsectorOrNull(fixed_t x, fixed_t y)
{
node_t *node;
INT32 side, i;
@ -1531,10 +1528,8 @@ void R_RegisterEngineStuff(void)
CV_RegisterVar(&cv_chasecam);
CV_RegisterVar(&cv_chasecam2);
CV_RegisterVar(&cv_shadow);
#ifdef GLBADSHADOWS
CV_RegisterVar(&cv_shadowoffs);
#endif //#ifdef GLBADSHADOWS
CV_RegisterVar(&cv_skybox);
CV_RegisterVar(&cv_cam_dist);

View File

@ -67,7 +67,7 @@ fixed_t R_PointToDist2(fixed_t px2, fixed_t py2, fixed_t px1, fixed_t py1);
fixed_t R_ScaleFromGlobalAngle(angle_t visangle);
subsector_t *R_PointInSubsector(fixed_t x, fixed_t y);
subsector_t *R_IsPointInSubsector(fixed_t x, fixed_t y);
subsector_t *R_PointInSubsectorOrNull(fixed_t x, fixed_t y);
boolean R_DoCulling(line_t *cullheight, line_t *viewcullheight, fixed_t vz, fixed_t bottomh, fixed_t toph);
@ -79,10 +79,8 @@ extern consvar_t cv_showhud, cv_translucenthud;
extern consvar_t cv_homremoval;
extern consvar_t cv_chasecam, cv_chasecam2;
extern consvar_t cv_flipcam, cv_flipcam2;
extern consvar_t cv_shadow;
#ifdef GLBADSHADOWS
extern conscar_t cv_shadowoffs;
#endif //#ifdef GLBADSHADOWS
extern consvar_t cv_translucency;
extern consvar_t cv_drawdist, cv_drawdist_nights, cv_drawdist_precip;
extern consvar_t cv_fov;

View File

@ -1441,6 +1441,12 @@ static tic_t pause_starttic;
/// Music Definitions
/// ------------------------
enum
{
MUSICDEF_220,
MUSICDEF_221,
};
musicdef_t soundtestsfx = {
"_STSFX", // prevents exactly one valid track name from being used on the sound test
"Sound Effects",
@ -1472,188 +1478,164 @@ static UINT16 W_CheckForMusicDefInPwad(UINT16 wadid)
return INT16_MAX; // not found
}
void S_LoadMusicDefs(UINT16 wadnum)
static void
MusicDefStrcpy (char *p, const char *s, size_t n, int version)
{
UINT16 lumpnum;
char *lump, *buf;
char *musdeftext;
char *stoken;
strlcpy(p, s, n);
if (version == MUSICDEF_220)
{
while (( p = strchr(p, '_') ))
*p++ = ' '; // turn _ into spaces.
}
}
static boolean
ReadMusicDefFields (UINT16 wadnum, int line, boolean fields, char *stoken,
musicdef_t **defp, int *versionp)
{
musicdef_t *def;
int version;
char *value;
char *textline;
size_t size;
INT32 i;
musicdef_t *def = NULL;
UINT16 line = 1; // for better error msgs
int i;
lumpnum = W_CheckForMusicDefInPwad(wadnum);
if (lumpnum == INT16_MAX)
return;
lump = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE);
size = W_LumpLengthPwad(wadnum, lumpnum);
// Null-terminated MUSICDEF lump.
musdeftext = malloc(size+1);
if (!musdeftext)
I_Error("S_LoadMusicDefs: No more free memory for the parser\n");
M_Memcpy(musdeftext, lump, size);
musdeftext[size] = '\0';
// for strtok
buf = malloc(size+1);
if (!buf)
I_Error("S_LoadMusicDefs: No more free memory for the parser\n");
M_Memcpy(buf, musdeftext, size+1);
stoken = strtok(buf, "\r\n ");
// Find music def
while (stoken)
if (!stricmp(stoken, "lump"))
{
/*if ((stoken[0] == '/' && stoken[1] == '/')
|| (stoken[0] == '#')) // skip comments
value = strtok(NULL, " ");
if (!value)
{
stoken = strtok(NULL, "\r\n"); // skip end of line
if (def)
stoken = strtok(NULL, "\r\n= ");
else
stoken = strtok(NULL, "\r\n ");
line++;
}
else*/ if (!stricmp(stoken, "lump"))
{
value = strtok(NULL, "\r\n ");
if (!value)
{
CONS_Alert(CONS_WARNING, "MUSICDEF: Lump '%s' is missing name. (file %s, line %d)\n", stoken, wadfiles[wadnum]->filename, line);
stoken = strtok(NULL, "\r\n"); // skip end of line
goto skip_lump;
}
// No existing musicdefs
/*if (!musicdefstart)
{
musicdefstart = Z_Calloc(sizeof (musicdef_t), PU_STATIC, NULL);
STRBUFCPY(musicdefstart->name, value);
strlwr(musicdefstart->name);
def = musicdefstart;
//CONS_Printf("S_LoadMusicDefs: Initialized musicdef w/ song '%s'\n", def->name);
}
else*/
{
musicdef_t *prev = NULL;
def = musicdefstart;
// Search if this is a replacement
//CONS_Printf("S_LoadMusicDefs: Searching for song replacement...\n");
while (def)
{
if (!stricmp(def->name, value))
{
//CONS_Printf("S_LoadMusicDefs: Found song replacement '%s'\n", def->name);
break;
}
prev = def;
def = def->next;
}
// Nothing found, add to the end.
if (!def)
{
def = Z_Calloc(sizeof (musicdef_t), PU_STATIC, NULL);
STRBUFCPY(def->name, value);
strlwr(def->name);
def->bpm = TICRATE<<(FRACBITS-1); // FixedDiv((60*TICRATE)<<FRACBITS, 120<<FRACBITS)
if (prev != NULL)
prev->next = def;
//CONS_Printf("S_LoadMusicDefs: Added song '%s'\n", def->name);
}
}
skip_lump:
stoken = strtok(NULL, "\r\n ");
line++;
CONS_Alert(CONS_WARNING,
"MUSICDEF: Field '%s' is missing name. (file %s, line %d)\n",
stoken, wadfiles[wadnum]->filename, line);
return false;
}
else
{
// If this is set true, the line was invalid.
boolean brokenline = false;
musicdef_t *prev = NULL;
def = musicdefstart;
// Delimit only by line break.
value = strtok(NULL, "\r\n");
// Search if this is a replacement
//CONS_Printf("S_LoadMusicDefs: Searching for song replacement...\n");
while (def)
{
if (!stricmp(def->name, value))
{
//CONS_Printf("S_LoadMusicDefs: Found song replacement '%s'\n", def->name);
break;
}
// Find the equals sign.
value = strchr(value, '=');
prev = def;
def = def->next;
}
// It's not there?!
// Nothing found, add to the end.
if (!def)
{
def = Z_Calloc(sizeof (musicdef_t), PU_STATIC, NULL);
STRBUFCPY(def->name, value);
strlwr(def->name);
def->bpm = TICRATE<<(FRACBITS-1); // FixedDiv((60*TICRATE)<<FRACBITS, 120<<FRACBITS)
if (prev != NULL)
prev->next = def;
//CONS_Printf("S_LoadMusicDefs: Added song '%s'\n", def->name);
}
(*defp) = def;
}
}
else if (!stricmp(stoken, "version"))
{
if (fields)/* is this not the first field? */
{
CONS_Alert(CONS_WARNING,
"MUSICDEF: Field '%s' must come first. (file %s, line %d)\n",
stoken, wadfiles[wadnum]->filename, line);
return false;
}
else
{
value = strtok(NULL, " ");
if (!value)
brokenline = true;
{
CONS_Alert(CONS_WARNING,
"MUSICDEF: Field '%s' is missing version. (file %s, line %d)\n",
stoken, wadfiles[wadnum]->filename, line);
return false;
}
else
{
if (strcasecmp(value, "2.2.0"))
(*versionp) = MUSICDEF_221;
}
}
}
else
{
version = (*versionp);
if (version == MUSICDEF_220)
value = strtok(NULL, " =");
else
{
value = strtok(NULL, "");
if (value)
{
// Find the equals sign.
value = strchr(value, '=');
}
}
if (!value)
{
CONS_Alert(CONS_WARNING,
"MUSICDEF: Field '%s' is missing value. (file %s, line %d)\n",
stoken, wadfiles[wadnum]->filename, line);
return false;
}
else
{
def = (*defp);
if (!def)
{
CONS_Alert(CONS_ERROR,
"MUSICDEF: No music definition before field '%s'. (file %s, line %d)\n",
stoken, wadfiles[wadnum]->filename, line);
return false;
}
if (version != MUSICDEF_220)
{
// Skip the equals sign.
value++;
// Now skip funny whitespace.
if (value[0] == '\0') // :NOTHING:
brokenline = true;
else
value += strspn(value, "\t ");
value += strspn(value, "\t ");
}
// If the line is valid, copy the text line from the lump data.
if (!brokenline)
{
// strtok returns memory that already belongs to the input string.
value = musdeftext + (value - buf);
// Find the length of the line.
size = strcspn(value, "\r\n");
// Copy the line.
textline = malloc(size+1);
if (!textline)
I_Error("S_LoadMusicDefs: No more free memory for text line\n");
M_Memcpy(textline, value, size);
textline[size] = '\0';
}
else
{
CONS_Alert(CONS_WARNING, "MUSICDEF: Field '%s' is missing value. (file %s, line %d)\n", stoken, wadfiles[wadnum]->filename, line);
stoken = strtok(NULL, "\r\n"); // skip end of line
goto skip_field;
}
if (!def)
{
CONS_Alert(CONS_ERROR, "MUSICDEF: No music definition before field '%s'. (file %s, line %d)\n", stoken, wadfiles[wadnum]->filename, line);
free(textline);
free(buf);
free(musdeftext);
return;
}
i = atoi(textline);
textline = value;
i = atoi(value);
/* based ignored lumps */
if (!stricmp(stoken, "usage")) {
#if 0 // Ignore for now
STRBUFCPY(def->usage, textline);
//CONS_Printf("S_LoadMusicDefs: Set usage to '%s'\n", def->usage);
#endif
} else if (!stricmp(stoken, "source")) {
#if 0 // Ignore for now
STRBUFCPY(def->source, textline);
//CONS_Printf("S_LoadMusicDefs: Set source to '%s'\n", def->usage);
#endif
} else if (!stricmp(stoken, "title")) {
STRBUFCPY(def->title, textline);
//CONS_Printf("S_LoadMusicDefs: Set title to '%s'\n", def->source);
MusicDefStrcpy(def->title, textline,
sizeof def->title, version);
} else if (!stricmp(stoken, "alttitle")) {
STRBUFCPY(def->alttitle, textline);
//CONS_Printf("S_LoadMusicDefs: Set alttitle to '%s'\n", def->source);
MusicDefStrcpy(def->alttitle, textline,
sizeof def->alttitle, version);
} else if (!stricmp(stoken, "authors")) {
STRBUFCPY(def->authors, textline);
//CONS_Printf("S_LoadMusicDefs: Set authors to '%s'\n", def->source);
MusicDefStrcpy(def->authors, textline,
sizeof def->authors, version);
} else if (!stricmp(stoken, "soundtestpage")) {
def->soundtestpage = (UINT8)i;
} else if (!stricmp(stoken, "soundtestcond")) {
@ -1670,21 +1652,90 @@ skip_lump:
if (bpmf > 0)
def->bpm = FixedDiv((60*TICRATE)<<FRACBITS, bpmf);
} else {
CONS_Alert(CONS_WARNING, "MUSICDEF: Invalid field '%s'. (file %s, line %d)\n", stoken, wadfiles[wadnum]->filename, line);
CONS_Alert(CONS_WARNING,
"MUSICDEF: Invalid field '%s'. (file %s, line %d)\n",
stoken, wadfiles[wadnum]->filename, line);
}
// Free the temporary text line from memory.
free(textline);
skip_field:
stoken = strtok(NULL, "\r\n= ");
line++;
}
}
free(buf);
return true;
}
void S_LoadMusicDefs(UINT16 wadnum)
{
UINT16 lumpnum;
char *lump;
char *musdeftext;
size_t size;
char *lf;
char *stoken;
size_t nlf;
size_t ncr;
musicdef_t *def = NULL;
int version = MUSICDEF_220;
int line = 1; // for better error msgs
boolean fields = false;
lumpnum = W_CheckForMusicDefInPwad(wadnum);
if (lumpnum == INT16_MAX)
return;
lump = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE);
size = W_LumpLengthPwad(wadnum, lumpnum);
// Null-terminated MUSICDEF lump.
musdeftext = malloc(size+1);
if (!musdeftext)
I_Error("S_LoadMusicDefs: No more free memory for the parser\n");
M_Memcpy(musdeftext, lump, size);
musdeftext[size] = '\0';
// Find music def
stoken = musdeftext;
for (;;)
{
lf = strpbrk(stoken, "\r\n");
if (lf)
{
if (*lf == '\n')
nlf = 1;
else
nlf = 0;
*lf++ = '\0';/* now we can delimit to here */
}
stoken = strtok(stoken, " ");
if (stoken)
{
if (! ReadMusicDefFields(wadnum, line, fields, stoken,
&def, &version))
break;
fields = true;
}
if (lf)
{
do
{
line += nlf;
ncr = strspn(lf, "\r");/* skip CR */
lf += ncr;
nlf = strspn(lf, "\n");
lf += nlf;
}
while (nlf || ncr) ;
stoken = lf;/* now the next nonempty line */
}
else
break;/* EOF */
}
free(musdeftext);
return;
}
//

View File

@ -110,7 +110,6 @@ static SDL_bool disable_fullscreen = SDL_FALSE;
#define USE_FULLSCREEN (disable_fullscreen||!allow_fullscreen)?0:cv_fullscreen.value
static SDL_bool disable_mouse = SDL_FALSE;
#define USE_MOUSEINPUT (!disable_mouse && cv_usemouse.value && havefocus)
#define IGNORE_MOUSE (!cv_alwaysgrabmouse.value && (menuactive || paused || con_destlines || chat_on || gamestate != GS_LEVEL))
#define MOUSE_MENU false //(!disable_mouse && cv_usemouse.value && menuactive && !USE_FULLSCREEN)
#define MOUSEBUTTONS_MAX MOUSEBUTTONS
@ -362,6 +361,17 @@ static INT32 Impl_SDL_Scancode_To_Keycode(SDL_Scancode code)
return 0;
}
static boolean IgnoreMouse(void)
{
if (cv_alwaysgrabmouse.value)
return false;
if (menuactive)
return !M_MouseNeeded();
if (paused || con_destlines || chat_on || gamestate != GS_LEVEL)
return true;
return false;
}
static void SDLdoGrabMouse(void)
{
SDL_ShowCursor(SDL_DISABLE);
@ -388,7 +398,7 @@ void I_UpdateMouseGrab(void)
{
if (SDL_WasInit(SDL_INIT_VIDEO) == SDL_INIT_VIDEO && window != NULL
&& SDL_GetMouseFocus() == window && SDL_GetKeyboardFocus() == window
&& USE_MOUSEINPUT && !IGNORE_MOUSE)
&& USE_MOUSEINPUT && !IgnoreMouse())
SDLdoGrabMouse();
}
@ -596,7 +606,7 @@ static void Impl_HandleWindowEvent(SDL_WindowEvent evt)
}
//else firsttimeonmouse = SDL_FALSE;
if (USE_MOUSEINPUT && !IGNORE_MOUSE)
if (USE_MOUSEINPUT && !IgnoreMouse())
SDLdoGrabMouse();
}
else if (!mousefocus && !kbfocus)
@ -647,7 +657,7 @@ static void Impl_HandleMouseMotionEvent(SDL_MouseMotionEvent evt)
if (USE_MOUSEINPUT)
{
if ((SDL_GetMouseFocus() != window && SDL_GetKeyboardFocus() != window) || (IGNORE_MOUSE && !firstmove))
if ((SDL_GetMouseFocus() != window && SDL_GetKeyboardFocus() != window) || (IgnoreMouse() && !firstmove))
{
SDLdoUngrabMouse();
firstmove = false;
@ -700,7 +710,7 @@ static void Impl_HandleMouseButtonEvent(SDL_MouseButtonEvent evt, Uint32 type)
// this apparently makes a mouse button down event but not a mouse button up event,
// resulting in whatever key was pressed down getting "stuck" if we don't ignore it.
// -- Monster Iestyn (28/05/18)
if (SDL_GetMouseFocus() != window || IGNORE_MOUSE)
if (SDL_GetMouseFocus() != window || IgnoreMouse())
return;
/// \todo inputEvent.button.which
@ -1082,7 +1092,7 @@ void I_StartupMouse(void)
}
else
firsttimeonmouse = SDL_FALSE;
if (cv_usemouse.value && !IGNORE_MOUSE)
if (cv_usemouse.value && !IgnoreMouse())
SDLdoGrabMouse();
else
SDLdoUngrabMouse();