mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
Merge branch 'hostcode' into 'master'
HOSTCODE initial pass Closes #240 See merge request KartKrew/Kart!615
This commit is contained in:
commit
062ac4ccf7
21 changed files with 1721 additions and 318 deletions
|
|
@ -34,6 +34,7 @@
|
|||
#include "k_menu.h"
|
||||
#include "filesrch.h"
|
||||
#include "m_misc.h"
|
||||
#include "m_random.h"
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#include "win32/win_main.h"
|
||||
|
|
@ -243,6 +244,81 @@ static void CONS_Bind_f(void)
|
|||
bindtable[key] = Z_StrDup(COM_Argv(2));
|
||||
}
|
||||
|
||||
static void CONS_Choose_f(void)
|
||||
{
|
||||
size_t na = COM_Argc();
|
||||
|
||||
if (na < 2)
|
||||
{
|
||||
CONS_Printf(M_GetText("choose <option1> [<option2>] [<option3>] [...]: Picks a command at random\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
COM_BufAddText(COM_Argv(M_RandomKey(na - 1) + 1));
|
||||
COM_BufAddText("\n");
|
||||
}
|
||||
|
||||
static void CONS_ChooseWeighted_f(void)
|
||||
{
|
||||
size_t na = COM_Argc();
|
||||
size_t i, cmd;
|
||||
const char *commands[40];
|
||||
INT32 weights[40];
|
||||
INT32 totalWeight = 0;
|
||||
INT32 roll;
|
||||
|
||||
if (na < 3)
|
||||
{
|
||||
CONS_Printf(M_GetText("chooseweighted <option1> <weight1> [<option2> <weight2>] [<option3> <weight3>] [...]: Picks a command with weighted randomization\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
memset(weights, 0, sizeof(weights));
|
||||
|
||||
i = 1;
|
||||
cmd = 0;
|
||||
while (i < na)
|
||||
{
|
||||
commands[cmd] = COM_Argv(i);
|
||||
|
||||
i++;
|
||||
if (i >= na)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
weights[cmd] = atoi(COM_Argv(i));
|
||||
totalWeight += weights[cmd];
|
||||
|
||||
i++;
|
||||
cmd++;
|
||||
}
|
||||
|
||||
if (cmd == 0 || totalWeight <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
roll = M_RandomRange(1, totalWeight);
|
||||
|
||||
for (i = 0; i < cmd; i++)
|
||||
{
|
||||
if (roll <= weights[i])
|
||||
{
|
||||
if (commands[i] == NULL)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
COM_BufAddText(commands[i]);
|
||||
COM_BufAddText("\n");
|
||||
break;
|
||||
}
|
||||
|
||||
roll -= weights[i];
|
||||
}
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// CONSOLE SETUP
|
||||
//======================================================================
|
||||
|
|
@ -445,6 +521,8 @@ void CON_Init(void)
|
|||
CV_RegisterVar(&cons_backpic);
|
||||
CV_RegisterVar(&cons_backcolor);
|
||||
COM_AddCommand("bind", CONS_Bind_f);
|
||||
COM_AddCommand("choose", CONS_Choose_f);
|
||||
COM_AddCommand("chooseweighted", CONS_ChooseWeighted_f);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
556
src/d_clisrv.c
556
src/d_clisrv.c
|
|
@ -122,7 +122,7 @@ SINT8 nodetoplayer4[MAXNETNODES]; // say the numplayer for this node if any (spl
|
|||
UINT8 playerpernode[MAXNETNODES]; // used specialy for splitscreen
|
||||
boolean nodeingame[MAXNETNODES]; // set false as nodes leave game
|
||||
|
||||
tic_t servermaxping = 800; // server's max ping. Defaults to 800
|
||||
tic_t servermaxping = 20; // server's max delay, in frames. Defaults to 20
|
||||
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];
|
||||
|
|
@ -189,6 +189,8 @@ consvar_t cv_playbackspeed = CVAR_INIT ("playbackspeed", "1", 0, playbackspeed_c
|
|||
|
||||
consvar_t cv_httpsource = CVAR_INIT ("http_source", "", CV_SAVE, NULL, NULL);
|
||||
|
||||
consvar_t cv_kicktime = CVAR_INIT ("kicktime", "10", CV_SAVE, CV_Unsigned, NULL);
|
||||
|
||||
static inline void *G_DcpyTiccmd(void* dest, const ticcmd_t* src, const size_t n)
|
||||
{
|
||||
const size_t d = n / sizeof(ticcmd_t);
|
||||
|
|
@ -2031,7 +2033,10 @@ static void CL_ConnectToServer(void)
|
|||
wipegamestate = GS_WAITINGPLAYERS;
|
||||
|
||||
ClearAdminPlayers();
|
||||
Schedule_Clear();
|
||||
Automate_Clear();
|
||||
K_ClearClientPowerLevels();
|
||||
|
||||
pnumnodes = 1;
|
||||
oldtic = 0;
|
||||
#ifndef NONET
|
||||
|
|
@ -2095,57 +2100,83 @@ static void CL_ConnectToServer(void)
|
|||
}
|
||||
|
||||
#ifndef NONET
|
||||
typedef struct banreason_s
|
||||
{
|
||||
char *reason;
|
||||
struct banreason_s *prev; //-1
|
||||
struct banreason_s *next; //+1
|
||||
} banreason_t;
|
||||
|
||||
static banreason_t *reasontail = NULL; //last entry, use prev
|
||||
static banreason_t *reasonhead = NULL; //1st entry, use next
|
||||
|
||||
static void Command_ShowBan(void) //Print out ban list
|
||||
{
|
||||
size_t i;
|
||||
const char *address, *mask;
|
||||
banreason_t *reasonlist = reasonhead;
|
||||
const char *address, *mask, *reason, *username;
|
||||
time_t unbanTime = NO_BAN_TIME;
|
||||
const time_t curTime = time(NULL);
|
||||
|
||||
if (I_GetBanAddress)
|
||||
CONS_Printf(M_GetText("Ban List:\n"));
|
||||
else
|
||||
return;
|
||||
|
||||
for (i = 0;(address = I_GetBanAddress(i)) != NULL;i++)
|
||||
for (i = 0; (address = I_GetBanAddress(i)) != NULL; i++)
|
||||
{
|
||||
unbanTime = NO_BAN_TIME;
|
||||
if (I_GetUnbanTime)
|
||||
unbanTime = I_GetUnbanTime(i);
|
||||
|
||||
if (unbanTime != NO_BAN_TIME && curTime >= unbanTime)
|
||||
continue;
|
||||
|
||||
CONS_Printf("%s: ", sizeu1(i+1));
|
||||
|
||||
if (I_GetBanUsername && (username = I_GetBanUsername(i)) != NULL)
|
||||
CONS_Printf("%s - ", username);
|
||||
|
||||
if (!I_GetBanMask || (mask = I_GetBanMask(i)) == NULL)
|
||||
CONS_Printf("%s: %s ", sizeu1(i+1), address);
|
||||
CONS_Printf("%s", address);
|
||||
else
|
||||
CONS_Printf("%s: %s/%s ", sizeu1(i+1), address, mask);
|
||||
CONS_Printf("%s/%s", address, mask);
|
||||
|
||||
if (reasonlist && reasonlist->reason)
|
||||
CONS_Printf("(%s)\n", reasonlist->reason);
|
||||
else
|
||||
CONS_Printf("\n");
|
||||
if (I_GetBanReason && (reason = I_GetBanReason(i)) != NULL)
|
||||
CONS_Printf(" - %s", reason);
|
||||
|
||||
if (reasonlist) reasonlist = reasonlist->next;
|
||||
if (unbanTime != NO_BAN_TIME)
|
||||
{
|
||||
// these are fudged a little to match what a joiner sees
|
||||
int minutes = ((unbanTime - curTime) + 30) / 60;
|
||||
int hours = (minutes + 1) / 60;
|
||||
int days = (hours + 1) / 24;
|
||||
if (days)
|
||||
CONS_Printf(" (%d day%s)", days, days > 1 ? "s" : "");
|
||||
else if (hours)
|
||||
CONS_Printf(" (%d hour%s)", hours, hours > 1 ? "s" : "");
|
||||
else if (minutes)
|
||||
CONS_Printf(" (%d minute%s)", minutes, minutes > 1 ? "s" : "");
|
||||
else
|
||||
CONS_Printf(" (<1 minute)");
|
||||
}
|
||||
|
||||
CONS_Printf("\n");
|
||||
}
|
||||
|
||||
if (i == 0 && !address)
|
||||
CONS_Printf(M_GetText("(empty)\n"));
|
||||
}
|
||||
|
||||
static boolean bansLoaded = false;
|
||||
// If you're a community contributor looking to improve how bans are written, please
|
||||
// offer your changes back to our Git repository. Kart Krew reserve the right to
|
||||
// utilise format numbers in use by community builds for different layouts.
|
||||
#define BANFORMAT 1
|
||||
|
||||
void D_SaveBan(void)
|
||||
{
|
||||
FILE *f;
|
||||
size_t i;
|
||||
banreason_t *reasonlist = reasonhead;
|
||||
const char *address, *mask;
|
||||
const char *username, *reason;
|
||||
const time_t curTime = time(NULL);
|
||||
time_t unbanTime = NO_BAN_TIME;
|
||||
const char *path = va("%s"PATHSEP"%s", srb2home, "ban.txt");
|
||||
|
||||
if (!reasonhead)
|
||||
if (bansLoaded != true)
|
||||
{
|
||||
remove(path);
|
||||
// You didn't even get to ATTEMPT to load bans.txt.
|
||||
// Don't immediately save nothing over it.
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -2157,78 +2188,79 @@ void D_SaveBan(void)
|
|||
return;
|
||||
}
|
||||
|
||||
for (i = 0;(address = I_GetBanAddress(i)) != NULL;i++)
|
||||
// Add header.
|
||||
fprintf(f, "BANFORMAT %d\n", BANFORMAT);
|
||||
|
||||
for (i = 0; (address = I_GetBanAddress(i)) != NULL; i++)
|
||||
{
|
||||
if (I_GetUnbanTime)
|
||||
{
|
||||
unbanTime = I_GetUnbanTime(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
unbanTime = NO_BAN_TIME;
|
||||
}
|
||||
|
||||
if (unbanTime != NO_BAN_TIME && curTime >= unbanTime)
|
||||
{
|
||||
// This one has served their sentence.
|
||||
// We don't need to save them in the file anymore.
|
||||
continue;
|
||||
}
|
||||
|
||||
mask = NULL;
|
||||
if (!I_GetBanMask || (mask = I_GetBanMask(i)) == NULL)
|
||||
fprintf(f, "%s 0", address);
|
||||
fprintf(f, "%s/0", address);
|
||||
else
|
||||
fprintf(f, "%s %s", address, mask);
|
||||
fprintf(f, "%s/%s", address, mask);
|
||||
|
||||
if (reasonlist && reasonlist->reason)
|
||||
fprintf(f, " %s\n", reasonlist->reason);
|
||||
// TODO: it'd be nice to convert this to an actual date-time,
|
||||
// so it'd be easier to edit outside of the game.
|
||||
fprintf(f, " %ld", (long)unbanTime);
|
||||
|
||||
username = NULL;
|
||||
if (I_GetBanUsername && (username = I_GetBanUsername(i)) != NULL)
|
||||
fprintf(f, " \"%s\"", username);
|
||||
else
|
||||
fprintf(f, " %s\n", "NA");
|
||||
fprintf(f, " \"%s\"", "Direct IP ban");
|
||||
|
||||
if (reasonlist) reasonlist = reasonlist->next;
|
||||
reason = NULL;
|
||||
if (I_GetBanReason && (reason = I_GetBanReason(i)) != NULL)
|
||||
fprintf(f, " \"%s\"\n", reason);
|
||||
else
|
||||
fprintf(f, " \"%s\"\n", "No reason given");
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
static void Ban_Add(const char *reason)
|
||||
{
|
||||
banreason_t *reasonlist = malloc(sizeof(*reasonlist));
|
||||
|
||||
if (!reasonlist)
|
||||
return;
|
||||
if (!reason)
|
||||
reason = "NA";
|
||||
|
||||
reasonlist->next = NULL;
|
||||
reasonlist->reason = Z_StrDup(reason);
|
||||
if ((reasonlist->prev = reasontail) == NULL)
|
||||
reasonhead = reasonlist;
|
||||
else
|
||||
reasontail->next = reasonlist;
|
||||
reasontail = reasonlist;
|
||||
}
|
||||
|
||||
static void Ban_Clear(void)
|
||||
{
|
||||
banreason_t *temp;
|
||||
|
||||
I_ClearBans();
|
||||
|
||||
reasontail = NULL;
|
||||
|
||||
while (reasonhead)
|
||||
{
|
||||
temp = reasonhead->next;
|
||||
Z_Free(reasonhead->reason);
|
||||
free(reasonhead);
|
||||
reasonhead = temp;
|
||||
}
|
||||
}
|
||||
|
||||
static void Command_ClearBans(void)
|
||||
{
|
||||
if (!I_ClearBans)
|
||||
return;
|
||||
|
||||
Ban_Clear();
|
||||
I_ClearBans();
|
||||
D_SaveBan();
|
||||
}
|
||||
|
||||
static void Ban_Load_File(boolean warning)
|
||||
void D_LoadBan(boolean warning)
|
||||
{
|
||||
FILE *f;
|
||||
size_t i;
|
||||
const char *address, *mask;
|
||||
size_t i, j;
|
||||
char *address, *mask;
|
||||
char *username, *reason;
|
||||
time_t unbanTime = NO_BAN_TIME;
|
||||
char buffer[MAX_WADPATH];
|
||||
UINT8 banmode = 0;
|
||||
boolean malformed = false;
|
||||
|
||||
if (!I_ClearBans)
|
||||
return;
|
||||
|
||||
// We at least attempted loading bans.txt
|
||||
bansLoaded = true;
|
||||
|
||||
f = fopen(va("%s"PATHSEP"%s", srb2home, "ban.txt"), "r");
|
||||
|
||||
if (!f)
|
||||
|
|
@ -2238,24 +2270,115 @@ static void Ban_Load_File(boolean warning)
|
|||
return;
|
||||
}
|
||||
|
||||
Ban_Clear();
|
||||
I_ClearBans();
|
||||
|
||||
for (i=0; fgets(buffer, (int)sizeof(buffer), f); i++)
|
||||
for (i = 0; fgets(buffer, (int)sizeof(buffer), f); i++)
|
||||
{
|
||||
address = strtok(buffer, " \t\r\n");
|
||||
address = strtok(buffer, " /\t\r\n");
|
||||
mask = strtok(NULL, " \t\r\n");
|
||||
|
||||
I_SetBanAddress(address, mask);
|
||||
if (i == 0 && !strncmp(address, "BANFORMAT", 9))
|
||||
{
|
||||
if (mask)
|
||||
{
|
||||
banmode = atoi(mask);
|
||||
}
|
||||
switch (banmode)
|
||||
{
|
||||
case BANFORMAT: // currently supported format
|
||||
//case 0: -- permitted only when BANFORMAT string not present
|
||||
break;
|
||||
default:
|
||||
{
|
||||
fclose(f);
|
||||
CONS_Alert(CONS_WARNING, "Could not load unknown ban.txt for ban list (BANFORMAT %s, expected %d)\n", mask, BANFORMAT);
|
||||
return;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
Ban_Add(strtok(NULL, "\r\n"));
|
||||
if (I_SetBanAddress(address, mask) == false) // invalid IP input?
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, "\"%s/%s\" is not a valid IP address, discarding...\n", address, mask);
|
||||
continue;
|
||||
}
|
||||
|
||||
// One-way legacy format conversion -- the game will crash otherwise
|
||||
if (banmode == 0)
|
||||
{
|
||||
unbanTime = NO_BAN_TIME;
|
||||
username = NULL; // not guaranteed to be accurate, but only sane substitute
|
||||
reason = strtok(NULL, "\r\n");
|
||||
if (reason && reason[0] == 'N' && reason[1] == 'A' && reason[2] == '\0')
|
||||
{
|
||||
reason = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
reason = strtok(NULL, " \"\t\r\n");
|
||||
if (reason)
|
||||
{
|
||||
unbanTime = atoi(reason);
|
||||
reason = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
unbanTime = NO_BAN_TIME;
|
||||
malformed = true;
|
||||
}
|
||||
|
||||
username = strtok(NULL, "\"\t\r\n"); // go until next "
|
||||
if (!username)
|
||||
{
|
||||
malformed = true;
|
||||
}
|
||||
|
||||
strtok(NULL, "\"\t\r\n"); // remove first "
|
||||
reason = strtok(NULL, "\"\r\n"); // go until next "
|
||||
if (!reason)
|
||||
{
|
||||
malformed = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Enforce MAX_REASONLENGTH.
|
||||
if (reason)
|
||||
{
|
||||
j = 0;
|
||||
while (reason[j] != '\0')
|
||||
{
|
||||
if ((j++) < MAX_REASONLENGTH)
|
||||
continue;
|
||||
reason[j] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (I_SetUnbanTime)
|
||||
I_SetUnbanTime(unbanTime);
|
||||
|
||||
if (I_SetBanUsername)
|
||||
I_SetBanUsername(username);
|
||||
|
||||
if (I_SetBanReason)
|
||||
I_SetBanReason(reason);
|
||||
}
|
||||
|
||||
if (malformed)
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, "One or more lines of ban.txt are malformed. The game can correct for this, but some data may be lost.\n");
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
#undef BANFORMAT
|
||||
|
||||
static void Command_ReloadBan(void) //recheck ban.txt
|
||||
{
|
||||
Ban_Load_File(true);
|
||||
D_LoadBan(true);
|
||||
}
|
||||
|
||||
static void Command_connect(void)
|
||||
|
|
@ -2400,6 +2523,8 @@ void CL_ClearPlayer(INT32 playernum)
|
|||
splitscreen_original_party_size[playernum] = 0;
|
||||
|
||||
memset(&players[playernum], 0, sizeof (player_t));
|
||||
|
||||
RemoveAdminPlayer(playernum); // don't stay admin after you're gone
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -2457,11 +2582,6 @@ void CL_RemovePlayer(INT32 playernum, kickreason_t reason)
|
|||
|
||||
player_name_changes[playernum] = 0;
|
||||
|
||||
if (IsPlayerAdmin(playernum))
|
||||
{
|
||||
RemoveAdminPlayer(playernum); // don't stay admin after you're gone
|
||||
}
|
||||
|
||||
LUA_InvalidatePlayer(&players[playernum]);
|
||||
|
||||
K_CheckBumpers();
|
||||
|
|
@ -2605,7 +2725,7 @@ static void Command_Ban(void)
|
|||
{
|
||||
if (COM_Argc() < 2)
|
||||
{
|
||||
CONS_Printf(M_GetText("Ban <playername/playernum> <reason>: ban and kick a player\n"));
|
||||
CONS_Printf(M_GetText("ban <playername/playernum> <reason>: ban and kick a player\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -2620,83 +2740,95 @@ static void Command_Ban(void)
|
|||
UINT8 buf[3 + MAX_REASONLENGTH];
|
||||
UINT8 *p = buf;
|
||||
const SINT8 pn = nametonum(COM_Argv(1));
|
||||
const INT32 node = playernode[(INT32)pn];
|
||||
|
||||
if (pn == -1 || pn == 0)
|
||||
return;
|
||||
|
||||
WRITEUINT8(p, pn);
|
||||
|
||||
if (server && I_Ban && !I_Ban(node)) // only the server is allowed to do this right now
|
||||
if (COM_Argc() == 2)
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, M_GetText("Too many bans! Geez, that's a lot of people you're excluding...\n"));
|
||||
WRITEUINT8(p, KICK_MSG_GO_AWAY);
|
||||
WRITEUINT8(p, KICK_MSG_BANNED);
|
||||
SendNetXCmd(XD_KICK, &buf, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (server) // only the server is allowed to do this right now
|
||||
size_t i, j = COM_Argc();
|
||||
char message[MAX_REASONLENGTH];
|
||||
|
||||
//Steal from the motd code so you don't have to put the reason in quotes.
|
||||
strlcpy(message, COM_Argv(2), sizeof message);
|
||||
for (i = 3; i < j; i++)
|
||||
{
|
||||
Ban_Add(COM_Argv(2));
|
||||
D_SaveBan(); // save the ban list
|
||||
strlcat(message, " ", sizeof message);
|
||||
strlcat(message, COM_Argv(i), sizeof message);
|
||||
}
|
||||
|
||||
if (COM_Argc() == 2)
|
||||
{
|
||||
WRITEUINT8(p, KICK_MSG_BANNED);
|
||||
SendNetXCmd(XD_KICK, &buf, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t i, j = COM_Argc();
|
||||
char message[MAX_REASONLENGTH];
|
||||
|
||||
//Steal from the motd code so you don't have to put the reason in quotes.
|
||||
strlcpy(message, COM_Argv(2), sizeof message);
|
||||
for (i = 3; i < j; i++)
|
||||
{
|
||||
strlcat(message, " ", sizeof message);
|
||||
strlcat(message, COM_Argv(i), sizeof message);
|
||||
}
|
||||
|
||||
WRITEUINT8(p, KICK_MSG_CUSTOM_BAN);
|
||||
WRITESTRINGN(p, message, MAX_REASONLENGTH);
|
||||
SendNetXCmd(XD_KICK, &buf, p - buf);
|
||||
}
|
||||
WRITEUINT8(p, KICK_MSG_CUSTOM_BAN);
|
||||
WRITESTRINGN(p, message, MAX_REASONLENGTH);
|
||||
SendNetXCmd(XD_KICK, &buf, p - buf);
|
||||
}
|
||||
}
|
||||
else
|
||||
CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n"));
|
||||
|
||||
}
|
||||
|
||||
static void Command_BanIP(void)
|
||||
{
|
||||
if (COM_Argc() < 2)
|
||||
size_t ac = COM_Argc();
|
||||
|
||||
if (ac < 2)
|
||||
{
|
||||
CONS_Printf(M_GetText("banip <ip> <reason>: ban an ip address\n"));
|
||||
CONS_Printf(M_GetText("banip <ip> [<reason>]: ban an ip address\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (server) // Only the server can use this, otherwise does nothing.
|
||||
{
|
||||
const char *address = (COM_Argv(1));
|
||||
const char *reason;
|
||||
char *addressInput = Z_StrDup(COM_Argv(1));
|
||||
|
||||
if (COM_Argc() == 2)
|
||||
reason = NULL;
|
||||
else
|
||||
const char *address = NULL;
|
||||
const char *mask = NULL;
|
||||
|
||||
const char *reason = NULL;
|
||||
|
||||
address = strtok(addressInput, "/");
|
||||
mask = strtok(NULL, "");
|
||||
|
||||
if (ac > 2)
|
||||
{
|
||||
reason = COM_Argv(2);
|
||||
}
|
||||
|
||||
|
||||
if (I_SetBanAddress && I_SetBanAddress(address, NULL))
|
||||
if (I_SetBanAddress && I_SetBanAddress(address, mask))
|
||||
{
|
||||
if (reason)
|
||||
CONS_Printf("Banned IP address %s for: %s\n", address, reason);
|
||||
{
|
||||
CONS_Printf(
|
||||
"Banned IP address %s%s for: %s\n",
|
||||
address,
|
||||
(mask && (strlen(mask) > 0)) ? va("/%s", mask) : "",
|
||||
reason
|
||||
);
|
||||
}
|
||||
else
|
||||
CONS_Printf("Banned IP address %s\n", address);
|
||||
{
|
||||
CONS_Printf(
|
||||
"Banned IP address %s%s\n",
|
||||
address,
|
||||
(mask && (strlen(mask) > 0)) ? va("/%s", mask) : ""
|
||||
);
|
||||
}
|
||||
|
||||
if (I_SetUnbanTime)
|
||||
I_SetUnbanTime(NO_BAN_TIME);
|
||||
|
||||
if (I_SetBanUsername)
|
||||
I_SetBanUsername(NULL);
|
||||
|
||||
if (I_SetBanReason)
|
||||
I_SetBanReason(reason);
|
||||
|
||||
Ban_Add(reason);
|
||||
D_SaveBan();
|
||||
}
|
||||
else
|
||||
|
|
@ -2774,6 +2906,7 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum)
|
|||
char buf[3 + MAX_REASONLENGTH];
|
||||
char *reason = buf;
|
||||
kickreason_t kickreason = KR_KICK;
|
||||
UINT32 banMinutes = 0;
|
||||
|
||||
pnum = READUINT8(*p);
|
||||
msg = READUINT8(*p);
|
||||
|
|
@ -2832,18 +2965,49 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum)
|
|||
msg = KICK_MSG_CON_FAIL;
|
||||
}
|
||||
|
||||
if (msg == KICK_MSG_CUSTOM_BAN || msg == KICK_MSG_CUSTOM_KICK)
|
||||
{
|
||||
READSTRINGN(*p, reason, MAX_REASONLENGTH+1);
|
||||
}
|
||||
|
||||
//CONS_Printf("\x82%s ", player_names[pnum]);
|
||||
|
||||
// If a verified admin banned someone, the server needs to know about it.
|
||||
// If the playernum isn't zero (the server) then the server needs to record the ban.
|
||||
if (server && playernum && (msg == KICK_MSG_BANNED || msg == KICK_MSG_CUSTOM_BAN))
|
||||
// Save bans here. Used to be split between here and the actual command, depending on
|
||||
// whenever the server did it or a remote admin did it, but it's simply more convenient
|
||||
// to keep it all in one place.
|
||||
if (server)
|
||||
{
|
||||
if (I_Ban && !I_Ban(playernode[(INT32)pnum]))
|
||||
CONS_Alert(CONS_WARNING, M_GetText("Too many bans! Geez, that's a lot of people you're excluding...\n"));
|
||||
#ifndef NONET
|
||||
else
|
||||
Ban_Add(reason);
|
||||
#endif
|
||||
if (msg == KICK_MSG_GO_AWAY || msg == KICK_MSG_CUSTOM_KICK)
|
||||
{
|
||||
// Kick as a temporary ban.
|
||||
banMinutes = cv_kicktime.value;
|
||||
}
|
||||
|
||||
if (msg == KICK_MSG_BANNED || msg == KICK_MSG_CUSTOM_BAN || banMinutes)
|
||||
{
|
||||
if (I_Ban && !I_Ban(playernode[(INT32)pnum]))
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, M_GetText("Ban failed. Invalid node?\n"));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (I_SetBanUsername)
|
||||
I_SetBanUsername(player_names[pnum]);
|
||||
|
||||
if (I_SetBanReason)
|
||||
I_SetBanReason(reason);
|
||||
|
||||
if (I_SetUnbanTime)
|
||||
{
|
||||
if (banMinutes)
|
||||
I_SetUnbanTime(time(NULL) + (banMinutes * 60));
|
||||
else
|
||||
I_SetUnbanTime(NO_BAN_TIME);
|
||||
}
|
||||
|
||||
D_SaveBan();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (msg == KICK_MSG_PLAYER_QUIT)
|
||||
|
|
@ -2858,7 +3022,7 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum)
|
|||
kickreason = KR_KICK;
|
||||
break;
|
||||
case KICK_MSG_PING_HIGH:
|
||||
HU_AddChatText(va("\x82*%s left the game (Broke ping limit)", player_names[pnum]), false);
|
||||
HU_AddChatText(va("\x82*%s left the game (Broke delay limit)", player_names[pnum]), false);
|
||||
kickreason = KR_PINGLIMIT;
|
||||
break;
|
||||
case KICK_MSG_CON_FAIL:
|
||||
|
|
@ -2912,12 +3076,10 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum)
|
|||
kickreason = KR_BAN;
|
||||
break;
|
||||
case KICK_MSG_CUSTOM_KICK:
|
||||
READSTRINGN(*p, reason, MAX_REASONLENGTH+1);
|
||||
HU_AddChatText(va("\x82*%s has been kicked (%s)", player_names[pnum], reason), false);
|
||||
kickreason = KR_KICK;
|
||||
break;
|
||||
case KICK_MSG_CUSTOM_BAN:
|
||||
READSTRINGN(*p, reason, MAX_REASONLENGTH+1);
|
||||
HU_AddChatText(va("\x82*%s has been banned (%s)", player_names[pnum], reason), false);
|
||||
kickreason = KR_BAN;
|
||||
break;
|
||||
|
|
@ -2940,23 +3102,25 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum)
|
|||
|
||||
if (playernode[pnum] == playernode[consoleplayer])
|
||||
{
|
||||
LUA_HookBool(false, HOOK(GameQuit));
|
||||
#ifdef DUMPCONSISTENCY
|
||||
if (msg == KICK_MSG_CON_FAIL) SV_SavedGame();
|
||||
#endif
|
||||
LUA_HookBool(false, HOOK(GameQuit)); //Lua hooks handled differently now
|
||||
|
||||
D_QuitNetGame();
|
||||
CL_Reset();
|
||||
D_StartTitle();
|
||||
|
||||
if (msg == KICK_MSG_CON_FAIL)
|
||||
M_StartMessage(M_GetText("Server closed connection\n(Synch failure)\nPress ESC\n"), NULL, MM_NOTHING);
|
||||
else if (msg == KICK_MSG_PING_HIGH)
|
||||
M_StartMessage(M_GetText("Server closed connection\n(Broke ping limit)\nPress ESC\n"), NULL, MM_NOTHING);
|
||||
M_StartMessage(M_GetText("Server closed connection\n(Broke delay limit)\nPress ESC\n"), NULL, MM_NOTHING);
|
||||
else if (msg == KICK_MSG_BANNED)
|
||||
M_StartMessage(M_GetText("You have been banned by the server\n\nPress ESC\n"), NULL, MM_NOTHING);
|
||||
else if (msg == KICK_MSG_CUSTOM_KICK)
|
||||
M_StartMessage(va(M_GetText("You have been kicked\n(%s)\nPress ESC\n"), reason), NULL, MM_NOTHING);
|
||||
M_StartMessage(va(M_GetText("You have been kicked\n(%s)\n\nPress ESC\n"), reason), NULL, MM_NOTHING);
|
||||
else if (msg == KICK_MSG_CUSTOM_BAN)
|
||||
M_StartMessage(va(M_GetText("You have been banned\n(%s)\nPress ESC\n"), reason), NULL, MM_NOTHING);
|
||||
M_StartMessage(va(M_GetText("You have been banned\n(%s)\n\nPress ESC\n"), reason), NULL, MM_NOTHING);
|
||||
else
|
||||
M_StartMessage(M_GetText("You have been kicked by the server\n\nPress ESC\n"), NULL, MM_NOTHING);
|
||||
}
|
||||
|
|
@ -3184,7 +3348,7 @@ void D_ClientServerInit(void)
|
|||
#ifdef DUMPCONSISTENCY
|
||||
CV_RegisterVar(&cv_dumpconsistency);
|
||||
#endif
|
||||
Ban_Load_File(false);
|
||||
D_LoadBan(false);
|
||||
#endif
|
||||
|
||||
gametic = 0;
|
||||
|
|
@ -3214,6 +3378,9 @@ static void ResetNode(INT32 node)
|
|||
sendingsavegame[node] = false;
|
||||
resendingsavegame[node] = false;
|
||||
savegameresendcooldown[node] = 0;
|
||||
|
||||
bannednode[node].banid = SIZE_MAX;
|
||||
bannednode[node].timeleft = NO_BAN_TIME;
|
||||
}
|
||||
|
||||
void SV_ResetServer(void)
|
||||
|
|
@ -3236,14 +3403,18 @@ void SV_ResetServer(void)
|
|||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
LUA_InvalidatePlayer(&players[i]);
|
||||
playeringame[i] = false;
|
||||
playernode[i] = UINT8_MAX;
|
||||
sprintf(player_names[i], "Player %c", 'A' + i);
|
||||
adminplayers[i] = -1; // Populate the entire adminplayers array with -1.
|
||||
K_ClearClientPowerLevels();
|
||||
splitscreen_invitations[i] = -1;
|
||||
}
|
||||
|
||||
memset(playeringame, false, sizeof playeringame);
|
||||
memset(playernode, UINT8_MAX, sizeof playernode);
|
||||
|
||||
ClearAdminPlayers();
|
||||
Schedule_Clear();
|
||||
Automate_Clear();
|
||||
K_ClearClientPowerLevels();
|
||||
|
||||
memset(splitscreen_invitations, -1, sizeof splitscreen_invitations);
|
||||
memset(splitscreen_partied, 0, sizeof splitscreen_partied);
|
||||
memset(player_name_changes, 0, sizeof player_name_changes);
|
||||
|
||||
|
|
@ -3328,6 +3499,8 @@ void D_QuitNetGame(void)
|
|||
|
||||
D_CloseConnection();
|
||||
ClearAdminPlayers();
|
||||
Schedule_Clear();
|
||||
Automate_Clear();
|
||||
K_ClearClientPowerLevels();
|
||||
|
||||
DEBFILE("===========================================================================\n"
|
||||
|
|
@ -3791,32 +3964,87 @@ static void HandleConnect(SINT8 node)
|
|||
// It's too much effort to legimately fix right now. Just prevent it from reaching that state.
|
||||
UINT8 maxplayers = min((dedicated ? MAXPLAYERS-1 : MAXPLAYERS), cv_maxconnections.value);
|
||||
|
||||
if (bannednode && bannednode[node])
|
||||
SV_SendRefuse(node, M_GetText("You have been banned\nfrom the server."));
|
||||
if (bannednode && bannednode[node].banid != SIZE_MAX)
|
||||
{
|
||||
const char *reason = NULL;
|
||||
|
||||
// Get the reason...
|
||||
if (!I_GetBanReason || (reason = I_GetBanReason(bannednode[node].banid)) == NULL)
|
||||
reason = "No reason given";
|
||||
|
||||
if (bannednode[node].timeleft != NO_BAN_TIME)
|
||||
{
|
||||
// these are fudged a little to allow it to sink in for impatient rejoiners
|
||||
int minutes = (bannednode[node].timeleft + 30) / 60;
|
||||
int hours = (minutes + 1) / 60;
|
||||
int days = (hours + 1) / 24;
|
||||
|
||||
if (days)
|
||||
{
|
||||
SV_SendRefuse(node, va("K|%s\n(Time remaining: %d day%s)", reason, days, days > 1 ? "s" : ""));
|
||||
}
|
||||
else if (hours)
|
||||
{
|
||||
SV_SendRefuse(node, va("K|%s\n(Time remaining: %d hour%s)", reason, hours, hours > 1 ? "s" : ""));
|
||||
}
|
||||
else if (minutes)
|
||||
{
|
||||
SV_SendRefuse(node, va("K|%s\n(Time remaining: %d minute%s)", reason, minutes, minutes > 1 ? "s" : ""));
|
||||
}
|
||||
else
|
||||
{
|
||||
SV_SendRefuse(node, va("K|%s\n(Time remaining: <1 minute)", reason));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SV_SendRefuse(node, va("B|%s", reason));
|
||||
}
|
||||
}
|
||||
else if (netbuffer->u.clientcfg._255 != 255 ||
|
||||
netbuffer->u.clientcfg.packetversion != PACKETVERSION)
|
||||
{
|
||||
SV_SendRefuse(node, "Incompatible packet formats.");
|
||||
}
|
||||
else if (strncmp(netbuffer->u.clientcfg.application, SRB2APPLICATION,
|
||||
sizeof netbuffer->u.clientcfg.application))
|
||||
{
|
||||
SV_SendRefuse(node, "Different Ring Racers modifications\nare not compatible.");
|
||||
}
|
||||
else if (netbuffer->u.clientcfg.version != VERSION
|
||||
|| netbuffer->u.clientcfg.subversion != SUBVERSION)
|
||||
{
|
||||
SV_SendRefuse(node, va(M_GetText("Different Ring Racers versions cannot\nplay a netgame!\n(server version %d.%d)"), VERSION, SUBVERSION));
|
||||
}
|
||||
else if (!cv_allownewplayer.value && node)
|
||||
{
|
||||
SV_SendRefuse(node, M_GetText("The server is not accepting\njoins for the moment."));
|
||||
}
|
||||
else if (D_NumPlayers() >= maxplayers)
|
||||
{
|
||||
SV_SendRefuse(node, va(M_GetText("Maximum players reached: %d"), maxplayers));
|
||||
}
|
||||
else if (netgame && netbuffer->u.clientcfg.localplayers > MAXSPLITSCREENPLAYERS) // Hacked client?
|
||||
{
|
||||
SV_SendRefuse(node, M_GetText("Too many players from\nthis node."));
|
||||
}
|
||||
else if (netgame && D_NumPlayers() + netbuffer->u.clientcfg.localplayers > maxplayers)
|
||||
{
|
||||
SV_SendRefuse(node, va(M_GetText("Number of local players\nwould exceed maximum: %d"), maxplayers));
|
||||
}
|
||||
else if (netgame && !netbuffer->u.clientcfg.localplayers) // Stealth join?
|
||||
{
|
||||
SV_SendRefuse(node, M_GetText("No players from\nthis node."));
|
||||
}
|
||||
else if (luafiletransfers)
|
||||
{
|
||||
SV_SendRefuse(node, M_GetText("The server is broadcasting a file\nrequested by a Lua script.\nPlease wait a bit and then\ntry rejoining."));
|
||||
}
|
||||
else if (netgame && joindelay > 2 * (tic_t)cv_joindelay.value * TICRATE)
|
||||
{
|
||||
SV_SendRefuse(node, va(M_GetText("Too many people are connecting.\nPlease wait %d seconds and then\ntry rejoining."),
|
||||
(joindelay - 2 * cv_joindelay.value * TICRATE) / TICRATE));
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifndef NONET
|
||||
|
|
@ -4090,13 +4318,22 @@ static void HandlePacketFromAwayNode(SINT8 node)
|
|||
break;
|
||||
}
|
||||
|
||||
M_StartMessage(va(M_GetText("Server refuses connection\n\nReason:\n%s"),
|
||||
reason), NULL, MM_NOTHING);
|
||||
|
||||
D_QuitNetGame();
|
||||
CL_Reset();
|
||||
D_StartTitle();
|
||||
|
||||
if (reason[1] == '|')
|
||||
{
|
||||
M_StartMessage(va("You have been %sfrom the server\n\nReason:\n%s",
|
||||
(reason[0] == 'B') ? "banned\n" : "temporarily\nkicked ",
|
||||
reason+2), NULL, MM_NOTHING);
|
||||
}
|
||||
else
|
||||
{
|
||||
M_StartMessage(va(M_GetText("Server refuses connection\n\nReason:\n%s"),
|
||||
reason), NULL, MM_NOTHING);
|
||||
}
|
||||
|
||||
free(reason);
|
||||
|
||||
// Will be reset by caller. Signals refusal.
|
||||
|
|
@ -5294,7 +5531,18 @@ boolean TryRunTics(tic_t realtics)
|
|||
ps_tictime = I_GetPreciseTime();
|
||||
|
||||
G_Ticker((gametic % NEWTICRATERATIO) == 0);
|
||||
if (gametic % TICRATE == 0)
|
||||
{
|
||||
Schedule_Run();
|
||||
|
||||
if (cv_livestudioaudience.value)
|
||||
{
|
||||
LiveStudioAudience();
|
||||
}
|
||||
}
|
||||
|
||||
ExtraDataTicker();
|
||||
|
||||
gametic++;
|
||||
consistancy[gametic%BACKUPTICS] = Consistancy();
|
||||
|
||||
|
|
@ -5424,7 +5672,7 @@ static void UpdatePingTable(void)
|
|||
if (! server_lagless && playernode[i] > 0 && !players[i].spectator)
|
||||
{
|
||||
lag = GetLag(playernode[i]);
|
||||
realpingtable[i] += (INT32)(lag * (1000.00f/TICRATE));
|
||||
realpingtable[i] += lag;
|
||||
|
||||
if (! fastest || lag < fastest)
|
||||
fastest = lag;
|
||||
|
|
@ -5432,7 +5680,7 @@ static void UpdatePingTable(void)
|
|||
else
|
||||
{
|
||||
// TicsToMilliseconds can't handle pings over 1000ms lol
|
||||
realpingtable[i] += (INT32)(GetLag(playernode[i]) * (1000.00f/TICRATE));
|
||||
realpingtable[i] += GetLag(playernode[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5450,7 +5698,7 @@ static void UpdatePingTable(void)
|
|||
else
|
||||
lag = GetLag(0);
|
||||
|
||||
lag = ( realpingtable[0] + G_TicsToMilliseconds(lag) );
|
||||
lag = ( realpingtable[0] + lag );
|
||||
|
||||
switch (playerpernode[0])
|
||||
{
|
||||
|
|
|
|||
|
|
@ -394,6 +394,7 @@ extern INT32 mapchangepending;
|
|||
extern doomdata_t *netbuffer;
|
||||
extern consvar_t cv_stunserver;
|
||||
extern consvar_t cv_httpsource;
|
||||
extern consvar_t cv_kicktime;
|
||||
|
||||
extern consvar_t cv_showjoinaddress;
|
||||
extern consvar_t cv_playbackspeed;
|
||||
|
|
|
|||
49
src/d_net.c
49
src/d_net.c
|
|
@ -83,8 +83,14 @@ void (*I_ClearBans)(void) = NULL;
|
|||
const char *(*I_GetNodeAddress) (INT32 node) = NULL;
|
||||
const char *(*I_GetBanAddress) (size_t ban) = NULL;
|
||||
const char *(*I_GetBanMask) (size_t ban) = NULL;
|
||||
const char *(*I_GetBanUsername) (size_t ban) = NULL;
|
||||
const char *(*I_GetBanReason) (size_t ban) = NULL;
|
||||
time_t (*I_GetUnbanTime) (size_t ban) = NULL;
|
||||
boolean (*I_SetBanAddress) (const char *address, const char *mask) = NULL;
|
||||
boolean *bannednode = NULL;
|
||||
boolean (*I_SetBanUsername) (const char *username) = NULL;
|
||||
boolean (*I_SetBanReason) (const char *reason) = NULL;
|
||||
boolean (*I_SetUnbanTime) (time_t timestamp) = NULL;
|
||||
bannednode_t *bannednode = NULL;
|
||||
|
||||
|
||||
// network stats
|
||||
|
|
@ -1389,6 +1395,7 @@ struct pingcell
|
|||
{
|
||||
INT32 num;
|
||||
INT32 ms;
|
||||
INT32 f;
|
||||
};
|
||||
|
||||
static int pingcellcmp(const void *va, const void *vb)
|
||||
|
|
@ -1412,6 +1419,7 @@ void Command_Ping_f(void)
|
|||
INT32 pingc;
|
||||
|
||||
int name_width = 0;
|
||||
int f_width = 0;
|
||||
int ms_width = 0;
|
||||
|
||||
int n;
|
||||
|
|
@ -1419,21 +1427,35 @@ void Command_Ping_f(void)
|
|||
|
||||
pingc = 0;
|
||||
for (i = 1; i < MAXPLAYERS; ++i)
|
||||
if (playeringame[i])
|
||||
{
|
||||
n = strlen(player_names[i]);
|
||||
if (n > name_width)
|
||||
name_width = n;
|
||||
if (playeringame[i])
|
||||
{
|
||||
INT32 ms;
|
||||
|
||||
n = playerpingtable[i];
|
||||
if (n > ms_width)
|
||||
ms_width = n;
|
||||
n = strlen(player_names[i]);
|
||||
if (n > name_width)
|
||||
name_width = n;
|
||||
|
||||
pingv[pingc].num = i;
|
||||
pingv[pingc].ms = playerpingtable[i];
|
||||
pingc++;
|
||||
n = playerpingtable[i];
|
||||
if (n > f_width)
|
||||
f_width = n;
|
||||
|
||||
ms = (INT32)(playerpingtable[i] * (1000.00f / TICRATE));
|
||||
n = ms;
|
||||
if (n > ms_width)
|
||||
ms_width = n;
|
||||
|
||||
pingv[pingc].num = i;
|
||||
pingv[pingc].f = playerpingtable[i];
|
||||
pingv[pingc].ms = ms;
|
||||
pingc++;
|
||||
}
|
||||
}
|
||||
|
||||
if (f_width < 10) f_width = 1;
|
||||
else if (f_width < 100) f_width = 2;
|
||||
else f_width = 3;
|
||||
|
||||
if (ms_width < 10) ms_width = 1;
|
||||
else if (ms_width < 100) ms_width = 2;
|
||||
else ms_width = 3;
|
||||
|
|
@ -1442,15 +1464,16 @@ void Command_Ping_f(void)
|
|||
|
||||
for (i = 0; i < pingc; ++i)
|
||||
{
|
||||
CONS_Printf("%02d : %-*s %*d ms\n",
|
||||
CONS_Printf("%02d : %-*s %*d frames (%*d ms)\n",
|
||||
pingv[i].num,
|
||||
name_width, player_names[pingv[i].num],
|
||||
f_width, pingv[i].f,
|
||||
ms_width, pingv[i].ms);
|
||||
}
|
||||
|
||||
if (!server && playeringame[consoleplayer])
|
||||
{
|
||||
CONS_Printf("\nYour ping is %d ms\n", playerpingtable[consoleplayer]);
|
||||
CONS_Printf("\nYour ping is %d frames (%d ms)\n", playerpingtable[consoleplayer], (INT32)(playerpingtable[i] * (1000.00f / TICRATE)));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ boolean HGetPacket(void);
|
|||
void D_SetDoomcom(void);
|
||||
#ifndef NONET
|
||||
void D_SaveBan(void);
|
||||
void D_LoadBan(boolean warning);
|
||||
#endif
|
||||
boolean D_CheckNetGame(void);
|
||||
void D_CloseConnection(void);
|
||||
|
|
|
|||
685
src/d_netcmd.c
685
src/d_netcmd.c
|
|
@ -99,6 +99,9 @@ static void Got_RunSOCcmd(UINT8 **cp, INT32 playernum);
|
|||
static void Got_Teamchange(UINT8 **cp, INT32 playernum);
|
||||
static void Got_Clearscores(UINT8 **cp, INT32 playernum);
|
||||
static void Got_DiscordInfo(UINT8 **cp, INT32 playernum);
|
||||
static void Got_ScheduleTaskcmd(UINT8 **cp, INT32 playernum);
|
||||
static void Got_ScheduleClearcmd(UINT8 **cp, INT32 playernum);
|
||||
static void Got_Automatecmd(UINT8 **cp, INT32 playernum);
|
||||
|
||||
static void PointLimit_OnChange(void);
|
||||
static void TimeLimit_OnChange(void);
|
||||
|
|
@ -147,6 +150,9 @@ static void KartEncore_OnChange(void);
|
|||
static void KartComeback_OnChange(void);
|
||||
static void KartEliminateLast_OnChange(void);
|
||||
|
||||
static void Schedule_OnChange(void);
|
||||
static void LiveStudioAudience_OnChange(void);
|
||||
|
||||
#ifdef NETGAME_DEVMODE
|
||||
static void Fishcake_OnChange(void);
|
||||
#endif
|
||||
|
|
@ -157,6 +163,8 @@ static void Command_Stopdemo_f(void);
|
|||
static void Command_StartMovie_f(void);
|
||||
static void Command_StopMovie_f(void);
|
||||
static void Command_Map_f(void);
|
||||
static void Command_RandomMap(void);
|
||||
static void Command_RestartLevel(void);
|
||||
static void Command_ResetCamera_f(void);
|
||||
|
||||
static void Command_View_f (void);
|
||||
|
|
@ -220,6 +228,12 @@ static void Command_Archivetest_f(void);
|
|||
|
||||
static void Command_KartGiveItem_f(void);
|
||||
|
||||
static void Command_Schedule_Add(void);
|
||||
static void Command_Schedule_Clear(void);
|
||||
static void Command_Schedule_List(void);
|
||||
|
||||
static void Command_Automate_Set(void);
|
||||
|
||||
// =========================================================================
|
||||
// CLIENT VARIABLES
|
||||
// =========================================================================
|
||||
|
|
@ -508,17 +522,20 @@ static CV_PossibleValue_t nettimeout_cons_t[] = {{TICRATE/7, "MIN"}, {60*TICRATE
|
|||
consvar_t cv_nettimeout = CVAR_INIT ("nettimeout", "105", CV_CALL|CV_SAVE, nettimeout_cons_t, NetTimeout_OnChange);
|
||||
//static CV_PossibleValue_t jointimeout_cons_t[] = {{5*TICRATE, "MIN"}, {60*TICRATE, "MAX"}, {0, NULL}};
|
||||
consvar_t cv_jointimeout = CVAR_INIT ("jointimeout", "105", CV_CALL|CV_SAVE, nettimeout_cons_t, JoinTimeout_OnChange);
|
||||
consvar_t cv_maxping = CVAR_INIT ("maxping", "800", CV_SAVE, CV_Unsigned, NULL);
|
||||
consvar_t cv_maxping = CVAR_INIT ("maxdelay", "20", CV_SAVE, CV_Unsigned, NULL);
|
||||
|
||||
consvar_t cv_lagless = CVAR_INIT ("lagless", "Off", CV_SAVE|CV_NETVAR|CV_CALL, CV_OnOff, Lagless_OnChange);
|
||||
|
||||
static CV_PossibleValue_t pingtimeout_cons_t[] = {{8, "MIN"}, {120, "MAX"}, {0, NULL}};
|
||||
consvar_t cv_pingtimeout = CVAR_INIT ("pingtimeout", "10", CV_SAVE|CV_NETVAR, pingtimeout_cons_t, NULL);
|
||||
consvar_t cv_pingtimeout = CVAR_INIT ("maxdelaytimeout", "10", CV_SAVE|CV_NETVAR, pingtimeout_cons_t, NULL);
|
||||
|
||||
// show your ping on the HUD next to framerate. Defaults to warning only (shows up if your ping is > maxping)
|
||||
static CV_PossibleValue_t showping_cons_t[] = {{0, "Off"}, {1, "Always"}, {2, "Warning"}, {0, NULL}};
|
||||
consvar_t cv_showping = CVAR_INIT ("showping", "Always", CV_SAVE, showping_cons_t, NULL);
|
||||
|
||||
static CV_PossibleValue_t pingmeasurement_cons_t[] = {{0, "Frames"}, {1, "Milliseconds"}, {0, NULL}};
|
||||
consvar_t cv_pingmeasurement = CVAR_INIT ("pingmeasurement", "Frames", CV_SAVE, pingmeasurement_cons_t, NULL);
|
||||
|
||||
consvar_t cv_showviewpointtext = CVAR_INIT ("showviewpointtext", "On", CV_SAVE, CV_OnOff, NULL);
|
||||
|
||||
// Intermission time Tails 04-19-2002
|
||||
|
|
@ -547,6 +564,16 @@ consvar_t cv_perfstats = CVAR_INIT ("perfstats", "Off", 0, perfstats_cons_t, NUL
|
|||
|
||||
consvar_t cv_director = CVAR_INIT ("director", "Off", 0, CV_OnOff, NULL);
|
||||
|
||||
consvar_t cv_schedule = CVAR_INIT ("schedule", "On", CV_NETVAR|CV_CALL, CV_OnOff, Schedule_OnChange);
|
||||
|
||||
consvar_t cv_automate = CVAR_INIT ("automate", "On", CV_NETVAR, CV_OnOff, NULL);
|
||||
|
||||
#ifdef DEVELOP
|
||||
consvar_t cv_livestudioaudience = CVAR_INIT ("livestudioaudience", "On", CV_NETVAR|CV_CALL, CV_OnOff, LiveStudioAudience_OnChange);
|
||||
#else
|
||||
consvar_t cv_livestudioaudience = CVAR_INIT ("livestudioaudience", "Off", CV_NETVAR|CV_CALL, CV_OnOff, LiveStudioAudience_OnChange);
|
||||
#endif
|
||||
|
||||
char timedemo_name[256];
|
||||
boolean timedemo_csv;
|
||||
char timedemo_csv_id[256];
|
||||
|
|
@ -562,44 +589,66 @@ UINT8 splitscreen = 0;
|
|||
boolean circuitmap = false;
|
||||
INT32 adminplayers[MAXPLAYERS];
|
||||
|
||||
// Scheduled commands.
|
||||
scheduleTask_t **schedule = NULL;
|
||||
size_t schedule_size = 0;
|
||||
size_t schedule_len = 0;
|
||||
|
||||
// Automation commands
|
||||
char *automate_commands[AEV__MAX];
|
||||
|
||||
const char *automate_names[AEV__MAX] =
|
||||
{
|
||||
"RoundStart", // AEV_ROUNDSTART
|
||||
"IntermissionStart", // AEV_INTERMISSIONSTART
|
||||
"VoteStart" // AEV_VOTESTART
|
||||
};
|
||||
|
||||
static UINT32 livestudioaudience_timer = 90;
|
||||
|
||||
/// \warning Keep this up-to-date if you add/remove/rename net text commands
|
||||
const char *netxcmdnames[MAXNETXCMD - 1] =
|
||||
{
|
||||
"NAMEANDCOLOR",
|
||||
"WEAPONPREF",
|
||||
"KICK",
|
||||
"NETVAR",
|
||||
"SAY",
|
||||
"MAP",
|
||||
"EXITLEVEL",
|
||||
"ADDFILE",
|
||||
"PAUSE",
|
||||
"ADDPLAYER",
|
||||
"TEAMCHANGE",
|
||||
"CLEARSCORES",
|
||||
"VERIFIED",
|
||||
"RANDOMSEED",
|
||||
"RUNSOC",
|
||||
"REQADDFILE",
|
||||
"SETMOTD",
|
||||
"RESPAWN",
|
||||
"DEMOTED",
|
||||
"LUACMD",
|
||||
"LUAVAR",
|
||||
"LUAFILE",
|
||||
"NAMEANDCOLOR", // XD_NAMEANDCOLOR
|
||||
"WEAPONPREF", // XD_WEAPONPREF
|
||||
"KICK", // XD_KICK
|
||||
"NETVAR", // XD_NETVAR
|
||||
"SAY", // XD_SAY
|
||||
"MAP", // XD_MAP
|
||||
"EXITLEVEL", // XD_EXITLEVEL
|
||||
"ADDFILE", // XD_ADDFILE
|
||||
"PAUSE", // XD_PAUSE
|
||||
"ADDPLAYER", // XD_ADDPLAYER
|
||||
"TEAMCHANGE", // XD_TEAMCHANGE
|
||||
"CLEARSCORES", // XD_CLEARSCORES
|
||||
"VERIFIED", // XD_VERIFIED
|
||||
"RANDOMSEED", // XD_RANDOMSEED
|
||||
"RUNSOC", // XD_RUNSOC
|
||||
"REQADDFILE", // XD_REQADDFILE
|
||||
"SETMOTD", // XD_SETMOTD
|
||||
"RESPAWN", // XD_RESPAWN
|
||||
"DEMOTED", // XD_DEMOTED
|
||||
"LUACMD", // XD_LUACMD
|
||||
"LUAVAR", // XD_LUAVAR
|
||||
"LUAFILE", // XD_LUAFILE
|
||||
|
||||
// SRB2Kart
|
||||
"SETUPVOTE",
|
||||
"MODIFYVOTE",
|
||||
"PICKVOTE",
|
||||
"REMOVEPLAYER",
|
||||
"POWERLEVEL",
|
||||
"PARTYINVITE",
|
||||
"ACCEPTPARTYINVITE",
|
||||
"LEAVEPARTY",
|
||||
"CANCELPARTYINVITE",
|
||||
"GIVEITEM",
|
||||
"ADDBOT"
|
||||
"SETUPVOTE", // XD_SETUPVOTE
|
||||
"MODIFYVOTE", // XD_MODIFYVOTE
|
||||
"PICKVOTE", // XD_PICKVOTE
|
||||
"REMOVEPLAYER", // XD_REMOVEPLAYER
|
||||
"POWERLEVEL", // XD_POWERLEVEL
|
||||
"PARTYINVITE", // XD_PARTYINVITE
|
||||
"ACCEPTPARTYINVITE", // XD_ACCEPTPARTYINVITE
|
||||
"LEAVEPARTY", // XD_LEAVEPARTY
|
||||
"CANCELPARTYINVITE", // XD_CANCELPARTYINVITE
|
||||
"GIVEITEM", // XD_GIVEITEM
|
||||
"ADDBOT", // XD_ADDBOT
|
||||
"DISCORD", // XD_DISCORD
|
||||
"PLAYSOUND", // XD_PLAYSOUND
|
||||
"SCHEDULETASK", // XD_SCHEDULETASK
|
||||
"SCHEDULECLEAR", // XD_SCHEDULECLEAR
|
||||
"AUTOMATE" // XD_AUTOMATE
|
||||
};
|
||||
|
||||
// =========================================================================
|
||||
|
|
@ -648,6 +697,10 @@ void D_RegisterServerCommands(void)
|
|||
|
||||
RegisterNetXCmd(XD_GIVEITEM, Got_GiveItemcmd);
|
||||
|
||||
RegisterNetXCmd(XD_SCHEDULETASK, Got_ScheduleTaskcmd);
|
||||
RegisterNetXCmd(XD_SCHEDULECLEAR, Got_ScheduleClearcmd);
|
||||
RegisterNetXCmd(XD_AUTOMATE, Got_Automatecmd);
|
||||
|
||||
// Remote Administration
|
||||
COM_AddCommand("password", Command_Changepassword_f);
|
||||
COM_AddCommand("login", Command_Login_f); // useful in dedicated to kick off remote admin
|
||||
|
|
@ -665,6 +718,8 @@ void D_RegisterServerCommands(void)
|
|||
RegisterNetXCmd(XD_CLEARSCORES, Got_Clearscores);
|
||||
COM_AddCommand("clearscores", Command_Clearscores_f);
|
||||
COM_AddCommand("map", Command_Map_f);
|
||||
COM_AddCommand("randommap", Command_RandomMap);
|
||||
COM_AddCommand("restartlevel", Command_RestartLevel);
|
||||
|
||||
COM_AddCommand("exitgame", Command_ExitGame_f);
|
||||
COM_AddCommand("retry", Command_Retry_f);
|
||||
|
|
@ -703,6 +758,12 @@ void D_RegisterServerCommands(void)
|
|||
|
||||
COM_AddCommand("kartgiveitem", Command_KartGiveItem_f);
|
||||
|
||||
COM_AddCommand("schedule_add", Command_Schedule_Add);
|
||||
COM_AddCommand("schedule_clear", Command_Schedule_Clear);
|
||||
COM_AddCommand("schedule_list", Command_Schedule_List);
|
||||
|
||||
COM_AddCommand("automate_set", Command_Automate_Set);
|
||||
|
||||
// for master server connection
|
||||
AddMServCommands();
|
||||
|
||||
|
|
@ -762,17 +823,22 @@ void D_RegisterServerCommands(void)
|
|||
COM_AddCommand("ping", Command_Ping_f);
|
||||
CV_RegisterVar(&cv_nettimeout);
|
||||
CV_RegisterVar(&cv_jointimeout);
|
||||
|
||||
CV_RegisterVar(&cv_kicktime);
|
||||
CV_RegisterVar(&cv_skipmapcheck);
|
||||
CV_RegisterVar(&cv_sleep);
|
||||
CV_RegisterVar(&cv_maxping);
|
||||
CV_RegisterVar(&cv_lagless);
|
||||
CV_RegisterVar(&cv_pingtimeout);
|
||||
CV_RegisterVar(&cv_showping);
|
||||
CV_RegisterVar(&cv_pingmeasurement);
|
||||
CV_RegisterVar(&cv_showviewpointtext);
|
||||
|
||||
CV_RegisterVar(&cv_director);
|
||||
|
||||
CV_RegisterVar(&cv_schedule);
|
||||
CV_RegisterVar(&cv_automate);
|
||||
CV_RegisterVar(&cv_livestudioaudience);
|
||||
|
||||
CV_RegisterVar(&cv_dummyconsvar);
|
||||
|
||||
#ifdef USE_STUN
|
||||
|
|
@ -963,6 +1029,11 @@ void D_RegisterClientCommands(void)
|
|||
CV_RegisterVar(&cv_consolechat);
|
||||
CV_RegisterVar(&cv_chatnotifications);
|
||||
CV_RegisterVar(&cv_chatbacktint);
|
||||
|
||||
CV_RegisterVar(&cv_shoutname);
|
||||
CV_RegisterVar(&cv_shoutcolor);
|
||||
CV_RegisterVar(&cv_autoshout);
|
||||
|
||||
CV_RegisterVar(&cv_songcredits);
|
||||
CV_RegisterVar(&cv_tutorialprompt);
|
||||
CV_RegisterVar(&cv_showfocuslost);
|
||||
|
|
@ -1079,6 +1150,15 @@ void D_RegisterClientCommands(void)
|
|||
* \sa CleanupPlayerName, SetPlayerName, Got_NameAndColor
|
||||
* \author Graue <graue@oceanbase.org>
|
||||
*/
|
||||
|
||||
static boolean AllowedPlayerNameChar(char ch)
|
||||
{
|
||||
if (!isprint(ch) || ch == ';' || ch == '"' || (UINT8)(ch) >= 0x80)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean EnsurePlayerNameIsGood(char *name, INT32 playernum)
|
||||
{
|
||||
INT32 ix;
|
||||
|
|
@ -1100,7 +1180,7 @@ boolean EnsurePlayerNameIsGood(char *name, INT32 playernum)
|
|||
// Also, anything over 0x80 is disallowed too, since compilers love to
|
||||
// differ on whether they're printable characters or not.
|
||||
for (ix = 0; name[ix] != '\0'; ix++)
|
||||
if (!isprint(name[ix]) || name[ix] == ';' || (UINT8)(name[ix]) >= 0x80)
|
||||
if (!AllowedPlayerNameChar(name[ix]))
|
||||
return false;
|
||||
|
||||
// Check if a player is currently using the name, case-insensitively.
|
||||
|
|
@ -1191,8 +1271,7 @@ void CleanupPlayerName(INT32 playernum, const char *newname)
|
|||
|
||||
do
|
||||
{
|
||||
/* from EnsurePlayerNameIsGood */
|
||||
if (!isprint(*p) || *p == ';' || (UINT8)*p >= 0x80)
|
||||
if (!AllowedPlayerNameChar(*p))
|
||||
break;
|
||||
}
|
||||
while (*++p) ;
|
||||
|
|
@ -2973,6 +3052,67 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum)
|
|||
#endif
|
||||
}
|
||||
|
||||
static void Command_RandomMap(void)
|
||||
{
|
||||
INT32 oldmapnum;
|
||||
INT32 newmapnum;
|
||||
INT32 newgametype;
|
||||
boolean newencoremode;
|
||||
boolean newresetplayers;
|
||||
|
||||
if (client && !IsPlayerAdmin(consoleplayer))
|
||||
{
|
||||
CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Handle singleplayer conditions.
|
||||
// The existing ones are way too annoyingly complicated and "anti-cheat" for my tastes.
|
||||
|
||||
if (Playing())
|
||||
{
|
||||
newgametype = gametype;
|
||||
newencoremode = encoremode;
|
||||
newresetplayers = false;
|
||||
|
||||
if (gamestate == GS_LEVEL)
|
||||
{
|
||||
oldmapnum = gamemap-1;
|
||||
}
|
||||
else
|
||||
{
|
||||
oldmapnum = prevmap;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
newgametype = cv_dummygametype.value; // Changed from cv_newgametype to match newmenus
|
||||
newencoremode = false;
|
||||
newresetplayers = true;
|
||||
oldmapnum = -1;
|
||||
}
|
||||
|
||||
newmapnum = G_RandMap(G_TOLFlag(newgametype), oldmapnum, 0, 0, false, NULL) + 1;
|
||||
D_MapChange(newmapnum, newgametype, newencoremode, newresetplayers, 0, false, false);
|
||||
}
|
||||
|
||||
static void Command_RestartLevel(void)
|
||||
{
|
||||
if (client && !IsPlayerAdmin(consoleplayer))
|
||||
{
|
||||
CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Playing())
|
||||
{
|
||||
CONS_Printf(M_GetText("You must be in a game to use this.\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
D_MapChange(gamemap, gametype, encoremode, false, 0, false, false);
|
||||
}
|
||||
|
||||
static void Command_Pause(void)
|
||||
{
|
||||
UINT8 buf[2];
|
||||
|
|
@ -3689,9 +3829,7 @@ void SetAdminPlayer(INT32 playernum)
|
|||
|
||||
void ClearAdminPlayers(void)
|
||||
{
|
||||
INT32 i;
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
adminplayers[i] = -1;
|
||||
memset(adminplayers, -1, sizeof(adminplayers));
|
||||
}
|
||||
|
||||
void RemoveAdminPlayer(INT32 playernum)
|
||||
|
|
@ -3808,6 +3946,218 @@ static void Got_Removal(UINT8 **cp, INT32 playernum)
|
|||
CONS_Printf(M_GetText("You are no longer a server administrator.\n"));
|
||||
}
|
||||
|
||||
void Schedule_Run(void)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (schedule_len == 0)
|
||||
{
|
||||
// No scheduled tasks to run.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!cv_schedule.value)
|
||||
{
|
||||
// We don't WANT to run tasks.
|
||||
return;
|
||||
}
|
||||
|
||||
if (K_CanChangeRules() == false)
|
||||
{
|
||||
// Don't engage in automation while in a restricted context.
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < schedule_len; i++)
|
||||
{
|
||||
scheduleTask_t *task = schedule[i];
|
||||
|
||||
if (task == NULL)
|
||||
{
|
||||
// Shouldn't happen.
|
||||
break;
|
||||
}
|
||||
|
||||
if (task->timer > 0)
|
||||
{
|
||||
task->timer--;
|
||||
}
|
||||
|
||||
if (task->timer == 0)
|
||||
{
|
||||
// Reset timer
|
||||
task->timer = task->basetime;
|
||||
|
||||
// Run command for server
|
||||
if (server)
|
||||
{
|
||||
CONS_Printf(
|
||||
"%d seconds elapsed, running \"" "\x82" "%s" "\x80" "\".\n",
|
||||
task->basetime,
|
||||
task->command
|
||||
);
|
||||
|
||||
COM_BufAddText(task->command);
|
||||
COM_BufAddText("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Schedule_Insert(scheduleTask_t *addTask)
|
||||
{
|
||||
if (schedule_len >= schedule_size)
|
||||
{
|
||||
if (schedule_size == 0)
|
||||
{
|
||||
schedule_size = 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
schedule_size *= 2;
|
||||
}
|
||||
|
||||
schedule = Z_ReallocAlign(
|
||||
(void*) schedule,
|
||||
sizeof(scheduleTask_t*) * schedule_size,
|
||||
PU_STATIC,
|
||||
NULL,
|
||||
sizeof(scheduleTask_t*) * 8
|
||||
);
|
||||
}
|
||||
|
||||
schedule[schedule_len] = addTask;
|
||||
schedule_len++;
|
||||
}
|
||||
|
||||
void Schedule_Add(INT16 basetime, INT16 timeleft, const char *command)
|
||||
{
|
||||
scheduleTask_t *task = (scheduleTask_t*) Z_CallocAlign(
|
||||
sizeof(scheduleTask_t),
|
||||
PU_STATIC,
|
||||
NULL,
|
||||
sizeof(scheduleTask_t) * 8
|
||||
);
|
||||
|
||||
task->basetime = basetime;
|
||||
task->timer = timeleft;
|
||||
task->command = Z_StrDup(command);
|
||||
|
||||
Schedule_Insert(task);
|
||||
}
|
||||
|
||||
void Schedule_Clear(void)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < schedule_len; i++)
|
||||
{
|
||||
scheduleTask_t *task = schedule[i];
|
||||
|
||||
if (task->command)
|
||||
Z_Free(task->command);
|
||||
}
|
||||
|
||||
schedule_len = 0;
|
||||
schedule_size = 0;
|
||||
schedule = NULL;
|
||||
}
|
||||
|
||||
void Automate_Set(automateEvents_t type, const char *command)
|
||||
{
|
||||
if (!server)
|
||||
{
|
||||
// Since there's no list command or anything for this,
|
||||
// we don't need this code to run for anyone but the server.
|
||||
return;
|
||||
}
|
||||
|
||||
if (automate_commands[type] != NULL)
|
||||
{
|
||||
// Free the old command.
|
||||
Z_Free(automate_commands[type]);
|
||||
}
|
||||
|
||||
if (command == NULL || strlen(command) == 0)
|
||||
{
|
||||
// Remove the command.
|
||||
automate_commands[type] = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
// New command.
|
||||
automate_commands[type] = Z_StrDup(command);
|
||||
}
|
||||
}
|
||||
|
||||
void Automate_Run(automateEvents_t type)
|
||||
{
|
||||
if (!server)
|
||||
{
|
||||
// Only the server should be doing this.
|
||||
return;
|
||||
}
|
||||
|
||||
if (K_CanChangeRules() == false)
|
||||
{
|
||||
// Don't engage in automation while in a restricted context.
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef PARANOIA
|
||||
if (type >= AEV__MAX)
|
||||
{
|
||||
// Shouldn't happen.
|
||||
I_Error("Attempted to run invalid automation type.");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!cv_automate.value)
|
||||
{
|
||||
// We don't want to run automation.
|
||||
return;
|
||||
}
|
||||
|
||||
if (automate_commands[type] == NULL)
|
||||
{
|
||||
// No command to run.
|
||||
return;
|
||||
}
|
||||
|
||||
CONS_Printf(
|
||||
"Running %s automate command \"" "\x82" "%s" "\x80" "\"...\n",
|
||||
automate_names[type],
|
||||
automate_commands[type]
|
||||
);
|
||||
|
||||
COM_BufAddText(automate_commands[type]);
|
||||
COM_BufAddText("\n");
|
||||
}
|
||||
|
||||
void Automate_Clear(void)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < AEV__MAX; i++)
|
||||
{
|
||||
Automate_Set(i, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void LiveStudioAudience(void)
|
||||
{
|
||||
if (livestudioaudience_timer == 0)
|
||||
{
|
||||
S_StartSound(NULL, sfx_mbv91);
|
||||
livestudioaudience_timer = 90;
|
||||
}
|
||||
else
|
||||
{
|
||||
livestudioaudience_timer--;
|
||||
}
|
||||
}
|
||||
|
||||
static void Command_MotD_f(void)
|
||||
{
|
||||
size_t i, j;
|
||||
|
|
@ -5002,6 +5352,101 @@ static void Got_GiveItemcmd(UINT8 **cp, INT32 playernum)
|
|||
players[playernum].itemamount = amt;
|
||||
}
|
||||
|
||||
static void Got_ScheduleTaskcmd(UINT8 **cp, INT32 playernum)
|
||||
{
|
||||
char command[MAXTEXTCMD];
|
||||
INT16 seconds;
|
||||
|
||||
seconds = READINT16(*cp);
|
||||
READSTRING(*cp, command);
|
||||
|
||||
if (playernum != serverplayer && !IsPlayerAdmin(playernum))
|
||||
{
|
||||
CONS_Alert(CONS_WARNING,
|
||||
M_GetText ("Illegal schedule task received from %s\n"),
|
||||
player_names[playernum]);
|
||||
if (server)
|
||||
SendKick(playernum, KICK_MSG_CON_FAIL);
|
||||
return;
|
||||
}
|
||||
|
||||
Schedule_Add(seconds, seconds, (const char *)command);
|
||||
|
||||
if (server || consoleplayer == playernum)
|
||||
{
|
||||
CONS_Printf(
|
||||
"OK! Running \"" "\x82" "%s" "\x80" "\" every " "\x82" "%d" "\x80" " seconds.\n",
|
||||
command,
|
||||
seconds
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static void Got_ScheduleClearcmd(UINT8 **cp, INT32 playernum)
|
||||
{
|
||||
(void)cp;
|
||||
|
||||
if (playernum != serverplayer && !IsPlayerAdmin(playernum))
|
||||
{
|
||||
CONS_Alert(CONS_WARNING,
|
||||
M_GetText ("Illegal schedule clear received from %s\n"),
|
||||
player_names[playernum]);
|
||||
if (server)
|
||||
SendKick(playernum, KICK_MSG_CON_FAIL);
|
||||
return;
|
||||
}
|
||||
|
||||
Schedule_Clear();
|
||||
|
||||
if (server || consoleplayer == playernum)
|
||||
{
|
||||
CONS_Printf("All scheduled tasks have been cleared.\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void Got_Automatecmd(UINT8 **cp, INT32 playernum)
|
||||
{
|
||||
UINT8 eventID;
|
||||
char command[MAXTEXTCMD];
|
||||
|
||||
eventID = READUINT8(*cp);
|
||||
READSTRING(*cp, command);
|
||||
|
||||
if (
|
||||
(playernum != serverplayer && !IsPlayerAdmin(playernum))
|
||||
|| (eventID >= AEV__MAX)
|
||||
)
|
||||
{
|
||||
CONS_Alert(CONS_WARNING,
|
||||
M_GetText ("Illegal automate received from %s\n"),
|
||||
player_names[playernum]);
|
||||
if (server)
|
||||
SendKick(playernum, KICK_MSG_CON_FAIL);
|
||||
return;
|
||||
}
|
||||
|
||||
Automate_Set(eventID, command);
|
||||
|
||||
if (server || consoleplayer == playernum)
|
||||
{
|
||||
if (command[0] == '\0')
|
||||
{
|
||||
CONS_Printf(
|
||||
"Removed the %s automate command.\n",
|
||||
automate_names[eventID]
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
CONS_Printf(
|
||||
"Set the %s automate command to \"" "\x82" "%s" "\x80" "\".\n",
|
||||
automate_names[eventID],
|
||||
command
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Prints the number of displayplayers[0].
|
||||
*
|
||||
* \todo Possibly remove this; it was useful for debugging at one point.
|
||||
|
|
@ -5266,6 +5711,135 @@ static void Command_KartGiveItem_f(void)
|
|||
}
|
||||
}
|
||||
|
||||
static void Command_Schedule_Add(void)
|
||||
{
|
||||
UINT8 buf[MAXTEXTCMD];
|
||||
UINT8 *buf_p = buf;
|
||||
|
||||
size_t ac;
|
||||
INT16 seconds;
|
||||
const char *command;
|
||||
|
||||
if (!(server || IsPlayerAdmin(consoleplayer)))
|
||||
{
|
||||
CONS_Printf("Only the server or a remote admin can use this.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ac = COM_Argc();
|
||||
if (ac < 3)
|
||||
{
|
||||
CONS_Printf("schedule <seconds> <...>: runs the specified commands on a recurring timer\n");
|
||||
return;
|
||||
}
|
||||
|
||||
seconds = atoi(COM_Argv(1));
|
||||
|
||||
if (seconds <= 0)
|
||||
{
|
||||
CONS_Printf("Timer must be at least 1 second.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
command = COM_Argv(2);
|
||||
|
||||
WRITEINT16(buf_p, seconds);
|
||||
WRITESTRING(buf_p, command);
|
||||
|
||||
SendNetXCmd(XD_SCHEDULETASK, buf, buf_p - buf);
|
||||
}
|
||||
|
||||
static void Command_Schedule_Clear(void)
|
||||
{
|
||||
if (!(server || IsPlayerAdmin(consoleplayer)))
|
||||
{
|
||||
CONS_Printf("Only the server or a remote admin can use this.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
SendNetXCmd(XD_SCHEDULECLEAR, NULL, 0);
|
||||
}
|
||||
|
||||
static void Command_Schedule_List(void)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (!(server || IsPlayerAdmin(consoleplayer)))
|
||||
{
|
||||
// I set it up in a way that this information could be available
|
||||
// to everyone, but HOSTMOD has it server/admin-only too, so eh?
|
||||
CONS_Printf("Only the server or a remote admin can use this.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (schedule_len == 0)
|
||||
{
|
||||
CONS_Printf("No tasks are scheduled.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < schedule_len; i++)
|
||||
{
|
||||
scheduleTask_t *task = schedule[i];
|
||||
|
||||
CONS_Printf(
|
||||
"In " "\x82" "%d" "\x80" " second%s: " "\x82" "%s" "\x80" "\n",
|
||||
task->timer,
|
||||
(task->timer > 1) ? "s" : "",
|
||||
task->command
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static void Command_Automate_Set(void)
|
||||
{
|
||||
UINT8 buf[MAXTEXTCMD];
|
||||
UINT8 *buf_p = buf;
|
||||
|
||||
size_t ac;
|
||||
|
||||
const char *event;
|
||||
size_t eventID;
|
||||
|
||||
const char *command;
|
||||
|
||||
if (!(server || IsPlayerAdmin(consoleplayer)))
|
||||
{
|
||||
CONS_Printf("Only the server or a remote admin can use this.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ac = COM_Argc();
|
||||
if (ac < 3)
|
||||
{
|
||||
CONS_Printf("automate_set <event> <command>: sets the command to run each time a event triggers\n");
|
||||
return;
|
||||
}
|
||||
|
||||
event = COM_Argv(1);
|
||||
|
||||
for (eventID = 0; eventID < AEV__MAX; eventID++)
|
||||
{
|
||||
if (strcasecmp(event, automate_names[eventID]) == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (eventID == AEV__MAX)
|
||||
{
|
||||
CONS_Printf("Unknown event type \"%s\".\n", event);
|
||||
return;
|
||||
}
|
||||
|
||||
command = COM_Argv(2);
|
||||
|
||||
WRITEUINT8(buf_p, eventID);
|
||||
WRITESTRING(buf_p, command);
|
||||
|
||||
SendNetXCmd(XD_AUTOMATE, buf, buf_p - buf);
|
||||
}
|
||||
|
||||
/** Makes a change to ::cv_forceskin take effect immediately.
|
||||
*
|
||||
* \sa Command_SetForcedSkin_f, cv_forceskin, forcedskin
|
||||
|
|
@ -5884,6 +6458,33 @@ static void KartEliminateLast_OnChange(void)
|
|||
P_CheckRacers();
|
||||
}
|
||||
|
||||
static void Schedule_OnChange(void)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (cv_schedule.value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (schedule_len == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Reset timers when turning off.
|
||||
for (i = 0; i < schedule_len; i++)
|
||||
{
|
||||
scheduleTask_t *task = schedule[i];
|
||||
task->timer = task->basetime;
|
||||
}
|
||||
}
|
||||
|
||||
static void LiveStudioAudience_OnChange(void)
|
||||
{
|
||||
livestudioaudience_timer = 90;
|
||||
}
|
||||
|
||||
void Got_DiscordInfo(UINT8 **p, INT32 playernum)
|
||||
{
|
||||
if (playernum != serverplayer /*&& !IsPlayerAdmin(playernum)*/)
|
||||
|
|
|
|||
|
|
@ -118,6 +118,7 @@ extern consvar_t cv_maxping;
|
|||
extern consvar_t cv_lagless;
|
||||
extern consvar_t cv_pingtimeout;
|
||||
extern consvar_t cv_showping;
|
||||
extern consvar_t cv_pingmeasurement;
|
||||
extern consvar_t cv_showviewpointtext;
|
||||
|
||||
extern consvar_t cv_skipmapcheck;
|
||||
|
|
@ -128,6 +129,10 @@ extern consvar_t cv_perfstats;
|
|||
|
||||
extern consvar_t cv_director;
|
||||
|
||||
extern consvar_t cv_schedule;
|
||||
|
||||
extern consvar_t cv_livestudioaudience;
|
||||
|
||||
extern char timedemo_name[256];
|
||||
extern boolean timedemo_csv;
|
||||
extern char timedemo_csv_id[256];
|
||||
|
|
@ -171,6 +176,10 @@ typedef enum
|
|||
XD_GIVEITEM, // 32
|
||||
XD_ADDBOT, // 33
|
||||
XD_DISCORD, // 34
|
||||
XD_PLAYSOUND, // 35
|
||||
XD_SCHEDULETASK, // 36
|
||||
XD_SCHEDULECLEAR, // 37
|
||||
XD_AUTOMATE, // 38
|
||||
|
||||
MAXNETXCMD
|
||||
} netxcmd_t;
|
||||
|
|
@ -239,6 +248,36 @@ void RemoveAdminPlayer(INT32 playernum);
|
|||
void ItemFinder_OnChange(void);
|
||||
void D_SetPassword(const char *pw);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT16 basetime;
|
||||
UINT16 timer;
|
||||
char *command;
|
||||
} scheduleTask_t;
|
||||
|
||||
extern scheduleTask_t **schedule;
|
||||
extern size_t schedule_size;
|
||||
extern size_t schedule_len;
|
||||
|
||||
void Schedule_Run(void);
|
||||
void Schedule_Insert(scheduleTask_t *addTask);
|
||||
void Schedule_Add(INT16 basetime, INT16 timeleft, const char *command);
|
||||
void Schedule_Clear(void);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
AEV_ROUNDSTART,
|
||||
AEV_INTERMISSIONSTART,
|
||||
AEV_VOTESTART,
|
||||
AEV__MAX
|
||||
} automateEvents_t;
|
||||
|
||||
void Automate_Run(automateEvents_t type);
|
||||
void Automate_Set(automateEvents_t type, const char *command);
|
||||
void Automate_Clear(void);
|
||||
|
||||
void LiveStudioAudience(void);
|
||||
|
||||
// used for the player setup menu
|
||||
UINT8 CanChangeSkin(INT32 playernum);
|
||||
|
||||
|
|
|
|||
|
|
@ -796,7 +796,6 @@ extern consvar_t cv_forceskin; // force clients to use the server's skin
|
|||
extern consvar_t cv_downloading; // allow clients to downloading WADs.
|
||||
extern consvar_t cv_nettimeout; // SRB2Kart: Advanced server options menu
|
||||
extern consvar_t cv_jointimeout;
|
||||
extern consvar_t cv_maxping;
|
||||
extern ticcmd_t netcmds[BACKUPTICS][MAXPLAYERS];
|
||||
extern INT32 serverplayer;
|
||||
extern INT32 adminplayers[MAXPLAYERS];
|
||||
|
|
|
|||
40
src/g_game.c
40
src/g_game.c
|
|
@ -379,6 +379,36 @@ consvar_t cv_chatbacktint = CVAR_INIT ("chatbacktint", "On", CV_SAVE, CV_OnOff,
|
|||
static CV_PossibleValue_t consolechat_cons_t[] = {{0, "Window"}, {1, "Console"}, {2, "Window (Hidden)"}, {0, NULL}};
|
||||
consvar_t cv_consolechat = CVAR_INIT ("chatmode", "Window", CV_SAVE, consolechat_cons_t, NULL);
|
||||
|
||||
// Shout settings
|
||||
// The relevant ones are CV_NETVAR because too lazy to send them any other way
|
||||
consvar_t cv_shoutname = CVAR_INIT ("shout_name", "SERVER", CV_NETVAR, NULL, NULL);
|
||||
|
||||
static CV_PossibleValue_t shoutcolor_cons_t[] =
|
||||
{
|
||||
{-1, "Player color"},
|
||||
{0, "White"},
|
||||
{1, "Yellow"},
|
||||
{2, "Purple"},
|
||||
{3, "Green"},
|
||||
{4, "Blue"},
|
||||
{5, "Red"},
|
||||
{6, "Gray"},
|
||||
{7, "Orange"},
|
||||
{8, "Sky-blue"},
|
||||
{9, "Gold"},
|
||||
{10, "Lavender"},
|
||||
{11, "Aqua-green"},
|
||||
{12, "Magenta"},
|
||||
{13, "Pink"},
|
||||
{14, "Brown"},
|
||||
{15, "Tan"},
|
||||
{0, NULL}
|
||||
};
|
||||
consvar_t cv_shoutcolor = CVAR_INIT ("shout_color", "Red", CV_NETVAR, shoutcolor_cons_t, NULL);
|
||||
|
||||
// If on and you're an admin, your messages will automatically become shouts.
|
||||
consvar_t cv_autoshout = CVAR_INIT ("autoshout", "Off", CV_NETVAR, CV_OnOff, NULL);
|
||||
|
||||
// Pause game upon window losing focus
|
||||
consvar_t cv_pauseifunfocused = CVAR_INIT ("pauseifunfocused", "Yes", CV_SAVE, CV_YesNo, NULL);
|
||||
|
||||
|
|
@ -1255,6 +1285,7 @@ static void weaponPrefChange4(void)
|
|||
//
|
||||
void G_DoLoadLevel(boolean resetplayer)
|
||||
{
|
||||
boolean doAutomate = false;
|
||||
INT32 i;
|
||||
|
||||
// Make sure objectplace is OFF when you first start the level!
|
||||
|
|
@ -1287,6 +1318,10 @@ void G_DoLoadLevel(boolean resetplayer)
|
|||
else
|
||||
titlemapinaction = TITLEMAP_OFF;
|
||||
|
||||
// Doing this matches HOSTMOD behavior.
|
||||
// Is that desired? IDK
|
||||
doAutomate = (gamestate != GS_LEVEL);
|
||||
|
||||
G_SetGamestate(GS_LEVEL);
|
||||
if (wipegamestate == GS_MENU)
|
||||
M_ClearMenus(true);
|
||||
|
|
@ -1325,6 +1360,11 @@ void G_DoLoadLevel(boolean resetplayer)
|
|||
CON_ClearHUD();
|
||||
|
||||
server_lagless = cv_lagless.value;
|
||||
|
||||
if (doAutomate == true)
|
||||
{
|
||||
Automate_Run(AEV_ROUNDSTART);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ extern boolean promptactive;
|
|||
extern consvar_t cv_tutorialprompt;
|
||||
|
||||
extern consvar_t cv_chatwidth, cv_chatnotifications, cv_chatheight, cv_chattime, cv_consolechat, cv_chatbacktint, cv_chatspamprotection;
|
||||
extern consvar_t cv_shoutname, cv_shoutcolor, cv_autoshout;
|
||||
extern consvar_t cv_songcredits;
|
||||
|
||||
extern consvar_t cv_pauseifunfocused;
|
||||
|
|
|
|||
141
src/hu_stuff.c
141
src/hu_stuff.c
|
|
@ -64,8 +64,11 @@
|
|||
#define HU_INPUTX 0
|
||||
#define HU_INPUTY 0
|
||||
|
||||
#define HU_SERVER_SAY 1 // Server message (dedicated).
|
||||
#define HU_CSAY 2 // Server CECHOes to everyone.
|
||||
typedef enum
|
||||
{
|
||||
HU_SHOUT = 1, // Shout message
|
||||
HU_CSAY = 1<<1, // Middle-of-screen server message
|
||||
} sayflags_t;
|
||||
|
||||
//-------------------------------------------
|
||||
// heads up font
|
||||
|
|
@ -75,6 +78,7 @@
|
|||
// Note: I'd like to adress that at this point we might *REALLY* want to work towards a common drawString function that can take any font we want because this is really turning into a MESS. :V -Lat'
|
||||
patch_t *pinggfx[5]; // small ping graphic
|
||||
patch_t *mping[5]; // smaller ping graphic
|
||||
patch_t *pingmeasure[2]; // ping measurement graphic
|
||||
|
||||
patch_t *framecounter;
|
||||
patch_t *frameslash; // framerate stuff. Used in screen.c
|
||||
|
|
@ -168,6 +172,7 @@ static void Command_Say_f(void);
|
|||
static void Command_Sayto_f(void);
|
||||
static void Command_Sayteam_f(void);
|
||||
static void Command_CSay_f(void);
|
||||
static void Command_Shout(void);
|
||||
static void Got_Saycmd(UINT8 **p, INT32 playernum);
|
||||
#endif
|
||||
|
||||
|
|
@ -189,6 +194,9 @@ void HU_LoadGraphics(void)
|
|||
HU_UpdatePatch(&mping[i], "MPING%d", i+1);
|
||||
}
|
||||
|
||||
HU_UpdatePatch(&pingmeasure[0], "PINGD");
|
||||
HU_UpdatePatch(&pingmeasure[1], "PINGMS");
|
||||
|
||||
// fps stuff
|
||||
HU_UpdatePatch(&framecounter, "FRAMER");
|
||||
HU_UpdatePatch(&frameslash, "FRAMESL");
|
||||
|
|
@ -206,6 +214,7 @@ void HU_Init(void)
|
|||
COM_AddCommand("sayto", Command_Sayto_f);
|
||||
COM_AddCommand("sayteam", Command_Sayteam_f);
|
||||
COM_AddCommand("csay", Command_CSay_f);
|
||||
COM_AddCommand("shout", Command_Shout);
|
||||
RegisterNetXCmd(XD_SAY, Got_Saycmd);
|
||||
#endif
|
||||
|
||||
|
|
@ -470,7 +479,7 @@ void HU_AddChatText(const char *text, boolean playsound)
|
|||
* to -32 to say to everyone on that player's team. Note: This means you
|
||||
* have to add 1 to the player number, since they are 0 to 31 internally.
|
||||
*
|
||||
* The flag HU_SERVER_SAY will be set if it is the dedicated server speaking.
|
||||
* The flag HU_SHOUT will be set if it is the dedicated server speaking.
|
||||
*
|
||||
* This function obtains the message using COM_Argc() and COM_Argv().
|
||||
*
|
||||
|
|
@ -497,14 +506,17 @@ static void DoSayCommand(SINT8 target, size_t usedargs, UINT8 flags)
|
|||
return;
|
||||
}
|
||||
|
||||
// Only servers/admins can CSAY.
|
||||
if(!server && !(IsPlayerAdmin(consoleplayer)))
|
||||
flags &= ~HU_CSAY;
|
||||
// Only servers/admins can shout or CSAY.
|
||||
if (!server && !IsPlayerAdmin(consoleplayer))
|
||||
{
|
||||
flags &= ~(HU_SHOUT|HU_CSAY);
|
||||
}
|
||||
|
||||
// We handle HU_SERVER_SAY, not the caller.
|
||||
flags &= ~HU_SERVER_SAY;
|
||||
if(dedicated && !(flags & HU_CSAY))
|
||||
flags |= HU_SERVER_SAY;
|
||||
// Enforce shout for the dedicated server.
|
||||
if (dedicated && !(flags & HU_CSAY))
|
||||
{
|
||||
flags |= HU_SHOUT;
|
||||
}
|
||||
|
||||
buf[0] = target;
|
||||
buf[1] = flags;
|
||||
|
|
@ -578,6 +590,8 @@ static void Command_Say_f(void)
|
|||
return;
|
||||
}
|
||||
|
||||
// Autoshout is handled by HU_queueChatChar.
|
||||
// If you're using the say command, you can use the shout command, lol.
|
||||
DoSayCommand(0, 1, 0);
|
||||
}
|
||||
|
||||
|
|
@ -641,7 +655,7 @@ static void Command_CSay_f(void)
|
|||
return;
|
||||
}
|
||||
|
||||
if(!server && !IsPlayerAdmin(consoleplayer))
|
||||
if (!server && !IsPlayerAdmin(consoleplayer))
|
||||
{
|
||||
CONS_Alert(CONS_NOTICE, M_GetText("Only servers and admins can use csay.\n"));
|
||||
return;
|
||||
|
|
@ -649,6 +663,24 @@ static void Command_CSay_f(void)
|
|||
|
||||
DoSayCommand(0, 1, HU_CSAY);
|
||||
}
|
||||
|
||||
static void Command_Shout(void)
|
||||
{
|
||||
if (COM_Argc() < 2)
|
||||
{
|
||||
CONS_Printf(M_GetText("shout <message>: send a message with special alert sound, name, and color\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!server && !IsPlayerAdmin(consoleplayer))
|
||||
{
|
||||
CONS_Alert(CONS_NOTICE, M_GetText("Only servers and admins can use shout.\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
DoSayCommand(0, 1, HU_SHOUT);
|
||||
}
|
||||
|
||||
static tic_t stop_spamming[MAXPLAYERS];
|
||||
|
||||
/** Receives a message, processing an ::XD_SAY command.
|
||||
|
|
@ -672,7 +704,7 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
|
|||
msg = (char *)*p;
|
||||
SKIPSTRING(*p);
|
||||
|
||||
if ((cv_mute.value || flags & (HU_CSAY|HU_SERVER_SAY)) && playernum != serverplayer && !(IsPlayerAdmin(playernum)))
|
||||
if ((cv_mute.value || flags & (HU_CSAY|HU_SHOUT)) && playernum != serverplayer && !(IsPlayerAdmin(playernum)))
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, cv_mute.value ?
|
||||
M_GetText("Illegal say command received from %s while muted\n") : M_GetText("Illegal csay command received from non-admin %s\n"),
|
||||
|
|
@ -701,7 +733,7 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
|
|||
// before we do anything, let's verify the guy isn't spamming, get this easier on us.
|
||||
|
||||
//if (stop_spamming[playernum] != 0 && cv_chatspamprotection.value && !(flags & HU_CSAY))
|
||||
if (stop_spamming[playernum] != 0 && consoleplayer != playernum && cv_chatspamprotection.value && !(flags & HU_CSAY))
|
||||
if (stop_spamming[playernum] != 0 && consoleplayer != playernum && cv_chatspamprotection.value && !(flags & (HU_CSAY|HU_SHOUT)))
|
||||
{
|
||||
CONS_Debug(DBG_NETPLAY,"Received SAY cmd too quickly from Player %d (%s), assuming as spam and blocking message.\n", playernum+1, player_names[playernum]);
|
||||
stop_spamming[playernum] = 4;
|
||||
|
|
@ -734,8 +766,8 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
|
|||
action = true;
|
||||
}
|
||||
|
||||
if (flags & HU_SERVER_SAY)
|
||||
dispname = "SERVER";
|
||||
if (flags & HU_SHOUT)
|
||||
dispname = cv_shoutname.zstring;
|
||||
else
|
||||
dispname = player_names[playernum];
|
||||
|
||||
|
|
@ -761,7 +793,30 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
|
|||
char *tempchar = NULL;
|
||||
char color_prefix[2];
|
||||
|
||||
if (players[playernum].spectator)
|
||||
if (flags & HU_SHOUT)
|
||||
{
|
||||
if (cv_shoutcolor.value == -1)
|
||||
{
|
||||
UINT16 chatcolor = skincolors[players[playernum].skincolor].chatcolor;
|
||||
|
||||
if (chatcolor > V_TANMAP)
|
||||
{
|
||||
sprintf(color_prefix, "%c", '\x80');
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(color_prefix, "%c", '\x80' + (chatcolor >> V_CHARCOLORSHIFT));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(color_prefix, "%c", '\x80' + cv_shoutcolor.value);
|
||||
}
|
||||
|
||||
// Colorize full text
|
||||
cstart = textcolor = color_prefix;
|
||||
}
|
||||
else if (players[playernum].spectator)
|
||||
{
|
||||
// grey text
|
||||
cstart = textcolor = "\x86";
|
||||
|
|
@ -848,7 +903,10 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
|
|||
fmt2 = "%s<%s%s>\x80%s %s%s";
|
||||
}*/
|
||||
|
||||
HU_AddChatText(va(fmt2, prefix, cstart, dispname, cend, textcolor, msg), cv_chatnotifications.value); // add to chat
|
||||
HU_AddChatText(va(fmt2, prefix, cstart, dispname, cend, textcolor, msg), (cv_chatnotifications.value) && !(flags & HU_SHOUT)); // add to chat
|
||||
|
||||
if ((cv_chatnotifications.value) && (flags & HU_SHOUT))
|
||||
S_StartSound(NULL, sfx_sysmsg);
|
||||
|
||||
if (tempchar)
|
||||
Z_Free(tempchar);
|
||||
|
|
@ -1172,7 +1230,7 @@ static void HU_queueChatChar(INT32 c)
|
|||
else
|
||||
buf[0] = target;
|
||||
|
||||
buf[1] = 0; // flags
|
||||
buf[1] = ((server || IsPlayerAdmin(consoleplayer)) && cv_autoshout.value) ? HU_SHOUT : 0; // flags
|
||||
SendNetXCmd(XD_SAY, buf, 2 + strlen(&buf[2]) + 1);
|
||||
}
|
||||
return;
|
||||
|
|
@ -2274,15 +2332,15 @@ void HU_Erase(void)
|
|||
//======================================================================
|
||||
|
||||
static int
|
||||
Ping_gfx_num (int ping)
|
||||
Ping_gfx_num (int lag)
|
||||
{
|
||||
if (ping < 76)
|
||||
if (lag < 2)
|
||||
return 0;
|
||||
else if (ping < 137)
|
||||
else if (lag < 4)
|
||||
return 1;
|
||||
else if (ping < 256)
|
||||
else if (lag < 7)
|
||||
return 2;
|
||||
else if (ping < 500)
|
||||
else if (lag < 10)
|
||||
return 3;
|
||||
else
|
||||
return 4;
|
||||
|
|
@ -2291,22 +2349,37 @@ Ping_gfx_num (int ping)
|
|||
//
|
||||
// HU_drawPing
|
||||
//
|
||||
void HU_drawPing(INT32 x, INT32 y, UINT32 ping, INT32 flags)
|
||||
void HU_drawPing(INT32 x, INT32 y, UINT32 lag, INT32 flags)
|
||||
{
|
||||
INT32 gfxnum; // gfx to draw
|
||||
UINT8 const *colormap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_RASPBERRY, GTC_CACHE);
|
||||
UINT8 *colormap = NULL;
|
||||
INT32 measureid = cv_pingmeasurement.value ? 1 : 0;
|
||||
INT32 gfxnum; // gfx to draw
|
||||
|
||||
gfxnum = Ping_gfx_num(ping);
|
||||
gfxnum = Ping_gfx_num(lag);
|
||||
|
||||
V_DrawScaledPatch(x, y, flags, pinggfx[gfxnum]);
|
||||
if (servermaxping && ping > servermaxping && hu_tick < 4) // flash ping red if too high
|
||||
V_DrawPingNum(x, y+9, flags, ping, colormap);
|
||||
else
|
||||
V_DrawPingNum(x, y+9, flags, ping, NULL);
|
||||
if (measureid == 1)
|
||||
V_DrawScaledPatch(x+11 - pingmeasure[measureid]->width, y+9, flags, pingmeasure[measureid]);
|
||||
V_DrawScaledPatch(x+2, y, flags, pinggfx[gfxnum]);
|
||||
|
||||
if (servermaxping && lag > servermaxping && hu_tick < 4)
|
||||
{
|
||||
// flash ping red if too high
|
||||
colormap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_RASPBERRY, GTC_CACHE);
|
||||
}
|
||||
|
||||
if (cv_pingmeasurement.value)
|
||||
{
|
||||
lag = (INT32)(lag * (1000.00f / TICRATE));
|
||||
}
|
||||
|
||||
x = V_DrawPingNum(x + (measureid == 1 ? 11 - pingmeasure[measureid]->width : 10), y+9, flags, lag, colormap);
|
||||
|
||||
if (measureid == 0)
|
||||
V_DrawScaledPatch(x+1 - pingmeasure[measureid]->width, y+9, flags, pingmeasure[measureid]);
|
||||
}
|
||||
|
||||
void
|
||||
HU_drawMiniPing (INT32 x, INT32 y, UINT32 ping, INT32 flags)
|
||||
HU_drawMiniPing (INT32 x, INT32 y, UINT32 lag, INT32 flags)
|
||||
{
|
||||
patch_t *patch;
|
||||
INT32 w = BASEVIDWIDTH;
|
||||
|
|
@ -2316,7 +2389,7 @@ HU_drawMiniPing (INT32 x, INT32 y, UINT32 ping, INT32 flags)
|
|||
w /= 2;
|
||||
}
|
||||
|
||||
patch = mping[Ping_gfx_num(ping)];
|
||||
patch = mping[Ping_gfx_num(lag)];
|
||||
|
||||
if (( flags & V_SNAPTORIGHT ))
|
||||
x += ( w - SHORT (patch->width) );
|
||||
|
|
|
|||
16
src/i_net.h
16
src/i_net.h
|
|
@ -31,6 +31,8 @@
|
|||
/// For use on the internet
|
||||
#define INETPACKETLENGTH 1024
|
||||
|
||||
#define NO_BAN_TIME (time_t)(-1)
|
||||
|
||||
extern INT16 hardware_MAXPACKETLENGTH;
|
||||
extern INT32 net_bandwidth; // in byte/s
|
||||
|
||||
|
|
@ -162,8 +164,20 @@ extern void (*I_ClearBans)(void);
|
|||
extern const char *(*I_GetNodeAddress) (INT32 node);
|
||||
extern const char *(*I_GetBanAddress) (size_t ban);
|
||||
extern const char *(*I_GetBanMask) (size_t ban);
|
||||
extern const char *(*I_GetBanUsername) (size_t ban);
|
||||
extern const char *(*I_GetBanReason) (size_t ban);
|
||||
extern time_t (*I_GetUnbanTime) (size_t ban);
|
||||
extern boolean (*I_SetBanAddress) (const char *address,const char *mask);
|
||||
extern boolean *bannednode;
|
||||
extern boolean (*I_SetBanUsername) (const char *username);
|
||||
extern boolean (*I_SetBanReason) (const char *reason);
|
||||
extern boolean (*I_SetUnbanTime) (time_t timestamp);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
size_t banid;
|
||||
time_t timeleft;
|
||||
} bannednode_t;
|
||||
extern bannednode_t *bannednode;
|
||||
|
||||
/// \brief Called by D_SRB2Main to be defined by extern network driver
|
||||
boolean I_InitNetwork(void);
|
||||
|
|
|
|||
259
src/i_tcp.c
259
src/i_tcp.c
|
|
@ -138,8 +138,6 @@
|
|||
|
||||
#endif // !NONET
|
||||
|
||||
#define MAXBANS 100
|
||||
|
||||
#include "i_system.h"
|
||||
#include "i_time.h"
|
||||
#include "i_net.h"
|
||||
|
|
@ -148,6 +146,7 @@
|
|||
#include "i_tcp.h"
|
||||
#include "m_argv.h"
|
||||
#include "stun.h"
|
||||
#include "z_zone.h"
|
||||
|
||||
#include "doomstat.h"
|
||||
|
||||
|
|
@ -189,6 +188,16 @@
|
|||
#if (defined (WATTCP) && !defined (__libsocket_socklen_t)) || defined (USE_WINSOCK1)
|
||||
typedef int socklen_t;
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
mysockaddr_t address;
|
||||
UINT8 mask;
|
||||
char *username;
|
||||
char *reason;
|
||||
time_t timestamp;
|
||||
} banned_t;
|
||||
|
||||
static SOCKET_TYPE mysockets[MAXNETNODES+1] = {ERRSOCKET};
|
||||
static size_t mysocketses = 0;
|
||||
static int myfamily[MAXNETNODES+1] = {0};
|
||||
|
|
@ -197,13 +206,14 @@
|
|||
static mysockaddr_t broadcastaddress[MAXNETNODES+1];
|
||||
static size_t broadcastaddresses = 0;
|
||||
static boolean nodeconnected[MAXNETNODES+1];
|
||||
static mysockaddr_t banned[MAXBANS];
|
||||
static UINT8 bannedmask[MAXBANS];
|
||||
static banned_t *banned;
|
||||
static const INT32 hole_punch_magic = MSBF_LONG (0x52eb11);
|
||||
#endif
|
||||
|
||||
static size_t numbans = 0;
|
||||
static boolean SOCK_bannednode[MAXNETNODES+1]; /// \note do we really need the +1?
|
||||
static size_t banned_size = 0;
|
||||
|
||||
static bannednode_t SOCK_bannednode[MAXNETNODES+1]; /// \note do we really need the +1?
|
||||
static boolean init_tcp_driver = false;
|
||||
|
||||
static const char *serverport_name = DEFAULTPORT;
|
||||
|
|
@ -431,7 +441,7 @@ static const char *SOCK_GetBanAddress(size_t ban)
|
|||
#ifdef NONET
|
||||
return NULL;
|
||||
#else
|
||||
return SOCK_AddrToStr(&banned[ban]);
|
||||
return SOCK_AddrToStr(&banned[ban].address);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -443,12 +453,48 @@ static const char *SOCK_GetBanMask(size_t ban)
|
|||
static char s[16]; //255.255.255.255 netmask? no, just CDIR for only
|
||||
if (ban >= numbans)
|
||||
return NULL;
|
||||
if (sprintf(s,"%d",bannedmask[ban]) > 0)
|
||||
if (sprintf(s,"%d",banned[ban].mask) > 0)
|
||||
return s;
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *SOCK_GetBanUsername(size_t ban)
|
||||
{
|
||||
#ifdef NONET
|
||||
(void)ban;
|
||||
return NULL;
|
||||
#else
|
||||
if (ban >= numbans)
|
||||
return NULL;
|
||||
return banned[ban].username;
|
||||
#endif
|
||||
}
|
||||
|
||||
static const char *SOCK_GetBanReason(size_t ban)
|
||||
{
|
||||
#ifdef NONET
|
||||
(void)ban;
|
||||
return NULL;
|
||||
#else
|
||||
if (ban >= numbans)
|
||||
return NULL;
|
||||
return banned[ban].reason;
|
||||
#endif
|
||||
}
|
||||
|
||||
static time_t SOCK_GetUnbanTime(size_t ban)
|
||||
{
|
||||
#ifdef NONET
|
||||
(void)ban;
|
||||
return NO_BAN_TIME;
|
||||
#else
|
||||
if (ban >= numbans)
|
||||
return NO_BAN_TIME;
|
||||
return banned[ban].timestamp;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef NONET
|
||||
static boolean SOCK_cmpaddr(mysockaddr_t *a, mysockaddr_t *b, UINT8 mask)
|
||||
{
|
||||
|
|
@ -622,6 +668,8 @@ static boolean SOCK_Get(void)
|
|||
j = getfreenode();
|
||||
if (j > 0)
|
||||
{
|
||||
const time_t curTime = time(NULL);
|
||||
|
||||
M_Memcpy(&clientaddress[j], &fromaddress, fromlen);
|
||||
nodesocket[j] = mysockets[n];
|
||||
DEBFILE(va("New node detected: node:%d address:%s\n", j,
|
||||
|
|
@ -632,15 +680,39 @@ static boolean SOCK_Get(void)
|
|||
// check if it's a banned dude so we can send a refusal later
|
||||
for (i = 0; i < numbans; i++)
|
||||
{
|
||||
if (SOCK_cmpaddr(&fromaddress, &banned[i], bannedmask[i]))
|
||||
if (SOCK_cmpaddr(&fromaddress, &banned[i].address, banned[i].mask))
|
||||
{
|
||||
SOCK_bannednode[j] = true;
|
||||
DEBFILE("This dude has been banned\n");
|
||||
break;
|
||||
if (banned[i].timestamp != NO_BAN_TIME)
|
||||
{
|
||||
if (curTime >= banned[i].timestamp)
|
||||
{
|
||||
SOCK_bannednode[j].timeleft = NO_BAN_TIME;
|
||||
SOCK_bannednode[j].banid = SIZE_MAX;
|
||||
DEBFILE("This dude was banned, but enough time has passed\n");
|
||||
break;
|
||||
}
|
||||
|
||||
SOCK_bannednode[j].timeleft = banned[i].timestamp - curTime;
|
||||
SOCK_bannednode[j].banid = i;
|
||||
DEBFILE("This dude has been temporarily banned\n");
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
SOCK_bannednode[j].timeleft = NO_BAN_TIME;
|
||||
SOCK_bannednode[j].banid = i;
|
||||
DEBFILE("This dude has been banned\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (i == numbans)
|
||||
SOCK_bannednode[j] = false;
|
||||
{
|
||||
SOCK_bannednode[j].timeleft = NO_BAN_TIME;
|
||||
SOCK_bannednode[j].banid = SIZE_MAX;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
|
|
@ -1435,30 +1507,116 @@ static boolean SOCK_OpenSocket(void)
|
|||
#endif
|
||||
}
|
||||
|
||||
static void AddBannedIndex(void)
|
||||
{
|
||||
if (numbans >= banned_size)
|
||||
{
|
||||
if (banned_size == 0)
|
||||
{
|
||||
banned_size = 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
banned_size *= 2;
|
||||
}
|
||||
|
||||
banned = Z_ReallocAlign(
|
||||
(void*) banned,
|
||||
sizeof(banned_t) * banned_size,
|
||||
PU_STATIC,
|
||||
NULL,
|
||||
sizeof(banned_t) * 8
|
||||
);
|
||||
}
|
||||
|
||||
numbans++;
|
||||
}
|
||||
|
||||
static boolean SOCK_Ban(INT32 node)
|
||||
{
|
||||
INT32 ban;
|
||||
|
||||
if (node > MAXNETNODES)
|
||||
return false;
|
||||
|
||||
#ifdef NONET
|
||||
(void)ban;
|
||||
return false;
|
||||
#else
|
||||
if (numbans == MAXBANS)
|
||||
return false;
|
||||
|
||||
M_Memcpy(&banned[numbans], &clientaddress[node], sizeof (mysockaddr_t));
|
||||
if (banned[numbans].any.sa_family == AF_INET)
|
||||
ban = numbans;
|
||||
AddBannedIndex();
|
||||
|
||||
M_Memcpy(&banned[ban].address, &clientaddress[node], sizeof (mysockaddr_t));
|
||||
|
||||
if (banned[ban].address.any.sa_family == AF_INET)
|
||||
{
|
||||
banned[numbans].ip4.sin_port = 0;
|
||||
bannedmask[numbans] = 32;
|
||||
banned[ban].address.ip4.sin_port = 0;
|
||||
banned[ban].mask = 32;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else if (banned[numbans].any.sa_family == AF_INET6)
|
||||
else if (banned[ban].address.any.sa_family == AF_INET6)
|
||||
{
|
||||
banned[numbans].ip6.sin6_port = 0;
|
||||
bannedmask[numbans] = 128;
|
||||
banned[ban].address.ip6.sin6_port = 0;
|
||||
banned[ban].mask = 128;
|
||||
}
|
||||
#endif
|
||||
numbans++;
|
||||
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
static boolean SOCK_SetBanUsername(const char *username)
|
||||
{
|
||||
#ifdef NONET
|
||||
(void)username;
|
||||
return false;
|
||||
#else
|
||||
if (username == NULL || strlen(username) == 0)
|
||||
{
|
||||
username = "Direct IP ban";
|
||||
}
|
||||
|
||||
if (banned[numbans - 1].username)
|
||||
{
|
||||
Z_Free(banned[numbans - 1].username);
|
||||
banned[numbans - 1].username = NULL;
|
||||
}
|
||||
|
||||
banned[numbans - 1].username = Z_StrDup(username);
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
static boolean SOCK_SetBanReason(const char *reason)
|
||||
{
|
||||
#ifdef NONET
|
||||
(void)reason;
|
||||
return false;
|
||||
#else
|
||||
if (reason == NULL || strlen(reason) == 0)
|
||||
{
|
||||
reason = "No reason given";
|
||||
}
|
||||
|
||||
if (banned[numbans - 1].reason)
|
||||
{
|
||||
Z_Free(banned[numbans - 1].reason);
|
||||
banned[numbans - 1].reason = NULL;
|
||||
}
|
||||
|
||||
banned[numbans - 1].reason = Z_StrDup(reason);
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
static boolean SOCK_SetUnbanTime(time_t timestamp)
|
||||
{
|
||||
#ifdef NONET
|
||||
(void)reason;
|
||||
return false;
|
||||
#else
|
||||
banned[numbans - 1].timestamp = timestamp;
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
|
@ -1473,7 +1631,7 @@ static boolean SOCK_SetBanAddress(const char *address, const char *mask)
|
|||
struct my_addrinfo *ai, *runp, hints;
|
||||
int gaie;
|
||||
|
||||
if (numbans == MAXBANS || !address)
|
||||
if (!address)
|
||||
return false;
|
||||
|
||||
memset(&hints, 0x00, sizeof(hints));
|
||||
|
|
@ -1488,26 +1646,42 @@ static boolean SOCK_SetBanAddress(const char *address, const char *mask)
|
|||
|
||||
runp = ai;
|
||||
|
||||
while(runp != NULL && numbans != MAXBANS)
|
||||
while (runp != NULL)
|
||||
{
|
||||
memcpy(&banned[numbans], runp->ai_addr, runp->ai_addrlen);
|
||||
INT32 ban;
|
||||
UINT8 numericalmask;
|
||||
|
||||
ban = numbans;
|
||||
AddBannedIndex();
|
||||
|
||||
memcpy(&banned[ban].address, runp->ai_addr, runp->ai_addrlen);
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (runp->ai_family == AF_INET6)
|
||||
banned[ban].mask = 128;
|
||||
else
|
||||
#endif
|
||||
banned[ban].mask = 32;
|
||||
|
||||
if (mask)
|
||||
bannedmask[numbans] = (UINT8)atoi(mask);
|
||||
#ifdef HAVE_IPV6
|
||||
else if (runp->ai_family == AF_INET6)
|
||||
bannedmask[numbans] = 128;
|
||||
#endif
|
||||
{
|
||||
numericalmask = (UINT8)atoi(mask);
|
||||
}
|
||||
else
|
||||
bannedmask[numbans] = 32;
|
||||
{
|
||||
numericalmask = 0;
|
||||
}
|
||||
|
||||
if (numericalmask > 0 && numericalmask < banned[ban].mask)
|
||||
{
|
||||
banned[ban].mask = numericalmask;
|
||||
}
|
||||
|
||||
// Set defaults, in case anything funny happens.
|
||||
SOCK_SetBanUsername(NULL);
|
||||
SOCK_SetBanReason(NULL);
|
||||
SOCK_SetUnbanTime(NO_BAN_TIME);
|
||||
|
||||
if (bannedmask[numbans] > 32 && runp->ai_family == AF_INET)
|
||||
bannedmask[numbans] = 32;
|
||||
#ifdef HAVE_IPV6
|
||||
else if (bannedmask[numbans] > 128 && runp->ai_family == AF_INET6)
|
||||
bannedmask[numbans] = 128;
|
||||
#endif
|
||||
numbans++;
|
||||
runp = runp->ai_next;
|
||||
}
|
||||
|
||||
|
|
@ -1520,6 +1694,9 @@ static boolean SOCK_SetBanAddress(const char *address, const char *mask)
|
|||
static void SOCK_ClearBans(void)
|
||||
{
|
||||
numbans = 0;
|
||||
banned_size = 0;
|
||||
Z_Free(banned);
|
||||
banned = NULL;
|
||||
}
|
||||
|
||||
boolean I_InitTcpNetwork(void)
|
||||
|
|
@ -1614,7 +1791,13 @@ boolean I_InitTcpNetwork(void)
|
|||
I_GetNodeAddress = SOCK_GetNodeAddress;
|
||||
I_GetBanAddress = SOCK_GetBanAddress;
|
||||
I_GetBanMask = SOCK_GetBanMask;
|
||||
I_GetBanUsername = SOCK_GetBanUsername;
|
||||
I_GetBanReason = SOCK_GetBanReason;
|
||||
I_GetUnbanTime = SOCK_GetUnbanTime;
|
||||
I_SetBanAddress = SOCK_SetBanAddress;
|
||||
I_SetBanUsername = SOCK_SetBanUsername;
|
||||
I_SetBanReason = SOCK_SetBanReason;
|
||||
I_SetUnbanTime = SOCK_SetUnbanTime;
|
||||
bannednode = SOCK_bannednode;
|
||||
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -57,16 +57,8 @@ SINT8 K_UsingPowerLevels(void)
|
|||
|
||||
void K_ClearClientPowerLevels(void)
|
||||
{
|
||||
UINT8 i, j;
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
clientPowerAdd[i] = 0;
|
||||
|
||||
for (j = 0; j < PWRLV_NUMTYPES; j++)
|
||||
{
|
||||
clientpowerlevels[i][j] = 0;
|
||||
}
|
||||
}
|
||||
memset(clientpowerlevels, 0, sizeof clientpowerlevels);
|
||||
memset(clientPowerAdd, 0, sizeof clientPowerAdd);
|
||||
}
|
||||
|
||||
// Adapted from this: http://wiki.tockdom.com/wiki/Player_Rating
|
||||
|
|
|
|||
|
|
@ -4423,7 +4423,7 @@ static inline void P_UnArchiveSPGame(INT16 mapoverride)
|
|||
|
||||
static void P_NetArchiveMisc(boolean resending)
|
||||
{
|
||||
INT32 i;
|
||||
size_t i;
|
||||
|
||||
WRITEUINT32(save_p, ARCHIVEBLOCK_MISC);
|
||||
|
||||
|
|
@ -4552,11 +4552,23 @@ static void P_NetArchiveMisc(boolean resending)
|
|||
WRITEUINT8(save_p, 0x2f);
|
||||
else
|
||||
WRITEUINT8(save_p, 0x2e);
|
||||
|
||||
// Only the server uses this, but it
|
||||
// needs synched for remote admins anyway.
|
||||
WRITEUINT32(save_p, schedule_len);
|
||||
for (i = 0; i < schedule_len; i++)
|
||||
{
|
||||
scheduleTask_t *task = schedule[i];
|
||||
WRITEINT16(save_p, task->basetime);
|
||||
WRITEINT16(save_p, task->timer);
|
||||
WRITESTRING(save_p, task->command);
|
||||
}
|
||||
}
|
||||
|
||||
static inline boolean P_NetUnArchiveMisc(boolean reloading)
|
||||
{
|
||||
INT32 i;
|
||||
size_t i;
|
||||
size_t numTasks;
|
||||
|
||||
if (READUINT32(save_p) != ARCHIVEBLOCK_MISC)
|
||||
I_Error("Bad $$$.sav at archive block Misc");
|
||||
|
|
@ -4700,6 +4712,24 @@ static inline boolean P_NetUnArchiveMisc(boolean reloading)
|
|||
if (READUINT8(save_p) == 0x2f)
|
||||
paused = true;
|
||||
|
||||
// Only the server uses this, but it
|
||||
// needs synched for remote admins anyway.
|
||||
Schedule_Clear();
|
||||
|
||||
numTasks = READUINT32(save_p);
|
||||
for (i = 0; i < numTasks; i++)
|
||||
{
|
||||
INT16 basetime;
|
||||
INT16 timer;
|
||||
char command[MAXTEXTCMD];
|
||||
|
||||
basetime = READINT16(save_p);
|
||||
timer = READINT16(save_p);
|
||||
READSTRING(save_p, command);
|
||||
|
||||
Schedule_Add(basetime, timer, command);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#include "m_cond.h" // for conditionsets
|
||||
#include "lua_hook.h" // MusicChange hook
|
||||
#include "k_boss.h" // bossinfo
|
||||
#include "byteptr.h"
|
||||
|
||||
#ifdef HW3SOUND
|
||||
// 3D Sound Interface
|
||||
|
|
@ -43,6 +44,8 @@ CV_PossibleValue_t soundvolume_cons_t[] = {{0, "MIN"}, {MAX_VOLUME, "MAX"}, {0,
|
|||
static void SetChannelsNum(void);
|
||||
static void Command_Tunes_f(void);
|
||||
static void Command_RestartAudio_f(void);
|
||||
static void Command_PlaySound(void);
|
||||
static void Got_PlaySound(UINT8 **p, INT32 playernum);
|
||||
|
||||
// Sound system toggles
|
||||
static void GameSounds_OnChange(void);
|
||||
|
|
@ -268,6 +271,8 @@ void S_RegisterSoundStuff(void)
|
|||
|
||||
COM_AddCommand("tunes", Command_Tunes_f);
|
||||
COM_AddCommand("restartaudio", Command_RestartAudio_f);
|
||||
COM_AddCommand("playsound", Command_PlaySound);
|
||||
RegisterNetXCmd(XD_PLAYSOUND, Got_PlaySound);
|
||||
}
|
||||
|
||||
static void SetChannelsNum(void)
|
||||
|
|
@ -2478,6 +2483,71 @@ static void Command_RestartAudio_f(void)
|
|||
S_ChangeMusicInternal("titles", looptitle);
|
||||
}
|
||||
|
||||
static void Command_PlaySound(void)
|
||||
{
|
||||
const char *sound;
|
||||
const size_t argc = COM_Argc();
|
||||
sfxenum_t sfx = NUMSFX;
|
||||
UINT8 buf[4];
|
||||
UINT8 *buf_p = buf;
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
CONS_Printf("playsound <name/num>: Plays a sound effect for the entire server.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (client && !IsPlayerAdmin(consoleplayer))
|
||||
{
|
||||
CONS_Printf("This can only be used by the server host.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
sound = COM_Argv(1);
|
||||
if (*sound >= '0' && *sound <= '9')
|
||||
{
|
||||
sfx = atoi(sound);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (sfx = 0; sfx < sfxfree; sfx++)
|
||||
{
|
||||
if (S_sfx[sfx].name && fasticmp(sound, S_sfx[sfx].name))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (sfx < 0 || sfx >= NUMSFX)
|
||||
{
|
||||
CONS_Printf("Could not find sound effect named \"sfx_%s\".\n", sound);
|
||||
return;
|
||||
}
|
||||
|
||||
WRITEINT32(buf_p, sfx);
|
||||
SendNetXCmd(XD_PLAYSOUND, buf, buf_p - buf);
|
||||
}
|
||||
|
||||
static void Got_PlaySound(UINT8 **cp, INT32 playernum)
|
||||
{
|
||||
INT32 sound_id = READINT32(*cp);
|
||||
|
||||
if (playernum != serverplayer && !IsPlayerAdmin(playernum)) // hacked client, or disasterous bug
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, M_GetText("Illegal playsound received from %s (serverplayer is %s)\n"), player_names[playernum], player_names[serverplayer]);
|
||||
if (server)
|
||||
SendKick(playernum, KICK_MSG_CON_FAIL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sound_id < 0 || sound_id >= NUMSFX)
|
||||
{
|
||||
// bad sound effect, ignore
|
||||
return;
|
||||
}
|
||||
|
||||
S_StartSound(NULL, sound_id);
|
||||
}
|
||||
|
||||
void GameSounds_OnChange(void)
|
||||
{
|
||||
if (M_CheckParm("-nosound") || M_CheckParm("-noaudio"))
|
||||
|
|
|
|||
|
|
@ -1114,6 +1114,9 @@ sfxinfo_t S_sfx[NUMSFX] =
|
|||
|
||||
{"ffbonc", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||
|
||||
// Shout message sound effect
|
||||
{"sysmsg", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Server notification"},
|
||||
|
||||
// SRB2Kart - Engine sounds
|
||||
// Engine class A
|
||||
{"krta00", false, 48, 65, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||
|
|
|
|||
|
|
@ -1179,6 +1179,9 @@ typedef enum
|
|||
// Fast fall bounce
|
||||
sfx_ffbonc,
|
||||
|
||||
// Shout message sound effect
|
||||
sfx_sysmsg,
|
||||
|
||||
// Next up: UNIQUE ENGINE SOUNDS! Hoooooo boy...
|
||||
// Engine class A - Low Speed, Low Weight
|
||||
sfx_krta00,
|
||||
|
|
|
|||
|
|
@ -2560,6 +2560,30 @@ void V_DrawRightAlignedThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, con
|
|||
V_DrawThinStringAtFixed(x, y, option, string);
|
||||
}
|
||||
|
||||
// Draws a number using the PING font thingy.
|
||||
// TODO: Merge number drawing functions into one with "font name" selection.
|
||||
|
||||
INT32 V_DrawPingNum(INT32 x, INT32 y, INT32 flags, INT32 num, const UINT8 *colormap)
|
||||
{
|
||||
INT32 w = SHORT(fontv[PINGNUM_FONT].font[0]->width); // this SHOULD always be 5 but I guess custom graphics exist.
|
||||
|
||||
if (flags & V_NOSCALESTART)
|
||||
w *= vid.dupx;
|
||||
|
||||
if (num < 0)
|
||||
num = -num;
|
||||
|
||||
// draw the number
|
||||
do
|
||||
{
|
||||
x -= (w-1); // Oni wanted their outline to intersect.
|
||||
V_DrawFixedPatch(x<<FRACBITS, y<<FRACBITS, FRACUNIT, flags, fontv[PINGNUM_FONT].font[num%10], colormap);
|
||||
num /= 10;
|
||||
} while (num);
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
void V_DrawCenteredKartString(INT32 x, INT32 y, INT32 option, const char *string)
|
||||
{
|
||||
x -= V_KartStringWidth(string, option)/2;
|
||||
|
|
@ -2683,28 +2707,6 @@ void V_DrawProfileNum(INT32 x, INT32 y, INT32 flags, UINT8 num)
|
|||
} while (--digits);
|
||||
}
|
||||
|
||||
// Draws a number using the PING font thingy.
|
||||
// TODO: Merge number drawing functions into one with "font name" selection.
|
||||
|
||||
void V_DrawPingNum(INT32 x, INT32 y, INT32 flags, INT32 num, const UINT8 *colormap)
|
||||
{
|
||||
INT32 w = SHORT(fontv[PINGNUM_FONT].font[0]->width); // this SHOULD always be 5 but I guess custom graphics exist.
|
||||
|
||||
if (flags & V_NOSCALESTART)
|
||||
w *= vid.dupx;
|
||||
|
||||
if (num < 0)
|
||||
num = -num;
|
||||
|
||||
// draw the number
|
||||
do
|
||||
{
|
||||
x -= (w-1); // Oni wanted their outline to intersect.
|
||||
V_DrawFixedPatch(x<<FRACBITS, y<<FRACBITS, FRACUNIT, flags, fontv[PINGNUM_FONT].font[num%10], colormap);
|
||||
num /= 10;
|
||||
} while (num);
|
||||
}
|
||||
|
||||
// Find max height of the string
|
||||
//
|
||||
INT32 V_LevelNameHeight(const char *string)
|
||||
|
|
|
|||
|
|
@ -314,7 +314,7 @@ void V_DrawPaddedTallNum(INT32 x, INT32 y, INT32 flags, INT32 num, INT32 digits)
|
|||
|
||||
// Draw ping numbers. Used by the scoreboard and that one ping option. :P
|
||||
// This is a separate function because IMO lua should have access to it as well.
|
||||
void V_DrawPingNum(INT32 x, INT32 y, INT32 flags, INT32 num, const UINT8 *colormap);
|
||||
INT32 V_DrawPingNum(INT32 x, INT32 y, INT32 flags, INT32 num, const UINT8 *colormap);
|
||||
|
||||
void V_DrawProfileNum(INT32 x, INT32 y, INT32 flags, UINT8 num);
|
||||
|
||||
|
|
|
|||
|
|
@ -884,6 +884,7 @@ void Y_StartIntermission(void)
|
|||
K_CashInPowerLevels();
|
||||
}
|
||||
|
||||
Automate_Run(AEV_INTERMISSIONSTART);
|
||||
bgpatch = W_CachePatchName("MENUBG", PU_STATIC);
|
||||
widebgpatch = W_CachePatchName("WEIRDRES", PU_STATIC);
|
||||
|
||||
|
|
@ -1543,6 +1544,7 @@ void Y_StartVote(void)
|
|||
}
|
||||
|
||||
voteclient.loaded = true;
|
||||
Automate_Run(AEV_VOTESTART);
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue