Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • MY-audio
  • abnormal-shutdown
  • ashnal-dev
  • awful-mix-fucked
  • benice
  • beta
  • beta-b
  • beta-c
  • better-replays
  • chadyes
  • downloads-notice
  • easy-colors
  • findvar
  • fixsignalhandler
  • fixsignalhandler-resurrection
  • freeplay
  • fuckinghell
  • hole
  • http-mserv-12
  • kill-these-please-12
  • kill-these-please-kart-v1-edition
  • less-battle-vote
  • load-shit
  • local-skins
  • lol
  • map-by-name
  • master
  • modern-talk-via-console
  • more-files
  • more-files-take2
  • move-changeviewpoint
  • ms-connectionfail-fix
  • mserv-is-dumb-and-what-else-is-new
  • music-standalone
  • netplayground
  • netreplays-dedicated-sigsegv-fix
  • netreplays-resetview-sigsegv-fix
  • opengl-gif-port
  • optional-focuslost
  • packetversion-112
  • perpetual-modifier-updates
  • public
  • talk-via-console
  • testsignalhandler
  • unconfuse-nodes
  • unpause-resume-sounds
  • V1.0.0
  • v1.0.1
  • v1.0.2
49 results

Target

Select target project
  • KartKrew/Kart-Public
  • SteelT/Kart-Public
  • SSNTails/Kart-Public
  • mazmazz_/Kart-Public
  • james/Kart-Public
  • Latius/Kart-Public
  • alphaRexJames/Kart-Public
  • heyjoeway/Kart-Public
  • Namolos/Kart-Public
  • SinnamonLat/Kart-Public
  • filpAM/Kart-Public
  • wolfy852/Kart-Public
  • bird/Kart-Public
  • TehRealSalt/Kart-Public
  • Snu/Kart-Public
  • Tyron/Kart-Public
  • kimmy/Kart-Public
  • Spice/Kart-Public
  • Callmore/Kart-Public
  • JugadorXEI/Kart-Public
  • Fafabis/Kart-Public
  • cspotcode/Kart-Public
  • Lonsfor_/Kart-Public
  • brokenspleentec/Kart-Public
  • minenice/Kart-Public
  • Lighto97/Kart-Public
  • X.organic/Kart-Public
  • Superjustinbros/srb2kart-custom-color-expansion
  • Galactice/Kart-Public
  • haya_/Kart-Public
  • QuantumToasted/Kart-Public
  • Indev/Kart-Public
  • chreas/kart-public-vr
  • alufolie91/Kart-Public2
  • Alam/Kart-Public
  • koi/Kart-Public
  • Alam/kart-public-vr
  • Hanicef/Kart-Public
  • hero0fnin/kart-public-batocera-edit
  • NepDisk/Kart-Public
  • Nep2Disk/Kart-Public
41 results
Select Git revision
  • alias-argh
  • better-bans
  • cap-splitscreen-fov
  • chat-flood-fix
  • cherrypicks-from-netreplays
  • clear-all-controls
  • color-def-fixes
  • color-flip
  • deployer-test
  • extra-travis-deploy
  • findfile-with-threads
  • fix-clang-compile
  • fix-damn-springs
  • fix-double-bombs
  • fix-fade-timeout
  • fix-nocurl
  • followme
  • fuckinghell
  • gamepad-tweaks
  • gitlab-ci_timeout
  • gl-framedrops
  • http-ms-rules
  • http-ms-startup-print
  • ignore-posthumous-ackret
  • itemodds-fallthrough-fix
  • join-passwords
  • latency-tweaks
  • majormods
  • make-bumpcode-perfecter
  • master
  • master-server-is-a-bad-name
  • merge-srb2
  • more-files
  • more-files-take2
  • ms-address-warning
  • mserv-fdset-bullshit
  • new_netreplays
  • next
  • no-turn-easing-v1
  • opengl-billboarding
  • opengl-maybe-uninitialised
  • opengl_match_software_wallclip
  • playerinfo_mscompat
  • prevent-permissions-footgun
  • revert-mserv
  • rr-item-cruncher
  • shrink-removed-checks
  • software-fov
  • sound_strikethrough
  • spb-blockmap-fix
  • spectator-little-things
  • spinout-changes
  • srb2-merge
  • test-many-mrs
  • thunder-fixes
  • uncapped-hud
  • uncapped-master
  • unfuck-gamepads
  • unfuck-icon-mac
  • version-prep
  • V1.0.0
  • v1.0.1
  • v1.0.2
  • v1.0.3
  • v1.0.4
  • v1.1
  • v1.2
  • v1.3
  • v1.4
  • v1.5
  • v1.6
