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;
221 t = Cmd_Argv(cmd, 1);
222 v = atoi (Cmd_Argv(cmd, 2));
236 // MED 01/04/97 added hipnotic give stuff
237 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_QUOTH)
242 PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | HIT_PROXIMITY_GUN;
244 PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | IT_GRENADE_LAUNCHER;
246 else if (t[0] == '9')
247 PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | HIT_LASER_CANNON;
248 else if (t[0] == '0')
249 PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | HIT_MJOLNIR;
250 else if (t[0] >= '2')
251 PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | (IT_SHOTGUN << (t[0] - '2'));
256 PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | (IT_SHOTGUN << (t[0] - '2'));
261 if (gamemode == GAME_ROGUE)
262 PRVM_serveredictfloat(host_client->edict, ammo_shells1) = v;
264 PRVM_serveredictfloat(host_client->edict, ammo_shells) = v;
267 if (gamemode == GAME_ROGUE)
269 PRVM_serveredictfloat(host_client->edict, ammo_nails1) = v;
270 if (PRVM_serveredictfloat(host_client->edict, weapon) <= IT_LIGHTNING)
271 PRVM_serveredictfloat(host_client->edict, ammo_nails) = v;
275 PRVM_serveredictfloat(host_client->edict, ammo_nails) = v;
279 if (gamemode == GAME_ROGUE)
281 PRVM_serveredictfloat(host_client->edict, ammo_lava_nails) = v;
282 if (PRVM_serveredictfloat(host_client->edict, weapon) > IT_LIGHTNING)
283 PRVM_serveredictfloat(host_client->edict, ammo_nails) = v;
287 if (gamemode == GAME_ROGUE)
289 PRVM_serveredictfloat(host_client->edict, ammo_rockets1) = v;
290 if (PRVM_serveredictfloat(host_client->edict, weapon) <= IT_LIGHTNING)
291 PRVM_serveredictfloat(host_client->edict, ammo_rockets) = v;
295 PRVM_serveredictfloat(host_client->edict, ammo_rockets) = v;
299 if (gamemode == GAME_ROGUE)
301 PRVM_serveredictfloat(host_client->edict, ammo_multi_rockets) = v;
302 if (PRVM_serveredictfloat(host_client->edict, weapon) > IT_LIGHTNING)
303 PRVM_serveredictfloat(host_client->edict, ammo_rockets) = v;
307 PRVM_serveredictfloat(host_client->edict, health) = v;
310 if (gamemode == GAME_ROGUE)
312 PRVM_serveredictfloat(host_client->edict, ammo_cells1) = v;
313 if (PRVM_serveredictfloat(host_client->edict, weapon) <= IT_LIGHTNING)
314 PRVM_serveredictfloat(host_client->edict, ammo_cells) = v;
318 PRVM_serveredictfloat(host_client->edict, ammo_cells) = v;
322 if (gamemode == GAME_ROGUE)
324 PRVM_serveredictfloat(host_client->edict, ammo_plasma) = v;
325 if (PRVM_serveredictfloat(host_client->edict, weapon) > IT_LIGHTNING)
326 PRVM_serveredictfloat(host_client->edict, ammo_cells) = v;
331 // Set the player armour value to the number specified and then adjust the armour type/colour based on the value
333 player_items = PRVM_serveredictfloat(host_client->edict, items);
334 PRVM_serveredictfloat(host_client->edict, armorvalue) = v;
336 // Remove whichever armour item the player currently has
337 if (gamemode == GAME_ROGUE)
338 player_items &= ~(RIT_ARMOR1 | RIT_ARMOR2 | RIT_ARMOR3);
340 player_items &= ~(IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3);
345 PRVM_serveredictfloat(host_client->edict, armortype) = 0.8;
346 if (gamemode == GAME_ROGUE)
347 player_items |= RIT_ARMOR3;
349 player_items |= IT_ARMOR3;
353 // Give yellow armour
354 PRVM_serveredictfloat(host_client->edict, armortype) = 0.6;
355 if (gamemode == GAME_ROGUE)
356 player_items |= RIT_ARMOR2;
358 player_items |= IT_ARMOR2;
363 PRVM_serveredictfloat(host_client->edict, armortype) = 0.3;
364 if (gamemode == GAME_ROGUE)
365 player_items |= RIT_ARMOR1;
367 player_items |= IT_ARMOR1;
370 PRVM_serveredictfloat(host_client->edict, items) = player_items;
379 Sets client to flymode
382 static void SV_Fly_f(cmd_state_t *cmd)
384 prvm_prog_t *prog = SVVM_prog;
386 if (PRVM_serveredictfloat(host_client->edict, movetype) != MOVETYPE_FLY)
388 PRVM_serveredictfloat(host_client->edict, movetype) = MOVETYPE_FLY;
389 SV_ClientPrint("flymode ON\n");
393 PRVM_serveredictfloat(host_client->edict, movetype) = MOVETYPE_WALK;
394 SV_ClientPrint("flymode OFF\n");
398 static void SV_Notarget_f(cmd_state_t *cmd)
400 prvm_prog_t *prog = SVVM_prog;
402 PRVM_serveredictfloat(host_client->edict, flags) = (int)PRVM_serveredictfloat(host_client->edict, flags) ^ FL_NOTARGET;
403 if (!((int)PRVM_serveredictfloat(host_client->edict, flags) & FL_NOTARGET) )
404 SV_ClientPrint("notarget OFF\n");
406 SV_ClientPrint("notarget ON\n");
414 static void SV_Kill_f(cmd_state_t *cmd)
416 prvm_prog_t *prog = SVVM_prog;
417 if (PRVM_serveredictfloat(host_client->edict, health) <= 0)
419 SV_ClientPrint("Can't suicide -- already dead!\n");
423 PRVM_serverglobalfloat(time) = sv.time;
424 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict);
425 prog->ExecuteProgram(prog, PRVM_serverfunction(ClientKill), "QC function ClientKill is missing");
433 static void SV_Pause_f(cmd_state_t *cmd)
435 void (*print) (const char *fmt, ...);
436 if (cmd->source == src_local)
439 print = SV_ClientPrintf;
441 if (!pausable.integer && cmd->source == src_client && LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) != LHNETADDRESSTYPE_LOOP)
443 print("Pause not allowed.\n");
448 if (cmd->source != src_local)
449 SV_BroadcastPrintf("%s %spaused the game\n", host_client->name, sv.paused ? "" : "un");
450 else if(*(sv_adminnick.string))
451 SV_BroadcastPrintf("%s %spaused the game\n", sv_adminnick.string, sv.paused ? "" : "un");
453 SV_BroadcastPrintf("%s %spaused the game\n", hostname.string, sv.paused ? "" : "un");
454 // send notification to all clients
455 MSG_WriteByte(&sv.reliable_datagram, svc_setpause);
456 MSG_WriteByte(&sv.reliable_datagram, sv.paused);
459 static void SV_Say(cmd_state_t *cmd, qbool teamonly)
461 prvm_prog_t *prog = SVVM_prog;
466 // LadyHavoc: long say messages
468 qbool fromServer = false;
470 if (cmd->source == src_local)
476 if (Cmd_Argc (cmd) < 2)
479 if (!teamplay.integer)
489 // note this uses the chat prefix \001
490 if (!fromServer && !teamonly)
491 dpsnprintf (text, sizeof(text), "\001%s: %s", host_client->name, p1);
492 else if (!fromServer && teamonly)
493 dpsnprintf (text, sizeof(text), "\001(%s): %s", host_client->name, p1);
494 else if(*(sv_adminnick.string))
495 dpsnprintf (text, sizeof(text), "\001<%s> %s", sv_adminnick.string, p1);
497 dpsnprintf (text, sizeof(text), "\001<%s> %s", hostname.string, p1);
498 p2 = text + strlen(text);
499 while ((const char *)p2 > (const char *)text && (p2[-1] == '\r' || p2[-1] == '\n' || (p2[-1] == '\"' && quoted)))
501 if (p2[-1] == '\"' && quoted)
506 dp_strlcat(text, "\n", sizeof(text));
508 // note: save is not a valid edict if fromServer is true
510 for (j = 0, host_client = svs.clients;j < svs.maxclients;j++, host_client++)
511 if (host_client->active && (!teamonly || PRVM_serveredictfloat(host_client->edict, team) == PRVM_serveredictfloat(save->edict, team)))
512 SV_ClientPrint(text);
515 if(!host_isclient.integer)
519 static void SV_Say_f(cmd_state_t *cmd)
524 static void SV_Say_Team_f(cmd_state_t *cmd)
529 static void SV_Tell_f(cmd_state_t *cmd)
531 const char *playername_start = NULL;
532 size_t playername_length = 0;
533 int playernumber = 0;
537 char text[MAX_INPUTLINE]; // LadyHavoc: FIXME: temporary buffer overflow fix (was 64)
538 qbool fromServer = false;
540 if (cmd->source == src_local)
543 if (Cmd_Argc (cmd) < 2)
546 // note this uses the chat prefix \001
548 dpsnprintf (text, sizeof(text), "\001%s tells you: ", host_client->name);
549 else if(*(sv_adminnick.string))
550 dpsnprintf (text, sizeof(text), "\001<%s tells you> ", sv_adminnick.string);
552 dpsnprintf (text, sizeof(text), "\001<%s tells you> ", hostname.string);
555 p2 = p1 + strlen(p1);
556 // remove the target name
557 while (p1 < p2 && *p1 == ' ')
562 while (p1 < p2 && *p1 == ' ')
564 while (p1 < p2 && isdigit(*p1))
566 playernumber = playernumber * 10 + (*p1 - '0');
574 playername_start = p1;
575 while (p1 < p2 && *p1 != '"')
577 playername_length = p1 - playername_start;
583 playername_start = p1;
584 while (p1 < p2 && *p1 != ' ')
586 playername_length = p1 - playername_start;
588 while (p1 < p2 && *p1 == ' ')
592 // set playernumber to the right client
594 if(playername_length >= sizeof(namebuf))
597 Con_Print("Host_Tell: too long player name/ID\n");
599 SV_ClientPrint("Host_Tell: too long player name/ID\n");
602 memcpy(namebuf, playername_start, playername_length);
603 namebuf[playername_length] = 0;
604 for (playernumber = 0; playernumber < svs.maxclients; playernumber++)
606 if (!svs.clients[playernumber].active)
608 if (strcasecmp(svs.clients[playernumber].name, namebuf) == 0)
612 if(playernumber < 0 || playernumber >= svs.maxclients || !(svs.clients[playernumber].active))
615 Con_Print("Host_Tell: invalid player name/ID\n");
617 SV_ClientPrint("Host_Tell: invalid player name/ID\n");
620 // remove trailing newlines
621 while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
623 // remove quotes if present
630 Con_Print("Host_Tell: missing end quote\n");
632 SV_ClientPrint("Host_Tell: missing end quote\n");
634 while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
638 for (j = (int)strlen(text);j < (int)(sizeof(text) - 2) && p1 < p2;)
644 host_client = svs.clients + playernumber;
645 SV_ClientPrint(text);
655 static void SV_Ping_f(cmd_state_t *cmd)
659 void (*print) (const char *fmt, ...);
661 if (cmd->source == src_local)
664 print = SV_ClientPrintf;
669 print("Client ping times:\n");
670 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
674 print("%4i %s\n", bound(0, (int)floor(client->ping*1000+0.5), 9999), client->name);
682 Send back ping and packet loss update for all current players to this player
685 static void SV_Pings_f(cmd_state_t *cmd)
687 int i, j, ping, packetloss, movementloss;
690 if (!host_client->netconnection)
693 if (sv.protocol != PROTOCOL_QUAKEWORLD)
695 MSG_WriteByte(&host_client->netconnection->message, svc_stufftext);
696 MSG_WriteUnterminatedString(&host_client->netconnection->message, "pingplreport");
698 for (i = 0;i < svs.maxclients;i++)
702 if (svs.clients[i].netconnection)
704 for (j = 0;j < NETGRAPH_PACKETS;j++)
705 if (svs.clients[i].netconnection->incoming_netgraph[j].unreliablebytes == NETGRAPH_LOSTPACKET)
707 for (j = 0;j < NETGRAPH_PACKETS;j++)
708 if (svs.clients[i].movement_count[j] < 0)
711 packetloss = (packetloss * 100 + NETGRAPH_PACKETS - 1) / NETGRAPH_PACKETS;
712 movementloss = (movementloss * 100 + NETGRAPH_PACKETS - 1) / NETGRAPH_PACKETS;
713 ping = (int)floor(svs.clients[i].ping*1000+0.5);
714 ping = bound(0, ping, 9999);
715 if (sv.protocol == PROTOCOL_QUAKEWORLD)
717 // send qw_svc_updateping and qw_svc_updatepl messages
718 MSG_WriteByte(&host_client->netconnection->message, qw_svc_updateping);
719 MSG_WriteShort(&host_client->netconnection->message, ping);
720 MSG_WriteByte(&host_client->netconnection->message, qw_svc_updatepl);
721 MSG_WriteByte(&host_client->netconnection->message, packetloss);
725 // write the string into the packet as multiple unterminated strings to avoid needing a local buffer
727 dpsnprintf(temp, sizeof(temp), " %d %d,%d", ping, packetloss, movementloss);
729 dpsnprintf(temp, sizeof(temp), " %d %d", ping, packetloss);
730 MSG_WriteUnterminatedString(&host_client->netconnection->message, temp);
733 if (sv.protocol != PROTOCOL_QUAKEWORLD)
734 MSG_WriteString(&host_client->netconnection->message, "\n");
742 static void SV_Status_f(cmd_state_t *cmd)
744 prvm_prog_t *prog = SVVM_prog;
747 int seconds = 0, minutes = 0, hours = 0, i, j, k, in, players, ping = 0, packetloss = 0;
748 void (*print) (const char *fmt, ...);
749 char ip[48]; // can contain a full length v6 address with [] and a port
753 if (cmd->source == src_local)
756 print = SV_ClientPrintf;
762 if (Cmd_Argc(cmd) == 2)
764 if (strcmp(Cmd_Argv(cmd, 1), "1") == 0)
766 else if (strcmp(Cmd_Argv(cmd, 1), "2") == 0)
770 for (players = 0, i = 0;i < svs.maxclients;i++)
771 if (svs.clients[i].active)
774 print ("host: %s\n", Cvar_VariableString (&cvars_all, "hostname", CF_SERVER));
775 print ("version: %s\n", engineversion);
776 print ("protocol: %i (%s)\n", Protocol_NumberForEnum(sv.protocol), Protocol_NameForEnum(sv.protocol));
777 print ("map: %s\n", sv.worldbasename);
778 print ("timing: %s\n", SV_TimingReport(vabuf, sizeof(vabuf)));
779 print ("players: %i active (%i max)\n\n", players, svs.maxclients);
782 print ("^2IP %%pl ping time frags no name\n");
784 print ("^5IP no name\n");
786 for (i = 0, k = 0, client = svs.clients;i < svs.maxclients;i++, client++)
793 if (in == 0 || in == 1)
795 seconds = (int)(host.realtime - client->connecttime);
796 minutes = seconds / 60;
799 seconds -= (minutes * 60);
800 hours = minutes / 60;
802 minutes -= (hours * 60);
808 if (client->netconnection)
809 for (j = 0;j < NETGRAPH_PACKETS;j++)
810 if (client->netconnection->incoming_netgraph[j].unreliablebytes == NETGRAPH_LOSTPACKET)
812 packetloss = (packetloss * 100 + NETGRAPH_PACKETS - 1) / NETGRAPH_PACKETS;
813 ping = bound(0, (int)floor(client->ping*1000+0.5), 9999);
816 if(sv_status_privacy.integer && cmd->source != src_local && LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) != LHNETADDRESSTYPE_LOOP)
817 dp_strlcpy(ip, client->netconnection ? "hidden" : "botclient", 48);
819 dp_strlcpy(ip, (client->netconnection && *client->netconnection->address) ? client->netconnection->address : "botclient", 48);
821 frags = client->frags;
823 if(sv_status_show_qcstatus.integer)
825 prvm_edict_t *ed = PRVM_EDICT_NUM(i + 1);
826 const char *str = PRVM_GetString(prog, PRVM_serveredictstring(ed, clientstatus));
832 for(q = str; *q && p != qcstatus + sizeof(qcstatus) - 1; ++q)
833 if(*q != '\\' && *q != '"' && !ISWHITESPACE(*q))
837 frags = atoi(qcstatus);
841 if (in == 0) // default layout
843 if (sv.protocol == PROTOCOL_QUAKE && svs.maxclients <= 99)
845 // LadyHavoc: this is very touchy because we must maintain ProQuake compatible status output
846 print ("#%-2u %-16.16s %3i %2i:%02i:%02i\n", i+1, client->name, frags, hours, minutes, seconds);
851 // LadyHavoc: no real restrictions here, not a ProQuake-compatible protocol anyway...
852 print ("#%-3u %-16.16s %4i %2i:%02i:%02i\n", i+1, client->name, frags, hours, minutes, seconds);
856 else if (in == 1) // extended layout
858 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);
860 else if (in == 2) // reduced layout
862 print ("%s%-47s #%-3u ^7%s\n", k%2 ? "^3" : "^7", ip, i+1, client->name);
867 void SV_Name(int clientnum)
869 prvm_prog_t *prog = SVVM_prog;
870 PRVM_serveredictstring(host_client->edict, netname) = PRVM_SetEngineString(prog, host_client->name);
871 if (strcmp(host_client->old_name, host_client->name))
873 if (host_client->begun)
874 SV_BroadcastPrintf("\003%s ^7changed name to ^3%s\n", host_client->old_name, host_client->name);
875 dp_strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
876 // send notification to all clients
877 MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
878 MSG_WriteByte (&sv.reliable_datagram, clientnum);
879 MSG_WriteString (&sv.reliable_datagram, host_client->name);
880 SV_WriteNetnameIntoDemo(host_client);
885 ======================
887 ======================
889 static void SV_Name_f(cmd_state_t *cmd)
893 const char *newNameSource;
894 char newName[sizeof(host_client->name)];
896 if (Cmd_Argc (cmd) == 1)
899 if (Cmd_Argc (cmd) == 2)
900 newNameSource = Cmd_Argv(cmd, 1);
902 newNameSource = Cmd_Args(cmd);
904 dp_strlcpy(newName, newNameSource, sizeof(newName));
906 if (cmd->source == src_local)
909 if (host.realtime < host_client->nametime && strcmp(newName, host_client->name))
911 SV_ClientPrintf("You can't change name more than once every %.1f seconds!\n", max(0.0f, sv_namechangetimer.value));
915 host_client->nametime = host.realtime + max(0.0f, sv_namechangetimer.value);
917 // point the string back at updateclient->name to keep it safe
918 dp_strlcpy (host_client->name, newName, sizeof (host_client->name));
920 for (i = 0, j = 0;host_client->name[i];i++)
921 if (host_client->name[i] != '\r' && host_client->name[i] != '\n')
922 host_client->name[j++] = host_client->name[i];
923 host_client->name[j] = 0;
925 if(host_client->name[0] == 1 || host_client->name[0] == 2)
926 // may interfere with chat area, and will needlessly beep; so let's add a ^7
928 memmove(host_client->name + 2, host_client->name, sizeof(host_client->name) - 2);
929 host_client->name[sizeof(host_client->name) - 1] = 0;
930 host_client->name[0] = STRING_COLOR_TAG;
931 host_client->name[1] = '0' + STRING_COLOR_DEFAULT;
934 u8_COM_StringLengthNoColors(host_client->name, 0, &valid_colors);
935 if(!valid_colors) // NOTE: this also proves the string is not empty, as "" is a valid colored string
938 l = strlen(host_client->name);
939 if(l < sizeof(host_client->name) - 1)
941 // duplicate the color tag to escape it
942 host_client->name[i] = STRING_COLOR_TAG;
943 host_client->name[i+1] = 0;
944 //Con_DPrintf("abuse detected, adding another trailing color tag\n");
948 // remove the last character to fix the color code
949 host_client->name[l-1] = 0;
950 //Con_DPrintf("abuse detected, removing a trailing color tag\n");
954 // find the last color tag offset and decide if we need to add a reset tag
955 for (i = 0, j = -1;host_client->name[i];i++)
957 if (host_client->name[i] == STRING_COLOR_TAG)
959 if (host_client->name[i+1] >= '0' && host_client->name[i+1] <= '9')
962 // if this happens to be a reset tag then we don't need one
963 if (host_client->name[i+1] == '0' + STRING_COLOR_DEFAULT)
968 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]))
974 if (host_client->name[i+1] == STRING_COLOR_TAG)
981 // does not end in the default color string, so add it
982 if (j >= 0 && strlen(host_client->name) < sizeof(host_client->name) - 2)
983 memcpy(host_client->name + strlen(host_client->name), STRING_COLOR_DEFAULT_STR, strlen(STRING_COLOR_DEFAULT_STR) + 1);
985 SV_Name(host_client - svs.clients);
988 static void SV_Rate_f(cmd_state_t *cmd)
992 rate = atoi(Cmd_Argv(cmd, 1));
994 if (cmd->source == src_local)
997 host_client->rate = rate;
1000 static void SV_Rate_BurstSize_f(cmd_state_t *cmd)
1004 if (Cmd_Argc(cmd) != 2)
1007 rate_burstsize = atoi(Cmd_Argv(cmd, 1));
1009 host_client->rate_burstsize = rate_burstsize;
1012 static void SV_Color_f(cmd_state_t *cmd)
1014 prvm_prog_t *prog = SVVM_prog;
1016 int top, bottom, playercolor;
1018 top = atoi(Cmd_Argv(cmd, 1));
1019 bottom = atoi(Cmd_Argv(cmd, 2));
1024 playercolor = top*16 + bottom;
1026 if (host_client->edict && PRVM_serverfunction(SV_ChangeTeam))
1028 Con_DPrint("Calling SV_ChangeTeam\n");
1029 prog->globals.fp[OFS_PARM0] = playercolor;
1030 PRVM_serverglobalfloat(time) = sv.time;
1031 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict);
1032 prog->ExecuteProgram(prog, PRVM_serverfunction(SV_ChangeTeam), "QC function SV_ChangeTeam is missing");
1036 if (host_client->edict)
1038 PRVM_serveredictfloat(host_client->edict, clientcolors) = playercolor;
1039 PRVM_serveredictfloat(host_client->edict, team) = bottom + 1;
1041 host_client->colors = playercolor;
1042 if (host_client->old_colors != host_client->colors)
1044 host_client->old_colors = host_client->colors;
1045 // send notification to all clients
1046 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1047 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1048 MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1057 Kicks a user off of the server
1060 static void SV_Kick_f(cmd_state_t *cmd)
1063 const char *message = NULL;
1067 qbool byNumber = false;
1074 if (Cmd_Argc(cmd) > 2 && strcmp(Cmd_Argv(cmd, 1), "#") == 0)
1076 i = (int)(atof(Cmd_Argv(cmd, 2)) - 1);
1077 if (i < 0 || i >= svs.maxclients || !(host_client = svs.clients + i)->active)
1083 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1085 if (!host_client->active)
1087 if (strcasecmp(host_client->name, Cmd_Argv(cmd, 1)) == 0)
1092 if (i < svs.maxclients)
1094 if (cmd->source == src_local)
1096 if(!host_isclient.integer)
1099 who = cl_name.string;
1104 // can't kick yourself!
1105 if (host_client == save)
1108 if (Cmd_Argc(cmd) > 2)
1110 message = Cmd_Args(cmd);
1111 COM_ParseToken_Simple(&message, false, false, true);
1114 message++; // skip the #
1115 while (*message == ' ') // skip white space
1117 message += strlen(Cmd_Argv(cmd, 2)); // skip the number
1119 while (*message && *message == ' ')
1123 SV_DropClient (false, va(reason, sizeof(reason), "Kicked by %s: %s", who, message)); // kicked
1124 //SV_ClientPrintf("Kicked by %s: %s\n", who, message);
1126 //SV_ClientPrintf("Kicked by %s\n", who);
1127 SV_DropClient (false, va(reason, sizeof(reason), "Kicked by %s", who)); // kicked
1133 static void SV_MaxPlayers_f(cmd_state_t *cmd)
1137 if (Cmd_Argc(cmd) != 2)
1139 Con_Printf("\"maxplayers\" is \"%u\"\n", svs.maxclients_next);
1145 Con_Print("maxplayers can not be changed while a server is running.\n");
1146 Con_Print("It will be changed on next server startup (\"map\" command).\n");
1149 n = atoi(Cmd_Argv(cmd, 1));
1150 n = bound(1, n, MAX_SCOREBOARD);
1151 Con_Printf("\"maxplayers\" set to \"%u\"\n", n);
1153 svs.maxclients_next = n;
1155 Cvar_Set (&cvars_all, "deathmatch", "0");
1157 Cvar_Set (&cvars_all, "deathmatch", "1");
1161 ======================
1163 ======================
1165 // the old playermodel in cl_main has been renamed to __cl_playermodel
1166 static void SV_Playermodel_f(cmd_state_t *cmd)
1168 prvm_prog_t *prog = SVVM_prog;
1170 char newPath[sizeof(host_client->playermodel)];
1172 if (Cmd_Argc (cmd) == 1)
1175 if (Cmd_Argc (cmd) == 2)
1176 dp_strlcpy (newPath, Cmd_Argv(cmd, 1), sizeof (newPath));
1178 dp_strlcpy (newPath, Cmd_Args(cmd), sizeof (newPath));
1180 for (i = 0, j = 0;newPath[i];i++)
1181 if (newPath[i] != '\r' && newPath[i] != '\n')
1182 newPath[j++] = newPath[i];
1186 if (host.realtime < host_client->nametime)
1188 SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
1192 host_client->nametime = host.realtime + 5;
1195 // point the string back at updateclient->name to keep it safe
1196 dp_strlcpy (host_client->playermodel, newPath, sizeof (host_client->playermodel));
1197 PRVM_serveredictstring(host_client->edict, playermodel) = PRVM_SetEngineString(prog, host_client->playermodel);
1198 if (strcmp(host_client->old_model, host_client->playermodel))
1200 dp_strlcpy(host_client->old_model, host_client->playermodel, sizeof(host_client->old_model));
1201 /*// send notification to all clients
1202 MSG_WriteByte (&sv.reliable_datagram, svc_updatepmodel);
1203 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1204 MSG_WriteString (&sv.reliable_datagram, host_client->playermodel);*/
1209 ======================
1211 ======================
1213 static void SV_Playerskin_f(cmd_state_t *cmd)
1215 prvm_prog_t *prog = SVVM_prog;
1217 char newPath[sizeof(host_client->playerskin)];
1219 if (Cmd_Argc (cmd) == 1)
1222 if (Cmd_Argc (cmd) == 2)
1223 dp_strlcpy (newPath, Cmd_Argv(cmd, 1), sizeof (newPath));
1225 dp_strlcpy (newPath, Cmd_Args(cmd), sizeof (newPath));
1227 for (i = 0, j = 0;newPath[i];i++)
1228 if (newPath[i] != '\r' && newPath[i] != '\n')
1229 newPath[j++] = newPath[i];
1233 if (host.realtime < host_client->nametime)
1235 SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
1239 host_client->nametime = host.realtime + 5;
1242 // point the string back at updateclient->name to keep it safe
1243 dp_strlcpy (host_client->playerskin, newPath, sizeof (host_client->playerskin));
1244 PRVM_serveredictstring(host_client->edict, playerskin) = PRVM_SetEngineString(prog, host_client->playerskin);
1245 if (strcmp(host_client->old_skin, host_client->playerskin))
1247 //if (host_client->begun)
1248 // SV_BroadcastPrintf("%s changed skin to %s\n", host_client->name, host_client->playerskin);
1249 dp_strlcpy(host_client->old_skin, host_client->playerskin, sizeof(host_client->old_skin));
1250 /*// send notification to all clients
1251 MSG_WriteByte (&sv.reliable_datagram, svc_updatepskin);
1252 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1253 MSG_WriteString (&sv.reliable_datagram, host_client->playerskin);*/
1258 ======================
1260 LadyHavoc: only supported for Nehahra, I personally think this is dumb, but Mindcrime won't listen.
1261 LadyHavoc: correction, Mindcrime will be removing pmodel in the future, but it's still stuck here for compatibility.
1262 ======================
1264 static void SV_PModel_f(cmd_state_t *cmd)
1266 prvm_prog_t *prog = SVVM_prog;
1268 if (Cmd_Argc (cmd) == 1)
1271 PRVM_serveredictfloat(host_client->edict, pmodel) = atoi(Cmd_Argv(cmd, 1));
1275 ===============================================================================
1279 ===============================================================================
1282 static prvm_edict_t *FindViewthing(prvm_prog_t *prog)
1287 for (i=0 ; i<prog->num_edicts ; i++)
1289 e = PRVM_EDICT_NUM(i);
1290 if (!strcmp (PRVM_GetString(prog, PRVM_serveredictstring(e, classname)), "viewthing"))
1293 Con_Print("No viewthing on map\n");
1302 static void SV_Viewmodel_f(cmd_state_t *cmd)
1304 prvm_prog_t *prog = SVVM_prog;
1311 e = FindViewthing(prog);
1314 m = Mod_ForName (Cmd_Argv(cmd, 1), false, true, NULL);
1315 if (m && m->loaded && m->Draw)
1317 PRVM_serveredictfloat(e, frame) = 0;
1318 cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)] = m;
1321 Con_Printf("viewmodel: can't load %s\n", Cmd_Argv(cmd, 1));
1330 static void SV_Viewframe_f(cmd_state_t *cmd)
1332 prvm_prog_t *prog = SVVM_prog;
1340 e = FindViewthing(prog);
1343 m = cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)];
1345 f = atoi(Cmd_Argv(cmd, 1));
1346 if (f >= m->numframes)
1349 PRVM_serveredictfloat(e, frame) = f;
1353 static void PrintFrameName (model_t *m, int frame)
1356 Con_Printf("frame %i: %s\n", frame, m->animscenes[frame].name);
1358 Con_Printf("frame %i\n", frame);
1366 static void SV_Viewnext_f(cmd_state_t *cmd)
1368 prvm_prog_t *prog = SVVM_prog;
1375 e = FindViewthing(prog);
1378 m = cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)];
1380 PRVM_serveredictfloat(e, frame) = PRVM_serveredictfloat(e, frame) + 1;
1381 if (PRVM_serveredictfloat(e, frame) >= m->numframes)
1382 PRVM_serveredictfloat(e, frame) = m->numframes - 1;
1384 PrintFrameName (m, (int)PRVM_serveredictfloat(e, frame));
1393 static void SV_Viewprev_f(cmd_state_t *cmd)
1395 prvm_prog_t *prog = SVVM_prog;
1402 e = FindViewthing(prog);
1405 m = cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)];
1407 PRVM_serveredictfloat(e, frame) = PRVM_serveredictfloat(e, frame) - 1;
1408 if (PRVM_serveredictfloat(e, frame) < 0)
1409 PRVM_serveredictfloat(e, frame) = 0;
1411 PrintFrameName (m, (int)PRVM_serveredictfloat(e, frame));
1415 static void SV_SendCvar_f(cmd_state_t *cmd)
1418 const char *cvarname;
1421 if(Cmd_Argc(cmd) != 2)
1424 if(!sv.active)// || !PRVM_serverfunction(SV_ParseClientCommand))
1427 cvarname = Cmd_Argv(cmd, 1);
1430 if(host_isclient.integer)
1434 for(;i<svs.maxclients;i++)
1435 if(svs.clients[i].active && svs.clients[i].netconnection)
1437 host_client = &svs.clients[i];
1438 SV_ClientCommands("sendcvar %s\n", cvarname);
1443 static void SV_Ent_Create_f(cmd_state_t *cmd)
1445 prvm_prog_t *prog = SVVM_prog;
1451 void (*print)(const char *, ...) = (cmd->source == src_client ? SV_ClientPrintf : Con_Printf);
1456 ed = PRVM_ED_Alloc(SVVM_prog);
1458 PRVM_ED_ParseEpair(prog, ed, PRVM_ED_FindField(prog, "classname"), Cmd_Argv(cmd, 1), false);
1460 // Spawn where the player is aiming. We need a view matrix first.
1461 if(cmd->source == src_client)
1463 vec3_t org, temp, dest;
1468 SV_GetEntityMatrix(prog, host_client->edict, &view, true);
1470 Matrix4x4_OriginFromMatrix(&view, org);
1471 VectorSet(temp, 65536, 0, 0);
1472 Matrix4x4_Transform(&view, temp, dest);
1474 trace = SV_TraceLine(org, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, 0, 0, collision_extendmovelength.value);
1476 dpsnprintf(buf, sizeof(buf), "%g %g %g", trace.endpos[0], trace.endpos[1], trace.endpos[2]);
1477 PRVM_ED_ParseEpair(prog, ed, PRVM_ED_FindField(prog, "origin"), buf, false);
1481 // Or spawn at a specified origin.
1488 // Allow more than one key/value pair by cycling between expecting either one.
1489 for(i = 2; i < Cmd_Argc(cmd); i += 2)
1491 if(!(key = PRVM_ED_FindField(prog, Cmd_Argv(cmd, i))))
1493 print("Key %s not found!\n", Cmd_Argv(cmd, i));
1494 PRVM_ED_Free(prog, ed);
1499 * This is mostly for dedicated server console, but if the
1500 * player gave a custom origin, we can ignore the traceline.
1502 if(!strcmp(Cmd_Argv(cmd, i), "origin"))
1505 if (i + 1 < Cmd_Argc(cmd))
1506 PRVM_ED_ParseEpair(prog, ed, key, Cmd_Argv(cmd, i+1), false);
1511 print("Missing origin\n");
1512 PRVM_ED_Free(prog, ed);
1517 PRVM_ED_CallPrespawnFunction(prog, ed);
1519 if(!PRVM_ED_CallSpawnFunction(prog, ed, NULL, NULL))
1521 print("Could not spawn a \"%s\". No such entity or it has no spawn function\n", Cmd_Argv(cmd, 1));
1522 if(cmd->source == src_client)
1523 Con_Printf("%s tried to spawn a \"%s\"\n", host_client->name, Cmd_Argv(cmd, 1));
1524 // CallSpawnFunction already freed the edict for us.
1528 PRVM_ED_CallPostspawnFunction(prog, ed);
1530 // Make it appear in the world
1533 if(cmd->source == src_client)
1534 Con_Printf("%s spawned a \"%s\"\n", host_client->name, Cmd_Argv(cmd, 1));
1537 static void SV_Ent_Remove_f(cmd_state_t *cmd)
1539 prvm_prog_t *prog = SVVM_prog;
1542 void (*print)(const char *, ...) = (cmd->source == src_client ? SV_ClientPrintf : Con_Printf);
1547 // Allow specifying edict by number
1548 if(Cmd_Argc(cmd) > 1 && Cmd_Argv(cmd, 1))
1550 ednum = atoi(Cmd_Argv(cmd, 1));
1553 print("Cannot remove the world\n");
1557 // Or trace a line if it's a client who didn't specify one.
1558 else if(cmd->source == src_client)
1560 vec3_t org, temp, dest;
1564 SV_GetEntityMatrix(prog, host_client->edict, &view, true);
1566 Matrix4x4_OriginFromMatrix(&view, org);
1567 VectorSet(temp, 65536, 0, 0);
1568 Matrix4x4_Transform(&view, temp, dest);
1570 trace = SV_TraceLine(org, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY, 0, 0, collision_extendmovelength.value);
1573 ednum = (int)PRVM_EDICT_TO_PROG(trace.ent);
1574 if(!trace.ent || !ednum)
1575 // Don't remove the world, but don't annoy players with a print if they miss
1580 // Only a dedicated server console should be able to reach this.
1581 print("No edict given\n");
1585 ed = PRVM_EDICT_NUM(ednum);
1590 for (i = 0; i < svs.maxclients; i++)
1592 if(ed == svs.clients[i].edict)
1598 print("Removed a \"%s\"\n", PRVM_GetString(prog, PRVM_serveredictstring(ed, classname)));
1599 PRVM_ED_ClearEdict(prog, ed);
1600 PRVM_ED_Free(prog, ed);
1605 // This should only be reachable if an invalid edict number was given
1606 print("No such entity\n");
1611 static void SV_Ent_Remove_All_f(cmd_state_t *cmd)
1613 prvm_prog_t *prog = SVVM_prog;
1616 void (*print)(const char *, ...) = (cmd->source == src_client ? SV_ClientPrintf : Con_Printf);
1618 for (i = 0, rmcount = 0, ed = PRVM_EDICT_NUM(i); i < prog->num_edicts; i++, ed = PRVM_NEXT_EDICT(ed))
1620 if(!ed->free && !strcmp(PRVM_GetString(prog, PRVM_serveredictstring(ed, classname)), Cmd_Argv(cmd, 1)))
1624 print("Cannot remove the world\n");
1627 PRVM_ED_ClearEdict(prog, ed);
1628 PRVM_ED_Free(prog, ed);
1634 print("No \"%s\" found\n", Cmd_Argv(cmd, 1));
1636 print("Removed %i of \"%s\"\n", rmcount, Cmd_Argv(cmd, 1));
1639 void SV_InitOperatorCommands(void)
1641 Cvar_RegisterVariable(&sv_cheats);
1642 Cvar_RegisterCallback(&sv_cheats, SV_DisableCheats_c);
1643 Cvar_RegisterVariable(&sv_adminnick);
1644 Cvar_RegisterVariable(&sv_status_privacy);
1645 Cvar_RegisterVariable(&sv_status_show_qcstatus);
1646 Cvar_RegisterVariable(&sv_namechangetimer);
1648 Cmd_AddCommand(CF_SERVER | CF_SERVER_FROM_CLIENT, "status", SV_Status_f, "print server status information");
1649 Cmd_AddCommand(CF_SHARED, "map", SV_Map_f, "kick everyone off the server and start a new level");
1650 Cmd_AddCommand(CF_SHARED, "restart", SV_Restart_f, "restart current level");
1651 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)");
1652 Cmd_AddCommand(CF_SHARED | CF_SERVER_FROM_CLIENT, "say", SV_Say_f, "send a chat message to everyone on the server");
1653 Cmd_AddCommand(CF_SERVER_FROM_CLIENT, "say_team", SV_Say_Team_f, "send a chat message to your team on the server");
1654 Cmd_AddCommand(CF_SHARED | CF_SERVER_FROM_CLIENT, "tell", SV_Tell_f, "send a chat message to only one person on the server");
1655 Cmd_AddCommand(CF_SERVER | CF_SERVER_FROM_CLIENT, "pause", SV_Pause_f, "pause the game (if the server allows pausing)");
1656 Cmd_AddCommand(CF_SHARED, "kick", SV_Kick_f, "kick a player off the server by number or name");
1657 Cmd_AddCommand(CF_SHARED | CF_SERVER_FROM_CLIENT, "ping", SV_Ping_f, "print ping times of all players on the server");
1658 Cmd_AddCommand(CF_SHARED, "load", SV_Loadgame_f, "load a saved game file");
1659 Cmd_AddCommand(CF_SHARED, "save", SV_Savegame_f, "save the game to a file");
1660 Cmd_AddCommand(CF_SHARED, "viewmodel", SV_Viewmodel_f, "change model of viewthing entity in current level");
1661 Cmd_AddCommand(CF_SHARED, "viewframe", SV_Viewframe_f, "change animation frame of viewthing entity in current level");
1662 Cmd_AddCommand(CF_SHARED, "viewnext", SV_Viewnext_f, "change to next animation frame of viewthing entity in current level");
1663 Cmd_AddCommand(CF_SHARED, "viewprev", SV_Viewprev_f, "change to previous animation frame of viewthing entity in current level");
1664 Cmd_AddCommand(CF_SHARED, "maxplayers", SV_MaxPlayers_f, "sets limit on how many players (or bots) may be connected to the server at once");
1665 host.hook.SV_SendCvar = SV_SendCvar_f;
1667 // 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)
1668 Cmd_AddCommand(CF_SERVER_FROM_CLIENT, "prespawn", SV_PreSpawn_f, "internal use - signon 1 (client acknowledges that server information has been received)");
1669 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)");
1670 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)");
1671 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)");
1673 Cmd_AddCommand(CF_CHEAT | CF_SERVER_FROM_CLIENT, "god", SV_God_f, "god mode (invulnerability)");
1674 Cmd_AddCommand(CF_CHEAT | CF_SERVER_FROM_CLIENT, "notarget", SV_Notarget_f, "notarget mode (monsters do not see you)");
1675 Cmd_AddCommand(CF_CHEAT | CF_SERVER_FROM_CLIENT, "fly", SV_Fly_f, "fly mode (flight)");
1676 Cmd_AddCommand(CF_CHEAT | CF_SERVER_FROM_CLIENT, "noclip", SV_Noclip_f, "noclip mode (flight without collisions, move through walls)");
1677 Cmd_AddCommand(CF_CHEAT | CF_SERVER_FROM_CLIENT, "give", SV_Give_f, "alter inventory");
1678 Cmd_AddCommand(CF_SERVER_FROM_CLIENT, "kill", SV_Kill_f, "die instantly");
1680 Cmd_AddCommand(CF_USERINFO, "color", SV_Color_f, "change your player shirt and pants colors");
1681 Cmd_AddCommand(CF_USERINFO, "name", SV_Name_f, "change your player name");
1682 Cmd_AddCommand(CF_USERINFO, "rate", SV_Rate_f, "change your network connection speed");
1683 Cmd_AddCommand(CF_USERINFO, "rate_burstsize", SV_Rate_BurstSize_f, "change your network connection speed");
1684 Cmd_AddCommand(CF_USERINFO, "pmodel", SV_PModel_f, "(Nehahra-only) change your player model choice");
1685 Cmd_AddCommand(CF_USERINFO, "playermodel", SV_Playermodel_f, "change your player model");
1686 Cmd_AddCommand(CF_USERINFO, "playerskin", SV_Playerskin_f, "change your player skin number");
1688 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.");
1689 Cmd_AddCommand(CF_CHEAT | CF_SERVER_FROM_CLIENT, "ent_remove_all", SV_Ent_Remove_All_f, "Removes all entities of the specified classname");
1690 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");