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_command)
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_command)
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_command)
456 if (cls.state == ca_dedicated)
463 CL_ForwardToServer_f(cmd);
468 if (Cmd_Argc (cmd) < 2)
471 if (!teamplay.integer)
481 // note this uses the chat prefix \001
482 if (!fromServer && !teamonly)
483 dpsnprintf (text, sizeof(text), "\001%s: %s", host_client->name, p1);
484 else if (!fromServer && teamonly)
485 dpsnprintf (text, sizeof(text), "\001(%s): %s", host_client->name, p1);
486 else if(*(sv_adminnick.string))
487 dpsnprintf (text, sizeof(text), "\001<%s> %s", sv_adminnick.string, p1);
489 dpsnprintf (text, sizeof(text), "\001<%s> %s", hostname.string, p1);
490 p2 = text + strlen(text);
491 while ((const char *)p2 > (const char *)text && (p2[-1] == '\r' || p2[-1] == '\n' || (p2[-1] == '\"' && quoted)))
493 if (p2[-1] == '\"' && quoted)
498 strlcat(text, "\n", sizeof(text));
500 // note: save is not a valid edict if fromServer is true
502 for (j = 0, host_client = svs.clients;j < svs.maxclients;j++, host_client++)
503 if (host_client->active && (!teamonly || PRVM_serveredictfloat(host_client->edict, team) == PRVM_serveredictfloat(save->edict, team)))
504 SV_ClientPrint(text);
507 if (cls.state == ca_dedicated)
511 static void SV_Say_f(cmd_state_t *cmd)
516 static void SV_Say_Team_f(cmd_state_t *cmd)
521 static void SV_Tell_f(cmd_state_t *cmd)
523 const char *playername_start = NULL;
524 size_t playername_length = 0;
525 int playernumber = 0;
529 char text[MAX_INPUTLINE]; // LadyHavoc: FIXME: temporary buffer overflow fix (was 64)
530 qboolean fromServer = false;
532 if (cmd->source == src_command)
534 if (cls.state == ca_dedicated)
538 CL_ForwardToServer_f(cmd);
543 if (Cmd_Argc (cmd) < 2)
546 // note this uses the chat prefix \001
548 dpsnprintf (text, sizeof(text), "\001%s tells you: ", host_client->name);
549 else if(*(sv_adminnick.string))
550 dpsnprintf (text, sizeof(text), "\001<%s tells you> ", sv_adminnick.string);
552 dpsnprintf (text, sizeof(text), "\001<%s tells you> ", hostname.string);
555 p2 = p1 + strlen(p1);
556 // remove the target name
557 while (p1 < p2 && *p1 == ' ')
562 while (p1 < p2 && *p1 == ' ')
564 while (p1 < p2 && isdigit(*p1))
566 playernumber = playernumber * 10 + (*p1 - '0');
574 playername_start = p1;
575 while (p1 < p2 && *p1 != '"')
577 playername_length = p1 - playername_start;
583 playername_start = p1;
584 while (p1 < p2 && *p1 != ' ')
586 playername_length = p1 - playername_start;
588 while (p1 < p2 && *p1 == ' ')
592 // set playernumber to the right client
594 if(playername_length >= sizeof(namebuf))
597 Con_Print("Host_Tell: too long player name/ID\n");
599 SV_ClientPrint("Host_Tell: too long player name/ID\n");
602 memcpy(namebuf, playername_start, playername_length);
603 namebuf[playername_length] = 0;
604 for (playernumber = 0; playernumber < svs.maxclients; playernumber++)
606 if (!svs.clients[playernumber].active)
608 if (strcasecmp(svs.clients[playernumber].name, namebuf) == 0)
612 if(playernumber < 0 || playernumber >= svs.maxclients || !(svs.clients[playernumber].active))
615 Con_Print("Host_Tell: invalid player name/ID\n");
617 SV_ClientPrint("Host_Tell: invalid player name/ID\n");
620 // remove trailing newlines
621 while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
623 // remove quotes if present
630 Con_Print("Host_Tell: missing end quote\n");
632 SV_ClientPrint("Host_Tell: missing end quote\n");
634 while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
638 for (j = (int)strlen(text);j < (int)(sizeof(text) - 2) && p1 < p2;)
644 host_client = svs.clients + playernumber;
645 SV_ClientPrint(text);
655 static void SV_Ping_f(cmd_state_t *cmd)
659 void (*print) (const char *fmt, ...);
661 if (cmd->source == src_command)
663 // if running a client, try to send over network so the client's ping report parser will see the report
664 if (cls.state == ca_connected)
666 CL_ForwardToServer_f(cmd);
672 print = SV_ClientPrintf;
677 print("Client ping times:\n");
678 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
682 print("%4i %s\n", bound(0, (int)floor(client->ping*1000+0.5), 9999), client->name);
690 Send back ping and packet loss update for all current players to this player
693 static void SV_Pings_f(cmd_state_t *cmd)
695 int i, j, ping, packetloss, movementloss;
698 if (!host_client->netconnection)
701 if (sv.protocol != PROTOCOL_QUAKEWORLD)
703 MSG_WriteByte(&host_client->netconnection->message, svc_stufftext);
704 MSG_WriteUnterminatedString(&host_client->netconnection->message, "pingplreport");
706 for (i = 0;i < svs.maxclients;i++)
710 if (svs.clients[i].netconnection)
712 for (j = 0;j < NETGRAPH_PACKETS;j++)
713 if (svs.clients[i].netconnection->incoming_netgraph[j].unreliablebytes == NETGRAPH_LOSTPACKET)
715 for (j = 0;j < NETGRAPH_PACKETS;j++)
716 if (svs.clients[i].movement_count[j] < 0)
719 packetloss = (packetloss * 100 + NETGRAPH_PACKETS - 1) / NETGRAPH_PACKETS;
720 movementloss = (movementloss * 100 + NETGRAPH_PACKETS - 1) / NETGRAPH_PACKETS;
721 ping = (int)floor(svs.clients[i].ping*1000+0.5);
722 ping = bound(0, ping, 9999);
723 if (sv.protocol == PROTOCOL_QUAKEWORLD)
725 // send qw_svc_updateping and qw_svc_updatepl messages
726 MSG_WriteByte(&host_client->netconnection->message, qw_svc_updateping);
727 MSG_WriteShort(&host_client->netconnection->message, ping);
728 MSG_WriteByte(&host_client->netconnection->message, qw_svc_updatepl);
729 MSG_WriteByte(&host_client->netconnection->message, packetloss);
733 // write the string into the packet as multiple unterminated strings to avoid needing a local buffer
735 dpsnprintf(temp, sizeof(temp), " %d %d,%d", ping, packetloss, movementloss);
737 dpsnprintf(temp, sizeof(temp), " %d %d", ping, packetloss);
738 MSG_WriteUnterminatedString(&host_client->netconnection->message, temp);
741 if (sv.protocol != PROTOCOL_QUAKEWORLD)
742 MSG_WriteString(&host_client->netconnection->message, "\n");
749 user <name or userid>
751 Dump userdata / masterdata for a user
754 static void SV_User_f(cmd_state_t *cmd) // credit: taken from QuakeWorld
759 if (Cmd_Argc(cmd) != 2)
761 Con_Printf ("Usage: user <username / userid>\n");
765 uid = atoi(Cmd_Argv(cmd, 1));
767 for (i = 0;i < cl.maxclients;i++)
769 if (!cl.scores[i].name[0])
771 if (cl.scores[i].qw_userid == uid || !strcasecmp(cl.scores[i].name, Cmd_Argv(cmd, 1)))
773 InfoString_Print(cl.scores[i].qw_userinfo);
777 Con_Printf ("User not in server.\n");
784 Dump userids for all current players
787 static void SV_Users_f(cmd_state_t *cmd) // credit: taken from QuakeWorld
793 Con_Printf ("userid frags name\n");
794 Con_Printf ("------ ----- ----\n");
795 for (i = 0;i < cl.maxclients;i++)
797 if (cl.scores[i].name[0])
799 Con_Printf ("%6i %4i %s\n", cl.scores[i].qw_userid, cl.scores[i].frags, cl.scores[i].name);
804 Con_Printf ("%i total users\n", c);
812 static void SV_Status_f(cmd_state_t *cmd)
814 prvm_prog_t *prog = SVVM_prog;
817 int seconds = 0, minutes = 0, hours = 0, i, j, k, in, players, ping = 0, packetloss = 0;
818 void (*print) (const char *fmt, ...);
819 char ip[48]; // can contain a full length v6 address with [] and a port
823 if (cmd->source == src_command)
826 print = SV_ClientPrintf;
832 if (Cmd_Argc(cmd) == 2)
834 if (strcmp(Cmd_Argv(cmd, 1), "1") == 0)
836 else if (strcmp(Cmd_Argv(cmd, 1), "2") == 0)
840 for (players = 0, i = 0;i < svs.maxclients;i++)
841 if (svs.clients[i].active)
843 print ("host: %s\n", Cvar_VariableString (&cvars_all, "hostname", CVAR_SERVER));
844 print ("version: %s build %s (gamename %s)\n", gamename, buildstring, gamenetworkfiltername);
845 print ("protocol: %i (%s)\n", Protocol_NumberForEnum(sv.protocol), Protocol_NameForEnum(sv.protocol));
846 print ("map: %s\n", sv.name);
847 print ("timing: %s\n", Host_TimingReport(vabuf, sizeof(vabuf)));
848 print ("players: %i active (%i max)\n\n", players, svs.maxclients);
851 print ("^2IP %%pl ping time frags no name\n");
853 print ("^5IP no name\n");
855 for (i = 0, k = 0, client = svs.clients;i < svs.maxclients;i++, client++)
862 if (in == 0 || in == 1)
864 seconds = (int)(host.realtime - client->connecttime);
865 minutes = seconds / 60;
868 seconds -= (minutes * 60);
869 hours = minutes / 60;
871 minutes -= (hours * 60);
877 if (client->netconnection)
878 for (j = 0;j < NETGRAPH_PACKETS;j++)
879 if (client->netconnection->incoming_netgraph[j].unreliablebytes == NETGRAPH_LOSTPACKET)
881 packetloss = (packetloss * 100 + NETGRAPH_PACKETS - 1) / NETGRAPH_PACKETS;
882 ping = bound(0, (int)floor(client->ping*1000+0.5), 9999);
885 if(sv_status_privacy.integer && cmd->source != src_command && LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) != LHNETADDRESSTYPE_LOOP)
886 strlcpy(ip, client->netconnection ? "hidden" : "botclient", 48);
888 strlcpy(ip, (client->netconnection && *client->netconnection->address) ? client->netconnection->address : "botclient", 48);
890 frags = client->frags;
892 if(sv_status_show_qcstatus.integer)
894 prvm_edict_t *ed = PRVM_EDICT_NUM(i + 1);
895 const char *str = PRVM_GetString(prog, PRVM_serveredictstring(ed, clientstatus));
901 for(q = str; *q && p != qcstatus + sizeof(qcstatus) - 1; ++q)
902 if(*q != '\\' && *q != '"' && !ISWHITESPACE(*q))
906 frags = atoi(qcstatus);
910 if (in == 0) // default layout
912 if (sv.protocol == PROTOCOL_QUAKE && svs.maxclients <= 99)
914 // LadyHavoc: this is very touchy because we must maintain ProQuake compatible status output
915 print ("#%-2u %-16.16s %3i %2i:%02i:%02i\n", i+1, client->name, frags, hours, minutes, seconds);
920 // LadyHavoc: no real restrictions here, not a ProQuake-compatible protocol anyway...
921 print ("#%-3u %-16.16s %4i %2i:%02i:%02i\n", i+1, client->name, frags, hours, minutes, seconds);
925 else if (in == 1) // extended layout
927 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);
929 else if (in == 2) // reduced layout
931 print ("%s%-47s #%-3u ^7%s\n", k%2 ? "^3" : "^7", ip, i+1, client->name);
936 void SV_Name(int clientnum)
938 prvm_prog_t *prog = SVVM_prog;
939 PRVM_serveredictstring(host_client->edict, netname) = PRVM_SetEngineString(prog, host_client->name);
940 if (strcmp(host_client->old_name, host_client->name))
942 if (host_client->begun)
943 SV_BroadcastPrintf("\003%s ^7changed name to ^3%s\n", host_client->old_name, host_client->name);
944 strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
945 // send notification to all clients
946 MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
947 MSG_WriteByte (&sv.reliable_datagram, clientnum);
948 MSG_WriteString (&sv.reliable_datagram, host_client->name);
949 SV_WriteNetnameIntoDemo(host_client);
954 ======================
956 ======================
958 static void SV_Name_f(cmd_state_t *cmd)
961 qboolean valid_colors;
962 const char *newNameSource;
963 char newName[sizeof(host_client->name)];
965 if (Cmd_Argc (cmd) == 1)
968 if (Cmd_Argc (cmd) == 2)
969 newNameSource = Cmd_Argv(cmd, 1);
971 newNameSource = Cmd_Args(cmd);
973 strlcpy(newName, newNameSource, sizeof(newName));
975 if (cmd->source == src_command)
978 if (host.realtime < host_client->nametime && strcmp(newName, host_client->name))
980 SV_ClientPrintf("You can't change name more than once every %.1f seconds!\n", max(0.0f, sv_namechangetimer.value));
984 host_client->nametime = host.realtime + max(0.0f, sv_namechangetimer.value);
986 // point the string back at updateclient->name to keep it safe
987 strlcpy (host_client->name, newName, sizeof (host_client->name));
989 for (i = 0, j = 0;host_client->name[i];i++)
990 if (host_client->name[i] != '\r' && host_client->name[i] != '\n')
991 host_client->name[j++] = host_client->name[i];
992 host_client->name[j] = 0;
994 if(host_client->name[0] == 1 || host_client->name[0] == 2)
995 // may interfere with chat area, and will needlessly beep; so let's add a ^7
997 memmove(host_client->name + 2, host_client->name, sizeof(host_client->name) - 2);
998 host_client->name[sizeof(host_client->name) - 1] = 0;
999 host_client->name[0] = STRING_COLOR_TAG;
1000 host_client->name[1] = '0' + STRING_COLOR_DEFAULT;
1003 u8_COM_StringLengthNoColors(host_client->name, 0, &valid_colors);
1004 if(!valid_colors) // NOTE: this also proves the string is not empty, as "" is a valid colored string
1007 l = strlen(host_client->name);
1008 if(l < sizeof(host_client->name) - 1)
1010 // duplicate the color tag to escape it
1011 host_client->name[i] = STRING_COLOR_TAG;
1012 host_client->name[i+1] = 0;
1013 //Con_DPrintf("abuse detected, adding another trailing color tag\n");
1017 // remove the last character to fix the color code
1018 host_client->name[l-1] = 0;
1019 //Con_DPrintf("abuse detected, removing a trailing color tag\n");
1023 // find the last color tag offset and decide if we need to add a reset tag
1024 for (i = 0, j = -1;host_client->name[i];i++)
1026 if (host_client->name[i] == STRING_COLOR_TAG)
1028 if (host_client->name[i+1] >= '0' && host_client->name[i+1] <= '9')
1031 // if this happens to be a reset tag then we don't need one
1032 if (host_client->name[i+1] == '0' + STRING_COLOR_DEFAULT)
1037 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]))
1043 if (host_client->name[i+1] == STRING_COLOR_TAG)
1050 // does not end in the default color string, so add it
1051 if (j >= 0 && strlen(host_client->name) < sizeof(host_client->name) - 2)
1052 memcpy(host_client->name + strlen(host_client->name), STRING_COLOR_DEFAULT_STR, strlen(STRING_COLOR_DEFAULT_STR) + 1);
1054 SV_Name(host_client - svs.clients);
1057 static void SV_Rate_f(cmd_state_t *cmd)
1061 rate = atoi(Cmd_Argv(cmd, 1));
1063 if (cmd->source == src_command)
1066 host_client->rate = rate;
1069 static void SV_Rate_BurstSize_f(cmd_state_t *cmd)
1073 if (Cmd_Argc(cmd) != 2)
1076 rate_burstsize = atoi(Cmd_Argv(cmd, 1));
1078 host_client->rate_burstsize = rate_burstsize;
1081 static void SV_Color_f(cmd_state_t *cmd)
1083 prvm_prog_t *prog = SVVM_prog;
1085 int top, bottom, playercolor;
1087 top = atoi(Cmd_Argv(cmd, 1));
1088 bottom = atoi(Cmd_Argv(cmd, 2));
1093 playercolor = top*16 + bottom;
1095 if (host_client->edict && PRVM_serverfunction(SV_ChangeTeam))
1097 Con_DPrint("Calling SV_ChangeTeam\n");
1098 prog->globals.fp[OFS_PARM0] = playercolor;
1099 PRVM_serverglobalfloat(time) = sv.time;
1100 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict);
1101 prog->ExecuteProgram(prog, PRVM_serverfunction(SV_ChangeTeam), "QC function SV_ChangeTeam is missing");
1105 if (host_client->edict)
1107 PRVM_serveredictfloat(host_client->edict, clientcolors) = playercolor;
1108 PRVM_serveredictfloat(host_client->edict, team) = bottom + 1;
1110 host_client->colors = playercolor;
1111 if (host_client->old_colors != host_client->colors)
1113 host_client->old_colors = host_client->colors;
1114 // send notification to all clients
1115 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1116 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1117 MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1126 Kicks a user off of the server
1129 static void SV_Kick_f(cmd_state_t *cmd)
1132 const char *message = NULL;
1135 qboolean byNumber = false;
1142 if (Cmd_Argc(cmd) > 2 && strcmp(Cmd_Argv(cmd, 1), "#") == 0)
1144 i = (int)(atof(Cmd_Argv(cmd, 2)) - 1);
1145 if (i < 0 || i >= svs.maxclients || !(host_client = svs.clients + i)->active)
1151 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1153 if (!host_client->active)
1155 if (strcasecmp(host_client->name, Cmd_Argv(cmd, 1)) == 0)
1160 if (i < svs.maxclients)
1162 if (cmd->source == src_command)
1164 if (cls.state == ca_dedicated)
1167 who = cl_name.string;
1172 // can't kick yourself!
1173 if (host_client == save)
1176 if (Cmd_Argc(cmd) > 2)
1178 message = Cmd_Args(cmd);
1179 COM_ParseToken_Simple(&message, false, false, true);
1182 message++; // skip the #
1183 while (*message == ' ') // skip white space
1185 message += strlen(Cmd_Argv(cmd, 2)); // skip the number
1187 while (*message && *message == ' ')
1191 SV_ClientPrintf("Kicked by %s: %s\n", who, message);
1193 SV_ClientPrintf("Kicked by %s\n", who);
1194 SV_DropClient (false); // kicked
1200 static void SV_MaxPlayers_f(cmd_state_t *cmd)
1204 if (Cmd_Argc(cmd) != 2)
1206 Con_Printf("\"maxplayers\" is \"%u\"\n", svs.maxclients_next);
1212 Con_Print("maxplayers can not be changed while a server is running.\n");
1213 Con_Print("It will be changed on next server startup (\"map\" command).\n");
1216 n = atoi(Cmd_Argv(cmd, 1));
1217 n = bound(1, n, MAX_SCOREBOARD);
1218 Con_Printf("\"maxplayers\" set to \"%u\"\n", n);
1220 svs.maxclients_next = n;
1222 Cvar_Set (&cvars_all, "deathmatch", "0");
1224 Cvar_Set (&cvars_all, "deathmatch", "1");
1228 ======================
1230 ======================
1232 // the old playermodel in cl_main has been renamed to __cl_playermodel
1233 static void SV_Playermodel_f(cmd_state_t *cmd)
1235 prvm_prog_t *prog = SVVM_prog;
1237 char newPath[sizeof(host_client->playermodel)];
1239 if (Cmd_Argc (cmd) == 1)
1242 if (Cmd_Argc (cmd) == 2)
1243 strlcpy (newPath, Cmd_Argv(cmd, 1), sizeof (newPath));
1245 strlcpy (newPath, Cmd_Args(cmd), sizeof (newPath));
1247 for (i = 0, j = 0;newPath[i];i++)
1248 if (newPath[i] != '\r' && newPath[i] != '\n')
1249 newPath[j++] = newPath[i];
1253 if (host.realtime < host_client->nametime)
1255 SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
1259 host_client->nametime = host.realtime + 5;
1262 // point the string back at updateclient->name to keep it safe
1263 strlcpy (host_client->playermodel, newPath, sizeof (host_client->playermodel));
1264 PRVM_serveredictstring(host_client->edict, playermodel) = PRVM_SetEngineString(prog, host_client->playermodel);
1265 if (strcmp(host_client->old_model, host_client->playermodel))
1267 strlcpy(host_client->old_model, host_client->playermodel, sizeof(host_client->old_model));
1268 /*// send notification to all clients
1269 MSG_WriteByte (&sv.reliable_datagram, svc_updatepmodel);
1270 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1271 MSG_WriteString (&sv.reliable_datagram, host_client->playermodel);*/
1276 ======================
1278 ======================
1280 static void SV_Playerskin_f(cmd_state_t *cmd)
1282 prvm_prog_t *prog = SVVM_prog;
1284 char newPath[sizeof(host_client->playerskin)];
1286 if (Cmd_Argc (cmd) == 1)
1289 if (Cmd_Argc (cmd) == 2)
1290 strlcpy (newPath, Cmd_Argv(cmd, 1), sizeof (newPath));
1292 strlcpy (newPath, Cmd_Args(cmd), sizeof (newPath));
1294 for (i = 0, j = 0;newPath[i];i++)
1295 if (newPath[i] != '\r' && newPath[i] != '\n')
1296 newPath[j++] = newPath[i];
1300 if (host.realtime < host_client->nametime)
1302 SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
1306 host_client->nametime = host.realtime + 5;
1309 // point the string back at updateclient->name to keep it safe
1310 strlcpy (host_client->playerskin, newPath, sizeof (host_client->playerskin));
1311 PRVM_serveredictstring(host_client->edict, playerskin) = PRVM_SetEngineString(prog, host_client->playerskin);
1312 if (strcmp(host_client->old_skin, host_client->playerskin))
1314 //if (host_client->begun)
1315 // SV_BroadcastPrintf("%s changed skin to %s\n", host_client->name, host_client->playerskin);
1316 strlcpy(host_client->old_skin, host_client->playerskin, sizeof(host_client->old_skin));
1317 /*// send notification to all clients
1318 MSG_WriteByte (&sv.reliable_datagram, svc_updatepskin);
1319 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1320 MSG_WriteString (&sv.reliable_datagram, host_client->playerskin);*/
1325 ======================
1327 LadyHavoc: only supported for Nehahra, I personally think this is dumb, but Mindcrime won't listen.
1328 LadyHavoc: correction, Mindcrime will be removing pmodel in the future, but it's still stuck here for compatibility.
1329 ======================
1331 static void SV_PModel_f(cmd_state_t *cmd)
1333 prvm_prog_t *prog = SVVM_prog;
1335 if (Cmd_Argc (cmd) == 1)
1338 PRVM_serveredictfloat(host_client->edict, pmodel) = atoi(Cmd_Argv(cmd, 1));
1342 ===============================================================================
1346 ===============================================================================
1349 static prvm_edict_t *FindViewthing(prvm_prog_t *prog)
1354 for (i=0 ; i<prog->num_edicts ; i++)
1356 e = PRVM_EDICT_NUM(i);
1357 if (!strcmp (PRVM_GetString(prog, PRVM_serveredictstring(e, classname)), "viewthing"))
1360 Con_Print("No viewthing on map\n");
1369 static void SV_Viewmodel_f(cmd_state_t *cmd)
1371 prvm_prog_t *prog = SVVM_prog;
1378 e = FindViewthing(prog);
1381 m = Mod_ForName (Cmd_Argv(cmd, 1), false, true, NULL);
1382 if (m && m->loaded && m->Draw)
1384 PRVM_serveredictfloat(e, frame) = 0;
1385 cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)] = m;
1388 Con_Printf("viewmodel: can't load %s\n", Cmd_Argv(cmd, 1));
1397 static void SV_Viewframe_f(cmd_state_t *cmd)
1399 prvm_prog_t *prog = SVVM_prog;
1407 e = FindViewthing(prog);
1410 m = cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)];
1412 f = atoi(Cmd_Argv(cmd, 1));
1413 if (f >= m->numframes)
1416 PRVM_serveredictfloat(e, frame) = f;
1420 static void PrintFrameName (dp_model_t *m, int frame)
1423 Con_Printf("frame %i: %s\n", frame, m->animscenes[frame].name);
1425 Con_Printf("frame %i\n", frame);
1433 static void SV_Viewnext_f(cmd_state_t *cmd)
1435 prvm_prog_t *prog = SVVM_prog;
1442 e = FindViewthing(prog);
1445 m = cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)];
1447 PRVM_serveredictfloat(e, frame) = PRVM_serveredictfloat(e, frame) + 1;
1448 if (PRVM_serveredictfloat(e, frame) >= m->numframes)
1449 PRVM_serveredictfloat(e, frame) = m->numframes - 1;
1451 PrintFrameName (m, (int)PRVM_serveredictfloat(e, frame));
1460 static void SV_Viewprev_f(cmd_state_t *cmd)
1462 prvm_prog_t *prog = SVVM_prog;
1469 e = FindViewthing(prog);
1472 m = cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)];
1474 PRVM_serveredictfloat(e, frame) = PRVM_serveredictfloat(e, frame) - 1;
1475 if (PRVM_serveredictfloat(e, frame) < 0)
1476 PRVM_serveredictfloat(e, frame) = 0;
1478 PrintFrameName (m, (int)PRVM_serveredictfloat(e, frame));
1482 static void SV_SendCvar_f(cmd_state_t *cmd)
1485 const char *cvarname;
1488 if(Cmd_Argc(cmd) != 2)
1491 if(!sv.active)// || !PRVM_serverfunction(SV_ParseClientCommand))
1494 cvarname = Cmd_Argv(cmd, 1);
1497 if (cls.state != ca_dedicated)
1501 for(;i<svs.maxclients;i++)
1502 if(svs.clients[i].active && svs.clients[i].netconnection)
1504 host_client = &svs.clients[i];
1505 SV_ClientCommands("sendcvar %s\n", cvarname);
1510 static void SV_Ent_Create_f(cmd_state_t *cmd)
1512 prvm_prog_t *prog = SVVM_prog;
1516 qboolean haveorigin;
1518 qboolean expectval = false;
1519 void (*print)(const char *, ...) = (cmd->source == src_client ? SV_ClientPrintf : Con_Printf);
1524 ed = PRVM_ED_Alloc(SVVM_prog);
1526 PRVM_ED_ParseEpair(prog, ed, PRVM_ED_FindField(prog, "classname"), Cmd_Argv(cmd, 1), false);
1528 // Spawn where the player is aiming. We need a view matrix first.
1529 if(cmd->source == src_client)
1531 vec3_t org, temp, dest;
1536 SV_GetEntityMatrix(prog, host_client->edict, &view, true);
1538 Matrix4x4_OriginFromMatrix(&view, org);
1539 VectorSet(temp, 65536, 0, 0);
1540 Matrix4x4_Transform(&view, temp, dest);
1542 trace = SV_TraceLine(org, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, 0, 0, collision_extendmovelength.value);
1544 dpsnprintf(buf, sizeof(buf), "%g %g %g", trace.endpos[0], trace.endpos[1], trace.endpos[2]);
1545 PRVM_ED_ParseEpair(prog, ed, PRVM_ED_FindField(prog, "origin"), buf, false);
1549 // Or spawn at a specified origin.
1556 // Allow more than one key/value pair by cycling between expecting either one.
1557 for(i = 2; i < Cmd_Argc(cmd); i++)
1561 if(!(key = PRVM_ED_FindField(prog, Cmd_Argv(cmd, i))))
1563 print("Key %s not found!\n", Cmd_Argv(cmd, i));
1564 PRVM_ED_Free(prog, ed);
1569 * This is mostly for dedicated server console, but if the
1570 * player gave a custom origin, we can ignore the traceline.
1572 if(!strcmp(Cmd_Argv(cmd, i), "origin"))
1579 PRVM_ED_ParseEpair(prog, ed, key, Cmd_Argv(cmd, i), false);
1586 print("Missing origin\n");
1587 PRVM_ED_Free(prog, ed);
1592 PRVM_ED_CallPrespawnFunction(prog, ed);
1594 if(!PRVM_ED_CallSpawnFunction(prog, ed, NULL, NULL))
1596 print("Could not spawn a \"%s\". No such entity or it has no spawn function\n", Cmd_Argv(cmd, 1));
1597 if(cmd->source == src_client)
1598 Con_Printf("%s tried to spawn a \"%s\"\n", host_client->name, Cmd_Argv(cmd, 1));
1599 // CallSpawnFunction already freed the edict for us.
1603 PRVM_ED_CallPostspawnFunction(prog, ed);
1605 // Make it appear in the world
1608 if(cmd->source == src_client)
1609 Con_Printf("%s spawned a \"%s\"\n", host_client->name, Cmd_Argv(cmd, 1));
1612 static void SV_Ent_Remove_f(cmd_state_t *cmd)
1614 prvm_prog_t *prog = SVVM_prog;
1617 void (*print)(const char *, ...) = (cmd->source == src_client ? SV_ClientPrintf : Con_Printf);
1622 // Allow specifying edict by number
1623 if(Cmd_Argc(cmd) > 1 && Cmd_Argv(cmd, 1))
1625 ednum = atoi(Cmd_Argv(cmd, 1));
1628 print("Cannot remove the world\n");
1632 // Or trace a line if it's a client who didn't specify one.
1633 else if(cmd->source == src_client)
1635 vec3_t org, temp, dest;
1639 SV_GetEntityMatrix(prog, host_client->edict, &view, true);
1641 Matrix4x4_OriginFromMatrix(&view, org);
1642 VectorSet(temp, 65536, 0, 0);
1643 Matrix4x4_Transform(&view, temp, dest);
1645 trace = SV_TraceLine(org, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY, 0, 0, collision_extendmovelength.value);
1648 ednum = (int)PRVM_EDICT_TO_PROG(trace.ent);
1649 if(!trace.ent || !ednum)
1650 // Don't remove the world, but don't annoy players with a print if they miss
1655 // Only a dedicated server console should be able to reach this.
1656 print("No edict given\n");
1660 ed = PRVM_EDICT_NUM(ednum);
1665 for (i = 0; i < svs.maxclients; i++)
1667 if(ed == svs.clients[i].edict)
1671 if(!ed->priv.required->free)
1673 print("Removed a \"%s\"\n", PRVM_GetString(prog, PRVM_serveredictstring(ed, classname)));
1674 PRVM_ED_ClearEdict(prog, ed);
1675 PRVM_ED_Free(prog, ed);
1680 // This should only be reachable if an invalid edict number was given
1681 print("No such entity\n");
1686 static void SV_Ent_Remove_All_f(cmd_state_t *cmd)
1688 prvm_prog_t *prog = SVVM_prog;
1691 void (*print)(const char *, ...) = (cmd->source == src_client ? SV_ClientPrintf : Con_Printf);
1693 for (i = 0, rmcount = 0, ed = PRVM_EDICT_NUM(i); i < prog->num_edicts; i++, ed = PRVM_NEXT_EDICT(ed))
1695 if(!ed->priv.required->free && !strcmp(PRVM_GetString(prog, PRVM_serveredictstring(ed, classname)), Cmd_Argv(cmd, 1)))
1699 print("Cannot remove the world\n");
1702 PRVM_ED_ClearEdict(prog, ed);
1703 PRVM_ED_Free(prog, ed);
1709 print("No \"%s\" found\n", Cmd_Argv(cmd, 1));
1711 print("Removed %i of \"%s\"\n", rmcount, Cmd_Argv(cmd, 1));
1714 void SV_InitOperatorCommands(void)
1716 Cvar_RegisterVariable(&sv_cheats);
1717 Cvar_RegisterCallback(&sv_cheats, SV_DisableCheats_c);
1718 Cvar_RegisterVariable(&sv_adminnick);
1719 Cvar_RegisterVariable(&sv_status_privacy);
1720 Cvar_RegisterVariable(&sv_status_show_qcstatus);
1721 Cvar_RegisterVariable(&sv_namechangetimer);
1723 Cmd_AddCommand(CMD_SERVER | CMD_SERVER_FROM_CLIENT, "status", SV_Status_f, "print server status information");
1724 Cmd_AddCommand(CMD_SHARED, "map", SV_Map_f, "kick everyone off the server and start a new level");
1725 Cmd_AddCommand(CMD_SHARED, "restart", SV_Restart_f, "restart current level");
1726 Cmd_AddCommand(CMD_SHARED, "changelevel", SV_Changelevel_f, "change to another level, bringing along all connected clients");
1727 Cmd_AddCommand(CMD_SHARED | CMD_SERVER_FROM_CLIENT, "say", SV_Say_f, "send a chat message to everyone on the server");
1728 Cmd_AddCommand(CMD_SERVER_FROM_CLIENT, "say_team", SV_Say_Team_f, "send a chat message to your team on the server");
1729 Cmd_AddCommand(CMD_SHARED | CMD_SERVER_FROM_CLIENT, "tell", SV_Tell_f, "send a chat message to only one person on the server");
1730 Cmd_AddCommand(CMD_SERVER | CMD_SERVER_FROM_CLIENT, "pause", SV_Pause_f, "pause the game (if the server allows pausing)");
1731 Cmd_AddCommand(CMD_SHARED, "kick", SV_Kick_f, "kick a player off the server by number or name");
1732 Cmd_AddCommand(CMD_SHARED | CMD_SERVER_FROM_CLIENT, "ping", SV_Ping_f, "print ping times of all players on the server");
1733 Cmd_AddCommand(CMD_SHARED, "load", SV_Loadgame_f, "load a saved game file");
1734 Cmd_AddCommand(CMD_SHARED, "save", SV_Savegame_f, "save the game to a file");
1735 Cmd_AddCommand(CMD_SHARED, "viewmodel", SV_Viewmodel_f, "change model of viewthing entity in current level");
1736 Cmd_AddCommand(CMD_SHARED, "viewframe", SV_Viewframe_f, "change animation frame of viewthing entity in current level");
1737 Cmd_AddCommand(CMD_SHARED, "viewnext", SV_Viewnext_f, "change to next animation frame of viewthing entity in current level");
1738 Cmd_AddCommand(CMD_SHARED, "viewprev", SV_Viewprev_f, "change to previous animation frame of viewthing entity in current level");
1739 Cmd_AddCommand(CMD_SHARED, "maxplayers", SV_MaxPlayers_f, "sets limit on how many players (or bots) may be connected to the server at once");
1740 Cmd_AddCommand(CMD_SHARED, "user", SV_User_f, "prints additional information about a player number or name on the scoreboard");
1741 Cmd_AddCommand(CMD_SHARED, "users", SV_Users_f, "prints additional information about all players on the scoreboard");
1742 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");
1744 // 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)
1745 Cmd_AddCommand(CMD_SERVER_FROM_CLIENT, "prespawn", SV_PreSpawn_f, "internal use - signon 1 (client acknowledges that server information has been received)");
1746 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)");
1747 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)");
1748 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)");
1750 Cmd_AddCommand(CMD_CHEAT | CMD_SERVER_FROM_CLIENT, "god", SV_God_f, "god mode (invulnerability)");
1751 Cmd_AddCommand(CMD_CHEAT | CMD_SERVER_FROM_CLIENT, "notarget", SV_Notarget_f, "notarget mode (monsters do not see you)");
1752 Cmd_AddCommand(CMD_CHEAT | CMD_SERVER_FROM_CLIENT, "fly", SV_Fly_f, "fly mode (flight)");
1753 Cmd_AddCommand(CMD_CHEAT | CMD_SERVER_FROM_CLIENT, "noclip", SV_Noclip_f, "noclip mode (flight without collisions, move through walls)");
1754 Cmd_AddCommand(CMD_CHEAT | CMD_SERVER_FROM_CLIENT, "give", SV_Give_f, "alter inventory");
1755 Cmd_AddCommand(CMD_SERVER_FROM_CLIENT, "kill", SV_Kill_f, "die instantly");
1757 Cmd_AddCommand(CMD_USERINFO, "color", SV_Color_f, "change your player shirt and pants colors");
1758 Cmd_AddCommand(CMD_USERINFO, "name", SV_Name_f, "change your player name");
1759 Cmd_AddCommand(CMD_USERINFO, "rate", SV_Rate_f, "change your network connection speed");
1760 Cmd_AddCommand(CMD_USERINFO, "rate_burstsize", SV_Rate_BurstSize_f, "change your network connection speed");
1761 Cmd_AddCommand(CMD_USERINFO, "pmodel", SV_PModel_f, "(Nehahra-only) change your player model choice");
1762 Cmd_AddCommand(CMD_USERINFO, "playermodel", SV_Playermodel_f, "change your player model");
1763 Cmd_AddCommand(CMD_USERINFO, "playerskin", SV_Playerskin_f, "change your player skin number");
1765 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.");
1766 Cmd_AddCommand(CMD_CHEAT | CMD_SERVER_FROM_CLIENT, "ent_remove_all", SV_Ent_Remove_All_f, "Removes all entities of the specified classname");
1767 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");