71 results
Show changes
Commits on Source (83)
......@@ -102,6 +102,11 @@ SINT8 nodetoplayer3[MAXNETNODES]; // say the numplayer for this node if any (spl
SINT8 nodetoplayer4[MAXNETNODES]; // say the numplayer for this node if any (splitscreen == 3)
UINT8 playerpernode[MAXNETNODES]; // used specialy for splitscreen
boolean nodeingame[MAXNETNODES]; // set false as nodes leave game
boolean nodedownloadrefuse[MAXNETNODES];
int nodedownloads [MAXNETNODES];
const char *nodedownloadfiles [MAXNETNODES][MAX_WADFILES];
static tic_t nettics[MAXNETNODES]; // what tic the client have received
static tic_t supposedtics[MAXNETNODES]; // nettics prevision for smaller packet
static UINT8 nodewaiting[MAXNETNODES];
......@@ -1332,6 +1337,70 @@ static boolean CL_SendJoin(void)
return HSendPacket(servernode, true, 0, sizeof (clientconfig_pak));
}
void
CopyCaretColors (char *p, const char *s, int n)
{
char *t;
int m;
int c;
if (!n)
return;
while (( t = strchr(s, '^') ))
{
m = ( t - s );
if (m >= n)
{
memcpy(p, s, n);
return;
}
else
memcpy(p, s, m);
p += m;
n -= m;
s += m;
if (!n)
return;
if (s[1])
{
c = toupper(s[1]);
if (isdigit(c))
c = 0x80 + ( c - '0' );
else if (c >= 'A' && c <= 'F')
c = 0x80 + ( c - 'A' );
else
c = 0;
if (c)
{
*p++ = c;
n--;
if (!n)
return;
}
else
{
if (n < 2)
break;
memcpy(p, s, 2);
p += 2;
n -= 2;
}
s += 2;
}
else
break;
}
strncpy(p, s, n);
}
static void SV_SendServerInfo(INT32 node, tic_t servertime)
{
UINT8 *p;
......@@ -1355,7 +1424,7 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime)
(D_IsJoinPasswordOn() ? SV_PASSWORD : 0)
);
strncpy(netbuffer->u.serverinfo.servername, cv_servername.string,
CopyCaretColors(netbuffer->u.serverinfo.servername, cv_servername.string,
MAXSERVERNAME);
strncpy(netbuffer->u.serverinfo.mapname, G_BuildMapName(gamemap), 7);
......@@ -2756,20 +2825,6 @@ void CL_Reset(void)
}
#ifndef NONET
static void Command_GetPlayerNum(void)
{
INT32 i;
for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i])
{
if (serverplayer == i)
CONS_Printf(M_GetText("num:%2d node:%2d %s\n"), i, playernode[i], player_names[i]);
else
CONS_Printf(M_GetText("\x82num:%2d node:%2d %s\n"), i, playernode[i], player_names[i]);
}
}
SINT8 nametonum(const char *name)
{
INT32 playernum, i;
......@@ -2799,41 +2854,145 @@ SINT8 nametonum(const char *name)
return -1;
}
/** Lists all players and their player numbers.
/** List all players along with a short status.
*
* \sa Command_GetPlayerNum
* \sa Command_NodeTree
*/
static void Command_Nodes(void)
/*
Formatted like so, with each element separated by space and written on lines:
Two digit player number, colon (:), colored player name, left-aligned.
Then a "status" which is delimited by a double dash (--).
If available, an IP address and port.
Admin status written as "(admin)".
Spectating status written as "(spectator)".
If admin and spectating status both apply and the player's address was not
available, the status is "crammed". If the status is not "crammed", it is
indented the width of " -- self". The intended effect is that the spectating
status aligns with other spectating statuses.
*/
static void Command_ListPlayers(void)
{
INT32 i;
size_t maxlen = 0;
const char *address;
int width = 0;
for (i = 0; i < MAXPLAYERS; i++)
boolean admin;
boolean spectator;
/*
Mode of player status for an individual player (admin, spectator).
1 for admin
2 for spectator
4 for both
*/
int mode = 0;
INT32 totalplayers = 0;
const char *cc;
const char *pcc;
INT32 i;
int n;
for (i = 0; i < MAXPLAYERS; ++i)
if (playeringame[i])
{
const size_t plen = strlen(player_names[i]);
if (playeringame[i] && plen > maxlen)
maxlen = plen;
n = strlen(player_names[i]);
if (n > width)
width = n;
if (mode != 7)
{
admin = IsPlayerAdmin(i);
spectator = players[i].spectator;
if (admin)
mode |= 1;
if (spectator)
mode |= 2;
if (admin && spectator)
mode |= 4;
}
}
for (i = 0; i < MAXPLAYERS; i++)
{
for (i = 0; i < MAXPLAYERS; ++i)
if (playeringame[i])
{
CONS_Printf("%.2u: %*s", i, (int)maxlen, player_names[i]);
CONS_Printf(" - %.2d", playernode[i]);
if (I_GetNodeAddress && (address = I_GetNodeAddress(playernode[i])) != NULL)
CONS_Printf(" - %s", address);
{
admin = IsPlayerAdmin(i);
spectator = players[i].spectator;
if (admin)
cc = "\x85";/* red */
else if (spectator)
cc = "\x86";/* gray */
else
cc = "";
if (IsPlayerAdmin(i))
CONS_Printf(M_GetText(" (verified admin)"));
pcc = V_ApproximateSkinColorCode(players[i].skincolor);
if (players[i].spectator)
CONS_Printf(M_GetText(" (spectator)"));
CONS_Printf("%.2d: ""%s""%-*s""\x80", i, pcc,width, player_names[i]);
CONS_Printf("\n");
if (I_GetNodeAddress)
{
if (( address = I_GetNodeAddress(playernode[i]) ))
CONS_Printf(" -- %s", address);
else/* print spacer */
{
/* ...but not if there's a crammed status and were admin */
if (mode != 7 || !admin)
CONS_Printf(" -- ");/* -- self */
}
}
if (admin)
CONS_Printf(M_GetText("%s"" (admin)"),cc);
if (spectator)
CONS_Printf(M_GetText("%s"" (spectator)"),cc);
CONS_Printf("\n");
totalplayers++;
}
if (totalplayers == 1)
CONS_Printf("\nThere is 1 player in the game.\n");
else
CONS_Printf("\nThere are %d players in the game.\n", totalplayers);
}
/** Print a table listing all nodes, addresses and associated players.
*
* \sa Command_ListPlayers
*/
static void Command_NodeTree(void)
{
const char *address;
INT32 i;
INT32 totalnodes = 0;
for (i = 0; i < MAXNETNODES; ++i)
if (nodeingame[i])
{
CONS_Printf("* %d", i);
if (playerpernode[i] > 1)
CONS_Printf(" (%d players)", playerpernode[i]);
if (I_GetNodeAddress && ( address = I_GetNodeAddress(i) ))
CONS_Printf(" - %s", address);
CONS_Printf("\n");
#define PRINTPLAYERNODE( prefix, array ) if ((array)[i] > -1) \
CONS_Printf(prefix" (%d) %s\n", (array)[i], player_names[(array)[i]]);
PRINTPLAYERNODE ("|-", nodetoplayer4)
PRINTPLAYERNODE ("|-", nodetoplayer3)
PRINTPLAYERNODE ("|-", nodetoplayer2)
PRINTPLAYERNODE ("\\-", nodetoplayer)
#undef PRINTPLAYERNODE
CONS_Printf("\n");
totalnodes++;
}
CONS_Printf("%d/%d nodes connected.\n", totalnodes, MAXNETNODES);
}
static void Command_Ban(void)
......@@ -3230,6 +3389,13 @@ consvar_t cv_noticedownload = {"noticedownload", "Off", CV_SAVE, CV_OnOff, NULL,
static CV_PossibleValue_t downloadspeed_cons_t[] = {{0, "MIN"}, {32, "MAX"}, {0, NULL}};
consvar_t cv_downloadspeed = {"downloadspeed", "16", CV_SAVE, downloadspeed_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_autoresetdownloads =
{
"autoresetdownloads", "Off",
CV_SAVE,
CV_OnOff
};
static void Got_AddPlayer(UINT8 **p, INT32 playernum);
static void Got_RemovePlayer(UINT8 **p, INT32 playernum);
......@@ -3240,7 +3406,7 @@ void D_ClientServerInit(void)
VERSION/100, VERSION%100, SUBVERSION));
#ifndef NONET
COM_AddCommand("getplayernum", Command_GetPlayerNum);
COM_AddCommand("listplayers", Command_ListPlayers);
COM_AddCommand("kick", Command_Kick);
COM_AddCommand("ban", Command_Ban);
COM_AddCommand("banip", Command_BanIP);
......@@ -3248,7 +3414,7 @@ void D_ClientServerInit(void)
COM_AddCommand("showbanlist", Command_ShowBan);
COM_AddCommand("reloadbans", Command_ReloadBan);
COM_AddCommand("connect", Command_connect);
COM_AddCommand("nodes", Command_Nodes);
COM_AddCommand("nodetree", Command_NodeTree);
#ifdef PACKETDROP
COM_AddCommand("drop", Command_Drop);
COM_AddCommand("droprate", Command_Droprate);
......@@ -3485,14 +3651,31 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum)
if (netgame)
{
if (server && cv_showjoinaddress.value)
char *text;
if (server)
{
const char *address;
if (I_GetNodeAddress && (address = I_GetNodeAddress(node)) != NULL)
HU_AddChatText(va("\x82*Player %d has joined the game (node %d) (%s)", newplayernum+1, node, address), false); // merge join notification + IP to avoid clogging console/chat.
if (cv_showjoinaddress.value &&
I_GetNodeAddress && ( address = I_GetNodeAddress(node) ))
{
text = va(
"\x82*Player %d (num %d) has joined the game (%s)",
newplayernum+1, newplayernum, address);
}
else
{
text = va(
"\x82Player %d (num %d) has joined the game",
newplayernum+1, newplayernum);
}
}
else
HU_AddChatText(va("\x82*Player %d has joined the game (node %d)", newplayernum+1, node), false); // if you don't wanna see the join address.
{
text = va(
"\x82Player %d has joined the game",
newplayernum+1);
}
HU_AddChatText(text, false);
}
if (server && multiplayer && motd[0] != '\0')
......@@ -3700,6 +3883,104 @@ static void SV_SendRefuse(INT32 node, const char *reason)
Net_CloseConnection(node);
}
/* Macros here 'cause I'm lazy! */
#define MAXVA 1024/* see m_misc.c's va function */
#define MAXMSGLINE 256/* see m_menu.c's M_DrawMessageMenu */
/*
Send a refuse message (like SV_SendRefuse) and include a file list with it.
WARNING: File names will not be truncated, simply left out. The usual message
box background will not display either, due to epic hack.
*/
static void
SV_SendDownloadRefuse (
INT32 node,
const char * reason,
int filec,
const char ** filev)
{
char filename[MAX_WADPATH];
char text[MAXVA];
char * p;
int right;
int i;
int n;
#define SUBTRACT ( p += n, right -= n )
/*
Insert same number of linefeeds before message as after (from the file
list) so that the text doesn't render too high--completely off screen.
*/
n = filec;
memset(text, '\n', n);
/* Initial values for these */
p = text + n;
right = sizeof text - n;/* Count terminating byte anyway, see below. */
/* This is the only text that'll render. */
n = right - 1;
CopyCaretColors(p, reason, n);
p[n] = '\0';
n = strlen(p);
SUBTRACT;
/*
Fill max line length of text box line. This causes the text box drawing
function to fail and print the message to console instead. The text before
this line still renders. This is a very convenient coincidence, and so
I've given myself a pat of the back for this one.
*/
n = MAXMSGLINE + 1;
if (n < right)/* No magic :( */
{
memset(p, '\t', MAXMSGLINE);
p[MAXMSGLINE] = '\n';/* This line can go on forever */
SUBTRACT;
/*
Now just iterate over the files and put them into a list,
with a linefeed after each one, except the last.
*/
for (i = 0; i < filec; ++i)
{
nameonly(strcpy(filename, filev[i]));
n = strlen(filename) + 1;/* plus linefeed */
/* Don't truncate file names, just leave them out. */
if (n > right)
break;
/*
The terminating byte is counted because
truncation here will erase the linefeed.
*/
snprintf(p, right, "%s\n", filename);
SUBTRACT;
}
if (right)/* not if filled out, snprintf did it */
p[-1] = '\0';/* we don't need an extra linefeed */
}
SV_SendRefuse(node, text);
#undef SUBTRACT
}
#undef MAXMSGLINE
#undef MAXVA
// used at txtcmds received to check packetsize bound
static size_t TotalTextCmdPerTic(tic_t tic)
{
......@@ -3743,6 +4024,26 @@ static void HandleConnect(SINT8 node)
SV_SendRefuse(node, M_GetText("Too many players from\nthis node."));
else if (netgame && !netbuffer->u.clientcfg.localplayers) // Stealth join?
SV_SendRefuse(node, M_GetText("No players from\nthis node."));
else if (nodedownloadrefuse[node])
{
const char *reason;
char *s;
char *p;
if (( s = strdup(cv_nodownloads.string) ))
{
reason = s;
for (p = s; ( p = strchr(p, '\\') ); ++p)
*p = '\n';
}
else
reason = "You can't download files from this server.\nGo home.";
SV_SendDownloadRefuse(node, reason,
nodedownloads[node], nodedownloadfiles[node]);
free(s);
}
else
{
#ifndef NONET
......@@ -3868,12 +4169,15 @@ static void HandleTimeout(SINT8 node)
*/
static void HandleServerInfo(SINT8 node)
{
char servername[MAXSERVERNAME];
// compute ping in ms
const tic_t ticnow = I_GetTime();
const tic_t ticthen = (tic_t)LONG(netbuffer->u.serverinfo.time);
const tic_t ticdiff = (ticnow - ticthen)*1000/NEWTICRATE;
netbuffer->u.serverinfo.time = (tic_t)LONG(ticdiff);
netbuffer->u.serverinfo.servername[MAXSERVERNAME-1] = 0;
memcpy(servername, netbuffer->u.serverinfo.servername, MAXSERVERNAME);
CopyCaretColors(netbuffer->u.serverinfo.servername, servername, MAXSERVERNAME);
netbuffer->u.serverinfo.gametype = (UINT8)((netbuffer->u.serverinfo.gametype == VANILLA_GT_MATCH) ? GT_MATCH : GT_RACE);
SL_InsertServer(&netbuffer->u.serverinfo, node);
......@@ -4159,7 +4463,7 @@ static void HandlePacketFromAwayNode(SINT8 node)
case PT_REQUESTFILE:
if (server)
{
if (!cv_downloading.value || !Got_RequestFilePak(node))
if (( !cv_downloading.value && !*cv_nodownloads.string ) || !Got_RequestFilePak(node))
Net_CloseConnection(node); // close connection if one of the requested files could not be sent, or you disabled downloading anyway
}
else
......@@ -4204,7 +4508,7 @@ static boolean CheckForSpeedHacks(UINT8 p)
|| netcmds[maketic%BACKUPTICS][p].driftturn > KART_FULLTURN || netcmds[maketic%BACKUPTICS][p].driftturn < -KART_FULLTURN)
{
XBOXSTATIC char buf[2];
CONS_Alert(CONS_WARNING, M_GetText("Illegal movement value received from node %d\n"), playernode[p]);
CONS_Alert(CONS_WARNING, M_GetText("Illegal movement value received from player %d\n"), p);
//D_Clearticcmd(k);
buf[0] = (char)p;
......
......@@ -541,7 +541,8 @@ extern consvar_t
#ifdef VANILLAJOINNEXTROUND
cv_joinnextround,
#endif
cv_netticbuffer, cv_allownewplayer, cv_maxplayers, cv_resynchattempts, cv_blamecfail, cv_maxsend, cv_noticedownload, cv_downloadspeed;
cv_netticbuffer, cv_allownewplayer, cv_maxplayers, cv_resynchattempts, cv_blamecfail, cv_maxsend, cv_noticedownload, cv_downloadspeed,
cv_autoresetdownloads;
// Used in d_net, the only dependence
tic_t ExpandTics(INT32 low);
......@@ -580,6 +581,8 @@ void D_QuitNetGame(void);
//? How many ticks to run?
void TryRunTics(tic_t realtic);
void CopyCaretColors(char *p, const char *s, int n);
// extra data for lmps
// these functions scare me. they contain magic.
/*boolean AddLmpExtradata(UINT8 **demo_p, INT32 playernum);
......
......@@ -110,8 +110,8 @@ UINT8 window_notinfocus = false;
//
//static INT32 demosequence;
static const char *pagename = "MAP1PIC";
static char *startupwadfiles[MAX_WADFILES];
static char *startuppwads[MAX_WADFILES];
static char *startupwadfiles[MAX_WADFILES][2];
static char *startuppwads[MAX_WADFILES][2];
boolean devparm = false; // started game with -devparm
......@@ -799,34 +799,46 @@ void D_StartTitle(void)
V_SetPaletteLump("PLAYPAL");*/
}
static char *
Daddfilestrdup (const char *s)
{
char *p;
if (!( p = strdup(s) ))
{
I_Error("No more free memory to AddFile %s",s);
}
return p;
}
//
// D_AddFile
//
static void D_AddFile(const char *file, char **filearray)
static void D_AddFile2(const char *file, const char *lumpname, char *(*filearray)[2])
{
size_t pnumwadfiles;
char *newfile;
for (pnumwadfiles = 0; filearray[pnumwadfiles]; pnumwadfiles++)
for (pnumwadfiles = 0; filearray[pnumwadfiles][0]; pnumwadfiles++)
;
newfile = malloc(strlen(file) + 1);
if (!newfile)
{
I_Error("No more free memory to AddFile %s",file);
}
strcpy(newfile, file);
filearray[pnumwadfiles][0] = Daddfilestrdup(file);
filearray[pnumwadfiles][1] = ( (lumpname) ? Daddfilestrdup(lumpname) : 0 );
}
filearray[pnumwadfiles] = newfile;
static void
D_AddFile (const char *file, char *(*filearray)[2])
{
D_AddFile2(file, 0, filearray);
}
static inline void D_CleanFile(char **filearray)
static inline void D_CleanFile(char *(*filearray)[2])
{
size_t pnumwadfiles;
for (pnumwadfiles = 0; filearray[pnumwadfiles]; pnumwadfiles++)
for (pnumwadfiles = 0; filearray[pnumwadfiles][0]; pnumwadfiles++)
{
free(filearray[pnumwadfiles]);
filearray[pnumwadfiles] = NULL;
free(filearray[pnumwadfiles][0]);
free(filearray[pnumwadfiles][1]);
filearray[pnumwadfiles][0] = NULL;
filearray[pnumwadfiles][1] = NULL;
}
}
......@@ -1144,6 +1156,22 @@ void D_SRB2Main(void)
D_AddFile(s, startuppwads);
}
}
if (M_CheckParm("-musicfile"))
{
while (M_IsNextParm())
{
const char *f;
const char *u;
f = M_GetNextParm();
u = M_GetNextParm();
if (!u)
{
I_Error("-musicfile missing second name: -musicfile <file> <name>");
}
D_AddFile2(f, u, startuppwads);
}
}
}
// get map from parms
......
......@@ -714,7 +714,10 @@ void Net_CloseConnection(INT32 node)
}
InitNode(&nodes[node]);
SV_AbortSendFiles(node);
if (cv_autoresetdownloads.value)
CloseNetFile();/* Hack to hopefully reduce lock outs. */
else
SV_AbortSendFiles(node);
I_NetFreeNodenum(node);
#endif
}
......
......@@ -18,6 +18,8 @@
#ifndef __D_NET__
#define __D_NET__
#include "w_wad.h"
// Max computers in a game
#define MAXNETNODES (MAXPLAYERS+4)
#define BROADCASTADDR MAXNETNODES
......@@ -41,6 +43,10 @@ extern SINT8 nodetoplayer4[MAXNETNODES]; // Say the numplayer for this node if a
extern UINT8 playerpernode[MAXNETNODES]; // Used specially for splitscreen
extern boolean nodeingame[MAXNETNODES]; // Set false as nodes leave game
extern boolean nodedownloadrefuse[MAXNETNODES];
extern int nodedownloads [MAXNETNODES];
extern const char *nodedownloadfiles [MAXNETNODES][MAX_WADFILES];
INT32 Net_GetFreeAcks(boolean urgent);
void Net_AckTicker(void);
......
......@@ -114,6 +114,7 @@ static void BaseNumLaps_OnChange(void);
static void KartFrantic_OnChange(void);
static void KartSpeed_OnChange(void);
static void KartEncore_OnChange(void);
static void KartVoteRuleChanges_OnChange(void);
static void KartComeback_OnChange(void);
static void KartEliminateLast_OnChange(void);
......@@ -121,6 +122,13 @@ static void KartEliminateLast_OnChange(void);
static void Fishcake_OnChange(void);
#endif
static void lessvotes_OnChange (void);
static void discardmaps_OnChange (void);
static void Command_resetdownloads_f (void);
static void Command_resetvotebuffer_f (void);
static void Command_hidemap_f (void);
static void Command_Playdemo_f(void);
static void Command_Timedemo_f(void);
static void Command_Stopdemo_f(void);
......@@ -133,6 +141,7 @@ static void Command_View_f (void);
static void Command_SetViews_f(void);
static void Command_Addfile(void);
static void Command_Addmusic(void);
static void Command_ListWADS_f(void);
#ifdef DELFILE
static void Command_Delfile(void);
......@@ -364,7 +373,9 @@ consvar_t cv_kartfrantic = {"kartfrantic", "Off", CV_NETVAR|CV_CHEAT|CV_CALL|CV_
consvar_t cv_kartcomeback = {"kartcomeback", "On", CV_NETVAR|CV_CHEAT|CV_CALL|CV_NOINIT, CV_OnOff, KartComeback_OnChange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_kartencore = {"kartencore", "Off", CV_NETVAR|CV_CALL|CV_NOINIT, CV_OnOff, KartEncore_OnChange, 0, NULL, NULL, 0, 0, NULL};
static CV_PossibleValue_t kartvoterulechanges_cons_t[] = {{0, "Never"}, {1, "Sometimes"}, {2, "Frequent"}, {3, "Always"}, {0, NULL}};
consvar_t cv_kartvoterulechanges = {"kartvoterulechanges", "Frequent", CV_NETVAR, kartvoterulechanges_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_kartvoterulechanges = {"kartvoterulechanges", "Frequent", CV_NETVAR|CV_CALL|CV_NOINIT, kartvoterulechanges_cons_t, KartVoteRuleChanges_OnChange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_kartgametypechanges = {"kartgametypechanges", "Frequent", 0, kartvoterulechanges_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_kartencorechance = {"kartencorechance", "Frequent", 0, kartvoterulechanges_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
static CV_PossibleValue_t kartspeedometer_cons_t[] = {{0, "Off"}, {1, "Kilometers"}, {2, "Miles"}, {3, "Fracunits"}, {0, NULL}};
consvar_t cv_kartspeedometer = {"kartdisplayspeed", "Off", CV_SAVE, kartspeedometer_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; // use tics in display
static CV_PossibleValue_t kartvoices_cons_t[] = {{0, "Never"}, {1, "Tasteful"}, {2, "Meme"}, {0, NULL}};
......@@ -463,6 +474,14 @@ consvar_t cv_mute = {"mute", "Off", CV_NETVAR|CV_CALL, CV_OnOff, Mute_OnChange,
consvar_t cv_sleep = {"cpusleep", "1", CV_SAVE, sleeping_cons_t, NULL, -1, NULL, NULL, 0, 0, NULL};
consvar_t cv_nodownloads = { "downloadnotice", "", CV_SAVE };
consvar_t cv_lessbattlevotes = {"lessbattlevotes", "No", CV_SAVE, CV_YesNo};
consvar_t cv_lessencorevotes = {"lessencorevotes", "No", CV_SAVE, CV_YesNo};
consvar_t cv_lessvotes = {"lessvotes", "0", CV_SAVE, CV_Unsigned, lessvotes_OnChange};
consvar_t cv_discardmaps = {"discardmaps", "No", CV_SAVE, CV_YesNo, discardmaps_OnChange};
INT16 gametype = GT_RACE; // SRB2kart
boolean forceresetplayers = false;
boolean deferencoremode = false;
......@@ -470,6 +489,8 @@ UINT8 splitscreen = 0;
boolean circuitmap = true; // SRB2kart
INT32 adminplayers[MAXPLAYERS];
boolean alreadyresetdownloads;
/// \warning Keep this up-to-date if you add/remove/rename net text commands
const char *netxcmdnames[MAXNETXCMD - 1] =
{
......@@ -553,6 +574,12 @@ void D_RegisterServerCommands(void)
RegisterNetXCmd(XD_MODIFYVOTE, Got_ModifyVotecmd);
RegisterNetXCmd(XD_PICKVOTE, Got_PickVotecmd);
COM_AddCommand("resetdownloads", Command_resetdownloads_f);
COM_AddCommand("resetvotebuffer", Command_resetvotebuffer_f);
COM_AddCommand("hidemap", Command_hidemap_f);
CV_RegisterVar(&cv_nodownloads);
// Remote Administration
CV_RegisterVar(&cv_dummyjoinpassword);
COM_AddCommand("joinpassword", Command_ChangeJoinPassword_f);
......@@ -581,6 +608,7 @@ void D_RegisterServerCommands(void)
COM_AddCommand("mapmd5", Command_Mapmd5_f);
COM_AddCommand("addfile", Command_Addfile);
COM_AddCommand("addmusic", Command_Addmusic);
COM_AddCommand("listwad", Command_ListWADS_f);
#ifdef DELFILE
......@@ -686,6 +714,7 @@ void D_RegisterServerCommands(void)
CV_RegisterVar(&cv_maxsend);
CV_RegisterVar(&cv_noticedownload);
CV_RegisterVar(&cv_downloadspeed);
CV_RegisterVar(&cv_autoresetdownloads);
#ifndef NONET
CV_RegisterVar(&cv_allownewplayer);
#ifdef VANILLAJOINNEXTROUND
......@@ -710,6 +739,12 @@ void D_RegisterServerCommands(void)
#endif
CV_RegisterVar(&cv_dummyconsvar);
CV_RegisterVar(&cv_lessbattlevotes);
CV_RegisterVar(&cv_lessencorevotes);
CV_RegisterVar(&cv_lessvotes);
CV_RegisterVar(&cv_discardmaps);
}
// =========================================================================
......@@ -848,6 +883,17 @@ void D_RegisterClientCommands(void)
CV_RegisterVar(&cv_chatnotifications);
CV_RegisterVar(&cv_chatbacktint);
CV_RegisterVar(&cv_songcredits);
CV_RegisterVar(&cv_showviewpoint);
CV_RegisterVar(&cv_showfreeplay);
CV_RegisterVar(&cv_playendingmusic);
CV_RegisterVar(&cv_playenginesounds);
CV_RegisterVar(&cv_growmusic);
CV_RegisterVar(&cv_supermusic);
CV_RegisterVar(&cv_growmusicfadein);
CV_RegisterVar(&cv_supermusicfadein);
CV_RegisterVar(&cv_defaultmusicfadein);
CV_RegisterVar(&cv_resumemusic);
CV_RegisterVar(&cv_crossovermusic);
//CV_RegisterVar(&cv_crosshair);
//CV_RegisterVar(&cv_crosshair2);
//CV_RegisterVar(&cv_crosshair3);
......@@ -2347,29 +2393,50 @@ void D_SetupVote(void)
UINT8 buf[6*2]; // five UINT16 maps (at twice the width of a UINT8), and two gametypes
UINT8 *p = buf;
INT32 i;
UINT8 secondgt = G_SometimesGetDifferentGametype();
UINT8 gt;
UINT8 secondgt;
INT16 votebuffer[3] = {-1,-1,-1};
if (cv_kartencore.value && G_RaceGametype())
WRITEUINT8(p, (gametype|0x80));
if (cv_lessbattlevotes.value && G_BattleGametype())
{
gt = GT_RACE;
secondgt = GT_MATCH;
}
else
WRITEUINT8(p, gametype);
{
gt = gametype;
secondgt = G_SometimesGetDifferentGametype();
if (cv_lessencorevotes.value)
{
if (secondgt == GT_RACE)
secondgt |= 0x80;
}
else
{
if (cv_kartencore.value && G_RaceGametype())
gt |= 0x80;
}
}
WRITEUINT8(p, gt);
WRITEUINT8(p, secondgt);
gt &= ~0x80;
secondgt &= ~0x80;
for (i = 0; i < 5; i++)
{
UINT16 m;
if (i == 2) // sometimes a different gametype
m = G_RandMap(G_TOLFlag(secondgt), prevmap, false, 0, true, votebuffer);
m = G_RandMap(G_TOLFlag(secondgt), prevmap, prevmapvotes, false, 0, true, votebuffer);
else if (i >= 3) // unknown-random and force-unknown MAP HELL
m = G_RandMap(G_TOLFlag(gametype), prevmap, false, (i-2), (i < 4), votebuffer);
m = G_RandMap(G_TOLFlag(gt), prevmap, prevmapvotes, false, (i-2), (i < 4), votebuffer);
else
m = G_RandMap(G_TOLFlag(gametype), prevmap, false, 0, true, votebuffer);
m = G_RandMap(G_TOLFlag(gt), prevmap, prevmapvotes, false, 0, true, votebuffer);
if (i < 3)
votebuffer[min(i, 2)] = m; // min() is a dumb workaround for gcc 4.4 array-bounds error
WRITEUINT16(p, m);
}
if (cv_lessvotes.value)
memcpy(prevmapvotes, votebuffer, sizeof prevmapvotes);
SendNetXCmd(XD_SETUPVOTE, buf, p - buf);
}
......@@ -3957,7 +4024,7 @@ static void Command_Verify_f(void)
if (COM_Argc() != 2)
{
CONS_Printf(M_GetText("promote <node>: give admin privileges to a node\n"));
CONS_Printf(M_GetText("promote <playernum>: give admin privileges to a player\n"));
return;
}
......@@ -4013,7 +4080,7 @@ static void Command_RemoveAdmin_f(void)
if (COM_Argc() != 2)
{
CONS_Printf(M_GetText("demote <node>: remove admin privileges from a node\n"));
CONS_Printf(M_GetText("demote <playernum>: remove admin privileges from a player\n"));
return;
}
......@@ -4383,7 +4450,7 @@ static void Command_Addfile(void)
// Add file on your client directly if it is trivial, or you aren't in a netgame.
if (!(netgame || multiplayer) || musiconly)
{
P_AddWadFile(fn);
P_AddWadFile(fn, 0);
return;
}
......@@ -4432,6 +4499,20 @@ static void Command_Addfile(void)
SendNetXCmd(XD_ADDFILE, buf, buf_p - buf);
}
/** Adds a music pwad at runtime.
*/
static void
Command_Addmusic (void)
{
if (COM_Argc() != 3)
{
CONS_Printf(
"addmusic <file> <name>: load music file, use 6 char. name\n");
return;
}
P_AddWadFile(COM_Argv(1), COM_Argv(2));
}
#ifdef DELFILE
/** removes the last added pwad at runtime.
* Searches for sounds, maps, music and images to remove
......@@ -4588,7 +4669,7 @@ static void Got_Addfilecmd(UINT8 **cp, INT32 playernum)
ncs = findfile(filename,md5sum,true);
if (ncs != FS_FOUND || !P_AddWadFile(filename))
if (ncs != FS_FOUND || !P_AddWadFile(filename, 0))
{
Command_ExitGame_f();
if (ncs == FS_FOUND)
......@@ -4621,6 +4702,7 @@ static void Command_ListWADS_f(void)
{
INT32 i = numwadfiles;
char *tempname;
lumpinfo_t *p;
CONS_Printf(M_GetText("There are %d wads loaded:\n"),numwadfiles);
for (i--; i >= 0; i--)
{
......@@ -4632,6 +4714,19 @@ static void Command_ListWADS_f(void)
else
CONS_Printf(" %.2d: %s\n", i, tempname);
}
if (wadfiles[WAD_MUSIC])
{
CONS_Printf("There are also %d music files:\n",
wadfiles[WAD_MUSIC]->numlumps);
for (i = 0; i < wadfiles[WAD_MUSIC]->numlumps; ++i)
{
p = &wadfiles[WAD_MUSIC]->lumpinfo[i];
if (strcmp(p->name, p->name2) == 0)
CONS_Printf("%02d: %-8s\n", i, p->name);
else
CONS_Printf("%02d: %-8s (%s)\n", i, p->name, p->name2);
}
}
}
// =========================================================================
......@@ -5860,6 +5955,14 @@ static void KartEncore_OnChange(void)
}
}
static void KartVoteRuleChanges_OnChange(void)
{
const char *s;
s = cv_kartvoterulechanges.string;
CV_StealthSet(&cv_kartgametypechanges, s);
CV_StealthSet(&cv_kartencorechance, s);
}
static void KartComeback_OnChange(void)
{
if (G_BattleGametype())
......@@ -5879,3 +5982,72 @@ static void KartEliminateLast_OnChange(void)
if (G_RaceGametype() && cv_karteliminatelast.value)
P_CheckRacers();
}
static void
Command_resetdownloads_f (void)
{
CloseNetFile();
if (server)
{
COM_ImmedExecute("say \"Downloads have been reset.\"");
alreadyresetdownloads = true;
}
}
static void
Command_resetvotebuffer_f (void)
{
prevmap = -1;
lessvotes_OnChange();
discardmaps_OnChange();
}
static void
Command_hidemap_f (void)
{
int ac;
const char *a;
char *title;
int i;
int n;
ac = COM_Argc();
for (i = 1; i < ac; ++i)
{
a = COM_Argv(i);
if (strlen(a) == 2)
{
n = M_MapNumber(a[0], a[1]);
if (n && mapheaderinfo[n-1])
{
mapheaderinfo[n-1]->hidden = ! mapheaderinfo[n-1]->hidden;
title = G_BuildMapTitle(n);
CONS_Printf(
"%s (%s) is %s hidden\n",
title,
G_BuildMapName(n),
( (mapheaderinfo[n-1]->hidden) ?
"now" :
"no longer" ));
}
}
}
}
static void
lessvotes_OnChange (void)
{
prevmapvotes[0] = -1;
prevmapvotes[1] = -1;
prevmapvotes[2] = -1;
}
static void
discardmaps_OnChange (void)
{
int i;
for (i = 0; i < NUMMAPS; ++i)
{
if (mapheaderinfo[i])
mapheaderinfo[i]->already = false;
}
}
......@@ -118,6 +118,8 @@ extern consvar_t cv_kartfrantic;
extern consvar_t cv_kartcomeback;
extern consvar_t cv_kartencore;
extern consvar_t cv_kartvoterulechanges;
extern consvar_t cv_kartgametypechanges;
extern consvar_t cv_kartencorechance;;
extern consvar_t cv_kartspeedometer;
extern consvar_t cv_kartvoices;
......@@ -151,6 +153,14 @@ extern consvar_t cv_skipmapcheck;
extern consvar_t cv_sleep;
extern consvar_t cv_nodownloads;
extern consvar_t cv_lessbattlevotes;
extern consvar_t cv_lessencorevotes;
extern consvar_t cv_lessvotes;
extern consvar_t cv_discardmaps;
typedef enum
{
XD_NAMEANDCOLOR = 1,
......
......@@ -75,6 +75,7 @@ typedef struct filetx_s
} id;
UINT32 size; // Size of the file
UINT8 fileid;
boolean dummy;/* For custom can't download notice; we don't actually send the file! */
INT32 node; // Destination
struct filetx_s *next; // Next file in the list
} filetx_t;
......@@ -144,12 +145,15 @@ UINT8 *PutFileNeeded(UINT16 firstfile)
filestatus = 1; // Importance - not really used any more, holds 1 by default for backwards compat with MS
// Store in the upper four bits
if (!cv_downloading.value)
filestatus += (2 << 4); // Won't send
else if ((wadfiles[i]->filesize <= (UINT32)cv_maxsend.value * 1024))
filestatus += (1 << 4); // Will send if requested
// else
// filestatus += (0 << 4); -- Won't send, too big
if (*cv_nodownloads.string)
filestatus += (1 << 4);/* This is a hack to get the client to ask for files. */
else
{
if (!cv_downloading.value)
filestatus += (2 << 4); // Won't send
else if ((wadfiles[i]->filesize <= (UINT32)cv_maxsend.value * 1024))
filestatus += (1 << 4); // Will send if requested
}
WRITEUINT8(p, filestatus);
......@@ -325,7 +329,7 @@ boolean Got_RequestFilePak(INT32 node)
char wad[MAX_WADPATH+1];
UINT8 *p = netbuffer->u.textcmd;
UINT8 id;
while (p < netbuffer->u.textcmd + MAXTEXTCMD-1) // Don't allow hacked client to overflow
while (p < netbuffer->u.textcmd + ( sizeof (doomdata_t) - BASEPACKETSIZE )) // Yeah fuck you
{
id = READUINT8(p);
if (id == 0xFF)
......@@ -445,7 +449,7 @@ void CL_LoadServerFiles(void)
continue; // Already loaded
else if (fileneeded[i].status == FS_FOUND)
{
P_AddWadFile(fileneeded[i].filename);
P_AddWadFile(fileneeded[i].filename, 0);
G_SetGameModified(true, false);
fileneeded[i].status = FS_OPEN;
}
......@@ -494,9 +498,6 @@ static boolean SV_SendFile(INT32 node, const char *filename, UINT8 fileid)
INT32 i;
char wadfilename[MAX_WADPATH];
if (cv_noticedownload.value)
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
q = &transfer[node].txlist;
while (*q)
......@@ -548,16 +549,32 @@ static boolean SV_SendFile(INT32 node, const char *filename, UINT8 fileid)
}
// Handle huge file requests (i.e. bigger than cv_maxsend.value KB)
if (wadfiles[i]->filesize > (UINT32)cv_maxsend.value * 1024)
if (!cv_downloading.value || wadfiles[i]->filesize > (UINT32)cv_maxsend.value * 1024)
{
// Too big
// Don't inform client (client sucks, man)
DEBFILE(va("Client %d request %s: file too big, not sending\n", node, filename));
free(p->id.filename);
free(p);
*q = NULL;
return false; // cancel the rest of the requests
if (*cv_nodownloads.string)
{
p->dummy = true;
nodedownloadrefuse[node] = true;
/* Save file name, we need this */
nodedownloadfiles[node][nodedownloads[node]++] =
wadfiles[i]->filename;
}
else
{
// Too big
// Don't inform client (client sucks, man)
DEBFILE(va("Client %d request %s: file too big, not sending\n", node, filename));
free(p->id.filename);
free(p);
*q = NULL;
return false; // cancel the rest of the requests
}
}
else
p->dummy = false;
if (cv_noticedownload.value)
CONS_Printf("Sending file \"%s\" to node %d (%s)\n", filename, node, I_GetNodeAddress(node));
DEBFILE(va("Sending file %s (id=%d) to %d\n", filename, fileid, node));
p->ram = SF_FILE; // It's a file, we need to close it and free its name once we're done sending it
......@@ -622,7 +639,7 @@ static void SV_EndFileSend(INT32 node)
case SF_FILE: // It's a file, close it and free its filename
if (cv_noticedownload.value)
CONS_Printf("Ending file transfer for node %d\n", node);
if (transfer[node].currentfile)
if (transfer[node].currentfile && !p->dummy)
fclose(transfer[node].currentfile);
free(p->id.filename);
break;
......@@ -710,25 +727,33 @@ void SV_FileSendTicker(void)
{
long filesize;
transfer[i].currentfile =
fopen(f->id.filename, "rb");
if (!transfer[i].currentfile)
I_Error("File %s does not exist",
f->id.filename);
fseek(transfer[i].currentfile, 0, SEEK_END);
filesize = ftell(transfer[i].currentfile);
// Nobody wants to transfer a file bigger
// than 4GB!
if (filesize >= LONG_MAX)
I_Error("filesize of %s is too large", f->id.filename);
if (filesize == -1)
I_Error("Error getting filesize of %s", f->id.filename);
f->size = (UINT32)filesize;
fseek(transfer[i].currentfile, 0, SEEK_SET);
if (f->dummy)
{
f->size = 1;/* client expects at least one byte */
transfer[i].currentfile = (FILE *)1;/* (see below) */
}
else
{
transfer[i].currentfile =
fopen(f->id.filename, "rb");
if (!transfer[i].currentfile)
I_Error("File %s does not exist",
f->id.filename);
fseek(transfer[i].currentfile, 0, SEEK_END);
filesize = ftell(transfer[i].currentfile);
// Nobody wants to transfer a file bigger
// than 4GB!
if (filesize >= LONG_MAX)
I_Error("filesize of %s is too large", f->id.filename);
if (filesize == -1)
I_Error("Error getting filesize of %s", f->id.filename);
f->size = (UINT32)filesize;
fseek(transfer[i].currentfile, 0, SEEK_SET);
}
}
else // Sending RAM
transfer[i].currentfile = (FILE *)1; // Set currentfile to a non-null value to indicate that it is open
......@@ -742,6 +767,8 @@ void SV_FileSendTicker(void)
size = f->size-transfer[i].position;
if (ram)
M_Memcpy(p->data, &f->id.ram[transfer[i].position], size);
else if (f->dummy)
p->data[0] = '\n';
else if (fread(p->data, 1, size, transfer[i].currentfile) != size)
I_Error("SV_FileSendTicker: can't read %s byte on %s at %d because %s", sizeu1(size), f->id.filename, transfer[i].position, strerror(ferror(transfer[i].currentfile)));
p->position = LONG(transfer[i].position);
......@@ -760,7 +787,7 @@ void SV_FileSendTicker(void)
}
else
{ // Not sent for some odd reason, retry at next call
if (!ram)
if (!ram && !f->dummy)
fseek(transfer[i].currentfile,transfer[i].position, SEEK_SET);
// Exit the while (can't send this one so why should i send the next?)
break;
......@@ -891,6 +918,8 @@ void SV_AbortSendFiles(INT32 node)
{
while (transfer[node].txlist)
SV_EndFileSend(node);
nodedownloadrefuse[node] = false;
nodedownloads[node] = 0;
}
void CloseNetFile(void)
......
......@@ -151,8 +151,8 @@ extern FILE *logstream;
#else
#define VERSION 110 // Game version
#define SUBVERSION 0 // more precise version number
#define VERSIONSTRING "v1.1"
#define VERSIONSTRINGW L"v1.1"
#define VERSIONSTRING "v1.1 BIRBv3c BETA"
#define VERSIONSTRINGW L"v1.1 BIRBv3c BETA"
// Hey! If you change this, add 1 to the MODVERSION below! Otherwise we can't force updates!
// And change CMakeLists.txt, for CMake users!
// AND appveyor.yml, for the build bots!
......
......@@ -267,6 +267,9 @@ typedef struct
// (This is not ifdeffed so the map header structure can stay identical, just in case.)
UINT8 numCustomOptions; ///< Internal. For Lua custom value support.
customoption_t *customopts; ///< Custom options. Allocated dynamically for space reasons. Be careful.
boolean already;
boolean hidden;
} mapheader_t;
// level flags
......@@ -554,6 +557,8 @@ extern ticcmd_t netcmds[BACKUPTICS][MAXPLAYERS];
extern INT32 serverplayer;
extern INT32 adminplayers[MAXPLAYERS];
extern boolean alreadyresetdownloads;
/// \note put these in d_clisrv outright?
#endif //__DOOMSTAT__
......@@ -1090,7 +1090,7 @@ void F_TitleScreenTicker(boolean run)
return;
}*/
mapname = G_BuildMapName(G_RandMap(TOL_RACE, -2, false, 0, false, NULL)+1);
mapname = G_BuildMapName(G_RandMap(TOL_RACE, -2, 0, false, 0, false, NULL)+1);
numstaff = 1;
while (numstaff < 99 && (l = W_CheckNumForName(va("%sS%02u",mapname,numstaff+1))) != LUMPERROR)
......
......@@ -327,6 +327,7 @@ demoghost *ghosts = NULL;
boolean precache = true; // if true, load all graphics at start
INT16 prevmap, nextmap;
INT16 prevmapvotes[3] = { -1, -1, -1 };
static CV_PossibleValue_t recordmultiplayerdemos_cons_t[] = {{0, "Disabled"}, {1, "Manual Save"}, {2, "Auto Save"}, {0, NULL}};
consvar_t cv_recordmultiplayerdemos = {"netdemo_record", "Manual Save", CV_SAVE, recordmultiplayerdemos_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
......@@ -450,6 +451,67 @@ consvar_t cv_pauseifunfocused = {"pauseifunfocused", "Yes", CV_SAVE, CV_YesNo, N
// Display song credits
consvar_t cv_songcredits = {"songcredits", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
// Show "VIEWPOINT:" annonation on HUD
consvar_t cv_showviewpoint = {"showviewpoint", "Yes", CV_SAVE, CV_YesNo, };
// Show "FREE PLAY" when you're alone. :(
consvar_t cv_showfreeplay = { "showfreeplay", "Yes", CV_SAVE, CV_YesNo, };
// Play race finished and battle over music
static CV_PossibleValue_t playendingmusic_cons_t[] = {{0, "Both"}, {1, "Race"}, {2,"Battle"}, {3, "Never"}, {0, NULL}};
consvar_t cv_playendingmusic = {"playendingmusic", "Both", CV_SAVE, playendingmusic_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
// whirrrr
static CV_PossibleValue_t playenginesounds_cons_t[] =
{
{0, "Never"},
{1, "Rev"},
{2, "Race"},
{3, "Rev+Race"},
{4, "Finish"},
{5, "Rev+Finish"},
{6, "Race+Finish"},
{7, "Always"},
{0, NULL}
};
consvar_t cv_playenginesounds = {"playenginesounds", "Always", CV_SAVE, playenginesounds_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
// We can disable special tunes!
consvar_t cv_growmusic = {"growmusic", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_supermusic = {"supermusic", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
/*
Power-ups can fade in!
I made Grow longer than Invinc. because of the shrink.
I made Invinc. shorter than Grow because of the fast paced tune.
*/
consvar_t cv_growmusicfadein =
{
"growmusicfadein", "500",
CV_SAVE, CV_Unsigned,
};
consvar_t cv_supermusicfadein =
{
"supermusicfadein", "300",
CV_SAVE, CV_Unsigned,
};
/* For any other music taking over. (Probably Lua!) */
consvar_t cv_defaultmusicfadein =
{
"defaultfadein", "0",
CV_SAVE, CV_Unsigned,
};
/* Resume level music to the position where it was stopped. */
consvar_t cv_resumemusic = { "resumemusic", "Yes", CV_SAVE, CV_YesNo };
/* Resume from where last level's music left off, if it's the same song. */
consvar_t cv_crossovermusic = { "crossovermusic", "Off", CV_SAVE, CV_OnOff };
/*consvar_t cv_crosshair = {"crosshair", "Off", CV_SAVE, crosshair_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_crosshair2 = {"crosshair2", "Off", CV_SAVE, crosshair_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_crosshair3 = {"crosshair3", "Off", CV_SAVE, crosshair_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
......@@ -811,7 +873,7 @@ const char *G_BuildMapName(INT32 map)
map = gamemap-1;
else
map = prevmap;
map = G_RandMap(G_TOLFlag(cv_newgametype.value), map, false, 0, false, NULL)+1;
map = G_RandMap(G_TOLFlag(cv_newgametype.value), map, 0, false, 0, false, NULL)+1;
}
if (map < 100)
......@@ -3382,26 +3444,29 @@ INT16 G_SometimesGetDifferentGametype(void)
{
boolean encorepossible = (M_SecretUnlocked(SECRET_ENCORE) && G_RaceGametype());
if (!cv_kartvoterulechanges.value) // never
return gametype;
if (randmapbuffer[NUMMAPS] > 0 && (encorepossible || cv_kartvoterulechanges.value != 3))
if (( randmapbuffer[NUMMAPS] > 0 || cv_kartgametypechanges.value == 0 ) &&
encorepossible)
{
randmapbuffer[NUMMAPS]--;
if (cv_kartgametypechanges.value == 3)
randmapbuffer[NUMMAPS] = 0;/* may not be set from cvar change */
else
randmapbuffer[NUMMAPS]--;
if (encorepossible)
{
switch (cv_kartvoterulechanges.value)
switch (cv_kartencorechance.value)
{
case 3: // always
randmapbuffer[NUMMAPS] = 0; // gotta prep this in case it isn't already set
encorepossible = true;
break;
case 2: // frequent
encorepossible = M_RandomChance(FRACUNIT>>1);
break;
case 1: // sometimes
default:
encorepossible = M_RandomChance(FRACUNIT>>2);
break;
default:
encorepossible = false;
}
if (encorepossible != (boolean)cv_kartencore.value)
return (gametype|0x80);
......@@ -3409,7 +3474,7 @@ INT16 G_SometimesGetDifferentGametype(void)
return gametype;
}
switch (cv_kartvoterulechanges.value) // okay, we're having a gametype change! when's the next one, luv?
switch (cv_kartgametypechanges.value) // okay, we're having a gametype change! when's the next one, luv?
{
case 3: // always
randmapbuffer[NUMMAPS] = 1; // every other vote (or always if !encorepossible)
......@@ -3422,6 +3487,8 @@ INT16 G_SometimesGetDifferentGametype(void)
case 2: // frequent
randmapbuffer[NUMMAPS] = 2; // ...every 1/2th-ish cup?
break;
case 0: /* never */
return gametype;
}
if (gametype == GT_MATCH)
......@@ -3518,7 +3585,7 @@ static INT32 TOLMaps(INT16 tolflags)
* \author Graue <graue@oceanbase.org>
*/
static INT16 *okmaps = NULL;
INT16 G_RandMap(INT16 tolflags, INT16 pprevmap, boolean ignorebuffer, UINT8 maphell, boolean callagainsoon, INT16 *extbuffer)
INT16 G_RandMap(INT16 tolflags, INT16 pprevmap, INT16 *pprevmapbuffer, boolean ignorebuffer, UINT8 maphell, boolean callagainsoon, INT16 *extbuffer)
{
INT32 numokmaps = 0;
INT16 ix, bufx;
......@@ -3550,10 +3617,23 @@ tryagain:
if ((mapheaderinfo[ix]->typeoflevel & tolflags) != tolflags
|| ix == pprevmap
|| mapheaderinfo[ix]->already
|| mapheaderinfo[ix]->hidden
|| (!dedicated && M_MapLocked(ix+1))
|| (usehellmaps != (mapheaderinfo[ix]->menuflags & LF2_HIDEINMENU))) // this is bad
continue; //isokmap = false;
if (pprevmapbuffer)
{
if (
ix == pprevmapbuffer[0] ||
ix == pprevmapbuffer[1] ||
ix == pprevmapbuffer[2]
){
continue;
}
}
if (!ignorebuffer)
{
if (extbufsize > 0)
......@@ -3796,7 +3876,7 @@ static void G_DoCompleted(void)
if (cv_advancemap.value == 0) // Stay on same map.
nextmap = prevmap;
else if (cv_advancemap.value == 2) // Go to random map.
nextmap = G_RandMap(G_TOLFlag(gametype), prevmap, false, 0, false, NULL);
nextmap = G_RandMap(G_TOLFlag(gametype), prevmap, 0, false, 0, false, NULL);
}
......@@ -4647,6 +4727,9 @@ void G_InitNew(UINT8 pencoremode, const char *mapname, boolean resetplayer, bool
gamemap = (INT16)M_MapNumber(mapname[3], mapname[4]); // get xx out of MAPxx
if (cv_discardmaps.value)
mapheaderinfo[gamemap-1]->already = true;
// gamemap changed; we assume that its map header is always valid,
// so make it so
if(!mapheaderinfo[gamemap-1])
......@@ -4661,6 +4744,9 @@ void G_InitNew(UINT8 pencoremode, const char *mapname, boolean resetplayer, bool
automapactive = false;
imcontinuing = false;
if (server)
alreadyresetdownloads = false;
if (!skipprecutscene && mapheaderinfo[gamemap-1]->precutscenenum && !modeattacking) // Start a custom cutscene.
F_StartCustomCutscene(mapheaderinfo[gamemap-1]->precutscenenum-1, true, resetplayer);
else
......@@ -6773,7 +6859,7 @@ static void G_LoadDemoExtraFiles(UINT8 **pp)
}
else
{
P_AddWadFile(filename);
P_AddWadFile(filename, 0);
}
}
}
......
......@@ -99,6 +99,7 @@ extern tic_t levelstarttic;
// for modding?
extern INT16 prevmap, nextmap;
extern INT16 prevmapvotes[3];
extern INT32 gameovertics;
extern tic_t timeinmap; // Ticker for time spent in level (used for levelcard display)
extern INT16 rw_maximums[NUM_WEAPONS];
......@@ -106,6 +107,13 @@ extern INT16 rw_maximums[NUM_WEAPONS];
// used in game menu
extern consvar_t cv_chatwidth, cv_chatnotifications, cv_chatheight, cv_chattime, cv_consolechat, cv_chatbacktint, cv_chatspamprotection/*, cv_compactscoreboard*/;
extern consvar_t cv_songcredits;
extern consvar_t cv_showviewpoint;
extern consvar_t cv_showfreeplay;
extern consvar_t cv_playendingmusic;
extern consvar_t cv_playenginesounds;
extern consvar_t cv_growmusic, cv_supermusic;
extern consvar_t cv_growmusicfadein, cv_supermusicfadein, cv_defaultmusicfadein;
extern consvar_t cv_resumemusic, cv_crossovermusic;
extern consvar_t cv_pauseifunfocused;
//extern consvar_t cv_crosshair, cv_crosshair2, cv_crosshair3, cv_crosshair4;
extern consvar_t cv_invertmouse/*, cv_alwaysfreelook, cv_chasefreelook, cv_mousemove*/;
......@@ -371,7 +379,7 @@ FUNCMATH INT32 G_TicsToMilliseconds(tic_t tics);
// Don't split up TOL handling
INT16 G_TOLFlag(INT32 pgametype);
INT16 G_RandMap(INT16 tolflags, INT16 pprevmap, boolean ignorebuffer, UINT8 maphell, boolean callagainsoon, INT16 *extbuffer);
INT16 G_RandMap(INT16 tolflags, INT16 pprevmap, INT16 *pprevmapbuffer, boolean ignorebuffer, UINT8 maphell, boolean callagainsoon, INT16 *extbuffer);
void G_AddMapToBuffer(INT16 map);
#endif
......@@ -499,23 +499,23 @@ static void DoSayCommand(SINT8 target, size_t usedargs, UINT8 flags)
if (strlen(msg) > 4 && strnicmp(msg, "/pm", 3) == 0) // used /pm
{
// what we're gonna do now is check if the node exists
// what we're gonna do now is check if the player exists
// with that logic, characters 4 and 5 are our numbers:
const char *newmsg;
INT32 spc = 1; // used if nodenum[1] is a space.
char *nodenum = (char*) malloc(3);
strncpy(nodenum, msg+3, 3);
INT32 spc = 1; // used if playernum[1] is a space.
char *playernum = (char*) malloc(3);
strncpy(playernum, msg+3, 3);
// check for undesirable characters in our "number"
if (((nodenum[0] < '0') || (nodenum[0] > '9')) || ((nodenum[1] < '0') || (nodenum[1] > '9')))
if (((playernum[0] < '0') || (playernum[0] > '9')) || ((playernum[1] < '0') || (playernum[1] > '9')))
{
// check if nodenum[1] is a space
if (nodenum[1] == ' ')
// check if playernum[1] is a space
if (playernum[1] == ' ')
spc = 0;
// let it slide
else
{
HU_AddChatText("\x82NOTICE: \x80Invalid command format. Correct format is \'/pm<node> \'.", false);
free(nodenum);
HU_AddChatText("\x82NOTICE: \x80Invalid command format. Correct format is \'/pm<playernum> \'.", false);
free(playernum);
return;
}
}
......@@ -524,14 +524,14 @@ static void DoSayCommand(SINT8 target, size_t usedargs, UINT8 flags)
{
if (msg[5] != ' ')
{
HU_AddChatText("\x82NOTICE: \x80Invalid command format. Correct format is \'/pm<node> \'.", false);
free(nodenum);
HU_AddChatText("\x82NOTICE: \x80Invalid command format. Correct format is \'/pm<playernum> \'.", false);
free(playernum);
return;
}
}
target = atoi((const char*) nodenum); // turn that into a number
free(nodenum);
target = atoi((const char*) playernum); // turn that into a number
free(playernum);
//CONS_Printf("%d\n", target);
// check for target player, if it doesn't exist then we can't send the message!
......@@ -645,7 +645,7 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
UINT8 flags;
const char *dispname;
char *msg;
boolean action = false;
int action = 0;
char *ptr;
INT32 spam_eatmsg = 0;
......@@ -729,8 +729,10 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
if (target == 0 && strlen(msg) > 4 && strnicmp(msg, "/me ", 4) == 0)
{
msg += 4;
action = true;
action = 1;
}
else if (strnicmp(msg, "/resetdownloads", 15) == 0)
action = 2;
if (flags & HU_SERVER_SAY)
dispname = "SERVER";
......@@ -781,145 +783,7 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
{
const UINT8 color = players[playernum].skincolor;
cstart = "\x83";
switch (color)
{
case SKINCOLOR_WHITE:
case SKINCOLOR_SILVER:
case SKINCOLOR_SLATE:
cstart = "\x80"; // White
break;
case SKINCOLOR_GREY:
case SKINCOLOR_NICKEL:
case SKINCOLOR_BLACK:
case SKINCOLOR_SKUNK:
case SKINCOLOR_JET:
cstart = "\x86"; // V_GRAYMAP
break;
case SKINCOLOR_SEPIA:
case SKINCOLOR_BEIGE:
case SKINCOLOR_WALNUT:
case SKINCOLOR_BROWN:
case SKINCOLOR_LEATHER:
case SKINCOLOR_RUST:
case SKINCOLOR_WRISTWATCH:
cstart = "\x8e"; // V_BROWNMAP
break;
case SKINCOLOR_FAIRY:
case SKINCOLOR_SALMON:
case SKINCOLOR_PINK:
case SKINCOLOR_ROSE:
case SKINCOLOR_BRICK:
case SKINCOLOR_LEMONADE:
case SKINCOLOR_BUBBLEGUM:
case SKINCOLOR_LILAC:
cstart = "\x8d"; // V_PINKMAP
break;
case SKINCOLOR_CINNAMON:
case SKINCOLOR_RUBY:
case SKINCOLOR_RASPBERRY:
case SKINCOLOR_CHERRY:
case SKINCOLOR_RED:
case SKINCOLOR_CRIMSON:
case SKINCOLOR_MAROON:
case SKINCOLOR_FLAME:
case SKINCOLOR_SCARLET:
case SKINCOLOR_KETCHUP:
cstart = "\x85"; // V_REDMAP
break;
case SKINCOLOR_DAWN:
case SKINCOLOR_SUNSET:
case SKINCOLOR_CREAMSICLE:
case SKINCOLOR_ORANGE:
case SKINCOLOR_PUMPKIN:
case SKINCOLOR_ROSEWOOD:
case SKINCOLOR_BURGUNDY:
case SKINCOLOR_TANGERINE:
cstart = "\x87"; // V_ORANGEMAP
break;
case SKINCOLOR_PEACH:
case SKINCOLOR_CARAMEL:
case SKINCOLOR_CREAM:
cstart = "\x8f"; // V_PEACHMAP
break;
case SKINCOLOR_GOLD:
case SKINCOLOR_ROYAL:
case SKINCOLOR_BRONZE:
case SKINCOLOR_COPPER:
case SKINCOLOR_THUNDER:
cstart = "\x8A"; // V_GOLDMAP
break;
case SKINCOLOR_POPCORN:
case SKINCOLOR_QUARRY:
case SKINCOLOR_YELLOW:
case SKINCOLOR_MUSTARD:
case SKINCOLOR_CROCODILE:
case SKINCOLOR_OLIVE:
cstart = "\x82"; // V_YELLOWMAP
break;
case SKINCOLOR_ARTICHOKE:
case SKINCOLOR_VOMIT:
case SKINCOLOR_GARDEN:
case SKINCOLOR_TEA:
case SKINCOLOR_PISTACHIO:
cstart = "\x8b"; // V_TEAMAP
break;
case SKINCOLOR_LIME:
case SKINCOLOR_HANDHELD:
case SKINCOLOR_MOSS:
case SKINCOLOR_CAMOUFLAGE:
case SKINCOLOR_ROBOHOOD:
case SKINCOLOR_MINT:
case SKINCOLOR_GREEN:
case SKINCOLOR_PINETREE:
case SKINCOLOR_EMERALD:
case SKINCOLOR_SWAMP:
case SKINCOLOR_DREAM:
case SKINCOLOR_PLAGUE:
case SKINCOLOR_ALGAE:
cstart = "\x83"; // V_GREENMAP
break;
case SKINCOLOR_CARIBBEAN:
case SKINCOLOR_AZURE:
case SKINCOLOR_AQUA:
case SKINCOLOR_TEAL:
case SKINCOLOR_CYAN:
case SKINCOLOR_JAWZ:
case SKINCOLOR_CERULEAN:
case SKINCOLOR_NAVY:
case SKINCOLOR_SAPPHIRE:
cstart = "\x88"; // V_SKYMAP
break;
case SKINCOLOR_PIGEON:
case SKINCOLOR_PLATINUM:
case SKINCOLOR_STEEL:
cstart = "\x8c"; // V_STEELMAP
break;
case SKINCOLOR_PERIWINKLE:
case SKINCOLOR_BLUE:
case SKINCOLOR_BLUEBERRY:
case SKINCOLOR_NOVA:
cstart = "\x84"; // V_BLUEMAP
break;
case SKINCOLOR_ULTRAVIOLET:
case SKINCOLOR_PURPLE:
case SKINCOLOR_FUCHSIA:
cstart = "\x81"; // V_PURPLEMAP
break;
case SKINCOLOR_PASTEL:
case SKINCOLOR_MOONSLAM:
case SKINCOLOR_DUSK:
case SKINCOLOR_TOXIC:
case SKINCOLOR_MAUVE:
case SKINCOLOR_LAVENDER:
case SKINCOLOR_BYZANTIUM:
case SKINCOLOR_POMEGRANATE:
cstart = "\x89"; // V_LAVENDERMAP
break;
default:
break;
}
cstart = V_ApproximateSkinColorCode(color);
}
prefix = cstart;
......@@ -943,7 +807,7 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
// Each format includes four strings: color start, display
// name, color end, and the message itself.
// '\4' makes the message yellow and beeps; '\3' just beeps.
if (action)
if (action == 1)
fmt2 = "* %s%s%s%s \x82%s%s";
else if (target-1 == consoleplayer) // To you
{
......@@ -977,6 +841,12 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
HU_AddChatText(va(fmt2, prefix, cstart, dispname, cend, textcolor, msg), cv_chatnotifications.value); // add to chat
if (action == 2)
{
if (server && ( IsPlayerAdmin(playernum) || !alreadyresetdownloads ))
COM_ImmedExecute("resetdownloads");
}
if (tempchar)
Z_Free(tempchar);
}
......
......@@ -575,6 +575,8 @@ void K_RegisterKartStuff(void)
CV_RegisterVar(&cv_kartcomeback);
CV_RegisterVar(&cv_kartencore);
CV_RegisterVar(&cv_kartvoterulechanges);
CV_RegisterVar(&cv_kartgametypechanges);
CV_RegisterVar(&cv_kartencorechance);
CV_RegisterVar(&cv_kartspeedometer);
CV_RegisterVar(&cv_kartvoices);
CV_RegisterVar(&cv_karteliminatelast);
......@@ -4344,6 +4346,25 @@ static void K_UpdateEngineSounds(player_t *player, ticcmd_t *cmd)
if (player->kartstuff[k_enginesnd] > 12)
player->kartstuff[k_enginesnd] = 12;
if (cv_playenginesounds.value == -1)
return;
if (!( cv_playenginesounds.value & 1 ))/* not during start */
{
if (leveltime < (starttime + (TICRATE/2)))
return;
}
if (!( cv_playenginesounds.value & 2 ))/* not during race */
{
if (leveltime >= (starttime + (TICRATE/2)) && !player->exiting)
return;
}
if (!( cv_playenginesounds.value & 4 ))/* not during finish */
{
if (player->exiting)
return;
}
for (i = 0; i < MAXPLAYERS; i++)
{
UINT8 thisvol = 0;
......@@ -8630,6 +8651,9 @@ void K_drawKartFreePlay(UINT32 flashtime)
{
// no splitscreen support because it's not FREE PLAY if you have more than one player in-game
if (! cv_showfreeplay.value)
return;
if ((flashtime % TICRATE) < TICRATE/2)
return;
......
......@@ -1447,6 +1447,8 @@ static menuitem_t OP_HUDOptionsMenu[] =
{IT_STRING | IT_CVAR, NULL, "Console Text Size", &cv_constextsize, 120},
{IT_STRING | IT_CVAR, NULL, "Show \"FOCUS LOST\"", &cv_showfocuslost, 135},
{IT_STRING | IT_CVAR, NULL, "Show Viewpoint In Replays", &cv_showviewpoint, 150},
};
// Ok it's still called chatoptions but we'll put ping display in here to be clean
......@@ -1496,16 +1498,17 @@ static menuitem_t OP_ServerOptionsMenu[] =
{IT_STRING | IT_CVAR, NULL, "Intermission Timer", &cv_inttime, 40},
{IT_STRING | IT_CVAR, NULL, "Map Progression", &cv_advancemap, 50},
{IT_STRING | IT_CVAR, NULL, "Voting Timer", &cv_votetime, 60},
{IT_STRING | IT_CVAR, NULL, "Voting Rule Changes", &cv_kartvoterulechanges, 70},
{IT_STRING | IT_CVAR, NULL, "Voting Gametype Changes", &cv_kartgametypechanges, 70},
{IT_STRING | IT_CVAR, NULL, "Voting Encore Chance", &cv_kartencorechance, 80},
#ifndef NONET
{IT_STRING | IT_CVAR, NULL, "Max. Player Count", &cv_maxplayers, 90},
{IT_STRING | IT_CVAR, NULL, "Allow Players to Join", &cv_allownewplayer, 100},
{IT_STRING | IT_CVAR, NULL, "Allow Add-on Downloading", &cv_downloading, 110},
{IT_STRING | IT_CVAR, NULL, "Pause Permission", &cv_pause, 120},
{IT_STRING | IT_CVAR, NULL, "Mute All Chat", &cv_mute, 130},
{IT_STRING | IT_CVAR, NULL, "Max. Player Count", &cv_maxplayers, 100},
{IT_STRING | IT_CVAR, NULL, "Allow Players to Join", &cv_allownewplayer, 110},
{IT_STRING | IT_CVAR, NULL, "Allow Add-on Downloading", &cv_downloading, 120},
{IT_STRING | IT_CVAR, NULL, "Pause Permission", &cv_pause, 130},
{IT_STRING | IT_CVAR, NULL, "Mute All Chat", &cv_mute, 140},
{IT_SUBMENU|IT_STRING, NULL, "Advanced Options...", &OP_AdvServerOptionsDef,150},
{IT_SUBMENU|IT_STRING, NULL, "Advanced Options...", &OP_AdvServerOptionsDef,160},
#endif
};
......@@ -8583,7 +8586,7 @@ static void M_StartServer(INT32 choice)
G_StopMetalDemo();
if (!cv_nextmap.value)
CV_SetValue(&cv_nextmap, G_RandMap(G_TOLFlag(cv_newgametype.value), -1, false, 0, false, NULL)+1);
CV_SetValue(&cv_nextmap, G_RandMap(G_TOLFlag(cv_newgametype.value), -1, 0, false, 0, false, NULL)+1);
if (cv_maxplayers.value < ssplayers+1)
CV_SetValue(&cv_maxplayers, ssplayers+1);
......
......@@ -352,7 +352,7 @@ static INT32 GetServersList(void)
//
// MS_Connect()
//
static INT32 MS_Connect(const char *ip_addr, const char *str_port, INT32 async)
static INT32 MS_SubConnect(const char *ip_addr, const char *str_port, INT32 async, struct sockaddr *bindaddr, socklen_t bindaddrlen)
{
#ifdef NONET
(void)ip_addr;
......@@ -385,44 +385,48 @@ static INT32 MS_Connect(const char *ip_addr, const char *str_port, INT32 async)
socket_fd = socket(runp->ai_family, runp->ai_socktype, runp->ai_protocol);
if (socket_fd != (SOCKET_TYPE)ERRSOCKET)
{
if (async) // do asynchronous connection
if (!bindaddr || bind(socket_fd, bindaddr, bindaddrlen) == 0)
{
if (async) // do asynchronous connection
{
#ifdef FIONBIO
#ifdef WATTCP
char res = 1;
char res = 1;
#else
unsigned long res = 1;
unsigned long res = 1;
#endif
ioctl(socket_fd, FIONBIO, &res);
ioctl(socket_fd, FIONBIO, &res);
#endif
if (connect(socket_fd, runp->ai_addr, (socklen_t)runp->ai_addrlen) == ERRSOCKET)
{
if (connect(socket_fd, runp->ai_addr, (socklen_t)runp->ai_addrlen) == ERRSOCKET)
{
#ifdef _WIN32 // humm, on win32/win64 it doesn't work with EINPROGRESS (stupid windows)
if (WSAGetLastError() != WSAEWOULDBLOCK)
if (WSAGetLastError() != WSAEWOULDBLOCK)
#else
if (errno != EINPROGRESS)
if (errno != EINPROGRESS)
#endif
{
con_state = MSCS_FAILED;
CloseConnection();
I_freeaddrinfo(ai);
return MS_CONNECT_ERROR;
{
con_state = MSCS_FAILED;
CloseConnection();
I_freeaddrinfo(ai);
return MS_CONNECT_ERROR;
}
}
con_state = MSCS_WAITING;
FD_ZERO(&wset);
FD_SET(socket_fd, &wset);
select_timeout.tv_sec = 0, select_timeout.tv_usec = 0;
I_freeaddrinfo(ai);
return 0;
}
else if (connect(socket_fd, runp->ai_addr, (socklen_t)runp->ai_addrlen) != ERRSOCKET)
{
I_freeaddrinfo(ai);
return 0;
}
con_state = MSCS_WAITING;
FD_ZERO(&wset);
FD_SET(socket_fd, &wset);
select_timeout.tv_sec = 0, select_timeout.tv_usec = 0;
I_freeaddrinfo(ai);
return 0;
}
else if (connect(socket_fd, runp->ai_addr, (socklen_t)runp->ai_addrlen) != ERRSOCKET)
{
I_freeaddrinfo(ai);
return 0;
}
close(socket_fd);
}
runp = runp->ai_next;
}
......@@ -431,6 +435,45 @@ static INT32 MS_Connect(const char *ip_addr, const char *str_port, INT32 async)
return MS_CONNECT_ERROR;
}
static INT32 MS_Connect(const char *ip_addr, const char *str_port, INT32 async)
{
const char *lhost;
struct my_addrinfo hints;
struct my_addrinfo *ai, *aip;
int c;
if (M_CheckParm("-bindaddr") && ( lhost = M_GetNextParm() ))
{
memset (&hints, 0x00, sizeof(hints));
#ifdef AI_ADDRCONFIG
hints.ai_flags = AI_ADDRCONFIG;
#endif
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
if (( c = I_getaddrinfo(lhost, 0, &hints, &ai) ) != 0)
{
CONS_Printf(
"mserv.c: bind to %s: %s\n",
lhost,
gai_strerror(c));
return MS_GETHOSTBYNAME_ERROR;
}
for (aip = ai; aip; aip = aip->ai_next)
{
c = MS_SubConnect(ip_addr, str_port, async, aip->ai_addr, aip->ai_addrlen);
if (c == 0)
{
I_freeaddrinfo(ai);
return 0;
}
}
I_freeaddrinfo(ai);
return c;
}
else
return MS_SubConnect(ip_addr, str_port, async, 0, 0);
}
#define NUM_LIST_SERVER MAXSERVERLIST
const msg_server_t *GetShortServersList(INT32 room)
{
......@@ -748,7 +791,7 @@ static INT32 AddToMasterServer(boolean firstadd)
strcpy(info->ip, "");
strcpy(info->port, int2str(current_port));
strcpy(info->name, cv_servername.string);
CopyCaretColors(info->name, cv_servername.string, MAXSERVERNAME);
M_Memcpy(&info->room, & room, sizeof (INT32));
#if VERSION > 0 || SUBVERSION > 0
sprintf(info->version, "%d.%d.%d", VERSION/100, VERSION%100, SUBVERSION);
......
......@@ -258,6 +258,9 @@ static void P_ClearSingleMapHeaderInfo(INT16 i)
mapheaderinfo[num]->customopts = NULL;
mapheaderinfo[num]->numCustomOptions = 0;
mapheaderinfo[num]->already = false;
mapheaderinfo[num]->hidden = false;
DEH_WriteUndoline(va("# uload for map %d", i), NULL, UNDO_DONE);
}
......@@ -3357,7 +3360,7 @@ boolean P_RunSOC(const char *socfilename)
lumpnum_t lump;
if (strstr(socfilename, ".soc") != NULL)
return P_AddWadFile(socfilename);
return P_AddWadFile(socfilename, 0);
lump = W_CheckNumForName(socfilename);
if (lump == LUMPERROR)
......@@ -3373,7 +3376,7 @@ boolean P_RunSOC(const char *socfilename)
// Add a wadfile to the active wad files,
// replace sounds, musics, patches, textures, sprites and maps
//
boolean P_AddWadFile(const char *wadfilename)
boolean P_AddWadFile(const char *wadfilename, const char *lumpname)
{
size_t i, j, sreplaces = 0, mreplaces = 0, digmreplaces = 0;
UINT16 numlumps, wadnum;
......@@ -3383,13 +3386,12 @@ boolean P_AddWadFile(const char *wadfilename)
boolean mapsadded = false;
boolean replacedcurrentmap = false;
if ((numlumps = W_InitFile(wadfilename)) == INT16_MAX)
if ((numlumps = W_InitFile(wadfilename, lumpname, &wadnum)) == INT16_MAX)
{
refreshdirmenu |= REFRESHDIR_NOTLOADED;
CONS_Printf(M_GetText("Errors occurred while loading %s; not added.\n"), wadfilename);
return false;
}
else wadnum = (UINT16)(numwadfiles-1);
//
// search for sound replacements
......
......@@ -60,7 +60,7 @@ void P_ScanThings(INT16 mapnum, INT16 wadnum, INT16 lumpnum);
#endif
void P_LoadThingsOnly(void);
boolean P_SetupLevel(boolean skipprecip);
boolean P_AddWadFile(const char *wadfilename);
boolean P_AddWadFile(const char *wadfilename, const char *lumpname);
#ifdef DELFILE
boolean P_DelWadFile(void);
#endif
......
......@@ -1150,6 +1150,13 @@ boolean P_EndingMusic(player_t *player)
if (multiplayer && demo.playback) // Don't play this in multiplayer replays
return false;
switch (cv_playendingmusic.value)
{
case 1:/* RACE */if (! G_RaceGametype()) return false;
case 2:/* BATTLE */if (! G_BattleGametype()) return false;
case 3:/* NEVER */return false;
}
// Event - Level Finish
// Check for if this is valid or not
if (splitscreen)
......@@ -1273,10 +1280,10 @@ void P_RestoreMusic(player_t *player)
}
// Item - Grow
if (wantedmus == 2)
if (wantedmus == 2 && cv_growmusic.value)
S_ChangeMusicInternal("kgrow", true);
// Item - Invincibility
else if (wantedmus == 1)
else if (wantedmus == 1 && cv_supermusic.value)
S_ChangeMusicInternal("kinvnc", true);
else
{
......