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 = {CVAR_SERVER | CVAR_NOTIFY, "sv_cheats", "0", "enables cheat commands in any game, and cheat impulses in dpmod"};
28 cvar_t sv_adminnick = {CVAR_SERVER | CVAR_SAVE, "sv_adminnick", "", "nick name to use for admin messages instead of host name"};
29 cvar_t sv_status_privacy = {CVAR_SERVER | CVAR_SAVE, "sv_status_privacy", "0", "do not show IP addresses in 'status' replies to clients"};
30 cvar_t sv_status_show_qcstatus = {CVAR_SERVER | 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."};
31 cvar_t sv_namechangetimer = {CVAR_SERVER | CVAR_SAVE, "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 qboolean 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)
421 if (cmd->source == src_client)
423 if(cls.state == ca_dedicated || host_client != &svs.clients[0]) // non-admin
425 print("Pause not allowed.\n");
432 if (cmd->source != src_local)
433 SV_BroadcastPrintf("%s %spaused the game\n", host_client->name, sv.paused ? "" : "un");
434 else if(*(sv_adminnick.string))
435 SV_BroadcastPrintf("%s %spaused the game\n", sv_adminnick.string, sv.paused ? "" : "un");
437 SV_BroadcastPrintf("%s %spaused the game\n", hostname.string, sv.paused ? "" : "un");
438 // send notification to all clients
439 MSG_WriteByte(&sv.reliable_datagram, svc_setpause);
440 MSG_WriteByte(&sv.reliable_datagram, sv.paused);
443 static void SV_Say(cmd_state_t *cmd, qboolean teamonly)
445 prvm_prog_t *prog = SVVM_prog;
450 // LadyHavoc: long say messages
452 qboolean fromServer = false;
454 if (cmd->source == src_local)
460 if (Cmd_Argc (cmd) < 2)
463 if (!teamplay.integer)
473 // note this uses the chat prefix \001
474 if (!fromServer && !teamonly)
475 dpsnprintf (text, sizeof(text), "\001%s: %s", host_client->name, p1);
476 else if (!fromServer && teamonly)
477 dpsnprintf (text, sizeof(text), "\001(%s): %s", host_client->name, p1);
478 else if(*(sv_adminnick.string))
479 dpsnprintf (text, sizeof(text), "\001<%s> %s", sv_adminnick.string, p1);
481 dpsnprintf (text, sizeof(text), "\001<%s> %s", hostname.string, p1);
482 p2 = text + strlen(text);
483 while ((const char *)p2 > (const char *)text && (p2[-1] == '\r' || p2[-1] == '\n' || (p2[-1] == '\"' && quoted)))
485 if (p2[-1] == '\"' && quoted)
490 strlcat(text, "\n", sizeof(text));
492 // note: save is not a valid edict if fromServer is true
494 for (j = 0, host_client = svs.clients;j < svs.maxclients;j++, host_client++)
495 if (host_client->active && (!teamonly || PRVM_serveredictfloat(host_client->edict, team) == PRVM_serveredictfloat(save->edict, team)))
496 SV_ClientPrint(text);
499 if (cls.state == ca_dedicated)
503 static void SV_Say_f(cmd_state_t *cmd)
508 static void SV_Say_Team_f(cmd_state_t *cmd)
513 static void SV_Tell_f(cmd_state_t *cmd)
515 const char *playername_start = NULL;
516 size_t playername_length = 0;
517 int playernumber = 0;
521 char text[MAX_INPUTLINE]; // LadyHavoc: FIXME: temporary buffer overflow fix (was 64)
522 qboolean fromServer = false;
524 if (cmd->source == src_local)
527 if (Cmd_Argc (cmd) < 2)
530 // note this uses the chat prefix \001
532 dpsnprintf (text, sizeof(text), "\001%s tells you: ", host_client->name);
533 else if(*(sv_adminnick.string))
534 dpsnprintf (text, sizeof(text), "\001<%s tells you> ", sv_adminnick.string);
536 dpsnprintf (text, sizeof(text), "\001<%s tells you> ", hostname.string);
539 p2 = p1 + strlen(p1);
540 // remove the target name
541 while (p1 < p2 && *p1 == ' ')
546 while (p1 < p2 && *p1 == ' ')
548 while (p1 < p2 && isdigit(*p1))
550 playernumber = playernumber * 10 + (*p1 - '0');
558 playername_start = p1;
559 while (p1 < p2 && *p1 != '"')
561 playername_length = p1 - playername_start;
567 playername_start = p1;
568 while (p1 < p2 && *p1 != ' ')
570 playername_length = p1 - playername_start;
572 while (p1 < p2 && *p1 == ' ')
576 // set playernumber to the right client
578 if(playername_length >= sizeof(namebuf))
581 Con_Print("Host_Tell: too long player name/ID\n");
583 SV_ClientPrint("Host_Tell: too long player name/ID\n");
586 memcpy(namebuf, playername_start, playername_length);
587 namebuf[playername_length] = 0;
588 for (playernumber = 0; playernumber < svs.maxclients; playernumber++)
590 if (!svs.clients[playernumber].active)
592 if (strcasecmp(svs.clients[playernumber].name, namebuf) == 0)
596 if(playernumber < 0 || playernumber >= svs.maxclients || !(svs.clients[playernumber].active))
599 Con_Print("Host_Tell: invalid player name/ID\n");
601 SV_ClientPrint("Host_Tell: invalid player name/ID\n");
604 // remove trailing newlines
605 while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
607 // remove quotes if present
614 Con_Print("Host_Tell: missing end quote\n");
616 SV_ClientPrint("Host_Tell: missing end quote\n");
618 while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
622 for (j = (int)strlen(text);j < (int)(sizeof(text) - 2) && p1 < p2;)
628 host_client = svs.clients + playernumber;
629 SV_ClientPrint(text);
639 static void SV_Ping_f(cmd_state_t *cmd)
643 void (*print) (const char *fmt, ...);
645 if (cmd->source == src_local)
648 print = SV_ClientPrintf;
653 print("Client ping times:\n");
654 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
658 print("%4i %s\n", bound(0, (int)floor(client->ping*1000+0.5), 9999), client->name);
666 Send back ping and packet loss update for all current players to this player
669 static void SV_Pings_f(cmd_state_t *cmd)
671 int i, j, ping, packetloss, movementloss;
674 if (!host_client->netconnection)
677 if (sv.protocol != PROTOCOL_QUAKEWORLD)
679 MSG_WriteByte(&host_client->netconnection->message, svc_stufftext);
680 MSG_WriteUnterminatedString(&host_client->netconnection->message, "pingplreport");
682 for (i = 0;i < svs.maxclients;i++)
686 if (svs.clients[i].netconnection)
688 for (j = 0;j < NETGRAPH_PACKETS;j++)
689 if (svs.clients[i].netconnection->incoming_netgraph[j].unreliablebytes == NETGRAPH_LOSTPACKET)
691 for (j = 0;j < NETGRAPH_PACKETS;j++)
692 if (svs.clients[i].movement_count[j] < 0)
695 packetloss = (packetloss * 100 + NETGRAPH_PACKETS - 1) / NETGRAPH_PACKETS;
696 movementloss = (movementloss * 100 + NETGRAPH_PACKETS - 1) / NETGRAPH_PACKETS;
697 ping = (int)floor(svs.clients[i].ping*1000+0.5);
698 ping = bound(0, ping, 9999);
699 if (sv.protocol == PROTOCOL_QUAKEWORLD)
701 // send qw_svc_updateping and qw_svc_updatepl messages
702 MSG_WriteByte(&host_client->netconnection->message, qw_svc_updateping);
703 MSG_WriteShort(&host_client->netconnection->message, ping);
704 MSG_WriteByte(&host_client->netconnection->message, qw_svc_updatepl);
705 MSG_WriteByte(&host_client->netconnection->message, packetloss);
709 // write the string into the packet as multiple unterminated strings to avoid needing a local buffer
711 dpsnprintf(temp, sizeof(temp), " %d %d,%d", ping, packetloss, movementloss);
713 dpsnprintf(temp, sizeof(temp), " %d %d", ping, packetloss);
714 MSG_WriteUnterminatedString(&host_client->netconnection->message, temp);
717 if (sv.protocol != PROTOCOL_QUAKEWORLD)
718 MSG_WriteString(&host_client->netconnection->message, "\n");
725 user <name or userid>
727 Dump userdata / masterdata for a user
730 static void SV_User_f(cmd_state_t *cmd) // credit: taken from QuakeWorld
735 if (Cmd_Argc(cmd) != 2)
737 Con_Printf ("Usage: user <username / userid>\n");
741 uid = atoi(Cmd_Argv(cmd, 1));
743 for (i = 0;i < cl.maxclients;i++)
745 if (!cl.scores[i].name[0])
747 if (cl.scores[i].qw_userid == uid || !strcasecmp(cl.scores[i].name, Cmd_Argv(cmd, 1)))
749 InfoString_Print(cl.scores[i].qw_userinfo);
753 Con_Printf ("User not in server.\n");
760 Dump userids for all current players
763 static void SV_Users_f(cmd_state_t *cmd) // credit: taken from QuakeWorld
769 Con_Printf ("userid frags name\n");
770 Con_Printf ("------ ----- ----\n");
771 for (i = 0;i < cl.maxclients;i++)
773 if (cl.scores[i].name[0])
775 Con_Printf ("%6i %4i %s\n", cl.scores[i].qw_userid, cl.scores[i].frags, cl.scores[i].name);
780 Con_Printf ("%i total users\n", c);
788 static void SV_Status_f(cmd_state_t *cmd)
790 prvm_prog_t *prog = SVVM_prog;
793 int seconds = 0, minutes = 0, hours = 0, i, j, k, in, players, ping = 0, packetloss = 0;
794 void (*print) (const char *fmt, ...);
795 char ip[48]; // can contain a full length v6 address with [] and a port
799 if (cmd->source == src_local)
802 print = SV_ClientPrintf;
808 if (Cmd_Argc(cmd) == 2)
810 if (strcmp(Cmd_Argv(cmd, 1), "1") == 0)
812 else if (strcmp(Cmd_Argv(cmd, 1), "2") == 0)
816 for (players = 0, i = 0;i < svs.maxclients;i++)
817 if (svs.clients[i].active)
819 print ("host: %s\n", Cvar_VariableString (&cvars_all, "hostname", CVAR_SERVER));
820 print ("version: %s build %s (gamename %s)\n", gamename, buildstring, gamenetworkfiltername);
821 print ("protocol: %i (%s)\n", Protocol_NumberForEnum(sv.protocol), Protocol_NameForEnum(sv.protocol));
822 print ("map: %s\n", sv.name);
823 print ("timing: %s\n", Host_TimingReport(vabuf, sizeof(vabuf)));
824 print ("players: %i active (%i max)\n\n", players, svs.maxclients);
827 print ("^2IP %%pl ping time frags no name\n");
829 print ("^5IP no name\n");
831 for (i = 0, k = 0, client = svs.clients;i < svs.maxclients;i++, client++)
838 if (in == 0 || in == 1)
840 seconds = (int)(host.realtime - client->connecttime);
841 minutes = seconds / 60;
844 seconds -= (minutes * 60);
845 hours = minutes / 60;
847 minutes -= (hours * 60);
853 if (client->netconnection)
854 for (j = 0;j < NETGRAPH_PACKETS;j++)
855 if (client->netconnection->incoming_netgraph[j].unreliablebytes == NETGRAPH_LOSTPACKET)
857 packetloss = (packetloss * 100 + NETGRAPH_PACKETS - 1) / NETGRAPH_PACKETS;
858 ping = bound(0, (int)floor(client->ping*1000+0.5), 9999);
861 if(sv_status_privacy.integer && cmd->source != src_local && LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) != LHNETADDRESSTYPE_LOOP)
862 strlcpy(ip, client->netconnection ? "hidden" : "botclient", 48);
864 strlcpy(ip, (client->netconnection && *client->netconnection->address) ? client->netconnection->address : "botclient", 48);
866 frags = client->frags;
868 if(sv_status_show_qcstatus.integer)
870 prvm_edict_t *ed = PRVM_EDICT_NUM(i + 1);
871 const char *str = PRVM_GetString(prog, PRVM_serveredictstring(ed, clientstatus));
877 for(q = str; *q && p != qcstatus + sizeof(qcstatus) - 1; ++q)
878 if(*q != '\\' && *q != '"' && !ISWHITESPACE(*q))
882 frags = atoi(qcstatus);
886 if (in == 0) // default layout
888 if (sv.protocol == PROTOCOL_QUAKE && svs.maxclients <= 99)
890 // LadyHavoc: this is very touchy because we must maintain ProQuake compatible status output
891 print ("#%-2u %-16.16s %3i %2i:%02i:%02i\n", i+1, client->name, frags, hours, minutes, seconds);
896 // LadyHavoc: no real restrictions here, not a ProQuake-compatible protocol anyway...
897 print ("#%-3u %-16.16s %4i %2i:%02i:%02i\n", i+1, client->name, frags, hours, minutes, seconds);
901 else if (in == 1) // extended layout
903 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);
905 else if (in == 2) // reduced layout
907 print ("%s%-47s #%-3u ^7%s\n", k%2 ? "^3" : "^7", ip, i+1, client->name);
912 void SV_Name(int clientnum)
914 prvm_prog_t *prog = SVVM_prog;
915 PRVM_serveredictstring(host_client->edict, netname) = PRVM_SetEngineString(prog, host_client->name);
916 if (strcmp(host_client->old_name, host_client->name))
918 if (host_client->begun)
919 SV_BroadcastPrintf("\003%s ^7changed name to ^3%s\n", host_client->old_name, host_client->name);
920 strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
921 // send notification to all clients
922 MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
923 MSG_WriteByte (&sv.reliable_datagram, clientnum);
924 MSG_WriteString (&sv.reliable_datagram, host_client->name);
925 SV_WriteNetnameIntoDemo(host_client);
930 ======================
932 ======================
934 static void SV_Name_f(cmd_state_t *cmd)
937 qboolean valid_colors;
938 const char *newNameSource;
939 char newName[sizeof(host_client->name)];
941 if (Cmd_Argc (cmd) == 1)
944 if (Cmd_Argc (cmd) == 2)
945 newNameSource = Cmd_Argv(cmd, 1);
947 newNameSource = Cmd_Args(cmd);
949 strlcpy(newName, newNameSource, sizeof(newName));
951 if (cmd->source == src_local)
954 if (host.realtime < host_client->nametime && strcmp(newName, host_client->name))
956 SV_ClientPrintf("You can't change name more than once every %.1f seconds!\n", max(0.0f, sv_namechangetimer.value));
960 host_client->nametime = host.realtime + max(0.0f, sv_namechangetimer.value);
962 // point the string back at updateclient->name to keep it safe
963 strlcpy (host_client->name, newName, sizeof (host_client->name));
965 for (i = 0, j = 0;host_client->name[i];i++)
966 if (host_client->name[i] != '\r' && host_client->name[i] != '\n')
967 host_client->name[j++] = host_client->name[i];
968 host_client->name[j] = 0;
970 if(host_client->name[0] == 1 || host_client->name[0] == 2)
971 // may interfere with chat area, and will needlessly beep; so let's add a ^7
973 memmove(host_client->name + 2, host_client->name, sizeof(host_client->name) - 2);
974 host_client->name[sizeof(host_client->name) - 1] = 0;
975 host_client->name[0] = STRING_COLOR_TAG;
976 host_client->name[1] = '0' + STRING_COLOR_DEFAULT;
979 u8_COM_StringLengthNoColors(host_client->name, 0, &valid_colors);
980 if(!valid_colors) // NOTE: this also proves the string is not empty, as "" is a valid colored string
983 l = strlen(host_client->name);
984 if(l < sizeof(host_client->name) - 1)
986 // duplicate the color tag to escape it
987 host_client->name[i] = STRING_COLOR_TAG;
988 host_client->name[i+1] = 0;
989 //Con_DPrintf("abuse detected, adding another trailing color tag\n");
993 // remove the last character to fix the color code
994 host_client->name[l-1] = 0;
995 //Con_DPrintf("abuse detected, removing a trailing color tag\n");
999 // find the last color tag offset and decide if we need to add a reset tag
1000 for (i = 0, j = -1;host_client->name[i];i++)
1002 if (host_client->name[i] == STRING_COLOR_TAG)
1004 if (host_client->name[i+1] >= '0' && host_client->name[i+1] <= '9')
1007 // if this happens to be a reset tag then we don't need one
1008 if (host_client->name[i+1] == '0' + STRING_COLOR_DEFAULT)
1013 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]))
1019 if (host_client->name[i+1] == STRING_COLOR_TAG)
1026 // does not end in the default color string, so add it
1027 if (j >= 0 && strlen(host_client->name) < sizeof(host_client->name) - 2)
1028 memcpy(host_client->name + strlen(host_client->name), STRING_COLOR_DEFAULT_STR, strlen(STRING_COLOR_DEFAULT_STR) + 1);
1030 SV_Name(host_client - svs.clients);
1033 static void SV_Rate_f(cmd_state_t *cmd)
1037 rate = atoi(Cmd_Argv(cmd, 1));
1039 if (cmd->source == src_local)
1042 host_client->rate = rate;
1045 static void SV_Rate_BurstSize_f(cmd_state_t *cmd)
1049 if (Cmd_Argc(cmd) != 2)
1052 rate_burstsize = atoi(Cmd_Argv(cmd, 1));
1054 host_client->rate_burstsize = rate_burstsize;
1057 static void SV_Color_f(cmd_state_t *cmd)
1059 prvm_prog_t *prog = SVVM_prog;
1061 int top, bottom, playercolor;
1063 top = atoi(Cmd_Argv(cmd, 1));
1064 bottom = atoi(Cmd_Argv(cmd, 2));
1069 playercolor = top*16 + bottom;
1071 if (host_client->edict && PRVM_serverfunction(SV_ChangeTeam))
1073 Con_DPrint("Calling SV_ChangeTeam\n");
1074 prog->globals.fp[OFS_PARM0] = playercolor;
1075 PRVM_serverglobalfloat(time) = sv.time;
1076 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict);
1077 prog->ExecuteProgram(prog, PRVM_serverfunction(SV_ChangeTeam), "QC function SV_ChangeTeam is missing");
1081 if (host_client->edict)
1083 PRVM_serveredictfloat(host_client->edict, clientcolors) = playercolor;
1084 PRVM_serveredictfloat(host_client->edict, team) = bottom + 1;
1086 host_client->colors = playercolor;
1087 if (host_client->old_colors != host_client->colors)
1089 host_client->old_colors = host_client->colors;
1090 // send notification to all clients
1091 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1092 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1093 MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1102 Kicks a user off of the server
1105 static void SV_Kick_f(cmd_state_t *cmd)
1108 const char *message = NULL;
1111 qboolean byNumber = false;
1118 if (Cmd_Argc(cmd) > 2 && strcmp(Cmd_Argv(cmd, 1), "#") == 0)
1120 i = (int)(atof(Cmd_Argv(cmd, 2)) - 1);
1121 if (i < 0 || i >= svs.maxclients || !(host_client = svs.clients + i)->active)
1127 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1129 if (!host_client->active)
1131 if (strcasecmp(host_client->name, Cmd_Argv(cmd, 1)) == 0)
1136 if (i < svs.maxclients)
1138 if (cmd->source == src_local)
1140 if (cls.state == ca_dedicated)
1143 who = cl_name.string;
1148 // can't kick yourself!
1149 if (host_client == save)
1152 if (Cmd_Argc(cmd) > 2)
1154 message = Cmd_Args(cmd);
1155 COM_ParseToken_Simple(&message, false, false, true);
1158 message++; // skip the #
1159 while (*message == ' ') // skip white space
1161 message += strlen(Cmd_Argv(cmd, 2)); // skip the number
1163 while (*message && *message == ' ')
1167 SV_ClientPrintf("Kicked by %s: %s\n", who, message);
1169 SV_ClientPrintf("Kicked by %s\n", who);
1170 SV_DropClient (false); // kicked
1176 static void SV_MaxPlayers_f(cmd_state_t *cmd)
1180 if (Cmd_Argc(cmd) != 2)
1182 Con_Printf("\"maxplayers\" is \"%u\"\n", svs.maxclients_next);
1188 Con_Print("maxplayers can not be changed while a server is running.\n");
1189 Con_Print("It will be changed on next server startup (\"map\" command).\n");
1192 n = atoi(Cmd_Argv(cmd, 1));
1193 n = bound(1, n, MAX_SCOREBOARD);
1194 Con_Printf("\"maxplayers\" set to \"%u\"\n", n);
1196 svs.maxclients_next = n;
1198 Cvar_Set (&cvars_all, "deathmatch", "0");
1200 Cvar_Set (&cvars_all, "deathmatch", "1");
1204 ======================
1206 ======================
1208 // the old playermodel in cl_main has been renamed to __cl_playermodel
1209 static void SV_Playermodel_f(cmd_state_t *cmd)
1211 prvm_prog_t *prog = SVVM_prog;
1213 char newPath[sizeof(host_client->playermodel)];
1215 if (Cmd_Argc (cmd) == 1)
1218 if (Cmd_Argc (cmd) == 2)
1219 strlcpy (newPath, Cmd_Argv(cmd, 1), sizeof (newPath));
1221 strlcpy (newPath, Cmd_Args(cmd), sizeof (newPath));
1223 for (i = 0, j = 0;newPath[i];i++)
1224 if (newPath[i] != '\r' && newPath[i] != '\n')
1225 newPath[j++] = newPath[i];
1229 if (host.realtime < host_client->nametime)
1231 SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
1235 host_client->nametime = host.realtime + 5;
1238 // point the string back at updateclient->name to keep it safe
1239 strlcpy (host_client->playermodel, newPath, sizeof (host_client->playermodel));
1240 PRVM_serveredictstring(host_client->edict, playermodel) = PRVM_SetEngineString(prog, host_client->playermodel);
1241 if (strcmp(host_client->old_model, host_client->playermodel))
1243 strlcpy(host_client->old_model, host_client->playermodel, sizeof(host_client->old_model));
1244 /*// send notification to all clients
1245 MSG_WriteByte (&sv.reliable_datagram, svc_updatepmodel);
1246 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1247 MSG_WriteString (&sv.reliable_datagram, host_client->playermodel);*/
1252 ======================
1254 ======================
1256 static void SV_Playerskin_f(cmd_state_t *cmd)
1258 prvm_prog_t *prog = SVVM_prog;
1260 char newPath[sizeof(host_client->playerskin)];
1262 if (Cmd_Argc (cmd) == 1)
1265 if (Cmd_Argc (cmd) == 2)
1266 strlcpy (newPath, Cmd_Argv(cmd, 1), sizeof (newPath));
1268 strlcpy (newPath, Cmd_Args(cmd), sizeof (newPath));
1270 for (i = 0, j = 0;newPath[i];i++)
1271 if (newPath[i] != '\r' && newPath[i] != '\n')
1272 newPath[j++] = newPath[i];
1276 if (host.realtime < host_client->nametime)
1278 SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
1282 host_client->nametime = host.realtime + 5;
1285 // point the string back at updateclient->name to keep it safe
1286 strlcpy (host_client->playerskin, newPath, sizeof (host_client->playerskin));
1287 PRVM_serveredictstring(host_client->edict, playerskin) = PRVM_SetEngineString(prog, host_client->playerskin);
1288 if (strcmp(host_client->old_skin, host_client->playerskin))
1290 //if (host_client->begun)
1291 // SV_BroadcastPrintf("%s changed skin to %s\n", host_client->name, host_client->playerskin);
1292 strlcpy(host_client->old_skin, host_client->playerskin, sizeof(host_client->old_skin));
1293 /*// send notification to all clients
1294 MSG_WriteByte (&sv.reliable_datagram, svc_updatepskin);
1295 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1296 MSG_WriteString (&sv.reliable_datagram, host_client->playerskin);*/
1301 ======================
1303 LadyHavoc: only supported for Nehahra, I personally think this is dumb, but Mindcrime won't listen.
1304 LadyHavoc: correction, Mindcrime will be removing pmodel in the future, but it's still stuck here for compatibility.
1305 ======================
1307 static void SV_PModel_f(cmd_state_t *cmd)
1309 prvm_prog_t *prog = SVVM_prog;
1311 if (Cmd_Argc (cmd) == 1)
1314 PRVM_serveredictfloat(host_client->edict, pmodel) = atoi(Cmd_Argv(cmd, 1));
1318 ===============================================================================
1322 ===============================================================================
1325 static prvm_edict_t *FindViewthing(prvm_prog_t *prog)
1330 for (i=0 ; i<prog->num_edicts ; i++)
1332 e = PRVM_EDICT_NUM(i);
1333 if (!strcmp (PRVM_GetString(prog, PRVM_serveredictstring(e, classname)), "viewthing"))
1336 Con_Print("No viewthing on map\n");
1345 static void SV_Viewmodel_f(cmd_state_t *cmd)
1347 prvm_prog_t *prog = SVVM_prog;
1354 e = FindViewthing(prog);
1357 m = Mod_ForName (Cmd_Argv(cmd, 1), false, true, NULL);
1358 if (m && m->loaded && m->Draw)
1360 PRVM_serveredictfloat(e, frame) = 0;
1361 cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)] = m;
1364 Con_Printf("viewmodel: can't load %s\n", Cmd_Argv(cmd, 1));
1373 static void SV_Viewframe_f(cmd_state_t *cmd)
1375 prvm_prog_t *prog = SVVM_prog;
1383 e = FindViewthing(prog);
1386 m = cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)];
1388 f = atoi(Cmd_Argv(cmd, 1));
1389 if (f >= m->numframes)
1392 PRVM_serveredictfloat(e, frame) = f;
1396 static void PrintFrameName (dp_model_t *m, int frame)
1399 Con_Printf("frame %i: %s\n", frame, m->animscenes[frame].name);
1401 Con_Printf("frame %i\n", frame);
1409 static void SV_Viewnext_f(cmd_state_t *cmd)
1411 prvm_prog_t *prog = SVVM_prog;
1418 e = FindViewthing(prog);
1421 m = cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)];
1423 PRVM_serveredictfloat(e, frame) = PRVM_serveredictfloat(e, frame) + 1;
1424 if (PRVM_serveredictfloat(e, frame) >= m->numframes)
1425 PRVM_serveredictfloat(e, frame) = m->numframes - 1;
1427 PrintFrameName (m, (int)PRVM_serveredictfloat(e, frame));
1436 static void SV_Viewprev_f(cmd_state_t *cmd)
1438 prvm_prog_t *prog = SVVM_prog;
1445 e = FindViewthing(prog);
1448 m = cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)];
1450 PRVM_serveredictfloat(e, frame) = PRVM_serveredictfloat(e, frame) - 1;
1451 if (PRVM_serveredictfloat(e, frame) < 0)
1452 PRVM_serveredictfloat(e, frame) = 0;
1454 PrintFrameName (m, (int)PRVM_serveredictfloat(e, frame));
1458 static void SV_SendCvar_f(cmd_state_t *cmd)
1461 const char *cvarname;
1464 if(Cmd_Argc(cmd) != 2)
1467 if(!sv.active)// || !PRVM_serverfunction(SV_ParseClientCommand))
1470 cvarname = Cmd_Argv(cmd, 1);
1473 if (cls.state != ca_dedicated)
1477 for(;i<svs.maxclients;i++)
1478 if(svs.clients[i].active && svs.clients[i].netconnection)
1480 host_client = &svs.clients[i];
1481 SV_ClientCommands("sendcvar %s\n", cvarname);
1486 static void SV_Ent_Create_f(cmd_state_t *cmd)
1488 prvm_prog_t *prog = SVVM_prog;
1492 qboolean haveorigin;
1494 qboolean expectval = false;
1495 void (*print)(const char *, ...) = (cmd->source == src_client ? SV_ClientPrintf : Con_Printf);
1500 ed = PRVM_ED_Alloc(SVVM_prog);
1502 PRVM_ED_ParseEpair(prog, ed, PRVM_ED_FindField(prog, "classname"), Cmd_Argv(cmd, 1), false);
1504 // Spawn where the player is aiming. We need a view matrix first.
1505 if(cmd->source == src_client)
1507 vec3_t org, temp, dest;
1512 SV_GetEntityMatrix(prog, host_client->edict, &view, true);
1514 Matrix4x4_OriginFromMatrix(&view, org);
1515 VectorSet(temp, 65536, 0, 0);
1516 Matrix4x4_Transform(&view, temp, dest);
1518 trace = SV_TraceLine(org, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, 0, 0, collision_extendmovelength.value);
1520 dpsnprintf(buf, sizeof(buf), "%g %g %g", trace.endpos[0], trace.endpos[1], trace.endpos[2]);
1521 PRVM_ED_ParseEpair(prog, ed, PRVM_ED_FindField(prog, "origin"), buf, false);
1525 // Or spawn at a specified origin.
1532 // Allow more than one key/value pair by cycling between expecting either one.
1533 for(i = 2; i < Cmd_Argc(cmd); i++)
1537 if(!(key = PRVM_ED_FindField(prog, Cmd_Argv(cmd, i))))
1539 print("Key %s not found!\n", Cmd_Argv(cmd, i));
1540 PRVM_ED_Free(prog, ed);
1545 * This is mostly for dedicated server console, but if the
1546 * player gave a custom origin, we can ignore the traceline.
1548 if(!strcmp(Cmd_Argv(cmd, i), "origin"))
1555 PRVM_ED_ParseEpair(prog, ed, key, Cmd_Argv(cmd, i), false);
1562 print("Missing origin\n");
1563 PRVM_ED_Free(prog, ed);
1568 PRVM_ED_CallPrespawnFunction(prog, ed);
1570 if(!PRVM_ED_CallSpawnFunction(prog, ed, NULL, NULL))
1572 print("Could not spawn a \"%s\". No such entity or it has no spawn function\n", Cmd_Argv(cmd, 1));
1573 if(cmd->source == src_client)
1574 Con_Printf("%s tried to spawn a \"%s\"\n", host_client->name, Cmd_Argv(cmd, 1));
1575 // CallSpawnFunction already freed the edict for us.
1579 PRVM_ED_CallPostspawnFunction(prog, ed);
1581 // Make it appear in the world
1584 if(cmd->source == src_client)
1585 Con_Printf("%s spawned a \"%s\"\n", host_client->name, Cmd_Argv(cmd, 1));
1588 static void SV_Ent_Remove_f(cmd_state_t *cmd)
1590 prvm_prog_t *prog = SVVM_prog;
1593 void (*print)(const char *, ...) = (cmd->source == src_client ? SV_ClientPrintf : Con_Printf);
1598 // Allow specifying edict by number
1599 if(Cmd_Argc(cmd) > 1 && Cmd_Argv(cmd, 1))
1601 ednum = atoi(Cmd_Argv(cmd, 1));
1604 print("Cannot remove the world\n");
1608 // Or trace a line if it's a client who didn't specify one.
1609 else if(cmd->source == src_client)
1611 vec3_t org, temp, dest;
1615 SV_GetEntityMatrix(prog, host_client->edict, &view, true);
1617 Matrix4x4_OriginFromMatrix(&view, org);
1618 VectorSet(temp, 65536, 0, 0);
1619 Matrix4x4_Transform(&view, temp, dest);
1621 trace = SV_TraceLine(org, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY, 0, 0, collision_extendmovelength.value);
1624 ednum = (int)PRVM_EDICT_TO_PROG(trace.ent);
1625 if(!trace.ent || !ednum)
1626 // Don't remove the world, but don't annoy players with a print if they miss
1631 // Only a dedicated server console should be able to reach this.
1632 print("No edict given\n");
1636 ed = PRVM_EDICT_NUM(ednum);
1641 for (i = 0; i < svs.maxclients; i++)
1643 if(ed == svs.clients[i].edict)
1647 if(!ed->priv.required->free)
1649 print("Removed a \"%s\"\n", PRVM_GetString(prog, PRVM_serveredictstring(ed, classname)));
1650 PRVM_ED_ClearEdict(prog, ed);
1651 PRVM_ED_Free(prog, ed);
1656 // This should only be reachable if an invalid edict number was given
1657 print("No such entity\n");
1662 static void SV_Ent_Remove_All_f(cmd_state_t *cmd)
1664 prvm_prog_t *prog = SVVM_prog;
1667 void (*print)(const char *, ...) = (cmd->source == src_client ? SV_ClientPrintf : Con_Printf);
1669 for (i = 0, rmcount = 0, ed = PRVM_EDICT_NUM(i); i < prog->num_edicts; i++, ed = PRVM_NEXT_EDICT(ed))
1671 if(!ed->priv.required->free && !strcmp(PRVM_GetString(prog, PRVM_serveredictstring(ed, classname)), Cmd_Argv(cmd, 1)))
1675 print("Cannot remove the world\n");
1678 PRVM_ED_ClearEdict(prog, ed);
1679 PRVM_ED_Free(prog, ed);
1685 print("No \"%s\" found\n", Cmd_Argv(cmd, 1));
1687 print("Removed %i of \"%s\"\n", rmcount, Cmd_Argv(cmd, 1));
1690 void SV_InitOperatorCommands(void)
1692 Cvar_RegisterVariable(&sv_cheats);
1693 Cvar_RegisterCallback(&sv_cheats, SV_DisableCheats_c);
1694 Cvar_RegisterVariable(&sv_adminnick);
1695 Cvar_RegisterVariable(&sv_status_privacy);
1696 Cvar_RegisterVariable(&sv_status_show_qcstatus);
1697 Cvar_RegisterVariable(&sv_namechangetimer);
1699 Cmd_AddCommand(CMD_SERVER | CMD_SERVER_FROM_CLIENT, "status", SV_Status_f, "print server status information");
1700 Cmd_AddCommand(CMD_SHARED, "map", SV_Map_f, "kick everyone off the server and start a new level");
1701 Cmd_AddCommand(CMD_SHARED, "restart", SV_Restart_f, "restart current level");
1702 Cmd_AddCommand(CMD_SHARED, "changelevel", SV_Changelevel_f, "change to another level, bringing along all connected clients");
1703 Cmd_AddCommand(CMD_SHARED | CMD_SERVER_FROM_CLIENT, "say", SV_Say_f, "send a chat message to everyone on the server");
1704 Cmd_AddCommand(CMD_SERVER_FROM_CLIENT, "say_team", SV_Say_Team_f, "send a chat message to your team on the server");
1705 Cmd_AddCommand(CMD_SHARED | CMD_SERVER_FROM_CLIENT, "tell", SV_Tell_f, "send a chat message to only one person on the server");
1706 Cmd_AddCommand(CMD_SERVER | CMD_SERVER_FROM_CLIENT, "pause", SV_Pause_f, "pause the game (if the server allows pausing)");
1707 Cmd_AddCommand(CMD_SHARED, "kick", SV_Kick_f, "kick a player off the server by number or name");
1708 Cmd_AddCommand(CMD_SHARED | CMD_SERVER_FROM_CLIENT, "ping", SV_Ping_f, "print ping times of all players on the server");
1709 Cmd_AddCommand(CMD_SHARED, "load", SV_Loadgame_f, "load a saved game file");
1710 Cmd_AddCommand(CMD_SHARED, "save", SV_Savegame_f, "save the game to a file");
1711 Cmd_AddCommand(CMD_SHARED, "viewmodel", SV_Viewmodel_f, "change model of viewthing entity in current level");
1712 Cmd_AddCommand(CMD_SHARED, "viewframe", SV_Viewframe_f, "change animation frame of viewthing entity in current level");
1713 Cmd_AddCommand(CMD_SHARED, "viewnext", SV_Viewnext_f, "change to next animation frame of viewthing entity in current level");
1714 Cmd_AddCommand(CMD_SHARED, "viewprev", SV_Viewprev_f, "change to previous animation frame of viewthing entity in current level");
1715 Cmd_AddCommand(CMD_SHARED, "maxplayers", SV_MaxPlayers_f, "sets limit on how many players (or bots) may be connected to the server at once");
1716 Cmd_AddCommand(CMD_SHARED, "user", SV_User_f, "prints additional information about a player number or name on the scoreboard");
1717 Cmd_AddCommand(CMD_SHARED, "users", SV_Users_f, "prints additional information about all players on the scoreboard");
1718 Cmd_AddCommand(CMD_SERVER, "sendcvar", SV_SendCvar_f, "sends the value of a cvar to the server as a sentcvar command, for use by QuakeC");
1720 // 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)
1721 Cmd_AddCommand(CMD_SERVER_FROM_CLIENT, "prespawn", SV_PreSpawn_f, "internal use - signon 1 (client acknowledges that server information has been received)");
1722 Cmd_AddCommand(CMD_SERVER_FROM_CLIENT, "spawn", SV_Spawn_f, "internal use - signon 2 (client has sent player information, and is asking server to send scoreboard rankings)");
1723 Cmd_AddCommand(CMD_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)");
1724 Cmd_AddCommand(CMD_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)");
1726 Cmd_AddCommand(CMD_CHEAT | CMD_SERVER_FROM_CLIENT, "god", SV_God_f, "god mode (invulnerability)");
1727 Cmd_AddCommand(CMD_CHEAT | CMD_SERVER_FROM_CLIENT, "notarget", SV_Notarget_f, "notarget mode (monsters do not see you)");
1728 Cmd_AddCommand(CMD_CHEAT | CMD_SERVER_FROM_CLIENT, "fly", SV_Fly_f, "fly mode (flight)");
1729 Cmd_AddCommand(CMD_CHEAT | CMD_SERVER_FROM_CLIENT, "noclip", SV_Noclip_f, "noclip mode (flight without collisions, move through walls)");
1730 Cmd_AddCommand(CMD_CHEAT | CMD_SERVER_FROM_CLIENT, "give", SV_Give_f, "alter inventory");
1731 Cmd_AddCommand(CMD_SERVER_FROM_CLIENT, "kill", SV_Kill_f, "die instantly");
1733 Cmd_AddCommand(CMD_USERINFO, "color", SV_Color_f, "change your player shirt and pants colors");
1734 Cmd_AddCommand(CMD_USERINFO, "name", SV_Name_f, "change your player name");
1735 Cmd_AddCommand(CMD_USERINFO, "rate", SV_Rate_f, "change your network connection speed");
1736 Cmd_AddCommand(CMD_USERINFO, "rate_burstsize", SV_Rate_BurstSize_f, "change your network connection speed");
1737 Cmd_AddCommand(CMD_USERINFO, "pmodel", SV_PModel_f, "(Nehahra-only) change your player model choice");
1738 Cmd_AddCommand(CMD_USERINFO, "playermodel", SV_Playermodel_f, "change your player model");
1739 Cmd_AddCommand(CMD_USERINFO, "playerskin", SV_Playerskin_f, "change your player skin number");
1741 Cmd_AddCommand(CMD_CHEAT | CMD_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.");
1742 Cmd_AddCommand(CMD_CHEAT | CMD_SERVER_FROM_CLIENT, "ent_remove_all", SV_Ent_Remove_All_f, "Removes all entities of the specified classname");
1743 Cmd_AddCommand(CMD_CHEAT | CMD_SERVER_FROM_CLIENT, "ent_remove", SV_Ent_Remove_f, "Removes an entity by number, or the entity you're aiming at");