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 cls.demonum = -1; // stop demo loop in case this fails
69 if(svs.maxclients != svs.maxclients_next)
71 svs.maxclients = svs.maxclients_next;
73 Mem_Free(svs.clients);
74 svs.clients = (client_t *)Mem_Alloc(sv_mempool, sizeof(client_t) * svs.maxclients);
79 if (key_dest == key_menu || key_dest == key_menu_grabbed)
84 svs.serverflags = 0; // haven't completed an episode yet
85 strlcpy(level, Cmd_Argv(cmd, 1), sizeof(level));
86 SV_SpawnServer(level);
88 if(sv.active && host.hook.ConnectLocal != NULL)
89 host.hook.ConnectLocal();
96 Goes to a new map, taking all clients along
99 static void SV_Changelevel_f(cmd_state_t *cmd)
101 char level[MAX_QPATH];
103 if (Cmd_Argc(cmd) != 2)
105 Con_Print("changelevel <levelname> : continue game on a new level\n");
111 Con_Printf("You must be running a server to changelevel. Use 'map %s' instead\n", Cmd_Argv(cmd, 1));
117 if (key_dest == key_menu || key_dest == key_menu_grabbed)
122 SV_SaveSpawnparms ();
123 strlcpy(level, Cmd_Argv(cmd, 1), sizeof(level));
124 SV_SpawnServer(level);
126 if(sv.active && host.hook.ConnectLocal != NULL)
127 host.hook.ConnectLocal();
134 Restarts the current server for a dead player
137 static void SV_Restart_f(cmd_state_t *cmd)
139 char mapname[MAX_QPATH];
141 if (Cmd_Argc(cmd) != 1)
143 Con_Print("restart : restart current level\n");
148 Con_Print("Only the server may restart\n");
154 if (key_dest == key_menu || key_dest == key_menu_grabbed)
159 strlcpy(mapname, sv.name, sizeof(mapname));
160 SV_SpawnServer(mapname);
162 if(sv.active && host.hook.ConnectLocal != NULL)
163 host.hook.ConnectLocal();
166 //===========================================================================
168 // Disable cheats if sv_cheats is turned off
169 static void SV_DisableCheats_c(cvar_t *var)
171 prvm_prog_t *prog = SVVM_prog;
176 while (svs.clients[i].edict)
178 if (((int)PRVM_serveredictfloat(svs.clients[i].edict, flags) & FL_GODMODE))
179 PRVM_serveredictfloat(svs.clients[i].edict, flags) = (int)PRVM_serveredictfloat(svs.clients[i].edict, flags) ^ FL_GODMODE;
180 if (((int)PRVM_serveredictfloat(svs.clients[i].edict, flags) & FL_NOTARGET))
181 PRVM_serveredictfloat(svs.clients[i].edict, flags) = (int)PRVM_serveredictfloat(svs.clients[i].edict, flags) ^ FL_NOTARGET;
182 if (PRVM_serveredictfloat(svs.clients[i].edict, movetype) == MOVETYPE_NOCLIP ||
183 PRVM_serveredictfloat(svs.clients[i].edict, movetype) == MOVETYPE_FLY)
185 noclip_anglehack = false;
186 PRVM_serveredictfloat(svs.clients[i].edict, movetype) = MOVETYPE_WALK;
197 Sets client to godmode
200 static void SV_God_f(cmd_state_t *cmd)
202 prvm_prog_t *prog = SVVM_prog;
204 PRVM_serveredictfloat(host_client->edict, flags) = (int)PRVM_serveredictfloat(host_client->edict, flags) ^ FL_GODMODE;
205 if (!((int)PRVM_serveredictfloat(host_client->edict, flags) & FL_GODMODE) )
206 SV_ClientPrint("godmode OFF\n");
208 SV_ClientPrint("godmode ON\n");
211 qbool noclip_anglehack;
213 static void SV_Noclip_f(cmd_state_t *cmd)
215 prvm_prog_t *prog = SVVM_prog;
217 if (PRVM_serveredictfloat(host_client->edict, movetype) != MOVETYPE_NOCLIP)
219 noclip_anglehack = true;
220 PRVM_serveredictfloat(host_client->edict, movetype) = MOVETYPE_NOCLIP;
221 SV_ClientPrint("noclip ON\n");
225 noclip_anglehack = false;
226 PRVM_serveredictfloat(host_client->edict, movetype) = MOVETYPE_WALK;
227 SV_ClientPrint("noclip OFF\n");
236 static void SV_Give_f(cmd_state_t *cmd)
238 prvm_prog_t *prog = SVVM_prog;
242 t = Cmd_Argv(cmd, 1);
243 v = atoi (Cmd_Argv(cmd, 2));
257 // MED 01/04/97 added hipnotic give stuff
258 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_QUOTH)
263 PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | HIT_PROXIMITY_GUN;
265 PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | IT_GRENADE_LAUNCHER;
267 else if (t[0] == '9')
268 PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | HIT_LASER_CANNON;
269 else if (t[0] == '0')
270 PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | HIT_MJOLNIR;
271 else if (t[0] >= '2')
272 PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | (IT_SHOTGUN << (t[0] - '2'));
277 PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | (IT_SHOTGUN << (t[0] - '2'));
282 if (gamemode == GAME_ROGUE)
283 PRVM_serveredictfloat(host_client->edict, ammo_shells1) = v;
285 PRVM_serveredictfloat(host_client->edict, ammo_shells) = v;
288 if (gamemode == GAME_ROGUE)
290 PRVM_serveredictfloat(host_client->edict, ammo_nails1) = v;
291 if (PRVM_serveredictfloat(host_client->edict, weapon) <= IT_LIGHTNING)
292 PRVM_serveredictfloat(host_client->edict, ammo_nails) = v;
296 PRVM_serveredictfloat(host_client->edict, ammo_nails) = v;
300 if (gamemode == GAME_ROGUE)
302 PRVM_serveredictfloat(host_client->edict, ammo_lava_nails) = v;
303 if (PRVM_serveredictfloat(host_client->edict, weapon) > IT_LIGHTNING)
304 PRVM_serveredictfloat(host_client->edict, ammo_nails) = v;
308 if (gamemode == GAME_ROGUE)
310 PRVM_serveredictfloat(host_client->edict, ammo_rockets1) = 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, ammo_rockets) = v;
320 if (gamemode == GAME_ROGUE)
322 PRVM_serveredictfloat(host_client->edict, ammo_multi_rockets) = v;
323 if (PRVM_serveredictfloat(host_client->edict, weapon) > IT_LIGHTNING)
324 PRVM_serveredictfloat(host_client->edict, ammo_rockets) = v;
328 PRVM_serveredictfloat(host_client->edict, health) = v;
331 if (gamemode == GAME_ROGUE)
333 PRVM_serveredictfloat(host_client->edict, ammo_cells1) = v;
334 if (PRVM_serveredictfloat(host_client->edict, weapon) <= IT_LIGHTNING)
335 PRVM_serveredictfloat(host_client->edict, ammo_cells) = v;
339 PRVM_serveredictfloat(host_client->edict, ammo_cells) = v;
343 if (gamemode == GAME_ROGUE)
345 PRVM_serveredictfloat(host_client->edict, ammo_plasma) = v;
346 if (PRVM_serveredictfloat(host_client->edict, weapon) > IT_LIGHTNING)
347 PRVM_serveredictfloat(host_client->edict, ammo_cells) = v;
357 Sets client to flymode
360 static void SV_Fly_f(cmd_state_t *cmd)
362 prvm_prog_t *prog = SVVM_prog;
364 if (PRVM_serveredictfloat(host_client->edict, movetype) != MOVETYPE_FLY)
366 PRVM_serveredictfloat(host_client->edict, movetype) = MOVETYPE_FLY;
367 SV_ClientPrint("flymode ON\n");
371 PRVM_serveredictfloat(host_client->edict, movetype) = MOVETYPE_WALK;
372 SV_ClientPrint("flymode OFF\n");
376 static void SV_Notarget_f(cmd_state_t *cmd)
378 prvm_prog_t *prog = SVVM_prog;
380 PRVM_serveredictfloat(host_client->edict, flags) = (int)PRVM_serveredictfloat(host_client->edict, flags) ^ FL_NOTARGET;
381 if (!((int)PRVM_serveredictfloat(host_client->edict, flags) & FL_NOTARGET) )
382 SV_ClientPrint("notarget OFF\n");
384 SV_ClientPrint("notarget ON\n");
392 static void SV_Kill_f(cmd_state_t *cmd)
394 prvm_prog_t *prog = SVVM_prog;
395 if (PRVM_serveredictfloat(host_client->edict, health) <= 0)
397 SV_ClientPrint("Can't suicide -- already dead!\n");
401 PRVM_serverglobalfloat(time) = sv.time;
402 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict);
403 prog->ExecuteProgram(prog, PRVM_serverfunction(ClientKill), "QC function ClientKill is missing");
411 static void SV_Pause_f(cmd_state_t *cmd)
413 void (*print) (const char *fmt, ...);
414 if (cmd->source == src_local)
417 print = SV_ClientPrintf;
419 if (!pausable.integer && cmd->source == src_client && LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) != LHNETADDRESSTYPE_LOOP)
421 print("Pause not allowed.\n");
426 if (cmd->source != src_local)
427 SV_BroadcastPrintf("%s %spaused the game\n", host_client->name, sv.paused ? "" : "un");
428 else if(*(sv_adminnick.string))
429 SV_BroadcastPrintf("%s %spaused the game\n", sv_adminnick.string, sv.paused ? "" : "un");
431 SV_BroadcastPrintf("%s %spaused the game\n", hostname.string, sv.paused ? "" : "un");
432 // send notification to all clients
433 MSG_WriteByte(&sv.reliable_datagram, svc_setpause);
434 MSG_WriteByte(&sv.reliable_datagram, sv.paused);
437 static void SV_Say(cmd_state_t *cmd, qbool teamonly)
439 prvm_prog_t *prog = SVVM_prog;
444 // LadyHavoc: long say messages
446 qbool fromServer = false;
448 if (cmd->source == src_local)
454 if (Cmd_Argc (cmd) < 2)
457 if (!teamplay.integer)
467 // note this uses the chat prefix \001
468 if (!fromServer && !teamonly)
469 dpsnprintf (text, sizeof(text), "\001%s: %s", host_client->name, p1);
470 else if (!fromServer && teamonly)
471 dpsnprintf (text, sizeof(text), "\001(%s): %s", host_client->name, p1);
472 else if(*(sv_adminnick.string))
473 dpsnprintf (text, sizeof(text), "\001<%s> %s", sv_adminnick.string, p1);
475 dpsnprintf (text, sizeof(text), "\001<%s> %s", hostname.string, p1);
476 p2 = text + strlen(text);
477 while ((const char *)p2 > (const char *)text && (p2[-1] == '\r' || p2[-1] == '\n' || (p2[-1] == '\"' && quoted)))
479 if (p2[-1] == '\"' && quoted)
484 strlcat(text, "\n", sizeof(text));
486 // note: save is not a valid edict if fromServer is true
488 for (j = 0, host_client = svs.clients;j < svs.maxclients;j++, host_client++)
489 if (host_client->active && (!teamonly || PRVM_serveredictfloat(host_client->edict, team) == PRVM_serveredictfloat(save->edict, team)))
490 SV_ClientPrint(text);
493 if(!host_isclient.integer)
497 static void SV_Say_f(cmd_state_t *cmd)
502 static void SV_Say_Team_f(cmd_state_t *cmd)
507 static void SV_Tell_f(cmd_state_t *cmd)
509 const char *playername_start = NULL;
510 size_t playername_length = 0;
511 int playernumber = 0;
515 char text[MAX_INPUTLINE]; // LadyHavoc: FIXME: temporary buffer overflow fix (was 64)
516 qbool fromServer = false;
518 if (cmd->source == src_local)
521 if (Cmd_Argc (cmd) < 2)
524 // note this uses the chat prefix \001
526 dpsnprintf (text, sizeof(text), "\001%s tells you: ", host_client->name);
527 else if(*(sv_adminnick.string))
528 dpsnprintf (text, sizeof(text), "\001<%s tells you> ", sv_adminnick.string);
530 dpsnprintf (text, sizeof(text), "\001<%s tells you> ", hostname.string);
533 p2 = p1 + strlen(p1);
534 // remove the target name
535 while (p1 < p2 && *p1 == ' ')
540 while (p1 < p2 && *p1 == ' ')
542 while (p1 < p2 && isdigit(*p1))
544 playernumber = playernumber * 10 + (*p1 - '0');
552 playername_start = p1;
553 while (p1 < p2 && *p1 != '"')
555 playername_length = p1 - playername_start;
561 playername_start = p1;
562 while (p1 < p2 && *p1 != ' ')
564 playername_length = p1 - playername_start;
566 while (p1 < p2 && *p1 == ' ')
570 // set playernumber to the right client
572 if(playername_length >= sizeof(namebuf))
575 Con_Print("Host_Tell: too long player name/ID\n");
577 SV_ClientPrint("Host_Tell: too long player name/ID\n");
580 memcpy(namebuf, playername_start, playername_length);
581 namebuf[playername_length] = 0;
582 for (playernumber = 0; playernumber < svs.maxclients; playernumber++)
584 if (!svs.clients[playernumber].active)
586 if (strcasecmp(svs.clients[playernumber].name, namebuf) == 0)
590 if(playernumber < 0 || playernumber >= svs.maxclients || !(svs.clients[playernumber].active))
593 Con_Print("Host_Tell: invalid player name/ID\n");
595 SV_ClientPrint("Host_Tell: invalid player name/ID\n");
598 // remove trailing newlines
599 while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
601 // remove quotes if present
608 Con_Print("Host_Tell: missing end quote\n");
610 SV_ClientPrint("Host_Tell: missing end quote\n");
612 while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
616 for (j = (int)strlen(text);j < (int)(sizeof(text) - 2) && p1 < p2;)
622 host_client = svs.clients + playernumber;
623 SV_ClientPrint(text);
633 static void SV_Ping_f(cmd_state_t *cmd)
637 void (*print) (const char *fmt, ...);
639 if (cmd->source == src_local)
642 print = SV_ClientPrintf;
647 print("Client ping times:\n");
648 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
652 print("%4i %s\n", bound(0, (int)floor(client->ping*1000+0.5), 9999), client->name);
660 Send back ping and packet loss update for all current players to this player
663 static void SV_Pings_f(cmd_state_t *cmd)
665 int i, j, ping, packetloss, movementloss;
668 if (!host_client->netconnection)
671 if (sv.protocol != PROTOCOL_QUAKEWORLD)
673 MSG_WriteByte(&host_client->netconnection->message, svc_stufftext);
674 MSG_WriteUnterminatedString(&host_client->netconnection->message, "pingplreport");
676 for (i = 0;i < svs.maxclients;i++)
680 if (svs.clients[i].netconnection)
682 for (j = 0;j < NETGRAPH_PACKETS;j++)
683 if (svs.clients[i].netconnection->incoming_netgraph[j].unreliablebytes == NETGRAPH_LOSTPACKET)
685 for (j = 0;j < NETGRAPH_PACKETS;j++)
686 if (svs.clients[i].movement_count[j] < 0)
689 packetloss = (packetloss * 100 + NETGRAPH_PACKETS - 1) / NETGRAPH_PACKETS;
690 movementloss = (movementloss * 100 + NETGRAPH_PACKETS - 1) / NETGRAPH_PACKETS;
691 ping = (int)floor(svs.clients[i].ping*1000+0.5);
692 ping = bound(0, ping, 9999);
693 if (sv.protocol == PROTOCOL_QUAKEWORLD)
695 // send qw_svc_updateping and qw_svc_updatepl messages
696 MSG_WriteByte(&host_client->netconnection->message, qw_svc_updateping);
697 MSG_WriteShort(&host_client->netconnection->message, ping);
698 MSG_WriteByte(&host_client->netconnection->message, qw_svc_updatepl);
699 MSG_WriteByte(&host_client->netconnection->message, packetloss);
703 // write the string into the packet as multiple unterminated strings to avoid needing a local buffer
705 dpsnprintf(temp, sizeof(temp), " %d %d,%d", ping, packetloss, movementloss);
707 dpsnprintf(temp, sizeof(temp), " %d %d", ping, packetloss);
708 MSG_WriteUnterminatedString(&host_client->netconnection->message, temp);
711 if (sv.protocol != PROTOCOL_QUAKEWORLD)
712 MSG_WriteString(&host_client->netconnection->message, "\n");
720 static void SV_Status_f(cmd_state_t *cmd)
722 prvm_prog_t *prog = SVVM_prog;
725 int seconds = 0, minutes = 0, hours = 0, i, j, k, in, players, ping = 0, packetloss = 0;
726 void (*print) (const char *fmt, ...);
727 char ip[48]; // can contain a full length v6 address with [] and a port
731 if (cmd->source == src_local)
734 print = SV_ClientPrintf;
740 if (Cmd_Argc(cmd) == 2)
742 if (strcmp(Cmd_Argv(cmd, 1), "1") == 0)
744 else if (strcmp(Cmd_Argv(cmd, 1), "2") == 0)
748 for (players = 0, i = 0;i < svs.maxclients;i++)
749 if (svs.clients[i].active)
751 print ("host: %s\n", Cvar_VariableString (&cvars_all, "hostname", CF_SERVER));
752 print ("version: %s build %s (gamename %s)\n", gamename, buildstring, gamenetworkfiltername);
753 print ("protocol: %i (%s)\n", Protocol_NumberForEnum(sv.protocol), Protocol_NameForEnum(sv.protocol));
754 print ("map: %s\n", sv.name);
755 print ("timing: %s\n", Host_TimingReport(vabuf, sizeof(vabuf)));
756 print ("players: %i active (%i max)\n\n", players, svs.maxclients);
759 print ("^2IP %%pl ping time frags no name\n");
761 print ("^5IP no name\n");
763 for (i = 0, k = 0, client = svs.clients;i < svs.maxclients;i++, client++)
770 if (in == 0 || in == 1)
772 seconds = (int)(host.realtime - client->connecttime);
773 minutes = seconds / 60;
776 seconds -= (minutes * 60);
777 hours = minutes / 60;
779 minutes -= (hours * 60);
785 if (client->netconnection)
786 for (j = 0;j < NETGRAPH_PACKETS;j++)
787 if (client->netconnection->incoming_netgraph[j].unreliablebytes == NETGRAPH_LOSTPACKET)
789 packetloss = (packetloss * 100 + NETGRAPH_PACKETS - 1) / NETGRAPH_PACKETS;
790 ping = bound(0, (int)floor(client->ping*1000+0.5), 9999);
793 if(sv_status_privacy.integer && cmd->source != src_local && LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) != LHNETADDRESSTYPE_LOOP)
794 strlcpy(ip, client->netconnection ? "hidden" : "botclient", 48);
796 strlcpy(ip, (client->netconnection && *client->netconnection->address) ? client->netconnection->address : "botclient", 48);
798 frags = client->frags;
800 if(sv_status_show_qcstatus.integer)
802 prvm_edict_t *ed = PRVM_EDICT_NUM(i + 1);
803 const char *str = PRVM_GetString(prog, PRVM_serveredictstring(ed, clientstatus));
809 for(q = str; *q && p != qcstatus + sizeof(qcstatus) - 1; ++q)
810 if(*q != '\\' && *q != '"' && !ISWHITESPACE(*q))
814 frags = atoi(qcstatus);
818 if (in == 0) // default layout
820 if (sv.protocol == PROTOCOL_QUAKE && svs.maxclients <= 99)
822 // LadyHavoc: this is very touchy because we must maintain ProQuake compatible status output
823 print ("#%-2u %-16.16s %3i %2i:%02i:%02i\n", i+1, client->name, frags, hours, minutes, seconds);
828 // LadyHavoc: no real restrictions here, not a ProQuake-compatible protocol anyway...
829 print ("#%-3u %-16.16s %4i %2i:%02i:%02i\n", i+1, client->name, frags, hours, minutes, seconds);
833 else if (in == 1) // extended layout
835 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);
837 else if (in == 2) // reduced layout
839 print ("%s%-47s #%-3u ^7%s\n", k%2 ? "^3" : "^7", ip, i+1, client->name);
844 void SV_Name(int clientnum)
846 prvm_prog_t *prog = SVVM_prog;
847 PRVM_serveredictstring(host_client->edict, netname) = PRVM_SetEngineString(prog, host_client->name);
848 if (strcmp(host_client->old_name, host_client->name))
850 if (host_client->begun)
851 SV_BroadcastPrintf("\003%s ^7changed name to ^3%s\n", host_client->old_name, host_client->name);
852 strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
853 // send notification to all clients
854 MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
855 MSG_WriteByte (&sv.reliable_datagram, clientnum);
856 MSG_WriteString (&sv.reliable_datagram, host_client->name);
857 SV_WriteNetnameIntoDemo(host_client);
862 ======================
864 ======================
866 static void SV_Name_f(cmd_state_t *cmd)
870 const char *newNameSource;
871 char newName[sizeof(host_client->name)];
873 if (Cmd_Argc (cmd) == 1)
876 if (Cmd_Argc (cmd) == 2)
877 newNameSource = Cmd_Argv(cmd, 1);
879 newNameSource = Cmd_Args(cmd);
881 strlcpy(newName, newNameSource, sizeof(newName));
883 if (cmd->source == src_local)
886 if (host.realtime < host_client->nametime && strcmp(newName, host_client->name))
888 SV_ClientPrintf("You can't change name more than once every %.1f seconds!\n", max(0.0f, sv_namechangetimer.value));
892 host_client->nametime = host.realtime + max(0.0f, sv_namechangetimer.value);
894 // point the string back at updateclient->name to keep it safe
895 strlcpy (host_client->name, newName, sizeof (host_client->name));
897 for (i = 0, j = 0;host_client->name[i];i++)
898 if (host_client->name[i] != '\r' && host_client->name[i] != '\n')
899 host_client->name[j++] = host_client->name[i];
900 host_client->name[j] = 0;
902 if(host_client->name[0] == 1 || host_client->name[0] == 2)
903 // may interfere with chat area, and will needlessly beep; so let's add a ^7
905 memmove(host_client->name + 2, host_client->name, sizeof(host_client->name) - 2);
906 host_client->name[sizeof(host_client->name) - 1] = 0;
907 host_client->name[0] = STRING_COLOR_TAG;
908 host_client->name[1] = '0' + STRING_COLOR_DEFAULT;
911 u8_COM_StringLengthNoColors(host_client->name, 0, &valid_colors);
912 if(!valid_colors) // NOTE: this also proves the string is not empty, as "" is a valid colored string
915 l = strlen(host_client->name);
916 if(l < sizeof(host_client->name) - 1)
918 // duplicate the color tag to escape it
919 host_client->name[i] = STRING_COLOR_TAG;
920 host_client->name[i+1] = 0;
921 //Con_DPrintf("abuse detected, adding another trailing color tag\n");
925 // remove the last character to fix the color code
926 host_client->name[l-1] = 0;
927 //Con_DPrintf("abuse detected, removing a trailing color tag\n");
931 // find the last color tag offset and decide if we need to add a reset tag
932 for (i = 0, j = -1;host_client->name[i];i++)
934 if (host_client->name[i] == STRING_COLOR_TAG)
936 if (host_client->name[i+1] >= '0' && host_client->name[i+1] <= '9')
939 // if this happens to be a reset tag then we don't need one
940 if (host_client->name[i+1] == '0' + STRING_COLOR_DEFAULT)
945 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]))
951 if (host_client->name[i+1] == STRING_COLOR_TAG)
958 // does not end in the default color string, so add it
959 if (j >= 0 && strlen(host_client->name) < sizeof(host_client->name) - 2)
960 memcpy(host_client->name + strlen(host_client->name), STRING_COLOR_DEFAULT_STR, strlen(STRING_COLOR_DEFAULT_STR) + 1);
962 SV_Name(host_client - svs.clients);
965 static void SV_Rate_f(cmd_state_t *cmd)
969 rate = atoi(Cmd_Argv(cmd, 1));
971 if (cmd->source == src_local)
974 host_client->rate = rate;
977 static void SV_Rate_BurstSize_f(cmd_state_t *cmd)
981 if (Cmd_Argc(cmd) != 2)
984 rate_burstsize = atoi(Cmd_Argv(cmd, 1));
986 host_client->rate_burstsize = rate_burstsize;
989 static void SV_Color_f(cmd_state_t *cmd)
991 prvm_prog_t *prog = SVVM_prog;
993 int top, bottom, playercolor;
995 top = atoi(Cmd_Argv(cmd, 1));
996 bottom = atoi(Cmd_Argv(cmd, 2));
1001 playercolor = top*16 + bottom;
1003 if (host_client->edict && PRVM_serverfunction(SV_ChangeTeam))
1005 Con_DPrint("Calling SV_ChangeTeam\n");
1006 prog->globals.fp[OFS_PARM0] = playercolor;
1007 PRVM_serverglobalfloat(time) = sv.time;
1008 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict);
1009 prog->ExecuteProgram(prog, PRVM_serverfunction(SV_ChangeTeam), "QC function SV_ChangeTeam is missing");
1013 if (host_client->edict)
1015 PRVM_serveredictfloat(host_client->edict, clientcolors) = playercolor;
1016 PRVM_serveredictfloat(host_client->edict, team) = bottom + 1;
1018 host_client->colors = playercolor;
1019 if (host_client->old_colors != host_client->colors)
1021 host_client->old_colors = host_client->colors;
1022 // send notification to all clients
1023 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1024 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1025 MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1034 Kicks a user off of the server
1037 static void SV_Kick_f(cmd_state_t *cmd)
1040 const char *message = NULL;
1043 qbool byNumber = false;
1050 if (Cmd_Argc(cmd) > 2 && strcmp(Cmd_Argv(cmd, 1), "#") == 0)
1052 i = (int)(atof(Cmd_Argv(cmd, 2)) - 1);
1053 if (i < 0 || i >= svs.maxclients || !(host_client = svs.clients + i)->active)
1059 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1061 if (!host_client->active)
1063 if (strcasecmp(host_client->name, Cmd_Argv(cmd, 1)) == 0)
1068 if (i < svs.maxclients)
1070 if (cmd->source == src_local)
1072 if(!host_isclient.integer)
1075 who = cl_name.string;
1080 // can't kick yourself!
1081 if (host_client == save)
1084 if (Cmd_Argc(cmd) > 2)
1086 message = Cmd_Args(cmd);
1087 COM_ParseToken_Simple(&message, false, false, true);
1090 message++; // skip the #
1091 while (*message == ' ') // skip white space
1093 message += strlen(Cmd_Argv(cmd, 2)); // skip the number
1095 while (*message && *message == ' ')
1099 SV_ClientPrintf("Kicked by %s: %s\n", who, message);
1101 SV_ClientPrintf("Kicked by %s\n", who);
1102 SV_DropClient (false); // kicked
1108 static void SV_MaxPlayers_f(cmd_state_t *cmd)
1112 if (Cmd_Argc(cmd) != 2)
1114 Con_Printf("\"maxplayers\" is \"%u\"\n", svs.maxclients_next);
1120 Con_Print("maxplayers can not be changed while a server is running.\n");
1121 Con_Print("It will be changed on next server startup (\"map\" command).\n");
1124 n = atoi(Cmd_Argv(cmd, 1));
1125 n = bound(1, n, MAX_SCOREBOARD);
1126 Con_Printf("\"maxplayers\" set to \"%u\"\n", n);
1128 svs.maxclients_next = n;
1130 Cvar_Set (&cvars_all, "deathmatch", "0");
1132 Cvar_Set (&cvars_all, "deathmatch", "1");
1136 ======================
1138 ======================
1140 // the old playermodel in cl_main has been renamed to __cl_playermodel
1141 static void SV_Playermodel_f(cmd_state_t *cmd)
1143 prvm_prog_t *prog = SVVM_prog;
1145 char newPath[sizeof(host_client->playermodel)];
1147 if (Cmd_Argc (cmd) == 1)
1150 if (Cmd_Argc (cmd) == 2)
1151 strlcpy (newPath, Cmd_Argv(cmd, 1), sizeof (newPath));
1153 strlcpy (newPath, Cmd_Args(cmd), sizeof (newPath));
1155 for (i = 0, j = 0;newPath[i];i++)
1156 if (newPath[i] != '\r' && newPath[i] != '\n')
1157 newPath[j++] = newPath[i];
1161 if (host.realtime < host_client->nametime)
1163 SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
1167 host_client->nametime = host.realtime + 5;
1170 // point the string back at updateclient->name to keep it safe
1171 strlcpy (host_client->playermodel, newPath, sizeof (host_client->playermodel));
1172 PRVM_serveredictstring(host_client->edict, playermodel) = PRVM_SetEngineString(prog, host_client->playermodel);
1173 if (strcmp(host_client->old_model, host_client->playermodel))
1175 strlcpy(host_client->old_model, host_client->playermodel, sizeof(host_client->old_model));
1176 /*// send notification to all clients
1177 MSG_WriteByte (&sv.reliable_datagram, svc_updatepmodel);
1178 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1179 MSG_WriteString (&sv.reliable_datagram, host_client->playermodel);*/
1184 ======================
1186 ======================
1188 static void SV_Playerskin_f(cmd_state_t *cmd)
1190 prvm_prog_t *prog = SVVM_prog;
1192 char newPath[sizeof(host_client->playerskin)];
1194 if (Cmd_Argc (cmd) == 1)
1197 if (Cmd_Argc (cmd) == 2)
1198 strlcpy (newPath, Cmd_Argv(cmd, 1), sizeof (newPath));
1200 strlcpy (newPath, Cmd_Args(cmd), sizeof (newPath));
1202 for (i = 0, j = 0;newPath[i];i++)
1203 if (newPath[i] != '\r' && newPath[i] != '\n')
1204 newPath[j++] = newPath[i];
1208 if (host.realtime < host_client->nametime)
1210 SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
1214 host_client->nametime = host.realtime + 5;
1217 // point the string back at updateclient->name to keep it safe
1218 strlcpy (host_client->playerskin, newPath, sizeof (host_client->playerskin));
1219 PRVM_serveredictstring(host_client->edict, playerskin) = PRVM_SetEngineString(prog, host_client->playerskin);
1220 if (strcmp(host_client->old_skin, host_client->playerskin))
1222 //if (host_client->begun)
1223 // SV_BroadcastPrintf("%s changed skin to %s\n", host_client->name, host_client->playerskin);
1224 strlcpy(host_client->old_skin, host_client->playerskin, sizeof(host_client->old_skin));
1225 /*// send notification to all clients
1226 MSG_WriteByte (&sv.reliable_datagram, svc_updatepskin);
1227 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1228 MSG_WriteString (&sv.reliable_datagram, host_client->playerskin);*/
1233 ======================
1235 LadyHavoc: only supported for Nehahra, I personally think this is dumb, but Mindcrime won't listen.
1236 LadyHavoc: correction, Mindcrime will be removing pmodel in the future, but it's still stuck here for compatibility.
1237 ======================
1239 static void SV_PModel_f(cmd_state_t *cmd)
1241 prvm_prog_t *prog = SVVM_prog;
1243 if (Cmd_Argc (cmd) == 1)
1246 PRVM_serveredictfloat(host_client->edict, pmodel) = atoi(Cmd_Argv(cmd, 1));
1250 ===============================================================================
1254 ===============================================================================
1257 static prvm_edict_t *FindViewthing(prvm_prog_t *prog)
1262 for (i=0 ; i<prog->num_edicts ; i++)
1264 e = PRVM_EDICT_NUM(i);
1265 if (!strcmp (PRVM_GetString(prog, PRVM_serveredictstring(e, classname)), "viewthing"))
1268 Con_Print("No viewthing on map\n");
1277 static void SV_Viewmodel_f(cmd_state_t *cmd)
1279 prvm_prog_t *prog = SVVM_prog;
1286 e = FindViewthing(prog);
1289 m = Mod_ForName (Cmd_Argv(cmd, 1), false, true, NULL);
1290 if (m && m->loaded && m->Draw)
1292 PRVM_serveredictfloat(e, frame) = 0;
1293 cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)] = m;
1296 Con_Printf("viewmodel: can't load %s\n", Cmd_Argv(cmd, 1));
1305 static void SV_Viewframe_f(cmd_state_t *cmd)
1307 prvm_prog_t *prog = SVVM_prog;
1315 e = FindViewthing(prog);
1318 m = cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)];
1320 f = atoi(Cmd_Argv(cmd, 1));
1321 if (f >= m->numframes)
1324 PRVM_serveredictfloat(e, frame) = f;
1328 static void PrintFrameName (model_t *m, int frame)
1331 Con_Printf("frame %i: %s\n", frame, m->animscenes[frame].name);
1333 Con_Printf("frame %i\n", frame);
1341 static void SV_Viewnext_f(cmd_state_t *cmd)
1343 prvm_prog_t *prog = SVVM_prog;
1350 e = FindViewthing(prog);
1353 m = cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)];
1355 PRVM_serveredictfloat(e, frame) = PRVM_serveredictfloat(e, frame) + 1;
1356 if (PRVM_serveredictfloat(e, frame) >= m->numframes)
1357 PRVM_serveredictfloat(e, frame) = m->numframes - 1;
1359 PrintFrameName (m, (int)PRVM_serveredictfloat(e, frame));
1368 static void SV_Viewprev_f(cmd_state_t *cmd)
1370 prvm_prog_t *prog = SVVM_prog;
1377 e = FindViewthing(prog);
1380 m = cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)];
1382 PRVM_serveredictfloat(e, frame) = PRVM_serveredictfloat(e, frame) - 1;
1383 if (PRVM_serveredictfloat(e, frame) < 0)
1384 PRVM_serveredictfloat(e, frame) = 0;
1386 PrintFrameName (m, (int)PRVM_serveredictfloat(e, frame));
1390 static void SV_SendCvar_f(cmd_state_t *cmd)
1393 const char *cvarname;
1396 if(Cmd_Argc(cmd) != 2)
1399 if(!sv.active)// || !PRVM_serverfunction(SV_ParseClientCommand))
1402 cvarname = Cmd_Argv(cmd, 1);
1405 if(host_isclient.integer)
1409 for(;i<svs.maxclients;i++)
1410 if(svs.clients[i].active && svs.clients[i].netconnection)
1412 host_client = &svs.clients[i];
1413 SV_ClientCommands("sendcvar %s\n", cvarname);
1418 static void SV_Ent_Create_f(cmd_state_t *cmd)
1420 prvm_prog_t *prog = SVVM_prog;
1426 qbool expectval = false;
1427 void (*print)(const char *, ...) = (cmd->source == src_client ? SV_ClientPrintf : Con_Printf);
1432 ed = PRVM_ED_Alloc(SVVM_prog);
1434 PRVM_ED_ParseEpair(prog, ed, PRVM_ED_FindField(prog, "classname"), Cmd_Argv(cmd, 1), false);
1436 // Spawn where the player is aiming. We need a view matrix first.
1437 if(cmd->source == src_client)
1439 vec3_t org, temp, dest;
1444 SV_GetEntityMatrix(prog, host_client->edict, &view, true);
1446 Matrix4x4_OriginFromMatrix(&view, org);
1447 VectorSet(temp, 65536, 0, 0);
1448 Matrix4x4_Transform(&view, temp, dest);
1450 trace = SV_TraceLine(org, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, 0, 0, collision_extendmovelength.value);
1452 dpsnprintf(buf, sizeof(buf), "%g %g %g", trace.endpos[0], trace.endpos[1], trace.endpos[2]);
1453 PRVM_ED_ParseEpair(prog, ed, PRVM_ED_FindField(prog, "origin"), buf, false);
1457 // Or spawn at a specified origin.
1464 // Allow more than one key/value pair by cycling between expecting either one.
1465 for(i = 2; i < Cmd_Argc(cmd); i++)
1469 if(!(key = PRVM_ED_FindField(prog, Cmd_Argv(cmd, i))))
1471 print("Key %s not found!\n", Cmd_Argv(cmd, i));
1472 PRVM_ED_Free(prog, ed);
1477 * This is mostly for dedicated server console, but if the
1478 * player gave a custom origin, we can ignore the traceline.
1480 if(!strcmp(Cmd_Argv(cmd, i), "origin"))
1487 PRVM_ED_ParseEpair(prog, ed, key, Cmd_Argv(cmd, i), false);
1494 print("Missing origin\n");
1495 PRVM_ED_Free(prog, ed);
1500 PRVM_ED_CallPrespawnFunction(prog, ed);
1502 if(!PRVM_ED_CallSpawnFunction(prog, ed, NULL, NULL))
1504 print("Could not spawn a \"%s\". No such entity or it has no spawn function\n", Cmd_Argv(cmd, 1));
1505 if(cmd->source == src_client)
1506 Con_Printf("%s tried to spawn a \"%s\"\n", host_client->name, Cmd_Argv(cmd, 1));
1507 // CallSpawnFunction already freed the edict for us.
1511 PRVM_ED_CallPostspawnFunction(prog, ed);
1513 // Make it appear in the world
1516 if(cmd->source == src_client)
1517 Con_Printf("%s spawned a \"%s\"\n", host_client->name, Cmd_Argv(cmd, 1));
1520 static void SV_Ent_Remove_f(cmd_state_t *cmd)
1522 prvm_prog_t *prog = SVVM_prog;
1525 void (*print)(const char *, ...) = (cmd->source == src_client ? SV_ClientPrintf : Con_Printf);
1530 // Allow specifying edict by number
1531 if(Cmd_Argc(cmd) > 1 && Cmd_Argv(cmd, 1))
1533 ednum = atoi(Cmd_Argv(cmd, 1));
1536 print("Cannot remove the world\n");
1540 // Or trace a line if it's a client who didn't specify one.
1541 else if(cmd->source == src_client)
1543 vec3_t org, temp, dest;
1547 SV_GetEntityMatrix(prog, host_client->edict, &view, true);
1549 Matrix4x4_OriginFromMatrix(&view, org);
1550 VectorSet(temp, 65536, 0, 0);
1551 Matrix4x4_Transform(&view, temp, dest);
1553 trace = SV_TraceLine(org, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY, 0, 0, collision_extendmovelength.value);
1556 ednum = (int)PRVM_EDICT_TO_PROG(trace.ent);
1557 if(!trace.ent || !ednum)
1558 // Don't remove the world, but don't annoy players with a print if they miss
1563 // Only a dedicated server console should be able to reach this.
1564 print("No edict given\n");
1568 ed = PRVM_EDICT_NUM(ednum);
1573 for (i = 0; i < svs.maxclients; i++)
1575 if(ed == svs.clients[i].edict)
1579 if(!ed->priv.required->free)
1581 print("Removed a \"%s\"\n", PRVM_GetString(prog, PRVM_serveredictstring(ed, classname)));
1582 PRVM_ED_ClearEdict(prog, ed);
1583 PRVM_ED_Free(prog, ed);
1588 // This should only be reachable if an invalid edict number was given
1589 print("No such entity\n");
1594 static void SV_Ent_Remove_All_f(cmd_state_t *cmd)
1596 prvm_prog_t *prog = SVVM_prog;
1599 void (*print)(const char *, ...) = (cmd->source == src_client ? SV_ClientPrintf : Con_Printf);
1601 for (i = 0, rmcount = 0, ed = PRVM_EDICT_NUM(i); i < prog->num_edicts; i++, ed = PRVM_NEXT_EDICT(ed))
1603 if(!ed->priv.required->free && !strcmp(PRVM_GetString(prog, PRVM_serveredictstring(ed, classname)), Cmd_Argv(cmd, 1)))
1607 print("Cannot remove the world\n");
1610 PRVM_ED_ClearEdict(prog, ed);
1611 PRVM_ED_Free(prog, ed);
1617 print("No \"%s\" found\n", Cmd_Argv(cmd, 1));
1619 print("Removed %i of \"%s\"\n", rmcount, Cmd_Argv(cmd, 1));
1622 void SV_InitOperatorCommands(void)
1624 Cvar_RegisterVariable(&sv_cheats);
1625 Cvar_RegisterCallback(&sv_cheats, SV_DisableCheats_c);
1626 Cvar_RegisterVariable(&sv_adminnick);
1627 Cvar_RegisterVariable(&sv_status_privacy);
1628 Cvar_RegisterVariable(&sv_status_show_qcstatus);
1629 Cvar_RegisterVariable(&sv_namechangetimer);
1631 Cmd_AddCommand(CF_SERVER | CF_SERVER_FROM_CLIENT, "status", SV_Status_f, "print server status information");
1632 Cmd_AddCommand(CF_SHARED, "map", SV_Map_f, "kick everyone off the server and start a new level");
1633 Cmd_AddCommand(CF_SHARED, "restart", SV_Restart_f, "restart current level");
1634 Cmd_AddCommand(CF_SHARED, "changelevel", SV_Changelevel_f, "change to another level, bringing along all connected clients");
1635 Cmd_AddCommand(CF_SHARED | CF_SERVER_FROM_CLIENT, "say", SV_Say_f, "send a chat message to everyone on the server");
1636 Cmd_AddCommand(CF_SERVER_FROM_CLIENT, "say_team", SV_Say_Team_f, "send a chat message to your team on the server");
1637 Cmd_AddCommand(CF_SHARED | CF_SERVER_FROM_CLIENT, "tell", SV_Tell_f, "send a chat message to only one person on the server");
1638 Cmd_AddCommand(CF_SERVER | CF_SERVER_FROM_CLIENT, "pause", SV_Pause_f, "pause the game (if the server allows pausing)");
1639 Cmd_AddCommand(CF_SHARED, "kick", SV_Kick_f, "kick a player off the server by number or name");
1640 Cmd_AddCommand(CF_SHARED | CF_SERVER_FROM_CLIENT, "ping", SV_Ping_f, "print ping times of all players on the server");
1641 Cmd_AddCommand(CF_SHARED, "load", SV_Loadgame_f, "load a saved game file");
1642 Cmd_AddCommand(CF_SHARED, "save", SV_Savegame_f, "save the game to a file");
1643 Cmd_AddCommand(CF_SHARED, "viewmodel", SV_Viewmodel_f, "change model of viewthing entity in current level");
1644 Cmd_AddCommand(CF_SHARED, "viewframe", SV_Viewframe_f, "change animation frame of viewthing entity in current level");
1645 Cmd_AddCommand(CF_SHARED, "viewnext", SV_Viewnext_f, "change to next animation frame of viewthing entity in current level");
1646 Cmd_AddCommand(CF_SHARED, "viewprev", SV_Viewprev_f, "change to previous animation frame of viewthing entity in current level");
1647 Cmd_AddCommand(CF_SHARED, "maxplayers", SV_MaxPlayers_f, "sets limit on how many players (or bots) may be connected to the server at once");
1648 Cmd_AddCommand(CF_SERVER, "sendcvar", SV_SendCvar_f, "sends the value of a cvar to the server as a sentcvar command, for use by QuakeC");
1650 // 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)
1651 Cmd_AddCommand(CF_SERVER_FROM_CLIENT, "prespawn", SV_PreSpawn_f, "internal use - signon 1 (client acknowledges that server information has been received)");
1652 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)");
1653 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)");
1654 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)");
1656 Cmd_AddCommand(CF_CHEAT | CF_SERVER_FROM_CLIENT, "god", SV_God_f, "god mode (invulnerability)");
1657 Cmd_AddCommand(CF_CHEAT | CF_SERVER_FROM_CLIENT, "notarget", SV_Notarget_f, "notarget mode (monsters do not see you)");
1658 Cmd_AddCommand(CF_CHEAT | CF_SERVER_FROM_CLIENT, "fly", SV_Fly_f, "fly mode (flight)");
1659 Cmd_AddCommand(CF_CHEAT | CF_SERVER_FROM_CLIENT, "noclip", SV_Noclip_f, "noclip mode (flight without collisions, move through walls)");
1660 Cmd_AddCommand(CF_CHEAT | CF_SERVER_FROM_CLIENT, "give", SV_Give_f, "alter inventory");
1661 Cmd_AddCommand(CF_SERVER_FROM_CLIENT, "kill", SV_Kill_f, "die instantly");
1663 Cmd_AddCommand(CF_USERINFO, "color", SV_Color_f, "change your player shirt and pants colors");
1664 Cmd_AddCommand(CF_USERINFO, "name", SV_Name_f, "change your player name");
1665 Cmd_AddCommand(CF_USERINFO, "rate", SV_Rate_f, "change your network connection speed");
1666 Cmd_AddCommand(CF_USERINFO, "rate_burstsize", SV_Rate_BurstSize_f, "change your network connection speed");
1667 Cmd_AddCommand(CF_USERINFO, "pmodel", SV_PModel_f, "(Nehahra-only) change your player model choice");
1668 Cmd_AddCommand(CF_USERINFO, "playermodel", SV_Playermodel_f, "change your player model");
1669 Cmd_AddCommand(CF_USERINFO, "playerskin", SV_Playerskin_f, "change your player skin number");
1671 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.");
1672 Cmd_AddCommand(CF_CHEAT | CF_SERVER_FROM_CLIENT, "ent_remove_all", SV_Ent_Remove_All_f, "Removes all entities of the specified classname");
1673 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");