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)
414 print = SV_ClientPrintf;
416 if (!pausable.integer)
418 if (cmd->source == src_client)
420 if(cls.state == ca_dedicated || host_client != &svs.clients[0]) // non-admin
422 print("Pause not allowed.\n");
429 if (cmd->source != src_command)
430 SV_BroadcastPrintf("%s %spaused the game\n", host_client->name, sv.paused ? "" : "un");
431 else if(*(sv_adminnick.string))
432 SV_BroadcastPrintf("%s %spaused the game\n", sv_adminnick.string, sv.paused ? "" : "un");
434 SV_BroadcastPrintf("%s %spaused the game\n", hostname.string, sv.paused ? "" : "un");
435 // send notification to all clients
436 MSG_WriteByte(&sv.reliable_datagram, svc_setpause);
437 MSG_WriteByte(&sv.reliable_datagram, sv.paused);
440 static void SV_Say(cmd_state_t *cmd, qboolean teamonly)
442 prvm_prog_t *prog = SVVM_prog;
447 // LadyHavoc: long say messages
449 qboolean fromServer = false;
451 if (cmd->source == src_command)
453 if (cls.state == ca_dedicated)
460 CL_ForwardToServer_f(cmd);
465 if (Cmd_Argc (cmd) < 2)
468 if (!teamplay.integer)
478 // note this uses the chat prefix \001
479 if (!fromServer && !teamonly)
480 dpsnprintf (text, sizeof(text), "\001%s: %s", host_client->name, p1);
481 else if (!fromServer && teamonly)
482 dpsnprintf (text, sizeof(text), "\001(%s): %s", host_client->name, p1);
483 else if(*(sv_adminnick.string))
484 dpsnprintf (text, sizeof(text), "\001<%s> %s", sv_adminnick.string, p1);
486 dpsnprintf (text, sizeof(text), "\001<%s> %s", hostname.string, p1);
487 p2 = text + strlen(text);
488 while ((const char *)p2 > (const char *)text && (p2[-1] == '\r' || p2[-1] == '\n' || (p2[-1] == '\"' && quoted)))
490 if (p2[-1] == '\"' && quoted)
495 strlcat(text, "\n", sizeof(text));
497 // note: save is not a valid edict if fromServer is true
499 for (j = 0, host_client = svs.clients;j < svs.maxclients;j++, host_client++)
500 if (host_client->active && (!teamonly || PRVM_serveredictfloat(host_client->edict, team) == PRVM_serveredictfloat(save->edict, team)))
501 SV_ClientPrint(text);
504 if (cls.state == ca_dedicated)
508 static void SV_Say_f(cmd_state_t *cmd)
513 static void SV_Say_Team_f(cmd_state_t *cmd)
518 static void SV_Tell_f(cmd_state_t *cmd)
520 const char *playername_start = NULL;
521 size_t playername_length = 0;
522 int playernumber = 0;
526 char text[MAX_INPUTLINE]; // LadyHavoc: FIXME: temporary buffer overflow fix (was 64)
527 qboolean fromServer = false;
529 if (cmd->source == src_command)
531 if (cls.state == ca_dedicated)
535 CL_ForwardToServer_f(cmd);
540 if (Cmd_Argc (cmd) < 2)
543 // note this uses the chat prefix \001
545 dpsnprintf (text, sizeof(text), "\001%s tells you: ", host_client->name);
546 else if(*(sv_adminnick.string))
547 dpsnprintf (text, sizeof(text), "\001<%s tells you> ", sv_adminnick.string);
549 dpsnprintf (text, sizeof(text), "\001<%s tells you> ", hostname.string);
552 p2 = p1 + strlen(p1);
553 // remove the target name
554 while (p1 < p2 && *p1 == ' ')
559 while (p1 < p2 && *p1 == ' ')
561 while (p1 < p2 && isdigit(*p1))
563 playernumber = playernumber * 10 + (*p1 - '0');
571 playername_start = p1;
572 while (p1 < p2 && *p1 != '"')
574 playername_length = p1 - playername_start;
580 playername_start = p1;
581 while (p1 < p2 && *p1 != ' ')
583 playername_length = p1 - playername_start;
585 while (p1 < p2 && *p1 == ' ')
589 // set playernumber to the right client
591 if(playername_length >= sizeof(namebuf))
594 Con_Print("Host_Tell: too long player name/ID\n");
596 SV_ClientPrint("Host_Tell: too long player name/ID\n");
599 memcpy(namebuf, playername_start, playername_length);
600 namebuf[playername_length] = 0;
601 for (playernumber = 0; playernumber < svs.maxclients; playernumber++)
603 if (!svs.clients[playernumber].active)
605 if (strcasecmp(svs.clients[playernumber].name, namebuf) == 0)
609 if(playernumber < 0 || playernumber >= svs.maxclients || !(svs.clients[playernumber].active))
612 Con_Print("Host_Tell: invalid player name/ID\n");
614 SV_ClientPrint("Host_Tell: invalid player name/ID\n");
617 // remove trailing newlines
618 while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
620 // remove quotes if present
627 Con_Print("Host_Tell: missing end quote\n");
629 SV_ClientPrint("Host_Tell: missing end quote\n");
631 while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
635 for (j = (int)strlen(text);j < (int)(sizeof(text) - 2) && p1 < p2;)
641 host_client = svs.clients + playernumber;
642 SV_ClientPrint(text);
652 static void SV_Ping_f(cmd_state_t *cmd)
656 void (*print) (const char *fmt, ...);
658 if (cmd->source == src_command)
660 // if running a client, try to send over network so the client's ping report parser will see the report
661 if (cls.state == ca_connected)
663 CL_ForwardToServer_f(cmd);
669 print = SV_ClientPrintf;
674 print("Client ping times:\n");
675 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
679 print("%4i %s\n", bound(0, (int)floor(client->ping*1000+0.5), 9999), client->name);
687 Send back ping and packet loss update for all current players to this player
690 static void SV_Pings_f(cmd_state_t *cmd)
692 int i, j, ping, packetloss, movementloss;
695 if (!host_client->netconnection)
698 if (sv.protocol != PROTOCOL_QUAKEWORLD)
700 MSG_WriteByte(&host_client->netconnection->message, svc_stufftext);
701 MSG_WriteUnterminatedString(&host_client->netconnection->message, "pingplreport");
703 for (i = 0;i < svs.maxclients;i++)
707 if (svs.clients[i].netconnection)
709 for (j = 0;j < NETGRAPH_PACKETS;j++)
710 if (svs.clients[i].netconnection->incoming_netgraph[j].unreliablebytes == NETGRAPH_LOSTPACKET)
712 for (j = 0;j < NETGRAPH_PACKETS;j++)
713 if (svs.clients[i].movement_count[j] < 0)
716 packetloss = (packetloss * 100 + NETGRAPH_PACKETS - 1) / NETGRAPH_PACKETS;
717 movementloss = (movementloss * 100 + NETGRAPH_PACKETS - 1) / NETGRAPH_PACKETS;
718 ping = (int)floor(svs.clients[i].ping*1000+0.5);
719 ping = bound(0, ping, 9999);
720 if (sv.protocol == PROTOCOL_QUAKEWORLD)
722 // send qw_svc_updateping and qw_svc_updatepl messages
723 MSG_WriteByte(&host_client->netconnection->message, qw_svc_updateping);
724 MSG_WriteShort(&host_client->netconnection->message, ping);
725 MSG_WriteByte(&host_client->netconnection->message, qw_svc_updatepl);
726 MSG_WriteByte(&host_client->netconnection->message, packetloss);
730 // write the string into the packet as multiple unterminated strings to avoid needing a local buffer
732 dpsnprintf(temp, sizeof(temp), " %d %d,%d", ping, packetloss, movementloss);
734 dpsnprintf(temp, sizeof(temp), " %d %d", ping, packetloss);
735 MSG_WriteUnterminatedString(&host_client->netconnection->message, temp);
738 if (sv.protocol != PROTOCOL_QUAKEWORLD)
739 MSG_WriteString(&host_client->netconnection->message, "\n");
746 user <name or userid>
748 Dump userdata / masterdata for a user
751 static void SV_User_f(cmd_state_t *cmd) // credit: taken from QuakeWorld
756 if (Cmd_Argc(cmd) != 2)
758 Con_Printf ("Usage: user <username / userid>\n");
762 uid = atoi(Cmd_Argv(cmd, 1));
764 for (i = 0;i < cl.maxclients;i++)
766 if (!cl.scores[i].name[0])
768 if (cl.scores[i].qw_userid == uid || !strcasecmp(cl.scores[i].name, Cmd_Argv(cmd, 1)))
770 InfoString_Print(cl.scores[i].qw_userinfo);
774 Con_Printf ("User not in server.\n");
781 Dump userids for all current players
784 static void SV_Users_f(cmd_state_t *cmd) // credit: taken from QuakeWorld
790 Con_Printf ("userid frags name\n");
791 Con_Printf ("------ ----- ----\n");
792 for (i = 0;i < cl.maxclients;i++)
794 if (cl.scores[i].name[0])
796 Con_Printf ("%6i %4i %s\n", cl.scores[i].qw_userid, cl.scores[i].frags, cl.scores[i].name);
801 Con_Printf ("%i total users\n", c);
809 static void SV_Status_f(cmd_state_t *cmd)
811 prvm_prog_t *prog = SVVM_prog;
814 int seconds = 0, minutes = 0, hours = 0, i, j, k, in, players, ping = 0, packetloss = 0;
815 void (*print) (const char *fmt, ...);
816 char ip[48]; // can contain a full length v6 address with [] and a port
820 if (cmd->source == src_command)
823 print = SV_ClientPrintf;
829 if (Cmd_Argc(cmd) == 2)
831 if (strcmp(Cmd_Argv(cmd, 1), "1") == 0)
833 else if (strcmp(Cmd_Argv(cmd, 1), "2") == 0)
837 for (players = 0, i = 0;i < svs.maxclients;i++)
838 if (svs.clients[i].active)
840 print ("host: %s\n", Cvar_VariableString (&cvars_all, "hostname", CVAR_SERVER));
841 print ("version: %s build %s (gamename %s)\n", gamename, buildstring, gamenetworkfiltername);
842 print ("protocol: %i (%s)\n", Protocol_NumberForEnum(sv.protocol), Protocol_NameForEnum(sv.protocol));
843 print ("map: %s\n", sv.name);
844 print ("timing: %s\n", Host_TimingReport(vabuf, sizeof(vabuf)));
845 print ("players: %i active (%i max)\n\n", players, svs.maxclients);
848 print ("^2IP %%pl ping time frags no name\n");
850 print ("^5IP no name\n");
852 for (i = 0, k = 0, client = svs.clients;i < svs.maxclients;i++, client++)
859 if (in == 0 || in == 1)
861 seconds = (int)(host.realtime - client->connecttime);
862 minutes = seconds / 60;
865 seconds -= (minutes * 60);
866 hours = minutes / 60;
868 minutes -= (hours * 60);
874 if (client->netconnection)
875 for (j = 0;j < NETGRAPH_PACKETS;j++)
876 if (client->netconnection->incoming_netgraph[j].unreliablebytes == NETGRAPH_LOSTPACKET)
878 packetloss = (packetloss * 100 + NETGRAPH_PACKETS - 1) / NETGRAPH_PACKETS;
879 ping = bound(0, (int)floor(client->ping*1000+0.5), 9999);
882 if(sv_status_privacy.integer && cmd->source != src_command && LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) != LHNETADDRESSTYPE_LOOP)
883 strlcpy(ip, client->netconnection ? "hidden" : "botclient", 48);
885 strlcpy(ip, (client->netconnection && *client->netconnection->address) ? client->netconnection->address : "botclient", 48);
887 frags = client->frags;
889 if(sv_status_show_qcstatus.integer)
891 prvm_edict_t *ed = PRVM_EDICT_NUM(i + 1);
892 const char *str = PRVM_GetString(prog, PRVM_serveredictstring(ed, clientstatus));
898 for(q = str; *q && p != qcstatus + sizeof(qcstatus) - 1; ++q)
899 if(*q != '\\' && *q != '"' && !ISWHITESPACE(*q))
903 frags = atoi(qcstatus);
907 if (in == 0) // default layout
909 if (sv.protocol == PROTOCOL_QUAKE && svs.maxclients <= 99)
911 // LadyHavoc: this is very touchy because we must maintain ProQuake compatible status output
912 print ("#%-2u %-16.16s %3i %2i:%02i:%02i\n", i+1, client->name, frags, hours, minutes, seconds);
917 // LadyHavoc: no real restrictions here, not a ProQuake-compatible protocol anyway...
918 print ("#%-3u %-16.16s %4i %2i:%02i:%02i\n", i+1, client->name, frags, hours, minutes, seconds);
922 else if (in == 1) // extended layout
924 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);
926 else if (in == 2) // reduced layout
928 print ("%s%-47s #%-3u ^7%s\n", k%2 ? "^3" : "^7", ip, i+1, client->name);
933 void SV_Name(int clientnum)
935 prvm_prog_t *prog = SVVM_prog;
936 PRVM_serveredictstring(host_client->edict, netname) = PRVM_SetEngineString(prog, host_client->name);
937 if (strcmp(host_client->old_name, host_client->name))
939 if (host_client->begun)
940 SV_BroadcastPrintf("\003%s ^7changed name to ^3%s\n", host_client->old_name, host_client->name);
941 strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
942 // send notification to all clients
943 MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
944 MSG_WriteByte (&sv.reliable_datagram, clientnum);
945 MSG_WriteString (&sv.reliable_datagram, host_client->name);
946 SV_WriteNetnameIntoDemo(host_client);
951 ======================
953 ======================
955 static void SV_Name_f(cmd_state_t *cmd)
958 qboolean valid_colors;
959 const char *newNameSource;
960 char newName[sizeof(host_client->name)];
962 if (Cmd_Argc (cmd) == 1)
965 if (Cmd_Argc (cmd) == 2)
966 newNameSource = Cmd_Argv(cmd, 1);
968 newNameSource = Cmd_Args(cmd);
970 strlcpy(newName, newNameSource, sizeof(newName));
972 if (cmd->source == src_command)
975 if (host.realtime < host_client->nametime && strcmp(newName, host_client->name))
977 SV_ClientPrintf("You can't change name more than once every %.1f seconds!\n", max(0.0f, sv_namechangetimer.value));
981 host_client->nametime = host.realtime + max(0.0f, sv_namechangetimer.value);
983 // point the string back at updateclient->name to keep it safe
984 strlcpy (host_client->name, newName, sizeof (host_client->name));
986 for (i = 0, j = 0;host_client->name[i];i++)
987 if (host_client->name[i] != '\r' && host_client->name[i] != '\n')
988 host_client->name[j++] = host_client->name[i];
989 host_client->name[j] = 0;
991 if(host_client->name[0] == 1 || host_client->name[0] == 2)
992 // may interfere with chat area, and will needlessly beep; so let's add a ^7
994 memmove(host_client->name + 2, host_client->name, sizeof(host_client->name) - 2);
995 host_client->name[sizeof(host_client->name) - 1] = 0;
996 host_client->name[0] = STRING_COLOR_TAG;
997 host_client->name[1] = '0' + STRING_COLOR_DEFAULT;
1000 u8_COM_StringLengthNoColors(host_client->name, 0, &valid_colors);
1001 if(!valid_colors) // NOTE: this also proves the string is not empty, as "" is a valid colored string
1004 l = strlen(host_client->name);
1005 if(l < sizeof(host_client->name) - 1)
1007 // duplicate the color tag to escape it
1008 host_client->name[i] = STRING_COLOR_TAG;
1009 host_client->name[i+1] = 0;
1010 //Con_DPrintf("abuse detected, adding another trailing color tag\n");
1014 // remove the last character to fix the color code
1015 host_client->name[l-1] = 0;
1016 //Con_DPrintf("abuse detected, removing a trailing color tag\n");
1020 // find the last color tag offset and decide if we need to add a reset tag
1021 for (i = 0, j = -1;host_client->name[i];i++)
1023 if (host_client->name[i] == STRING_COLOR_TAG)
1025 if (host_client->name[i+1] >= '0' && host_client->name[i+1] <= '9')
1028 // if this happens to be a reset tag then we don't need one
1029 if (host_client->name[i+1] == '0' + STRING_COLOR_DEFAULT)
1034 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]))
1040 if (host_client->name[i+1] == STRING_COLOR_TAG)
1047 // does not end in the default color string, so add it
1048 if (j >= 0 && strlen(host_client->name) < sizeof(host_client->name) - 2)
1049 memcpy(host_client->name + strlen(host_client->name), STRING_COLOR_DEFAULT_STR, strlen(STRING_COLOR_DEFAULT_STR) + 1);
1051 SV_Name(host_client - svs.clients);
1054 static void SV_Rate_f(cmd_state_t *cmd)
1058 rate = atoi(Cmd_Argv(cmd, 1));
1060 if (cmd->source == src_command)
1063 host_client->rate = rate;
1066 static void SV_Rate_BurstSize_f(cmd_state_t *cmd)
1070 if (Cmd_Argc(cmd) != 2)
1073 rate_burstsize = atoi(Cmd_Argv(cmd, 1));
1075 host_client->rate_burstsize = rate_burstsize;
1078 static void SV_Color_f(cmd_state_t *cmd)
1080 prvm_prog_t *prog = SVVM_prog;
1082 int top, bottom, playercolor;
1084 top = atoi(Cmd_Argv(cmd, 1));
1085 bottom = atoi(Cmd_Argv(cmd, 2));
1090 playercolor = top*16 + bottom;
1092 if (host_client->edict && PRVM_serverfunction(SV_ChangeTeam))
1094 Con_DPrint("Calling SV_ChangeTeam\n");
1095 prog->globals.fp[OFS_PARM0] = playercolor;
1096 PRVM_serverglobalfloat(time) = sv.time;
1097 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict);
1098 prog->ExecuteProgram(prog, PRVM_serverfunction(SV_ChangeTeam), "QC function SV_ChangeTeam is missing");
1102 if (host_client->edict)
1104 PRVM_serveredictfloat(host_client->edict, clientcolors) = playercolor;
1105 PRVM_serveredictfloat(host_client->edict, team) = bottom + 1;
1107 host_client->colors = playercolor;
1108 if (host_client->old_colors != host_client->colors)
1110 host_client->old_colors = host_client->colors;
1111 // send notification to all clients
1112 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1113 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1114 MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1123 Kicks a user off of the server
1126 static void SV_Kick_f(cmd_state_t *cmd)
1129 const char *message = NULL;
1132 qboolean byNumber = false;
1139 if (Cmd_Argc(cmd) > 2 && strcmp(Cmd_Argv(cmd, 1), "#") == 0)
1141 i = (int)(atof(Cmd_Argv(cmd, 2)) - 1);
1142 if (i < 0 || i >= svs.maxclients || !(host_client = svs.clients + i)->active)
1148 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1150 if (!host_client->active)
1152 if (strcasecmp(host_client->name, Cmd_Argv(cmd, 1)) == 0)
1157 if (i < svs.maxclients)
1159 if (cmd->source == src_command)
1161 if (cls.state == ca_dedicated)
1164 who = cl_name.string;
1169 // can't kick yourself!
1170 if (host_client == save)
1173 if (Cmd_Argc(cmd) > 2)
1175 message = Cmd_Args(cmd);
1176 COM_ParseToken_Simple(&message, false, false, true);
1179 message++; // skip the #
1180 while (*message == ' ') // skip white space
1182 message += strlen(Cmd_Argv(cmd, 2)); // skip the number
1184 while (*message && *message == ' ')
1188 SV_ClientPrintf("Kicked by %s: %s\n", who, message);
1190 SV_ClientPrintf("Kicked by %s\n", who);
1191 SV_DropClient (false); // kicked
1197 static void SV_MaxPlayers_f(cmd_state_t *cmd)
1201 if (Cmd_Argc(cmd) != 2)
1203 Con_Printf("\"maxplayers\" is \"%u\"\n", svs.maxclients_next);
1209 Con_Print("maxplayers can not be changed while a server is running.\n");
1210 Con_Print("It will be changed on next server startup (\"map\" command).\n");
1213 n = atoi(Cmd_Argv(cmd, 1));
1214 n = bound(1, n, MAX_SCOREBOARD);
1215 Con_Printf("\"maxplayers\" set to \"%u\"\n", n);
1217 svs.maxclients_next = n;
1219 Cvar_Set (&cvars_all, "deathmatch", "0");
1221 Cvar_Set (&cvars_all, "deathmatch", "1");
1225 ======================
1227 ======================
1229 // the old playermodel in cl_main has been renamed to __cl_playermodel
1230 static void SV_Playermodel_f(cmd_state_t *cmd)
1232 prvm_prog_t *prog = SVVM_prog;
1234 char newPath[sizeof(host_client->playermodel)];
1236 if (Cmd_Argc (cmd) == 1)
1239 if (Cmd_Argc (cmd) == 2)
1240 strlcpy (newPath, Cmd_Argv(cmd, 1), sizeof (newPath));
1242 strlcpy (newPath, Cmd_Args(cmd), sizeof (newPath));
1244 for (i = 0, j = 0;newPath[i];i++)
1245 if (newPath[i] != '\r' && newPath[i] != '\n')
1246 newPath[j++] = newPath[i];
1250 if (host.realtime < host_client->nametime)
1252 SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
1256 host_client->nametime = host.realtime + 5;
1259 // point the string back at updateclient->name to keep it safe
1260 strlcpy (host_client->playermodel, newPath, sizeof (host_client->playermodel));
1261 PRVM_serveredictstring(host_client->edict, playermodel) = PRVM_SetEngineString(prog, host_client->playermodel);
1262 if (strcmp(host_client->old_model, host_client->playermodel))
1264 strlcpy(host_client->old_model, host_client->playermodel, sizeof(host_client->old_model));
1265 /*// send notification to all clients
1266 MSG_WriteByte (&sv.reliable_datagram, svc_updatepmodel);
1267 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1268 MSG_WriteString (&sv.reliable_datagram, host_client->playermodel);*/
1273 ======================
1275 ======================
1277 static void SV_Playerskin_f(cmd_state_t *cmd)
1279 prvm_prog_t *prog = SVVM_prog;
1281 char newPath[sizeof(host_client->playerskin)];
1283 if (Cmd_Argc (cmd) == 1)
1286 if (Cmd_Argc (cmd) == 2)
1287 strlcpy (newPath, Cmd_Argv(cmd, 1), sizeof (newPath));
1289 strlcpy (newPath, Cmd_Args(cmd), sizeof (newPath));
1291 for (i = 0, j = 0;newPath[i];i++)
1292 if (newPath[i] != '\r' && newPath[i] != '\n')
1293 newPath[j++] = newPath[i];
1297 if (host.realtime < host_client->nametime)
1299 SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
1303 host_client->nametime = host.realtime + 5;
1306 // point the string back at updateclient->name to keep it safe
1307 strlcpy (host_client->playerskin, newPath, sizeof (host_client->playerskin));
1308 PRVM_serveredictstring(host_client->edict, playerskin) = PRVM_SetEngineString(prog, host_client->playerskin);
1309 if (strcmp(host_client->old_skin, host_client->playerskin))
1311 //if (host_client->begun)
1312 // SV_BroadcastPrintf("%s changed skin to %s\n", host_client->name, host_client->playerskin);
1313 strlcpy(host_client->old_skin, host_client->playerskin, sizeof(host_client->old_skin));
1314 /*// send notification to all clients
1315 MSG_WriteByte (&sv.reliable_datagram, svc_updatepskin);
1316 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1317 MSG_WriteString (&sv.reliable_datagram, host_client->playerskin);*/
1322 ======================
1324 LadyHavoc: only supported for Nehahra, I personally think this is dumb, but Mindcrime won't listen.
1325 LadyHavoc: correction, Mindcrime will be removing pmodel in the future, but it's still stuck here for compatibility.
1326 ======================
1328 static void SV_PModel_f(cmd_state_t *cmd)
1330 prvm_prog_t *prog = SVVM_prog;
1332 if (Cmd_Argc (cmd) == 1)
1335 PRVM_serveredictfloat(host_client->edict, pmodel) = atoi(Cmd_Argv(cmd, 1));
1339 ===============================================================================
1343 ===============================================================================
1346 static prvm_edict_t *FindViewthing(prvm_prog_t *prog)
1351 for (i=0 ; i<prog->num_edicts ; i++)
1353 e = PRVM_EDICT_NUM(i);
1354 if (!strcmp (PRVM_GetString(prog, PRVM_serveredictstring(e, classname)), "viewthing"))
1357 Con_Print("No viewthing on map\n");
1366 static void SV_Viewmodel_f(cmd_state_t *cmd)
1368 prvm_prog_t *prog = SVVM_prog;
1375 e = FindViewthing(prog);
1378 m = Mod_ForName (Cmd_Argv(cmd, 1), false, true, NULL);
1379 if (m && m->loaded && m->Draw)
1381 PRVM_serveredictfloat(e, frame) = 0;
1382 cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)] = m;
1385 Con_Printf("viewmodel: can't load %s\n", Cmd_Argv(cmd, 1));
1394 static void SV_Viewframe_f(cmd_state_t *cmd)
1396 prvm_prog_t *prog = SVVM_prog;
1404 e = FindViewthing(prog);
1407 m = cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)];
1409 f = atoi(Cmd_Argv(cmd, 1));
1410 if (f >= m->numframes)
1413 PRVM_serveredictfloat(e, frame) = f;
1417 static void PrintFrameName (dp_model_t *m, int frame)
1420 Con_Printf("frame %i: %s\n", frame, m->animscenes[frame].name);
1422 Con_Printf("frame %i\n", frame);
1430 static void SV_Viewnext_f(cmd_state_t *cmd)
1432 prvm_prog_t *prog = SVVM_prog;
1439 e = FindViewthing(prog);
1442 m = cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)];
1444 PRVM_serveredictfloat(e, frame) = PRVM_serveredictfloat(e, frame) + 1;
1445 if (PRVM_serveredictfloat(e, frame) >= m->numframes)
1446 PRVM_serveredictfloat(e, frame) = m->numframes - 1;
1448 PrintFrameName (m, (int)PRVM_serveredictfloat(e, frame));
1457 static void SV_Viewprev_f(cmd_state_t *cmd)
1459 prvm_prog_t *prog = SVVM_prog;
1466 e = FindViewthing(prog);
1469 m = cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)];
1471 PRVM_serveredictfloat(e, frame) = PRVM_serveredictfloat(e, frame) - 1;
1472 if (PRVM_serveredictfloat(e, frame) < 0)
1473 PRVM_serveredictfloat(e, frame) = 0;
1475 PrintFrameName (m, (int)PRVM_serveredictfloat(e, frame));
1479 static void SV_SendCvar_f(cmd_state_t *cmd)
1482 const char *cvarname;
1485 if(Cmd_Argc(cmd) != 2)
1488 if(!sv.active)// || !PRVM_serverfunction(SV_ParseClientCommand))
1491 cvarname = Cmd_Argv(cmd, 1);
1494 if (cls.state != ca_dedicated)
1498 for(;i<svs.maxclients;i++)
1499 if(svs.clients[i].active && svs.clients[i].netconnection)
1501 host_client = &svs.clients[i];
1502 SV_ClientCommands("sendcvar %s\n", cvarname);
1507 static void SV_Ent_Create_f(cmd_state_t *cmd)
1509 prvm_prog_t *prog = SVVM_prog;
1513 qboolean haveorigin;
1515 qboolean expectval = false;
1516 void (*print)(const char *, ...) = (cmd->source == src_client ? SV_ClientPrintf : Con_Printf);
1521 ed = PRVM_ED_Alloc(SVVM_prog);
1523 PRVM_ED_ParseEpair(prog, ed, PRVM_ED_FindField(prog, "classname"), Cmd_Argv(cmd, 1), false);
1525 // Spawn where the player is aiming. We need a view matrix first.
1526 if(cmd->source == src_client)
1528 vec3_t org, temp, dest;
1533 SV_GetEntityMatrix(prog, host_client->edict, &view, true);
1535 Matrix4x4_OriginFromMatrix(&view, org);
1536 VectorSet(temp, 65536, 0, 0);
1537 Matrix4x4_Transform(&view, temp, dest);
1539 trace = SV_TraceLine(org, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, 0, 0, collision_extendmovelength.value);
1541 dpsnprintf(buf, sizeof(buf), "%g %g %g", trace.endpos[0], trace.endpos[1], trace.endpos[2]);
1542 PRVM_ED_ParseEpair(prog, ed, PRVM_ED_FindField(prog, "origin"), buf, false);
1546 // Or spawn at a specified origin.
1553 // Allow more than one key/value pair by cycling between expecting either one.
1554 for(i = 2; i < Cmd_Argc(cmd); i++)
1558 if(!(key = PRVM_ED_FindField(prog, Cmd_Argv(cmd, i))))
1560 print("Key %s not found!\n", Cmd_Argv(cmd, i));
1561 PRVM_ED_Free(prog, ed);
1566 * This is mostly for dedicated server console, but if the
1567 * player gave a custom origin, we can ignore the traceline.
1569 if(!strcmp(Cmd_Argv(cmd, i), "origin"))
1576 PRVM_ED_ParseEpair(prog, ed, key, Cmd_Argv(cmd, i), false);
1583 print("Missing origin\n");
1584 PRVM_ED_Free(prog, ed);
1589 PRVM_ED_CallPrespawnFunction(prog, ed);
1591 if(!PRVM_ED_CallSpawnFunction(prog, ed, NULL, NULL))
1593 print("Could not spawn a \"%s\". No such entity or it has no spawn function\n", Cmd_Argv(cmd, 1));
1594 if(cmd->source == src_client)
1595 Con_Printf("%s tried to spawn a \"%s\"\n", host_client->name, Cmd_Argv(cmd, 1));
1596 // CallSpawnFunction already freed the edict for us.
1600 PRVM_ED_CallPostspawnFunction(prog, ed);
1602 // Make it appear in the world
1605 if(cmd->source == src_client)
1606 Con_Printf("%s spawned a \"%s\"\n", host_client->name, Cmd_Argv(cmd, 1));
1609 static void SV_Ent_Remove_f(cmd_state_t *cmd)
1611 prvm_prog_t *prog = SVVM_prog;
1614 void (*print)(const char *, ...) = (cmd->source == src_client ? SV_ClientPrintf : Con_Printf);
1619 // Allow specifying edict by number
1620 if(Cmd_Argc(cmd) > 1 && Cmd_Argv(cmd, 1))
1622 ednum = atoi(Cmd_Argv(cmd, 1));
1625 print("Cannot remove the world\n");
1629 // Or trace a line if it's a client who didn't specify one.
1630 else if(cmd->source == src_client)
1632 vec3_t org, temp, dest;
1636 SV_GetEntityMatrix(prog, host_client->edict, &view, true);
1638 Matrix4x4_OriginFromMatrix(&view, org);
1639 VectorSet(temp, 65536, 0, 0);
1640 Matrix4x4_Transform(&view, temp, dest);
1642 trace = SV_TraceLine(org, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY, 0, 0, collision_extendmovelength.value);
1645 ednum = (int)PRVM_EDICT_TO_PROG(trace.ent);
1646 if(!trace.ent || !ednum)
1647 // Don't remove the world, but don't annoy players with a print if they miss
1652 // Only a dedicated server console should be able to reach this.
1653 print("No edict given\n");
1657 ed = PRVM_EDICT_NUM(ednum);
1662 for (i = 0; i < svs.maxclients; i++)
1664 if(ed == svs.clients[i].edict)
1668 if(!ed->priv.required->free)
1670 print("Removed a \"%s\"\n", PRVM_GetString(prog, PRVM_serveredictstring(ed, classname)));
1671 PRVM_ED_ClearEdict(prog, ed);
1672 PRVM_ED_Free(prog, ed);
1677 // This should only be reachable if an invalid edict number was given
1678 print("No such entity\n");
1683 static void SV_Ent_Remove_All_f(cmd_state_t *cmd)
1685 prvm_prog_t *prog = SVVM_prog;
1688 void (*print)(const char *, ...) = (cmd->source == src_client ? SV_ClientPrintf : Con_Printf);
1690 for (i = 0, rmcount = 0, ed = PRVM_EDICT_NUM(i); i < prog->num_edicts; i++, ed = PRVM_NEXT_EDICT(ed))
1692 if(!ed->priv.required->free && !strcmp(PRVM_GetString(prog, PRVM_serveredictstring(ed, classname)), Cmd_Argv(cmd, 1)))
1696 print("Cannot remove the world\n");
1699 PRVM_ED_ClearEdict(prog, ed);
1700 PRVM_ED_Free(prog, ed);
1706 print("No \"%s\" found\n", Cmd_Argv(cmd, 1));
1708 print("Removed %i of \"%s\"\n", rmcount, Cmd_Argv(cmd, 1));
1711 void SV_InitOperatorCommands(void)
1713 Cvar_RegisterVariable(&sv_cheats);
1714 Cvar_RegisterCallback(&sv_cheats, SV_DisableCheats_c);
1715 Cvar_RegisterVariable(&sv_adminnick);
1716 Cvar_RegisterVariable(&sv_status_privacy);
1717 Cvar_RegisterVariable(&sv_status_show_qcstatus);
1718 Cvar_RegisterVariable(&sv_namechangetimer);
1720 Cmd_AddCommand(CMD_SERVER | CMD_SERVER_FROM_CLIENT, "status", SV_Status_f, "print server status information");
1721 Cmd_AddCommand(CMD_SHARED, "map", SV_Map_f, "kick everyone off the server and start a new level");
1722 Cmd_AddCommand(CMD_SHARED, "restart", SV_Restart_f, "restart current level");
1723 Cmd_AddCommand(CMD_SHARED, "changelevel", SV_Changelevel_f, "change to another level, bringing along all connected clients");
1724 Cmd_AddCommand(CMD_SHARED | CMD_SERVER_FROM_CLIENT, "say", SV_Say_f, "send a chat message to everyone on the server");
1725 Cmd_AddCommand(CMD_SERVER_FROM_CLIENT, "say_team", SV_Say_Team_f, "send a chat message to your team on the server");
1726 Cmd_AddCommand(CMD_SHARED | CMD_SERVER_FROM_CLIENT, "tell", SV_Tell_f, "send a chat message to only one person on the server");
1727 Cmd_AddCommand(CMD_SERVER | CMD_SERVER_FROM_CLIENT, "pause", SV_Pause_f, "pause the game (if the server allows pausing)");
1728 Cmd_AddCommand(CMD_SHARED, "kick", SV_Kick_f, "kick a player off the server by number or name");
1729 Cmd_AddCommand(CMD_SHARED | CMD_SERVER_FROM_CLIENT, "ping", SV_Ping_f, "print ping times of all players on the server");
1730 Cmd_AddCommand(CMD_SHARED, "load", SV_Loadgame_f, "load a saved game file");
1731 Cmd_AddCommand(CMD_SHARED, "save", SV_Savegame_f, "save the game to a file");
1732 Cmd_AddCommand(CMD_SHARED, "viewmodel", SV_Viewmodel_f, "change model of viewthing entity in current level");
1733 Cmd_AddCommand(CMD_SHARED, "viewframe", SV_Viewframe_f, "change animation frame of viewthing entity in current level");
1734 Cmd_AddCommand(CMD_SHARED, "viewnext", SV_Viewnext_f, "change to next animation frame of viewthing entity in current level");
1735 Cmd_AddCommand(CMD_SHARED, "viewprev", SV_Viewprev_f, "change to previous animation frame of viewthing entity in current level");
1736 Cmd_AddCommand(CMD_SHARED, "maxplayers", SV_MaxPlayers_f, "sets limit on how many players (or bots) may be connected to the server at once");
1737 Cmd_AddCommand(CMD_SHARED, "user", SV_User_f, "prints additional information about a player number or name on the scoreboard");
1738 Cmd_AddCommand(CMD_SHARED, "users", SV_Users_f, "prints additional information about all players on the scoreboard");
1739 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");
1741 // 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)
1742 Cmd_AddCommand(CMD_SERVER_FROM_CLIENT, "prespawn", SV_PreSpawn_f, "internal use - signon 1 (client acknowledges that server information has been received)");
1743 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)");
1744 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)");
1745 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)");
1747 Cmd_AddCommand(CMD_CHEAT | CMD_SERVER_FROM_CLIENT, "god", SV_God_f, "god mode (invulnerability)");
1748 Cmd_AddCommand(CMD_CHEAT | CMD_SERVER_FROM_CLIENT, "notarget", SV_Notarget_f, "notarget mode (monsters do not see you)");
1749 Cmd_AddCommand(CMD_CHEAT | CMD_SERVER_FROM_CLIENT, "fly", SV_Fly_f, "fly mode (flight)");
1750 Cmd_AddCommand(CMD_CHEAT | CMD_SERVER_FROM_CLIENT, "noclip", SV_Noclip_f, "noclip mode (flight without collisions, move through walls)");
1751 Cmd_AddCommand(CMD_CHEAT | CMD_SERVER_FROM_CLIENT, "give", SV_Give_f, "alter inventory");
1752 Cmd_AddCommand(CMD_SERVER_FROM_CLIENT, "kill", SV_Kill_f, "die instantly");
1754 Cmd_AddCommand(CMD_USERINFO, "color", SV_Color_f, "change your player shirt and pants colors");
1755 Cmd_AddCommand(CMD_USERINFO, "name", SV_Name_f, "change your player name");
1756 Cmd_AddCommand(CMD_USERINFO, "rate", SV_Rate_f, "change your network connection speed");
1757 Cmd_AddCommand(CMD_USERINFO, "rate_burstsize", SV_Rate_BurstSize_f, "change your network connection speed");
1758 Cmd_AddCommand(CMD_USERINFO, "pmodel", SV_PModel_f, "(Nehahra-only) change your player model choice");
1759 Cmd_AddCommand(CMD_USERINFO, "playermodel", SV_Playermodel_f, "change your player model");
1760 Cmd_AddCommand(CMD_USERINFO, "playerskin", SV_Playerskin_f, "change your player skin number");
1762 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.");
1763 Cmd_AddCommand(CMD_CHEAT | CMD_SERVER_FROM_CLIENT, "ent_remove_all", SV_Ent_Remove_All_f, "Removes all entities of the specified classname");
1764 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");