-extern qboolean host_shuttingdown;
-extern cvar_t developer_entityparsing;
-
-/*
-==================
-Host_Quit_f
-==================
-*/
-
-void Host_Quit_f(cmd_state_t *cmd)
-{
- if(host_shuttingdown)
- Con_Printf("shutting down already!\n");
- else
- Sys_Quit (0);
-}
-
-/*
-==================
-Host_Status_f
-==================
-*/
-static void Host_Status_f(cmd_state_t *cmd)
-{
- prvm_prog_t *prog = SVVM_prog;
- char qcstatus[256];
- client_t *client;
- int seconds = 0, minutes = 0, hours = 0, i, j, k, in, players, ping = 0, packetloss = 0;
- void (*print) (const char *fmt, ...);
- char ip[48]; // can contain a full length v6 address with [] and a port
- int frags;
- char vabuf[1024];
-
- if (cmd->source == src_command)
- {
- // if running a client, try to send over network so the client's status report parser will see the report
- if (cls.state == ca_connected)
- {
- Cmd_ForwardToServer_f(cmd);
- return;
- }
- print = Con_Printf;
- }
- else
- print = SV_ClientPrintf;
-
- if (!sv.active)
- return;
-
- in = 0;
- if (Cmd_Argc(cmd) == 2)
- {
- if (strcmp(Cmd_Argv(cmd, 1), "1") == 0)
- in = 1;
- else if (strcmp(Cmd_Argv(cmd, 1), "2") == 0)
- in = 2;
- }
-
- for (players = 0, i = 0;i < svs.maxclients;i++)
- if (svs.clients[i].active)
- players++;
- print ("host: %s\n", Cvar_VariableString (&cvars_all, "hostname", CVAR_SERVER));
- print ("version: %s build %s (gamename %s)\n", gamename, buildstring, gamenetworkfiltername);
- 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(vabuf, sizeof(vabuf)));
- print ("players: %i active (%i max)\n\n", players, svs.maxclients);
-
- 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;
-
- ++k;
-
- if (in == 0 || in == 1)
- {
- 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_netgraph[j].unreliablebytes == NETGRAPH_LOSTPACKET)
- packetloss++;
- packetloss = (packetloss * 100 + NETGRAPH_PACKETS - 1) / 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", 48);
- else
- strlcpy(ip, (client->netconnection && *client->netconnection->address) ? client->netconnection->address : "botclient", 48);
-
- frags = client->frags;
-
- if(sv_status_show_qcstatus.integer)
- {
- prvm_edict_t *ed = PRVM_EDICT_NUM(i + 1);
- const char *str = PRVM_GetString(prog, PRVM_serveredictstring(ed, 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
- {
- if (sv.protocol == PROTOCOL_QUAKE && svs.maxclients <= 99)
- {
- // LadyHavoc: this is very touchy because we must maintain ProQuake compatible status output
- print ("#%-2u %-16.16s %3i %2i:%02i:%02i\n", i+1, client->name, frags, hours, minutes, seconds);
- print (" %s\n", ip);
- }
- else
- {
- // LadyHavoc: no real restrictions here, not a ProQuake-compatible protocol anyway...
- print ("#%-3u %-16.16s %4i %2i:%02i:%02i\n", i+1, client->name, frags, hours, minutes, seconds);
- print (" %s\n", ip);
- }
- }
- else if (in == 1) // extended layout
- {
- print ("%s%-47s %2i %4i %2i:%02i:%02i %4i #%-3u ^7%s\n", k%2 ? "^3" : "^7", ip, packetloss, ping, hours, minutes, seconds, frags, i+1, client->name);
- }
- else if (in == 2) // reduced layout
- {
- print ("%s%-47s #%-3u ^7%s\n", k%2 ? "^3" : "^7", ip, i+1, client->name);
- }
- }
-}
-
-
-/*
-==================
-Host_God_f
-
-Sets client to godmode
-==================
-*/
-static void Host_God_f(cmd_state_t *cmd)
-{
- prvm_prog_t *prog = SVVM_prog;
-
- PRVM_serveredictfloat(host_client->edict, flags) = (int)PRVM_serveredictfloat(host_client->edict, flags) ^ FL_GODMODE;
- if (!((int)PRVM_serveredictfloat(host_client->edict, flags) & FL_GODMODE) )
- SV_ClientPrint("godmode OFF\n");
- else
- SV_ClientPrint("godmode ON\n");
-}
-
-static void Host_Notarget_f(cmd_state_t *cmd)
-{
- prvm_prog_t *prog = SVVM_prog;
-
- PRVM_serveredictfloat(host_client->edict, flags) = (int)PRVM_serveredictfloat(host_client->edict, flags) ^ FL_NOTARGET;
- if (!((int)PRVM_serveredictfloat(host_client->edict, flags) & FL_NOTARGET) )
- SV_ClientPrint("notarget OFF\n");
- else
- SV_ClientPrint("notarget ON\n");
-}
-
-qboolean noclip_anglehack;
-
-static void Host_Noclip_f(cmd_state_t *cmd)
-{
- prvm_prog_t *prog = SVVM_prog;
-
- if (PRVM_serveredictfloat(host_client->edict, movetype) != MOVETYPE_NOCLIP)
- {
- noclip_anglehack = true;
- PRVM_serveredictfloat(host_client->edict, movetype) = MOVETYPE_NOCLIP;
- SV_ClientPrint("noclip ON\n");
- }
- else
- {
- noclip_anglehack = false;
- PRVM_serveredictfloat(host_client->edict, movetype) = MOVETYPE_WALK;
- SV_ClientPrint("noclip OFF\n");
- }
-}
-
-/*
-==================
-Host_Fly_f
-
-Sets client to flymode
-==================
-*/
-static void Host_Fly_f(cmd_state_t *cmd)
-{
- prvm_prog_t *prog = SVVM_prog;
-
- if (PRVM_serveredictfloat(host_client->edict, movetype) != MOVETYPE_FLY)
- {
- PRVM_serveredictfloat(host_client->edict, movetype) = MOVETYPE_FLY;
- SV_ClientPrint("flymode ON\n");
- }
- else
- {
- PRVM_serveredictfloat(host_client->edict, movetype) = MOVETYPE_WALK;
- SV_ClientPrint("flymode OFF\n");
- }
-}
-
-
-/*
-==================
-Host_Ping_f
-
-==================
-*/
-static void Host_Ping_f(cmd_state_t *cmd)
-{
- int i;
- client_t *client;
- void (*print) (const char *fmt, ...);
-
- if (cmd->source == src_command)
- {
- // if running a client, try to send over network so the client's ping report parser will see the report
- if (cls.state == ca_connected)
- {
- Cmd_ForwardToServer_f(cmd);
- return;
- }
- print = Con_Printf;
- }
- else
- print = SV_ClientPrintf;
-
- if (!sv.active)
- return;
-
- print("Client ping times:\n");
- for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
- {
- if (!client->active)
- continue;
- print("%4i %s\n", bound(0, (int)floor(client->ping*1000+0.5), 9999), client->name);
- }
-}
-
-// Disable cheats if sv_cheats is turned off
-static void Host_DisableCheats_c(char *value)
-{
- prvm_prog_t *prog = SVVM_prog;
- int i = 0;
-
- if (value[0] == '0' && !value[1])
- {
- while (svs.clients[i].edict)
- {
- if (((int)PRVM_serveredictfloat(svs.clients[i].edict, flags) & FL_GODMODE))
- PRVM_serveredictfloat(svs.clients[i].edict, flags) = (int)PRVM_serveredictfloat(svs.clients[i].edict, flags) ^ FL_GODMODE;
- if (((int)PRVM_serveredictfloat(svs.clients[i].edict, flags) & FL_NOTARGET))
- PRVM_serveredictfloat(svs.clients[i].edict, flags) = (int)PRVM_serveredictfloat(svs.clients[i].edict, flags) ^ FL_NOTARGET;
- if (PRVM_serveredictfloat(svs.clients[i].edict, movetype) == MOVETYPE_NOCLIP ||
- PRVM_serveredictfloat(svs.clients[i].edict, movetype) == MOVETYPE_FLY)
- {
- noclip_anglehack = false;
- PRVM_serveredictfloat(svs.clients[i].edict, movetype) = MOVETYPE_WALK;
- }
- i++;
- }
- }
-}
-
-/*
-===============================================================================
-
-SERVER TRANSITIONS
-
-===============================================================================
-*/
-
-/*
-======================
-Host_Map_f
-
-handle a
-map <servername>
-command from the console. Active clients are kicked off.
-======================
-*/
-static void Host_Map_f(cmd_state_t *cmd)
-{
- char level[MAX_QPATH];
-
- if (Cmd_Argc(cmd) != 2)
- {
- Con_Print("map <levelname> : start a new game (kicks off all players)\n");
- return;
- }
-
- // GAME_DELUXEQUAKE - clear warpmark (used by QC)
- if (gamemode == GAME_DELUXEQUAKE)
- Cvar_Set(&cvars_all, "warpmark", "");
-
- cls.demonum = -1; // stop demo loop in case this fails
-
- CL_Disconnect ();
- Host_ShutdownServer();
-
- if(svs.maxclients != svs.maxclients_next)
- {
- svs.maxclients = svs.maxclients_next;
- if (svs.clients)
- Mem_Free(svs.clients);
- svs.clients = (client_t *)Mem_Alloc(sv_mempool, sizeof(client_t) * svs.maxclients);
- }
-
-#ifdef CONFIG_MENU
- // remove menu
- if (key_dest == key_menu || key_dest == key_menu_grabbed)
- MR_ToggleMenu(0);
-#endif
- key_dest = key_game;
-
- svs.serverflags = 0; // haven't completed an episode yet
- strlcpy(level, Cmd_Argv(cmd, 1), sizeof(level));
- SV_SpawnServer(level);
- if (sv.active && cls.state == ca_disconnected)
- CL_EstablishConnection("local:1", -2);
-}
-
-/*
-==================
-Host_Changelevel_f
-
-Goes to a new map, taking all clients along
-==================
-*/
-static void Host_Changelevel_f(cmd_state_t *cmd)
-{
- char level[MAX_QPATH];
-
- if (Cmd_Argc(cmd) != 2)
- {
- Con_Print("changelevel <levelname> : continue game on a new level\n");
- return;
- }
- // HACKHACKHACK
- if (!sv.active) {
- Host_Map_f(cmd);
- return;
- }
-
-#ifdef CONFIG_MENU
- // remove menu
- if (key_dest == key_menu || key_dest == key_menu_grabbed)
- MR_ToggleMenu(0);
-#endif
- key_dest = key_game;
-
- SV_SaveSpawnparms ();
- strlcpy(level, Cmd_Argv(cmd, 1), sizeof(level));
- SV_SpawnServer(level);
- if (sv.active && cls.state == ca_disconnected)
- CL_EstablishConnection("local:1", -2);
-}
-
-/*
-==================
-Host_Restart_f
-
-Restarts the current server for a dead player
-==================
-*/
-static void Host_Restart_f(cmd_state_t *cmd)
-{
- char mapname[MAX_QPATH];
-
- if (Cmd_Argc(cmd) != 1)
- {
- Con_Print("restart : restart current level\n");
- return;
- }
- if (!sv.active)
- {
- Con_Print("Only the server may restart\n");
- return;
- }
-
-#ifdef CONFIG_MENU
- // remove menu
- if (key_dest == key_menu || key_dest == key_menu_grabbed)
- MR_ToggleMenu(0);
-#endif
- key_dest = key_game;
-
- strlcpy(mapname, sv.name, sizeof(mapname));
- SV_SpawnServer(mapname);
- if (sv.active && cls.state == ca_disconnected)
- CL_EstablishConnection("local:1", -2);
-}
-
-/*
-==================
-Host_Reconnect_f
-
-This command causes the client to wait for the signon messages again.
-This is sent just before a server changes levels
-==================
-*/
-void Host_Reconnect_f(cmd_state_t *cmd)
-{
- 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, -1);
- 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.state == ca_connected)
- {
- Con_Printf("Server is changing level...\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(cmd) != 1)
- {
- Con_Print("reconnect : wait for signon messages again\n");
- return;
- }
- if (!cls.signon)
- {
- Con_Print("reconnect: no signon, ignoring reconnect\n");
- return;
- }
- cls.signon = 0; // need new connection messages
- }
-}
-
-/*
-=====================
-Host_Connect_f
-
-User command to connect to server
-=====================
-*/
-static void Host_Connect_f(cmd_state_t *cmd)
-{
- if (Cmd_Argc(cmd) < 2)
- {
- Con_Print("connect <serveraddress> [<key> <value> ...]: connect to a multiplayer game\n");
- return;
- }
- // clear the rcon password, to prevent vulnerability by stuffcmd-ing a connect command
- if(rcon_secure.integer <= 0)
- Cvar_SetQuick(&rcon_password, "");
- CL_EstablishConnection(Cmd_Argv(cmd, 1), 2);
-}
-
-
-/*
-===============================================================================
-
-LOAD / SAVE GAME
-
-===============================================================================
-*/
-
-#define SAVEGAME_VERSION 5
-
-void Host_Savegame_to(prvm_prog_t *prog, const char *name)
-{
- qfile_t *f;
- int i, k, l, numbuffers, lightstyles = 64;
- char comment[SAVEGAME_COMMENT_LENGTH+1];
- char line[MAX_INPUTLINE];
- qboolean isserver;
- char *s;
-
- // 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 = prog == SVVM_prog;
-
- 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, PRVM_serveredictstring(prog->edicts, message)), (int)PRVM_serverglobalfloat(killed_monsters), (int)PRVM_serverglobalfloat(total_monsters));
- else
- dpsnprintf(comment, sizeof(comment), "(crash dump of %s progs)", prog->name);
- // convert space to _ to make stdio happy
- // LadyHavoc: convert control characters to _ as well
- for (i=0 ; i<SAVEGAME_COMMENT_LENGTH ; i++)
- 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 (prog, 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 (prog, 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]);
-
- // darkplaces extension - save buffers
- numbuffers = (int)Mem_ExpandableArray_IndexRange(&prog->stringbuffersarray);
- for (i = 0; i < numbuffers; i++)
- {
- prvm_stringbuffer_t *stringbuffer = (prvm_stringbuffer_t*) Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, i);
- if(stringbuffer && (stringbuffer->flags & STRINGBUFFER_SAVED))
- {
- FS_Printf(f,"sv.buffer %i %i \"string\"\n", i, stringbuffer->flags & STRINGBUFFER_QCFLAGS);
- for(k = 0; k < stringbuffer->num_strings; k++)
- {
- if (!stringbuffer->strings[k])
- continue;
- // Parse the string a bit to turn special characters
- // (like newline, specifically) into escape codes
- s = stringbuffer->strings[k];
- for (l = 0;l < (int)sizeof(line) - 2 && *s;)
- {
- if (*s == '\n')
- {
- line[l++] = '\\';
- line[l++] = 'n';
- }
- else if (*s == '\r')
- {
- line[l++] = '\\';
- line[l++] = 'r';
- }
- else if (*s == '\\')
- {
- line[l++] = '\\';
- line[l++] = '\\';
- }
- else if (*s == '"')
- {
- line[l++] = '\\';
- line[l++] = '"';
- }
- else
- line[l++] = *s;
- s++;
- }
- line[l] = '\0';
- FS_Printf(f,"sv.bufstr %i %i \"%s\"\n", i, k, line);
- }
- }
- }
- FS_Printf(f,"*/\n");
-#endif
-
- FS_Close (f);
- Con_Print("done.\n");
-}
-
-/*
-===============
-Host_Savegame_f
-===============
-*/
-static void Host_Savegame_f(cmd_state_t *cmd)
-{
- prvm_prog_t *prog = SVVM_prog;
- char name[MAX_QPATH];
- qboolean deadflag = false;
-
- if (!sv.active)
- {
- Con_Print("Can't save - no server running.\n");
- return;
- }
-
- deadflag = cl.islocalgame && svs.clients[0].active && PRVM_serveredictfloat(svs.clients[0].edict, deadflag);
-
- if (cl.islocalgame)
- {
- // singleplayer checks
- if (cl.intermission)
- {
- Con_Print("Can't save in intermission.\n");
- return;
- }
-
- if (deadflag)
- {
- Con_Print("Can't savegame with a dead player\n");
- return;
- }
- }
- else
- Con_Warn("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(cmd) != 2)
- {
- Con_Print("save <savename> : save a game\n");
- return;
- }
-
- if (strstr(Cmd_Argv(cmd, 1), ".."))
- {
- Con_Print("Relative pathnames are not allowed.\n");
- return;
- }
-
- strlcpy (name, Cmd_Argv(cmd, 1), sizeof (name));
- FS_DefaultExtension (name, ".sav", sizeof (name));
-
- Host_Savegame_to(prog, name);
-}
-
-
-/*
-===============
-Host_Loadgame_f
-===============
-*/
-
-static void Host_Loadgame_f(cmd_state_t *cmd)
-{
- prvm_prog_t *prog = SVVM_prog;
- char filename[MAX_QPATH];
- char mapname[MAX_QPATH];
- float time;
- const char *start;
- const char *end;
- const char *t;
- char *text;
- prvm_edict_t *ent;
- int i, k, numbuffers;
- int entnum;
- int version;
- float spawn_parms[NUM_SPAWN_PARMS];
- prvm_stringbuffer_t *stringbuffer;
-
- if (Cmd_Argc(cmd) != 2)
- {
- Con_Print("load <savename> : load a game\n");
- return;
- }
-
- strlcpy (filename, Cmd_Argv(cmd, 1), sizeof(filename));
- FS_DefaultExtension (filename, ".sav", sizeof (filename));
-
- Con_Printf("Loading game from %s...\n", filename);
-
- // stop playing demos
- if (cls.demoplayback)
- CL_Disconnect ();
-
-#ifdef CONFIG_MENU
- // remove menu
- if (key_dest == key_menu || key_dest == key_menu_grabbed)
- MR_ToggleMenu(0);
-#endif
- key_dest = key_game;
-
- cls.demonum = -1; // stop demo loop in case this fails
-
- t = text = (char *)FS_LoadFile (filename, tempmempool, false, NULL);
- if (!text)
- {
- Con_Print("ERROR: couldn't open.\n");
- return;
- }
-
- if(developer_entityparsing.integer)
- Con_Printf("Host_Loadgame_f: loading version\n");
-
- // version
- COM_ParseToken_Simple(&t, false, false, true);
- version = atoi(com_token);
- if (version != SAVEGAME_VERSION)
- {
- Mem_Free(text);
- Con_Printf("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION);
- return;
- }
-
- if(developer_entityparsing.integer)
- Con_Printf("Host_Loadgame_f: loading description\n");
-
- // description
- COM_ParseToken_Simple(&t, false, false, true);
-
- for (i = 0;i < NUM_SPAWN_PARMS;i++)
- {
- COM_ParseToken_Simple(&t, false, false, true);
- spawn_parms[i] = atof(com_token);
- }
- // skill
- COM_ParseToken_Simple(&t, false, false, true);
-// 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 (&cvars_all, "skill", (float)current_skill);
-
- if(developer_entityparsing.integer)
- Con_Printf("Host_Loadgame_f: loading mapname\n");
-
- // mapname
- COM_ParseToken_Simple(&t, false, false, true);
- strlcpy (mapname, com_token, sizeof(mapname));
-
- if(developer_entityparsing.integer)
- Con_Printf("Host_Loadgame_f: loading time\n");
-
- // time
- COM_ParseToken_Simple(&t, false, false, true);
- time = atof(com_token);
-
- if(developer_entityparsing.integer)
- Con_Printf("Host_Loadgame_f: spawning server\n");
-
- SV_SpawnServer (mapname);
- if (!sv.active)
- {
- Mem_Free(text);
- Con_Print("Couldn't load map\n");
- return;
- }
- 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
-
- // -1 is the globals
- entnum = -1;
-
- for (i = 0;i < MAX_LIGHTSTYLES;i++)
- {
- // light style
- start = t;
- COM_ParseToken_Simple(&t, false, false, true);
- // if this is a 64 lightstyle savegame produced by Quake, stop now
- // we have to check this because darkplaces may save more than 64
- if (com_token[0] == '{')
- {
- 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 (;;)
- {
- start = t;
- if (!COM_ParseToken_Simple(&t, false, false, true))
- break;
- if (com_token[0] == '{')
- {
- t = start;
- break;
- }
- }
-
- // unlink all entities
- World_UnlinkAll(&sv.world);
-
-// load the edicts out of the savegame file
- end = t;
- for (;;)
- {
- start = t;
- while (COM_ParseToken_Simple(&t, false, false, true))
- if (!strcmp(com_token, "}"))
- break;
- if (!COM_ParseToken_Simple(&start, false, false, true))
- {
- // end of file
- break;
- }
- if (strcmp(com_token,"{"))
- {
- Mem_Free(text);
- Host_Error ("First token isn't a brace");
- }
-
- if (entnum == -1)
- {
- if(developer_entityparsing.integer)
- Con_Printf("Host_Loadgame_f: loading globals\n");
-
- // parse the global vars
- PRVM_ED_ParseGlobals (prog, start);
-
- // restore the autocvar globals
- Cvar_UpdateAllAutoCvars(prog->console_cmd->cvars);
- }
- else
- {
- // parse an edict
- if (entnum >= MAX_EDICTS)
- {
- Mem_Free(text);
- Host_Error("Host_PerformLoadGame: too many edicts in save file (reached MAX_EDICTS %i)", MAX_EDICTS);
- }
- while (entnum >= prog->max_edicts)
- PRVM_MEM_IncreaseEdicts(prog);
- ent = PRVM_EDICT_NUM(entnum);
- memset(ent->fields.fp, 0, prog->entityfields * sizeof(prvm_vec_t));
- ent->priv.server->free = false;
-
- if(developer_entityparsing.integer)
- Con_Printf("Host_Loadgame_f: loading edict %d\n", entnum);
-
- PRVM_ED_ParseEdict (prog, start, ent);
-
- // link it into the bsp tree
- if (!ent->priv.server->free && !VectorCompare(PRVM_serveredictvector(ent, absmin), PRVM_serveredictvector(ent, absmax)))
- SV_LinkEdict(ent);
- }
-
- end = t;
- entnum++;
- }
-
- 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));
- BufStr_Flush(prog);
-
- while (COM_ParseToken_Simple(&t, false, false, true))
- {
- if (!strcmp(com_token, "sv.lightstyles"))
- {
- COM_ParseToken_Simple(&t, false, false, true);
- i = atoi(com_token);
- COM_ParseToken_Simple(&t, false, false, true);
- 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, true);
- i = atoi(com_token);
- COM_ParseToken_Simple(&t, false, false, true);
- 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, sv.model_precache[i][0] == '*' ? sv.worldname : NULL);
- }
- 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, true);
- i = atoi(com_token);
- COM_ParseToken_Simple(&t, false, false, true);
- 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);
- }
- else if (!strcmp(com_token, "sv.buffer"))
- {
- if (COM_ParseToken_Simple(&t, false, false, true))
- {
- i = atoi(com_token);
- if (i >= 0)
- {
- k = STRINGBUFFER_SAVED;
- if (COM_ParseToken_Simple(&t, false, false, true))
- k |= atoi(com_token);
- if (!BufStr_FindCreateReplace(prog, i, k, "string"))
- Con_Errorf("failed to create stringbuffer %i\n", i);
- }
- else
- Con_Printf("unsupported stringbuffer index %i \"%s\"\n", i, com_token);
- }
- else
- Con_Printf("unexpected end of line when parsing sv.buffer (expected buffer index)\n");
- }
- else if (!strcmp(com_token, "sv.bufstr"))
- {
- if (!COM_ParseToken_Simple(&t, false, false, true))
- Con_Printf("unexpected end of line when parsing sv.bufstr\n");
- else
- {
- i = atoi(com_token);
- stringbuffer = BufStr_FindCreateReplace(prog, i, STRINGBUFFER_SAVED, "string");
- if (stringbuffer)
- {
- if (COM_ParseToken_Simple(&t, false, false, true))
- {
- k = atoi(com_token);
- if (COM_ParseToken_Simple(&t, false, false, true))
- BufStr_Set(prog, stringbuffer, k, com_token);
- else
- Con_Printf("unexpected end of line when parsing sv.bufstr (expected string)\n");
- }
- else
- Con_Printf("unexpected end of line when parsing sv.bufstr (expected strindex)\n");
- }
- else
- Con_Errorf("failed to create stringbuffer %i \"%s\"\n", i, com_token);
- }
- }
- // skip any trailing text or unrecognized commands
- while (COM_ParseToken_Simple(&t, true, false, true) && strcmp(com_token, "\n"))
- ;
- }
- }
- }
- Mem_Free(text);
-
- // remove all temporary flagged string buffers (ones created with BufStr_FindCreateReplace)
- numbuffers = (int)Mem_ExpandableArray_IndexRange(&prog->stringbuffersarray);
- for (i = 0; i < numbuffers; i++)
- {
- if ( (stringbuffer = (prvm_stringbuffer_t *)Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, i)) )
- if (stringbuffer->flags & STRINGBUFFER_TEMP)
- BufStr_Del(prog, stringbuffer);
- }
-
- if(developer_entityparsing.integer)
- Con_Printf("Host_Loadgame_f: finished\n");
-
- // make sure we're connected to loopback
- if (sv.active && cls.state == ca_disconnected)
- CL_EstablishConnection("local:1", -2);
-}
-
-//============================================================================
-
-/*
-======================
-Host_Name_f
-======================
-*/
-cvar_t cl_name = {CVAR_CLIENT | CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_name", "player", "internal storage cvar for current player name (changed by name command)"};
-static void Host_Name_f(cmd_state_t *cmd)
-{
- prvm_prog_t *prog = SVVM_prog;
- int i, j;
- qboolean valid_colors;
- const char *newNameSource;
- char newName[sizeof(host_client->name)];
-
- if (Cmd_Argc (cmd) == 1)
- {
- if (cmd->source == src_command)
- {
- Con_Printf("name: %s\n", cl_name.string);
- }
- return;
- }
-
- if (Cmd_Argc (cmd) == 2)
- newNameSource = Cmd_Argv(cmd, 1);
- else
- newNameSource = Cmd_Args(cmd);
-
- strlcpy(newName, newNameSource, sizeof(newName));
-
- if (cmd->source == src_command)
- {
- Cvar_Set (&cvars_all, "_cl_name", newName);
- if (strlen(newNameSource) >= sizeof(newName)) // overflowed
- {
- Con_Printf("Your name is longer than %i chars! It has been truncated.\n", (int) (sizeof(newName) - 1));
- Con_Printf("name: %s\n", cl_name.string);
- }
- return;
- }
-
- if (realtime < host_client->nametime)
- {
- SV_ClientPrintf("You can't change name more than once every %.1f seconds!\n", max(0.0f, sv_namechangetimer.value));
- return;
- }
-
- host_client->nametime = realtime + max(0.0f, sv_namechangetimer.value);
-
- // 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;
- }
-
- u8_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);
-
- PRVM_serveredictstring(host_client->edict, netname) = PRVM_SetEngineString(prog, host_client->name);
- if (strcmp(host_client->old_name, host_client->name))
- {
- if (host_client->begun)
- 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_CLIENT | CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_playermodel", "", "internal storage cvar for current player model in Nexuiz/Xonotic (changed by playermodel command)"};
-// the old cl_playermodel in cl_main has been renamed to __cl_playermodel
-static void Host_Playermodel_f(cmd_state_t *cmd)
-{
- prvm_prog_t *prog = SVVM_prog;
- int i, j;
- char newPath[sizeof(host_client->playermodel)];
-
- if (Cmd_Argc (cmd) == 1)
- {
- if (cmd->source == src_command)
- {
- Con_Printf("\"playermodel\" is \"%s\"\n", cl_playermodel.string);
- }
- return;
- }
-
- if (Cmd_Argc (cmd) == 2)
- strlcpy (newPath, Cmd_Argv(cmd, 1), sizeof (newPath));
- else
- strlcpy (newPath, Cmd_Args(cmd), sizeof (newPath));
-
- for (i = 0, j = 0;newPath[i];i++)
- if (newPath[i] != '\r' && newPath[i] != '\n')
- newPath[j++] = newPath[i];
- newPath[j] = 0;
-
- if (cmd->source == src_command)
- {
- Cvar_Set (&cvars_all, "_cl_playermodel", newPath);
- return;
- }
-
- /*
- if (realtime < host_client->nametime)
- {
- SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
- return;
- }
-
- 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));
- PRVM_serveredictstring(host_client->edict, playermodel) = PRVM_SetEngineString(prog, 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));
- /*// send notification to all clients
- MSG_WriteByte (&sv.reliable_datagram, svc_updatepmodel);
- MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
- MSG_WriteString (&sv.reliable_datagram, host_client->playermodel);*/
- }
-}
-
-/*
-======================
-Host_Playerskin_f
-======================
-*/
-cvar_t cl_playerskin = {CVAR_CLIENT | CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_playerskin", "", "internal storage cvar for current player skin in Nexuiz/Xonotic (changed by playerskin command)"};
-static void Host_Playerskin_f(cmd_state_t *cmd)
-{
- prvm_prog_t *prog = SVVM_prog;
- int i, j;
- char newPath[sizeof(host_client->playerskin)];
-
- if (Cmd_Argc (cmd) == 1)
- {
- if (cmd->source == src_command)
- {
- Con_Printf("\"playerskin\" is \"%s\"\n", cl_playerskin.string);
- }
- return;
- }
-
- if (Cmd_Argc (cmd) == 2)
- strlcpy (newPath, Cmd_Argv(cmd, 1), sizeof (newPath));
- else
- strlcpy (newPath, Cmd_Args(cmd), sizeof (newPath));
-
- for (i = 0, j = 0;newPath[i];i++)
- if (newPath[i] != '\r' && newPath[i] != '\n')
- newPath[j++] = newPath[i];
- newPath[j] = 0;
-
- if (cmd->source == src_command)
- {
- Cvar_Set (&cvars_all, "_cl_playerskin", newPath);
- return;
- }
-
- /*
- if (realtime < host_client->nametime)
- {
- SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
- return;
- }
-
- 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));
- PRVM_serveredictstring(host_client->edict, playerskin) = PRVM_SetEngineString(prog, host_client->playerskin);
- if (strcmp(host_client->old_skin, host_client->playerskin))
- {
- //if (host_client->begun)
- // SV_BroadcastPrintf("%s changed skin to %s\n", host_client->name, host_client->playerskin);
- strlcpy(host_client->old_skin, host_client->playerskin, sizeof(host_client->old_skin));
- /*// send notification to all clients
- MSG_WriteByte (&sv.reliable_datagram, svc_updatepskin);
- MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
- MSG_WriteString (&sv.reliable_datagram, host_client->playerskin);*/
- }
-}
-
-static void Host_Version_f(cmd_state_t *cmd)
-{
- Con_Printf("Version: %s build %s\n", gamename, buildstring);
-}
-
-static void Host_Say(cmd_state_t *cmd, qboolean teamonly)
-{
- prvm_prog_t *prog = SVVM_prog;
- client_t *save;
- int j, quoted;
- const char *p1;
- char *p2;
- // LadyHavoc: long say messages
- char text[1024];
- qboolean fromServer = false;
-
- if (cmd->source == src_command)
- {
- if (cls.state == ca_dedicated)
- {
- fromServer = true;
- teamonly = false;
- }
- else
- {
- Cmd_ForwardToServer_f(cmd);
- return;
- }
- }
-
- if (Cmd_Argc (cmd) < 2)
- return;
-
- if (!teamplay.integer)
- teamonly = false;
-
- p1 = Cmd_Args(cmd);
- quoted = false;
- if (*p1 == '\"')
- {
- quoted = true;
- p1++;
- }
- // note this uses the chat prefix \001
- 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> %s", hostname.string, p1);
- p2 = text + strlen(text);
- while ((const char *)p2 > (const char *)text && (p2[-1] == '\r' || p2[-1] == '\n' || (p2[-1] == '\"' && quoted)))
- {
- if (p2[-1] == '\"' && quoted)
- quoted = false;
- p2[-1] = 0;
- p2--;
- }
- strlcat(text, "\n", sizeof(text));
-
- // 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->active && (!teamonly || PRVM_serveredictfloat(host_client->edict, team) == PRVM_serveredictfloat(save->edict, team)))
- SV_ClientPrint(text);
- host_client = save;
-
- if (cls.state == ca_dedicated)
- Con_Print(&text[1]);
-}
-
-
-static void Host_Say_f(cmd_state_t *cmd)
-{
- Host_Say(cmd, false);
-}
-
-
-static void Host_Say_Team_f(cmd_state_t *cmd)
-{
- Host_Say(cmd, true);
-}
-
-
-static void Host_Tell_f(cmd_state_t *cmd)
-{
- const char *playername_start = NULL;
- size_t playername_length = 0;
- int playernumber = 0;
- client_t *save;
- int j;
- const char *p1, *p2;
- char text[MAX_INPUTLINE]; // LadyHavoc: FIXME: temporary buffer overflow fix (was 64)
- qboolean fromServer = false;
-
- if (cmd->source == src_command)
- {
- if (cls.state == ca_dedicated)
- fromServer = true;
- else
- {
- Cmd_ForwardToServer_f(cmd);
- return;
- }
- }
-
- if (Cmd_Argc (cmd) < 2)
- return;
-
- // note this uses the chat prefix \001
- if (!fromServer)
- 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
- dpsnprintf (text, sizeof(text), "\001<%s tells you> ", hostname.string);
-
- p1 = Cmd_Args(cmd);
- p2 = p1 + strlen(p1);
- // remove the target name
- 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--;
- // remove quotes if present
- if (*p1 == '"')
- {
- p1++;
- if (p2[-1] == '"')
- p2--;
- else if (fromServer)
- Con_Print("Host_Tell: missing end quote\n");
- else
- SV_ClientPrint("Host_Tell: missing end quote\n");
- }
- 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;
- host_client = svs.clients + playernumber;
- SV_ClientPrint(text);
- host_client = save;
-}
-
-
-/*
-==================
-Host_Color_f
-==================
-*/
-cvar_t cl_color = {CVAR_CLIENT | CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_color", "0", "internal storage cvar for current player colors (changed by color command)"};
-static void Host_Color(cmd_state_t *cmd, int changetop, int changebottom)
-{
- prvm_prog_t *prog = SVVM_prog;
- int top, bottom, playercolor;
-
- // get top and bottom either from the provided values or the current values
- // (allows changing only top or bottom, or both at once)
- top = changetop >= 0 ? changetop : (cl_color.integer >> 4);
- bottom = changebottom >= 0 ? changebottom : cl_color.integer;
-
- top &= 15;
- bottom &= 15;
- // LadyHavoc: allowing skin colormaps 14 and 15 by commenting this out
- //if (top > 13)
- // top = 13;
- //if (bottom > 13)
- // bottom = 13;
-
- playercolor = top*16 + bottom;
-
- if (cmd->source == src_command)
- {
- Cvar_SetValueQuick(&cl_color, playercolor);
- return;
- }
-
- if (cls.protocol == PROTOCOL_QUAKEWORLD)
- return;
-
- if (host_client->edict && PRVM_serverfunction(SV_ChangeTeam))
- {
- Con_DPrint("Calling SV_ChangeTeam\n");
- prog->globals.fp[OFS_PARM0] = playercolor;
- PRVM_serverglobalfloat(time) = sv.time;
- PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict);
- prog->ExecuteProgram(prog, PRVM_serverfunction(SV_ChangeTeam), "QC function SV_ChangeTeam is missing");
- }
- else
- {
- if (host_client->edict)
- {
- PRVM_serveredictfloat(host_client->edict, clientcolors) = playercolor;
- PRVM_serveredictfloat(host_client->edict, team) = bottom + 1;
- }
- host_client->colors = playercolor;
- if (host_client->old_colors != host_client->colors)
- {
- host_client->old_colors = host_client->colors;
- // send notification to all clients
- MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
- MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
- MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
- }
- }
-}
-
-static void Host_Color_f(cmd_state_t *cmd)
-{
- int top, bottom;
-
- if (Cmd_Argc(cmd) == 1)
- {
- if (cmd->source == src_command)
- {
- Con_Printf("\"color\" is \"%i %i\"\n", cl_color.integer >> 4, cl_color.integer & 15);
- Con_Print("color <0-15> [0-15]\n");
- }
- return;
- }
-
- if (Cmd_Argc(cmd) == 2)
- top = bottom = atoi(Cmd_Argv(cmd, 1));
- else
- {
- top = atoi(Cmd_Argv(cmd, 1));
- bottom = atoi(Cmd_Argv(cmd, 2));
- }
- Host_Color(cmd, top, bottom);
-}
-
-static void Host_TopColor_f(cmd_state_t *cmd)
-{
- if (Cmd_Argc(cmd) == 1)
- {
- if (cmd->source == src_command)
- {
- Con_Printf("\"topcolor\" is \"%i\"\n", (cl_color.integer >> 4) & 15);
- Con_Print("topcolor <0-15>\n");
- }
- return;
- }
-
- Host_Color(cmd, atoi(Cmd_Argv(cmd, 1)), -1);
-}
-
-static void Host_BottomColor_f(cmd_state_t *cmd)
-{
- if (Cmd_Argc(cmd) == 1)
- {
- if (cmd->source == src_command)
- {
- Con_Printf("\"bottomcolor\" is \"%i\"\n", cl_color.integer & 15);
- Con_Print("bottomcolor <0-15>\n");
- }
- return;
- }
-
- Host_Color(cmd, -1, atoi(Cmd_Argv(cmd, 1)));
-}
-
-cvar_t cl_rate = {CVAR_CLIENT | CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_rate", "20000", "internal storage cvar for current rate (changed by rate command)"};
-cvar_t cl_rate_burstsize = {CVAR_CLIENT | CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_rate_burstsize", "1024", "internal storage cvar for current rate control burst size (changed by rate_burstsize command)"};
-static void Host_Rate_f(cmd_state_t *cmd)
-{
- int rate;
-
- if (Cmd_Argc(cmd) != 2)
- {
- if (cmd->source == src_command)
- {
- Con_Printf("\"rate\" is \"%i\"\n", cl_rate.integer);
- Con_Print("rate <bytespersecond>\n");
- }
- return;
- }
-
- rate = atoi(Cmd_Argv(cmd, 1));
-
- if (cmd->source == src_command)
- {
- Cvar_SetValue (&cvars_all, "_cl_rate", max(NET_MINRATE, rate));
- return;
- }
-
- host_client->rate = rate;
-}
-static void Host_Rate_BurstSize_f(cmd_state_t *cmd)
-{
- int rate_burstsize;
-
- if (Cmd_Argc(cmd) != 2)
- {
- Con_Printf("\"rate_burstsize\" is \"%i\"\n", cl_rate_burstsize.integer);
- Con_Print("rate_burstsize <bytes>\n");
- return;
- }
-
- rate_burstsize = atoi(Cmd_Argv(cmd, 1));
-
- if (cmd->source == src_command)
- {
- Cvar_SetValue (&cvars_all, "_cl_rate_burstsize", rate_burstsize);
- return;
- }
-
- host_client->rate_burstsize = rate_burstsize;
-}
-
-/*
-==================
-Host_Kill_f
-==================
-*/
-static void Host_Kill_f(cmd_state_t *cmd)
-{
- prvm_prog_t *prog = SVVM_prog;
- if (PRVM_serveredictfloat(host_client->edict, health) <= 0)
- {
- SV_ClientPrint("Can't suicide -- already dead!\n");
- return;
- }
-
- PRVM_serverglobalfloat(time) = sv.time;
- PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict);
- prog->ExecuteProgram(prog, PRVM_serverfunction(ClientKill), "QC function ClientKill is missing");
-}
-
-
-/*
-==================
-Host_Pause_f
-==================
-*/
-static void Host_Pause_f(cmd_state_t *cmd)
-{
- void (*print) (const char *fmt, ...);
- if (cmd->source == src_command)
- {
- // if running a client, try to send over network so the pause is handled by the server
- if (cls.state == ca_connected)
- {
- Cmd_ForwardToServer_f(cmd);
- return;
- }
- print = Con_Printf;
- }
- else
- print = SV_ClientPrintf;
-
- if (!pausable.integer)
- {
- if (cmd->source == src_client)
- {
- if(cls.state == ca_dedicated || host_client != &svs.clients[0]) // non-admin
- {
- print("Pause not allowed.\n");
- return;
- }
- }
- }
-
- sv.paused ^= 1;
- if (cmd->source != src_command)
- SV_BroadcastPrintf("%s %spaused the game\n", host_client->name, sv.paused ? "" : "un");
- else if(*(sv_adminnick.string))
- SV_BroadcastPrintf("%s %spaused the game\n", sv_adminnick.string, sv.paused ? "" : "un");
- else
- SV_BroadcastPrintf("%s %spaused the game\n", hostname.string, sv.paused ? "" : "un");
- // send notification to all clients
- MSG_WriteByte(&sv.reliable_datagram, svc_setpause);
- MSG_WriteByte(&sv.reliable_datagram, sv.paused);
-}