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 = {CF_SERVER | CF_NOTIFY, "sv_cheats", "0", "enables cheat commands in any game, and cheat impulses in dpmod"};
28 cvar_t sv_adminnick = {CF_SERVER | CF_ARCHIVE, "sv_adminnick", "", "nick name to use for admin messages instead of host name"};
29 cvar_t sv_status_privacy = {CF_SERVER | CF_ARCHIVE, "sv_status_privacy", "0", "do not show IP addresses in 'status' replies to clients"};
30 cvar_t sv_status_show_qcstatus = {CF_SERVER | CF_ARCHIVE, "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 = {CF_SERVER | CF_ARCHIVE, "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 if(host.hook.Disconnect)
65 host.hook.Disconnect(false, NULL);
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);
77 if(host.hook.ToggleMenu)
78 host.hook.ToggleMenu();
80 svs.serverflags = 0; // haven't completed an episode yet
81 dp_strlcpy(level, Cmd_Argv(cmd, 1), sizeof(level));
82 SV_SpawnServer(level);
84 if(sv.active && host.hook.ConnectLocal != NULL)
85 host.hook.ConnectLocal();
92 Goes to a new map, taking all clients along
95 static void SV_Changelevel_f(cmd_state_t *cmd)
97 char level[MAX_QPATH];
99 if (Cmd_Argc(cmd) != 2)
101 Con_Print("changelevel <levelname> : continue game on a new level\n");
107 Con_Printf("You must be running a server to changelevel. Use 'map %s' instead\n", Cmd_Argv(cmd, 1));
111 if(host.hook.ToggleMenu)
112 host.hook.ToggleMenu();
114 SV_SaveSpawnparms ();
115 dp_strlcpy(level, Cmd_Argv(cmd, 1), sizeof(level));
116 SV_SpawnServer(level);
118 if(sv.active && host.hook.ConnectLocal != NULL)
119 host.hook.ConnectLocal();
126 Restarts the current server for a dead player
129 static void SV_Restart_f(cmd_state_t *cmd)
131 char mapname[MAX_QPATH];
133 if (Cmd_Argc(cmd) != 1)
135 Con_Print("restart : restart current level\n");
140 Con_Print("Only the server may restart\n");
144 if(host.hook.ToggleMenu)
145 host.hook.ToggleMenu();
147 dp_strlcpy(mapname, sv.worldbasename, sizeof(mapname));
148 SV_SpawnServer(mapname);
150 if(sv.active && host.hook.ConnectLocal != NULL)
151 host.hook.ConnectLocal();
154 //===========================================================================
156 // Disable cheats if sv_cheats is turned off
157 static void SV_DisableCheats_c(cvar_t *var)
159 prvm_prog_t *prog = SVVM_prog;
162 if (prog->loaded && var->value == 0)
164 for (i = 0; i < svs.maxclients; ++i)
166 if (((int)PRVM_serveredictfloat(svs.clients[i].edict, flags) & FL_GODMODE))
167 PRVM_serveredictfloat(svs.clients[i].edict, flags) = (int)PRVM_serveredictfloat(svs.clients[i].edict, flags) ^ FL_GODMODE;
168 if (((int)PRVM_serveredictfloat(svs.clients[i].edict, flags) & FL_NOTARGET))
169 PRVM_serveredictfloat(svs.clients[i].edict, flags) = (int)PRVM_serveredictfloat(svs.clients[i].edict, flags) ^ FL_NOTARGET;
170 if (PRVM_serveredictfloat(svs.clients[i].edict, movetype) == MOVETYPE_NOCLIP ||
171 PRVM_serveredictfloat(svs.clients[i].edict, movetype) == MOVETYPE_FLY)
173 noclip_anglehack = false;
174 PRVM_serveredictfloat(svs.clients[i].edict, movetype) = MOVETYPE_WALK;
184 Sets client to godmode
187 static void SV_God_f(cmd_state_t *cmd)
189 prvm_prog_t *prog = SVVM_prog;
191 PRVM_serveredictfloat(host_client->edict, flags) = (int)PRVM_serveredictfloat(host_client->edict, flags) ^ FL_GODMODE;
192 if (!((int)PRVM_serveredictfloat(host_client->edict, flags) & FL_GODMODE) )
193 SV_ClientPrint("godmode OFF\n");
195 SV_ClientPrint("godmode ON\n");
198 qbool noclip_anglehack;
200 static void SV_Noclip_f(cmd_state_t *cmd)
202 prvm_prog_t *prog = SVVM_prog;
204 if (PRVM_serveredictfloat(host_client->edict, movetype) != MOVETYPE_NOCLIP)
206 noclip_anglehack = true;
207 PRVM_serveredictfloat(host_client->edict, movetype) = MOVETYPE_NOCLIP;
208 SV_ClientPrint("noclip ON\n");
212 noclip_anglehack = false;
213 PRVM_serveredictfloat(host_client->edict, movetype) = MOVETYPE_WALK;
214 SV_ClientPrint("noclip OFF\n");
223 static void SV_Give_f(cmd_state_t *cmd)
225 prvm_prog_t *prog = SVVM_prog;
229 t = Cmd_Argv(cmd, 1);
230 v = atoi (Cmd_Argv(cmd, 2));
244 // MED 01/04/97 added hipnotic give stuff
245 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_QUOTH)
250 PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | HIT_PROXIMITY_GUN;
252 PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | IT_GRENADE_LAUNCHER;
254 else if (t[0] == '9')
255 PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | HIT_LASER_CANNON;
256 else if (t[0] == '0')
257 PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | HIT_MJOLNIR;
258 else if (t[0] >= '2')
259 PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | (IT_SHOTGUN << (t[0] - '2'));
264 PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | (IT_SHOTGUN << (t[0] - '2'));
269 if (gamemode == GAME_ROGUE)
270 PRVM_serveredictfloat(host_client->edict, ammo_shells1) = v;
272 PRVM_serveredictfloat(host_client->edict, ammo_shells) = v;
275 if (gamemode == GAME_ROGUE)
277 PRVM_serveredictfloat(host_client->edict, ammo_nails1) = v;
278 if (PRVM_serveredictfloat(host_client->edict, weapon) <= IT_LIGHTNING)
279 PRVM_serveredictfloat(host_client->edict, ammo_nails) = v;
283 PRVM_serveredictfloat(host_client->edict, ammo_nails) = v;
287 if (gamemode == GAME_ROGUE)
289 PRVM_serveredictfloat(host_client->edict, ammo_lava_nails) = v;
290 if (PRVM_serveredictfloat(host_client->edict, weapon) > IT_LIGHTNING)
291 PRVM_serveredictfloat(host_client->edict, ammo_nails) = v;
295 if (gamemode == GAME_ROGUE)
297 PRVM_serveredictfloat(host_client->edict, ammo_rockets1) = v;
298 if (PRVM_serveredictfloat(host_client->edict, weapon) <= IT_LIGHTNING)
299 PRVM_serveredictfloat(host_client->edict, ammo_rockets) = v;
303 PRVM_serveredictfloat(host_client->edict, ammo_rockets) = v;
307 if (gamemode == GAME_ROGUE)
309 PRVM_serveredictfloat(host_client->edict, ammo_multi_rockets) = v;
310 if (PRVM_serveredictfloat(host_client->edict, weapon) > IT_LIGHTNING)
311 PRVM_serveredictfloat(host_client->edict, ammo_rockets) = v;
315 PRVM_serveredictfloat(host_client->edict, health) = v;
318 if (gamemode == GAME_ROGUE)
320 PRVM_serveredictfloat(host_client->edict, ammo_cells1) = v;
321 if (PRVM_serveredictfloat(host_client->edict, weapon) <= IT_LIGHTNING)
322 PRVM_serveredictfloat(host_client->edict, ammo_cells) = v;
326 PRVM_serveredictfloat(host_client->edict, ammo_cells) = v;
330 if (gamemode == GAME_ROGUE)
332 PRVM_serveredictfloat(host_client->edict, ammo_plasma) = v;
333 if (PRVM_serveredictfloat(host_client->edict, weapon) > IT_LIGHTNING)
334 PRVM_serveredictfloat(host_client->edict, ammo_cells) = v;
344 Sets client to flymode
347 static void SV_Fly_f(cmd_state_t *cmd)
349 prvm_prog_t *prog = SVVM_prog;
351 if (PRVM_serveredictfloat(host_client->edict, movetype) != MOVETYPE_FLY)
353 PRVM_serveredictfloat(host_client->edict, movetype) = MOVETYPE_FLY;
354 SV_ClientPrint("flymode ON\n");
358 PRVM_serveredictfloat(host_client->edict, movetype) = MOVETYPE_WALK;
359 SV_ClientPrint("flymode OFF\n");
363 static void SV_Notarget_f(cmd_state_t *cmd)
365 prvm_prog_t *prog = SVVM_prog;
367 PRVM_serveredictfloat(host_client->edict, flags) = (int)PRVM_serveredictfloat(host_client->edict, flags) ^ FL_NOTARGET;
368 if (!((int)PRVM_serveredictfloat(host_client->edict, flags) & FL_NOTARGET) )
369 SV_ClientPrint("notarget OFF\n");
371 SV_ClientPrint("notarget ON\n");
379 static void SV_Kill_f(cmd_state_t *cmd)
381 prvm_prog_t *prog = SVVM_prog;
382 if (PRVM_serveredictfloat(host_client->edict, health) <= 0)
384 SV_ClientPrint("Can't suicide -- already dead!\n");
388 PRVM_serverglobalfloat(time) = sv.time;
389 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict);
390 prog->ExecuteProgram(prog, PRVM_serverfunction(ClientKill), "QC function ClientKill is missing");
398 static void SV_Pause_f(cmd_state_t *cmd)
400 void (*print) (const char *fmt, ...);
401 if (cmd->source == src_local)
404 print = SV_ClientPrintf;
406 if (!pausable.integer && cmd->source == src_client && LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) != LHNETADDRESSTYPE_LOOP)
408 print("Pause not allowed.\n");
413 if (cmd->source != src_local)
414 SV_BroadcastPrintf("%s %spaused the game\n", host_client->name, sv.paused ? "" : "un");
415 else if(*(sv_adminnick.string))
416 SV_BroadcastPrintf("%s %spaused the game\n", sv_adminnick.string, sv.paused ? "" : "un");
418 SV_BroadcastPrintf("%s %spaused the game\n", hostname.string, sv.paused ? "" : "un");
419 // send notification to all clients
420 MSG_WriteByte(&sv.reliable_datagram, svc_setpause);
421 MSG_WriteByte(&sv.reliable_datagram, sv.paused);
424 static void SV_Say(cmd_state_t *cmd, qbool teamonly)
426 prvm_prog_t *prog = SVVM_prog;
431 // LadyHavoc: long say messages
433 qbool fromServer = false;
435 if (cmd->source == src_local)
441 if (Cmd_Argc (cmd) < 2)
444 if (!teamplay.integer)
454 // note this uses the chat prefix \001
455 if (!fromServer && !teamonly)
456 dpsnprintf (text, sizeof(text), "\001%s: %s", host_client->name, p1);
457 else if (!fromServer && teamonly)
458 dpsnprintf (text, sizeof(text), "\001(%s): %s", host_client->name, p1);
459 else if(*(sv_adminnick.string))
460 dpsnprintf (text, sizeof(text), "\001<%s> %s", sv_adminnick.string, p1);
462 dpsnprintf (text, sizeof(text), "\001<%s> %s", hostname.string, p1);
463 p2 = text + strlen(text);
464 while ((const char *)p2 > (const char *)text && (p2[-1] == '\r' || p2[-1] == '\n' || (p2[-1] == '\"' && quoted)))
466 if (p2[-1] == '\"' && quoted)
471 dp_strlcat(text, "\n", sizeof(text));
473 // note: save is not a valid edict if fromServer is true
475 for (j = 0, host_client = svs.clients;j < svs.maxclients;j++, host_client++)
476 if (host_client->active && (!teamonly || PRVM_serveredictfloat(host_client->edict, team) == PRVM_serveredictfloat(save->edict, team)))
477 SV_ClientPrint(text);
480 if(!host_isclient.integer)
484 static void SV_Say_f(cmd_state_t *cmd)
489 static void SV_Say_Team_f(cmd_state_t *cmd)
494 static void SV_Tell_f(cmd_state_t *cmd)
496 const char *playername_start = NULL;
497 size_t playername_length = 0;
498 int playernumber = 0;
502 char text[MAX_INPUTLINE]; // LadyHavoc: FIXME: temporary buffer overflow fix (was 64)
503 qbool fromServer = false;
505 if (cmd->source == src_local)
508 if (Cmd_Argc (cmd) < 2)
511 // note this uses the chat prefix \001
513 dpsnprintf (text, sizeof(text), "\001%s tells you: ", host_client->name);
514 else if(*(sv_adminnick.string))
515 dpsnprintf (text, sizeof(text), "\001<%s tells you> ", sv_adminnick.string);
517 dpsnprintf (text, sizeof(text), "\001<%s tells you> ", hostname.string);
520 p2 = p1 + strlen(p1);
521 // remove the target name
522 while (p1 < p2 && *p1 == ' ')
527 while (p1 < p2 && *p1 == ' ')
529 while (p1 < p2 && isdigit(*p1))
531 playernumber = playernumber * 10 + (*p1 - '0');
539 playername_start = p1;
540 while (p1 < p2 && *p1 != '"')
542 playername_length = p1 - playername_start;
548 playername_start = p1;
549 while (p1 < p2 && *p1 != ' ')
551 playername_length = p1 - playername_start;
553 while (p1 < p2 && *p1 == ' ')
557 // set playernumber to the right client
559 if(playername_length >= sizeof(namebuf))
562 Con_Print("Host_Tell: too long player name/ID\n");
564 SV_ClientPrint("Host_Tell: too long player name/ID\n");
567 memcpy(namebuf, playername_start, playername_length);
568 namebuf[playername_length] = 0;
569 for (playernumber = 0; playernumber < svs.maxclients; playernumber++)
571 if (!svs.clients[playernumber].active)
573 if (strcasecmp(svs.clients[playernumber].name, namebuf) == 0)
577 if(playernumber < 0 || playernumber >= svs.maxclients || !(svs.clients[playernumber].active))
580 Con_Print("Host_Tell: invalid player name/ID\n");
582 SV_ClientPrint("Host_Tell: invalid player name/ID\n");
585 // remove trailing newlines
586 while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
588 // remove quotes if present
595 Con_Print("Host_Tell: missing end quote\n");
597 SV_ClientPrint("Host_Tell: missing end quote\n");
599 while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
603 for (j = (int)strlen(text);j < (int)(sizeof(text) - 2) && p1 < p2;)
609 host_client = svs.clients + playernumber;
610 SV_ClientPrint(text);
620 static void SV_Ping_f(cmd_state_t *cmd)
624 void (*print) (const char *fmt, ...);
626 if (cmd->source == src_local)
629 print = SV_ClientPrintf;
634 print("Client ping times:\n");
635 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
639 print("%4i %s\n", bound(0, (int)floor(client->ping*1000+0.5), 9999), client->name);
647 Send back ping and packet loss update for all current players to this player
650 static void SV_Pings_f(cmd_state_t *cmd)
652 int i, j, ping, packetloss, movementloss;
655 if (!host_client->netconnection)
658 if (sv.protocol != PROTOCOL_QUAKEWORLD)
660 MSG_WriteByte(&host_client->netconnection->message, svc_stufftext);
661 MSG_WriteUnterminatedString(&host_client->netconnection->message, "pingplreport");
663 for (i = 0;i < svs.maxclients;i++)
667 if (svs.clients[i].netconnection)
669 for (j = 0;j < NETGRAPH_PACKETS;j++)
670 if (svs.clients[i].netconnection->incoming_netgraph[j].unreliablebytes == NETGRAPH_LOSTPACKET)
672 for (j = 0;j < NETGRAPH_PACKETS;j++)
673 if (svs.clients[i].movement_count[j] < 0)
676 packetloss = (packetloss * 100 + NETGRAPH_PACKETS - 1) / NETGRAPH_PACKETS;
677 movementloss = (movementloss * 100 + NETGRAPH_PACKETS - 1) / NETGRAPH_PACKETS;
678 ping = (int)floor(svs.clients[i].ping*1000+0.5);
679 ping = bound(0, ping, 9999);
680 if (sv.protocol == PROTOCOL_QUAKEWORLD)
682 // send qw_svc_updateping and qw_svc_updatepl messages
683 MSG_WriteByte(&host_client->netconnection->message, qw_svc_updateping);
684 MSG_WriteShort(&host_client->netconnection->message, ping);
685 MSG_WriteByte(&host_client->netconnection->message, qw_svc_updatepl);
686 MSG_WriteByte(&host_client->netconnection->message, packetloss);
690 // write the string into the packet as multiple unterminated strings to avoid needing a local buffer
692 dpsnprintf(temp, sizeof(temp), " %d %d,%d", ping, packetloss, movementloss);
694 dpsnprintf(temp, sizeof(temp), " %d %d", ping, packetloss);
695 MSG_WriteUnterminatedString(&host_client->netconnection->message, temp);
698 if (sv.protocol != PROTOCOL_QUAKEWORLD)
699 MSG_WriteString(&host_client->netconnection->message, "\n");
707 static void SV_Status_f(cmd_state_t *cmd)
709 prvm_prog_t *prog = SVVM_prog;
712 int seconds = 0, minutes = 0, hours = 0, i, j, k, in, players, ping = 0, packetloss = 0;
713 void (*print) (const char *fmt, ...);
714 char ip[48]; // can contain a full length v6 address with [] and a port
718 if (cmd->source == src_local)
721 print = SV_ClientPrintf;
727 if (Cmd_Argc(cmd) == 2)
729 if (strcmp(Cmd_Argv(cmd, 1), "1") == 0)
731 else if (strcmp(Cmd_Argv(cmd, 1), "2") == 0)
735 for (players = 0, i = 0;i < svs.maxclients;i++)
736 if (svs.clients[i].active)
739 print ("host: %s\n", Cvar_VariableString (&cvars_all, "hostname", CF_SERVER));
740 print ("version: %s\n", engineversion);
741 print ("protocol: %i (%s)\n", Protocol_NumberForEnum(sv.protocol), Protocol_NameForEnum(sv.protocol));
742 print ("map: %s\n", sv.worldbasename);
743 print ("timing: %s\n", SV_TimingReport(vabuf, sizeof(vabuf)));
744 print ("players: %i active (%i max)\n\n", players, svs.maxclients);
747 print ("^2IP %%pl ping time frags no name\n");
749 print ("^5IP no name\n");
751 for (i = 0, k = 0, client = svs.clients;i < svs.maxclients;i++, client++)
758 if (in == 0 || in == 1)
760 seconds = (int)(host.realtime - client->connecttime);
761 minutes = seconds / 60;
764 seconds -= (minutes * 60);
765 hours = minutes / 60;
767 minutes -= (hours * 60);
773 if (client->netconnection)
774 for (j = 0;j < NETGRAPH_PACKETS;j++)
775 if (client->netconnection->incoming_netgraph[j].unreliablebytes == NETGRAPH_LOSTPACKET)
777 packetloss = (packetloss * 100 + NETGRAPH_PACKETS - 1) / NETGRAPH_PACKETS;
778 ping = bound(0, (int)floor(client->ping*1000+0.5), 9999);
781 if(sv_status_privacy.integer && cmd->source != src_local && LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) != LHNETADDRESSTYPE_LOOP)
782 dp_strlcpy(ip, client->netconnection ? "hidden" : "botclient", 48);
784 dp_strlcpy(ip, (client->netconnection && *client->netconnection->address) ? client->netconnection->address : "botclient", 48);
786 frags = client->frags;
788 if(sv_status_show_qcstatus.integer)
790 prvm_edict_t *ed = PRVM_EDICT_NUM(i + 1);
791 const char *str = PRVM_GetString(prog, PRVM_serveredictstring(ed, clientstatus));
797 for(q = str; *q && p != qcstatus + sizeof(qcstatus) - 1; ++q)
798 if(*q != '\\' && *q != '"' && !ISWHITESPACE(*q))
802 frags = atoi(qcstatus);
806 if (in == 0) // default layout
808 if (sv.protocol == PROTOCOL_QUAKE && svs.maxclients <= 99)
810 // LadyHavoc: this is very touchy because we must maintain ProQuake compatible status output
811 print ("#%-2u %-16.16s %3i %2i:%02i:%02i\n", i+1, client->name, frags, hours, minutes, seconds);
816 // LadyHavoc: no real restrictions here, not a ProQuake-compatible protocol anyway...
817 print ("#%-3u %-16.16s %4i %2i:%02i:%02i\n", i+1, client->name, frags, hours, minutes, seconds);
821 else if (in == 1) // extended layout
823 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);
825 else if (in == 2) // reduced layout
827 print ("%s%-47s #%-3u ^7%s\n", k%2 ? "^3" : "^7", ip, i+1, client->name);
832 void SV_Name(int clientnum)
834 prvm_prog_t *prog = SVVM_prog;
835 PRVM_serveredictstring(host_client->edict, netname) = PRVM_SetEngineString(prog, host_client->name);
836 if (strcmp(host_client->old_name, host_client->name))
838 if (host_client->begun)
839 SV_BroadcastPrintf("\003%s ^7changed name to ^3%s\n", host_client->old_name, host_client->name);
840 dp_strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
841 // send notification to all clients
842 MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
843 MSG_WriteByte (&sv.reliable_datagram, clientnum);
844 MSG_WriteString (&sv.reliable_datagram, host_client->name);
845 SV_WriteNetnameIntoDemo(host_client);
850 ======================
852 ======================
854 static void SV_Name_f(cmd_state_t *cmd)
858 const char *newNameSource;
859 char newName[sizeof(host_client->name)];
861 if (Cmd_Argc (cmd) == 1)
864 if (Cmd_Argc (cmd) == 2)
865 newNameSource = Cmd_Argv(cmd, 1);
867 newNameSource = Cmd_Args(cmd);
869 dp_strlcpy(newName, newNameSource, sizeof(newName));
871 if (cmd->source == src_local)
874 if (host.realtime < host_client->nametime && strcmp(newName, host_client->name))
876 SV_ClientPrintf("You can't change name more than once every %.1f seconds!\n", max(0.0f, sv_namechangetimer.value));
880 host_client->nametime = host.realtime + max(0.0f, sv_namechangetimer.value);
882 // point the string back at updateclient->name to keep it safe
883 dp_strlcpy (host_client->name, newName, sizeof (host_client->name));
885 for (i = 0, j = 0;host_client->name[i];i++)
886 if (host_client->name[i] != '\r' && host_client->name[i] != '\n')
887 host_client->name[j++] = host_client->name[i];
888 host_client->name[j] = 0;
890 if(host_client->name[0] == 1 || host_client->name[0] == 2)
891 // may interfere with chat area, and will needlessly beep; so let's add a ^7
893 memmove(host_client->name + 2, host_client->name, sizeof(host_client->name) - 2);
894 host_client->name[sizeof(host_client->name) - 1] = 0;
895 host_client->name[0] = STRING_COLOR_TAG;
896 host_client->name[1] = '0' + STRING_COLOR_DEFAULT;
899 u8_COM_StringLengthNoColors(host_client->name, 0, &valid_colors);
900 if(!valid_colors) // NOTE: this also proves the string is not empty, as "" is a valid colored string
903 l = strlen(host_client->name);
904 if(l < sizeof(host_client->name) - 1)
906 // duplicate the color tag to escape it
907 host_client->name[i] = STRING_COLOR_TAG;
908 host_client->name[i+1] = 0;
909 //Con_DPrintf("abuse detected, adding another trailing color tag\n");
913 // remove the last character to fix the color code
914 host_client->name[l-1] = 0;
915 //Con_DPrintf("abuse detected, removing a trailing color tag\n");
919 // find the last color tag offset and decide if we need to add a reset tag
920 for (i = 0, j = -1;host_client->name[i];i++)
922 if (host_client->name[i] == STRING_COLOR_TAG)
924 if (host_client->name[i+1] >= '0' && host_client->name[i+1] <= '9')
927 // if this happens to be a reset tag then we don't need one
928 if (host_client->name[i+1] == '0' + STRING_COLOR_DEFAULT)
933 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]))
939 if (host_client->name[i+1] == STRING_COLOR_TAG)
946 // does not end in the default color string, so add it
947 if (j >= 0 && strlen(host_client->name) < sizeof(host_client->name) - 2)
948 memcpy(host_client->name + strlen(host_client->name), STRING_COLOR_DEFAULT_STR, strlen(STRING_COLOR_DEFAULT_STR) + 1);
950 SV_Name(host_client - svs.clients);
953 static void SV_Rate_f(cmd_state_t *cmd)
957 rate = atoi(Cmd_Argv(cmd, 1));
959 if (cmd->source == src_local)
962 host_client->rate = rate;
965 static void SV_Rate_BurstSize_f(cmd_state_t *cmd)
969 if (Cmd_Argc(cmd) != 2)
972 rate_burstsize = atoi(Cmd_Argv(cmd, 1));
974 host_client->rate_burstsize = rate_burstsize;
977 static void SV_Color_f(cmd_state_t *cmd)
979 prvm_prog_t *prog = SVVM_prog;
981 int top, bottom, playercolor;
983 top = atoi(Cmd_Argv(cmd, 1));
984 bottom = atoi(Cmd_Argv(cmd, 2));
989 playercolor = top*16 + bottom;
991 if (host_client->edict && PRVM_serverfunction(SV_ChangeTeam))
993 Con_DPrint("Calling SV_ChangeTeam\n");
994 prog->globals.fp[OFS_PARM0] = playercolor;
995 PRVM_serverglobalfloat(time) = sv.time;
996 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict);
997 prog->ExecuteProgram(prog, PRVM_serverfunction(SV_ChangeTeam), "QC function SV_ChangeTeam is missing");
1001 if (host_client->edict)
1003 PRVM_serveredictfloat(host_client->edict, clientcolors) = playercolor;
1004 PRVM_serveredictfloat(host_client->edict, team) = bottom + 1;
1006 host_client->colors = playercolor;
1007 if (host_client->old_colors != host_client->colors)
1009 host_client->old_colors = host_client->colors;
1010 // send notification to all clients
1011 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1012 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1013 MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1022 Kicks a user off of the server
1025 static void SV_Kick_f(cmd_state_t *cmd)
1028 const char *message = NULL;
1032 qbool byNumber = false;
1039 if (Cmd_Argc(cmd) > 2 && strcmp(Cmd_Argv(cmd, 1), "#") == 0)
1041 i = (int)(atof(Cmd_Argv(cmd, 2)) - 1);
1042 if (i < 0 || i >= svs.maxclients || !(host_client = svs.clients + i)->active)
1048 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1050 if (!host_client->active)
1052 if (strcasecmp(host_client->name, Cmd_Argv(cmd, 1)) == 0)
1057 if (i < svs.maxclients)
1059 if (cmd->source == src_local)
1061 if(!host_isclient.integer)
1064 who = cl_name.string;
1069 // can't kick yourself!
1070 if (host_client == save)
1073 if (Cmd_Argc(cmd) > 2)
1075 message = Cmd_Args(cmd);
1076 COM_ParseToken_Simple(&message, false, false, true);
1079 message++; // skip the #
1080 while (*message == ' ') // skip white space
1082 message += strlen(Cmd_Argv(cmd, 2)); // skip the number
1084 while (*message && *message == ' ')
1088 SV_DropClient (false, va(reason, sizeof(reason), "Kicked by %s: %s", who, message)); // kicked
1089 //SV_ClientPrintf("Kicked by %s: %s\n", who, message);
1091 //SV_ClientPrintf("Kicked by %s\n", who);
1092 SV_DropClient (false, va(reason, sizeof(reason), "Kicked by %s", who)); // kicked
1098 static void SV_MaxPlayers_f(cmd_state_t *cmd)
1102 if (Cmd_Argc(cmd) != 2)
1104 Con_Printf("\"maxplayers\" is \"%u\"\n", svs.maxclients_next);
1110 Con_Print("maxplayers can not be changed while a server is running.\n");
1111 Con_Print("It will be changed on next server startup (\"map\" command).\n");
1114 n = atoi(Cmd_Argv(cmd, 1));
1115 n = bound(1, n, MAX_SCOREBOARD);
1116 Con_Printf("\"maxplayers\" set to \"%u\"\n", n);
1118 svs.maxclients_next = n;
1120 Cvar_Set (&cvars_all, "deathmatch", "0");
1122 Cvar_Set (&cvars_all, "deathmatch", "1");
1126 ======================
1128 ======================
1130 // the old playermodel in cl_main has been renamed to __cl_playermodel
1131 static void SV_Playermodel_f(cmd_state_t *cmd)
1133 prvm_prog_t *prog = SVVM_prog;
1135 char newPath[sizeof(host_client->playermodel)];
1137 if (Cmd_Argc (cmd) == 1)
1140 if (Cmd_Argc (cmd) == 2)
1141 dp_strlcpy (newPath, Cmd_Argv(cmd, 1), sizeof (newPath));
1143 dp_strlcpy (newPath, Cmd_Args(cmd), sizeof (newPath));
1145 for (i = 0, j = 0;newPath[i];i++)
1146 if (newPath[i] != '\r' && newPath[i] != '\n')
1147 newPath[j++] = newPath[i];
1151 if (host.realtime < host_client->nametime)
1153 SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
1157 host_client->nametime = host.realtime + 5;
1160 // point the string back at updateclient->name to keep it safe
1161 dp_strlcpy (host_client->playermodel, newPath, sizeof (host_client->playermodel));
1162 PRVM_serveredictstring(host_client->edict, playermodel) = PRVM_SetEngineString(prog, host_client->playermodel);
1163 if (strcmp(host_client->old_model, host_client->playermodel))
1165 dp_strlcpy(host_client->old_model, host_client->playermodel, sizeof(host_client->old_model));
1166 /*// send notification to all clients
1167 MSG_WriteByte (&sv.reliable_datagram, svc_updatepmodel);
1168 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1169 MSG_WriteString (&sv.reliable_datagram, host_client->playermodel);*/
1174 ======================
1176 ======================
1178 static void SV_Playerskin_f(cmd_state_t *cmd)
1180 prvm_prog_t *prog = SVVM_prog;
1182 char newPath[sizeof(host_client->playerskin)];
1184 if (Cmd_Argc (cmd) == 1)
1187 if (Cmd_Argc (cmd) == 2)
1188 dp_strlcpy (newPath, Cmd_Argv(cmd, 1), sizeof (newPath));
1190 dp_strlcpy (newPath, Cmd_Args(cmd), sizeof (newPath));
1192 for (i = 0, j = 0;newPath[i];i++)
1193 if (newPath[i] != '\r' && newPath[i] != '\n')
1194 newPath[j++] = newPath[i];
1198 if (host.realtime < host_client->nametime)
1200 SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
1204 host_client->nametime = host.realtime + 5;
1207 // point the string back at updateclient->name to keep it safe
1208 dp_strlcpy (host_client->playerskin, newPath, sizeof (host_client->playerskin));
1209 PRVM_serveredictstring(host_client->edict, playerskin) = PRVM_SetEngineString(prog, host_client->playerskin);
1210 if (strcmp(host_client->old_skin, host_client->playerskin))
1212 //if (host_client->begun)
1213 // SV_BroadcastPrintf("%s changed skin to %s\n", host_client->name, host_client->playerskin);
1214 dp_strlcpy(host_client->old_skin, host_client->playerskin, sizeof(host_client->old_skin));
1215 /*// send notification to all clients
1216 MSG_WriteByte (&sv.reliable_datagram, svc_updatepskin);
1217 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1218 MSG_WriteString (&sv.reliable_datagram, host_client->playerskin);*/
1223 ======================
1225 LadyHavoc: only supported for Nehahra, I personally think this is dumb, but Mindcrime won't listen.
1226 LadyHavoc: correction, Mindcrime will be removing pmodel in the future, but it's still stuck here for compatibility.
1227 ======================
1229 static void SV_PModel_f(cmd_state_t *cmd)
1231 prvm_prog_t *prog = SVVM_prog;
1233 if (Cmd_Argc (cmd) == 1)
1236 PRVM_serveredictfloat(host_client->edict, pmodel) = atoi(Cmd_Argv(cmd, 1));
1240 ===============================================================================
1244 ===============================================================================
1247 static prvm_edict_t *FindViewthing(prvm_prog_t *prog)
1252 for (i=0 ; i<prog->num_edicts ; i++)
1254 e = PRVM_EDICT_NUM(i);
1255 if (!strcmp (PRVM_GetString(prog, PRVM_serveredictstring(e, classname)), "viewthing"))
1258 Con_Print("No viewthing on map\n");
1267 static void SV_Viewmodel_f(cmd_state_t *cmd)
1269 prvm_prog_t *prog = SVVM_prog;
1276 e = FindViewthing(prog);
1279 m = Mod_ForName (Cmd_Argv(cmd, 1), false, true, NULL);
1280 if (m && m->loaded && m->Draw)
1282 PRVM_serveredictfloat(e, frame) = 0;
1283 cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)] = m;
1286 Con_Printf("viewmodel: can't load %s\n", Cmd_Argv(cmd, 1));
1295 static void SV_Viewframe_f(cmd_state_t *cmd)
1297 prvm_prog_t *prog = SVVM_prog;
1305 e = FindViewthing(prog);
1308 m = cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)];
1310 f = atoi(Cmd_Argv(cmd, 1));
1311 if (f >= m->numframes)
1314 PRVM_serveredictfloat(e, frame) = f;
1318 static void PrintFrameName (model_t *m, int frame)
1321 Con_Printf("frame %i: %s\n", frame, m->animscenes[frame].name);
1323 Con_Printf("frame %i\n", frame);
1331 static void SV_Viewnext_f(cmd_state_t *cmd)
1333 prvm_prog_t *prog = SVVM_prog;
1340 e = FindViewthing(prog);
1343 m = cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)];
1345 PRVM_serveredictfloat(e, frame) = PRVM_serveredictfloat(e, frame) + 1;
1346 if (PRVM_serveredictfloat(e, frame) >= m->numframes)
1347 PRVM_serveredictfloat(e, frame) = m->numframes - 1;
1349 PrintFrameName (m, (int)PRVM_serveredictfloat(e, frame));
1358 static void SV_Viewprev_f(cmd_state_t *cmd)
1360 prvm_prog_t *prog = SVVM_prog;
1367 e = FindViewthing(prog);
1370 m = cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)];
1372 PRVM_serveredictfloat(e, frame) = PRVM_serveredictfloat(e, frame) - 1;
1373 if (PRVM_serveredictfloat(e, frame) < 0)
1374 PRVM_serveredictfloat(e, frame) = 0;
1376 PrintFrameName (m, (int)PRVM_serveredictfloat(e, frame));
1380 static void SV_SendCvar_f(cmd_state_t *cmd)
1383 const char *cvarname;
1386 if(Cmd_Argc(cmd) != 2)
1389 if(!sv.active)// || !PRVM_serverfunction(SV_ParseClientCommand))
1392 cvarname = Cmd_Argv(cmd, 1);
1395 if(host_isclient.integer)
1399 for(;i<svs.maxclients;i++)
1400 if(svs.clients[i].active && svs.clients[i].netconnection)
1402 host_client = &svs.clients[i];
1403 SV_ClientCommands("sendcvar %s\n", cvarname);
1408 static void SV_Ent_Create_f(cmd_state_t *cmd)
1410 prvm_prog_t *prog = SVVM_prog;
1416 void (*print)(const char *, ...) = (cmd->source == src_client ? SV_ClientPrintf : Con_Printf);
1421 ed = PRVM_ED_Alloc(SVVM_prog);
1423 PRVM_ED_ParseEpair(prog, ed, PRVM_ED_FindField(prog, "classname"), Cmd_Argv(cmd, 1), false);
1425 // Spawn where the player is aiming. We need a view matrix first.
1426 if(cmd->source == src_client)
1428 vec3_t org, temp, dest;
1433 SV_GetEntityMatrix(prog, host_client->edict, &view, true);
1435 Matrix4x4_OriginFromMatrix(&view, org);
1436 VectorSet(temp, 65536, 0, 0);
1437 Matrix4x4_Transform(&view, temp, dest);
1439 trace = SV_TraceLine(org, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, 0, 0, collision_extendmovelength.value);
1441 dpsnprintf(buf, sizeof(buf), "%g %g %g", trace.endpos[0], trace.endpos[1], trace.endpos[2]);
1442 PRVM_ED_ParseEpair(prog, ed, PRVM_ED_FindField(prog, "origin"), buf, false);
1446 // Or spawn at a specified origin.
1453 // Allow more than one key/value pair by cycling between expecting either one.
1454 for(i = 2; i < Cmd_Argc(cmd); i += 2)
1456 if(!(key = PRVM_ED_FindField(prog, Cmd_Argv(cmd, i))))
1458 print("Key %s not found!\n", Cmd_Argv(cmd, i));
1459 PRVM_ED_Free(prog, ed);
1464 * This is mostly for dedicated server console, but if the
1465 * player gave a custom origin, we can ignore the traceline.
1467 if(!strcmp(Cmd_Argv(cmd, i), "origin"))
1470 if (i + 1 < Cmd_Argc(cmd))
1471 PRVM_ED_ParseEpair(prog, ed, key, Cmd_Argv(cmd, i+1), false);
1476 print("Missing origin\n");
1477 PRVM_ED_Free(prog, ed);
1482 PRVM_ED_CallPrespawnFunction(prog, ed);
1484 if(!PRVM_ED_CallSpawnFunction(prog, ed, NULL, NULL))
1486 print("Could not spawn a \"%s\". No such entity or it has no spawn function\n", Cmd_Argv(cmd, 1));
1487 if(cmd->source == src_client)
1488 Con_Printf("%s tried to spawn a \"%s\"\n", host_client->name, Cmd_Argv(cmd, 1));
1489 // CallSpawnFunction already freed the edict for us.
1493 PRVM_ED_CallPostspawnFunction(prog, ed);
1495 // Make it appear in the world
1498 if(cmd->source == src_client)
1499 Con_Printf("%s spawned a \"%s\"\n", host_client->name, Cmd_Argv(cmd, 1));
1502 static void SV_Ent_Remove_f(cmd_state_t *cmd)
1504 prvm_prog_t *prog = SVVM_prog;
1507 void (*print)(const char *, ...) = (cmd->source == src_client ? SV_ClientPrintf : Con_Printf);
1512 // Allow specifying edict by number
1513 if(Cmd_Argc(cmd) > 1 && Cmd_Argv(cmd, 1))
1515 ednum = atoi(Cmd_Argv(cmd, 1));
1518 print("Cannot remove the world\n");
1522 // Or trace a line if it's a client who didn't specify one.
1523 else if(cmd->source == src_client)
1525 vec3_t org, temp, dest;
1529 SV_GetEntityMatrix(prog, host_client->edict, &view, true);
1531 Matrix4x4_OriginFromMatrix(&view, org);
1532 VectorSet(temp, 65536, 0, 0);
1533 Matrix4x4_Transform(&view, temp, dest);
1535 trace = SV_TraceLine(org, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY, 0, 0, collision_extendmovelength.value);
1538 ednum = (int)PRVM_EDICT_TO_PROG(trace.ent);
1539 if(!trace.ent || !ednum)
1540 // Don't remove the world, but don't annoy players with a print if they miss
1545 // Only a dedicated server console should be able to reach this.
1546 print("No edict given\n");
1550 ed = PRVM_EDICT_NUM(ednum);
1555 for (i = 0; i < svs.maxclients; i++)
1557 if(ed == svs.clients[i].edict)
1563 print("Removed a \"%s\"\n", PRVM_GetString(prog, PRVM_serveredictstring(ed, classname)));
1564 PRVM_ED_ClearEdict(prog, ed);
1565 PRVM_ED_Free(prog, ed);
1570 // This should only be reachable if an invalid edict number was given
1571 print("No such entity\n");
1576 static void SV_Ent_Remove_All_f(cmd_state_t *cmd)
1578 prvm_prog_t *prog = SVVM_prog;
1581 void (*print)(const char *, ...) = (cmd->source == src_client ? SV_ClientPrintf : Con_Printf);
1583 for (i = 0, rmcount = 0, ed = PRVM_EDICT_NUM(i); i < prog->num_edicts; i++, ed = PRVM_NEXT_EDICT(ed))
1585 if(!ed->free && !strcmp(PRVM_GetString(prog, PRVM_serveredictstring(ed, classname)), Cmd_Argv(cmd, 1)))
1589 print("Cannot remove the world\n");
1592 PRVM_ED_ClearEdict(prog, ed);
1593 PRVM_ED_Free(prog, ed);
1599 print("No \"%s\" found\n", Cmd_Argv(cmd, 1));
1601 print("Removed %i of \"%s\"\n", rmcount, Cmd_Argv(cmd, 1));
1604 void SV_InitOperatorCommands(void)
1606 Cvar_RegisterVariable(&sv_cheats);
1607 Cvar_RegisterCallback(&sv_cheats, SV_DisableCheats_c);
1608 Cvar_RegisterVariable(&sv_adminnick);
1609 Cvar_RegisterVariable(&sv_status_privacy);
1610 Cvar_RegisterVariable(&sv_status_show_qcstatus);
1611 Cvar_RegisterVariable(&sv_namechangetimer);
1613 Cmd_AddCommand(CF_SERVER | CF_SERVER_FROM_CLIENT, "status", SV_Status_f, "print server status information");
1614 Cmd_AddCommand(CF_SHARED, "map", SV_Map_f, "kick everyone off the server and start a new level");
1615 Cmd_AddCommand(CF_SHARED, "restart", SV_Restart_f, "restart current level");
1616 Cmd_AddCommand(CF_SHARED, "changelevel", SV_Changelevel_f, "change to another level, bringing along all connected clients");
1617 Cmd_AddCommand(CF_SHARED | CF_SERVER_FROM_CLIENT, "say", SV_Say_f, "send a chat message to everyone on the server");
1618 Cmd_AddCommand(CF_SERVER_FROM_CLIENT, "say_team", SV_Say_Team_f, "send a chat message to your team on the server");
1619 Cmd_AddCommand(CF_SHARED | CF_SERVER_FROM_CLIENT, "tell", SV_Tell_f, "send a chat message to only one person on the server");
1620 Cmd_AddCommand(CF_SERVER | CF_SERVER_FROM_CLIENT, "pause", SV_Pause_f, "pause the game (if the server allows pausing)");
1621 Cmd_AddCommand(CF_SHARED, "kick", SV_Kick_f, "kick a player off the server by number or name");
1622 Cmd_AddCommand(CF_SHARED | CF_SERVER_FROM_CLIENT, "ping", SV_Ping_f, "print ping times of all players on the server");
1623 Cmd_AddCommand(CF_SHARED, "load", SV_Loadgame_f, "load a saved game file");
1624 Cmd_AddCommand(CF_SHARED, "save", SV_Savegame_f, "save the game to a file");
1625 Cmd_AddCommand(CF_SHARED, "viewmodel", SV_Viewmodel_f, "change model of viewthing entity in current level");
1626 Cmd_AddCommand(CF_SHARED, "viewframe", SV_Viewframe_f, "change animation frame of viewthing entity in current level");
1627 Cmd_AddCommand(CF_SHARED, "viewnext", SV_Viewnext_f, "change to next animation frame of viewthing entity in current level");
1628 Cmd_AddCommand(CF_SHARED, "viewprev", SV_Viewprev_f, "change to previous animation frame of viewthing entity in current level");
1629 Cmd_AddCommand(CF_SHARED, "maxplayers", SV_MaxPlayers_f, "sets limit on how many players (or bots) may be connected to the server at once");
1630 host.hook.SV_SendCvar = SV_SendCvar_f;
1632 // commands that do not have automatic forwarding from cmd_local, 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)
1633 Cmd_AddCommand(CF_SERVER_FROM_CLIENT, "prespawn", SV_PreSpawn_f, "internal use - signon 1 (client acknowledges that server information has been received)");
1634 Cmd_AddCommand(CF_SERVER_FROM_CLIENT, "spawn", SV_Spawn_f, "internal use - signon 2 (client has sent player information, and is asking server to send scoreboard rankings)");
1635 Cmd_AddCommand(CF_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)");
1636 Cmd_AddCommand(CF_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)");
1638 Cmd_AddCommand(CF_CHEAT | CF_SERVER_FROM_CLIENT, "god", SV_God_f, "god mode (invulnerability)");
1639 Cmd_AddCommand(CF_CHEAT | CF_SERVER_FROM_CLIENT, "notarget", SV_Notarget_f, "notarget mode (monsters do not see you)");
1640 Cmd_AddCommand(CF_CHEAT | CF_SERVER_FROM_CLIENT, "fly", SV_Fly_f, "fly mode (flight)");
1641 Cmd_AddCommand(CF_CHEAT | CF_SERVER_FROM_CLIENT, "noclip", SV_Noclip_f, "noclip mode (flight without collisions, move through walls)");
1642 Cmd_AddCommand(CF_CHEAT | CF_SERVER_FROM_CLIENT, "give", SV_Give_f, "alter inventory");
1643 Cmd_AddCommand(CF_SERVER_FROM_CLIENT, "kill", SV_Kill_f, "die instantly");
1645 Cmd_AddCommand(CF_USERINFO, "color", SV_Color_f, "change your player shirt and pants colors");
1646 Cmd_AddCommand(CF_USERINFO, "name", SV_Name_f, "change your player name");
1647 Cmd_AddCommand(CF_USERINFO, "rate", SV_Rate_f, "change your network connection speed");
1648 Cmd_AddCommand(CF_USERINFO, "rate_burstsize", SV_Rate_BurstSize_f, "change your network connection speed");
1649 Cmd_AddCommand(CF_USERINFO, "pmodel", SV_PModel_f, "(Nehahra-only) change your player model choice");
1650 Cmd_AddCommand(CF_USERINFO, "playermodel", SV_Playermodel_f, "change your player model");
1651 Cmd_AddCommand(CF_USERINFO, "playerskin", SV_Playerskin_f, "change your player skin number");
1653 Cmd_AddCommand(CF_CHEAT | CF_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.");
1654 Cmd_AddCommand(CF_CHEAT | CF_SERVER_FROM_CLIENT, "ent_remove_all", SV_Ent_Remove_All_f, "Removes all entities of the specified classname");
1655 Cmd_AddCommand(CF_CHEAT | CF_SERVER_FROM_CLIENT, "ent_remove", SV_Ent_Remove_f, "Removes an entity by number, or the entity you're aiming at");