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);
87 if (sv.active && cls.state == ca_disconnected)
88 CL_EstablishConnection("local:1", -2);
95 Goes to a new map, taking all clients along
98 static void SV_Changelevel_f(cmd_state_t *cmd)
100 char level[MAX_QPATH];
102 if (Cmd_Argc(cmd) != 2)
104 Con_Print("changelevel <levelname> : continue game on a new level\n");
110 Con_Printf("You must be running a server to changelevel. Use 'map %s' instead\n", Cmd_Argv(cmd, 1));
116 if (key_dest == key_menu || key_dest == key_menu_grabbed)
121 SV_SaveSpawnparms ();
122 strlcpy(level, Cmd_Argv(cmd, 1), sizeof(level));
123 SV_SpawnServer(level);
124 if (sv.active && cls.state == ca_disconnected)
125 CL_EstablishConnection("local:1", -2);
132 Restarts the current server for a dead player
135 static void SV_Restart_f(cmd_state_t *cmd)
137 char mapname[MAX_QPATH];
139 if (Cmd_Argc(cmd) != 1)
141 Con_Print("restart : restart current level\n");
146 Con_Print("Only the server may restart\n");
152 if (key_dest == key_menu || key_dest == key_menu_grabbed)
157 strlcpy(mapname, sv.name, sizeof(mapname));
158 SV_SpawnServer(mapname);
159 if (sv.active && cls.state == ca_disconnected)
160 CL_EstablishConnection("local:1", -2);
163 //===========================================================================
165 // Disable cheats if sv_cheats is turned off
166 static void SV_DisableCheats_c(cvar_t *var)
168 prvm_prog_t *prog = SVVM_prog;
173 while (svs.clients[i].edict)
175 if (((int)PRVM_serveredictfloat(svs.clients[i].edict, flags) & FL_GODMODE))
176 PRVM_serveredictfloat(svs.clients[i].edict, flags) = (int)PRVM_serveredictfloat(svs.clients[i].edict, flags) ^ FL_GODMODE;
177 if (((int)PRVM_serveredictfloat(svs.clients[i].edict, flags) & FL_NOTARGET))
178 PRVM_serveredictfloat(svs.clients[i].edict, flags) = (int)PRVM_serveredictfloat(svs.clients[i].edict, flags) ^ FL_NOTARGET;
179 if (PRVM_serveredictfloat(svs.clients[i].edict, movetype) == MOVETYPE_NOCLIP ||
180 PRVM_serveredictfloat(svs.clients[i].edict, movetype) == MOVETYPE_FLY)
182 noclip_anglehack = false;
183 PRVM_serveredictfloat(svs.clients[i].edict, movetype) = MOVETYPE_WALK;
194 Sets client to godmode
197 static void SV_God_f(cmd_state_t *cmd)
199 prvm_prog_t *prog = SVVM_prog;
201 PRVM_serveredictfloat(host_client->edict, flags) = (int)PRVM_serveredictfloat(host_client->edict, flags) ^ FL_GODMODE;
202 if (!((int)PRVM_serveredictfloat(host_client->edict, flags) & FL_GODMODE) )
203 SV_ClientPrint("godmode OFF\n");
205 SV_ClientPrint("godmode ON\n");
208 qboolean noclip_anglehack;
210 static void SV_Noclip_f(cmd_state_t *cmd)
212 prvm_prog_t *prog = SVVM_prog;
214 if (PRVM_serveredictfloat(host_client->edict, movetype) != MOVETYPE_NOCLIP)
216 noclip_anglehack = true;
217 PRVM_serveredictfloat(host_client->edict, movetype) = MOVETYPE_NOCLIP;
218 SV_ClientPrint("noclip ON\n");
222 noclip_anglehack = false;
223 PRVM_serveredictfloat(host_client->edict, movetype) = MOVETYPE_WALK;
224 SV_ClientPrint("noclip OFF\n");
233 static void SV_Give_f(cmd_state_t *cmd)
235 prvm_prog_t *prog = SVVM_prog;
239 t = Cmd_Argv(cmd, 1);
240 v = atoi (Cmd_Argv(cmd, 2));
254 // MED 01/04/97 added hipnotic give stuff
255 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_QUOTH)
260 PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | HIT_PROXIMITY_GUN;
262 PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | IT_GRENADE_LAUNCHER;
264 else if (t[0] == '9')
265 PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | HIT_LASER_CANNON;
266 else if (t[0] == '0')
267 PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | HIT_MJOLNIR;
268 else if (t[0] >= '2')
269 PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | (IT_SHOTGUN << (t[0] - '2'));
274 PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | (IT_SHOTGUN << (t[0] - '2'));
279 if (gamemode == GAME_ROGUE)
280 PRVM_serveredictfloat(host_client->edict, ammo_shells1) = v;
282 PRVM_serveredictfloat(host_client->edict, ammo_shells) = v;
285 if (gamemode == GAME_ROGUE)
287 PRVM_serveredictfloat(host_client->edict, ammo_nails1) = v;
288 if (PRVM_serveredictfloat(host_client->edict, weapon) <= IT_LIGHTNING)
289 PRVM_serveredictfloat(host_client->edict, ammo_nails) = v;
293 PRVM_serveredictfloat(host_client->edict, ammo_nails) = v;
297 if (gamemode == GAME_ROGUE)
299 PRVM_serveredictfloat(host_client->edict, ammo_lava_nails) = v;
300 if (PRVM_serveredictfloat(host_client->edict, weapon) > IT_LIGHTNING)
301 PRVM_serveredictfloat(host_client->edict, ammo_nails) = v;
305 if (gamemode == GAME_ROGUE)
307 PRVM_serveredictfloat(host_client->edict, ammo_rockets1) = v;
308 if (PRVM_serveredictfloat(host_client->edict, weapon) <= IT_LIGHTNING)
309 PRVM_serveredictfloat(host_client->edict, ammo_rockets) = v;
313 PRVM_serveredictfloat(host_client->edict, ammo_rockets) = v;
317 if (gamemode == GAME_ROGUE)
319 PRVM_serveredictfloat(host_client->edict, ammo_multi_rockets) = v;
320 if (PRVM_serveredictfloat(host_client->edict, weapon) > IT_LIGHTNING)
321 PRVM_serveredictfloat(host_client->edict, ammo_rockets) = v;
325 PRVM_serveredictfloat(host_client->edict, health) = v;
328 if (gamemode == GAME_ROGUE)
330 PRVM_serveredictfloat(host_client->edict, ammo_cells1) = v;
331 if (PRVM_serveredictfloat(host_client->edict, weapon) <= IT_LIGHTNING)
332 PRVM_serveredictfloat(host_client->edict, ammo_cells) = v;
336 PRVM_serveredictfloat(host_client->edict, ammo_cells) = v;
340 if (gamemode == GAME_ROGUE)
342 PRVM_serveredictfloat(host_client->edict, ammo_plasma) = v;
343 if (PRVM_serveredictfloat(host_client->edict, weapon) > IT_LIGHTNING)
344 PRVM_serveredictfloat(host_client->edict, ammo_cells) = v;
354 Sets client to flymode
357 static void SV_Fly_f(cmd_state_t *cmd)
359 prvm_prog_t *prog = SVVM_prog;
361 if (PRVM_serveredictfloat(host_client->edict, movetype) != MOVETYPE_FLY)
363 PRVM_serveredictfloat(host_client->edict, movetype) = MOVETYPE_FLY;
364 SV_ClientPrint("flymode ON\n");
368 PRVM_serveredictfloat(host_client->edict, movetype) = MOVETYPE_WALK;
369 SV_ClientPrint("flymode OFF\n");
373 static void SV_Notarget_f(cmd_state_t *cmd)
375 prvm_prog_t *prog = SVVM_prog;
377 PRVM_serveredictfloat(host_client->edict, flags) = (int)PRVM_serveredictfloat(host_client->edict, flags) ^ FL_NOTARGET;
378 if (!((int)PRVM_serveredictfloat(host_client->edict, flags) & FL_NOTARGET) )
379 SV_ClientPrint("notarget OFF\n");
381 SV_ClientPrint("notarget ON\n");
389 static void SV_Kill_f(cmd_state_t *cmd)
391 prvm_prog_t *prog = SVVM_prog;
392 if (PRVM_serveredictfloat(host_client->edict, health) <= 0)
394 SV_ClientPrint("Can't suicide -- already dead!\n");
398 PRVM_serverglobalfloat(time) = sv.time;
399 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict);
400 prog->ExecuteProgram(prog, PRVM_serverfunction(ClientKill), "QC function ClientKill is missing");
408 static void SV_Pause_f(cmd_state_t *cmd)
410 void (*print) (const char *fmt, ...);
411 if (cmd->source == src_command)
413 // if running a client, try to send over network so the pause is handled by the server
414 if (cls.state == ca_connected)
416 CL_ForwardToServer_f(cmd);
422 print = SV_ClientPrintf;
424 if (!pausable.integer)
426 if (cmd->source == src_client)
428 if(cls.state == ca_dedicated || host_client != &svs.clients[0]) // non-admin
430 print("Pause not allowed.\n");
437 if (cmd->source != src_command)
438 SV_BroadcastPrintf("%s %spaused the game\n", host_client->name, sv.paused ? "" : "un");
439 else if(*(sv_adminnick.string))
440 SV_BroadcastPrintf("%s %spaused the game\n", sv_adminnick.string, sv.paused ? "" : "un");
442 SV_BroadcastPrintf("%s %spaused the game\n", hostname.string, sv.paused ? "" : "un");
443 // send notification to all clients
444 MSG_WriteByte(&sv.reliable_datagram, svc_setpause);
445 MSG_WriteByte(&sv.reliable_datagram, sv.paused);
448 static void SV_Say(cmd_state_t *cmd, qboolean teamonly)
450 prvm_prog_t *prog = SVVM_prog;
455 // LadyHavoc: long say messages
457 qboolean fromServer = false;
459 if (cmd->source == src_command)
461 if (cls.state == ca_dedicated)
468 CL_ForwardToServer_f(cmd);
473 if (Cmd_Argc (cmd) < 2)
476 if (!teamplay.integer)
486 // note this uses the chat prefix \001
487 if (!fromServer && !teamonly)
488 dpsnprintf (text, sizeof(text), "\001%s: %s", host_client->name, p1);
489 else if (!fromServer && teamonly)
490 dpsnprintf (text, sizeof(text), "\001(%s): %s", host_client->name, p1);
491 else if(*(sv_adminnick.string))
492 dpsnprintf (text, sizeof(text), "\001<%s> %s", sv_adminnick.string, p1);
494 dpsnprintf (text, sizeof(text), "\001<%s> %s", hostname.string, p1);
495 p2 = text + strlen(text);
496 while ((const char *)p2 > (const char *)text && (p2[-1] == '\r' || p2[-1] == '\n' || (p2[-1] == '\"' && quoted)))
498 if (p2[-1] == '\"' && quoted)
503 strlcat(text, "\n", sizeof(text));
505 // note: save is not a valid edict if fromServer is true
507 for (j = 0, host_client = svs.clients;j < svs.maxclients;j++, host_client++)
508 if (host_client->active && (!teamonly || PRVM_serveredictfloat(host_client->edict, team) == PRVM_serveredictfloat(save->edict, team)))
509 SV_ClientPrint(text);
512 if (cls.state == ca_dedicated)
516 static void SV_Say_f(cmd_state_t *cmd)
521 static void SV_Say_Team_f(cmd_state_t *cmd)
526 static void SV_Tell_f(cmd_state_t *cmd)
528 const char *playername_start = NULL;
529 size_t playername_length = 0;
530 int playernumber = 0;
534 char text[MAX_INPUTLINE]; // LadyHavoc: FIXME: temporary buffer overflow fix (was 64)
535 qboolean fromServer = false;
537 if (cmd->source == src_command)
539 if (cls.state == ca_dedicated)
543 CL_ForwardToServer_f(cmd);
548 if (Cmd_Argc (cmd) < 2)
551 // note this uses the chat prefix \001
553 dpsnprintf (text, sizeof(text), "\001%s tells you: ", host_client->name);
554 else if(*(sv_adminnick.string))
555 dpsnprintf (text, sizeof(text), "\001<%s tells you> ", sv_adminnick.string);
557 dpsnprintf (text, sizeof(text), "\001<%s tells you> ", hostname.string);
560 p2 = p1 + strlen(p1);
561 // remove the target name
562 while (p1 < p2 && *p1 == ' ')
567 while (p1 < p2 && *p1 == ' ')
569 while (p1 < p2 && isdigit(*p1))
571 playernumber = playernumber * 10 + (*p1 - '0');
579 playername_start = p1;
580 while (p1 < p2 && *p1 != '"')
582 playername_length = p1 - playername_start;
588 playername_start = p1;
589 while (p1 < p2 && *p1 != ' ')
591 playername_length = p1 - playername_start;
593 while (p1 < p2 && *p1 == ' ')
597 // set playernumber to the right client
599 if(playername_length >= sizeof(namebuf))
602 Con_Print("Host_Tell: too long player name/ID\n");
604 SV_ClientPrint("Host_Tell: too long player name/ID\n");
607 memcpy(namebuf, playername_start, playername_length);
608 namebuf[playername_length] = 0;
609 for (playernumber = 0; playernumber < svs.maxclients; playernumber++)
611 if (!svs.clients[playernumber].active)
613 if (strcasecmp(svs.clients[playernumber].name, namebuf) == 0)
617 if(playernumber < 0 || playernumber >= svs.maxclients || !(svs.clients[playernumber].active))
620 Con_Print("Host_Tell: invalid player name/ID\n");
622 SV_ClientPrint("Host_Tell: invalid player name/ID\n");
625 // remove trailing newlines
626 while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
628 // remove quotes if present
635 Con_Print("Host_Tell: missing end quote\n");
637 SV_ClientPrint("Host_Tell: missing end quote\n");
639 while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
643 for (j = (int)strlen(text);j < (int)(sizeof(text) - 2) && p1 < p2;)
649 host_client = svs.clients + playernumber;
650 SV_ClientPrint(text);
660 static void SV_Ping_f(cmd_state_t *cmd)
664 void (*print) (const char *fmt, ...);
666 if (cmd->source == src_command)
668 // if running a client, try to send over network so the client's ping report parser will see the report
669 if (cls.state == ca_connected)
671 CL_ForwardToServer_f(cmd);
677 print = SV_ClientPrintf;
682 print("Client ping times:\n");
683 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
687 print("%4i %s\n", bound(0, (int)floor(client->ping*1000+0.5), 9999), client->name);
695 Send back ping and packet loss update for all current players to this player
698 static void SV_Pings_f(cmd_state_t *cmd)
700 int i, j, ping, packetloss, movementloss;
703 if (!host_client->netconnection)
706 if (sv.protocol != PROTOCOL_QUAKEWORLD)
708 MSG_WriteByte(&host_client->netconnection->message, svc_stufftext);
709 MSG_WriteUnterminatedString(&host_client->netconnection->message, "pingplreport");
711 for (i = 0;i < svs.maxclients;i++)
715 if (svs.clients[i].netconnection)
717 for (j = 0;j < NETGRAPH_PACKETS;j++)
718 if (svs.clients[i].netconnection->incoming_netgraph[j].unreliablebytes == NETGRAPH_LOSTPACKET)
720 for (j = 0;j < NETGRAPH_PACKETS;j++)
721 if (svs.clients[i].movement_count[j] < 0)
724 packetloss = (packetloss * 100 + NETGRAPH_PACKETS - 1) / NETGRAPH_PACKETS;
725 movementloss = (movementloss * 100 + NETGRAPH_PACKETS - 1) / NETGRAPH_PACKETS;
726 ping = (int)floor(svs.clients[i].ping*1000+0.5);
727 ping = bound(0, ping, 9999);
728 if (sv.protocol == PROTOCOL_QUAKEWORLD)
730 // send qw_svc_updateping and qw_svc_updatepl messages
731 MSG_WriteByte(&host_client->netconnection->message, qw_svc_updateping);
732 MSG_WriteShort(&host_client->netconnection->message, ping);
733 MSG_WriteByte(&host_client->netconnection->message, qw_svc_updatepl);
734 MSG_WriteByte(&host_client->netconnection->message, packetloss);
738 // write the string into the packet as multiple unterminated strings to avoid needing a local buffer
740 dpsnprintf(temp, sizeof(temp), " %d %d,%d", ping, packetloss, movementloss);
742 dpsnprintf(temp, sizeof(temp), " %d %d", ping, packetloss);
743 MSG_WriteUnterminatedString(&host_client->netconnection->message, temp);
746 if (sv.protocol != PROTOCOL_QUAKEWORLD)
747 MSG_WriteString(&host_client->netconnection->message, "\n");
754 user <name or userid>
756 Dump userdata / masterdata for a user
759 static void SV_User_f(cmd_state_t *cmd) // credit: taken from QuakeWorld
764 if (Cmd_Argc(cmd) != 2)
766 Con_Printf ("Usage: user <username / userid>\n");
770 uid = atoi(Cmd_Argv(cmd, 1));
772 for (i = 0;i < cl.maxclients;i++)
774 if (!cl.scores[i].name[0])
776 if (cl.scores[i].qw_userid == uid || !strcasecmp(cl.scores[i].name, Cmd_Argv(cmd, 1)))
778 InfoString_Print(cl.scores[i].qw_userinfo);
782 Con_Printf ("User not in server.\n");
789 Dump userids for all current players
792 static void SV_Users_f(cmd_state_t *cmd) // credit: taken from QuakeWorld
798 Con_Printf ("userid frags name\n");
799 Con_Printf ("------ ----- ----\n");
800 for (i = 0;i < cl.maxclients;i++)
802 if (cl.scores[i].name[0])
804 Con_Printf ("%6i %4i %s\n", cl.scores[i].qw_userid, cl.scores[i].frags, cl.scores[i].name);
809 Con_Printf ("%i total users\n", c);
817 static void SV_Status_f(cmd_state_t *cmd)
819 prvm_prog_t *prog = SVVM_prog;
822 int seconds = 0, minutes = 0, hours = 0, i, j, k, in, players, ping = 0, packetloss = 0;
823 void (*print) (const char *fmt, ...);
824 char ip[48]; // can contain a full length v6 address with [] and a port
828 if (cmd->source == src_command)
831 print = SV_ClientPrintf;
837 if (Cmd_Argc(cmd) == 2)
839 if (strcmp(Cmd_Argv(cmd, 1), "1") == 0)
841 else if (strcmp(Cmd_Argv(cmd, 1), "2") == 0)
845 for (players = 0, i = 0;i < svs.maxclients;i++)
846 if (svs.clients[i].active)
848 print ("host: %s\n", Cvar_VariableString (&cvars_all, "hostname", CVAR_SERVER));
849 print ("version: %s build %s (gamename %s)\n", gamename, buildstring, gamenetworkfiltername);
850 print ("protocol: %i (%s)\n", Protocol_NumberForEnum(sv.protocol), Protocol_NameForEnum(sv.protocol));
851 print ("map: %s\n", sv.name);
852 print ("timing: %s\n", Host_TimingReport(vabuf, sizeof(vabuf)));
853 print ("players: %i active (%i max)\n\n", players, svs.maxclients);
856 print ("^2IP %%pl ping time frags no name\n");
858 print ("^5IP no name\n");
860 for (i = 0, k = 0, client = svs.clients;i < svs.maxclients;i++, client++)
867 if (in == 0 || in == 1)
869 seconds = (int)(host.realtime - client->connecttime);
870 minutes = seconds / 60;
873 seconds -= (minutes * 60);
874 hours = minutes / 60;
876 minutes -= (hours * 60);
882 if (client->netconnection)
883 for (j = 0;j < NETGRAPH_PACKETS;j++)
884 if (client->netconnection->incoming_netgraph[j].unreliablebytes == NETGRAPH_LOSTPACKET)
886 packetloss = (packetloss * 100 + NETGRAPH_PACKETS - 1) / NETGRAPH_PACKETS;
887 ping = bound(0, (int)floor(client->ping*1000+0.5), 9999);
890 if(sv_status_privacy.integer && cmd->source != src_command && LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) != LHNETADDRESSTYPE_LOOP)
891 strlcpy(ip, client->netconnection ? "hidden" : "botclient", 48);
893 strlcpy(ip, (client->netconnection && *client->netconnection->address) ? client->netconnection->address : "botclient", 48);
895 frags = client->frags;
897 if(sv_status_show_qcstatus.integer)
899 prvm_edict_t *ed = PRVM_EDICT_NUM(i + 1);
900 const char *str = PRVM_GetString(prog, PRVM_serveredictstring(ed, clientstatus));
906 for(q = str; *q && p != qcstatus + sizeof(qcstatus) - 1; ++q)
907 if(*q != '\\' && *q != '"' && !ISWHITESPACE(*q))
911 frags = atoi(qcstatus);
915 if (in == 0) // default layout
917 if (sv.protocol == PROTOCOL_QUAKE && svs.maxclients <= 99)
919 // LadyHavoc: this is very touchy because we must maintain ProQuake compatible status output
920 print ("#%-2u %-16.16s %3i %2i:%02i:%02i\n", i+1, client->name, frags, hours, minutes, seconds);
925 // LadyHavoc: no real restrictions here, not a ProQuake-compatible protocol anyway...
926 print ("#%-3u %-16.16s %4i %2i:%02i:%02i\n", i+1, client->name, frags, hours, minutes, seconds);
930 else if (in == 1) // extended layout
932 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);
934 else if (in == 2) // reduced layout
936 print ("%s%-47s #%-3u ^7%s\n", k%2 ? "^3" : "^7", ip, i+1, client->name);
941 void SV_Name(int clientnum)
943 prvm_prog_t *prog = SVVM_prog;
944 PRVM_serveredictstring(host_client->edict, netname) = PRVM_SetEngineString(prog, host_client->name);
945 if (strcmp(host_client->old_name, host_client->name))
947 if (host_client->begun)
948 SV_BroadcastPrintf("\003%s ^7changed name to ^3%s\n", host_client->old_name, host_client->name);
949 strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
950 // send notification to all clients
951 MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
952 MSG_WriteByte (&sv.reliable_datagram, clientnum);
953 MSG_WriteString (&sv.reliable_datagram, host_client->name);
954 SV_WriteNetnameIntoDemo(host_client);
959 ======================
961 ======================
963 static void SV_Name_f(cmd_state_t *cmd)
966 qboolean valid_colors;
967 const char *newNameSource;
968 char newName[sizeof(host_client->name)];
970 if (Cmd_Argc (cmd) == 1)
973 if (Cmd_Argc (cmd) == 2)
974 newNameSource = Cmd_Argv(cmd, 1);
976 newNameSource = Cmd_Args(cmd);
978 strlcpy(newName, newNameSource, sizeof(newName));
980 if (cmd->source == src_command)
983 if (host.realtime < host_client->nametime && strcmp(newName, host_client->name))
985 SV_ClientPrintf("You can't change name more than once every %.1f seconds!\n", max(0.0f, sv_namechangetimer.value));
989 host_client->nametime = host.realtime + max(0.0f, sv_namechangetimer.value);
991 // point the string back at updateclient->name to keep it safe
992 strlcpy (host_client->name, newName, sizeof (host_client->name));
994 for (i = 0, j = 0;host_client->name[i];i++)
995 if (host_client->name[i] != '\r' && host_client->name[i] != '\n')
996 host_client->name[j++] = host_client->name[i];
997 host_client->name[j] = 0;
999 if(host_client->name[0] == 1 || host_client->name[0] == 2)
1000 // may interfere with chat area, and will needlessly beep; so let's add a ^7
1002 memmove(host_client->name + 2, host_client->name, sizeof(host_client->name) - 2);
1003 host_client->name[sizeof(host_client->name) - 1] = 0;
1004 host_client->name[0] = STRING_COLOR_TAG;
1005 host_client->name[1] = '0' + STRING_COLOR_DEFAULT;
1008 u8_COM_StringLengthNoColors(host_client->name, 0, &valid_colors);
1009 if(!valid_colors) // NOTE: this also proves the string is not empty, as "" is a valid colored string
1012 l = strlen(host_client->name);
1013 if(l < sizeof(host_client->name) - 1)
1015 // duplicate the color tag to escape it
1016 host_client->name[i] = STRING_COLOR_TAG;
1017 host_client->name[i+1] = 0;
1018 //Con_DPrintf("abuse detected, adding another trailing color tag\n");
1022 // remove the last character to fix the color code
1023 host_client->name[l-1] = 0;
1024 //Con_DPrintf("abuse detected, removing a trailing color tag\n");
1028 // find the last color tag offset and decide if we need to add a reset tag
1029 for (i = 0, j = -1;host_client->name[i];i++)
1031 if (host_client->name[i] == STRING_COLOR_TAG)
1033 if (host_client->name[i+1] >= '0' && host_client->name[i+1] <= '9')
1036 // if this happens to be a reset tag then we don't need one
1037 if (host_client->name[i+1] == '0' + STRING_COLOR_DEFAULT)
1042 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]))
1048 if (host_client->name[i+1] == STRING_COLOR_TAG)
1055 // does not end in the default color string, so add it
1056 if (j >= 0 && strlen(host_client->name) < sizeof(host_client->name) - 2)
1057 memcpy(host_client->name + strlen(host_client->name), STRING_COLOR_DEFAULT_STR, strlen(STRING_COLOR_DEFAULT_STR) + 1);
1059 SV_Name(host_client - svs.clients);
1062 static void SV_Rate_f(cmd_state_t *cmd)
1066 rate = atoi(Cmd_Argv(cmd, 1));
1068 if (cmd->source == src_command)
1071 host_client->rate = rate;
1074 static void SV_Rate_BurstSize_f(cmd_state_t *cmd)
1078 if (Cmd_Argc(cmd) != 2)
1081 rate_burstsize = atoi(Cmd_Argv(cmd, 1));
1083 host_client->rate_burstsize = rate_burstsize;
1086 static void SV_Color_f(cmd_state_t *cmd)
1088 prvm_prog_t *prog = SVVM_prog;
1090 int top, bottom, playercolor;
1092 top = atoi(Cmd_Argv(cmd, 1));
1093 bottom = atoi(Cmd_Argv(cmd, 2));
1098 playercolor = top*16 + bottom;
1100 if (host_client->edict && PRVM_serverfunction(SV_ChangeTeam))
1102 Con_DPrint("Calling SV_ChangeTeam\n");
1103 prog->globals.fp[OFS_PARM0] = playercolor;
1104 PRVM_serverglobalfloat(time) = sv.time;
1105 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict);
1106 prog->ExecuteProgram(prog, PRVM_serverfunction(SV_ChangeTeam), "QC function SV_ChangeTeam is missing");
1110 if (host_client->edict)
1112 PRVM_serveredictfloat(host_client->edict, clientcolors) = playercolor;
1113 PRVM_serveredictfloat(host_client->edict, team) = bottom + 1;
1115 host_client->colors = playercolor;
1116 if (host_client->old_colors != host_client->colors)
1118 host_client->old_colors = host_client->colors;
1119 // send notification to all clients
1120 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1121 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1122 MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1131 Kicks a user off of the server
1134 static void SV_Kick_f(cmd_state_t *cmd)
1137 const char *message = NULL;
1140 qboolean byNumber = false;
1147 if (Cmd_Argc(cmd) > 2 && strcmp(Cmd_Argv(cmd, 1), "#") == 0)
1149 i = (int)(atof(Cmd_Argv(cmd, 2)) - 1);
1150 if (i < 0 || i >= svs.maxclients || !(host_client = svs.clients + i)->active)
1156 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1158 if (!host_client->active)
1160 if (strcasecmp(host_client->name, Cmd_Argv(cmd, 1)) == 0)
1165 if (i < svs.maxclients)
1167 if (cmd->source == src_command)
1169 if (cls.state == ca_dedicated)
1172 who = cl_name.string;
1177 // can't kick yourself!
1178 if (host_client == save)
1181 if (Cmd_Argc(cmd) > 2)
1183 message = Cmd_Args(cmd);
1184 COM_ParseToken_Simple(&message, false, false, true);
1187 message++; // skip the #
1188 while (*message == ' ') // skip white space
1190 message += strlen(Cmd_Argv(cmd, 2)); // skip the number
1192 while (*message && *message == ' ')
1196 SV_ClientPrintf("Kicked by %s: %s\n", who, message);
1198 SV_ClientPrintf("Kicked by %s\n", who);
1199 SV_DropClient (false); // kicked
1205 static void SV_MaxPlayers_f(cmd_state_t *cmd)
1209 if (Cmd_Argc(cmd) != 2)
1211 Con_Printf("\"maxplayers\" is \"%u\"\n", svs.maxclients_next);
1217 Con_Print("maxplayers can not be changed while a server is running.\n");
1218 Con_Print("It will be changed on next server startup (\"map\" command).\n");
1221 n = atoi(Cmd_Argv(cmd, 1));
1222 n = bound(1, n, MAX_SCOREBOARD);
1223 Con_Printf("\"maxplayers\" set to \"%u\"\n", n);
1225 svs.maxclients_next = n;
1227 Cvar_Set (&cvars_all, "deathmatch", "0");
1229 Cvar_Set (&cvars_all, "deathmatch", "1");
1233 ======================
1235 ======================
1237 // the old playermodel in cl_main has been renamed to __cl_playermodel
1238 static void SV_Playermodel_f(cmd_state_t *cmd)
1240 prvm_prog_t *prog = SVVM_prog;
1242 char newPath[sizeof(host_client->playermodel)];
1244 if (Cmd_Argc (cmd) == 1)
1247 if (Cmd_Argc (cmd) == 2)
1248 strlcpy (newPath, Cmd_Argv(cmd, 1), sizeof (newPath));
1250 strlcpy (newPath, Cmd_Args(cmd), sizeof (newPath));
1252 for (i = 0, j = 0;newPath[i];i++)
1253 if (newPath[i] != '\r' && newPath[i] != '\n')
1254 newPath[j++] = newPath[i];
1258 if (host.realtime < host_client->nametime)
1260 SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
1264 host_client->nametime = host.realtime + 5;
1267 // point the string back at updateclient->name to keep it safe
1268 strlcpy (host_client->playermodel, newPath, sizeof (host_client->playermodel));
1269 PRVM_serveredictstring(host_client->edict, playermodel) = PRVM_SetEngineString(prog, host_client->playermodel);
1270 if (strcmp(host_client->old_model, host_client->playermodel))
1272 strlcpy(host_client->old_model, host_client->playermodel, sizeof(host_client->old_model));
1273 /*// send notification to all clients
1274 MSG_WriteByte (&sv.reliable_datagram, svc_updatepmodel);
1275 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1276 MSG_WriteString (&sv.reliable_datagram, host_client->playermodel);*/
1281 ======================
1283 ======================
1285 static void SV_Playerskin_f(cmd_state_t *cmd)
1287 prvm_prog_t *prog = SVVM_prog;
1289 char newPath[sizeof(host_client->playerskin)];
1291 if (Cmd_Argc (cmd) == 1)
1294 if (Cmd_Argc (cmd) == 2)
1295 strlcpy (newPath, Cmd_Argv(cmd, 1), sizeof (newPath));
1297 strlcpy (newPath, Cmd_Args(cmd), sizeof (newPath));
1299 for (i = 0, j = 0;newPath[i];i++)
1300 if (newPath[i] != '\r' && newPath[i] != '\n')
1301 newPath[j++] = newPath[i];
1305 if (host.realtime < host_client->nametime)
1307 SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
1311 host_client->nametime = host.realtime + 5;
1314 // point the string back at updateclient->name to keep it safe
1315 strlcpy (host_client->playerskin, newPath, sizeof (host_client->playerskin));
1316 PRVM_serveredictstring(host_client->edict, playerskin) = PRVM_SetEngineString(prog, host_client->playerskin);
1317 if (strcmp(host_client->old_skin, host_client->playerskin))
1319 //if (host_client->begun)
1320 // SV_BroadcastPrintf("%s changed skin to %s\n", host_client->name, host_client->playerskin);
1321 strlcpy(host_client->old_skin, host_client->playerskin, sizeof(host_client->old_skin));
1322 /*// send notification to all clients
1323 MSG_WriteByte (&sv.reliable_datagram, svc_updatepskin);
1324 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1325 MSG_WriteString (&sv.reliable_datagram, host_client->playerskin);*/
1330 ======================
1332 LadyHavoc: only supported for Nehahra, I personally think this is dumb, but Mindcrime won't listen.
1333 LadyHavoc: correction, Mindcrime will be removing pmodel in the future, but it's still stuck here for compatibility.
1334 ======================
1336 static void SV_PModel_f(cmd_state_t *cmd)
1338 prvm_prog_t *prog = SVVM_prog;
1340 if (Cmd_Argc (cmd) == 1)
1343 PRVM_serveredictfloat(host_client->edict, pmodel) = atoi(Cmd_Argv(cmd, 1));
1347 ===============================================================================
1351 ===============================================================================
1354 static prvm_edict_t *FindViewthing(prvm_prog_t *prog)
1359 for (i=0 ; i<prog->num_edicts ; i++)
1361 e = PRVM_EDICT_NUM(i);
1362 if (!strcmp (PRVM_GetString(prog, PRVM_serveredictstring(e, classname)), "viewthing"))
1365 Con_Print("No viewthing on map\n");
1374 static void SV_Viewmodel_f(cmd_state_t *cmd)
1376 prvm_prog_t *prog = SVVM_prog;
1383 e = FindViewthing(prog);
1386 m = Mod_ForName (Cmd_Argv(cmd, 1), false, true, NULL);
1387 if (m && m->loaded && m->Draw)
1389 PRVM_serveredictfloat(e, frame) = 0;
1390 cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)] = m;
1393 Con_Printf("viewmodel: can't load %s\n", Cmd_Argv(cmd, 1));
1402 static void SV_Viewframe_f(cmd_state_t *cmd)
1404 prvm_prog_t *prog = SVVM_prog;
1412 e = FindViewthing(prog);
1415 m = cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)];
1417 f = atoi(Cmd_Argv(cmd, 1));
1418 if (f >= m->numframes)
1421 PRVM_serveredictfloat(e, frame) = f;
1425 static void PrintFrameName (dp_model_t *m, int frame)
1428 Con_Printf("frame %i: %s\n", frame, m->animscenes[frame].name);
1430 Con_Printf("frame %i\n", frame);
1438 static void SV_Viewnext_f(cmd_state_t *cmd)
1440 prvm_prog_t *prog = SVVM_prog;
1447 e = FindViewthing(prog);
1450 m = cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)];
1452 PRVM_serveredictfloat(e, frame) = PRVM_serveredictfloat(e, frame) + 1;
1453 if (PRVM_serveredictfloat(e, frame) >= m->numframes)
1454 PRVM_serveredictfloat(e, frame) = m->numframes - 1;
1456 PrintFrameName (m, (int)PRVM_serveredictfloat(e, frame));
1465 static void SV_Viewprev_f(cmd_state_t *cmd)
1467 prvm_prog_t *prog = SVVM_prog;
1474 e = FindViewthing(prog);
1477 m = cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)];
1479 PRVM_serveredictfloat(e, frame) = PRVM_serveredictfloat(e, frame) - 1;
1480 if (PRVM_serveredictfloat(e, frame) < 0)
1481 PRVM_serveredictfloat(e, frame) = 0;
1483 PrintFrameName (m, (int)PRVM_serveredictfloat(e, frame));
1487 static void SV_SendCvar_f(cmd_state_t *cmd)
1490 const char *cvarname;
1493 if(Cmd_Argc(cmd) != 2)
1496 if(!sv.active)// || !PRVM_serverfunction(SV_ParseClientCommand))
1499 cvarname = Cmd_Argv(cmd, 1);
1502 if (cls.state != ca_dedicated)
1506 for(;i<svs.maxclients;i++)
1507 if(svs.clients[i].active && svs.clients[i].netconnection)
1509 host_client = &svs.clients[i];
1510 SV_ClientCommands("sendcvar %s\n", cvarname);
1515 static void SV_Ent_Create_f(cmd_state_t *cmd)
1517 prvm_prog_t *prog = SVVM_prog;
1521 qboolean haveorigin;
1523 qboolean expectval = false;
1524 void (*print)(const char *, ...) = (cmd->source == src_client ? SV_ClientPrintf : Con_Printf);
1529 ed = PRVM_ED_Alloc(SVVM_prog);
1531 PRVM_ED_ParseEpair(prog, ed, PRVM_ED_FindField(prog, "classname"), Cmd_Argv(cmd, 1), false);
1533 // Spawn where the player is aiming. We need a view matrix first.
1534 if(cmd->source == src_client)
1536 vec3_t org, temp, dest;
1541 SV_GetEntityMatrix(prog, host_client->edict, &view, true);
1543 Matrix4x4_OriginFromMatrix(&view, org);
1544 VectorSet(temp, 65536, 0, 0);
1545 Matrix4x4_Transform(&view, temp, dest);
1547 trace = SV_TraceLine(org, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, 0, 0, collision_extendmovelength.value);
1549 dpsnprintf(buf, sizeof(buf), "%g %g %g", trace.endpos[0], trace.endpos[1], trace.endpos[2]);
1550 PRVM_ED_ParseEpair(prog, ed, PRVM_ED_FindField(prog, "origin"), buf, false);
1554 // Or spawn at a specified origin.
1561 // Allow more than one key/value pair by cycling between expecting either one.
1562 for(i = 2; i < Cmd_Argc(cmd); i++)
1566 if(!(key = PRVM_ED_FindField(prog, Cmd_Argv(cmd, i))))
1568 print("Key %s not found!\n", Cmd_Argv(cmd, i));
1569 PRVM_ED_Free(prog, ed);
1574 * This is mostly for dedicated server console, but if the
1575 * player gave a custom origin, we can ignore the traceline.
1577 if(!strcmp(Cmd_Argv(cmd, i), "origin"))
1584 PRVM_ED_ParseEpair(prog, ed, key, Cmd_Argv(cmd, i), false);
1591 print("Missing origin\n");
1592 PRVM_ED_Free(prog, ed);
1597 PRVM_ED_CallPrespawnFunction(prog, ed);
1599 if(!PRVM_ED_CallSpawnFunction(prog, ed, NULL, NULL))
1601 print("Could not spawn a \"%s\". No such entity or it has no spawn function\n", Cmd_Argv(cmd, 1));
1602 if(cmd->source == src_client)
1603 Con_Printf("%s tried to spawn a \"%s\"\n", host_client->name, Cmd_Argv(cmd, 1));
1604 // CallSpawnFunction already freed the edict for us.
1608 PRVM_ED_CallPostspawnFunction(prog, ed);
1610 // Make it appear in the world
1613 if(cmd->source == src_client)
1614 Con_Printf("%s spawned a \"%s\"\n", host_client->name, Cmd_Argv(cmd, 1));
1617 static void SV_Ent_Remove_f(cmd_state_t *cmd)
1619 prvm_prog_t *prog = SVVM_prog;
1622 void (*print)(const char *, ...) = (cmd->source == src_client ? SV_ClientPrintf : Con_Printf);
1627 // Allow specifying edict by number
1628 if(Cmd_Argc(cmd) > 1 && Cmd_Argv(cmd, 1))
1630 ednum = atoi(Cmd_Argv(cmd, 1));
1633 print("Cannot remove the world\n");
1637 // Or trace a line if it's a client who didn't specify one.
1638 else if(cmd->source == src_client)
1640 vec3_t org, temp, dest;
1644 SV_GetEntityMatrix(prog, host_client->edict, &view, true);
1646 Matrix4x4_OriginFromMatrix(&view, org);
1647 VectorSet(temp, 65536, 0, 0);
1648 Matrix4x4_Transform(&view, temp, dest);
1650 trace = SV_TraceLine(org, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY, 0, 0, collision_extendmovelength.value);
1653 ednum = (int)PRVM_EDICT_TO_PROG(trace.ent);
1654 if(!trace.ent || !ednum)
1655 // Don't remove the world, but don't annoy players with a print if they miss
1660 // Only a dedicated server console should be able to reach this.
1661 print("No edict given\n");
1665 ed = PRVM_EDICT_NUM(ednum);
1670 for (i = 0; i < svs.maxclients; i++)
1672 if(ed == svs.clients[i].edict)
1676 if(!ed->priv.required->free)
1678 print("Removed a \"%s\"\n", PRVM_GetString(prog, PRVM_serveredictstring(ed, classname)));
1679 PRVM_ED_ClearEdict(prog, ed);
1680 PRVM_ED_Free(prog, ed);
1685 // This should only be reachable if an invalid edict number was given
1686 print("No such entity\n");
1691 static void SV_Ent_Remove_All_f(cmd_state_t *cmd)
1693 prvm_prog_t *prog = SVVM_prog;
1696 void (*print)(const char *, ...) = (cmd->source == src_client ? SV_ClientPrintf : Con_Printf);
1698 for (i = 0, rmcount = 0, ed = PRVM_EDICT_NUM(i); i < prog->num_edicts; i++, ed = PRVM_NEXT_EDICT(ed))
1700 if(!ed->priv.required->free && !strcmp(PRVM_GetString(prog, PRVM_serveredictstring(ed, classname)), Cmd_Argv(cmd, 1)))
1704 print("Cannot remove the world\n");
1707 PRVM_ED_ClearEdict(prog, ed);
1708 PRVM_ED_Free(prog, ed);
1714 print("No \"%s\" found\n", Cmd_Argv(cmd, 1));
1716 print("Removed %i of \"%s\"\n", rmcount, Cmd_Argv(cmd, 1));
1719 void SV_InitOperatorCommands(void)
1721 Cvar_RegisterVariable(&sv_cheats);
1722 Cvar_RegisterCallback(&sv_cheats, SV_DisableCheats_c);
1723 Cvar_RegisterVariable(&sv_adminnick);
1724 Cvar_RegisterVariable(&sv_status_privacy);
1725 Cvar_RegisterVariable(&sv_status_show_qcstatus);
1726 Cvar_RegisterVariable(&sv_namechangetimer);
1728 Cmd_AddCommand(CMD_SERVER | CMD_SERVER_FROM_CLIENT, "status", SV_Status_f, "print server status information");
1729 Cmd_AddCommand(CMD_SHARED, "map", SV_Map_f, "kick everyone off the server and start a new level");
1730 Cmd_AddCommand(CMD_SHARED, "restart", SV_Restart_f, "restart current level");
1731 Cmd_AddCommand(CMD_SHARED, "changelevel", SV_Changelevel_f, "change to another level, bringing along all connected clients");
1732 Cmd_AddCommand(CMD_SHARED | CMD_SERVER_FROM_CLIENT, "say", SV_Say_f, "send a chat message to everyone on the server");
1733 Cmd_AddCommand(CMD_SERVER_FROM_CLIENT, "say_team", SV_Say_Team_f, "send a chat message to your team on the server");
1734 Cmd_AddCommand(CMD_SHARED | CMD_SERVER_FROM_CLIENT, "tell", SV_Tell_f, "send a chat message to only one person on the server");
1735 Cmd_AddCommand(CMD_SERVER | CMD_SERVER_FROM_CLIENT, "pause", SV_Pause_f, "pause the game (if the server allows pausing)");
1736 Cmd_AddCommand(CMD_SHARED, "kick", SV_Kick_f, "kick a player off the server by number or name");
1737 Cmd_AddCommand(CMD_SHARED | CMD_SERVER_FROM_CLIENT, "ping", SV_Ping_f, "print ping times of all players on the server");
1738 Cmd_AddCommand(CMD_SHARED, "load", SV_Loadgame_f, "load a saved game file");
1739 Cmd_AddCommand(CMD_SHARED, "save", SV_Savegame_f, "save the game to a file");
1740 Cmd_AddCommand(CMD_SHARED, "viewmodel", SV_Viewmodel_f, "change model of viewthing entity in current level");
1741 Cmd_AddCommand(CMD_SHARED, "viewframe", SV_Viewframe_f, "change animation frame of viewthing entity in current level");
1742 Cmd_AddCommand(CMD_SHARED, "viewnext", SV_Viewnext_f, "change to next animation frame of viewthing entity in current level");
1743 Cmd_AddCommand(CMD_SHARED, "viewprev", SV_Viewprev_f, "change to previous animation frame of viewthing entity in current level");
1744 Cmd_AddCommand(CMD_SHARED, "maxplayers", SV_MaxPlayers_f, "sets limit on how many players (or bots) may be connected to the server at once");
1745 Cmd_AddCommand(CMD_SHARED, "user", SV_User_f, "prints additional information about a player number or name on the scoreboard");
1746 Cmd_AddCommand(CMD_SHARED, "users", SV_Users_f, "prints additional information about all players on the scoreboard");
1747 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");
1749 // 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)
1750 Cmd_AddCommand(CMD_SERVER_FROM_CLIENT, "prespawn", SV_PreSpawn_f, "internal use - signon 1 (client acknowledges that server information has been received)");
1751 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)");
1752 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)");
1753 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)");
1755 Cmd_AddCommand(CMD_CHEAT | CMD_SERVER_FROM_CLIENT, "god", SV_God_f, "god mode (invulnerability)");
1756 Cmd_AddCommand(CMD_CHEAT | CMD_SERVER_FROM_CLIENT, "notarget", SV_Notarget_f, "notarget mode (monsters do not see you)");
1757 Cmd_AddCommand(CMD_CHEAT | CMD_SERVER_FROM_CLIENT, "fly", SV_Fly_f, "fly mode (flight)");
1758 Cmd_AddCommand(CMD_CHEAT | CMD_SERVER_FROM_CLIENT, "noclip", SV_Noclip_f, "noclip mode (flight without collisions, move through walls)");
1759 Cmd_AddCommand(CMD_CHEAT | CMD_SERVER_FROM_CLIENT, "give", SV_Give_f, "alter inventory");
1760 Cmd_AddCommand(CMD_SERVER_FROM_CLIENT, "kill", SV_Kill_f, "die instantly");
1762 Cmd_AddCommand(CMD_USERINFO, "color", SV_Color_f, "change your player shirt and pants colors");
1763 Cmd_AddCommand(CMD_USERINFO, "name", SV_Name_f, "change your player name");
1764 Cmd_AddCommand(CMD_USERINFO, "rate", SV_Rate_f, "change your network connection speed");
1765 Cmd_AddCommand(CMD_USERINFO, "rate_burstsize", SV_Rate_BurstSize_f, "change your network connection speed");
1766 Cmd_AddCommand(CMD_USERINFO, "pmodel", SV_PModel_f, "(Nehahra-only) change your player model choice");
1767 Cmd_AddCommand(CMD_USERINFO, "playermodel", SV_Playermodel_f, "change your player model");
1768 Cmd_AddCommand(CMD_USERINFO, "playerskin", SV_Playerskin_f, "change your player skin number");
1770 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.");
1771 Cmd_AddCommand(CMD_CHEAT | CMD_SERVER_FROM_CLIENT, "ent_remove_all", SV_Ent_Remove_All_f, "Removes all entities of the specified classname");
1772 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");