2 Copyright (C) 1996-1997 Id Software, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 cvar_t sv_cheats = {CF_SERVER | CF_NOTIFY, "sv_cheats", "0", "enables cheat commands in any game, and cheat impulses in dpmod"};
28 cvar_t sv_adminnick = {CF_SERVER | CF_ARCHIVE, "sv_adminnick", "", "nick name to use for admin messages instead of host name"};
29 cvar_t sv_status_privacy = {CF_SERVER | CF_ARCHIVE, "sv_status_privacy", "0", "do not show IP addresses in 'status' replies to clients"};
30 cvar_t sv_status_show_qcstatus = {CF_SERVER | CF_ARCHIVE, "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."};
31 cvar_t sv_namechangetimer = {CF_SERVER | CF_ARCHIVE, "sv_namechangetimer", "5", "how often to allow name changes, in seconds (prevents people from using animated names and other tricks"};
34 ===============================================================================
38 ===============================================================================
42 ======================
47 command from the console. Active clients are kicked off.
48 ======================
50 static void SV_Map_f(cmd_state_t *cmd)
52 char level[MAX_QPATH];
54 if (Cmd_Argc(cmd) != 2)
56 Con_Print("map <levelname> : start a new game (kicks off all players)\n");
60 // GAME_DELUXEQUAKE - clear warpmark (used by QC)
61 if (gamemode == GAME_DELUXEQUAKE)
62 Cvar_Set(&cvars_all, "warpmark", "");
64 cls.demonum = -1; // stop demo loop in case this fails
69 if(svs.maxclients != svs.maxclients_next)
71 svs.maxclients = svs.maxclients_next;
73 Mem_Free(svs.clients);
74 svs.clients = (client_t *)Mem_Alloc(sv_mempool, sizeof(client_t) * svs.maxclients);
79 if (key_dest == key_menu || key_dest == key_menu_grabbed)
84 svs.serverflags = 0; // haven't completed an episode yet
85 strlcpy(level, Cmd_Argv(cmd, 1), sizeof(level));
86 SV_SpawnServer(level);
88 if(sv.active && host.hook.ConnectLocal != NULL)
89 host.hook.ConnectLocal();
96 Goes to a new map, taking all clients along
99 static void SV_Changelevel_f(cmd_state_t *cmd)
101 char level[MAX_QPATH];
103 if (Cmd_Argc(cmd) != 2)
105 Con_Print("changelevel <levelname> : continue game on a new level\n");
111 Con_Printf("You must be running a server to changelevel. Use 'map %s' instead\n", Cmd_Argv(cmd, 1));
117 if (key_dest == key_menu || key_dest == key_menu_grabbed)
122 SV_SaveSpawnparms ();
123 strlcpy(level, Cmd_Argv(cmd, 1), sizeof(level));
124 SV_SpawnServer(level);
126 if(sv.active && host.hook.ConnectLocal != NULL)
127 host.hook.ConnectLocal();
134 Restarts the current server for a dead player
137 static void SV_Restart_f(cmd_state_t *cmd)
139 char mapname[MAX_QPATH];
141 if (Cmd_Argc(cmd) != 1)
143 Con_Print("restart : restart current level\n");
148 Con_Print("Only the server may restart\n");
154 if (key_dest == key_menu || key_dest == key_menu_grabbed)
159 strlcpy(mapname, sv.name, sizeof(mapname));
160 SV_SpawnServer(mapname);
162 if(sv.active && host.hook.ConnectLocal != NULL)
163 host.hook.ConnectLocal();
166 //===========================================================================
168 // Disable cheats if sv_cheats is turned off
169 static void SV_DisableCheats_c(cvar_t *var)
171 prvm_prog_t *prog = SVVM_prog;
176 while (svs.clients[i].edict)
178 if (((int)PRVM_serveredictfloat(svs.clients[i].edict, flags) & FL_GODMODE))
179 PRVM_serveredictfloat(svs.clients[i].edict, flags) = (int)PRVM_serveredictfloat(svs.clients[i].edict, flags) ^ FL_GODMODE;
180 if (((int)PRVM_serveredictfloat(svs.clients[i].edict, flags) & FL_NOTARGET))
181 PRVM_serveredictfloat(svs.clients[i].edict, flags) = (int)PRVM_serveredictfloat(svs.clients[i].edict, flags) ^ FL_NOTARGET;
182 if (PRVM_serveredictfloat(svs.clients[i].edict, movetype) == MOVETYPE_NOCLIP ||
183 PRVM_serveredictfloat(svs.clients[i].edict, movetype) == MOVETYPE_FLY)
185 noclip_anglehack = false;
186 PRVM_serveredictfloat(svs.clients[i].edict, movetype) = MOVETYPE_WALK;
197 Sets client to godmode
200 static void SV_God_f(cmd_state_t *cmd)
202 prvm_prog_t *prog = SVVM_prog;
204 PRVM_serveredictfloat(host_client->edict, flags) = (int)PRVM_serveredictfloat(host_client->edict, flags) ^ FL_GODMODE;
205 if (!((int)PRVM_serveredictfloat(host_client->edict, flags) & FL_GODMODE) )
206 SV_ClientPrint("godmode OFF\n");
208 SV_ClientPrint("godmode ON\n");
211 qbool noclip_anglehack;
213 static void SV_Noclip_f(cmd_state_t *cmd)
215 prvm_prog_t *prog = SVVM_prog;
217 if (PRVM_serveredictfloat(host_client->edict, movetype) != MOVETYPE_NOCLIP)
219 noclip_anglehack = true;
220 PRVM_serveredictfloat(host_client->edict, movetype) = MOVETYPE_NOCLIP;
221 SV_ClientPrint("noclip ON\n");
225 noclip_anglehack = false;
226 PRVM_serveredictfloat(host_client->edict, movetype) = MOVETYPE_WALK;
227 SV_ClientPrint("noclip OFF\n");
236 static void SV_Give_f(cmd_state_t *cmd)
238 prvm_prog_t *prog = SVVM_prog;
242 t = Cmd_Argv(cmd, 1);
243 v = atoi (Cmd_Argv(cmd, 2));
257 // MED 01/04/97 added hipnotic give stuff
258 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_QUOTH)
263 PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | HIT_PROXIMITY_GUN;
265 PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | IT_GRENADE_LAUNCHER;
267 else if (t[0] == '9')
268 PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | HIT_LASER_CANNON;
269 else if (t[0] == '0')
270 PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | HIT_MJOLNIR;
271 else if (t[0] >= '2')
272 PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | (IT_SHOTGUN << (t[0] - '2'));
277 PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | (IT_SHOTGUN << (t[0] - '2'));
282 if (gamemode == GAME_ROGUE)
283 PRVM_serveredictfloat(host_client->edict, ammo_shells1) = v;
285 PRVM_serveredictfloat(host_client->edict, ammo_shells) = v;
288 if (gamemode == GAME_ROGUE)
290 PRVM_serveredictfloat(host_client->edict, ammo_nails1) = v;
291 if (PRVM_serveredictfloat(host_client->edict, weapon) <= IT_LIGHTNING)
292 PRVM_serveredictfloat(host_client->edict, ammo_nails) = v;
296 PRVM_serveredictfloat(host_client->edict, ammo_nails) = v;
300 if (gamemode == GAME_ROGUE)
302 PRVM_serveredictfloat(host_client->edict, ammo_lava_nails) = v;
303 if (PRVM_serveredictfloat(host_client->edict, weapon) > IT_LIGHTNING)
304 PRVM_serveredictfloat(host_client->edict, ammo_nails) = v;
308 if (gamemode == GAME_ROGUE)
310 PRVM_serveredictfloat(host_client->edict, ammo_rockets1) = v;
311 if (PRVM_serveredictfloat(host_client->edict, weapon) <= IT_LIGHTNING)
312 PRVM_serveredictfloat(host_client->edict, ammo_rockets) = v;
316 PRVM_serveredictfloat(host_client->edict, ammo_rockets) = v;
320 if (gamemode == GAME_ROGUE)
322 PRVM_serveredictfloat(host_client->edict, ammo_multi_rockets) = v;
323 if (PRVM_serveredictfloat(host_client->edict, weapon) > IT_LIGHTNING)
324 PRVM_serveredictfloat(host_client->edict, ammo_rockets) = v;
328 PRVM_serveredictfloat(host_client->edict, health) = v;
331 if (gamemode == GAME_ROGUE)
333 PRVM_serveredictfloat(host_client->edict, ammo_cells1) = v;
334 if (PRVM_serveredictfloat(host_client->edict, weapon) <= IT_LIGHTNING)
335 PRVM_serveredictfloat(host_client->edict, ammo_cells) = v;
339 PRVM_serveredictfloat(host_client->edict, ammo_cells) = v;
343 if (gamemode == GAME_ROGUE)
345 PRVM_serveredictfloat(host_client->edict, ammo_plasma) = v;
346 if (PRVM_serveredictfloat(host_client->edict, weapon) > IT_LIGHTNING)
347 PRVM_serveredictfloat(host_client->edict, ammo_cells) = v;
357 Sets client to flymode
360 static void SV_Fly_f(cmd_state_t *cmd)
362 prvm_prog_t *prog = SVVM_prog;
364 if (PRVM_serveredictfloat(host_client->edict, movetype) != MOVETYPE_FLY)
366 PRVM_serveredictfloat(host_client->edict, movetype) = MOVETYPE_FLY;
367 SV_ClientPrint("flymode ON\n");
371 PRVM_serveredictfloat(host_client->edict, movetype) = MOVETYPE_WALK;
372 SV_ClientPrint("flymode OFF\n");
376 static void SV_Notarget_f(cmd_state_t *cmd)
378 prvm_prog_t *prog = SVVM_prog;
380 PRVM_serveredictfloat(host_client->edict, flags) = (int)PRVM_serveredictfloat(host_client->edict, flags) ^ FL_NOTARGET;
381 if (!((int)PRVM_serveredictfloat(host_client->edict, flags) & FL_NOTARGET) )
382 SV_ClientPrint("notarget OFF\n");
384 SV_ClientPrint("notarget ON\n");
392 static void SV_Kill_f(cmd_state_t *cmd)
394 prvm_prog_t *prog = SVVM_prog;
395 if (PRVM_serveredictfloat(host_client->edict, health) <= 0)
397 SV_ClientPrint("Can't suicide -- already dead!\n");
401 PRVM_serverglobalfloat(time) = sv.time;
402 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict);
403 prog->ExecuteProgram(prog, PRVM_serverfunction(ClientKill), "QC function ClientKill is missing");
411 static void SV_Pause_f(cmd_state_t *cmd)
413 void (*print) (const char *fmt, ...);
414 if (cmd->source == src_local)
417 print = SV_ClientPrintf;
419 if (!pausable.integer && cmd->source == src_client && LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) != LHNETADDRESSTYPE_LOOP)
421 print("Pause not allowed.\n");
426 if (cmd->source != src_local)
427 SV_BroadcastPrintf("%s %spaused the game\n", host_client->name, sv.paused ? "" : "un");
428 else if(*(sv_adminnick.string))
429 SV_BroadcastPrintf("%s %spaused the game\n", sv_adminnick.string, sv.paused ? "" : "un");
431 SV_BroadcastPrintf("%s %spaused the game\n", hostname.string, sv.paused ? "" : "un");
432 // send notification to all clients
433 MSG_WriteByte(&sv.reliable_datagram, svc_setpause);
434 MSG_WriteByte(&sv.reliable_datagram, sv.paused);
437 static void SV_Say(cmd_state_t *cmd, qbool teamonly)
439 prvm_prog_t *prog = SVVM_prog;
444 // LadyHavoc: long say messages
446 qbool fromServer = false;
448 if (cmd->source == src_local)
454 if (Cmd_Argc (cmd) < 2)
457 if (!teamplay.integer)
467 // note this uses the chat prefix \001
468 if (!fromServer && !teamonly)
469 dpsnprintf (text, sizeof(text), "\001%s: %s", host_client->name, p1);
470 else if (!fromServer && teamonly)
471 dpsnprintf (text, sizeof(text), "\001(%s): %s", host_client->name, p1);
472 else if(*(sv_adminnick.string))
473 dpsnprintf (text, sizeof(text), "\001<%s> %s", sv_adminnick.string, p1);
475 dpsnprintf (text, sizeof(text), "\001<%s> %s", hostname.string, p1);
476 p2 = text + strlen(text);
477 while ((const char *)p2 > (const char *)text && (p2[-1] == '\r' || p2[-1] == '\n' || (p2[-1] == '\"' && quoted)))
479 if (p2[-1] == '\"' && quoted)
484 strlcat(text, "\n", sizeof(text));
486 // note: save is not a valid edict if fromServer is true
488 for (j = 0, host_client = svs.clients;j < svs.maxclients;j++, host_client++)
489 if (host_client->active && (!teamonly || PRVM_serveredictfloat(host_client->edict, team) == PRVM_serveredictfloat(save->edict, team)))
490 SV_ClientPrint(text);
493 if(!host_isclient.integer)
497 static void SV_Say_f(cmd_state_t *cmd)
502 static void SV_Say_Team_f(cmd_state_t *cmd)
507 static void SV_Tell_f(cmd_state_t *cmd)
509 const char *playername_start = NULL;
510 size_t playername_length = 0;
511 int playernumber = 0;
515 char text[MAX_INPUTLINE]; // LadyHavoc: FIXME: temporary buffer overflow fix (was 64)
516 qbool fromServer = false;
518 if (cmd->source == src_local)
521 if (Cmd_Argc (cmd) < 2)
524 // note this uses the chat prefix \001
526 dpsnprintf (text, sizeof(text), "\001%s tells you: ", host_client->name);
527 else if(*(sv_adminnick.string))
528 dpsnprintf (text, sizeof(text), "\001<%s tells you> ", sv_adminnick.string);
530 dpsnprintf (text, sizeof(text), "\001<%s tells you> ", hostname.string);
533 p2 = p1 + strlen(p1);
534 // remove the target name
535 while (p1 < p2 && *p1 == ' ')
540 while (p1 < p2 && *p1 == ' ')
542 while (p1 < p2 && isdigit(*p1))
544 playernumber = playernumber * 10 + (*p1 - '0');
552 playername_start = p1;
553 while (p1 < p2 && *p1 != '"')
555 playername_length = p1 - playername_start;
561 playername_start = p1;
562 while (p1 < p2 && *p1 != ' ')
564 playername_length = p1 - playername_start;
566 while (p1 < p2 && *p1 == ' ')
570 // set playernumber to the right client
572 if(playername_length >= sizeof(namebuf))
575 Con_Print("Host_Tell: too long player name/ID\n");
577 SV_ClientPrint("Host_Tell: too long player name/ID\n");
580 memcpy(namebuf, playername_start, playername_length);
581 namebuf[playername_length] = 0;
582 for (playernumber = 0; playernumber < svs.maxclients; playernumber++)
584 if (!svs.clients[playernumber].active)
586 if (strcasecmp(svs.clients[playernumber].name, namebuf) == 0)
590 if(playernumber < 0 || playernumber >= svs.maxclients || !(svs.clients[playernumber].active))
593 Con_Print("Host_Tell: invalid player name/ID\n");
595 SV_ClientPrint("Host_Tell: invalid player name/ID\n");
598 // remove trailing newlines
599 while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
601 // remove quotes if present
608 Con_Print("Host_Tell: missing end quote\n");
610 SV_ClientPrint("Host_Tell: missing end quote\n");
612 while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
616 for (j = (int)strlen(text);j < (int)(sizeof(text) - 2) && p1 < p2;)
622 host_client = svs.clients + playernumber;
623 SV_ClientPrint(text);
633 static void SV_Ping_f(cmd_state_t *cmd)
637 void (*print) (const char *fmt, ...);
639 if (cmd->source == src_local)
642 print = SV_ClientPrintf;
647 print("Client ping times:\n");
648 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
652 print("%4i %s\n", bound(0, (int)floor(client->ping*1000+0.5), 9999), client->name);
660 Send back ping and packet loss update for all current players to this player
663 static void SV_Pings_f(cmd_state_t *cmd)
665 int i, j, ping, packetloss, movementloss;
668 if (!host_client->netconnection)
671 if (sv.protocol != PROTOCOL_QUAKEWORLD)
673 MSG_WriteByte(&host_client->netconnection->message, svc_stufftext);
674 MSG_WriteUnterminatedString(&host_client->netconnection->message, "pingplreport");
676 for (i = 0;i < svs.maxclients;i++)
680 if (svs.clients[i].netconnection)
682 for (j = 0;j < NETGRAPH_PACKETS;j++)
683 if (svs.clients[i].netconnection->incoming_netgraph[j].unreliablebytes == NETGRAPH_LOSTPACKET)
685 for (j = 0;j < NETGRAPH_PACKETS;j++)
686 if (svs.clients[i].movement_count[j] < 0)
689 packetloss = (packetloss * 100 + NETGRAPH_PACKETS - 1) / NETGRAPH_PACKETS;
690 movementloss = (movementloss * 100 + NETGRAPH_PACKETS - 1) / NETGRAPH_PACKETS;
691 ping = (int)floor(svs.clients[i].ping*1000+0.5);
692 ping = bound(0, ping, 9999);
693 if (sv.protocol == PROTOCOL_QUAKEWORLD)
695 // send qw_svc_updateping and qw_svc_updatepl messages
696 MSG_WriteByte(&host_client->netconnection->message, qw_svc_updateping);
697 MSG_WriteShort(&host_client->netconnection->message, ping);
698 MSG_WriteByte(&host_client->netconnection->message, qw_svc_updatepl);
699 MSG_WriteByte(&host_client->netconnection->message, packetloss);
703 // write the string into the packet as multiple unterminated strings to avoid needing a local buffer
705 dpsnprintf(temp, sizeof(temp), " %d %d,%d", ping, packetloss, movementloss);
707 dpsnprintf(temp, sizeof(temp), " %d %d", ping, packetloss);
708 MSG_WriteUnterminatedString(&host_client->netconnection->message, temp);
711 if (sv.protocol != PROTOCOL_QUAKEWORLD)
712 MSG_WriteString(&host_client->netconnection->message, "\n");
719 user <name or userid>
721 Dump userdata / masterdata for a user
724 static void SV_User_f(cmd_state_t *cmd) // credit: taken from QuakeWorld
729 if (Cmd_Argc(cmd) != 2)
731 Con_Printf ("Usage: user <username / userid>\n");
735 uid = atoi(Cmd_Argv(cmd, 1));
737 for (i = 0;i < cl.maxclients;i++)
739 if (!cl.scores[i].name[0])
741 if (cl.scores[i].qw_userid == uid || !strcasecmp(cl.scores[i].name, Cmd_Argv(cmd, 1)))
743 InfoString_Print(cl.scores[i].qw_userinfo);
747 Con_Printf ("User not in server.\n");
754 Dump userids for all current players
757 static void SV_Users_f(cmd_state_t *cmd) // credit: taken from QuakeWorld
763 Con_Printf ("userid frags name\n");
764 Con_Printf ("------ ----- ----\n");
765 for (i = 0;i < cl.maxclients;i++)
767 if (cl.scores[i].name[0])
769 Con_Printf ("%6i %4i %s\n", cl.scores[i].qw_userid, cl.scores[i].frags, cl.scores[i].name);
774 Con_Printf ("%i total users\n", c);
782 static void SV_Status_f(cmd_state_t *cmd)
784 prvm_prog_t *prog = SVVM_prog;
787 int seconds = 0, minutes = 0, hours = 0, i, j, k, in, players, ping = 0, packetloss = 0;
788 void (*print) (const char *fmt, ...);
789 char ip[48]; // can contain a full length v6 address with [] and a port
793 if (cmd->source == src_local)
796 print = SV_ClientPrintf;
802 if (Cmd_Argc(cmd) == 2)
804 if (strcmp(Cmd_Argv(cmd, 1), "1") == 0)
806 else if (strcmp(Cmd_Argv(cmd, 1), "2") == 0)
810 for (players = 0, i = 0;i < svs.maxclients;i++)
811 if (svs.clients[i].active)
813 print ("host: %s\n", Cvar_VariableString (&cvars_all, "hostname", CF_SERVER));
814 print ("version: %s build %s (gamename %s)\n", gamename, buildstring, gamenetworkfiltername);
815 print ("protocol: %i (%s)\n", Protocol_NumberForEnum(sv.protocol), Protocol_NameForEnum(sv.protocol));
816 print ("map: %s\n", sv.name);
817 print ("timing: %s\n", Host_TimingReport(vabuf, sizeof(vabuf)));
818 print ("players: %i active (%i max)\n\n", players, svs.maxclients);
821 print ("^2IP %%pl ping time frags no name\n");
823 print ("^5IP no name\n");
825 for (i = 0, k = 0, client = svs.clients;i < svs.maxclients;i++, client++)
832 if (in == 0 || in == 1)
834 seconds = (int)(host.realtime - client->connecttime);
835 minutes = seconds / 60;
838 seconds -= (minutes * 60);
839 hours = minutes / 60;
841 minutes -= (hours * 60);
847 if (client->netconnection)
848 for (j = 0;j < NETGRAPH_PACKETS;j++)
849 if (client->netconnection->incoming_netgraph[j].unreliablebytes == NETGRAPH_LOSTPACKET)
851 packetloss = (packetloss * 100 + NETGRAPH_PACKETS - 1) / NETGRAPH_PACKETS;
852 ping = bound(0, (int)floor(client->ping*1000+0.5), 9999);
855 if(sv_status_privacy.integer && cmd->source != src_local && LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) != LHNETADDRESSTYPE_LOOP)
856 strlcpy(ip, client->netconnection ? "hidden" : "botclient", 48);
858 strlcpy(ip, (client->netconnection && *client->netconnection->address) ? client->netconnection->address : "botclient", 48);
860 frags = client->frags;
862 if(sv_status_show_qcstatus.integer)
864 prvm_edict_t *ed = PRVM_EDICT_NUM(i + 1);
865 const char *str = PRVM_GetString(prog, PRVM_serveredictstring(ed, clientstatus));
871 for(q = str; *q && p != qcstatus + sizeof(qcstatus) - 1; ++q)
872 if(*q != '\\' && *q != '"' && !ISWHITESPACE(*q))
876 frags = atoi(qcstatus);
880 if (in == 0) // default layout
882 if (sv.protocol == PROTOCOL_QUAKE && svs.maxclients <= 99)
884 // LadyHavoc: this is very touchy because we must maintain ProQuake compatible status output
885 print ("#%-2u %-16.16s %3i %2i:%02i:%02i\n", i+1, client->name, frags, hours, minutes, seconds);
890 // LadyHavoc: no real restrictions here, not a ProQuake-compatible protocol anyway...
891 print ("#%-3u %-16.16s %4i %2i:%02i:%02i\n", i+1, client->name, frags, hours, minutes, seconds);
895 else if (in == 1) // extended layout
897 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);
899 else if (in == 2) // reduced layout
901 print ("%s%-47s #%-3u ^7%s\n", k%2 ? "^3" : "^7", ip, i+1, client->name);
906 void SV_Name(int clientnum)
908 prvm_prog_t *prog = SVVM_prog;
909 PRVM_serveredictstring(host_client->edict, netname) = PRVM_SetEngineString(prog, host_client->name);
910 if (strcmp(host_client->old_name, host_client->name))
912 if (host_client->begun)
913 SV_BroadcastPrintf("\003%s ^7changed name to ^3%s\n", host_client->old_name, host_client->name);
914 strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
915 // send notification to all clients
916 MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
917 MSG_WriteByte (&sv.reliable_datagram, clientnum);
918 MSG_WriteString (&sv.reliable_datagram, host_client->name);
919 SV_WriteNetnameIntoDemo(host_client);
924 ======================
926 ======================
928 static void SV_Name_f(cmd_state_t *cmd)
932 const char *newNameSource;
933 char newName[sizeof(host_client->name)];
935 if (Cmd_Argc (cmd) == 1)
938 if (Cmd_Argc (cmd) == 2)
939 newNameSource = Cmd_Argv(cmd, 1);
941 newNameSource = Cmd_Args(cmd);
943 strlcpy(newName, newNameSource, sizeof(newName));
945 if (cmd->source == src_local)
948 if (host.realtime < host_client->nametime && strcmp(newName, host_client->name))
950 SV_ClientPrintf("You can't change name more than once every %.1f seconds!\n", max(0.0f, sv_namechangetimer.value));
954 host_client->nametime = host.realtime + max(0.0f, sv_namechangetimer.value);
956 // point the string back at updateclient->name to keep it safe
957 strlcpy (host_client->name, newName, sizeof (host_client->name));
959 for (i = 0, j = 0;host_client->name[i];i++)
960 if (host_client->name[i] != '\r' && host_client->name[i] != '\n')
961 host_client->name[j++] = host_client->name[i];
962 host_client->name[j] = 0;
964 if(host_client->name[0] == 1 || host_client->name[0] == 2)
965 // may interfere with chat area, and will needlessly beep; so let's add a ^7
967 memmove(host_client->name + 2, host_client->name, sizeof(host_client->name) - 2);
968 host_client->name[sizeof(host_client->name) - 1] = 0;
969 host_client->name[0] = STRING_COLOR_TAG;
970 host_client->name[1] = '0' + STRING_COLOR_DEFAULT;
973 u8_COM_StringLengthNoColors(host_client->name, 0, &valid_colors);
974 if(!valid_colors) // NOTE: this also proves the string is not empty, as "" is a valid colored string
977 l = strlen(host_client->name);
978 if(l < sizeof(host_client->name) - 1)
980 // duplicate the color tag to escape it
981 host_client->name[i] = STRING_COLOR_TAG;
982 host_client->name[i+1] = 0;
983 //Con_DPrintf("abuse detected, adding another trailing color tag\n");
987 // remove the last character to fix the color code
988 host_client->name[l-1] = 0;
989 //Con_DPrintf("abuse detected, removing a trailing color tag\n");
993 // find the last color tag offset and decide if we need to add a reset tag
994 for (i = 0, j = -1;host_client->name[i];i++)
996 if (host_client->name[i] == STRING_COLOR_TAG)
998 if (host_client->name[i+1] >= '0' && host_client->name[i+1] <= '9')
1001 // if this happens to be a reset tag then we don't need one
1002 if (host_client->name[i+1] == '0' + STRING_COLOR_DEFAULT)
1007 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]))
1013 if (host_client->name[i+1] == STRING_COLOR_TAG)
1020 // does not end in the default color string, so add it
1021 if (j >= 0 && strlen(host_client->name) < sizeof(host_client->name) - 2)
1022 memcpy(host_client->name + strlen(host_client->name), STRING_COLOR_DEFAULT_STR, strlen(STRING_COLOR_DEFAULT_STR) + 1);
1024 SV_Name(host_client - svs.clients);
1027 static void SV_Rate_f(cmd_state_t *cmd)
1031 rate = atoi(Cmd_Argv(cmd, 1));
1033 if (cmd->source == src_local)
1036 host_client->rate = rate;
1039 static void SV_Rate_BurstSize_f(cmd_state_t *cmd)
1043 if (Cmd_Argc(cmd) != 2)
1046 rate_burstsize = atoi(Cmd_Argv(cmd, 1));
1048 host_client->rate_burstsize = rate_burstsize;
1051 static void SV_Color_f(cmd_state_t *cmd)
1053 prvm_prog_t *prog = SVVM_prog;
1055 int top, bottom, playercolor;
1057 top = atoi(Cmd_Argv(cmd, 1));
1058 bottom = atoi(Cmd_Argv(cmd, 2));
1063 playercolor = top*16 + bottom;
1065 if (host_client->edict && PRVM_serverfunction(SV_ChangeTeam))
1067 Con_DPrint("Calling SV_ChangeTeam\n");
1068 prog->globals.fp[OFS_PARM0] = playercolor;
1069 PRVM_serverglobalfloat(time) = sv.time;
1070 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict);
1071 prog->ExecuteProgram(prog, PRVM_serverfunction(SV_ChangeTeam), "QC function SV_ChangeTeam is missing");
1075 if (host_client->edict)
1077 PRVM_serveredictfloat(host_client->edict, clientcolors) = playercolor;
1078 PRVM_serveredictfloat(host_client->edict, team) = bottom + 1;
1080 host_client->colors = playercolor;
1081 if (host_client->old_colors != host_client->colors)
1083 host_client->old_colors = host_client->colors;
1084 // send notification to all clients
1085 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1086 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1087 MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1096 Kicks a user off of the server
1099 static void SV_Kick_f(cmd_state_t *cmd)
1102 const char *message = NULL;
1105 qbool byNumber = false;
1112 if (Cmd_Argc(cmd) > 2 && strcmp(Cmd_Argv(cmd, 1), "#") == 0)
1114 i = (int)(atof(Cmd_Argv(cmd, 2)) - 1);
1115 if (i < 0 || i >= svs.maxclients || !(host_client = svs.clients + i)->active)
1121 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1123 if (!host_client->active)
1125 if (strcasecmp(host_client->name, Cmd_Argv(cmd, 1)) == 0)
1130 if (i < svs.maxclients)
1132 if (cmd->source == src_local)
1134 if(!host_isclient.integer)
1137 who = cl_name.string;
1142 // can't kick yourself!
1143 if (host_client == save)
1146 if (Cmd_Argc(cmd) > 2)
1148 message = Cmd_Args(cmd);
1149 COM_ParseToken_Simple(&message, false, false, true);
1152 message++; // skip the #
1153 while (*message == ' ') // skip white space
1155 message += strlen(Cmd_Argv(cmd, 2)); // skip the number
1157 while (*message && *message == ' ')
1161 SV_ClientPrintf("Kicked by %s: %s\n", who, message);
1163 SV_ClientPrintf("Kicked by %s\n", who);
1164 SV_DropClient (false); // kicked
1170 static void SV_MaxPlayers_f(cmd_state_t *cmd)
1174 if (Cmd_Argc(cmd) != 2)
1176 Con_Printf("\"maxplayers\" is \"%u\"\n", svs.maxclients_next);
1182 Con_Print("maxplayers can not be changed while a server is running.\n");
1183 Con_Print("It will be changed on next server startup (\"map\" command).\n");
1186 n = atoi(Cmd_Argv(cmd, 1));
1187 n = bound(1, n, MAX_SCOREBOARD);
1188 Con_Printf("\"maxplayers\" set to \"%u\"\n", n);
1190 svs.maxclients_next = n;
1192 Cvar_Set (&cvars_all, "deathmatch", "0");
1194 Cvar_Set (&cvars_all, "deathmatch", "1");
1198 ======================
1200 ======================
1202 // the old playermodel in cl_main has been renamed to __cl_playermodel
1203 static void SV_Playermodel_f(cmd_state_t *cmd)
1205 prvm_prog_t *prog = SVVM_prog;
1207 char newPath[sizeof(host_client->playermodel)];
1209 if (Cmd_Argc (cmd) == 1)
1212 if (Cmd_Argc (cmd) == 2)
1213 strlcpy (newPath, Cmd_Argv(cmd, 1), sizeof (newPath));
1215 strlcpy (newPath, Cmd_Args(cmd), sizeof (newPath));
1217 for (i = 0, j = 0;newPath[i];i++)
1218 if (newPath[i] != '\r' && newPath[i] != '\n')
1219 newPath[j++] = newPath[i];
1223 if (host.realtime < host_client->nametime)
1225 SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
1229 host_client->nametime = host.realtime + 5;
1232 // point the string back at updateclient->name to keep it safe
1233 strlcpy (host_client->playermodel, newPath, sizeof (host_client->playermodel));
1234 PRVM_serveredictstring(host_client->edict, playermodel) = PRVM_SetEngineString(prog, host_client->playermodel);
1235 if (strcmp(host_client->old_model, host_client->playermodel))
1237 strlcpy(host_client->old_model, host_client->playermodel, sizeof(host_client->old_model));
1238 /*// send notification to all clients
1239 MSG_WriteByte (&sv.reliable_datagram, svc_updatepmodel);
1240 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1241 MSG_WriteString (&sv.reliable_datagram, host_client->playermodel);*/
1246 ======================
1248 ======================
1250 static void SV_Playerskin_f(cmd_state_t *cmd)
1252 prvm_prog_t *prog = SVVM_prog;
1254 char newPath[sizeof(host_client->playerskin)];
1256 if (Cmd_Argc (cmd) == 1)
1259 if (Cmd_Argc (cmd) == 2)
1260 strlcpy (newPath, Cmd_Argv(cmd, 1), sizeof (newPath));
1262 strlcpy (newPath, Cmd_Args(cmd), sizeof (newPath));
1264 for (i = 0, j = 0;newPath[i];i++)
1265 if (newPath[i] != '\r' && newPath[i] != '\n')
1266 newPath[j++] = newPath[i];
1270 if (host.realtime < host_client->nametime)
1272 SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
1276 host_client->nametime = host.realtime + 5;
1279 // point the string back at updateclient->name to keep it safe
1280 strlcpy (host_client->playerskin, newPath, sizeof (host_client->playerskin));
1281 PRVM_serveredictstring(host_client->edict, playerskin) = PRVM_SetEngineString(prog, host_client->playerskin);
1282 if (strcmp(host_client->old_skin, host_client->playerskin))
1284 //if (host_client->begun)
1285 // SV_BroadcastPrintf("%s changed skin to %s\n", host_client->name, host_client->playerskin);
1286 strlcpy(host_client->old_skin, host_client->playerskin, sizeof(host_client->old_skin));
1287 /*// send notification to all clients
1288 MSG_WriteByte (&sv.reliable_datagram, svc_updatepskin);
1289 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1290 MSG_WriteString (&sv.reliable_datagram, host_client->playerskin);*/
1295 ======================
1297 LadyHavoc: only supported for Nehahra, I personally think this is dumb, but Mindcrime won't listen.
1298 LadyHavoc: correction, Mindcrime will be removing pmodel in the future, but it's still stuck here for compatibility.
1299 ======================
1301 static void SV_PModel_f(cmd_state_t *cmd)
1303 prvm_prog_t *prog = SVVM_prog;
1305 if (Cmd_Argc (cmd) == 1)
1308 PRVM_serveredictfloat(host_client->edict, pmodel) = atoi(Cmd_Argv(cmd, 1));
1312 ===============================================================================
1316 ===============================================================================
1319 static prvm_edict_t *FindViewthing(prvm_prog_t *prog)
1324 for (i=0 ; i<prog->num_edicts ; i++)
1326 e = PRVM_EDICT_NUM(i);
1327 if (!strcmp (PRVM_GetString(prog, PRVM_serveredictstring(e, classname)), "viewthing"))
1330 Con_Print("No viewthing on map\n");
1339 static void SV_Viewmodel_f(cmd_state_t *cmd)
1341 prvm_prog_t *prog = SVVM_prog;
1348 e = FindViewthing(prog);
1351 m = Mod_ForName (Cmd_Argv(cmd, 1), false, true, NULL);
1352 if (m && m->loaded && m->Draw)
1354 PRVM_serveredictfloat(e, frame) = 0;
1355 cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)] = m;
1358 Con_Printf("viewmodel: can't load %s\n", Cmd_Argv(cmd, 1));
1367 static void SV_Viewframe_f(cmd_state_t *cmd)
1369 prvm_prog_t *prog = SVVM_prog;
1377 e = FindViewthing(prog);
1380 m = cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)];
1382 f = atoi(Cmd_Argv(cmd, 1));
1383 if (f >= m->numframes)
1386 PRVM_serveredictfloat(e, frame) = f;
1390 static void PrintFrameName (dp_model_t *m, int frame)
1393 Con_Printf("frame %i: %s\n", frame, m->animscenes[frame].name);
1395 Con_Printf("frame %i\n", frame);
1403 static void SV_Viewnext_f(cmd_state_t *cmd)
1405 prvm_prog_t *prog = SVVM_prog;
1412 e = FindViewthing(prog);
1415 m = cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)];
1417 PRVM_serveredictfloat(e, frame) = PRVM_serveredictfloat(e, frame) + 1;
1418 if (PRVM_serveredictfloat(e, frame) >= m->numframes)
1419 PRVM_serveredictfloat(e, frame) = m->numframes - 1;
1421 PrintFrameName (m, (int)PRVM_serveredictfloat(e, frame));
1430 static void SV_Viewprev_f(cmd_state_t *cmd)
1432 prvm_prog_t *prog = SVVM_prog;
1439 e = FindViewthing(prog);
1442 m = cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)];
1444 PRVM_serveredictfloat(e, frame) = PRVM_serveredictfloat(e, frame) - 1;
1445 if (PRVM_serveredictfloat(e, frame) < 0)
1446 PRVM_serveredictfloat(e, frame) = 0;
1448 PrintFrameName (m, (int)PRVM_serveredictfloat(e, frame));
1452 static void SV_SendCvar_f(cmd_state_t *cmd)
1455 const char *cvarname;
1458 if(Cmd_Argc(cmd) != 2)
1461 if(!sv.active)// || !PRVM_serverfunction(SV_ParseClientCommand))
1464 cvarname = Cmd_Argv(cmd, 1);
1467 if(host_isclient.integer)
1471 for(;i<svs.maxclients;i++)
1472 if(svs.clients[i].active && svs.clients[i].netconnection)
1474 host_client = &svs.clients[i];
1475 SV_ClientCommands("sendcvar %s\n", cvarname);
1480 static void SV_Ent_Create_f(cmd_state_t *cmd)
1482 prvm_prog_t *prog = SVVM_prog;
1488 qbool expectval = false;
1489 void (*print)(const char *, ...) = (cmd->source == src_client ? SV_ClientPrintf : Con_Printf);
1494 ed = PRVM_ED_Alloc(SVVM_prog);
1496 PRVM_ED_ParseEpair(prog, ed, PRVM_ED_FindField(prog, "classname"), Cmd_Argv(cmd, 1), false);
1498 // Spawn where the player is aiming. We need a view matrix first.
1499 if(cmd->source == src_client)
1501 vec3_t org, temp, dest;
1506 SV_GetEntityMatrix(prog, host_client->edict, &view, true);
1508 Matrix4x4_OriginFromMatrix(&view, org);
1509 VectorSet(temp, 65536, 0, 0);
1510 Matrix4x4_Transform(&view, temp, dest);
1512 trace = SV_TraceLine(org, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, 0, 0, collision_extendmovelength.value);
1514 dpsnprintf(buf, sizeof(buf), "%g %g %g", trace.endpos[0], trace.endpos[1], trace.endpos[2]);
1515 PRVM_ED_ParseEpair(prog, ed, PRVM_ED_FindField(prog, "origin"), buf, false);
1519 // Or spawn at a specified origin.
1526 // Allow more than one key/value pair by cycling between expecting either one.
1527 for(i = 2; i < Cmd_Argc(cmd); i++)
1531 if(!(key = PRVM_ED_FindField(prog, Cmd_Argv(cmd, i))))
1533 print("Key %s not found!\n", Cmd_Argv(cmd, i));
1534 PRVM_ED_Free(prog, ed);
1539 * This is mostly for dedicated server console, but if the
1540 * player gave a custom origin, we can ignore the traceline.
1542 if(!strcmp(Cmd_Argv(cmd, i), "origin"))
1549 PRVM_ED_ParseEpair(prog, ed, key, Cmd_Argv(cmd, i), false);
1556 print("Missing origin\n");
1557 PRVM_ED_Free(prog, ed);
1562 PRVM_ED_CallPrespawnFunction(prog, ed);
1564 if(!PRVM_ED_CallSpawnFunction(prog, ed, NULL, NULL))
1566 print("Could not spawn a \"%s\". No such entity or it has no spawn function\n", Cmd_Argv(cmd, 1));
1567 if(cmd->source == src_client)
1568 Con_Printf("%s tried to spawn a \"%s\"\n", host_client->name, Cmd_Argv(cmd, 1));
1569 // CallSpawnFunction already freed the edict for us.
1573 PRVM_ED_CallPostspawnFunction(prog, ed);
1575 // Make it appear in the world
1578 if(cmd->source == src_client)
1579 Con_Printf("%s spawned a \"%s\"\n", host_client->name, Cmd_Argv(cmd, 1));
1582 static void SV_Ent_Remove_f(cmd_state_t *cmd)
1584 prvm_prog_t *prog = SVVM_prog;
1587 void (*print)(const char *, ...) = (cmd->source == src_client ? SV_ClientPrintf : Con_Printf);
1592 // Allow specifying edict by number
1593 if(Cmd_Argc(cmd) > 1 && Cmd_Argv(cmd, 1))
1595 ednum = atoi(Cmd_Argv(cmd, 1));
1598 print("Cannot remove the world\n");
1602 // Or trace a line if it's a client who didn't specify one.
1603 else if(cmd->source == src_client)
1605 vec3_t org, temp, dest;
1609 SV_GetEntityMatrix(prog, host_client->edict, &view, true);
1611 Matrix4x4_OriginFromMatrix(&view, org);
1612 VectorSet(temp, 65536, 0, 0);
1613 Matrix4x4_Transform(&view, temp, dest);
1615 trace = SV_TraceLine(org, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY, 0, 0, collision_extendmovelength.value);
1618 ednum = (int)PRVM_EDICT_TO_PROG(trace.ent);
1619 if(!trace.ent || !ednum)
1620 // Don't remove the world, but don't annoy players with a print if they miss
1625 // Only a dedicated server console should be able to reach this.
1626 print("No edict given\n");
1630 ed = PRVM_EDICT_NUM(ednum);
1635 for (i = 0; i < svs.maxclients; i++)
1637 if(ed == svs.clients[i].edict)
1641 if(!ed->priv.required->free)
1643 print("Removed a \"%s\"\n", PRVM_GetString(prog, PRVM_serveredictstring(ed, classname)));
1644 PRVM_ED_ClearEdict(prog, ed);
1645 PRVM_ED_Free(prog, ed);
1650 // This should only be reachable if an invalid edict number was given
1651 print("No such entity\n");
1656 static void SV_Ent_Remove_All_f(cmd_state_t *cmd)
1658 prvm_prog_t *prog = SVVM_prog;
1661 void (*print)(const char *, ...) = (cmd->source == src_client ? SV_ClientPrintf : Con_Printf);
1663 for (i = 0, rmcount = 0, ed = PRVM_EDICT_NUM(i); i < prog->num_edicts; i++, ed = PRVM_NEXT_EDICT(ed))
1665 if(!ed->priv.required->free && !strcmp(PRVM_GetString(prog, PRVM_serveredictstring(ed, classname)), Cmd_Argv(cmd, 1)))
1669 print("Cannot remove the world\n");
1672 PRVM_ED_ClearEdict(prog, ed);
1673 PRVM_ED_Free(prog, ed);
1679 print("No \"%s\" found\n", Cmd_Argv(cmd, 1));
1681 print("Removed %i of \"%s\"\n", rmcount, Cmd_Argv(cmd, 1));
1684 void SV_InitOperatorCommands(void)
1686 Cvar_RegisterVariable(&sv_cheats);
1687 Cvar_RegisterCallback(&sv_cheats, SV_DisableCheats_c);
1688 Cvar_RegisterVariable(&sv_adminnick);
1689 Cvar_RegisterVariable(&sv_status_privacy);
1690 Cvar_RegisterVariable(&sv_status_show_qcstatus);
1691 Cvar_RegisterVariable(&sv_namechangetimer);
1693 Cmd_AddCommand(CF_SERVER | CF_SERVER_FROM_CLIENT, "status", SV_Status_f, "print server status information");
1694 Cmd_AddCommand(CF_SHARED, "map", SV_Map_f, "kick everyone off the server and start a new level");
1695 Cmd_AddCommand(CF_SHARED, "restart", SV_Restart_f, "restart current level");
1696 Cmd_AddCommand(CF_SHARED, "changelevel", SV_Changelevel_f, "change to another level, bringing along all connected clients");
1697 Cmd_AddCommand(CF_SHARED | CF_SERVER_FROM_CLIENT, "say", SV_Say_f, "send a chat message to everyone on the server");
1698 Cmd_AddCommand(CF_SERVER_FROM_CLIENT, "say_team", SV_Say_Team_f, "send a chat message to your team on the server");
1699 Cmd_AddCommand(CF_SHARED | CF_SERVER_FROM_CLIENT, "tell", SV_Tell_f, "send a chat message to only one person on the server");
1700 Cmd_AddCommand(CF_SERVER | CF_SERVER_FROM_CLIENT, "pause", SV_Pause_f, "pause the game (if the server allows pausing)");
1701 Cmd_AddCommand(CF_SHARED, "kick", SV_Kick_f, "kick a player off the server by number or name");
1702 Cmd_AddCommand(CF_SHARED | CF_SERVER_FROM_CLIENT, "ping", SV_Ping_f, "print ping times of all players on the server");
1703 Cmd_AddCommand(CF_SHARED, "load", SV_Loadgame_f, "load a saved game file");
1704 Cmd_AddCommand(CF_SHARED, "save", SV_Savegame_f, "save the game to a file");
1705 Cmd_AddCommand(CF_SHARED, "viewmodel", SV_Viewmodel_f, "change model of viewthing entity in current level");
1706 Cmd_AddCommand(CF_SHARED, "viewframe", SV_Viewframe_f, "change animation frame of viewthing entity in current level");
1707 Cmd_AddCommand(CF_SHARED, "viewnext", SV_Viewnext_f, "change to next animation frame of viewthing entity in current level");
1708 Cmd_AddCommand(CF_SHARED, "viewprev", SV_Viewprev_f, "change to previous animation frame of viewthing entity in current level");
1709 Cmd_AddCommand(CF_SHARED, "maxplayers", SV_MaxPlayers_f, "sets limit on how many players (or bots) may be connected to the server at once");
1710 Cmd_AddCommand(CF_SHARED, "user", SV_User_f, "prints additional information about a player number or name on the scoreboard");
1711 Cmd_AddCommand(CF_SHARED, "users", SV_Users_f, "prints additional information about all players on the scoreboard");
1712 Cmd_AddCommand(CF_SERVER, "sendcvar", SV_SendCvar_f, "sends the value of a cvar to the server as a sentcvar command, for use by QuakeC");
1714 // commands that do not have automatic forwarding from cmd_client, these are internal details of the network protocol and not of interest to users (if they know what they are doing they can still use a generic "cmd prespawn" or similar)
1715 Cmd_AddCommand(CF_SERVER_FROM_CLIENT, "prespawn", SV_PreSpawn_f, "internal use - signon 1 (client acknowledges that server information has been received)");
1716 Cmd_AddCommand(CF_SERVER_FROM_CLIENT, "spawn", SV_Spawn_f, "internal use - signon 2 (client has sent player information, and is asking server to send scoreboard rankings)");
1717 Cmd_AddCommand(CF_SERVER_FROM_CLIENT, "begin", SV_Begin_f, "internal use - signon 3 (client asks server to start sending entities, and will go to signon 4 (playing) when the first entity update is received)");
1718 Cmd_AddCommand(CF_SERVER_FROM_CLIENT, "pings", SV_Pings_f, "internal use - command sent by clients to request updated ping and packetloss of players on scoreboard (originally from QW, but also used on NQ servers)");
1720 Cmd_AddCommand(CF_CHEAT | CF_SERVER_FROM_CLIENT, "god", SV_God_f, "god mode (invulnerability)");
1721 Cmd_AddCommand(CF_CHEAT | CF_SERVER_FROM_CLIENT, "notarget", SV_Notarget_f, "notarget mode (monsters do not see you)");
1722 Cmd_AddCommand(CF_CHEAT | CF_SERVER_FROM_CLIENT, "fly", SV_Fly_f, "fly mode (flight)");
1723 Cmd_AddCommand(CF_CHEAT | CF_SERVER_FROM_CLIENT, "noclip", SV_Noclip_f, "noclip mode (flight without collisions, move through walls)");
1724 Cmd_AddCommand(CF_CHEAT | CF_SERVER_FROM_CLIENT, "give", SV_Give_f, "alter inventory");
1725 Cmd_AddCommand(CF_SERVER_FROM_CLIENT, "kill", SV_Kill_f, "die instantly");
1727 Cmd_AddCommand(CF_USERINFO, "color", SV_Color_f, "change your player shirt and pants colors");
1728 Cmd_AddCommand(CF_USERINFO, "name", SV_Name_f, "change your player name");
1729 Cmd_AddCommand(CF_USERINFO, "rate", SV_Rate_f, "change your network connection speed");
1730 Cmd_AddCommand(CF_USERINFO, "rate_burstsize", SV_Rate_BurstSize_f, "change your network connection speed");
1731 Cmd_AddCommand(CF_USERINFO, "pmodel", SV_PModel_f, "(Nehahra-only) change your player model choice");
1732 Cmd_AddCommand(CF_USERINFO, "playermodel", SV_Playermodel_f, "change your player model");
1733 Cmd_AddCommand(CF_USERINFO, "playerskin", SV_Playerskin_f, "change your player skin number");
1735 Cmd_AddCommand(CF_CHEAT | CF_SERVER_FROM_CLIENT, "ent_create", SV_Ent_Create_f, "Creates an entity at the specified coordinate, of the specified classname. If executed from a server, origin has to be specified manually.");
1736 Cmd_AddCommand(CF_CHEAT | CF_SERVER_FROM_CLIENT, "ent_remove_all", SV_Ent_Remove_All_f, "Removes all entities of the specified classname");
1737 Cmd_AddCommand(CF_CHEAT | CF_SERVER_FROM_CLIENT, "ent_remove", SV_Ent_Remove_f, "Removes an entity by number, or the entity you're aiming at");