*/
#include "quakedef.h"
+#include "sv_demo.h"
+#include "image.h"
int current_skill;
cvar_t sv_cheats = {0, "sv_cheats", "0", "enables cheat commands in any game, and cheat impulses in dpmod"};
+cvar_t sv_adminnick = {CVAR_SAVE, "sv_adminnick", "", "nick name to use for admin messages instead of host name"};
+cvar_t sv_status_privacy = {CVAR_SAVE, "sv_status_privacy", "0", "do not show IP addresses in 'status' replies to clients"};
+cvar_t sv_status_show_qcstatus = {CVAR_SAVE, "sv_status_show_qcstatus", "0", "show the 'qcstatus' field in status replies, not the 'frags' field. Turn this on if your mod uses this field, and the 'frags' field on the other hand has no meaningful value."};
cvar_t rcon_password = {CVAR_PRIVATE, "rcon_password", "", "password to authenticate rcon commands"};
cvar_t rcon_address = {0, "rcon_address", "", "server address to send rcon commands to (when not connected to a server)"};
cvar_t team = {CVAR_USERINFO | CVAR_SAVE, "team", "none", "QW team (4 character limit, example: blue)"};
cvar_t skin = {CVAR_USERINFO | CVAR_SAVE, "skin", "", "QW player skin name (example: base)"};
cvar_t noaim = {CVAR_USERINFO | CVAR_SAVE, "noaim", "1", "QW option to disable vertical autoaim"};
+cvar_t r_fixtrans_auto = {0, "r_fixtrans_auto", "0", "automatically fixtrans textures (when set to 2, it also saves the fixed versions to a fixtrans directory)"};
qboolean allowcheats = false;
+extern qboolean host_shuttingdown;
+extern cvar_t developer_entityparsing;
+
/*
==================
Host_Quit_f
void Host_Quit_f (void)
{
- Sys_Quit ();
+ if(host_shuttingdown)
+ Con_Printf("shutting down already!\n");
+ else
+ Sys_Quit (0);
}
-
/*
==================
Host_Status_f
*/
void Host_Status_f (void)
{
+ char qcstatus[256];
client_t *client;
- int seconds, minutes, hours = 0, j, players;
+ int seconds = 0, minutes = 0, hours = 0, i, j, k, in, players, ping = 0, packetloss = 0;
void (*print) (const char *fmt, ...);
+ char ip[22];
+ int frags;
if (cmd_source == src_command)
{
if (!sv.active)
return;
+
+ if(cmd_source == src_command)
+ SV_VM_Begin();
+
+ in = 0;
+ if (Cmd_Argc() == 2)
+ {
+ if (strcmp(Cmd_Argv(1), "1") == 0)
+ in = 1;
+ else if (strcmp(Cmd_Argv(1), "2") == 0)
+ in = 2;
+ }
- for (players = 0, j = 0;j < svs.maxclients;j++)
- if (svs.clients[j].active)
+ for (players = 0, i = 0;i < svs.maxclients;i++)
+ if (svs.clients[i].active)
players++;
print ("host: %s\n", Cvar_VariableString ("hostname"));
print ("version: %s build %s\n", gamename, buildstring);
print ("protocol: %i (%s)\n", Protocol_NumberForEnum(sv.protocol), Protocol_NameForEnum(sv.protocol));
print ("map: %s\n", sv.name);
+ print ("timing: %s\n", Host_TimingReport());
print ("players: %i active (%i max)\n\n", players, svs.maxclients);
- for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
+
+ if (in == 1)
+ print ("^2IP %%pl ping time frags no name\n");
+ else if (in == 2)
+ print ("^5IP no name\n");
+
+ for (i = 0, k = 0, client = svs.clients;i < svs.maxclients;i++, client++)
{
if (!client->active)
continue;
- seconds = (int)(realtime - client->connecttime);
- minutes = seconds / 60;
- if (minutes)
+
+ ++k;
+
+ if (in == 0 || in == 1)
{
- seconds -= (minutes * 60);
- hours = minutes / 60;
- if (hours)
- minutes -= (hours * 60);
+ seconds = (int)(realtime - client->connecttime);
+ minutes = seconds / 60;
+ if (minutes)
+ {
+ seconds -= (minutes * 60);
+ hours = minutes / 60;
+ if (hours)
+ minutes -= (hours * 60);
+ }
+ else
+ hours = 0;
+
+ packetloss = 0;
+ if (client->netconnection)
+ for (j = 0;j < NETGRAPH_PACKETS;j++)
+ if (client->netconnection->incoming_unreliablesize[j] == NETGRAPH_LOSTPACKET)
+ packetloss++;
+ packetloss = packetloss * 100 / NETGRAPH_PACKETS;
+ ping = bound(0, (int)floor(client->ping*1000+0.5), 9999);
}
+
+ if(sv_status_privacy.integer && cmd_source != src_command)
+ strlcpy(ip, client->netconnection ? "hidden" : "botclient" , 22);
else
- hours = 0;
- print ("#%-3u %-16.16s %3i %2i:%02i:%02i\n", j+1, client->name, (int)client->edict->fields.server->frags, hours, minutes, seconds);
- print (" %s\n", client->netconnection ? client->netconnection->address : "botclient");
+ strlcpy(ip, (client->netconnection && client->netconnection->address) ? client->netconnection->address : "botclient", 22);
+
+ frags = client->frags;
+
+ if(sv_status_show_qcstatus.integer && prog->fieldoffsets.clientstatus >= 0)
+ {
+ const char *str = PRVM_E_STRING(PRVM_EDICT_NUM(i + 1), prog->fieldoffsets.clientstatus);
+ if(str && *str)
+ {
+ char *p;
+ const char *q;
+ p = qcstatus;
+ for(q = str; *q && p != qcstatus + sizeof(qcstatus) - 1; ++q)
+ if(*q != '\\' && *q != '"' && !ISWHITESPACE(*q))
+ *p++ = *q;
+ *p = 0;
+ if(*qcstatus)
+ frags = atoi(qcstatus);
+ }
+ }
+
+ if (in == 0) // default layout
+ {
+ print ("#%-3u ", i+1);
+ print ("%-16.16s ", client->name);
+ print ("%4i ", frags);
+ print ("%2i:%02i:%02i\n ", hours, minutes, seconds);
+ print ("%s\n", ip);
+ }
+ else if (in == 1) // extended layout
+ {
+ k%2 ? print("^3") : print("^7");
+ print ("%-21s ", ip);
+ print ("%2i ", packetloss);
+ print ("%4i ", ping);
+ print ("%2i:%02i:%02i ", hours, minutes, seconds);
+ print ("%4i ", frags);
+ print ("#%-3u ", i+1);
+ print ("^7%s\n", client->name);
+ }
+ else if (in == 2) // reduced layout
+ {
+ k%2 ? print("^3") : print("^7");
+ print ("%-21s ", ip);
+ print ("#%-3u ", i+1);
+ print ("^7%s\n", client->name);
+ }
}
+
+ if(cmd_source == src_command)
+ SV_VM_End();
}
}
// now call the Pings command also, which will send a report that contains packet loss for the scoreboard (as well as a simpler ping report)
- Host_Pings_f();
+ // actually, don't, it confuses old clients (resulting in "unknown command pingplreport" flooding the console)
+ //Host_Pings_f();
}
/*
return;
}
+ // GAME_DELUXEQUAKE - clear warpmark (used by QC)
+ if (gamemode == GAME_DELUXEQUAKE)
+ Cvar_Set("warpmark", "");
+
cls.demonum = -1; // stop demo loop in case this fails
CL_Disconnect ();
SV_SpawnServer(level);
if (sv.active && cls.state == ca_disconnected)
CL_EstablishConnection("local:1");
-
-#ifdef AUTODEMO_BROKEN
-// if cl_autodemo is set, automatically start recording a demo if one isn't being recorded already
- if (cl_autodemo.integer && !cls.demorecording)
- {
- char demofile[MAX_OSPATH];
-
- dpsnprintf (demofile, sizeof(demofile), "%s_%s.dem", Sys_TimeString (cl_autodemo_nameformat.string), level);
-
- Con_Printf ("Recording to %s.\n", demofile);
-
- cls.demofile = FS_Open (demofile, "wb", false, false);
- if (cls.demofile)
- {
- cls.forcetrack = -1;
- FS_Printf (cls.demofile, "%i\n", cls.forcetrack);
- }
- else
- Con_Print ("ERROR: couldn't open.\n");
-
- cls.demorecording = true;
- }
-#endif
}
/*
*/
void Host_Reconnect_f (void)
{
+ char temp[128];
+ // if not connected, reconnect to the most recent server
+ if (!cls.netcon)
+ {
+ // if we have connected to a server recently, the userinfo
+ // will still contain its IP address, so get the address...
+ InfoString_GetValue(cls.userinfo, "*ip", temp, sizeof(temp));
+ if (temp[0])
+ CL_EstablishConnection(temp);
+ else
+ Con_Printf("Reconnect to what server? (you have not connected to a server yet)\n");
+ return;
+ }
+ // if connected, do something based on protocol
if (cls.protocol == PROTOCOL_QUAKEWORLD)
{
+ // quakeworld can just re-login
if (cls.qw_downloadmemory) // don't change when downloading
return;
S_StopAllSounds();
- if (cls.netcon)
+ if (cls.state == ca_connected && cls.signon < SIGNONS)
{
- if (cls.state == ca_connected && cls.signon < SIGNONS)
- {
- Con_Printf("reconnecting...\n");
- MSG_WriteChar(&cls.netcon->message, qw_clc_stringcmd);
- MSG_WriteString(&cls.netcon->message, "new");
- }
- else
- {
- char temp[128];
- // if we have connected to a server recently, the userinfo
- // will still contain its IP address, so get the address...
- InfoString_GetValue(cls.userinfo, "*ip", temp, sizeof(temp));
- if (temp[0])
- CL_EstablishConnection(temp);
- else
- Con_Printf("Reconnect to what server? (you have not connected to a server yet)\n");
- }
+ Con_Printf("reconnecting...\n");
+ MSG_WriteChar(&cls.netcon->message, qw_clc_stringcmd);
+ MSG_WriteString(&cls.netcon->message, "new");
}
}
else
{
+ // netquake uses reconnect on level changes (silly)
if (Cmd_Argc() != 1)
{
Con_Print("reconnect : wait for signon messages again\n");
#define SAVEGAME_VERSION 5
-/*
-===============
-Host_SavegameComment
-
-Writes a SAVEGAME_COMMENT_LENGTH character comment describing the current
-===============
-*/
-void Host_SavegameComment (char *text)
+void Host_Savegame_to (const char *name)
{
- int i;
- char kills[20];
+ qfile_t *f;
+ int i, lightstyles = 64;
+ char comment[SAVEGAME_COMMENT_LENGTH+1];
+ qboolean isserver;
- for (i=0 ; i<SAVEGAME_COMMENT_LENGTH ; i++)
- text[i] = ' ';
- // LordHavoc: added min() to prevent overflow
- memcpy (text, cl.levelname, min(strlen(cl.levelname), SAVEGAME_COMMENT_LENGTH));
- sprintf (kills,"kills:%3i/%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]);
- memcpy (text+22, kills, strlen(kills));
+ // first we have to figure out if this can be saved in 64 lightstyles
+ // (for Quake compatibility)
+ for (i=64 ; i<MAX_LIGHTSTYLES ; i++)
+ if (sv.lightstyles[i][0])
+ lightstyles = i+1;
+
+ isserver = !strcmp(PRVM_NAME, "server");
+
+ Con_Printf("Saving game to %s...\n", name);
+ f = FS_OpenRealFile(name, "wb", false);
+ if (!f)
+ {
+ Con_Print("ERROR: couldn't open.\n");
+ return;
+ }
+
+ FS_Printf(f, "%i\n", SAVEGAME_VERSION);
+
+ memset(comment, 0, sizeof(comment));
+ if(isserver)
+ dpsnprintf(comment, sizeof(comment), "%-21.21s kills:%3i/%3i", PRVM_GetString(prog->edicts->fields.server->message), (int)prog->globals.server->killed_monsters, (int)prog->globals.server->total_monsters);
+ else
+ dpsnprintf(comment, sizeof(comment), "(crash dump of %s progs)", PRVM_NAME);
// convert space to _ to make stdio happy
// LordHavoc: convert control characters to _ as well
for (i=0 ; i<SAVEGAME_COMMENT_LENGTH ; i++)
- if (text[i] <= ' ')
- text[i] = '_';
- text[SAVEGAME_COMMENT_LENGTH] = '\0';
-}
+ if (ISWHITESPACEORCONTROL(comment[i]))
+ comment[i] = '_';
+ comment[SAVEGAME_COMMENT_LENGTH] = '\0';
+
+ FS_Printf(f, "%s\n", comment);
+ if(isserver)
+ {
+ for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
+ FS_Printf(f, "%f\n", svs.clients[0].spawn_parms[i]);
+ FS_Printf(f, "%d\n", current_skill);
+ FS_Printf(f, "%s\n", sv.name);
+ FS_Printf(f, "%f\n",sv.time);
+ }
+ else
+ {
+ for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
+ FS_Printf(f, "(dummy)\n");
+ FS_Printf(f, "%d\n", 0);
+ FS_Printf(f, "%s\n", "(dummy)");
+ FS_Printf(f, "%f\n", realtime);
+ }
+
+ // write the light styles
+ for (i=0 ; i<lightstyles ; i++)
+ {
+ if (isserver && sv.lightstyles[i][0])
+ FS_Printf(f, "%s\n", sv.lightstyles[i]);
+ else
+ FS_Print(f,"m\n");
+ }
+
+ PRVM_ED_WriteGlobals (f);
+ for (i=0 ; i<prog->num_edicts ; i++)
+ {
+ FS_Printf(f,"// edict %d\n", i);
+ //Con_Printf("edict %d...\n", i);
+ PRVM_ED_Write (f, PRVM_EDICT_NUM(i));
+ }
+
+#if 1
+ FS_Printf(f,"/*\n");
+ FS_Printf(f,"// DarkPlaces extended savegame\n");
+ // darkplaces extension - extra lightstyles, support for color lightstyles
+ for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
+ if (isserver && sv.lightstyles[i][0])
+ FS_Printf(f, "sv.lightstyles %i %s\n", i, sv.lightstyles[i]);
+
+ // darkplaces extension - model precaches
+ for (i=1 ; i<MAX_MODELS ; i++)
+ if (sv.model_precache[i][0])
+ FS_Printf(f,"sv.model_precache %i %s\n", i, sv.model_precache[i]);
+
+ // darkplaces extension - sound precaches
+ for (i=1 ; i<MAX_SOUNDS ; i++)
+ if (sv.sound_precache[i][0])
+ FS_Printf(f,"sv.sound_precache %i %s\n", i, sv.sound_precache[i]);
+ FS_Printf(f,"*/\n");
+#endif
+ FS_Close (f);
+ Con_Print("done.\n");
+}
/*
===============
void Host_Savegame_f (void)
{
char name[MAX_QPATH];
- qfile_t *f;
- int i;
- char comment[SAVEGAME_COMMENT_LENGTH+1];
- if (cls.state != ca_connected || !sv.active)
+ if (!sv.active)
{
- Con_Print("Not playing a local game.\n");
+ Con_Print("Can't save - no server running.\n");
return;
}
- if (cl.intermission)
+ if (cl.islocalgame)
{
- Con_Print("Can't save in intermission.\n");
- return;
- }
+ // singleplayer checks
+ if (cl.intermission)
+ {
+ Con_Print("Can't save in intermission.\n");
+ return;
+ }
- for (i = 0;i < svs.maxclients;i++)
- {
- if (svs.clients[i].active)
+ if (svs.clients[0].active && svs.clients[0].edict->fields.server->deadflag)
{
- if (i > 0)
- {
- Con_Print("Can't save multiplayer games.\n");
- return;
- }
- if (svs.clients[i].edict->fields.server->deadflag)
- {
- Con_Print("Can't savegame with a dead player\n");
- return;
- }
+ Con_Print("Can't savegame with a dead player\n");
+ return;
}
}
+ else
+ Con_Print("Warning: saving a multiplayer game may have strange results when restored (to properly resume, all players must join in the same player slots and then the game can be reloaded).\n");
if (Cmd_Argc() != 2)
{
strlcpy (name, Cmd_Argv(1), sizeof (name));
FS_DefaultExtension (name, ".sav", sizeof (name));
- Con_Printf("Saving game to %s...\n", name);
- f = FS_Open (name, "wb", false, false);
- if (!f)
- {
- Con_Print("ERROR: couldn't open.\n");
- return;
- }
-
- FS_Printf(f, "%i\n", SAVEGAME_VERSION);
- Host_SavegameComment (comment);
- FS_Printf(f, "%s\n", comment);
- for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
- FS_Printf(f, "%f\n", svs.clients[0].spawn_parms[i]);
- FS_Printf(f, "%d\n", current_skill);
- FS_Printf(f, "%s\n", sv.name);
- FS_Printf(f, "%f\n",sv.time);
-
- // write the light styles
- for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
- {
- if (sv.lightstyles[i][0])
- FS_Printf(f, "%s\n", sv.lightstyles[i]);
- else
- FS_Print(f,"m\n");
- }
-
SV_VM_Begin();
-
- PRVM_ED_WriteGlobals (f);
- for (i=0 ; i<prog->num_edicts ; i++)
- PRVM_ED_Write (f, PRVM_EDICT_NUM(i));
-
+ Host_Savegame_to(name);
SV_VM_End();
-
- FS_Close (f);
- Con_Print("done.\n");
}
char mapname[MAX_QPATH];
float time;
const char *start;
+ const char *end;
const char *t;
- const char *oldt;
char *text;
prvm_edict_t *ent;
int i;
Con_Printf("Loading game from %s...\n", filename);
+ // stop playing demos
+ if (cls.demoplayback)
+ CL_Disconnect ();
+
+ // remove menu
+ key_dest = key_game;
+
cls.demonum = -1; // stop demo loop in case this fails
t = text = (char *)FS_LoadFile (filename, tempmempool, false, NULL);
return;
}
+ if(developer_entityparsing.integer)
+ Con_Printf("Host_Loadgame_f: loading version\n");
+
// version
- COM_ParseTokenConsole(&t);
+ COM_ParseToken_Simple(&t, false, false);
version = atoi(com_token);
if (version != SAVEGAME_VERSION)
{
return;
}
+ if(developer_entityparsing.integer)
+ Con_Printf("Host_Loadgame_f: loading description\n");
+
// description
- // this is a little hard to parse, as : is a separator in COM_ParseToken,
- // so use the console parser instead
- COM_ParseTokenConsole(&t);
+ COM_ParseToken_Simple(&t, false, false);
for (i = 0;i < NUM_SPAWN_PARMS;i++)
{
- COM_ParseTokenConsole(&t);
+ COM_ParseToken_Simple(&t, false, false);
spawn_parms[i] = atof(com_token);
}
// skill
- COM_ParseTokenConsole(&t);
+ COM_ParseToken_Simple(&t, false, false);
// this silliness is so we can load 1.06 save files, which have float skill values
current_skill = (int)(atof(com_token) + 0.5);
Cvar_SetValue ("skill", (float)current_skill);
+ if(developer_entityparsing.integer)
+ Con_Printf("Host_Loadgame_f: loading mapname\n");
+
// mapname
- COM_ParseTokenConsole(&t);
+ COM_ParseToken_Simple(&t, false, false);
strlcpy (mapname, com_token, sizeof(mapname));
+ if(developer_entityparsing.integer)
+ Con_Printf("Host_Loadgame_f: loading time\n");
+
// time
- COM_ParseTokenConsole(&t);
+ COM_ParseToken_Simple(&t, false, false);
time = atof(com_token);
allowcheats = sv_cheats.integer != 0;
+ if(developer_entityparsing.integer)
+ Con_Printf("Host_Loadgame_f: spawning server\n");
+
SV_SpawnServer (mapname);
if (!sv.active)
{
sv.paused = true; // pause until all clients connect
sv.loadgame = true;
+ if(developer_entityparsing.integer)
+ Con_Printf("Host_Loadgame_f: loading light styles\n");
+
// load the light styles
+ SV_VM_Begin();
+ // -1 is the globals
+ entnum = -1;
+
for (i = 0;i < MAX_LIGHTSTYLES;i++)
{
// light style
- oldt = t;
- COM_ParseTokenConsole(&t);
+ start = t;
+ COM_ParseToken_Simple(&t, false, false);
// if this is a 64 lightstyle savegame produced by Quake, stop now
- // we have to check this because darkplaces saves 256 lightstyle savegames
+ // we have to check this because darkplaces may save more than 64
if (com_token[0] == '{')
{
- t = oldt;
+ t = start;
break;
}
strlcpy(sv.lightstyles[i], com_token, sizeof(sv.lightstyles[i]));
}
+ if(developer_entityparsing.integer)
+ Con_Printf("Host_Loadgame_f: skipping until globals\n");
+
// now skip everything before the first opening brace
// (this is for forward compatibility, so that older versions (at
// least ones with this fix) can load savegames with extra data before the
// first brace, as might be produced by a later engine version)
- for(;;)
+ for (;;)
{
- oldt = t;
- COM_ParseTokenConsole(&t);
+ start = t;
+ if (!COM_ParseToken_Simple(&t, false, false))
+ break;
if (com_token[0] == '{')
{
- t = oldt;
+ t = start;
break;
}
}
// load the edicts out of the savegame file
- SV_VM_Begin();
- // -1 is the globals
- entnum = -1;
+ end = t;
for (;;)
{
start = t;
- while (COM_ParseTokenConsole(&t))
+ while (COM_ParseToken_Simple(&t, false, false))
if (!strcmp(com_token, "}"))
break;
- if (!COM_ParseTokenConsole(&start))
+ if (!COM_ParseToken_Simple(&start, false, false))
{
// end of file
break;
if (entnum == -1)
{
+ if(developer_entityparsing.integer)
+ Con_Printf("Host_Loadgame_f: loading globals\n");
+
// parse the global vars
PRVM_ED_ParseGlobals (start);
}
Host_Error("Host_PerformLoadGame: too many edicts in save file (reached MAX_EDICTS %i)", MAX_EDICTS);
}
while (entnum >= prog->max_edicts)
- //SV_IncreaseEdicts();
PRVM_MEM_IncreaseEdicts();
ent = PRVM_EDICT_NUM(entnum);
memset (ent->fields.server, 0, prog->progs->entityfields * 4);
ent->priv.server->free = false;
+
+ if(developer_entityparsing.integer)
+ Con_Printf("Host_Loadgame_f: loading edict %d\n", entnum);
+
PRVM_ED_ParseEdict (start, ent);
// link it into the bsp tree
SV_LinkEdict (ent, false);
}
+ end = t;
entnum++;
}
- Mem_Free(text);
prog->num_edicts = entnum;
sv.time = time;
for (i = 0;i < NUM_SPAWN_PARMS;i++)
svs.clients[0].spawn_parms[i] = spawn_parms[i];
+ if(developer_entityparsing.integer)
+ Con_Printf("Host_Loadgame_f: skipping until extended data\n");
+
+ // read extended data if present
+ // the extended data is stored inside a /* */ comment block, which the
+ // parser intentionally skips, so we have to check for it manually here
+ if(end)
+ {
+ while (*end == '\r' || *end == '\n')
+ end++;
+ if (end[0] == '/' && end[1] == '*' && (end[2] == '\r' || end[2] == '\n'))
+ {
+ if(developer_entityparsing.integer)
+ Con_Printf("Host_Loadgame_f: loading extended data\n");
+
+ Con_Printf("Loading extended DarkPlaces savegame\n");
+ t = end + 2;
+ memset(sv.lightstyles[0], 0, sizeof(sv.lightstyles));
+ memset(sv.model_precache[0], 0, sizeof(sv.model_precache));
+ memset(sv.sound_precache[0], 0, sizeof(sv.sound_precache));
+ while (COM_ParseToken_Simple(&t, false, false))
+ {
+ if (!strcmp(com_token, "sv.lightstyles"))
+ {
+ COM_ParseToken_Simple(&t, false, false);
+ i = atoi(com_token);
+ COM_ParseToken_Simple(&t, false, false);
+ if (i >= 0 && i < MAX_LIGHTSTYLES)
+ strlcpy(sv.lightstyles[i], com_token, sizeof(sv.lightstyles[i]));
+ else
+ Con_Printf("unsupported lightstyle %i \"%s\"\n", i, com_token);
+ }
+ else if (!strcmp(com_token, "sv.model_precache"))
+ {
+ COM_ParseToken_Simple(&t, false, false);
+ i = atoi(com_token);
+ COM_ParseToken_Simple(&t, false, false);
+ if (i >= 0 && i < MAX_MODELS)
+ {
+ strlcpy(sv.model_precache[i], com_token, sizeof(sv.model_precache[i]));
+ sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, false);
+ }
+ else
+ Con_Printf("unsupported model %i \"%s\"\n", i, com_token);
+ }
+ else if (!strcmp(com_token, "sv.sound_precache"))
+ {
+ COM_ParseToken_Simple(&t, false, false);
+ i = atoi(com_token);
+ COM_ParseToken_Simple(&t, false, false);
+ if (i >= 0 && i < MAX_SOUNDS)
+ strlcpy(sv.sound_precache[i], com_token, sizeof(sv.sound_precache[i]));
+ else
+ Con_Printf("unsupported sound %i \"%s\"\n", i, com_token);
+ }
+ // skip any trailing text or unrecognized commands
+ while (COM_ParseToken_Simple(&t, true, false) && strcmp(com_token, "\n"))
+ ;
+ }
+ }
+ }
+ Mem_Free(text);
+
+ if(developer_entityparsing.integer)
+ Con_Printf("Host_Loadgame_f: finished\n");
+
SV_VM_End();
// make sure we're connected to loopback
- if (cls.state == ca_disconnected || !(cls.state == ca_connected && cls.netcon != NULL && LHNETADDRESS_GetAddressType(&cls.netcon->peeraddress) == LHNETADDRESSTYPE_LOOP))
+ if (sv.active && cls.state == ca_disconnected)
CL_EstablishConnection("local:1");
}
Host_Name_f
======================
*/
-cvar_t cl_name = {CVAR_SAVE, "_cl_name", "player", "internal storage cvar for current player name (changed by name command)"};
+cvar_t cl_name = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_name", "player", "internal storage cvar for current player name (changed by name command)"};
void Host_Name_f (void)
{
int i, j;
+ qboolean valid_colors;
char newName[sizeof(host_client->name)];
if (Cmd_Argc () == 1)
else
strlcpy (newName, Cmd_Args(), sizeof (newName));
- for (i = 0, j = 0;newName[i];i++)
- if (newName[i] != '\r' && newName[i] != '\n')
- newName[j++] = newName[i];
- newName[j] = 0;
-
if (cmd_source == src_command)
{
Cvar_Set ("_cl_name", newName);
- CL_SetInfo("name", newName, true, false, false, false);
return;
}
- if (sv.time < host_client->nametime)
+ if (realtime < host_client->nametime)
{
SV_ClientPrintf("You can't change name more than once every 5 seconds!\n");
return;
}
- host_client->nametime = sv.time + 5;
+ host_client->nametime = realtime + 5;
// point the string back at updateclient->name to keep it safe
strlcpy (host_client->name, newName, sizeof (host_client->name));
+
+ for (i = 0, j = 0;host_client->name[i];i++)
+ if (host_client->name[i] != '\r' && host_client->name[i] != '\n')
+ host_client->name[j++] = host_client->name[i];
+ host_client->name[j] = 0;
+
+ if(host_client->name[0] == 1 || host_client->name[0] == 2)
+ // may interfere with chat area, and will needlessly beep; so let's add a ^7
+ {
+ memmove(host_client->name + 2, host_client->name, sizeof(host_client->name) - 2);
+ host_client->name[sizeof(host_client->name) - 1] = 0;
+ host_client->name[0] = STRING_COLOR_TAG;
+ host_client->name[1] = '0' + STRING_COLOR_DEFAULT;
+ }
+
+ COM_StringLengthNoColors(host_client->name, 0, &valid_colors);
+ if(!valid_colors) // NOTE: this also proves the string is not empty, as "" is a valid colored string
+ {
+ size_t l;
+ l = strlen(host_client->name);
+ if(l < sizeof(host_client->name) - 1)
+ {
+ // duplicate the color tag to escape it
+ host_client->name[i] = STRING_COLOR_TAG;
+ host_client->name[i+1] = 0;
+ //Con_DPrintf("abuse detected, adding another trailing color tag\n");
+ }
+ else
+ {
+ // remove the last character to fix the color code
+ host_client->name[l-1] = 0;
+ //Con_DPrintf("abuse detected, removing a trailing color tag\n");
+ }
+ }
+
+ // find the last color tag offset and decide if we need to add a reset tag
+ for (i = 0, j = -1;host_client->name[i];i++)
+ {
+ if (host_client->name[i] == STRING_COLOR_TAG)
+ {
+ if (host_client->name[i+1] >= '0' && host_client->name[i+1] <= '9')
+ {
+ j = i;
+ // if this happens to be a reset tag then we don't need one
+ if (host_client->name[i+1] == '0' + STRING_COLOR_DEFAULT)
+ j = -1;
+ i++;
+ continue;
+ }
+ if (host_client->name[i+1] == STRING_COLOR_RGB_TAG_CHAR && isxdigit(host_client->name[i+2]) && isxdigit(host_client->name[i+3]) && isxdigit(host_client->name[i+4]))
+ {
+ j = i;
+ i += 4;
+ continue;
+ }
+ if (host_client->name[i+1] == STRING_COLOR_TAG)
+ {
+ i++;
+ continue;
+ }
+ }
+ }
+ // does not end in the default color string, so add it
+ if (j >= 0 && strlen(host_client->name) < sizeof(host_client->name) - 2)
+ memcpy(host_client->name + strlen(host_client->name), STRING_COLOR_DEFAULT_STR, strlen(STRING_COLOR_DEFAULT_STR) + 1);
+
host_client->edict->fields.server->netname = PRVM_SetEngineString(host_client->name);
if (strcmp(host_client->old_name, host_client->name))
{
if (host_client->spawned)
- SV_BroadcastPrintf("%s changed name to %s\n", host_client->old_name, host_client->name);
+ SV_BroadcastPrintf("%s ^7changed name to %s\n", host_client->old_name, host_client->name);
strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
// send notification to all clients
MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
MSG_WriteString (&sv.reliable_datagram, host_client->name);
+ SV_WriteNetnameIntoDemo(host_client);
}
}
Host_Playermodel_f
======================
*/
-cvar_t cl_playermodel = {CVAR_SAVE, "_cl_playermodel", "", "internal storage cvar for current player model in Nexuiz (changed by playermodel command)"};
+cvar_t cl_playermodel = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_playermodel", "", "internal storage cvar for current player model in Nexuiz (changed by playermodel command)"};
// the old cl_playermodel in cl_main has been renamed to __cl_playermodel
void Host_Playermodel_f (void)
{
if (cmd_source == src_command)
{
Cvar_Set ("_cl_playermodel", newPath);
- CL_SetInfo("playermodel", newPath, true, false, false, false);
return;
}
/*
- if (sv.time < host_client->nametime)
+ if (realtime < host_client->nametime)
{
SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
return;
}
- host_client->nametime = sv.time + 5;
+ host_client->nametime = realtime + 5;
*/
// point the string back at updateclient->name to keep it safe
strlcpy (host_client->playermodel, newPath, sizeof (host_client->playermodel));
- if( eval_playermodel )
- PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string = PRVM_SetEngineString(host_client->playermodel);
+ if( prog->fieldoffsets.playermodel >= 0 )
+ PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playermodel)->string = PRVM_SetEngineString(host_client->playermodel);
if (strcmp(host_client->old_model, host_client->playermodel))
{
strlcpy(host_client->old_model, host_client->playermodel, sizeof(host_client->old_model));
Host_Playerskin_f
======================
*/
-cvar_t cl_playerskin = {CVAR_SAVE, "_cl_playerskin", "", "internal storage cvar for current player skin in Nexuiz (changed by playerskin command)"};
+cvar_t cl_playerskin = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_playerskin", "", "internal storage cvar for current player skin in Nexuiz (changed by playerskin command)"};
void Host_Playerskin_f (void)
{
int i, j;
if (cmd_source == src_command)
{
Cvar_Set ("_cl_playerskin", newPath);
- CL_SetInfo("playerskin", newPath, true, false, false, false);
return;
}
/*
- if (sv.time < host_client->nametime)
+ if (realtime < host_client->nametime)
{
SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
return;
}
- host_client->nametime = sv.time + 5;
+ host_client->nametime = realtime + 5;
*/
// point the string back at updateclient->name to keep it safe
strlcpy (host_client->playerskin, newPath, sizeof (host_client->playerskin));
- if( eval_playerskin )
- PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string = PRVM_SetEngineString(host_client->playerskin);
+ if( prog->fieldoffsets.playerskin >= 0 )
+ PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playerskin)->string = PRVM_SetEngineString(host_client->playerskin);
if (strcmp(host_client->old_skin, host_client->playerskin))
{
//if (host_client->spawned)
p1++;
}
// note this uses the chat prefix \001
- if (!fromServer)
- dpsnprintf (text, sizeof(text), "\001%s" STRING_COLOR_DEFAULT_STR ": %s", host_client->name, p1);
+ if (!fromServer && !teamonly)
+ dpsnprintf (text, sizeof(text), "\001%s: %s", host_client->name, p1);
+ else if (!fromServer && teamonly)
+ dpsnprintf (text, sizeof(text), "\001(%s): %s", host_client->name, p1);
+ else if(*(sv_adminnick.string))
+ dpsnprintf (text, sizeof(text), "\001<%s> %s", sv_adminnick.string, p1);
else
- dpsnprintf (text, sizeof(text), "\001<%s" STRING_COLOR_DEFAULT_STR "> %s", hostname.string, p1);
+ dpsnprintf (text, sizeof(text), "\001<%s> %s", hostname.string, p1);
p2 = text + strlen(text);
while ((const char *)p2 > (const char *)text && (p2[-1] == '\r' || p2[-1] == '\n' || (p2[-1] == '\"' && quoted)))
{
// note: save is not a valid edict if fromServer is true
save = host_client;
for (j = 0, host_client = svs.clients;j < svs.maxclients;j++, host_client++)
- if (host_client->spawned && (!teamonly || host_client->edict->fields.server->team == save->edict->fields.server->team))
+ if (host_client->active && (!teamonly || host_client->edict->fields.server->team == save->edict->fields.server->team))
SV_ClientPrint(text);
host_client = save;
void Host_Tell_f(void)
{
+ const char *playername_start = NULL;
+ size_t playername_length = 0;
+ int playernumber = 0;
client_t *save;
int j;
const char *p1, *p2;
}
}
- if (Cmd_Argc () < 3)
+ if (Cmd_Argc () < 2)
return;
// note this uses the chat prefix \001
if (!fromServer)
- sprintf (text, "\001%s tells you: ", host_client->name);
+ dpsnprintf (text, sizeof(text), "\001%s tells you: ", host_client->name);
+ else if(*(sv_adminnick.string))
+ dpsnprintf (text, sizeof(text), "\001<%s tells you> ", sv_adminnick.string);
else
- sprintf (text, "\001<%s tells you> ", hostname.string);
+ dpsnprintf (text, sizeof(text), "\001<%s tells you> ", hostname.string);
p1 = Cmd_Args();
p2 = p1 + strlen(p1);
// remove the target name
- while (p1 < p2 && *p1 != ' ')
+ while (p1 < p2 && *p1 == ' ')
p1++;
+ if(*p1 == '#')
+ {
+ ++p1;
+ while (p1 < p2 && *p1 == ' ')
+ p1++;
+ while (p1 < p2 && isdigit(*p1))
+ {
+ playernumber = playernumber * 10 + (*p1 - '0');
+ p1++;
+ }
+ --playernumber;
+ }
+ else if(*p1 == '"')
+ {
+ ++p1;
+ playername_start = p1;
+ while (p1 < p2 && *p1 != '"')
+ p1++;
+ playername_length = p1 - playername_start;
+ if(p1 < p2)
+ p1++;
+ }
+ else
+ {
+ playername_start = p1;
+ while (p1 < p2 && *p1 != ' ')
+ p1++;
+ playername_length = p1 - playername_start;
+ }
while (p1 < p2 && *p1 == ' ')
p1++;
+ if(playername_start)
+ {
+ // set playernumber to the right client
+ char namebuf[128];
+ if(playername_length >= sizeof(namebuf))
+ {
+ if (fromServer)
+ Con_Print("Host_Tell: too long player name/ID\n");
+ else
+ SV_ClientPrint("Host_Tell: too long player name/ID\n");
+ return;
+ }
+ memcpy(namebuf, playername_start, playername_length);
+ namebuf[playername_length] = 0;
+ for (playernumber = 0; playernumber < svs.maxclients; playernumber++)
+ {
+ if (!svs.clients[playernumber].active)
+ continue;
+ if (strcasecmp(svs.clients[playernumber].name, namebuf) == 0)
+ break;
+ }
+ }
+ if(playernumber < 0 || playernumber >= svs.maxclients || !(svs.clients[playernumber].active))
+ {
+ if (fromServer)
+ Con_Print("Host_Tell: invalid player name/ID\n");
+ else
+ SV_ClientPrint("Host_Tell: invalid player name/ID\n");
+ return;
+ }
// remove trailing newlines
while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
p2--;
}
while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
p2--;
+ if(p1 == p2)
+ return; // empty say
for (j = (int)strlen(text);j < (int)(sizeof(text) - 2) && p1 < p2;)
text[j++] = *p1++;
text[j++] = '\n';
text[j++] = 0;
save = host_client;
- for (j = 0, host_client = svs.clients;j < svs.maxclients;j++, host_client++)
- if (host_client->spawned && !strcasecmp(host_client->name, Cmd_Argv(1)))
- SV_ClientPrint(text);
+ host_client = svs.clients + playernumber;
+ SV_ClientPrint(text);
host_client = save;
}
Host_Color_f
==================
*/
-cvar_t cl_color = {CVAR_SAVE, "_cl_color", "0", "internal storage cvar for current player colors (changed by color command)"};
+cvar_t cl_color = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_color", "0", "internal storage cvar for current player colors (changed by color command)"};
void Host_Color(int changetop, int changebottom)
{
int top, bottom, playercolor;
- mfunction_t *f;
- func_t SV_ChangeTeam;
// get top and bottom either from the provided values or the current values
// (allows changing only top or bottom, or both at once)
if (cmd_source == src_command)
{
Cvar_SetValueQuick(&cl_color, playercolor);
- if (changetop >= 0)
- CL_SetInfo("topcolor", va("%i", top), true, false, false, false);
- if (changebottom >= 0)
- CL_SetInfo("bottomcolor", va("%i", bottom), true, false, false, false);
- if (cls.protocol != PROTOCOL_QUAKEWORLD && cls.netcon)
- {
- MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
- MSG_WriteString(&cls.netcon->message, va("color %i %i", top, bottom));
- }
return;
}
if (cls.protocol == PROTOCOL_QUAKEWORLD)
return;
- if (host_client->edict && (f = PRVM_ED_FindFunction ("SV_ChangeTeam")) && (SV_ChangeTeam = (func_t)(f - prog->functions)))
+ if (host_client->edict && prog->funcoffsets.SV_ChangeTeam)
{
Con_DPrint("Calling SV_ChangeTeam\n");
prog->globals.server->time = sv.time;
prog->globals.generic[OFS_PARM0] = playercolor;
prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
- PRVM_ExecuteProgram (SV_ChangeTeam, "QC function SV_ChangeTeam is missing");
+ PRVM_ExecuteProgram(prog->funcoffsets.SV_ChangeTeam, "QC function SV_ChangeTeam is missing");
}
else
{
prvm_eval_t *val;
if (host_client->edict)
{
- if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_clientcolors)))
+ if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.clientcolors)))
val->_float = playercolor;
host_client->edict->fields.server->team = bottom + 1;
}
Host_Color(-1, atoi(Cmd_Argv(1)));
}
-cvar_t cl_rate = {CVAR_SAVE, "_cl_rate", "10000", "internal storage cvar for current rate (changed by rate command)"};
+cvar_t cl_rate = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_rate", "20000", "internal storage cvar for current rate (changed by rate command)"};
void Host_Rate_f(void)
{
int rate;
if (cmd_source == src_command)
{
Cvar_SetValue ("_cl_rate", max(NET_MINRATE, rate));
- CL_SetInfo("rate", va("%i", rate), true, false, false, false);
return;
}
LordHavoc: correction, Mindcrime will be removing pmodel in the future, but it's still stuck here for compatibility.
======================
*/
-cvar_t cl_pmodel = {CVAR_SAVE, "_cl_pmodel", "0", "internal storage cvar for current player model number in nehahra (changed by pmodel command)"};
+cvar_t cl_pmodel = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_pmodel", "0", "internal storage cvar for current player model number in nehahra (changed by pmodel command)"};
static void Host_PModel_f (void)
{
int i;
return;
}
- if (host_client->edict && (val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_pmodel)))
+ if (host_client->edict && (val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.pmodel)))
val->_float = i;
}
SZ_Write (&host_client->netconnection->message, sv.signon.data, sv.signon.cursize);
MSG_WriteByte (&host_client->netconnection->message, svc_signonnum);
MSG_WriteByte (&host_client->netconnection->message, 2);
+ host_client->sendsignon = 0; // enable unlimited sends again
}
// reset the name change timer because the client will send name soon
{
int i;
client_t *client;
- func_t RestoreGame;
- mfunction_t *f;
int stats[MAX_CL_STATS];
if (host_client->spawned)
if (sv.loadgame)
{
// loaded games are fully initialized already
- // if this is the last client to be connected, unpause
- sv.paused = false;
-
- if ((f = PRVM_ED_FindFunction ("RestoreGame")))
- if ((RestoreGame = (func_t)(f - prog->functions)))
+ if (prog->funcoffsets.RestoreGame)
{
Con_DPrint("Calling RestoreGame\n");
prog->globals.server->time = sv.time;
prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
- PRVM_ExecuteProgram (RestoreGame, "QC function RestoreGame is missing");
+ PRVM_ExecuteProgram(prog->funcoffsets.RestoreGame, "QC function RestoreGame is missing");
}
}
else
prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
PRVM_ExecuteProgram (prog->globals.server->ClientConnect, "QC function ClientConnect is missing");
- if ((Sys_DoubleTime() - host_client->connecttime) <= sv.time)
- Con_Printf("%s entered the game\n", host_client->name);
+ if (cls.state == ca_dedicated)
+ Con_Printf("%s connected\n", host_client->name);
PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing");
}
MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->v_angle[0], sv.protocol);
MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->v_angle[1], sv.protocol);
MSG_WriteAngle (&host_client->netconnection->message, 0, sv.protocol);
- sv.loadgame = false; // we're basically done with loading now
}
else
{
void Host_Begin_f (void)
{
host_client->spawned = true;
+
+ // LordHavoc: note: this code also exists in SV_DropClient
+ if (sv.loadgame)
+ {
+ int i;
+ for (i = 0;i < svs.maxclients;i++)
+ if (svs.clients[i].active && !svs.clients[i].spawned)
+ break;
+ if (i == svs.maxclients)
+ {
+ Con_Printf("Loaded game, everyone rejoined - unpausing\n");
+ sv.paused = sv.loadgame = false; // we're basically done with loading now
+ }
+ }
}
//===========================================================================
if (Cmd_Argc() > 2)
{
message = Cmd_Args();
- COM_ParseTokenConsole(&message);
+ COM_ParseToken_Simple(&message, false, false);
if (byNumber)
{
message++; // skip the #
break;
case 's':
- if (gamemode == GAME_ROGUE && (val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_ammo_shells1)))
+ if (gamemode == GAME_ROGUE && (val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_shells1)))
val->_float = v;
host_client->edict->fields.server->ammo_shells = v;
case 'n':
if (gamemode == GAME_ROGUE)
{
- if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_ammo_nails1)))
+ if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_nails1)))
{
val->_float = v;
if (host_client->edict->fields.server->weapon <= IT_LIGHTNING)
case 'l':
if (gamemode == GAME_ROGUE)
{
- val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_ammo_lava_nails);
+ val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_lava_nails);
if (val)
{
val->_float = v;
case 'r':
if (gamemode == GAME_ROGUE)
{
- val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_ammo_rockets1);
+ val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_rockets1);
if (val)
{
val->_float = v;
case 'm':
if (gamemode == GAME_ROGUE)
{
- val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_ammo_multi_rockets);
+ val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_multi_rockets);
if (val)
{
val->_float = v;
case 'c':
if (gamemode == GAME_ROGUE)
{
- val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_ammo_cells1);
+ val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_cells1);
if (val)
{
val->_float = v;
case 'p':
if (gamemode == GAME_ROGUE)
{
- val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_ammo_plasma);
+ val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_plasma);
if (val)
{
val->_float = v;
void Host_Viewmodel_f (void)
{
prvm_edict_t *e;
- model_t *m;
+ dp_model_t *m;
if (!sv.active)
return;
{
prvm_edict_t *e;
int f;
- model_t *m;
+ dp_model_t *m;
if (!sv.active)
return;
}
-void PrintFrameName (model_t *m, int frame)
+void PrintFrameName (dp_model_t *m, int frame)
{
if (m->animscenes)
Con_Printf("frame %i: %s\n", frame, m->animscenes[frame].name);
void Host_Viewnext_f (void)
{
prvm_edict_t *e;
- model_t *m;
+ dp_model_t *m;
if (!sv.active)
return;
void Host_Viewprev_f (void)
{
prvm_edict_t *e;
- model_t *m;
+ dp_model_t *m;
if (!sv.active)
return;
{
int i, c;
- if (cls.state == ca_dedicated || COM_CheckParm("-listen") || COM_CheckParm("-benchmark") || COM_CheckParm("-demo") || COM_CheckParm("-demolooponly"))
+ if (cls.state == ca_dedicated || COM_CheckParm("-listen") || COM_CheckParm("-benchmark") || COM_CheckParm("-demo") || COM_CheckParm("-capturedemo"))
return;
c = Cmd_Argc() - 1;
Con_Printf("Max %i demos in demoloop\n", MAX_DEMOS);
c = MAX_DEMOS;
}
- Con_Printf("%i demo(s) in loop\n", c);
+ Con_DPrintf("%i demo(s) in loop\n", c);
for (i=1 ; i<c+1 ; i++)
strlcpy (cls.demos[i-1], Cmd_Argv(i), sizeof (cls.demos[i-1]));
{
int i;
cvar_t *c;
+ const char *cvarname;
client_t *old;
if(Cmd_Argc() != 2)
return;
- if(!(c = Cvar_FindVar(Cmd_Argv(1))) || (c->flags & CVAR_PRIVATE))
+ cvarname = Cmd_Argv(1);
+ if (cls.state == ca_connected)
+ {
+ c = Cvar_FindVar(cvarname);
+ // LordHavoc: if there is no such cvar or if it is private, send a
+ // reply indicating that it has no value
+ if(!c || (c->flags & CVAR_PRIVATE))
+ Cmd_ForwardStringToServer(va("sentcvar %s", cvarname));
+ else
+ Cmd_ForwardStringToServer(va("sentcvar %s \"%s\"", c->name, c->string));
return;
- if (cls.state != ca_dedicated)
- Cmd_ForwardStringToServer(va("sentcvar %s %s\n", c->name, c->string));
- if(!sv.active)// || !SV_ParseClientCommandQC)
+ }
+ if(!sv.active)// || !prog->funcoffsets.SV_ParseClientCommand)
return;
old = host_client;
if(svs.clients[i].active && svs.clients[i].netconnection)
{
host_client = &svs.clients[i];
- Host_ClientCommands(va("sendcvar %s\n", c->name));
+ Host_ClientCommands("sendcvar %s\n", cvarname);
}
host_client = old;
}
for (i = 0;rcon_password.string[i];i++)
{
- if (rcon_password.string[i] <= ' ')
+ if (ISWHITESPACE(rcon_password.string[i]))
{
Con_Printf("rcon_password is not allowed to have any whitespace.\n");
return;
}
mysocket = NetConn_ChooseClientSocketForAddress(&address);
+ if (!mysocket)
+ mysocket = NetConn_ChooseServerSocketForAddress(&address);
if (mysocket)
NetConn_Write(mysocket, send, out - send, &address);
}
{
packetloss = 0;
if (svs.clients[i].netconnection)
- for (j = 0;j < 100;j++)
- packetloss += svs.clients[i].netconnection->packetlost[j];
+ for (j = 0;j < NETGRAPH_PACKETS;j++)
+ if (svs.clients[i].netconnection->incoming_unreliablesize[j] == NETGRAPH_LOSTPACKET)
+ packetloss++;
+ packetloss = packetloss * 100 / NETGRAPH_PACKETS;
ping = (int)floor(svs.clients[i].ping*1000+0.5);
ping = bound(0, ping, 9999);
if (sv.protocol == PROTOCOL_QUAKEWORLD)
*/
void Host_InitCommands (void)
{
- dpsnprintf(cls.userinfo, sizeof(cls.userinfo), "\\name\\player\\team\\none\\topcolor\\0\\bottomcolor\\0\\rate\\10000\\msg\\1\\noaim\\1\\*ver\\%s", engineversion);
+ dpsnprintf(cls.userinfo, sizeof(cls.userinfo), "\\name\\player\\team\\none\\topcolor\\0\\bottomcolor\\0\\rate\\10000\\msg\\1\\noaim\\1\\*ver\\dp");
Cmd_AddCommand_WithClientCommand ("status", Host_Status_f, Host_Status_f, "print server status information");
Cmd_AddCommand ("quit", Host_Quit_f, "quit the game");
Cmd_AddCommand ("restart", Host_Restart_f, "restart current level");
Cmd_AddCommand ("changelevel", Host_Changelevel_f, "change to another level, bringing along all connected clients");
Cmd_AddCommand ("connect", Host_Connect_f, "connect to a server by IP address or hostname");
- Cmd_AddCommand ("reconnect", Host_Reconnect_f, "reset signon level in preparation for a new level (do not use)");
+ Cmd_AddCommand ("reconnect", Host_Reconnect_f, "reconnect to the last server you were on, or resets a quakeworld connection (do not use if currently playing on a netquake server)");
Cmd_AddCommand ("version", Host_Version_f, "print engine version");
Cmd_AddCommand_WithClientCommand ("say", Host_Say_f, Host_Say_f, "send a chat message to everyone on the server");
Cmd_AddCommand_WithClientCommand ("say_team", Host_Say_Team_f, Host_Say_Team_f, "send a chat message to your team on the server");
Cmd_AddCommand_WithClientCommand ("begin", NULL, Host_Begin_f, "signon 3 (client asks server to start sending entities, and will go to signon 4 (playing) when the first entity update is received)");
Cmd_AddCommand ("maxplayers", MaxPlayers_f, "sets limit on how many players (or bots) may be connected to the server at once");
- Cmd_AddCommand ("sendcvar", Host_SendCvar_f, "sends the value of a cvar to the server as a sentcvar command, for use by QuakeC"); // By [515]
+ Cmd_AddCommand ("sendcvar", Host_SendCvar_f, "sends the value of a cvar to the server as a sentcvar command, for use by QuakeC");
Cvar_RegisterVariable (&rcon_password);
Cvar_RegisterVariable (&rcon_address);
Cmd_AddCommand_WithClientCommand ("pings", NULL, Host_Pings_f, "command sent by clients to request updated ping and packetloss of players on scoreboard (originally from QW, but also used on NQ servers)");
Cmd_AddCommand ("pingplreport", Host_PingPLReport_f, "command sent by server containing client ping and packet loss values for scoreboard, triggered by pings command from client (not used by QW servers)");
+ Cmd_AddCommand ("fixtrans", Image_FixTransparentPixels_f, "change alpha-zero pixels in an image file to sensible values, and write out a new TGA (warning: SLOW)");
+ Cvar_RegisterVariable (&r_fixtrans_auto);
+
Cvar_RegisterVariable (&team);
Cvar_RegisterVariable (&skin);
Cvar_RegisterVariable (&noaim);
Cvar_RegisterVariable(&sv_cheats);
+ Cvar_RegisterVariable(&sv_adminnick);
+ Cvar_RegisterVariable(&sv_status_privacy);
+ Cvar_RegisterVariable(&sv_status_show_qcstatus);
}
+void Host_NoOperation_f(void)
+{
+}