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 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 if(host.hook.ToggleMenu)
145 host.hook.ToggleMenu();
147 strlcpy(mapname, sv.name, 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;
164 while (svs.clients[i].edict)
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;
185 Sets client to godmode
188 static void SV_God_f(cmd_state_t *cmd)
190 prvm_prog_t *prog = SVVM_prog;
192 PRVM_serveredictfloat(host_client->edict, flags) = (int)PRVM_serveredictfloat(host_client->edict, flags) ^ FL_GODMODE;
193 if (!((int)PRVM_serveredictfloat(host_client->edict, flags) & FL_GODMODE) )
194 SV_ClientPrint("godmode OFF\n");
196 SV_ClientPrint("godmode ON\n");
199 qbool noclip_anglehack;
201 static void SV_Noclip_f(cmd_state_t *cmd)
203 prvm_prog_t *prog = SVVM_prog;
205 if (PRVM_serveredictfloat(host_client->edict, movetype) != MOVETYPE_NOCLIP)
207 noclip_anglehack = true;
208 PRVM_serveredictfloat(host_client->edict, movetype) = MOVETYPE_NOCLIP;
209 SV_ClientPrint("noclip ON\n");
213 noclip_anglehack = false;
214 PRVM_serveredictfloat(host_client->edict, movetype) = MOVETYPE_WALK;
215 SV_ClientPrint("noclip OFF\n");
224 static void SV_Give_f(cmd_state_t *cmd)
226 prvm_prog_t *prog = SVVM_prog;
230 t = Cmd_Argv(cmd, 1);
231 v = atoi (Cmd_Argv(cmd, 2));
245 // MED 01/04/97 added hipnotic give stuff
246 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_QUOTH)
251 PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | HIT_PROXIMITY_GUN;
253 PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | IT_GRENADE_LAUNCHER;
255 else if (t[0] == '9')
256 PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | HIT_LASER_CANNON;
257 else if (t[0] == '0')
258 PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | HIT_MJOLNIR;
259 else if (t[0] >= '2')
260 PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | (IT_SHOTGUN << (t[0] - '2'));
265 PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | (IT_SHOTGUN << (t[0] - '2'));
270 if (gamemode == GAME_ROGUE)
271 PRVM_serveredictfloat(host_client->edict, ammo_shells1) = v;
273 PRVM_serveredictfloat(host_client->edict, ammo_shells) = v;
276 if (gamemode == GAME_ROGUE)
278 PRVM_serveredictfloat(host_client->edict, ammo_nails1) = v;
279 if (PRVM_serveredictfloat(host_client->edict, weapon) <= IT_LIGHTNING)
280 PRVM_serveredictfloat(host_client->edict, ammo_nails) = v;
284 PRVM_serveredictfloat(host_client->edict, ammo_nails) = v;
288 if (gamemode == GAME_ROGUE)
290 PRVM_serveredictfloat(host_client->edict, ammo_lava_nails) = v;
291 if (PRVM_serveredictfloat(host_client->edict, weapon) > IT_LIGHTNING)
292 PRVM_serveredictfloat(host_client->edict, ammo_nails) = v;
296 if (gamemode == GAME_ROGUE)
298 PRVM_serveredictfloat(host_client->edict, ammo_rockets1) = v;
299 if (PRVM_serveredictfloat(host_client->edict, weapon) <= IT_LIGHTNING)
300 PRVM_serveredictfloat(host_client->edict, ammo_rockets) = v;
304 PRVM_serveredictfloat(host_client->edict, ammo_rockets) = v;
308 if (gamemode == GAME_ROGUE)
310 PRVM_serveredictfloat(host_client->edict, ammo_multi_rockets) = v;
311 if (PRVM_serveredictfloat(host_client->edict, weapon) > IT_LIGHTNING)
312 PRVM_serveredictfloat(host_client->edict, ammo_rockets) = v;
316 PRVM_serveredictfloat(host_client->edict, health) = v;
319 if (gamemode == GAME_ROGUE)
321 PRVM_serveredictfloat(host_client->edict, ammo_cells1) = v;
322 if (PRVM_serveredictfloat(host_client->edict, weapon) <= IT_LIGHTNING)
323 PRVM_serveredictfloat(host_client->edict, ammo_cells) = v;
327 PRVM_serveredictfloat(host_client->edict, ammo_cells) = v;
331 if (gamemode == GAME_ROGUE)
333 PRVM_serveredictfloat(host_client->edict, ammo_plasma) = v;
334 if (PRVM_serveredictfloat(host_client->edict, weapon) > IT_LIGHTNING)
335 PRVM_serveredictfloat(host_client->edict, ammo_cells) = v;
345 Sets client to flymode
348 static void SV_Fly_f(cmd_state_t *cmd)
350 prvm_prog_t *prog = SVVM_prog;
352 if (PRVM_serveredictfloat(host_client->edict, movetype) != MOVETYPE_FLY)
354 PRVM_serveredictfloat(host_client->edict, movetype) = MOVETYPE_FLY;
355 SV_ClientPrint("flymode ON\n");
359 PRVM_serveredictfloat(host_client->edict, movetype) = MOVETYPE_WALK;
360 SV_ClientPrint("flymode OFF\n");
364 static void SV_Notarget_f(cmd_state_t *cmd)
366 prvm_prog_t *prog = SVVM_prog;
368 PRVM_serveredictfloat(host_client->edict, flags) = (int)PRVM_serveredictfloat(host_client->edict, flags) ^ FL_NOTARGET;
369 if (!((int)PRVM_serveredictfloat(host_client->edict, flags) & FL_NOTARGET) )
370 SV_ClientPrint("notarget OFF\n");
372 SV_ClientPrint("notarget ON\n");
380 static void SV_Kill_f(cmd_state_t *cmd)
382 prvm_prog_t *prog = SVVM_prog;
383 if (PRVM_serveredictfloat(host_client->edict, health) <= 0)
385 SV_ClientPrint("Can't suicide -- already dead!\n");
389 PRVM_serverglobalfloat(time) = sv.time;
390 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict);
391 prog->ExecuteProgram(prog, PRVM_serverfunction(ClientKill), "QC function ClientKill is missing");
399 static void SV_Pause_f(cmd_state_t *cmd)
401 void (*print) (const char *fmt, ...);
402 if (cmd->source == src_local)
405 print = SV_ClientPrintf;
407 if (!pausable.integer && cmd->source == src_client && LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) != LHNETADDRESSTYPE_LOOP)
409 print("Pause not allowed.\n");
414 if (cmd->source != src_local)
415 SV_BroadcastPrintf("%s %spaused the game\n", host_client->name, sv.paused ? "" : "un");
416 else if(*(sv_adminnick.string))
417 SV_BroadcastPrintf("%s %spaused the game\n", sv_adminnick.string, sv.paused ? "" : "un");
419 SV_BroadcastPrintf("%s %spaused the game\n", hostname.string, sv.paused ? "" : "un");
420 // send notification to all clients
421 MSG_WriteByte(&sv.reliable_datagram, svc_setpause);
422 MSG_WriteByte(&sv.reliable_datagram, sv.paused);
425 static void SV_Say(cmd_state_t *cmd, qbool teamonly)
427 prvm_prog_t *prog = SVVM_prog;
432 // LadyHavoc: long say messages
434 qbool fromServer = false;
436 if (cmd->source == src_local)
442 if (Cmd_Argc (cmd) < 2)
445 if (!teamplay.integer)
455 // note this uses the chat prefix \001
456 if (!fromServer && !teamonly)
457 dpsnprintf (text, sizeof(text), "\001%s: %s", host_client->name, p1);
458 else if (!fromServer && teamonly)
459 dpsnprintf (text, sizeof(text), "\001(%s): %s", host_client->name, p1);
460 else if(*(sv_adminnick.string))
461 dpsnprintf (text, sizeof(text), "\001<%s> %s", sv_adminnick.string, p1);
463 dpsnprintf (text, sizeof(text), "\001<%s> %s", hostname.string, p1);
464 p2 = text + strlen(text);
465 while ((const char *)p2 > (const char *)text && (p2[-1] == '\r' || p2[-1] == '\n' || (p2[-1] == '\"' && quoted)))
467 if (p2[-1] == '\"' && quoted)
472 strlcat(text, "\n", sizeof(text));
474 // note: save is not a valid edict if fromServer is true
476 for (j = 0, host_client = svs.clients;j < svs.maxclients;j++, host_client++)
477 if (host_client->active && (!teamonly || PRVM_serveredictfloat(host_client->edict, team) == PRVM_serveredictfloat(save->edict, team)))
478 SV_ClientPrint(text);
481 if(!host_isclient.integer)
485 static void SV_Say_f(cmd_state_t *cmd)
490 static void SV_Say_Team_f(cmd_state_t *cmd)
495 static void SV_Tell_f(cmd_state_t *cmd)
497 const char *playername_start = NULL;
498 size_t playername_length = 0;
499 int playernumber = 0;
503 char text[MAX_INPUTLINE]; // LadyHavoc: FIXME: temporary buffer overflow fix (was 64)
504 qbool fromServer = false;
506 if (cmd->source == src_local)
509 if (Cmd_Argc (cmd) < 2)
512 // note this uses the chat prefix \001
514 dpsnprintf (text, sizeof(text), "\001%s tells you: ", host_client->name);
515 else if(*(sv_adminnick.string))
516 dpsnprintf (text, sizeof(text), "\001<%s tells you> ", sv_adminnick.string);
518 dpsnprintf (text, sizeof(text), "\001<%s tells you> ", hostname.string);
521 p2 = p1 + strlen(p1);
522 // remove the target name
523 while (p1 < p2 && *p1 == ' ')
528 while (p1 < p2 && *p1 == ' ')
530 while (p1 < p2 && isdigit(*p1))
532 playernumber = playernumber * 10 + (*p1 - '0');
540 playername_start = p1;
541 while (p1 < p2 && *p1 != '"')
543 playername_length = p1 - playername_start;
549 playername_start = p1;
550 while (p1 < p2 && *p1 != ' ')
552 playername_length = p1 - playername_start;
554 while (p1 < p2 && *p1 == ' ')
558 // set playernumber to the right client
560 if(playername_length >= sizeof(namebuf))
563 Con_Print("Host_Tell: too long player name/ID\n");
565 SV_ClientPrint("Host_Tell: too long player name/ID\n");
568 memcpy(namebuf, playername_start, playername_length);
569 namebuf[playername_length] = 0;
570 for (playernumber = 0; playernumber < svs.maxclients; playernumber++)
572 if (!svs.clients[playernumber].active)
574 if (strcasecmp(svs.clients[playernumber].name, namebuf) == 0)
578 if(playernumber < 0 || playernumber >= svs.maxclients || !(svs.clients[playernumber].active))
581 Con_Print("Host_Tell: invalid player name/ID\n");
583 SV_ClientPrint("Host_Tell: invalid player name/ID\n");
586 // remove trailing newlines
587 while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
589 // remove quotes if present
596 Con_Print("Host_Tell: missing end quote\n");
598 SV_ClientPrint("Host_Tell: missing end quote\n");
600 while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
604 for (j = (int)strlen(text);j < (int)(sizeof(text) - 2) && p1 < p2;)
610 host_client = svs.clients + playernumber;
611 SV_ClientPrint(text);
621 static void SV_Ping_f(cmd_state_t *cmd)
625 void (*print) (const char *fmt, ...);
627 if (cmd->source == src_local)
630 print = SV_ClientPrintf;
635 print("Client ping times:\n");
636 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
640 print("%4i %s\n", bound(0, (int)floor(client->ping*1000+0.5), 9999), client->name);
648 Send back ping and packet loss update for all current players to this player
651 static void SV_Pings_f(cmd_state_t *cmd)
653 int i, j, ping, packetloss, movementloss;
656 if (!host_client->netconnection)
659 if (sv.protocol != PROTOCOL_QUAKEWORLD)
661 MSG_WriteByte(&host_client->netconnection->message, svc_stufftext);
662 MSG_WriteUnterminatedString(&host_client->netconnection->message, "pingplreport");
664 for (i = 0;i < svs.maxclients;i++)
668 if (svs.clients[i].netconnection)
670 for (j = 0;j < NETGRAPH_PACKETS;j++)
671 if (svs.clients[i].netconnection->incoming_netgraph[j].unreliablebytes == NETGRAPH_LOSTPACKET)
673 for (j = 0;j < NETGRAPH_PACKETS;j++)
674 if (svs.clients[i].movement_count[j] < 0)
677 packetloss = (packetloss * 100 + NETGRAPH_PACKETS - 1) / NETGRAPH_PACKETS;
678 movementloss = (movementloss * 100 + NETGRAPH_PACKETS - 1) / NETGRAPH_PACKETS;
679 ping = (int)floor(svs.clients[i].ping*1000+0.5);
680 ping = bound(0, ping, 9999);
681 if (sv.protocol == PROTOCOL_QUAKEWORLD)
683 // send qw_svc_updateping and qw_svc_updatepl messages
684 MSG_WriteByte(&host_client->netconnection->message, qw_svc_updateping);
685 MSG_WriteShort(&host_client->netconnection->message, ping);
686 MSG_WriteByte(&host_client->netconnection->message, qw_svc_updatepl);
687 MSG_WriteByte(&host_client->netconnection->message, packetloss);
691 // write the string into the packet as multiple unterminated strings to avoid needing a local buffer
693 dpsnprintf(temp, sizeof(temp), " %d %d,%d", ping, packetloss, movementloss);
695 dpsnprintf(temp, sizeof(temp), " %d %d", ping, packetloss);
696 MSG_WriteUnterminatedString(&host_client->netconnection->message, temp);
699 if (sv.protocol != PROTOCOL_QUAKEWORLD)
700 MSG_WriteString(&host_client->netconnection->message, "\n");
708 static void SV_Status_f(cmd_state_t *cmd)
710 prvm_prog_t *prog = SVVM_prog;
713 int seconds = 0, minutes = 0, hours = 0, i, j, k, in, players, ping = 0, packetloss = 0;
714 void (*print) (const char *fmt, ...);
715 char ip[48]; // can contain a full length v6 address with [] and a port
719 if (cmd->source == src_local)
722 print = SV_ClientPrintf;
728 if (Cmd_Argc(cmd) == 2)
730 if (strcmp(Cmd_Argv(cmd, 1), "1") == 0)
732 else if (strcmp(Cmd_Argv(cmd, 1), "2") == 0)
736 for (players = 0, i = 0;i < svs.maxclients;i++)
737 if (svs.clients[i].active)
740 print ("host: %s\n", Cvar_VariableString (&cvars_all, "hostname", CF_SERVER));
741 print ("version: %s\n", engineversion);
742 print ("protocol: %i (%s)\n", Protocol_NumberForEnum(sv.protocol), Protocol_NameForEnum(sv.protocol));
743 print ("map: %s\n", sv.name);
744 print ("timing: %s\n", SV_TimingReport(vabuf, sizeof(vabuf)));
745 print ("players: %i active (%i max)\n\n", players, svs.maxclients);
748 print ("^2IP %%pl ping time frags no name\n");
750 print ("^5IP no name\n");
752 for (i = 0, k = 0, client = svs.clients;i < svs.maxclients;i++, client++)
759 if (in == 0 || in == 1)
761 seconds = (int)(host.realtime - client->connecttime);
762 minutes = seconds / 60;
765 seconds -= (minutes * 60);
766 hours = minutes / 60;
768 minutes -= (hours * 60);
774 if (client->netconnection)
775 for (j = 0;j < NETGRAPH_PACKETS;j++)
776 if (client->netconnection->incoming_netgraph[j].unreliablebytes == NETGRAPH_LOSTPACKET)
778 packetloss = (packetloss * 100 + NETGRAPH_PACKETS - 1) / NETGRAPH_PACKETS;
779 ping = bound(0, (int)floor(client->ping*1000+0.5), 9999);
782 if(sv_status_privacy.integer && cmd->source != src_local && LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) != LHNETADDRESSTYPE_LOOP)
783 strlcpy(ip, client->netconnection ? "hidden" : "botclient", 48);
785 strlcpy(ip, (client->netconnection && *client->netconnection->address) ? client->netconnection->address : "botclient", 48);
787 frags = client->frags;
789 if(sv_status_show_qcstatus.integer)
791 prvm_edict_t *ed = PRVM_EDICT_NUM(i + 1);
792 const char *str = PRVM_GetString(prog, PRVM_serveredictstring(ed, clientstatus));
798 for(q = str; *q && p != qcstatus + sizeof(qcstatus) - 1; ++q)
799 if(*q != '\\' && *q != '"' && !ISWHITESPACE(*q))
803 frags = atoi(qcstatus);
807 if (in == 0) // default layout
809 if (sv.protocol == PROTOCOL_QUAKE && svs.maxclients <= 99)
811 // LadyHavoc: this is very touchy because we must maintain ProQuake compatible status output
812 print ("#%-2u %-16.16s %3i %2i:%02i:%02i\n", i+1, client->name, frags, hours, minutes, seconds);
817 // LadyHavoc: no real restrictions here, not a ProQuake-compatible protocol anyway...
818 print ("#%-3u %-16.16s %4i %2i:%02i:%02i\n", i+1, client->name, frags, hours, minutes, seconds);
822 else if (in == 1) // extended layout
824 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);
826 else if (in == 2) // reduced layout
828 print ("%s%-47s #%-3u ^7%s\n", k%2 ? "^3" : "^7", ip, i+1, client->name);
833 void SV_Name(int clientnum)
835 prvm_prog_t *prog = SVVM_prog;
836 PRVM_serveredictstring(host_client->edict, netname) = PRVM_SetEngineString(prog, host_client->name);
837 if (strcmp(host_client->old_name, host_client->name))
839 if (host_client->begun)
840 SV_BroadcastPrintf("\003%s ^7changed name to ^3%s\n", host_client->old_name, host_client->name);
841 strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
842 // send notification to all clients
843 MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
844 MSG_WriteByte (&sv.reliable_datagram, clientnum);
845 MSG_WriteString (&sv.reliable_datagram, host_client->name);
846 SV_WriteNetnameIntoDemo(host_client);
851 ======================
853 ======================
855 static void SV_Name_f(cmd_state_t *cmd)
859 const char *newNameSource;
860 char newName[sizeof(host_client->name)];
862 if (Cmd_Argc (cmd) == 1)
865 if (Cmd_Argc (cmd) == 2)
866 newNameSource = Cmd_Argv(cmd, 1);
868 newNameSource = Cmd_Args(cmd);
870 strlcpy(newName, newNameSource, sizeof(newName));
872 if (cmd->source == src_local)
875 if (host.realtime < host_client->nametime && strcmp(newName, host_client->name))
877 SV_ClientPrintf("You can't change name more than once every %.1f seconds!\n", max(0.0f, sv_namechangetimer.value));
881 host_client->nametime = host.realtime + max(0.0f, sv_namechangetimer.value);
883 // point the string back at updateclient->name to keep it safe
884 strlcpy (host_client->name, newName, sizeof (host_client->name));
886 for (i = 0, j = 0;host_client->name[i];i++)
887 if (host_client->name[i] != '\r' && host_client->name[i] != '\n')
888 host_client->name[j++] = host_client->name[i];
889 host_client->name[j] = 0;
891 if(host_client->name[0] == 1 || host_client->name[0] == 2)
892 // may interfere with chat area, and will needlessly beep; so let's add a ^7
894 memmove(host_client->name + 2, host_client->name, sizeof(host_client->name) - 2);
895 host_client->name[sizeof(host_client->name) - 1] = 0;
896 host_client->name[0] = STRING_COLOR_TAG;
897 host_client->name[1] = '0' + STRING_COLOR_DEFAULT;
900 u8_COM_StringLengthNoColors(host_client->name, 0, &valid_colors);
901 if(!valid_colors) // NOTE: this also proves the string is not empty, as "" is a valid colored string
904 l = strlen(host_client->name);
905 if(l < sizeof(host_client->name) - 1)
907 // duplicate the color tag to escape it
908 host_client->name[i] = STRING_COLOR_TAG;
909 host_client->name[i+1] = 0;
910 //Con_DPrintf("abuse detected, adding another trailing color tag\n");
914 // remove the last character to fix the color code
915 host_client->name[l-1] = 0;
916 //Con_DPrintf("abuse detected, removing a trailing color tag\n");
920 // find the last color tag offset and decide if we need to add a reset tag
921 for (i = 0, j = -1;host_client->name[i];i++)
923 if (host_client->name[i] == STRING_COLOR_TAG)
925 if (host_client->name[i+1] >= '0' && host_client->name[i+1] <= '9')
928 // if this happens to be a reset tag then we don't need one
929 if (host_client->name[i+1] == '0' + STRING_COLOR_DEFAULT)
934 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]))
940 if (host_client->name[i+1] == STRING_COLOR_TAG)
947 // does not end in the default color string, so add it
948 if (j >= 0 && strlen(host_client->name) < sizeof(host_client->name) - 2)
949 memcpy(host_client->name + strlen(host_client->name), STRING_COLOR_DEFAULT_STR, strlen(STRING_COLOR_DEFAULT_STR) + 1);
951 SV_Name(host_client - svs.clients);
954 static void SV_Rate_f(cmd_state_t *cmd)
958 rate = atoi(Cmd_Argv(cmd, 1));
960 if (cmd->source == src_local)
963 host_client->rate = rate;
966 static void SV_Rate_BurstSize_f(cmd_state_t *cmd)
970 if (Cmd_Argc(cmd) != 2)
973 rate_burstsize = atoi(Cmd_Argv(cmd, 1));
975 host_client->rate_burstsize = rate_burstsize;
978 static void SV_Color_f(cmd_state_t *cmd)
980 prvm_prog_t *prog = SVVM_prog;
982 int top, bottom, playercolor;
984 top = atoi(Cmd_Argv(cmd, 1));
985 bottom = atoi(Cmd_Argv(cmd, 2));
990 playercolor = top*16 + bottom;
992 if (host_client->edict && PRVM_serverfunction(SV_ChangeTeam))
994 Con_DPrint("Calling SV_ChangeTeam\n");
995 prog->globals.fp[OFS_PARM0] = playercolor;
996 PRVM_serverglobalfloat(time) = sv.time;
997 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict);
998 prog->ExecuteProgram(prog, PRVM_serverfunction(SV_ChangeTeam), "QC function SV_ChangeTeam is missing");
1002 if (host_client->edict)
1004 PRVM_serveredictfloat(host_client->edict, clientcolors) = playercolor;
1005 PRVM_serveredictfloat(host_client->edict, team) = bottom + 1;
1007 host_client->colors = playercolor;
1008 if (host_client->old_colors != host_client->colors)
1010 host_client->old_colors = host_client->colors;
1011 // send notification to all clients
1012 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1013 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1014 MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1023 Kicks a user off of the server
1026 static void SV_Kick_f(cmd_state_t *cmd)
1029 const char *message = NULL;
1033 qbool byNumber = false;
1040 if (Cmd_Argc(cmd) > 2 && strcmp(Cmd_Argv(cmd, 1), "#") == 0)
1042 i = (int)(atof(Cmd_Argv(cmd, 2)) - 1);
1043 if (i < 0 || i >= svs.maxclients || !(host_client = svs.clients + i)->active)
1049 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1051 if (!host_client->active)
1053 if (strcasecmp(host_client->name, Cmd_Argv(cmd, 1)) == 0)
1058 if (i < svs.maxclients)
1060 if (cmd->source == src_local)
1062 if(!host_isclient.integer)
1065 who = cl_name.string;
1070 // can't kick yourself!
1071 if (host_client == save)
1074 if (Cmd_Argc(cmd) > 2)
1076 message = Cmd_Args(cmd);
1077 COM_ParseToken_Simple(&message, false, false, true);
1080 message++; // skip the #
1081 while (*message == ' ') // skip white space
1083 message += strlen(Cmd_Argv(cmd, 2)); // skip the number
1085 while (*message && *message == ' ')
1089 SV_DropClient (false, va(reason, sizeof(reason), "Kicked by %s: %s", who, message)); // kicked
1090 //SV_ClientPrintf("Kicked by %s: %s\n", who, message);
1092 //SV_ClientPrintf("Kicked by %s\n", who);
1093 SV_DropClient (false, va(reason, sizeof(reason), "Kicked by %s", who)); // kicked
1099 static void SV_MaxPlayers_f(cmd_state_t *cmd)
1103 if (Cmd_Argc(cmd) != 2)
1105 Con_Printf("\"maxplayers\" is \"%u\"\n", svs.maxclients_next);
1111 Con_Print("maxplayers can not be changed while a server is running.\n");
1112 Con_Print("It will be changed on next server startup (\"map\" command).\n");
1115 n = atoi(Cmd_Argv(cmd, 1));
1116 n = bound(1, n, MAX_SCOREBOARD);
1117 Con_Printf("\"maxplayers\" set to \"%u\"\n", n);
1119 svs.maxclients_next = n;
1121 Cvar_Set (&cvars_all, "deathmatch", "0");
1123 Cvar_Set (&cvars_all, "deathmatch", "1");
1127 ======================
1129 ======================
1131 // the old playermodel in cl_main has been renamed to __cl_playermodel
1132 static void SV_Playermodel_f(cmd_state_t *cmd)
1134 prvm_prog_t *prog = SVVM_prog;
1136 char newPath[sizeof(host_client->playermodel)];
1138 if (Cmd_Argc (cmd) == 1)
1141 if (Cmd_Argc (cmd) == 2)
1142 strlcpy (newPath, Cmd_Argv(cmd, 1), sizeof (newPath));
1144 strlcpy (newPath, Cmd_Args(cmd), sizeof (newPath));
1146 for (i = 0, j = 0;newPath[i];i++)
1147 if (newPath[i] != '\r' && newPath[i] != '\n')
1148 newPath[j++] = newPath[i];
1152 if (host.realtime < host_client->nametime)
1154 SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
1158 host_client->nametime = host.realtime + 5;
1161 // point the string back at updateclient->name to keep it safe
1162 strlcpy (host_client->playermodel, newPath, sizeof (host_client->playermodel));
1163 PRVM_serveredictstring(host_client->edict, playermodel) = PRVM_SetEngineString(prog, host_client->playermodel);
1164 if (strcmp(host_client->old_model, host_client->playermodel))
1166 strlcpy(host_client->old_model, host_client->playermodel, sizeof(host_client->old_model));
1167 /*// send notification to all clients
1168 MSG_WriteByte (&sv.reliable_datagram, svc_updatepmodel);
1169 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1170 MSG_WriteString (&sv.reliable_datagram, host_client->playermodel);*/
1175 ======================
1177 ======================
1179 static void SV_Playerskin_f(cmd_state_t *cmd)
1181 prvm_prog_t *prog = SVVM_prog;
1183 char newPath[sizeof(host_client->playerskin)];
1185 if (Cmd_Argc (cmd) == 1)
1188 if (Cmd_Argc (cmd) == 2)
1189 strlcpy (newPath, Cmd_Argv(cmd, 1), sizeof (newPath));
1191 strlcpy (newPath, Cmd_Args(cmd), sizeof (newPath));
1193 for (i = 0, j = 0;newPath[i];i++)
1194 if (newPath[i] != '\r' && newPath[i] != '\n')
1195 newPath[j++] = newPath[i];
1199 if (host.realtime < host_client->nametime)
1201 SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
1205 host_client->nametime = host.realtime + 5;
1208 // point the string back at updateclient->name to keep it safe
1209 strlcpy (host_client->playerskin, newPath, sizeof (host_client->playerskin));
1210 PRVM_serveredictstring(host_client->edict, playerskin) = PRVM_SetEngineString(prog, host_client->playerskin);
1211 if (strcmp(host_client->old_skin, host_client->playerskin))
1213 //if (host_client->begun)
1214 // SV_BroadcastPrintf("%s changed skin to %s\n", host_client->name, host_client->playerskin);
1215 strlcpy(host_client->old_skin, host_client->playerskin, sizeof(host_client->old_skin));
1216 /*// send notification to all clients
1217 MSG_WriteByte (&sv.reliable_datagram, svc_updatepskin);
1218 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1219 MSG_WriteString (&sv.reliable_datagram, host_client->playerskin);*/
1224 ======================
1226 LadyHavoc: only supported for Nehahra, I personally think this is dumb, but Mindcrime won't listen.
1227 LadyHavoc: correction, Mindcrime will be removing pmodel in the future, but it's still stuck here for compatibility.
1228 ======================
1230 static void SV_PModel_f(cmd_state_t *cmd)
1232 prvm_prog_t *prog = SVVM_prog;
1234 if (Cmd_Argc (cmd) == 1)
1237 PRVM_serveredictfloat(host_client->edict, pmodel) = atoi(Cmd_Argv(cmd, 1));
1241 ===============================================================================
1245 ===============================================================================
1248 static prvm_edict_t *FindViewthing(prvm_prog_t *prog)
1253 for (i=0 ; i<prog->num_edicts ; i++)
1255 e = PRVM_EDICT_NUM(i);
1256 if (!strcmp (PRVM_GetString(prog, PRVM_serveredictstring(e, classname)), "viewthing"))
1259 Con_Print("No viewthing on map\n");
1268 static void SV_Viewmodel_f(cmd_state_t *cmd)
1270 prvm_prog_t *prog = SVVM_prog;
1277 e = FindViewthing(prog);
1280 m = Mod_ForName (Cmd_Argv(cmd, 1), false, true, NULL);
1281 if (m && m->loaded && m->Draw)
1283 PRVM_serveredictfloat(e, frame) = 0;
1284 cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)] = m;
1287 Con_Printf("viewmodel: can't load %s\n", Cmd_Argv(cmd, 1));
1296 static void SV_Viewframe_f(cmd_state_t *cmd)
1298 prvm_prog_t *prog = SVVM_prog;
1306 e = FindViewthing(prog);
1309 m = cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)];
1311 f = atoi(Cmd_Argv(cmd, 1));
1312 if (f >= m->numframes)
1315 PRVM_serveredictfloat(e, frame) = f;
1319 static void PrintFrameName (model_t *m, int frame)
1322 Con_Printf("frame %i: %s\n", frame, m->animscenes[frame].name);
1324 Con_Printf("frame %i\n", frame);
1332 static void SV_Viewnext_f(cmd_state_t *cmd)
1334 prvm_prog_t *prog = SVVM_prog;
1341 e = FindViewthing(prog);
1344 m = cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)];
1346 PRVM_serveredictfloat(e, frame) = PRVM_serveredictfloat(e, frame) + 1;
1347 if (PRVM_serveredictfloat(e, frame) >= m->numframes)
1348 PRVM_serveredictfloat(e, frame) = m->numframes - 1;
1350 PrintFrameName (m, (int)PRVM_serveredictfloat(e, frame));
1359 static void SV_Viewprev_f(cmd_state_t *cmd)
1361 prvm_prog_t *prog = SVVM_prog;
1368 e = FindViewthing(prog);
1371 m = cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)];
1373 PRVM_serveredictfloat(e, frame) = PRVM_serveredictfloat(e, frame) - 1;
1374 if (PRVM_serveredictfloat(e, frame) < 0)
1375 PRVM_serveredictfloat(e, frame) = 0;
1377 PrintFrameName (m, (int)PRVM_serveredictfloat(e, frame));
1381 static void SV_SendCvar_f(cmd_state_t *cmd)
1384 const char *cvarname;
1387 if(Cmd_Argc(cmd) != 2)
1390 if(!sv.active)// || !PRVM_serverfunction(SV_ParseClientCommand))
1393 cvarname = Cmd_Argv(cmd, 1);
1396 if(host_isclient.integer)
1400 for(;i<svs.maxclients;i++)
1401 if(svs.clients[i].active && svs.clients[i].netconnection)
1403 host_client = &svs.clients[i];
1404 SV_ClientCommands("sendcvar %s\n", cvarname);
1409 static void SV_Ent_Create_f(cmd_state_t *cmd)
1411 prvm_prog_t *prog = SVVM_prog;
1417 void (*print)(const char *, ...) = (cmd->source == src_client ? SV_ClientPrintf : Con_Printf);
1422 ed = PRVM_ED_Alloc(SVVM_prog);
1424 PRVM_ED_ParseEpair(prog, ed, PRVM_ED_FindField(prog, "classname"), Cmd_Argv(cmd, 1), false);
1426 // Spawn where the player is aiming. We need a view matrix first.
1427 if(cmd->source == src_client)
1429 vec3_t org, temp, dest;
1434 SV_GetEntityMatrix(prog, host_client->edict, &view, true);
1436 Matrix4x4_OriginFromMatrix(&view, org);
1437 VectorSet(temp, 65536, 0, 0);
1438 Matrix4x4_Transform(&view, temp, dest);
1440 trace = SV_TraceLine(org, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, 0, 0, collision_extendmovelength.value);
1442 dpsnprintf(buf, sizeof(buf), "%g %g %g", trace.endpos[0], trace.endpos[1], trace.endpos[2]);
1443 PRVM_ED_ParseEpair(prog, ed, PRVM_ED_FindField(prog, "origin"), buf, false);
1447 // Or spawn at a specified origin.
1454 // Allow more than one key/value pair by cycling between expecting either one.
1455 for(i = 2; i < Cmd_Argc(cmd); i += 2)
1457 if(!(key = PRVM_ED_FindField(prog, Cmd_Argv(cmd, i))))
1459 print("Key %s not found!\n", Cmd_Argv(cmd, i));
1460 PRVM_ED_Free(prog, ed);
1465 * This is mostly for dedicated server console, but if the
1466 * player gave a custom origin, we can ignore the traceline.
1468 if(!strcmp(Cmd_Argv(cmd, i), "origin"))
1471 if (i + 1 < Cmd_Argc(cmd))
1472 PRVM_ED_ParseEpair(prog, ed, key, Cmd_Argv(cmd, i+1), false);
1477 print("Missing origin\n");
1478 PRVM_ED_Free(prog, ed);
1483 PRVM_ED_CallPrespawnFunction(prog, ed);
1485 if(!PRVM_ED_CallSpawnFunction(prog, ed, NULL, NULL))
1487 print("Could not spawn a \"%s\". No such entity or it has no spawn function\n", Cmd_Argv(cmd, 1));
1488 if(cmd->source == src_client)
1489 Con_Printf("%s tried to spawn a \"%s\"\n", host_client->name, Cmd_Argv(cmd, 1));
1490 // CallSpawnFunction already freed the edict for us.
1494 PRVM_ED_CallPostspawnFunction(prog, ed);
1496 // Make it appear in the world
1499 if(cmd->source == src_client)
1500 Con_Printf("%s spawned a \"%s\"\n", host_client->name, Cmd_Argv(cmd, 1));
1503 static void SV_Ent_Remove_f(cmd_state_t *cmd)
1505 prvm_prog_t *prog = SVVM_prog;
1508 void (*print)(const char *, ...) = (cmd->source == src_client ? SV_ClientPrintf : Con_Printf);
1513 // Allow specifying edict by number
1514 if(Cmd_Argc(cmd) > 1 && Cmd_Argv(cmd, 1))
1516 ednum = atoi(Cmd_Argv(cmd, 1));
1519 print("Cannot remove the world\n");
1523 // Or trace a line if it's a client who didn't specify one.
1524 else if(cmd->source == src_client)
1526 vec3_t org, temp, dest;
1530 SV_GetEntityMatrix(prog, host_client->edict, &view, true);
1532 Matrix4x4_OriginFromMatrix(&view, org);
1533 VectorSet(temp, 65536, 0, 0);
1534 Matrix4x4_Transform(&view, temp, dest);
1536 trace = SV_TraceLine(org, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY, 0, 0, collision_extendmovelength.value);
1539 ednum = (int)PRVM_EDICT_TO_PROG(trace.ent);
1540 if(!trace.ent || !ednum)
1541 // Don't remove the world, but don't annoy players with a print if they miss
1546 // Only a dedicated server console should be able to reach this.
1547 print("No edict given\n");
1551 ed = PRVM_EDICT_NUM(ednum);
1556 for (i = 0; i < svs.maxclients; i++)
1558 if(ed == svs.clients[i].edict)
1564 print("Removed a \"%s\"\n", PRVM_GetString(prog, PRVM_serveredictstring(ed, classname)));
1565 PRVM_ED_ClearEdict(prog, ed);
1566 PRVM_ED_Free(prog, ed);
1571 // This should only be reachable if an invalid edict number was given
1572 print("No such entity\n");
1577 static void SV_Ent_Remove_All_f(cmd_state_t *cmd)
1579 prvm_prog_t *prog = SVVM_prog;
1582 void (*print)(const char *, ...) = (cmd->source == src_client ? SV_ClientPrintf : Con_Printf);
1584 for (i = 0, rmcount = 0, ed = PRVM_EDICT_NUM(i); i < prog->num_edicts; i++, ed = PRVM_NEXT_EDICT(ed))
1586 if(!ed->free && !strcmp(PRVM_GetString(prog, PRVM_serveredictstring(ed, classname)), Cmd_Argv(cmd, 1)))
1590 print("Cannot remove the world\n");
1593 PRVM_ED_ClearEdict(prog, ed);
1594 PRVM_ED_Free(prog, ed);
1600 print("No \"%s\" found\n", Cmd_Argv(cmd, 1));
1602 print("Removed %i of \"%s\"\n", rmcount, Cmd_Argv(cmd, 1));
1605 void SV_InitOperatorCommands(void)
1607 Cvar_RegisterVariable(&sv_cheats);
1608 Cvar_RegisterCallback(&sv_cheats, SV_DisableCheats_c);
1609 Cvar_RegisterVariable(&sv_adminnick);
1610 Cvar_RegisterVariable(&sv_status_privacy);
1611 Cvar_RegisterVariable(&sv_status_show_qcstatus);
1612 Cvar_RegisterVariable(&sv_namechangetimer);
1614 Cmd_AddCommand(CF_SERVER | CF_SERVER_FROM_CLIENT, "status", SV_Status_f, "print server status information");
1615 Cmd_AddCommand(CF_SHARED, "map", SV_Map_f, "kick everyone off the server and start a new level");
1616 Cmd_AddCommand(CF_SHARED, "restart", SV_Restart_f, "restart current level");
1617 Cmd_AddCommand(CF_SHARED, "changelevel", SV_Changelevel_f, "change to another level, bringing along all connected clients");
1618 Cmd_AddCommand(CF_SHARED | CF_SERVER_FROM_CLIENT, "say", SV_Say_f, "send a chat message to everyone on the server");
1619 Cmd_AddCommand(CF_SERVER_FROM_CLIENT, "say_team", SV_Say_Team_f, "send a chat message to your team on the server");
1620 Cmd_AddCommand(CF_SHARED | CF_SERVER_FROM_CLIENT, "tell", SV_Tell_f, "send a chat message to only one person on the server");
1621 Cmd_AddCommand(CF_SERVER | CF_SERVER_FROM_CLIENT, "pause", SV_Pause_f, "pause the game (if the server allows pausing)");
1622 Cmd_AddCommand(CF_SHARED, "kick", SV_Kick_f, "kick a player off the server by number or name");
1623 Cmd_AddCommand(CF_SHARED | CF_SERVER_FROM_CLIENT, "ping", SV_Ping_f, "print ping times of all players on the server");
1624 Cmd_AddCommand(CF_SHARED, "load", SV_Loadgame_f, "load a saved game file");
1625 Cmd_AddCommand(CF_SHARED, "save", SV_Savegame_f, "save the game to a file");
1626 Cmd_AddCommand(CF_SHARED, "viewmodel", SV_Viewmodel_f, "change model of viewthing entity in current level");
1627 Cmd_AddCommand(CF_SHARED, "viewframe", SV_Viewframe_f, "change animation frame of viewthing entity in current level");
1628 Cmd_AddCommand(CF_SHARED, "viewnext", SV_Viewnext_f, "change to next animation frame of viewthing entity in current level");
1629 Cmd_AddCommand(CF_SHARED, "viewprev", SV_Viewprev_f, "change to previous animation frame of viewthing entity in current level");
1630 Cmd_AddCommand(CF_SHARED, "maxplayers", SV_MaxPlayers_f, "sets limit on how many players (or bots) may be connected to the server at once");
1631 host.hook.SV_SendCvar = SV_SendCvar_f;
1633 // 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)
1634 Cmd_AddCommand(CF_SERVER_FROM_CLIENT, "prespawn", SV_PreSpawn_f, "internal use - signon 1 (client acknowledges that server information has been received)");
1635 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)");
1636 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)");
1637 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)");
1639 Cmd_AddCommand(CF_CHEAT | CF_SERVER_FROM_CLIENT, "god", SV_God_f, "god mode (invulnerability)");
1640 Cmd_AddCommand(CF_CHEAT | CF_SERVER_FROM_CLIENT, "notarget", SV_Notarget_f, "notarget mode (monsters do not see you)");
1641 Cmd_AddCommand(CF_CHEAT | CF_SERVER_FROM_CLIENT, "fly", SV_Fly_f, "fly mode (flight)");
1642 Cmd_AddCommand(CF_CHEAT | CF_SERVER_FROM_CLIENT, "noclip", SV_Noclip_f, "noclip mode (flight without collisions, move through walls)");
1643 Cmd_AddCommand(CF_CHEAT | CF_SERVER_FROM_CLIENT, "give", SV_Give_f, "alter inventory");
1644 Cmd_AddCommand(CF_SERVER_FROM_CLIENT, "kill", SV_Kill_f, "die instantly");
1646 Cmd_AddCommand(CF_USERINFO, "color", SV_Color_f, "change your player shirt and pants colors");
1647 Cmd_AddCommand(CF_USERINFO, "name", SV_Name_f, "change your player name");
1648 Cmd_AddCommand(CF_USERINFO, "rate", SV_Rate_f, "change your network connection speed");
1649 Cmd_AddCommand(CF_USERINFO, "rate_burstsize", SV_Rate_BurstSize_f, "change your network connection speed");
1650 Cmd_AddCommand(CF_USERINFO, "pmodel", SV_PModel_f, "(Nehahra-only) change your player model choice");
1651 Cmd_AddCommand(CF_USERINFO, "playermodel", SV_Playermodel_f, "change your player model");
1652 Cmd_AddCommand(CF_USERINFO, "playerskin", SV_Playerskin_f, "change your player skin number");
1654 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.");
1655 Cmd_AddCommand(CF_CHEAT | CF_SERVER_FROM_CLIENT, "ent_remove_all", SV_Ent_Remove_All_f, "Removes all entities of the specified classname");
1656 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");