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);
942 ======================
944 ======================
946 static void SV_Name_f(cmd_state_t *cmd)
948 prvm_prog_t *prog = SVVM_prog;
950 qboolean valid_colors;
951 const char *newNameSource;
952 char newName[sizeof(host_client->name)];
954 if (Cmd_Argc (cmd) == 1)
957 if (Cmd_Argc (cmd) == 2)
958 newNameSource = Cmd_Argv(cmd, 1);
960 newNameSource = Cmd_Args(cmd);
962 strlcpy(newName, newNameSource, sizeof(newName));
964 if (cmd->source == src_command)
967 if (host.realtime < host_client->nametime && strcmp(newName, host_client->name))
969 SV_ClientPrintf("You can't change name more than once every %.1f seconds!\n", max(0.0f, sv_namechangetimer.value));
973 host_client->nametime = host.realtime + max(0.0f, sv_namechangetimer.value);
975 // point the string back at updateclient->name to keep it safe
976 strlcpy (host_client->name, newName, sizeof (host_client->name));
978 for (i = 0, j = 0;host_client->name[i];i++)
979 if (host_client->name[i] != '\r' && host_client->name[i] != '\n')
980 host_client->name[j++] = host_client->name[i];
981 host_client->name[j] = 0;
983 if(host_client->name[0] == 1 || host_client->name[0] == 2)
984 // may interfere with chat area, and will needlessly beep; so let's add a ^7
986 memmove(host_client->name + 2, host_client->name, sizeof(host_client->name) - 2);
987 host_client->name[sizeof(host_client->name) - 1] = 0;
988 host_client->name[0] = STRING_COLOR_TAG;
989 host_client->name[1] = '0' + STRING_COLOR_DEFAULT;
992 u8_COM_StringLengthNoColors(host_client->name, 0, &valid_colors);
993 if(!valid_colors) // NOTE: this also proves the string is not empty, as "" is a valid colored string
996 l = strlen(host_client->name);
997 if(l < sizeof(host_client->name) - 1)
999 // duplicate the color tag to escape it
1000 host_client->name[i] = STRING_COLOR_TAG;
1001 host_client->name[i+1] = 0;
1002 //Con_DPrintf("abuse detected, adding another trailing color tag\n");
1006 // remove the last character to fix the color code
1007 host_client->name[l-1] = 0;
1008 //Con_DPrintf("abuse detected, removing a trailing color tag\n");
1012 // find the last color tag offset and decide if we need to add a reset tag
1013 for (i = 0, j = -1;host_client->name[i];i++)
1015 if (host_client->name[i] == STRING_COLOR_TAG)
1017 if (host_client->name[i+1] >= '0' && host_client->name[i+1] <= '9')
1020 // if this happens to be a reset tag then we don't need one
1021 if (host_client->name[i+1] == '0' + STRING_COLOR_DEFAULT)
1026 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]))
1032 if (host_client->name[i+1] == STRING_COLOR_TAG)
1039 // does not end in the default color string, so add it
1040 if (j >= 0 && strlen(host_client->name) < sizeof(host_client->name) - 2)
1041 memcpy(host_client->name + strlen(host_client->name), STRING_COLOR_DEFAULT_STR, strlen(STRING_COLOR_DEFAULT_STR) + 1);
1043 PRVM_serveredictstring(host_client->edict, netname) = PRVM_SetEngineString(prog, host_client->name);
1044 if (strcmp(host_client->old_name, host_client->name))
1046 if (host_client->begun)
1047 SV_BroadcastPrintf("%s ^7changed name to %s\n", host_client->old_name, host_client->name);
1048 strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
1049 // send notification to all clients
1050 MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
1051 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1052 MSG_WriteString (&sv.reliable_datagram, host_client->name);
1053 SV_WriteNetnameIntoDemo(host_client);
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));
1611 //static void SV_Ent_Remove()
1613 static void SV_Ent_Remove_All_f(cmd_state_t *cmd)
1615 prvm_prog_t *prog = SVVM_prog;
1618 void (*print)(const char *, ...) = (cmd->source == src_client ? SV_ClientPrintf : Con_Printf);
1620 for (i = 0, rmcount = 0, ed = PRVM_EDICT_NUM(i); i < prog->num_edicts; i++, ed = PRVM_NEXT_EDICT(ed))
1622 if(!ed->priv.required->free && !strcmp(PRVM_GetString(prog, PRVM_serveredictstring(ed, classname)), Cmd_Argv(cmd, 1)))
1626 print("Cannot remove the world\n");
1629 PRVM_ED_ClearEdict(prog, ed);
1630 PRVM_ED_Free(prog, ed);
1636 print("No \"%s\" found\n", Cmd_Argv(cmd, 1));
1638 print("Removed %i of \"%s\"\n", rmcount, Cmd_Argv(cmd, 1));
1641 void SV_InitOperatorCommands(void)
1643 Cvar_RegisterVariable(&sv_cheats);
1644 Cvar_RegisterCallback(&sv_cheats, SV_DisableCheats_c);
1645 Cvar_RegisterVariable(&sv_adminnick);
1646 Cvar_RegisterVariable(&sv_status_privacy);
1647 Cvar_RegisterVariable(&sv_status_show_qcstatus);
1648 Cvar_RegisterVariable(&sv_namechangetimer);
1650 Cmd_AddCommand(CMD_SERVER | CMD_SERVER_FROM_CLIENT, "status", SV_Status_f, "print server status information");
1651 Cmd_AddCommand(CMD_SHARED, "map", SV_Map_f, "kick everyone off the server and start a new level");
1652 Cmd_AddCommand(CMD_SHARED, "restart", SV_Restart_f, "restart current level");
1653 Cmd_AddCommand(CMD_SHARED, "changelevel", SV_Changelevel_f, "change to another level, bringing along all connected clients");
1654 Cmd_AddCommand(CMD_SHARED | CMD_SERVER_FROM_CLIENT, "say", SV_Say_f, "send a chat message to everyone on the server");
1655 Cmd_AddCommand(CMD_SERVER_FROM_CLIENT, "say_team", SV_Say_Team_f, "send a chat message to your team on the server");
1656 Cmd_AddCommand(CMD_SHARED | CMD_SERVER_FROM_CLIENT, "tell", SV_Tell_f, "send a chat message to only one person on the server");
1657 Cmd_AddCommand(CMD_SERVER | CMD_SERVER_FROM_CLIENT, "pause", SV_Pause_f, "pause the game (if the server allows pausing)");
1658 Cmd_AddCommand(CMD_SHARED, "kick", SV_Kick_f, "kick a player off the server by number or name");
1659 Cmd_AddCommand(CMD_SHARED | CMD_SERVER_FROM_CLIENT, "ping", SV_Ping_f, "print ping times of all players on the server");
1660 Cmd_AddCommand(CMD_SHARED, "load", SV_Loadgame_f, "load a saved game file");
1661 Cmd_AddCommand(CMD_SHARED, "save", SV_Savegame_f, "save the game to a file");
1662 Cmd_AddCommand(CMD_SHARED, "viewmodel", SV_Viewmodel_f, "change model of viewthing entity in current level");
1663 Cmd_AddCommand(CMD_SHARED, "viewframe", SV_Viewframe_f, "change animation frame of viewthing entity in current level");
1664 Cmd_AddCommand(CMD_SHARED, "viewnext", SV_Viewnext_f, "change to next animation frame of viewthing entity in current level");
1665 Cmd_AddCommand(CMD_SHARED, "viewprev", SV_Viewprev_f, "change to previous animation frame of viewthing entity in current level");
1666 Cmd_AddCommand(CMD_SHARED, "maxplayers", SV_MaxPlayers_f, "sets limit on how many players (or bots) may be connected to the server at once");
1667 Cmd_AddCommand(CMD_SHARED, "user", SV_User_f, "prints additional information about a player number or name on the scoreboard");
1668 Cmd_AddCommand(CMD_SHARED, "users", SV_Users_f, "prints additional information about all players on the scoreboard");
1669 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");
1671 // 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)
1672 Cmd_AddCommand(CMD_SERVER_FROM_CLIENT, "prespawn", SV_PreSpawn_f, "internal use - signon 1 (client acknowledges that server information has been received)");
1673 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)");
1674 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)");
1675 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)");
1677 Cmd_AddCommand(CMD_CHEAT | CMD_SERVER_FROM_CLIENT, "god", SV_God_f, "god mode (invulnerability)");
1678 Cmd_AddCommand(CMD_CHEAT | CMD_SERVER_FROM_CLIENT, "notarget", SV_Notarget_f, "notarget mode (monsters do not see you)");
1679 Cmd_AddCommand(CMD_CHEAT | CMD_SERVER_FROM_CLIENT, "fly", SV_Fly_f, "fly mode (flight)");
1680 Cmd_AddCommand(CMD_CHEAT | CMD_SERVER_FROM_CLIENT, "noclip", SV_Noclip_f, "noclip mode (flight without collisions, move through walls)");
1681 Cmd_AddCommand(CMD_CHEAT | CMD_SERVER_FROM_CLIENT, "give", SV_Give_f, "alter inventory");
1682 Cmd_AddCommand(CMD_SERVER_FROM_CLIENT, "kill", SV_Kill_f, "die instantly");
1684 Cmd_AddCommand(CMD_USERINFO, "color", SV_Color_f, "change your player shirt and pants colors");
1685 Cmd_AddCommand(CMD_USERINFO, "name", SV_Name_f, "change your player name");
1686 Cmd_AddCommand(CMD_USERINFO, "rate", SV_Rate_f, "change your network connection speed");
1687 Cmd_AddCommand(CMD_USERINFO, "rate_burstsize", SV_Rate_BurstSize_f, "change your network connection speed");
1688 Cmd_AddCommand(CMD_USERINFO, "pmodel", SV_PModel_f, "(Nehahra-only) change your player model choice");
1689 Cmd_AddCommand(CMD_USERINFO, "playermodel", SV_Playermodel_f, "change your player model");
1690 Cmd_AddCommand(CMD_USERINFO, "playerskin", SV_Playerskin_f, "change your player skin number");
1692 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.");
1693 Cmd_AddCommand(CMD_CHEAT | CMD_SERVER_FROM_CLIENT, "ent_remove_all", SV_Ent_Remove_All_f, "Removes all entities of the specified classname");