3 #include <server/defs.qh>
4 #include <server/miscfunctions.qh>
6 #include <common/command/_mod.qh>
11 #include "../bot/api.qh"
13 #include "../campaign.qh"
14 #include "../cheats.qh"
15 #include "../client.qh"
16 #include "../clientkill.qh"
17 #include "../player.qh"
18 #include "../ipban.qh"
19 #include "../mapvoting.qh"
20 #include "../scores.qh"
21 #include "../teamplay.qh"
23 #include <server/mutators/_mod.qh>
24 #include <common/gamemodes/_mod.qh>
27 #include <common/vehicles/all.qh>
30 #include <common/constants.qh>
31 #include <common/deathtypes/all.qh>
32 #include <common/effects/all.qh>
33 #include <common/mapinfo.qh>
34 #include <common/notifications/all.qh>
35 #include <common/physics/player.qh>
36 #include <common/teams.qh>
37 #include <common/util.qh>
38 #include <common/mapobjects/triggers.qh>
40 #include <common/minigames/sv_minigames.qh>
42 #include <common/monsters/_mod.qh>
43 #include <common/monsters/sv_spawn.qh>
44 #include <common/monsters/sv_monsters.qh>
46 #include <lib/warpzone/common.qh>
48 // =========================================================
49 // Server side networked commands code, reworked by Samual
50 // Last updated: December 28th, 2011
51 // =========================================================
53 bool SV_ParseClientCommand_floodcheck(entity this)
55 entity store = IS_CLIENT(this) ? CS(this) : this; // unfortunately, we need to store these on the client initially
57 if (!timeout_status) // not while paused
59 if (time <= (store.cmd_floodtime + autocvar_sv_clientcommand_antispam_time))
61 store.cmd_floodcount += 1;
62 if (store.cmd_floodcount > autocvar_sv_clientcommand_antispam_count) return false; // too much spam, halt
66 store.cmd_floodtime = time;
67 store.cmd_floodcount = 1;
70 return true; // continue, as we're not flooding yet
74 // =======================
75 // Command Sub-Functions
76 // =======================
78 void ClientCommand_autoswitch(entity caller, int request, int argc)
82 case CMD_REQUEST_COMMAND:
86 CS(caller).autoswitch = InterpretBoolean(argv(1));
87 sprint(caller, strcat("^1autoswitch is currently turned ", (CS(caller).autoswitch ? "on" : "off"), ".\n"));
93 sprint(caller, "Incorrect parameters for ^2autoswitch^7\n");
94 case CMD_REQUEST_USAGE:
96 sprint(caller, "\nUsage:^3 cmd autoswitch selection\n");
97 sprint(caller, " Where 'selection' controls if autoswitch is on or off.\n");
103 void ClientCommand_clientversion(entity caller, int request, int argc) // internal command, used only by code
107 case CMD_REQUEST_COMMAND:
111 if (IS_CLIENT(caller))
113 CS(caller).version = ((argv(1) == "$gameversion") ? 1 : stof(argv(1)));
115 if (CS(caller).version < autocvar_gameversion_min || CS(caller).version > autocvar_gameversion_max)
117 CS(caller).version_mismatch = true;
118 ClientKill_TeamChange(caller, -2); // observe
120 else if (autocvar_g_campaign || autocvar_g_balance_teams)
122 // JoinBestTeam(caller, false, true);
124 else if (teamplay && !autocvar_sv_spectate && !(Player_GetForcedTeamIndex(caller) > 0))
126 TRANSMUTE(Observer, caller); // really?
127 stuffcmd(caller, "menu_showteamselect\n");
136 sprint(caller, "Incorrect parameters for ^2clientversion^7\n");
137 case CMD_REQUEST_USAGE:
139 sprint(caller, "\nUsage:^3 cmd clientversion version\n");
140 sprint(caller, " Where 'version' is the game version reported by caller.\n");
146 void ClientCommand_mv_getpicture(entity caller, int request, int argc) // internal command, used only by code
150 case CMD_REQUEST_COMMAND:
154 if (intermission_running) MapVote_SendPicture(caller, stof(argv(1)));
161 sprint(caller, "Incorrect parameters for ^2mv_getpicture^7\n");
162 case CMD_REQUEST_USAGE:
164 sprint(caller, "\nUsage:^3 cmd mv_getpicture mapid\n");
165 sprint(caller, " Where 'mapid' is the id number of the map to request an image of on the map vote selection menu.\n");
171 void ClientCommand_wpeditor(entity caller, int request, int argc)
175 case CMD_REQUEST_COMMAND:
177 if (!autocvar_g_waypointeditor)
179 sprint(caller, "ERROR: this command works only if the waypoint editor is on\n");
185 if (argv(1) == "spawn")
188 if (!IS_PLAYER(caller))
189 sprint(caller, "ERROR: this command works only if you are player\n");
191 waypoint_spawn_fromeditor(caller, (s == "crosshair"), (s == "jump"), (s == "crouch"), (s == "support"));
194 else if (argv(1) == "remove")
196 if (!IS_PLAYER(caller))
197 sprint(caller, "ERROR: this command works only if you are player\n");
199 waypoint_remove_fromeditor(caller);
202 else if (argv(1) == "hardwire")
205 waypoint_start_hardwiredlink(caller, (s == "crosshair"));
208 else if (argv(1) == "unreachable")
210 if (!IS_PLAYER(caller))
211 sprint(caller, "ERROR: this command works only if you are player\n");
213 waypoint_unreachable(caller);
216 else if (argv(1) == "saveall")
221 else if (argv(1) == "relinkall")
223 waypoint_schedulerelinkall();
226 else if (argv(1) == "symaxis")
228 if (argv(2) == "set" || argv(2) == "get")
230 waypoint_getSymmetricalAxis_cmd(caller, (argv(2) == "set"), 3);
234 else if (argv(1) == "symorigin")
236 if (argv(2) == "set" || argv(2) == "get")
238 waypoint_getSymmetricalOrigin_cmd(caller, (argv(2) == "set"), 3);
246 sprint(caller, "Incorrect parameters for ^2wpeditor^7\n");
247 case CMD_REQUEST_USAGE:
249 sprint(caller, "\nUsage:^3 cmd wpeditor action\n");
250 sprint(caller, " Where 'action' can be:\n");
251 sprint(caller, " ^5spawn^7: spawns a waypoint at player's position\n");
252 sprint(caller, " ^5remove^7: remove player's nearest waypoint\n");
253 sprint(caller, " ^5unreachable^7: useful to reveal waypoints and items unreachable from the current position and spawnpoints without a nearest waypoint\n");
254 sprint(caller, " ^5saveall^7: saves all waypoints and links to file\n");
255 sprint(caller, " ^5relinkall^7: relink all waypoints as if they were respawned\n");
256 sprint(caller, " ^5spawn crosshair^7: spawns a waypoint at crosshair's position (in general useful to create special and hardwired links with ease from existing waypoints, in particular it's the only way to create custom jumppad waypoints (spawn another waypoint to create destination))\n");
257 sprint(caller, " ^5spawn jump^7: spawns a jump waypoint (spawn another waypoint to create destination)\n");
258 sprint(caller, " ^5spawn crouch^7: spawns a crouch waypoint\n");
259 sprint(caller, " ^5spawn support^7: spawns a support waypoint (spawn another waypoint to create destination from which all incoming links are removed), useful to replace links to preblematic jumppad/teleport waypoints\n");
260 sprint(caller, " ^5hardwire^7: marks the nearest waypoint as origin of a new hardwired link (spawn another waypoint over an existing one to create destination)\n");
261 sprint(caller, " ^5hardwire crosshair^7: marks the waypoint at crosshair instead of the nearest waypoint\n");
262 sprint(caller, " ^5symorigin get|set\n");
263 sprint(caller, " ^5symorigin get|set p1 p2 ... pX\n");
264 sprint(caller, " ^5symaxis get|set p1 p2\n");
265 sprint(caller, " ^7 where p1 p2 ... pX are positions (\"x y z\", z can be omitted) that you know are perfectly symmetrical");
266 sprint(caller, " ^7 so you can determine origin/axis of symmetry of maps without ctf flags or where flags aren't perfectly symmetrical\n");
272 void ClientCommand_join(entity caller, int request)
276 case CMD_REQUEST_COMMAND:
279 if (IS_CLIENT(caller) && !IS_PLAYER(caller))
280 if (joinAllowed(caller))
283 return; // never fall through to usage
287 case CMD_REQUEST_USAGE:
289 sprint(caller, "\nUsage:^3 cmd join\n");
290 sprint(caller, " No arguments required.\n");
296 void ClientCommand_kill(entity caller, int request)
300 case CMD_REQUEST_COMMAND:
302 if(IS_SPEC(caller) || IS_OBSERVER(caller))
303 return; // no point warning about this, command does nothing
305 if(GetResource(caller, RES_HEALTH) <= 0)
307 sprint(caller, "Can't die - you are already dead!\n");
313 return; // never fall through to usage
317 case CMD_REQUEST_USAGE:
319 sprint(caller, "\nUsage:^3 cmd kill\n");
320 sprint(caller, " No arguments required.\n");
326 void ClientCommand_physics(entity caller, int request, int argc)
330 case CMD_REQUEST_COMMAND:
332 string command = strtolower(argv(1));
334 if (!autocvar_g_physics_clientselect)
336 sprint(caller, "Client physics selection is currently disabled.\n");
340 if (command == "list" || command == "help")
342 sprint(caller, strcat("Available physics sets: \n\n", autocvar_g_physics_clientselect_options, " default\n"));
346 if (Physics_Valid(command) || command == "default")
348 stuffcmd(caller, strcat("\nseta cl_physics ", command, "\nsendcvar cl_physics\n"));
349 sprint(caller, strcat("^2Physics set successfully changed to ^3", command, "\n"));
355 sprint(caller, strcat("Current physics set: ^3", CS(caller).cvar_cl_physics, "\n"));
356 case CMD_REQUEST_USAGE:
358 sprint(caller, "\nUsage:^3 cmd physics <physics>\n");
359 sprint(caller, " See 'cmd physics list' for available physics sets.\n");
360 sprint(caller, " Argument 'default' resets to standard physics.\n");
366 void ClientCommand_ready(entity caller, int request) // todo: anti-spam for toggling readyness
370 case CMD_REQUEST_COMMAND:
372 if (IS_CLIENT(caller))
374 if (warmup_stage || sv_ready_restart || g_race_qualifying == 2)
376 if (!readyrestart_happened || sv_ready_restart_repeatable)
378 if (time < game_starttime) // game is already restarting
380 if (caller.ready) // toggle
382 caller.ready = false;
383 if(IS_PLAYER(caller) || caller.caplayer == 1)
384 bprint(playername(caller, false), "^2 is ^1NOT^2 ready\n");
389 if(IS_PLAYER(caller) || caller.caplayer == 1)
390 bprint(playername(caller, false), "^2 is ready\n");
393 // cannot reset the game while a timeout is active!
394 if (!timeout_status) ReadyCount();
398 sprint(caller, "^1Game has already been restarted\n");
402 return; // never fall through to usage
406 case CMD_REQUEST_USAGE:
408 sprint(caller, "\nUsage:^3 cmd ready\n");
409 sprint(caller, " No arguments required.\n");
415 void ClientCommand_say(entity caller, int request, int argc, string command)
419 case CMD_REQUEST_COMMAND:
421 if (argc >= 2) Say(caller, false, NULL, substring(command, argv_start_index(1), argv_end_index(-1) - argv_start_index(1)), 1);
422 return; // never fall through to usage
426 case CMD_REQUEST_USAGE:
428 sprint(caller, "\nUsage:^3 cmd say <message>\n");
429 sprint(caller, " Where 'message' is the string of text to say.\n");
435 void ClientCommand_say_team(entity caller, int request, int argc, string command)
439 case CMD_REQUEST_COMMAND:
442 Say(caller, true, NULL, substring(command, argv_start_index(1), argv_end_index(-1) - argv_start_index(1)), 1);
443 return; // never fall through to usage
447 case CMD_REQUEST_USAGE:
449 sprint(caller, "\nUsage:^3 cmd say_team <message>\n");
450 sprint(caller, " Where 'message' is the string of text to say.\n");
457 void ClientCommand_selectteam(entity caller, int request, int argc)
461 case CMD_REQUEST_COMMAND:
467 if (!IS_CLIENT(caller))
473 sprint(caller, "^7selectteam can only be used in teamgames\n");
476 if (Player_GetForcedTeamIndex(caller) > 0)
478 sprint(caller, "^7selectteam can not be used as your team is forced\n");
483 sprint(caller, "^7The game has already begun, you must wait until the next map to be able to join a team.\n");
491 selection = NUM_TEAM_1;
496 selection = NUM_TEAM_2;
501 selection = NUM_TEAM_3;
506 selection = NUM_TEAM_4;
519 if (caller.team == selection && selection != -1 && !IS_DEAD(caller))
521 sprint(caller, "^7You already are on that team.\n");
524 if (CS(caller).wasplayer && autocvar_g_changeteam_banned)
526 sprint(caller, "^1You cannot change team, forbidden by the server.\n");
529 if ((selection != -1) && autocvar_g_balance_teams &&
530 autocvar_g_balance_teams_prevent_imbalance)
532 entity balance = TeamBalance_CheckAllowedTeams(caller);
533 TeamBalance_GetTeamCounts(balance, caller);
534 if ((Team_IndexToBit(Team_TeamToIndex(selection)) &
535 TeamBalance_FindBestTeams(balance, caller, false)) == 0)
537 Send_Notification(NOTIF_ONE, caller, MSG_INFO, INFO_TEAMCHANGE_LARGERTEAM);
538 TeamBalance_Destroy(balance);
541 TeamBalance_Destroy(balance);
543 ClientKill_TeamChange(caller, selection);
544 if (!IS_PLAYER(caller))
546 caller.team_selected = true; // avoids asking again for team selection on join
551 sprint(caller, "Incorrect parameters for ^2selectteam^7\n");
552 case CMD_REQUEST_USAGE:
554 sprint(caller, "\nUsage:^3 cmd selectteam team\n");
555 sprint(caller, " Where 'team' is the prefered team to try and join.\n");
556 sprint(caller, " Full list of options here: \"red, blue, yellow, pink, auto\"\n");
562 void ClientCommand_selfstuff(entity caller, int request, string command)
566 case CMD_REQUEST_COMMAND:
570 stuffcmd(caller, substring(command, argv_start_index(1), argv_end_index(-1) - argv_start_index(1)));
576 sprint(caller, "Incorrect parameters for ^2selfstuff^7\n");
577 case CMD_REQUEST_USAGE:
579 sprint(caller, "\nUsage:^3 cmd selfstuff <command>\n");
580 sprint(caller, " Where 'command' is the string to be stuffed to your client.\n");
586 void ClientCommand_sentcvar(entity caller, int request, int argc, string command)
590 case CMD_REQUEST_COMMAND:
597 if (argc == 2) // undefined cvar: use the default value on the server then
599 s = strcat(substring(command, argv_start_index(0), argv_end_index(1) - argv_start_index(0)), " \"", cvar_defstring(argv(1)), "\"");
603 GetCvars(caller, CS(caller), 1);
610 sprint(caller, "Incorrect parameters for ^2sentcvar^7\n");
611 case CMD_REQUEST_USAGE:
613 sprint(caller, "\nUsage:^3 cmd sentcvar <cvar>\n");
614 sprint(caller, " Where 'cvar' is the cvar plus arguments to send to the server.\n");
620 void ClientCommand_spectate(entity caller, int request)
624 case CMD_REQUEST_COMMAND:
626 if (!intermission_running && IS_CLIENT(caller))
628 if((IS_SPEC(caller) || IS_OBSERVER(caller)) && argv(1) != "")
630 entity client = GetFilteredEntity(argv(1));
631 int spec_accepted = VerifyClientEntity(client, false, false);
632 if(spec_accepted > 0 && IS_PLAYER(client))
634 if(Spectate(caller, client))
635 return; // fall back to regular handling
639 int mutator_returnvalue = MUTATOR_CALLHOOK(ClientCommand_Spectate, caller);
641 if (mutator_returnvalue == MUT_SPECCMD_RETURN) return;
643 if ((IS_PLAYER(caller) || mutator_returnvalue == MUT_SPECCMD_FORCE))
644 if (autocvar_sv_spectate == 1)
645 ClientKill_TeamChange(caller, -2); // observe
647 return; // never fall through to usage
651 case CMD_REQUEST_USAGE:
653 sprint(caller, "\nUsage:^3 cmd spectate <client>\n");
654 sprint(caller, " Where 'client' can be the player to spectate.\n");
660 void ClientCommand_suggestmap(entity caller, int request, int argc)
664 case CMD_REQUEST_COMMAND:
668 sprint(caller, strcat(MapVote_Suggest(caller, argv(1)), "\n"));
674 sprint(caller, "Incorrect parameters for ^2suggestmap^7\n");
675 case CMD_REQUEST_USAGE:
677 sprint(caller, "\nUsage:^3 cmd suggestmap map\n");
678 sprint(caller, " Where 'map' is the name of the map to suggest.\n");
684 void ClientCommand_tell(entity caller, int request, int argc, string command)
688 case CMD_REQUEST_COMMAND:
692 if(!IS_CLIENT(caller) && IS_REAL_CLIENT(caller)) // connecting
694 print_to(caller, "You can't ^2tell^7 a message while connecting.");
698 entity tell_to = GetIndexedEntity(argc, 1);
699 float tell_accepted = VerifyClientEntity(tell_to, true, false);
701 if (tell_accepted > 0) // the target is a real client
703 if (tell_to != caller) // and we're allowed to send to them :D
705 // workaround for argv indexes indexing ascii chars instead of utf8 chars
706 // In this case when the player name contains utf8 chars
707 // the message gets partially trimmed in the beginning.
708 // Potentially this bug affects any substring call that uses
709 // argv_start_index and argv_end_index.
711 string utf8_enable_save = cvar_string("utf8_enable");
712 cvar_set("utf8_enable", "0");
713 string msg = substring(command, argv_start_index(next_token), argv_end_index(-1) - argv_start_index(next_token));
714 cvar_set("utf8_enable", utf8_enable_save);
716 Say(caller, false, tell_to, msg, true);
719 else { print_to(caller, "You can't ^2tell^7 a message to yourself."); return; }
721 else if (argv(1) == "#0")
723 trigger_magicear_processmessage_forallears(caller, -1, NULL, substring(command, argv_start_index(next_token), argv_end_index(-1) - argv_start_index(next_token)));
726 else { print_to(caller, strcat("tell: ", GetClientErrorString(tell_accepted, argv(1)), ".")); return; }
731 sprint(caller, "Incorrect parameters for ^2tell^7\n");
732 case CMD_REQUEST_USAGE:
734 sprint(caller, "\nUsage:^3 cmd tell client <message>\n");
735 sprint(caller, " Where 'client' is the entity number or name of the player to send 'message' to.\n");
741 void ClientCommand_voice(entity caller, int request, int argc, string command)
745 case CMD_REQUEST_COMMAND:
749 entity e = GetVoiceMessage(argv(1));
752 sprint(caller, sprintf("Invalid voice. Use one of: %s\n", allvoicesamples));
757 msg = substring(command, argv_start_index(2), argv_end_index(-1) - argv_start_index(2));
758 VoiceMessage(caller, e, msg);
765 sprint(caller, "Incorrect parameters for ^2voice^7\n");
766 case CMD_REQUEST_USAGE:
768 sprint(caller, "\nUsage:^3 cmd voice messagetype <soundname>\n");
769 sprint(caller, " 'messagetype' is the type of broadcast to do, like team only or such,\n");
770 sprint(caller, " and 'soundname' is the string/filename of the sound/voice message to play.\n");
776 /* use this when creating a new command, making sure to place it in alphabetical order... also,
777 ** ADD ALL NEW COMMANDS TO commands.cfg WITH PROPER ALIASES IN THE SAME FASHION!
778 void ClientCommand_(entity caller, int request)
782 case CMD_REQUEST_COMMAND:
785 return; // never fall through to usage
789 case CMD_REQUEST_USAGE:
791 sprint(caller, "\nUsage:^3 cmd \n");
792 sprint(caller, " No arguments required.\n");
800 // =====================================
801 // Macro system for networked commands
802 // =====================================
804 // Do not hard code aliases for these, instead create them in commands.cfg... also: keep in alphabetical order, please ;)
805 #define CLIENT_COMMANDS(ent, request, arguments, command) \
806 CLIENT_COMMAND("autoswitch", ClientCommand_autoswitch(ent, request, arguments), "Whether or not to switch automatically when getting a better weapon") \
807 CLIENT_COMMAND("clientversion", ClientCommand_clientversion(ent, request, arguments), "Release version of the game") \
808 CLIENT_COMMAND("join", ClientCommand_join(ent, request), "Become a player in the game") \
809 CLIENT_COMMAND("kill", ClientCommand_kill(ent, request), "Become a member of the dead") \
810 CLIENT_COMMAND("minigame", ClientCommand_minigame(ent, request, arguments, command), "Start a minigame") \
811 CLIENT_COMMAND("mv_getpicture", ClientCommand_mv_getpicture(ent, request, arguments), "Retrieve mapshot picture from the server") \
812 CLIENT_COMMAND("physics", ClientCommand_physics(ent, request, arguments), "Change physics set") \
813 CLIENT_COMMAND("ready", ClientCommand_ready(ent, request), "Qualify as ready to end warmup stage (or restart server if allowed)") \
814 CLIENT_COMMAND("say", ClientCommand_say(ent, request, arguments, command), "Print a message to chat to all players") \
815 CLIENT_COMMAND("say_team", ClientCommand_say_team(ent, request, arguments, command), "Print a message to chat to all team mates") \
816 CLIENT_COMMAND("selectteam", ClientCommand_selectteam(ent, request, arguments), "Attempt to choose a team to join into") \
817 CLIENT_COMMAND("selfstuff", ClientCommand_selfstuff(ent, request, command), "Stuffcmd a command to your own client") \
818 CLIENT_COMMAND("sentcvar", ClientCommand_sentcvar(ent, request, arguments, command), "New system for sending a client cvar to the server") \
819 CLIENT_COMMAND("spectate", ClientCommand_spectate(ent, request), "Become an observer") \
820 CLIENT_COMMAND("suggestmap", ClientCommand_suggestmap(ent, request, arguments), "Suggest a map to the mapvote at match end") \
821 CLIENT_COMMAND("tell", ClientCommand_tell(ent, request, arguments, command), "Send a message directly to a player") \
822 CLIENT_COMMAND("voice", ClientCommand_voice(ent, request, arguments, command), "Send voice message via sound") \
823 CLIENT_COMMAND("wpeditor", ClientCommand_wpeditor(ent, request, arguments), "Waypoint editor commands") \
826 void ClientCommand_macro_help(entity caller)
828 #define CLIENT_COMMAND(name, function, description) \
829 { sprint(caller, " ^2", name, "^7: ", description, "\n"); }
831 CLIENT_COMMANDS(NULL, 0, 0, "");
832 #undef CLIENT_COMMAND
835 float ClientCommand_macro_command(int argc, entity caller, string command)
837 #define CLIENT_COMMAND(name, function, description) \
838 { if (name == strtolower(argv(0))) { function; return true; } }
840 CLIENT_COMMANDS(caller, CMD_REQUEST_COMMAND, argc, command);
841 #undef CLIENT_COMMAND
846 float ClientCommand_macro_usage(int argc, entity caller)
848 #define CLIENT_COMMAND(name, function, description) \
849 { if (name == strtolower(argv(1))) { function; return true; } }
851 CLIENT_COMMANDS(caller, CMD_REQUEST_USAGE, argc, "");
852 #undef CLIENT_COMMAND
857 void ClientCommand_macro_write_aliases(float fh)
859 #define CLIENT_COMMAND(name, function, description) \
860 { CMD_Write_Alias("qc_cmd_cmd", name, description); }
862 CLIENT_COMMANDS(NULL, 0, 0, "");
863 #undef CLIENT_COMMAND
866 // ======================================
867 // Main Function Called By Engine (cmd)
868 // ======================================
869 // If this function exists, server game code parses clientcommand before the engine code gets it.
871 void SV_ParseClientCommand(entity this, string command)
873 // If invalid UTF-8, don't even parse it
874 string command2 = "";
875 float len = strlen(command);
877 for (i = 0; i < len; ++i)
878 command2 = strcat(command2, chr2str(str2chr(command, i)));
879 if (command != command2) return;
881 // if we're banned, don't even parse the command
882 if (Ban_MaybeEnforceBanOnce(this)) return;
884 int argc = tokenize_console(command);
886 // Guide for working with argc arguments by example:
887 // argc: 1 - 2 - 3 - 4
888 // argv: 0 - 1 - 2 - 3
889 // cmd vote - master - login - password
892 switch (strtolower(argv(0)))
894 // exempt commands which are not subject to floodcheck
895 case "begin": break; // handled by engine in host_cmd.c
896 case "download": break; // handled by engine in cl_parse.c
897 case "mv_getpicture": break; // handled by server in this file
898 case "wpeditor": break; // handled by server in this file
899 case "pause": break; // handled by engine in host_cmd.c
900 case "prespawn": break; // handled by engine in host_cmd.c
901 case "sentcvar": break; // handled by server in this file
902 case "spawn": break; // handled by engine in host_cmd.c
903 case "c2s": Net_ClientCommand(this, command); return; // handled by net.qh
906 if (SV_ParseClientCommand_floodcheck(this)) break; // "true": continue, as we're not flooding yet
907 else return; // "false": not allowed to continue, halt // print("^1ERROR: ^7ANTISPAM CAUGHT: ", command, ".\n");
910 /* NOTE: should this be disabled? It can be spammy perhaps, but hopefully it's okay for now */
911 if (argv(0) == "help")
915 sprint(this, "\nClient networked commands:\n");
916 ClientCommand_macro_help(this);
918 sprint(this, "\nCommon networked commands:\n");
919 CommonCommand_macro_help(this);
921 sprint(this, "\nUsage:^3 cmd COMMAND...^7, where possible commands are listed above.\n");
922 sprint(this, "For help about a specific command, type cmd help COMMAND\n");
925 else if (CommonCommand_macro_usage(argc, this)) // Instead of trying to call a command, we're going to see detailed information about it
929 else if (ClientCommand_macro_usage(argc, this)) // same, but for normal commands now
934 else if (MUTATOR_CALLHOOK(SV_ParseClientCommand, this, strtolower(argv(0)), argc, command))
936 return; // handled by a mutator
938 else if (CheatCommand(this, argc))
940 return; // handled by server/cheats.qc
942 else if (CommonCommand_macro_command(argc, this, command))
944 return; // handled by server/command/common.qc
946 else if (ClientCommand_macro_command(argc, this, command)) // continue as usual and scan for normal commands
948 return; // handled by one of the above ClientCommand_* functions
952 clientcommand(this, command);