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 if (Cmd_Argc(cmd) != 2)
54 Con_Print("map <levelname> : start a new game (kicks off all players)\n");
58 // GAME_DELUXEQUAKE - clear warpmark (used by QC)
59 if (gamemode == GAME_DELUXEQUAKE)
60 Cvar_Set(&cvars_all, "warpmark", "");
62 if(host.hook.Disconnect)
63 host.hook.Disconnect(false, NULL);
67 if(svs.maxclients != svs.maxclients_next)
69 svs.maxclients = svs.maxclients_next;
71 Mem_Free(svs.clients);
72 svs.clients = (client_t *)Mem_Alloc(sv_mempool, sizeof(client_t) * svs.maxclients);
75 if(host.hook.ToggleMenu)
76 host.hook.ToggleMenu();
78 svs.serverflags = 0; // haven't completed an episode yet
79 SV_SpawnServer(Cmd_Argv(cmd, 1));
81 if(sv.active && host.hook.ConnectLocal != NULL)
82 host.hook.ConnectLocal();
89 Goes to a new map, taking all clients along
92 static void SV_Changelevel_f(cmd_state_t *cmd)
94 if (Cmd_Argc(cmd) != 2)
96 Con_Print("changelevel <levelname> : continue game on a new level\n");
106 if(host.hook.ToggleMenu)
107 host.hook.ToggleMenu();
109 SV_SaveSpawnparms ();
110 SV_SpawnServer(Cmd_Argv(cmd, 1));
112 if(sv.active && host.hook.ConnectLocal != NULL)
113 host.hook.ConnectLocal();
120 Restarts the current server for a dead player
123 static void SV_Restart_f(cmd_state_t *cmd)
125 if (Cmd_Argc(cmd) != 1)
127 Con_Print("restart : restart current level\n");
132 Con_Print("Only the server may restart\n");
136 if(host.hook.ToggleMenu)
137 host.hook.ToggleMenu();
139 SV_SpawnServer(sv.worldbasename);
141 if(sv.active && host.hook.ConnectLocal != NULL)
142 host.hook.ConnectLocal();
145 //===========================================================================
147 // Disable cheats if sv_cheats is turned off
148 static void SV_DisableCheats_c(cvar_t *var)
150 prvm_prog_t *prog = SVVM_prog;
153 if (prog->loaded && var->value == 0)
155 for (i = 0; i < svs.maxclients; ++i)
157 if (((int)PRVM_serveredictfloat(svs.clients[i].edict, flags) & FL_GODMODE))
158 PRVM_serveredictfloat(svs.clients[i].edict, flags) = (int)PRVM_serveredictfloat(svs.clients[i].edict, flags) ^ FL_GODMODE;
159 if (((int)PRVM_serveredictfloat(svs.clients[i].edict, flags) & FL_NOTARGET))
160 PRVM_serveredictfloat(svs.clients[i].edict, flags) = (int)PRVM_serveredictfloat(svs.clients[i].edict, flags) ^ FL_NOTARGET;
161 if (PRVM_serveredictfloat(svs.clients[i].edict, movetype) == MOVETYPE_NOCLIP ||
162 PRVM_serveredictfloat(svs.clients[i].edict, movetype) == MOVETYPE_FLY)
164 noclip_anglehack = false;
165 PRVM_serveredictfloat(svs.clients[i].edict, movetype) = MOVETYPE_WALK;
175 Sets client to godmode
178 static void SV_God_f(cmd_state_t *cmd)
180 prvm_prog_t *prog = SVVM_prog;
182 PRVM_serveredictfloat(host_client->edict, flags) = (int)PRVM_serveredictfloat(host_client->edict, flags) ^ FL_GODMODE;
183 if (!((int)PRVM_serveredictfloat(host_client->edict, flags) & FL_GODMODE) )
184 SV_ClientPrint("godmode OFF\n");
186 SV_ClientPrint("godmode ON\n");
189 qbool noclip_anglehack;
191 static void SV_Noclip_f(cmd_state_t *cmd)
193 prvm_prog_t *prog = SVVM_prog;
195 if (PRVM_serveredictfloat(host_client->edict, movetype) != MOVETYPE_NOCLIP)
197 noclip_anglehack = true;
198 PRVM_serveredictfloat(host_client->edict, movetype) = MOVETYPE_NOCLIP;
199 SV_ClientPrint("noclip ON\n");
203 noclip_anglehack = false;
204 PRVM_serveredictfloat(host_client->edict, movetype) = MOVETYPE_WALK;
205 SV_ClientPrint("noclip OFF\n");
214 static void SV_Give_f(cmd_state_t *cmd)
216 prvm_prog_t *prog = SVVM_prog;
220 t = Cmd_Argv(cmd, 1);
221 v = atoi (Cmd_Argv(cmd, 2));
235 // MED 01/04/97 added hipnotic give stuff
236 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_QUOTH)
241 PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | HIT_PROXIMITY_GUN;
243 PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | IT_GRENADE_LAUNCHER;
245 else if (t[0] == '9')
246 PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | HIT_LASER_CANNON;
247 else if (t[0] == '0')
248 PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | HIT_MJOLNIR;
249 else if (t[0] >= '2')
250 PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | (IT_SHOTGUN << (t[0] - '2'));
255 PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | (IT_SHOTGUN << (t[0] - '2'));
260 if (gamemode == GAME_ROGUE)
261 PRVM_serveredictfloat(host_client->edict, ammo_shells1) = v;
263 PRVM_serveredictfloat(host_client->edict, ammo_shells) = v;
266 if (gamemode == GAME_ROGUE)
268 PRVM_serveredictfloat(host_client->edict, ammo_nails1) = v;
269 if (PRVM_serveredictfloat(host_client->edict, weapon) <= IT_LIGHTNING)
270 PRVM_serveredictfloat(host_client->edict, ammo_nails) = v;
274 PRVM_serveredictfloat(host_client->edict, ammo_nails) = v;
278 if (gamemode == GAME_ROGUE)
280 PRVM_serveredictfloat(host_client->edict, ammo_lava_nails) = v;
281 if (PRVM_serveredictfloat(host_client->edict, weapon) > IT_LIGHTNING)
282 PRVM_serveredictfloat(host_client->edict, ammo_nails) = v;
286 if (gamemode == GAME_ROGUE)
288 PRVM_serveredictfloat(host_client->edict, ammo_rockets1) = v;
289 if (PRVM_serveredictfloat(host_client->edict, weapon) <= IT_LIGHTNING)
290 PRVM_serveredictfloat(host_client->edict, ammo_rockets) = v;
294 PRVM_serveredictfloat(host_client->edict, ammo_rockets) = v;
298 if (gamemode == GAME_ROGUE)
300 PRVM_serveredictfloat(host_client->edict, ammo_multi_rockets) = v;
301 if (PRVM_serveredictfloat(host_client->edict, weapon) > IT_LIGHTNING)
302 PRVM_serveredictfloat(host_client->edict, ammo_rockets) = v;
306 PRVM_serveredictfloat(host_client->edict, health) = v;
309 if (gamemode == GAME_ROGUE)
311 PRVM_serveredictfloat(host_client->edict, ammo_cells1) = v;
312 if (PRVM_serveredictfloat(host_client->edict, weapon) <= IT_LIGHTNING)
313 PRVM_serveredictfloat(host_client->edict, ammo_cells) = v;
317 PRVM_serveredictfloat(host_client->edict, ammo_cells) = v;
321 if (gamemode == GAME_ROGUE)
323 PRVM_serveredictfloat(host_client->edict, ammo_plasma) = v;
324 if (PRVM_serveredictfloat(host_client->edict, weapon) > IT_LIGHTNING)
325 PRVM_serveredictfloat(host_client->edict, ammo_cells) = v;
335 Sets client to flymode
338 static void SV_Fly_f(cmd_state_t *cmd)
340 prvm_prog_t *prog = SVVM_prog;
342 if (PRVM_serveredictfloat(host_client->edict, movetype) != MOVETYPE_FLY)
344 PRVM_serveredictfloat(host_client->edict, movetype) = MOVETYPE_FLY;
345 SV_ClientPrint("flymode ON\n");
349 PRVM_serveredictfloat(host_client->edict, movetype) = MOVETYPE_WALK;
350 SV_ClientPrint("flymode OFF\n");
354 static void SV_Notarget_f(cmd_state_t *cmd)
356 prvm_prog_t *prog = SVVM_prog;
358 PRVM_serveredictfloat(host_client->edict, flags) = (int)PRVM_serveredictfloat(host_client->edict, flags) ^ FL_NOTARGET;
359 if (!((int)PRVM_serveredictfloat(host_client->edict, flags) & FL_NOTARGET) )
360 SV_ClientPrint("notarget OFF\n");
362 SV_ClientPrint("notarget ON\n");
370 static void SV_Kill_f(cmd_state_t *cmd)
372 prvm_prog_t *prog = SVVM_prog;
373 if (PRVM_serveredictfloat(host_client->edict, health) <= 0)
375 SV_ClientPrint("Can't suicide -- already dead!\n");
379 PRVM_serverglobalfloat(time) = sv.time;
380 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict);
381 prog->ExecuteProgram(prog, PRVM_serverfunction(ClientKill), "QC function ClientKill is missing");
389 static void SV_Pause_f(cmd_state_t *cmd)
391 void (*print) (const char *fmt, ...);
392 if (cmd->source == src_local)
395 print = SV_ClientPrintf;
397 if (!pausable.integer && cmd->source == src_client && LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) != LHNETADDRESSTYPE_LOOP)
399 print("Pause not allowed.\n");
404 if (cmd->source != src_local)
405 SV_BroadcastPrintf("%s %spaused the game\n", host_client->name, sv.paused ? "" : "un");
406 else if(*(sv_adminnick.string))
407 SV_BroadcastPrintf("%s %spaused the game\n", sv_adminnick.string, sv.paused ? "" : "un");
409 SV_BroadcastPrintf("%s %spaused the game\n", hostname.string, sv.paused ? "" : "un");
410 // send notification to all clients
411 MSG_WriteByte(&sv.reliable_datagram, svc_setpause);
412 MSG_WriteByte(&sv.reliable_datagram, sv.paused);
415 static void SV_Say(cmd_state_t *cmd, qbool teamonly)
417 prvm_prog_t *prog = SVVM_prog;
422 // LadyHavoc: long say messages
424 qbool fromServer = false;
426 if (cmd->source == src_local)
432 if (Cmd_Argc (cmd) < 2)
435 if (!teamplay.integer)
445 // note this uses the chat prefix \001
446 if (!fromServer && !teamonly)
447 dpsnprintf (text, sizeof(text), "\001%s: %s", host_client->name, p1);
448 else if (!fromServer && teamonly)
449 dpsnprintf (text, sizeof(text), "\001(%s): %s", host_client->name, p1);
450 else if(*(sv_adminnick.string))
451 dpsnprintf (text, sizeof(text), "\001<%s> %s", sv_adminnick.string, p1);
453 dpsnprintf (text, sizeof(text), "\001<%s> %s", hostname.string, p1);
454 p2 = text + strlen(text);
455 while ((const char *)p2 > (const char *)text && (p2[-1] == '\r' || p2[-1] == '\n' || (p2[-1] == '\"' && quoted)))
457 if (p2[-1] == '\"' && quoted)
462 dp_strlcat(text, "\n", sizeof(text));
464 // note: save is not a valid edict if fromServer is true
466 for (j = 0, host_client = svs.clients;j < svs.maxclients;j++, host_client++)
467 if (host_client->active && (!teamonly || PRVM_serveredictfloat(host_client->edict, team) == PRVM_serveredictfloat(save->edict, team)))
468 SV_ClientPrint(text);
471 if(!host_isclient.integer)
475 static void SV_Say_f(cmd_state_t *cmd)
480 static void SV_Say_Team_f(cmd_state_t *cmd)
485 static void SV_Tell_f(cmd_state_t *cmd)
487 const char *playername_start = NULL;
488 size_t playername_length = 0;
489 int playernumber = 0;
493 char text[MAX_INPUTLINE]; // LadyHavoc: FIXME: temporary buffer overflow fix (was 64)
494 qbool fromServer = false;
496 if (cmd->source == src_local)
499 if (Cmd_Argc (cmd) < 2)
502 // note this uses the chat prefix \001
504 dpsnprintf (text, sizeof(text), "\001%s tells you: ", host_client->name);
505 else if(*(sv_adminnick.string))
506 dpsnprintf (text, sizeof(text), "\001<%s tells you> ", sv_adminnick.string);
508 dpsnprintf (text, sizeof(text), "\001<%s tells you> ", hostname.string);
511 p2 = p1 + strlen(p1);
512 // remove the target name
513 while (p1 < p2 && *p1 == ' ')
518 while (p1 < p2 && *p1 == ' ')
520 while (p1 < p2 && isdigit(*p1))
522 playernumber = playernumber * 10 + (*p1 - '0');
530 playername_start = p1;
531 while (p1 < p2 && *p1 != '"')
533 playername_length = p1 - playername_start;
539 playername_start = p1;
540 while (p1 < p2 && *p1 != ' ')
542 playername_length = p1 - playername_start;
544 while (p1 < p2 && *p1 == ' ')
548 // set playernumber to the right client
550 if(playername_length >= sizeof(namebuf))
553 Con_Print("Host_Tell: too long player name/ID\n");
555 SV_ClientPrint("Host_Tell: too long player name/ID\n");
558 memcpy(namebuf, playername_start, playername_length);
559 namebuf[playername_length] = 0;
560 for (playernumber = 0; playernumber < svs.maxclients; playernumber++)
562 if (!svs.clients[playernumber].active)
564 if (strcasecmp(svs.clients[playernumber].name, namebuf) == 0)
568 if(playernumber < 0 || playernumber >= svs.maxclients || !(svs.clients[playernumber].active))
571 Con_Print("Host_Tell: invalid player name/ID\n");
573 SV_ClientPrint("Host_Tell: invalid player name/ID\n");
576 // remove trailing newlines
577 while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
579 // remove quotes if present
586 Con_Print("Host_Tell: missing end quote\n");
588 SV_ClientPrint("Host_Tell: missing end quote\n");
590 while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
594 for (j = (int)strlen(text);j < (int)(sizeof(text) - 2) && p1 < p2;)
600 host_client = svs.clients + playernumber;
601 SV_ClientPrint(text);
611 static void SV_Ping_f(cmd_state_t *cmd)
615 void (*print) (const char *fmt, ...);
617 if (cmd->source == src_local)
620 print = SV_ClientPrintf;
625 print("Client ping times:\n");
626 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
630 print("%4i %s\n", bound(0, (int)floor(client->ping*1000+0.5), 9999), client->name);
638 Send back ping and packet loss update for all current players to this player
641 static void SV_Pings_f(cmd_state_t *cmd)
643 int i, j, ping, packetloss, movementloss;
646 if (!host_client->netconnection)
649 if (sv.protocol != PROTOCOL_QUAKEWORLD)
651 MSG_WriteByte(&host_client->netconnection->message, svc_stufftext);
652 MSG_WriteUnterminatedString(&host_client->netconnection->message, "pingplreport");
654 for (i = 0;i < svs.maxclients;i++)
658 if (svs.clients[i].netconnection)
660 for (j = 0;j < NETGRAPH_PACKETS;j++)
661 if (svs.clients[i].netconnection->incoming_netgraph[j].unreliablebytes == NETGRAPH_LOSTPACKET)
663 for (j = 0;j < NETGRAPH_PACKETS;j++)
664 if (svs.clients[i].movement_count[j] < 0)
667 packetloss = (packetloss * 100 + NETGRAPH_PACKETS - 1) / NETGRAPH_PACKETS;
668 movementloss = (movementloss * 100 + NETGRAPH_PACKETS - 1) / NETGRAPH_PACKETS;
669 ping = (int)floor(svs.clients[i].ping*1000+0.5);
670 ping = bound(0, ping, 9999);
671 if (sv.protocol == PROTOCOL_QUAKEWORLD)
673 // send qw_svc_updateping and qw_svc_updatepl messages
674 MSG_WriteByte(&host_client->netconnection->message, qw_svc_updateping);
675 MSG_WriteShort(&host_client->netconnection->message, ping);
676 MSG_WriteByte(&host_client->netconnection->message, qw_svc_updatepl);
677 MSG_WriteByte(&host_client->netconnection->message, packetloss);
681 // write the string into the packet as multiple unterminated strings to avoid needing a local buffer
683 dpsnprintf(temp, sizeof(temp), " %d %d,%d", ping, packetloss, movementloss);
685 dpsnprintf(temp, sizeof(temp), " %d %d", ping, packetloss);
686 MSG_WriteUnterminatedString(&host_client->netconnection->message, temp);
689 if (sv.protocol != PROTOCOL_QUAKEWORLD)
690 MSG_WriteString(&host_client->netconnection->message, "\n");
698 static void SV_Status_f(cmd_state_t *cmd)
700 prvm_prog_t *prog = SVVM_prog;
703 int seconds = 0, minutes = 0, hours = 0, i, j, k, in, players, ping = 0, packetloss = 0;
704 void (*print) (const char *fmt, ...);
705 char ip[48]; // can contain a full length v6 address with [] and a port
709 if (cmd->source == src_local)
712 print = SV_ClientPrintf;
718 if (Cmd_Argc(cmd) == 2)
720 if (strcmp(Cmd_Argv(cmd, 1), "1") == 0)
722 else if (strcmp(Cmd_Argv(cmd, 1), "2") == 0)
726 for (players = 0, i = 0;i < svs.maxclients;i++)
727 if (svs.clients[i].active)
730 print ("host: %s\n", Cvar_VariableString (&cvars_all, "hostname", CF_SERVER));
731 print ("version: %s\n", engineversion);
732 print ("protocol: %i (%s)\n", Protocol_NumberForEnum(sv.protocol), Protocol_NameForEnum(sv.protocol));
733 print ("map: %s\n", sv.worldbasename);
734 print ("timing: %s\n", SV_TimingReport(vabuf, sizeof(vabuf)));
735 print ("players: %i active (%i max)\n\n", players, svs.maxclients);
738 print ("^2IP %%pl ping time frags no name\n");
740 print ("^5IP no name\n");
742 for (i = 0, k = 0, client = svs.clients;i < svs.maxclients;i++, client++)
749 if (in == 0 || in == 1)
751 seconds = (int)(host.realtime - client->connecttime);
752 minutes = seconds / 60;
755 seconds -= (minutes * 60);
756 hours = minutes / 60;
758 minutes -= (hours * 60);
764 if (client->netconnection)
765 for (j = 0;j < NETGRAPH_PACKETS;j++)
766 if (client->netconnection->incoming_netgraph[j].unreliablebytes == NETGRAPH_LOSTPACKET)
768 packetloss = (packetloss * 100 + NETGRAPH_PACKETS - 1) / NETGRAPH_PACKETS;
769 ping = bound(0, (int)floor(client->ping*1000+0.5), 9999);
772 if(sv_status_privacy.integer && cmd->source != src_local && LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) != LHNETADDRESSTYPE_LOOP)
773 dp_strlcpy(ip, client->netconnection ? "hidden" : "botclient", 48);
775 dp_strlcpy(ip, (client->netconnection && *client->netconnection->address) ? client->netconnection->address : "botclient", 48);
777 frags = client->frags;
779 if(sv_status_show_qcstatus.integer)
781 prvm_edict_t *ed = PRVM_EDICT_NUM(i + 1);
782 const char *str = PRVM_GetString(prog, PRVM_serveredictstring(ed, clientstatus));
788 for(q = str; *q && p != qcstatus + sizeof(qcstatus) - 1; ++q)
789 if(*q != '\\' && *q != '"' && !ISWHITESPACE(*q))
793 frags = atoi(qcstatus);
797 if (in == 0) // default layout
799 if (sv.protocol == PROTOCOL_QUAKE && svs.maxclients <= 99)
801 // LadyHavoc: this is very touchy because we must maintain ProQuake compatible status output
802 print ("#%-2u %-16.16s %3i %2i:%02i:%02i\n", i+1, client->name, frags, hours, minutes, seconds);
807 // LadyHavoc: no real restrictions here, not a ProQuake-compatible protocol anyway...
808 print ("#%-3u %-16.16s %4i %2i:%02i:%02i\n", i+1, client->name, frags, hours, minutes, seconds);
812 else if (in == 1) // extended layout
814 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);
816 else if (in == 2) // reduced layout
818 print ("%s%-47s #%-3u ^7%s\n", k%2 ? "^3" : "^7", ip, i+1, client->name);
823 void SV_Name(int clientnum)
825 prvm_prog_t *prog = SVVM_prog;
826 PRVM_serveredictstring(host_client->edict, netname) = PRVM_SetEngineString(prog, host_client->name);
827 if (strcmp(host_client->old_name, host_client->name))
829 if (host_client->begun)
830 SV_BroadcastPrintf("\003%s ^7changed name to ^3%s\n", host_client->old_name, host_client->name);
831 dp_strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
832 // send notification to all clients
833 MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
834 MSG_WriteByte (&sv.reliable_datagram, clientnum);
835 MSG_WriteString (&sv.reliable_datagram, host_client->name);
836 SV_WriteNetnameIntoDemo(host_client);
841 ======================
843 ======================
845 static void SV_Name_f(cmd_state_t *cmd)
849 const char *newNameSource;
850 char newName[sizeof(host_client->name)];
852 if (Cmd_Argc (cmd) == 1)
855 if (Cmd_Argc (cmd) == 2)
856 newNameSource = Cmd_Argv(cmd, 1);
858 newNameSource = Cmd_Args(cmd);
860 dp_strlcpy(newName, newNameSource, sizeof(newName));
862 if (cmd->source == src_local)
865 if (host.realtime < host_client->nametime && strcmp(newName, host_client->name))
867 SV_ClientPrintf("You can't change name more than once every %.1f seconds!\n", max(0.0f, sv_namechangetimer.value));
871 host_client->nametime = host.realtime + max(0.0f, sv_namechangetimer.value);
873 // point the string back at updateclient->name to keep it safe
874 dp_strlcpy (host_client->name, newName, sizeof (host_client->name));
876 for (i = 0, j = 0;host_client->name[i];i++)
877 if (host_client->name[i] != '\r' && host_client->name[i] != '\n')
878 host_client->name[j++] = host_client->name[i];
879 host_client->name[j] = 0;
881 if(host_client->name[0] == 1 || host_client->name[0] == 2)
882 // may interfere with chat area, and will needlessly beep; so let's add a ^7
884 memmove(host_client->name + 2, host_client->name, sizeof(host_client->name) - 2);
885 host_client->name[sizeof(host_client->name) - 1] = 0;
886 host_client->name[0] = STRING_COLOR_TAG;
887 host_client->name[1] = '0' + STRING_COLOR_DEFAULT;
890 u8_COM_StringLengthNoColors(host_client->name, 0, &valid_colors);
891 if(!valid_colors) // NOTE: this also proves the string is not empty, as "" is a valid colored string
894 l = strlen(host_client->name);
895 if(l < sizeof(host_client->name) - 1)
897 // duplicate the color tag to escape it
898 host_client->name[i] = STRING_COLOR_TAG;
899 host_client->name[i+1] = 0;
900 //Con_DPrintf("abuse detected, adding another trailing color tag\n");
904 // remove the last character to fix the color code
905 host_client->name[l-1] = 0;
906 //Con_DPrintf("abuse detected, removing a trailing color tag\n");
910 // find the last color tag offset and decide if we need to add a reset tag
911 for (i = 0, j = -1;host_client->name[i];i++)
913 if (host_client->name[i] == STRING_COLOR_TAG)
915 if (host_client->name[i+1] >= '0' && host_client->name[i+1] <= '9')
918 // if this happens to be a reset tag then we don't need one
919 if (host_client->name[i+1] == '0' + STRING_COLOR_DEFAULT)
924 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]))
930 if (host_client->name[i+1] == STRING_COLOR_TAG)
937 // does not end in the default color string, so add it
938 if (j >= 0 && strlen(host_client->name) < sizeof(host_client->name) - 2)
939 memcpy(host_client->name + strlen(host_client->name), STRING_COLOR_DEFAULT_STR, strlen(STRING_COLOR_DEFAULT_STR) + 1);
941 SV_Name(host_client - svs.clients);
944 static void SV_Rate_f(cmd_state_t *cmd)
948 rate = atoi(Cmd_Argv(cmd, 1));
950 if (cmd->source == src_local)
953 host_client->rate = rate;
956 static void SV_Rate_BurstSize_f(cmd_state_t *cmd)
960 if (Cmd_Argc(cmd) != 2)
963 rate_burstsize = atoi(Cmd_Argv(cmd, 1));
965 host_client->rate_burstsize = rate_burstsize;
968 static void SV_Color_f(cmd_state_t *cmd)
970 prvm_prog_t *prog = SVVM_prog;
972 int top, bottom, playercolor;
974 top = atoi(Cmd_Argv(cmd, 1));
975 bottom = atoi(Cmd_Argv(cmd, 2));
980 playercolor = top*16 + bottom;
982 if (host_client->edict && PRVM_serverfunction(SV_ChangeTeam))
984 Con_DPrint("Calling SV_ChangeTeam\n");
985 prog->globals.fp[OFS_PARM0] = playercolor;
986 PRVM_serverglobalfloat(time) = sv.time;
987 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict);
988 prog->ExecuteProgram(prog, PRVM_serverfunction(SV_ChangeTeam), "QC function SV_ChangeTeam is missing");
992 if (host_client->edict)
994 PRVM_serveredictfloat(host_client->edict, clientcolors) = playercolor;
995 PRVM_serveredictfloat(host_client->edict, team) = bottom + 1;
997 host_client->colors = playercolor;
998 if (host_client->old_colors != host_client->colors)
1000 host_client->old_colors = host_client->colors;
1001 // send notification to all clients
1002 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1003 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1004 MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1013 Kicks a user off of the server
1016 static void SV_Kick_f(cmd_state_t *cmd)
1019 const char *message = NULL;
1023 qbool byNumber = false;
1030 if (Cmd_Argc(cmd) > 2 && strcmp(Cmd_Argv(cmd, 1), "#") == 0)
1032 i = (int)(atof(Cmd_Argv(cmd, 2)) - 1);
1033 if (i < 0 || i >= svs.maxclients || !(host_client = svs.clients + i)->active)
1039 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1041 if (!host_client->active)
1043 if (strcasecmp(host_client->name, Cmd_Argv(cmd, 1)) == 0)
1048 if (i < svs.maxclients)
1050 if (cmd->source == src_local)
1052 if(!host_isclient.integer)
1055 who = cl_name.string;
1060 // can't kick yourself!
1061 if (host_client == save)
1064 if (Cmd_Argc(cmd) > 2)
1066 message = Cmd_Args(cmd);
1067 COM_ParseToken_Simple(&message, false, false, true);
1070 message++; // skip the #
1071 while (*message == ' ') // skip white space
1073 message += strlen(Cmd_Argv(cmd, 2)); // skip the number
1075 while (*message && *message == ' ')
1079 SV_DropClient (false, va(reason, sizeof(reason), "Kicked by %s: %s", who, message)); // kicked
1080 //SV_ClientPrintf("Kicked by %s: %s\n", who, message);
1082 //SV_ClientPrintf("Kicked by %s\n", who);
1083 SV_DropClient (false, va(reason, sizeof(reason), "Kicked by %s", who)); // kicked
1089 static void SV_MaxPlayers_f(cmd_state_t *cmd)
1093 if (Cmd_Argc(cmd) != 2)
1095 Con_Printf("\"maxplayers\" is \"%u\"\n", svs.maxclients_next);
1101 Con_Print("maxplayers can not be changed while a server is running.\n");
1102 Con_Print("It will be changed on next server startup (\"map\" command).\n");
1105 n = atoi(Cmd_Argv(cmd, 1));
1106 n = bound(1, n, MAX_SCOREBOARD);
1107 Con_Printf("\"maxplayers\" set to \"%u\"\n", n);
1109 svs.maxclients_next = n;
1111 Cvar_Set (&cvars_all, "deathmatch", "0");
1113 Cvar_Set (&cvars_all, "deathmatch", "1");
1117 ======================
1119 ======================
1121 // the old playermodel in cl_main has been renamed to __cl_playermodel
1122 static void SV_Playermodel_f(cmd_state_t *cmd)
1124 prvm_prog_t *prog = SVVM_prog;
1126 char newPath[sizeof(host_client->playermodel)];
1128 if (Cmd_Argc (cmd) == 1)
1131 if (Cmd_Argc (cmd) == 2)
1132 dp_strlcpy (newPath, Cmd_Argv(cmd, 1), sizeof (newPath));
1134 dp_strlcpy (newPath, Cmd_Args(cmd), sizeof (newPath));
1136 for (i = 0, j = 0;newPath[i];i++)
1137 if (newPath[i] != '\r' && newPath[i] != '\n')
1138 newPath[j++] = newPath[i];
1142 if (host.realtime < host_client->nametime)
1144 SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
1148 host_client->nametime = host.realtime + 5;
1151 // point the string back at updateclient->name to keep it safe
1152 dp_strlcpy (host_client->playermodel, newPath, sizeof (host_client->playermodel));
1153 PRVM_serveredictstring(host_client->edict, playermodel) = PRVM_SetEngineString(prog, host_client->playermodel);
1154 if (strcmp(host_client->old_model, host_client->playermodel))
1156 dp_strlcpy(host_client->old_model, host_client->playermodel, sizeof(host_client->old_model));
1157 /*// send notification to all clients
1158 MSG_WriteByte (&sv.reliable_datagram, svc_updatepmodel);
1159 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1160 MSG_WriteString (&sv.reliable_datagram, host_client->playermodel);*/
1165 ======================
1167 ======================
1169 static void SV_Playerskin_f(cmd_state_t *cmd)
1171 prvm_prog_t *prog = SVVM_prog;
1173 char newPath[sizeof(host_client->playerskin)];
1175 if (Cmd_Argc (cmd) == 1)
1178 if (Cmd_Argc (cmd) == 2)
1179 dp_strlcpy (newPath, Cmd_Argv(cmd, 1), sizeof (newPath));
1181 dp_strlcpy (newPath, Cmd_Args(cmd), sizeof (newPath));
1183 for (i = 0, j = 0;newPath[i];i++)
1184 if (newPath[i] != '\r' && newPath[i] != '\n')
1185 newPath[j++] = newPath[i];
1189 if (host.realtime < host_client->nametime)
1191 SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
1195 host_client->nametime = host.realtime + 5;
1198 // point the string back at updateclient->name to keep it safe
1199 dp_strlcpy (host_client->playerskin, newPath, sizeof (host_client->playerskin));
1200 PRVM_serveredictstring(host_client->edict, playerskin) = PRVM_SetEngineString(prog, host_client->playerskin);
1201 if (strcmp(host_client->old_skin, host_client->playerskin))
1203 //if (host_client->begun)
1204 // SV_BroadcastPrintf("%s changed skin to %s\n", host_client->name, host_client->playerskin);
1205 dp_strlcpy(host_client->old_skin, host_client->playerskin, sizeof(host_client->old_skin));
1206 /*// send notification to all clients
1207 MSG_WriteByte (&sv.reliable_datagram, svc_updatepskin);
1208 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1209 MSG_WriteString (&sv.reliable_datagram, host_client->playerskin);*/
1214 ======================
1216 LadyHavoc: only supported for Nehahra, I personally think this is dumb, but Mindcrime won't listen.
1217 LadyHavoc: correction, Mindcrime will be removing pmodel in the future, but it's still stuck here for compatibility.
1218 ======================
1220 static void SV_PModel_f(cmd_state_t *cmd)
1222 prvm_prog_t *prog = SVVM_prog;
1224 if (Cmd_Argc (cmd) == 1)
1227 PRVM_serveredictfloat(host_client->edict, pmodel) = atoi(Cmd_Argv(cmd, 1));
1231 ===============================================================================
1235 ===============================================================================
1238 static prvm_edict_t *FindViewthing(prvm_prog_t *prog)
1243 for (i=0 ; i<prog->num_edicts ; i++)
1245 e = PRVM_EDICT_NUM(i);
1246 if (!strcmp (PRVM_GetString(prog, PRVM_serveredictstring(e, classname)), "viewthing"))
1249 Con_Print("No viewthing on map\n");
1258 static void SV_Viewmodel_f(cmd_state_t *cmd)
1260 prvm_prog_t *prog = SVVM_prog;
1267 e = FindViewthing(prog);
1270 m = Mod_ForName (Cmd_Argv(cmd, 1), false, true, NULL);
1271 if (m && m->loaded && m->Draw)
1273 PRVM_serveredictfloat(e, frame) = 0;
1274 cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)] = m;
1277 Con_Printf("viewmodel: can't load %s\n", Cmd_Argv(cmd, 1));
1286 static void SV_Viewframe_f(cmd_state_t *cmd)
1288 prvm_prog_t *prog = SVVM_prog;
1296 e = FindViewthing(prog);
1299 m = cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)];
1301 f = atoi(Cmd_Argv(cmd, 1));
1302 if (f >= m->numframes)
1305 PRVM_serveredictfloat(e, frame) = f;
1309 static void PrintFrameName (model_t *m, int frame)
1312 Con_Printf("frame %i: %s\n", frame, m->animscenes[frame].name);
1314 Con_Printf("frame %i\n", frame);
1322 static void SV_Viewnext_f(cmd_state_t *cmd)
1324 prvm_prog_t *prog = SVVM_prog;
1331 e = FindViewthing(prog);
1334 m = cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)];
1336 PRVM_serveredictfloat(e, frame) = PRVM_serveredictfloat(e, frame) + 1;
1337 if (PRVM_serveredictfloat(e, frame) >= m->numframes)
1338 PRVM_serveredictfloat(e, frame) = m->numframes - 1;
1340 PrintFrameName (m, (int)PRVM_serveredictfloat(e, frame));
1349 static void SV_Viewprev_f(cmd_state_t *cmd)
1351 prvm_prog_t *prog = SVVM_prog;
1358 e = FindViewthing(prog);
1361 m = cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)];
1363 PRVM_serveredictfloat(e, frame) = PRVM_serveredictfloat(e, frame) - 1;
1364 if (PRVM_serveredictfloat(e, frame) < 0)
1365 PRVM_serveredictfloat(e, frame) = 0;
1367 PrintFrameName (m, (int)PRVM_serveredictfloat(e, frame));
1371 static void SV_SendCvar_f(cmd_state_t *cmd)
1374 const char *cvarname;
1377 if(Cmd_Argc(cmd) != 2)
1380 if(!sv.active)// || !PRVM_serverfunction(SV_ParseClientCommand))
1383 cvarname = Cmd_Argv(cmd, 1);
1386 if(host_isclient.integer)
1390 for(;i<svs.maxclients;i++)
1391 if(svs.clients[i].active && svs.clients[i].netconnection)
1393 host_client = &svs.clients[i];
1394 SV_ClientCommands("sendcvar %s\n", cvarname);
1399 static void SV_Ent_Create_f(cmd_state_t *cmd)
1401 prvm_prog_t *prog = SVVM_prog;
1407 void (*print)(const char *, ...) = (cmd->source == src_client ? SV_ClientPrintf : Con_Printf);
1412 ed = PRVM_ED_Alloc(SVVM_prog);
1414 PRVM_ED_ParseEpair(prog, ed, PRVM_ED_FindField(prog, "classname"), Cmd_Argv(cmd, 1), false);
1416 // Spawn where the player is aiming. We need a view matrix first.
1417 if(cmd->source == src_client)
1419 vec3_t org, temp, dest;
1424 SV_GetEntityMatrix(prog, host_client->edict, &view, true);
1426 Matrix4x4_OriginFromMatrix(&view, org);
1427 VectorSet(temp, 65536, 0, 0);
1428 Matrix4x4_Transform(&view, temp, dest);
1430 trace = SV_TraceLine(org, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, 0, 0, collision_extendmovelength.value);
1432 dpsnprintf(buf, sizeof(buf), "%g %g %g", trace.endpos[0], trace.endpos[1], trace.endpos[2]);
1433 PRVM_ED_ParseEpair(prog, ed, PRVM_ED_FindField(prog, "origin"), buf, false);
1437 // Or spawn at a specified origin.
1444 // Allow more than one key/value pair by cycling between expecting either one.
1445 for(i = 2; i < Cmd_Argc(cmd); i += 2)
1447 if(!(key = PRVM_ED_FindField(prog, Cmd_Argv(cmd, i))))
1449 print("Key %s not found!\n", Cmd_Argv(cmd, i));
1450 PRVM_ED_Free(prog, ed);
1455 * This is mostly for dedicated server console, but if the
1456 * player gave a custom origin, we can ignore the traceline.
1458 if(!strcmp(Cmd_Argv(cmd, i), "origin"))
1461 if (i + 1 < Cmd_Argc(cmd))
1462 PRVM_ED_ParseEpair(prog, ed, key, Cmd_Argv(cmd, i+1), false);
1467 print("Missing origin\n");
1468 PRVM_ED_Free(prog, ed);
1473 PRVM_ED_CallPrespawnFunction(prog, ed);
1475 if(!PRVM_ED_CallSpawnFunction(prog, ed, NULL, NULL))
1477 print("Could not spawn a \"%s\". No such entity or it has no spawn function\n", Cmd_Argv(cmd, 1));
1478 if(cmd->source == src_client)
1479 Con_Printf("%s tried to spawn a \"%s\"\n", host_client->name, Cmd_Argv(cmd, 1));
1480 // CallSpawnFunction already freed the edict for us.
1484 PRVM_ED_CallPostspawnFunction(prog, ed);
1486 // Make it appear in the world
1489 if(cmd->source == src_client)
1490 Con_Printf("%s spawned a \"%s\"\n", host_client->name, Cmd_Argv(cmd, 1));
1493 static void SV_Ent_Remove_f(cmd_state_t *cmd)
1495 prvm_prog_t *prog = SVVM_prog;
1498 void (*print)(const char *, ...) = (cmd->source == src_client ? SV_ClientPrintf : Con_Printf);
1503 // Allow specifying edict by number
1504 if(Cmd_Argc(cmd) > 1 && Cmd_Argv(cmd, 1))
1506 ednum = atoi(Cmd_Argv(cmd, 1));
1509 print("Cannot remove the world\n");
1513 // Or trace a line if it's a client who didn't specify one.
1514 else if(cmd->source == src_client)
1516 vec3_t org, temp, dest;
1520 SV_GetEntityMatrix(prog, host_client->edict, &view, true);
1522 Matrix4x4_OriginFromMatrix(&view, org);
1523 VectorSet(temp, 65536, 0, 0);
1524 Matrix4x4_Transform(&view, temp, dest);
1526 trace = SV_TraceLine(org, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY, 0, 0, collision_extendmovelength.value);
1529 ednum = (int)PRVM_EDICT_TO_PROG(trace.ent);
1530 if(!trace.ent || !ednum)
1531 // Don't remove the world, but don't annoy players with a print if they miss
1536 // Only a dedicated server console should be able to reach this.
1537 print("No edict given\n");
1541 ed = PRVM_EDICT_NUM(ednum);
1546 for (i = 0; i < svs.maxclients; i++)
1548 if(ed == svs.clients[i].edict)
1554 print("Removed a \"%s\"\n", PRVM_GetString(prog, PRVM_serveredictstring(ed, classname)));
1555 PRVM_ED_ClearEdict(prog, ed);
1556 PRVM_ED_Free(prog, ed);
1561 // This should only be reachable if an invalid edict number was given
1562 print("No such entity\n");
1567 static void SV_Ent_Remove_All_f(cmd_state_t *cmd)
1569 prvm_prog_t *prog = SVVM_prog;
1572 void (*print)(const char *, ...) = (cmd->source == src_client ? SV_ClientPrintf : Con_Printf);
1574 for (i = 0, rmcount = 0, ed = PRVM_EDICT_NUM(i); i < prog->num_edicts; i++, ed = PRVM_NEXT_EDICT(ed))
1576 if(!ed->free && !strcmp(PRVM_GetString(prog, PRVM_serveredictstring(ed, classname)), Cmd_Argv(cmd, 1)))
1580 print("Cannot remove the world\n");
1583 PRVM_ED_ClearEdict(prog, ed);
1584 PRVM_ED_Free(prog, ed);
1590 print("No \"%s\" found\n", Cmd_Argv(cmd, 1));
1592 print("Removed %i of \"%s\"\n", rmcount, Cmd_Argv(cmd, 1));
1595 void SV_InitOperatorCommands(void)
1597 Cvar_RegisterVariable(&sv_cheats);
1598 Cvar_RegisterCallback(&sv_cheats, SV_DisableCheats_c);
1599 Cvar_RegisterVariable(&sv_adminnick);
1600 Cvar_RegisterVariable(&sv_status_privacy);
1601 Cvar_RegisterVariable(&sv_status_show_qcstatus);
1602 Cvar_RegisterVariable(&sv_namechangetimer);
1604 Cmd_AddCommand(CF_SERVER | CF_SERVER_FROM_CLIENT, "status", SV_Status_f, "print server status information");
1605 Cmd_AddCommand(CF_SHARED, "map", SV_Map_f, "kick everyone off the server and start a new level");
1606 Cmd_AddCommand(CF_SHARED, "restart", SV_Restart_f, "restart current level");
1607 Cmd_AddCommand(CF_SHARED, "changelevel", SV_Changelevel_f, "change to another level, bringing along all connected clients (or start a new level if none is loaded)");
1608 Cmd_AddCommand(CF_SHARED | CF_SERVER_FROM_CLIENT, "say", SV_Say_f, "send a chat message to everyone on the server");
1609 Cmd_AddCommand(CF_SERVER_FROM_CLIENT, "say_team", SV_Say_Team_f, "send a chat message to your team on the server");
1610 Cmd_AddCommand(CF_SHARED | CF_SERVER_FROM_CLIENT, "tell", SV_Tell_f, "send a chat message to only one person on the server");
1611 Cmd_AddCommand(CF_SERVER | CF_SERVER_FROM_CLIENT, "pause", SV_Pause_f, "pause the game (if the server allows pausing)");
1612 Cmd_AddCommand(CF_SHARED, "kick", SV_Kick_f, "kick a player off the server by number or name");
1613 Cmd_AddCommand(CF_SHARED | CF_SERVER_FROM_CLIENT, "ping", SV_Ping_f, "print ping times of all players on the server");
1614 Cmd_AddCommand(CF_SHARED, "load", SV_Loadgame_f, "load a saved game file");
1615 Cmd_AddCommand(CF_SHARED, "save", SV_Savegame_f, "save the game to a file");
1616 Cmd_AddCommand(CF_SHARED, "viewmodel", SV_Viewmodel_f, "change model of viewthing entity in current level");
1617 Cmd_AddCommand(CF_SHARED, "viewframe", SV_Viewframe_f, "change animation frame of viewthing entity in current level");
1618 Cmd_AddCommand(CF_SHARED, "viewnext", SV_Viewnext_f, "change to next animation frame of viewthing entity in current level");
1619 Cmd_AddCommand(CF_SHARED, "viewprev", SV_Viewprev_f, "change to previous animation frame of viewthing entity in current level");
1620 Cmd_AddCommand(CF_SHARED, "maxplayers", SV_MaxPlayers_f, "sets limit on how many players (or bots) may be connected to the server at once");
1621 host.hook.SV_SendCvar = SV_SendCvar_f;
1623 // 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)
1624 Cmd_AddCommand(CF_SERVER_FROM_CLIENT, "prespawn", SV_PreSpawn_f, "internal use - signon 1 (client acknowledges that server information has been received)");
1625 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)");
1626 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)");
1627 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)");
1629 Cmd_AddCommand(CF_CHEAT | CF_SERVER_FROM_CLIENT, "god", SV_God_f, "god mode (invulnerability)");
1630 Cmd_AddCommand(CF_CHEAT | CF_SERVER_FROM_CLIENT, "notarget", SV_Notarget_f, "notarget mode (monsters do not see you)");
1631 Cmd_AddCommand(CF_CHEAT | CF_SERVER_FROM_CLIENT, "fly", SV_Fly_f, "fly mode (flight)");
1632 Cmd_AddCommand(CF_CHEAT | CF_SERVER_FROM_CLIENT, "noclip", SV_Noclip_f, "noclip mode (flight without collisions, move through walls)");
1633 Cmd_AddCommand(CF_CHEAT | CF_SERVER_FROM_CLIENT, "give", SV_Give_f, "alter inventory");
1634 Cmd_AddCommand(CF_SERVER_FROM_CLIENT, "kill", SV_Kill_f, "die instantly");
1636 Cmd_AddCommand(CF_USERINFO, "color", SV_Color_f, "change your player shirt and pants colors");
1637 Cmd_AddCommand(CF_USERINFO, "name", SV_Name_f, "change your player name");
1638 Cmd_AddCommand(CF_USERINFO, "rate", SV_Rate_f, "change your network connection speed");
1639 Cmd_AddCommand(CF_USERINFO, "rate_burstsize", SV_Rate_BurstSize_f, "change your network connection speed");
1640 Cmd_AddCommand(CF_USERINFO, "pmodel", SV_PModel_f, "(Nehahra-only) change your player model choice");
1641 Cmd_AddCommand(CF_USERINFO, "playermodel", SV_Playermodel_f, "change your player model");
1642 Cmd_AddCommand(CF_USERINFO, "playerskin", SV_Playerskin_f, "change your player skin number");
1644 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.");
1645 Cmd_AddCommand(CF_CHEAT | CF_SERVER_FROM_CLIENT, "ent_remove_all", SV_Ent_Remove_All_f, "Removes all entities of the specified classname");
1646 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");