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();
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 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 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 prvm_prog_t *prog = SVVM_prog;
145 if (PRVM_serverfunction(RestartTriggered))
147 Con_DPrint("Calling RestartTriggered\n");
148 PRVM_serverglobalfloat(time) = sv.time;
149 prog->ExecuteProgram(prog, PRVM_serverfunction(RestartTriggered), "QC function RestartTriggered is missing");
152 if(host.hook.ToggleMenu)
153 host.hook.ToggleMenu();
155 strlcpy(mapname, sv.name, sizeof(mapname));
156 SV_SpawnServer(mapname);
158 if(sv.active && host.hook.ConnectLocal != NULL)
159 host.hook.ConnectLocal();
162 //===========================================================================
164 // Disable cheats if sv_cheats is turned off
165 static void SV_DisableCheats_c(cvar_t *var)
167 prvm_prog_t *prog = SVVM_prog;
172 while (svs.clients[i].edict)
174 if (((int)PRVM_serveredictfloat(svs.clients[i].edict, flags) & FL_GODMODE))
175 PRVM_serveredictfloat(svs.clients[i].edict, flags) = (int)PRVM_serveredictfloat(svs.clients[i].edict, flags) ^ FL_GODMODE;
176 if (((int)PRVM_serveredictfloat(svs.clients[i].edict, flags) & FL_NOTARGET))
177 PRVM_serveredictfloat(svs.clients[i].edict, flags) = (int)PRVM_serveredictfloat(svs.clients[i].edict, flags) ^ FL_NOTARGET;
178 if (PRVM_serveredictfloat(svs.clients[i].edict, movetype) == MOVETYPE_NOCLIP ||
179 PRVM_serveredictfloat(svs.clients[i].edict, movetype) == MOVETYPE_FLY)
181 noclip_anglehack = false;
182 PRVM_serveredictfloat(svs.clients[i].edict, movetype) = MOVETYPE_WALK;
193 Sets client to godmode
196 static void SV_God_f(cmd_state_t *cmd)
198 prvm_prog_t *prog = SVVM_prog;
200 PRVM_serveredictfloat(host_client->edict, flags) = (int)PRVM_serveredictfloat(host_client->edict, flags) ^ FL_GODMODE;
201 if (!((int)PRVM_serveredictfloat(host_client->edict, flags) & FL_GODMODE) )
202 SV_ClientPrint("godmode OFF\n");
204 SV_ClientPrint("godmode ON\n");
207 qbool noclip_anglehack;
209 static void SV_Noclip_f(cmd_state_t *cmd)
211 prvm_prog_t *prog = SVVM_prog;
213 if (PRVM_serveredictfloat(host_client->edict, movetype) != MOVETYPE_NOCLIP)
215 noclip_anglehack = true;
216 PRVM_serveredictfloat(host_client->edict, movetype) = MOVETYPE_NOCLIP;
217 SV_ClientPrint("noclip ON\n");
221 noclip_anglehack = false;
222 PRVM_serveredictfloat(host_client->edict, movetype) = MOVETYPE_WALK;
223 SV_ClientPrint("noclip OFF\n");
232 static void SV_Give_f(cmd_state_t *cmd)
234 prvm_prog_t *prog = SVVM_prog;
238 t = Cmd_Argv(cmd, 1);
239 v = atoi (Cmd_Argv(cmd, 2));
253 // MED 01/04/97 added hipnotic give stuff
254 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_QUOTH)
259 PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | HIT_PROXIMITY_GUN;
261 PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | IT_GRENADE_LAUNCHER;
263 else if (t[0] == '9')
264 PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | HIT_LASER_CANNON;
265 else if (t[0] == '0')
266 PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | HIT_MJOLNIR;
267 else if (t[0] >= '2')
268 PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | (IT_SHOTGUN << (t[0] - '2'));
273 PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | (IT_SHOTGUN << (t[0] - '2'));
278 if (gamemode == GAME_ROGUE)
279 PRVM_serveredictfloat(host_client->edict, ammo_shells1) = v;
281 PRVM_serveredictfloat(host_client->edict, ammo_shells) = v;
284 if (gamemode == GAME_ROGUE)
286 PRVM_serveredictfloat(host_client->edict, ammo_nails1) = v;
287 if (PRVM_serveredictfloat(host_client->edict, weapon) <= IT_LIGHTNING)
288 PRVM_serveredictfloat(host_client->edict, ammo_nails) = v;
292 PRVM_serveredictfloat(host_client->edict, ammo_nails) = v;
296 if (gamemode == GAME_ROGUE)
298 PRVM_serveredictfloat(host_client->edict, ammo_lava_nails) = v;
299 if (PRVM_serveredictfloat(host_client->edict, weapon) > IT_LIGHTNING)
300 PRVM_serveredictfloat(host_client->edict, ammo_nails) = v;
304 if (gamemode == GAME_ROGUE)
306 PRVM_serveredictfloat(host_client->edict, ammo_rockets1) = v;
307 if (PRVM_serveredictfloat(host_client->edict, weapon) <= IT_LIGHTNING)
308 PRVM_serveredictfloat(host_client->edict, ammo_rockets) = v;
312 PRVM_serveredictfloat(host_client->edict, ammo_rockets) = v;
316 if (gamemode == GAME_ROGUE)
318 PRVM_serveredictfloat(host_client->edict, ammo_multi_rockets) = v;
319 if (PRVM_serveredictfloat(host_client->edict, weapon) > IT_LIGHTNING)
320 PRVM_serveredictfloat(host_client->edict, ammo_rockets) = v;
324 PRVM_serveredictfloat(host_client->edict, health) = v;
327 if (gamemode == GAME_ROGUE)
329 PRVM_serveredictfloat(host_client->edict, ammo_cells1) = v;
330 if (PRVM_serveredictfloat(host_client->edict, weapon) <= IT_LIGHTNING)
331 PRVM_serveredictfloat(host_client->edict, ammo_cells) = v;
335 PRVM_serveredictfloat(host_client->edict, ammo_cells) = v;
339 if (gamemode == GAME_ROGUE)
341 PRVM_serveredictfloat(host_client->edict, ammo_plasma) = v;
342 if (PRVM_serveredictfloat(host_client->edict, weapon) > IT_LIGHTNING)
343 PRVM_serveredictfloat(host_client->edict, ammo_cells) = v;
353 Sets client to flymode
356 static void SV_Fly_f(cmd_state_t *cmd)
358 prvm_prog_t *prog = SVVM_prog;
360 if (PRVM_serveredictfloat(host_client->edict, movetype) != MOVETYPE_FLY)
362 PRVM_serveredictfloat(host_client->edict, movetype) = MOVETYPE_FLY;
363 SV_ClientPrint("flymode ON\n");
367 PRVM_serveredictfloat(host_client->edict, movetype) = MOVETYPE_WALK;
368 SV_ClientPrint("flymode OFF\n");
372 static void SV_Notarget_f(cmd_state_t *cmd)
374 prvm_prog_t *prog = SVVM_prog;
376 PRVM_serveredictfloat(host_client->edict, flags) = (int)PRVM_serveredictfloat(host_client->edict, flags) ^ FL_NOTARGET;
377 if (!((int)PRVM_serveredictfloat(host_client->edict, flags) & FL_NOTARGET) )
378 SV_ClientPrint("notarget OFF\n");
380 SV_ClientPrint("notarget ON\n");
388 static void SV_Kill_f(cmd_state_t *cmd)
390 prvm_prog_t *prog = SVVM_prog;
391 if (PRVM_serveredictfloat(host_client->edict, health) <= 0)
393 SV_ClientPrint("Can't suicide -- already dead!\n");
397 PRVM_serverglobalfloat(time) = sv.time;
398 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict);
399 prog->ExecuteProgram(prog, PRVM_serverfunction(ClientKill), "QC function ClientKill is missing");
407 static void SV_Pause_f(cmd_state_t *cmd)
409 void (*print) (const char *fmt, ...);
410 if (cmd->source == src_local)
413 print = SV_ClientPrintf;
415 if (!pausable.integer && cmd->source == src_client && LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) != LHNETADDRESSTYPE_LOOP)
417 print("Pause not allowed.\n");
422 if (cmd->source != src_local)
423 SV_BroadcastPrintf("%s %spaused the game\n", host_client->name, sv.paused ? "" : "un");
424 else if(*(sv_adminnick.string))
425 SV_BroadcastPrintf("%s %spaused the game\n", sv_adminnick.string, sv.paused ? "" : "un");
427 SV_BroadcastPrintf("%s %spaused the game\n", hostname.string, sv.paused ? "" : "un");
428 // send notification to all clients
429 MSG_WriteByte(&sv.reliable_datagram, svc_setpause);
430 MSG_WriteByte(&sv.reliable_datagram, sv.paused);
433 static void SV_Say(cmd_state_t *cmd, qbool teamonly)
435 prvm_prog_t *prog = SVVM_prog;
440 // LadyHavoc: long say messages
442 qbool fromServer = false;
444 if (cmd->source == src_local)
450 if (Cmd_Argc (cmd) < 2)
453 if (!teamplay.integer)
463 // note this uses the chat prefix \001
464 if (!fromServer && !teamonly)
465 dpsnprintf (text, sizeof(text), "\001%s: %s", host_client->name, p1);
466 else if (!fromServer && teamonly)
467 dpsnprintf (text, sizeof(text), "\001(%s): %s", host_client->name, p1);
468 else if(*(sv_adminnick.string))
469 dpsnprintf (text, sizeof(text), "\001<%s> %s", sv_adminnick.string, p1);
471 dpsnprintf (text, sizeof(text), "\001<%s> %s", hostname.string, p1);
472 p2 = text + strlen(text);
473 while ((const char *)p2 > (const char *)text && (p2[-1] == '\r' || p2[-1] == '\n' || (p2[-1] == '\"' && quoted)))
475 if (p2[-1] == '\"' && quoted)
480 strlcat(text, "\n", sizeof(text));
482 // note: save is not a valid edict if fromServer is true
484 for (j = 0, host_client = svs.clients;j < svs.maxclients;j++, host_client++)
485 if (host_client->active && (!teamonly || PRVM_serveredictfloat(host_client->edict, team) == PRVM_serveredictfloat(save->edict, team)))
486 SV_ClientPrint(text);
489 if(!host_isclient.integer)
493 static void SV_Say_f(cmd_state_t *cmd)
498 static void SV_Say_Team_f(cmd_state_t *cmd)
503 static void SV_Tell_f(cmd_state_t *cmd)
505 const char *playername_start = NULL;
506 size_t playername_length = 0;
507 int playernumber = 0;
511 char text[MAX_INPUTLINE]; // LadyHavoc: FIXME: temporary buffer overflow fix (was 64)
512 qbool fromServer = false;
514 if (cmd->source == src_local)
517 if (Cmd_Argc (cmd) < 2)
520 // note this uses the chat prefix \001
522 dpsnprintf (text, sizeof(text), "\001%s tells you: ", host_client->name);
523 else if(*(sv_adminnick.string))
524 dpsnprintf (text, sizeof(text), "\001<%s tells you> ", sv_adminnick.string);
526 dpsnprintf (text, sizeof(text), "\001<%s tells you> ", hostname.string);
529 p2 = p1 + strlen(p1);
530 // remove the target name
531 while (p1 < p2 && *p1 == ' ')
536 while (p1 < p2 && *p1 == ' ')
538 while (p1 < p2 && isdigit(*p1))
540 playernumber = playernumber * 10 + (*p1 - '0');
548 playername_start = p1;
549 while (p1 < p2 && *p1 != '"')
551 playername_length = p1 - playername_start;
557 playername_start = p1;
558 while (p1 < p2 && *p1 != ' ')
560 playername_length = p1 - playername_start;
562 while (p1 < p2 && *p1 == ' ')
566 // set playernumber to the right client
568 if(playername_length >= sizeof(namebuf))
571 Con_Print("Host_Tell: too long player name/ID\n");
573 SV_ClientPrint("Host_Tell: too long player name/ID\n");
576 memcpy(namebuf, playername_start, playername_length);
577 namebuf[playername_length] = 0;
578 for (playernumber = 0; playernumber < svs.maxclients; playernumber++)
580 if (!svs.clients[playernumber].active)
582 if (strcasecmp(svs.clients[playernumber].name, namebuf) == 0)
586 if(playernumber < 0 || playernumber >= svs.maxclients || !(svs.clients[playernumber].active))
589 Con_Print("Host_Tell: invalid player name/ID\n");
591 SV_ClientPrint("Host_Tell: invalid player name/ID\n");
594 // remove trailing newlines
595 while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
597 // remove quotes if present
604 Con_Print("Host_Tell: missing end quote\n");
606 SV_ClientPrint("Host_Tell: missing end quote\n");
608 while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
612 for (j = (int)strlen(text);j < (int)(sizeof(text) - 2) && p1 < p2;)
618 host_client = svs.clients + playernumber;
619 SV_ClientPrint(text);
629 static void SV_Ping_f(cmd_state_t *cmd)
633 void (*print) (const char *fmt, ...);
635 if (cmd->source == src_local)
638 print = SV_ClientPrintf;
643 print("Client ping times:\n");
644 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
648 print("%4i %s\n", bound(0, (int)floor(client->ping*1000+0.5), 9999), client->name);
656 Send back ping and packet loss update for all current players to this player
659 static void SV_Pings_f(cmd_state_t *cmd)
661 int i, j, ping, packetloss, movementloss;
664 if (!host_client->netconnection)
667 if (sv.protocol != PROTOCOL_QUAKEWORLD)
669 MSG_WriteByte(&host_client->netconnection->message, svc_stufftext);
670 MSG_WriteUnterminatedString(&host_client->netconnection->message, "pingplreport");
672 for (i = 0;i < svs.maxclients;i++)
676 if (svs.clients[i].netconnection)
678 for (j = 0;j < NETGRAPH_PACKETS;j++)
679 if (svs.clients[i].netconnection->incoming_netgraph[j].unreliablebytes == NETGRAPH_LOSTPACKET)
681 for (j = 0;j < NETGRAPH_PACKETS;j++)
682 if (svs.clients[i].movement_count[j] < 0)
685 packetloss = (packetloss * 100 + NETGRAPH_PACKETS - 1) / NETGRAPH_PACKETS;
686 movementloss = (movementloss * 100 + NETGRAPH_PACKETS - 1) / NETGRAPH_PACKETS;
687 ping = (int)floor(svs.clients[i].ping*1000+0.5);
688 ping = bound(0, ping, 9999);
689 if (sv.protocol == PROTOCOL_QUAKEWORLD)
691 // send qw_svc_updateping and qw_svc_updatepl messages
692 MSG_WriteByte(&host_client->netconnection->message, qw_svc_updateping);
693 MSG_WriteShort(&host_client->netconnection->message, ping);
694 MSG_WriteByte(&host_client->netconnection->message, qw_svc_updatepl);
695 MSG_WriteByte(&host_client->netconnection->message, packetloss);
699 // write the string into the packet as multiple unterminated strings to avoid needing a local buffer
701 dpsnprintf(temp, sizeof(temp), " %d %d,%d", ping, packetloss, movementloss);
703 dpsnprintf(temp, sizeof(temp), " %d %d", ping, packetloss);
704 MSG_WriteUnterminatedString(&host_client->netconnection->message, temp);
707 if (sv.protocol != PROTOCOL_QUAKEWORLD)
708 MSG_WriteString(&host_client->netconnection->message, "\n");
716 static void SV_Status_f(cmd_state_t *cmd)
718 prvm_prog_t *prog = SVVM_prog;
721 int seconds = 0, minutes = 0, hours = 0, i, j, k, in, players, ping = 0, packetloss = 0;
722 void (*print) (const char *fmt, ...);
723 char ip[48]; // can contain a full length v6 address with [] and a port
727 if (cmd->source == src_local)
730 print = SV_ClientPrintf;
736 if (Cmd_Argc(cmd) == 2)
738 if (strcmp(Cmd_Argv(cmd, 1), "1") == 0)
740 else if (strcmp(Cmd_Argv(cmd, 1), "2") == 0)
744 for (players = 0, i = 0;i < svs.maxclients;i++)
745 if (svs.clients[i].active)
747 print ("host: %s\n", Cvar_VariableString (&cvars_all, "hostname", CF_SERVER));
748 print ("version: %s build %s (gamename %s)\n", gamename, buildstring, gamenetworkfiltername);
749 print ("protocol: %i (%s)\n", Protocol_NumberForEnum(sv.protocol), Protocol_NameForEnum(sv.protocol));
750 print ("map: %s\n", sv.name);
751 print ("timing: %s\n", Host_TimingReport(vabuf, sizeof(vabuf)));
752 print ("players: %i active (%i max)\n\n", players, svs.maxclients);
755 print ("^2IP %%pl ping time frags no name\n");
757 print ("^5IP no name\n");
759 for (i = 0, k = 0, client = svs.clients;i < svs.maxclients;i++, client++)
766 if (in == 0 || in == 1)
768 seconds = (int)(host.realtime - client->connecttime);
769 minutes = seconds / 60;
772 seconds -= (minutes * 60);
773 hours = minutes / 60;
775 minutes -= (hours * 60);
781 if (client->netconnection)
782 for (j = 0;j < NETGRAPH_PACKETS;j++)
783 if (client->netconnection->incoming_netgraph[j].unreliablebytes == NETGRAPH_LOSTPACKET)
785 packetloss = (packetloss * 100 + NETGRAPH_PACKETS - 1) / NETGRAPH_PACKETS;
786 ping = bound(0, (int)floor(client->ping*1000+0.5), 9999);
789 if(sv_status_privacy.integer && cmd->source != src_local && LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) != LHNETADDRESSTYPE_LOOP)
790 strlcpy(ip, client->netconnection ? "hidden" : "botclient", 48);
792 strlcpy(ip, (client->netconnection && *client->netconnection->address) ? client->netconnection->address : "botclient", 48);
794 frags = client->frags;
796 if(sv_status_show_qcstatus.integer)
798 prvm_edict_t *ed = PRVM_EDICT_NUM(i + 1);
799 const char *str = PRVM_GetString(prog, PRVM_serveredictstring(ed, clientstatus));
805 for(q = str; *q && p != qcstatus + sizeof(qcstatus) - 1; ++q)
806 if(*q != '\\' && *q != '"' && !ISWHITESPACE(*q))
810 frags = atoi(qcstatus);
814 if (in == 0) // default layout
816 if (sv.protocol == PROTOCOL_QUAKE && svs.maxclients <= 99)
818 // LadyHavoc: this is very touchy because we must maintain ProQuake compatible status output
819 print ("#%-2u %-16.16s %3i %2i:%02i:%02i\n", i+1, client->name, frags, hours, minutes, seconds);
824 // LadyHavoc: no real restrictions here, not a ProQuake-compatible protocol anyway...
825 print ("#%-3u %-16.16s %4i %2i:%02i:%02i\n", i+1, client->name, frags, hours, minutes, seconds);
829 else if (in == 1) // extended layout
831 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);
833 else if (in == 2) // reduced layout
835 print ("%s%-47s #%-3u ^7%s\n", k%2 ? "^3" : "^7", ip, i+1, client->name);
840 void SV_Name(int clientnum)
842 prvm_prog_t *prog = SVVM_prog;
843 PRVM_serveredictstring(host_client->edict, netname) = PRVM_SetEngineString(prog, host_client->name);
844 if (strcmp(host_client->old_name, host_client->name))
846 if (host_client->begun)
847 SV_BroadcastPrintf("\003%s ^7changed name to ^3%s\n", host_client->old_name, host_client->name);
848 strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
849 // send notification to all clients
850 MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
851 MSG_WriteByte (&sv.reliable_datagram, clientnum);
852 MSG_WriteString (&sv.reliable_datagram, host_client->name);
853 SV_WriteNetnameIntoDemo(host_client);
858 ======================
860 ======================
862 static void SV_Name_f(cmd_state_t *cmd)
866 const char *newNameSource;
867 char newName[sizeof(host_client->name)];
869 if (Cmd_Argc (cmd) == 1)
872 if (Cmd_Argc (cmd) == 2)
873 newNameSource = Cmd_Argv(cmd, 1);
875 newNameSource = Cmd_Args(cmd);
877 strlcpy(newName, newNameSource, sizeof(newName));
879 if (cmd->source == src_local)
882 if (host.realtime < host_client->nametime && strcmp(newName, host_client->name))
884 SV_ClientPrintf("You can't change name more than once every %.1f seconds!\n", max(0.0f, sv_namechangetimer.value));
888 host_client->nametime = host.realtime + max(0.0f, sv_namechangetimer.value);
890 // point the string back at updateclient->name to keep it safe
891 strlcpy (host_client->name, newName, sizeof (host_client->name));
893 for (i = 0, j = 0;host_client->name[i];i++)
894 if (host_client->name[i] != '\r' && host_client->name[i] != '\n')
895 host_client->name[j++] = host_client->name[i];
896 host_client->name[j] = 0;
898 if(host_client->name[0] == 1 || host_client->name[0] == 2)
899 // may interfere with chat area, and will needlessly beep; so let's add a ^7
901 memmove(host_client->name + 2, host_client->name, sizeof(host_client->name) - 2);
902 host_client->name[sizeof(host_client->name) - 1] = 0;
903 host_client->name[0] = STRING_COLOR_TAG;
904 host_client->name[1] = '0' + STRING_COLOR_DEFAULT;
907 u8_COM_StringLengthNoColors(host_client->name, 0, &valid_colors);
908 if(!valid_colors) // NOTE: this also proves the string is not empty, as "" is a valid colored string
911 l = strlen(host_client->name);
912 if(l < sizeof(host_client->name) - 1)
914 // duplicate the color tag to escape it
915 host_client->name[i] = STRING_COLOR_TAG;
916 host_client->name[i+1] = 0;
917 //Con_DPrintf("abuse detected, adding another trailing color tag\n");
921 // remove the last character to fix the color code
922 host_client->name[l-1] = 0;
923 //Con_DPrintf("abuse detected, removing a trailing color tag\n");
927 // find the last color tag offset and decide if we need to add a reset tag
928 for (i = 0, j = -1;host_client->name[i];i++)
930 if (host_client->name[i] == STRING_COLOR_TAG)
932 if (host_client->name[i+1] >= '0' && host_client->name[i+1] <= '9')
935 // if this happens to be a reset tag then we don't need one
936 if (host_client->name[i+1] == '0' + STRING_COLOR_DEFAULT)
941 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]))
947 if (host_client->name[i+1] == STRING_COLOR_TAG)
954 // does not end in the default color string, so add it
955 if (j >= 0 && strlen(host_client->name) < sizeof(host_client->name) - 2)
956 memcpy(host_client->name + strlen(host_client->name), STRING_COLOR_DEFAULT_STR, strlen(STRING_COLOR_DEFAULT_STR) + 1);
958 SV_Name(host_client - svs.clients);
961 static void SV_Rate_f(cmd_state_t *cmd)
965 rate = atoi(Cmd_Argv(cmd, 1));
967 if (cmd->source == src_local)
970 host_client->rate = rate;
973 static void SV_Rate_BurstSize_f(cmd_state_t *cmd)
977 if (Cmd_Argc(cmd) != 2)
980 rate_burstsize = atoi(Cmd_Argv(cmd, 1));
982 host_client->rate_burstsize = rate_burstsize;
985 static void SV_Color_f(cmd_state_t *cmd)
987 prvm_prog_t *prog = SVVM_prog;
989 int top, bottom, playercolor;
991 top = atoi(Cmd_Argv(cmd, 1));
992 bottom = atoi(Cmd_Argv(cmd, 2));
997 playercolor = top*16 + bottom;
999 if (host_client->edict && PRVM_serverfunction(SV_ChangeTeam))
1001 Con_DPrint("Calling SV_ChangeTeam\n");
1002 prog->globals.fp[OFS_PARM0] = playercolor;
1003 PRVM_serverglobalfloat(time) = sv.time;
1004 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict);
1005 prog->ExecuteProgram(prog, PRVM_serverfunction(SV_ChangeTeam), "QC function SV_ChangeTeam is missing");
1009 if (host_client->edict)
1011 PRVM_serveredictfloat(host_client->edict, clientcolors) = playercolor;
1012 PRVM_serveredictfloat(host_client->edict, team) = bottom + 1;
1014 host_client->colors = playercolor;
1015 if (host_client->old_colors != host_client->colors)
1017 host_client->old_colors = host_client->colors;
1018 // send notification to all clients
1019 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1020 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1021 MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1030 Kicks a user off of the server
1033 static void SV_Kick_f(cmd_state_t *cmd)
1036 const char *message = NULL;
1039 qbool byNumber = false;
1046 if (Cmd_Argc(cmd) > 2 && strcmp(Cmd_Argv(cmd, 1), "#") == 0)
1048 i = (int)(atof(Cmd_Argv(cmd, 2)) - 1);
1049 if (i < 0 || i >= svs.maxclients || !(host_client = svs.clients + i)->active)
1055 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1057 if (!host_client->active)
1059 if (strcasecmp(host_client->name, Cmd_Argv(cmd, 1)) == 0)
1064 if (i < svs.maxclients)
1066 if (cmd->source == src_local)
1068 if(!host_isclient.integer)
1071 who = cl_name.string;
1076 // can't kick yourself!
1077 if (host_client == save)
1080 if (Cmd_Argc(cmd) > 2)
1082 message = Cmd_Args(cmd);
1083 COM_ParseToken_Simple(&message, false, false, true);
1086 message++; // skip the #
1087 while (*message == ' ') // skip white space
1089 message += strlen(Cmd_Argv(cmd, 2)); // skip the number
1091 while (*message && *message == ' ')
1095 SV_ClientPrintf("Kicked by %s: %s\n", who, message);
1097 SV_ClientPrintf("Kicked by %s\n", who);
1098 SV_DropClient (false); // kicked
1104 static void SV_MaxPlayers_f(cmd_state_t *cmd)
1108 if (Cmd_Argc(cmd) != 2)
1110 Con_Printf("\"maxplayers\" is \"%u\"\n", svs.maxclients_next);
1116 Con_Print("maxplayers can not be changed while a server is running.\n");
1117 Con_Print("It will be changed on next server startup (\"map\" command).\n");
1120 n = atoi(Cmd_Argv(cmd, 1));
1121 n = bound(1, n, MAX_SCOREBOARD);
1122 Con_Printf("\"maxplayers\" set to \"%u\"\n", n);
1124 svs.maxclients_next = n;
1126 Cvar_Set (&cvars_all, "deathmatch", "0");
1128 Cvar_Set (&cvars_all, "deathmatch", "1");
1132 ======================
1134 ======================
1136 // the old playermodel in cl_main has been renamed to __cl_playermodel
1137 static void SV_Playermodel_f(cmd_state_t *cmd)
1139 prvm_prog_t *prog = SVVM_prog;
1141 char newPath[sizeof(host_client->playermodel)];
1143 if (Cmd_Argc (cmd) == 1)
1146 if (Cmd_Argc (cmd) == 2)
1147 strlcpy (newPath, Cmd_Argv(cmd, 1), sizeof (newPath));
1149 strlcpy (newPath, Cmd_Args(cmd), sizeof (newPath));
1151 for (i = 0, j = 0;newPath[i];i++)
1152 if (newPath[i] != '\r' && newPath[i] != '\n')
1153 newPath[j++] = newPath[i];
1157 if (host.realtime < host_client->nametime)
1159 SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
1163 host_client->nametime = host.realtime + 5;
1166 // point the string back at updateclient->name to keep it safe
1167 strlcpy (host_client->playermodel, newPath, sizeof (host_client->playermodel));
1168 PRVM_serveredictstring(host_client->edict, playermodel) = PRVM_SetEngineString(prog, host_client->playermodel);
1169 if (strcmp(host_client->old_model, host_client->playermodel))
1171 strlcpy(host_client->old_model, host_client->playermodel, sizeof(host_client->old_model));
1172 /*// send notification to all clients
1173 MSG_WriteByte (&sv.reliable_datagram, svc_updatepmodel);
1174 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1175 MSG_WriteString (&sv.reliable_datagram, host_client->playermodel);*/
1180 ======================
1182 ======================
1184 static void SV_Playerskin_f(cmd_state_t *cmd)
1186 prvm_prog_t *prog = SVVM_prog;
1188 char newPath[sizeof(host_client->playerskin)];
1190 if (Cmd_Argc (cmd) == 1)
1193 if (Cmd_Argc (cmd) == 2)
1194 strlcpy (newPath, Cmd_Argv(cmd, 1), sizeof (newPath));
1196 strlcpy (newPath, Cmd_Args(cmd), sizeof (newPath));
1198 for (i = 0, j = 0;newPath[i];i++)
1199 if (newPath[i] != '\r' && newPath[i] != '\n')
1200 newPath[j++] = newPath[i];
1204 if (host.realtime < host_client->nametime)
1206 SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
1210 host_client->nametime = host.realtime + 5;
1213 // point the string back at updateclient->name to keep it safe
1214 strlcpy (host_client->playerskin, newPath, sizeof (host_client->playerskin));
1215 PRVM_serveredictstring(host_client->edict, playerskin) = PRVM_SetEngineString(prog, host_client->playerskin);
1216 if (strcmp(host_client->old_skin, host_client->playerskin))
1218 //if (host_client->begun)
1219 // SV_BroadcastPrintf("%s changed skin to %s\n", host_client->name, host_client->playerskin);
1220 strlcpy(host_client->old_skin, host_client->playerskin, sizeof(host_client->old_skin));
1221 /*// send notification to all clients
1222 MSG_WriteByte (&sv.reliable_datagram, svc_updatepskin);
1223 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1224 MSG_WriteString (&sv.reliable_datagram, host_client->playerskin);*/
1229 ======================
1231 LadyHavoc: only supported for Nehahra, I personally think this is dumb, but Mindcrime won't listen.
1232 LadyHavoc: correction, Mindcrime will be removing pmodel in the future, but it's still stuck here for compatibility.
1233 ======================
1235 static void SV_PModel_f(cmd_state_t *cmd)
1237 prvm_prog_t *prog = SVVM_prog;
1239 if (Cmd_Argc (cmd) == 1)
1242 PRVM_serveredictfloat(host_client->edict, pmodel) = atoi(Cmd_Argv(cmd, 1));
1246 ===============================================================================
1250 ===============================================================================
1253 static prvm_edict_t *FindViewthing(prvm_prog_t *prog)
1258 for (i=0 ; i<prog->num_edicts ; i++)
1260 e = PRVM_EDICT_NUM(i);
1261 if (!strcmp (PRVM_GetString(prog, PRVM_serveredictstring(e, classname)), "viewthing"))
1264 Con_Print("No viewthing on map\n");
1273 static void SV_Viewmodel_f(cmd_state_t *cmd)
1275 prvm_prog_t *prog = SVVM_prog;
1282 e = FindViewthing(prog);
1285 m = Mod_ForName (Cmd_Argv(cmd, 1), false, true, NULL);
1286 if (m && m->loaded && m->Draw)
1288 PRVM_serveredictfloat(e, frame) = 0;
1289 cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)] = m;
1292 Con_Printf("viewmodel: can't load %s\n", Cmd_Argv(cmd, 1));
1301 static void SV_Viewframe_f(cmd_state_t *cmd)
1303 prvm_prog_t *prog = SVVM_prog;
1311 e = FindViewthing(prog);
1314 m = cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)];
1316 f = atoi(Cmd_Argv(cmd, 1));
1317 if (f >= m->numframes)
1320 PRVM_serveredictfloat(e, frame) = f;
1324 static void PrintFrameName (model_t *m, int frame)
1327 Con_Printf("frame %i: %s\n", frame, m->animscenes[frame].name);
1329 Con_Printf("frame %i\n", frame);
1337 static void SV_Viewnext_f(cmd_state_t *cmd)
1339 prvm_prog_t *prog = SVVM_prog;
1346 e = FindViewthing(prog);
1349 m = cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)];
1351 PRVM_serveredictfloat(e, frame) = PRVM_serveredictfloat(e, frame) + 1;
1352 if (PRVM_serveredictfloat(e, frame) >= m->numframes)
1353 PRVM_serveredictfloat(e, frame) = m->numframes - 1;
1355 PrintFrameName (m, (int)PRVM_serveredictfloat(e, frame));
1364 static void SV_Viewprev_f(cmd_state_t *cmd)
1366 prvm_prog_t *prog = SVVM_prog;
1373 e = FindViewthing(prog);
1376 m = cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)];
1378 PRVM_serveredictfloat(e, frame) = PRVM_serveredictfloat(e, frame) - 1;
1379 if (PRVM_serveredictfloat(e, frame) < 0)
1380 PRVM_serveredictfloat(e, frame) = 0;
1382 PrintFrameName (m, (int)PRVM_serveredictfloat(e, frame));
1386 static void SV_SendCvar_f(cmd_state_t *cmd)
1389 const char *cvarname;
1392 if(Cmd_Argc(cmd) != 2)
1395 if(!sv.active)// || !PRVM_serverfunction(SV_ParseClientCommand))
1398 cvarname = Cmd_Argv(cmd, 1);
1401 if(host_isclient.integer)
1405 for(;i<svs.maxclients;i++)
1406 if(svs.clients[i].active && svs.clients[i].netconnection)
1408 host_client = &svs.clients[i];
1409 SV_ClientCommands("sendcvar %s\n", cvarname);
1414 static void SV_Ent_Create_f(cmd_state_t *cmd)
1416 prvm_prog_t *prog = SVVM_prog;
1422 void (*print)(const char *, ...) = (cmd->source == src_client ? SV_ClientPrintf : Con_Printf);
1427 ed = PRVM_ED_Alloc(SVVM_prog);
1429 PRVM_ED_ParseEpair(prog, ed, PRVM_ED_FindField(prog, "classname"), Cmd_Argv(cmd, 1), false);
1431 // Spawn where the player is aiming. We need a view matrix first.
1432 if(cmd->source == src_client)
1434 vec3_t org, temp, dest;
1439 SV_GetEntityMatrix(prog, host_client->edict, &view, true);
1441 Matrix4x4_OriginFromMatrix(&view, org);
1442 VectorSet(temp, 65536, 0, 0);
1443 Matrix4x4_Transform(&view, temp, dest);
1445 trace = SV_TraceLine(org, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, 0, 0, collision_extendmovelength.value);
1447 dpsnprintf(buf, sizeof(buf), "%g %g %g", trace.endpos[0], trace.endpos[1], trace.endpos[2]);
1448 PRVM_ED_ParseEpair(prog, ed, PRVM_ED_FindField(prog, "origin"), buf, false);
1452 // Or spawn at a specified origin.
1459 // Allow more than one key/value pair by cycling between expecting either one.
1460 for(i = 2; i < Cmd_Argc(cmd); i += 2)
1462 if(!(key = PRVM_ED_FindField(prog, Cmd_Argv(cmd, i))))
1464 print("Key %s not found!\n", Cmd_Argv(cmd, i));
1465 PRVM_ED_Free(prog, ed);
1470 * This is mostly for dedicated server console, but if the
1471 * player gave a custom origin, we can ignore the traceline.
1473 if(!strcmp(Cmd_Argv(cmd, i), "origin"))
1476 if (i + 1 < Cmd_Argc(cmd))
1477 PRVM_ED_ParseEpair(prog, ed, key, Cmd_Argv(cmd, i+1), false);
1482 print("Missing origin\n");
1483 PRVM_ED_Free(prog, ed);
1488 PRVM_ED_CallPrespawnFunction(prog, ed);
1490 if(!PRVM_ED_CallSpawnFunction(prog, ed, NULL, NULL))
1492 print("Could not spawn a \"%s\". No such entity or it has no spawn function\n", Cmd_Argv(cmd, 1));
1493 if(cmd->source == src_client)
1494 Con_Printf("%s tried to spawn a \"%s\"\n", host_client->name, Cmd_Argv(cmd, 1));
1495 // CallSpawnFunction already freed the edict for us.
1499 PRVM_ED_CallPostspawnFunction(prog, ed);
1501 // Make it appear in the world
1504 if(cmd->source == src_client)
1505 Con_Printf("%s spawned a \"%s\"\n", host_client->name, Cmd_Argv(cmd, 1));
1508 static void SV_Ent_Remove_f(cmd_state_t *cmd)
1510 prvm_prog_t *prog = SVVM_prog;
1513 void (*print)(const char *, ...) = (cmd->source == src_client ? SV_ClientPrintf : Con_Printf);
1518 // Allow specifying edict by number
1519 if(Cmd_Argc(cmd) > 1 && Cmd_Argv(cmd, 1))
1521 ednum = atoi(Cmd_Argv(cmd, 1));
1524 print("Cannot remove the world\n");
1528 // Or trace a line if it's a client who didn't specify one.
1529 else if(cmd->source == src_client)
1531 vec3_t org, temp, dest;
1535 SV_GetEntityMatrix(prog, host_client->edict, &view, true);
1537 Matrix4x4_OriginFromMatrix(&view, org);
1538 VectorSet(temp, 65536, 0, 0);
1539 Matrix4x4_Transform(&view, temp, dest);
1541 trace = SV_TraceLine(org, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY, 0, 0, collision_extendmovelength.value);
1544 ednum = (int)PRVM_EDICT_TO_PROG(trace.ent);
1545 if(!trace.ent || !ednum)
1546 // Don't remove the world, but don't annoy players with a print if they miss
1551 // Only a dedicated server console should be able to reach this.
1552 print("No edict given\n");
1556 ed = PRVM_EDICT_NUM(ednum);
1561 for (i = 0; i < svs.maxclients; i++)
1563 if(ed == svs.clients[i].edict)
1567 if(!ed->priv.required->free)
1569 print("Removed a \"%s\"\n", PRVM_GetString(prog, PRVM_serveredictstring(ed, classname)));
1570 PRVM_ED_ClearEdict(prog, ed);
1571 PRVM_ED_Free(prog, ed);
1576 // This should only be reachable if an invalid edict number was given
1577 print("No such entity\n");
1582 static void SV_Ent_Remove_All_f(cmd_state_t *cmd)
1584 prvm_prog_t *prog = SVVM_prog;
1587 void (*print)(const char *, ...) = (cmd->source == src_client ? SV_ClientPrintf : Con_Printf);
1589 for (i = 0, rmcount = 0, ed = PRVM_EDICT_NUM(i); i < prog->num_edicts; i++, ed = PRVM_NEXT_EDICT(ed))
1591 if(!ed->priv.required->free && !strcmp(PRVM_GetString(prog, PRVM_serveredictstring(ed, classname)), Cmd_Argv(cmd, 1)))
1595 print("Cannot remove the world\n");
1598 PRVM_ED_ClearEdict(prog, ed);
1599 PRVM_ED_Free(prog, ed);
1605 print("No \"%s\" found\n", Cmd_Argv(cmd, 1));
1607 print("Removed %i of \"%s\"\n", rmcount, Cmd_Argv(cmd, 1));
1610 void SV_InitOperatorCommands(void)
1612 Cvar_RegisterVariable(&sv_cheats);
1613 Cvar_RegisterCallback(&sv_cheats, SV_DisableCheats_c);
1614 Cvar_RegisterVariable(&sv_adminnick);
1615 Cvar_RegisterVariable(&sv_status_privacy);
1616 Cvar_RegisterVariable(&sv_status_show_qcstatus);
1617 Cvar_RegisterVariable(&sv_namechangetimer);
1619 Cmd_AddCommand(CF_SERVER | CF_SERVER_FROM_CLIENT, "status", SV_Status_f, "print server status information");
1620 Cmd_AddCommand(CF_SHARED, "map", SV_Map_f, "kick everyone off the server and start a new level");
1621 Cmd_AddCommand(CF_SHARED, "restart", SV_Restart_f, "restart current level");
1622 Cmd_AddCommand(CF_SHARED, "changelevel", SV_Changelevel_f, "change to another level, bringing along all connected clients");
1623 Cmd_AddCommand(CF_SHARED | CF_SERVER_FROM_CLIENT, "say", SV_Say_f, "send a chat message to everyone on the server");
1624 Cmd_AddCommand(CF_SERVER_FROM_CLIENT, "say_team", SV_Say_Team_f, "send a chat message to your team on the server");
1625 Cmd_AddCommand(CF_SHARED | CF_SERVER_FROM_CLIENT, "tell", SV_Tell_f, "send a chat message to only one person on the server");
1626 Cmd_AddCommand(CF_SERVER | CF_SERVER_FROM_CLIENT, "pause", SV_Pause_f, "pause the game (if the server allows pausing)");
1627 Cmd_AddCommand(CF_SHARED, "kick", SV_Kick_f, "kick a player off the server by number or name");
1628 Cmd_AddCommand(CF_SHARED | CF_SERVER_FROM_CLIENT, "ping", SV_Ping_f, "print ping times of all players on the server");
1629 Cmd_AddCommand(CF_SHARED, "load", SV_Loadgame_f, "load a saved game file");
1630 Cmd_AddCommand(CF_SHARED, "save", SV_Savegame_f, "save the game to a file");
1631 Cmd_AddCommand(CF_SHARED, "viewmodel", SV_Viewmodel_f, "change model of viewthing entity in current level");
1632 Cmd_AddCommand(CF_SHARED, "viewframe", SV_Viewframe_f, "change animation frame of viewthing entity in current level");
1633 Cmd_AddCommand(CF_SHARED, "viewnext", SV_Viewnext_f, "change to next animation frame of viewthing entity in current level");
1634 Cmd_AddCommand(CF_SHARED, "viewprev", SV_Viewprev_f, "change to previous animation frame of viewthing entity in current level");
1635 Cmd_AddCommand(CF_SHARED, "maxplayers", SV_MaxPlayers_f, "sets limit on how many players (or bots) may be connected to the server at once");
1636 host.hook.SV_SendCvar = SV_SendCvar_f;
1638 // 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)
1639 Cmd_AddCommand(CF_SERVER_FROM_CLIENT, "prespawn", SV_PreSpawn_f, "internal use - signon 1 (client acknowledges that server information has been received)");
1640 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)");
1641 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)");
1642 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)");
1644 Cmd_AddCommand(CF_CHEAT | CF_SERVER_FROM_CLIENT, "god", SV_God_f, "god mode (invulnerability)");
1645 Cmd_AddCommand(CF_CHEAT | CF_SERVER_FROM_CLIENT, "notarget", SV_Notarget_f, "notarget mode (monsters do not see you)");
1646 Cmd_AddCommand(CF_CHEAT | CF_SERVER_FROM_CLIENT, "fly", SV_Fly_f, "fly mode (flight)");
1647 Cmd_AddCommand(CF_CHEAT | CF_SERVER_FROM_CLIENT, "noclip", SV_Noclip_f, "noclip mode (flight without collisions, move through walls)");
1648 Cmd_AddCommand(CF_CHEAT | CF_SERVER_FROM_CLIENT, "give", SV_Give_f, "alter inventory");
1649 Cmd_AddCommand(CF_SERVER_FROM_CLIENT, "kill", SV_Kill_f, "die instantly");
1651 Cmd_AddCommand(CF_USERINFO, "color", SV_Color_f, "change your player shirt and pants colors");
1652 Cmd_AddCommand(CF_USERINFO, "name", SV_Name_f, "change your player name");
1653 Cmd_AddCommand(CF_USERINFO, "rate", SV_Rate_f, "change your network connection speed");
1654 Cmd_AddCommand(CF_USERINFO, "rate_burstsize", SV_Rate_BurstSize_f, "change your network connection speed");
1655 Cmd_AddCommand(CF_USERINFO, "pmodel", SV_PModel_f, "(Nehahra-only) change your player model choice");
1656 Cmd_AddCommand(CF_USERINFO, "playermodel", SV_Playermodel_f, "change your player model");
1657 Cmd_AddCommand(CF_USERINFO, "playerskin", SV_Playerskin_f, "change your player skin number");
1659 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.");
1660 Cmd_AddCommand(CF_CHEAT | CF_SERVER_FROM_CLIENT, "ent_remove_all", SV_Ent_Remove_All_f, "Removes all entities of the specified classname");
1661 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");