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) == "lock")
210 waypoint_lock(caller);
213 else if (argv(1) == "unreachable")
215 if (!IS_PLAYER(caller))
216 sprint(caller, "ERROR: this command works only if you are player\n");
218 waypoint_unreachable(caller);
221 else if (argv(1) == "saveall")
226 else if (argv(1) == "relinkall")
228 waypoint_schedulerelinkall();
231 else if (argv(1) == "symaxis")
233 if (argv(2) == "set" || argv(2) == "get")
235 waypoint_getSymmetricalAxis_cmd(caller, (argv(2) == "set"), 3);
239 else if (argv(1) == "symorigin")
241 if (argv(2) == "set" || argv(2) == "get")
243 waypoint_getSymmetricalOrigin_cmd(caller, (argv(2) == "set"), 3);
251 sprint(caller, "Incorrect parameters for ^2wpeditor^7\n");
252 case CMD_REQUEST_USAGE:
254 sprint(caller, "\nUsage:^3 cmd wpeditor action\n");
255 sprint(caller, " Where 'action' can be:\n");
256 sprint(caller, " ^5spawn^7: spawns a waypoint at player's position\n");
257 sprint(caller, " ^5remove^7: remove player's nearest waypoint\n");
258 sprint(caller, " ^5unreachable^7: useful to reveal waypoints and items unreachable from the current position and spawnpoints without a nearest waypoint\n");
259 sprint(caller, " ^5saveall^7: saves all waypoints and links to file\n");
260 sprint(caller, " ^5relinkall^7: relink all waypoints as if they were respawned\n");
261 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");
262 sprint(caller, " ^5spawn jump^7: spawns a jump waypoint (spawn another waypoint to create destination)\n");
263 sprint(caller, " ^5spawn crouch^7: spawns a crouch waypoint\n");
264 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");
265 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");
266 sprint(caller, " ^5hardwire crosshair^7: marks the waypoint at crosshair instead of the nearest waypoint\n");
267 sprint(caller, " ^5lock^7: locks link display of the aimed waypoint (unlocks if no waypoint is found at crosshair's position)\n");
268 sprint(caller, " ^5symorigin get|set\n");
269 sprint(caller, " ^5symorigin get|set p1 p2 ... pX\n");
270 sprint(caller, " ^5symaxis get|set p1 p2\n");
271 sprint(caller, " ^7 where p1 p2 ... pX are positions (\"x y z\", z can be omitted) that you know are perfectly symmetrical");
272 sprint(caller, " ^7 so you can determine origin/axis of symmetry of maps without ctf flags or where flags aren't perfectly symmetrical\n");
278 void ClientCommand_join(entity caller, int request)
282 case CMD_REQUEST_COMMAND:
285 if (IS_CLIENT(caller) && !IS_PLAYER(caller))
286 if (joinAllowed(caller))
289 return; // never fall through to usage
293 case CMD_REQUEST_USAGE:
295 sprint(caller, "\nUsage:^3 cmd join\n");
296 sprint(caller, " No arguments required.\n");
302 void ClientCommand_kill(entity caller, int request)
306 case CMD_REQUEST_COMMAND:
308 if(IS_SPEC(caller) || IS_OBSERVER(caller))
309 return; // no point warning about this, command does nothing
311 if(GetResource(caller, RES_HEALTH) <= 0)
313 sprint(caller, "Can't die - you are already dead!\n");
319 return; // never fall through to usage
323 case CMD_REQUEST_USAGE:
325 sprint(caller, "\nUsage:^3 cmd kill\n");
326 sprint(caller, " No arguments required.\n");
332 void ClientCommand_physics(entity caller, int request, int argc)
336 case CMD_REQUEST_COMMAND:
338 string command = strtolower(argv(1));
340 if (!autocvar_g_physics_clientselect)
342 sprint(caller, "Client physics selection is currently disabled.\n");
346 if (command == "list" || command == "help")
348 sprint(caller, strcat("Available physics sets: \n\n", autocvar_g_physics_clientselect_options, " default\n"));
352 if (Physics_Valid(command) || command == "default")
354 stuffcmd(caller, strcat("\nseta cl_physics ", command, "\nsendcvar cl_physics\n"));
355 sprint(caller, strcat("^2Physics set successfully changed to ^3", command, "\n"));
361 sprint(caller, strcat("Current physics set: ^3", CS(caller).cvar_cl_physics, "\n"));
362 case CMD_REQUEST_USAGE:
364 sprint(caller, "\nUsage:^3 cmd physics <physics>\n");
365 sprint(caller, " See 'cmd physics list' for available physics sets.\n");
366 sprint(caller, " Argument 'default' resets to standard physics.\n");
372 void ClientCommand_ready(entity caller, int request) // todo: anti-spam for toggling readyness
376 case CMD_REQUEST_COMMAND:
378 if (IS_CLIENT(caller))
380 if (warmup_stage || sv_ready_restart || g_race_qualifying == 2)
382 if (!readyrestart_happened || sv_ready_restart_repeatable)
384 if (time < game_starttime) // game is already restarting
386 if (caller.ready) // toggle
388 caller.ready = false;
389 if(IS_PLAYER(caller) || caller.caplayer == 1)
390 bprint(playername(caller, false), "^2 is ^1NOT^2 ready\n");
395 if(IS_PLAYER(caller) || caller.caplayer == 1)
396 bprint(playername(caller, false), "^2 is ready\n");
399 // cannot reset the game while a timeout is active!
400 if (!timeout_status) ReadyCount();
404 sprint(caller, "^1Game has already been restarted\n");
408 return; // never fall through to usage
412 case CMD_REQUEST_USAGE:
414 sprint(caller, "\nUsage:^3 cmd ready\n");
415 sprint(caller, " No arguments required.\n");
421 void ClientCommand_say(entity caller, int request, int argc, string command)
425 case CMD_REQUEST_COMMAND:
427 if (argc >= 2) Say(caller, false, NULL, substring(command, argv_start_index(1), argv_end_index(-1) - argv_start_index(1)), 1);
428 return; // never fall through to usage
432 case CMD_REQUEST_USAGE:
434 sprint(caller, "\nUsage:^3 cmd say <message>\n");
435 sprint(caller, " Where 'message' is the string of text to say.\n");
441 void ClientCommand_say_team(entity caller, int request, int argc, string command)
445 case CMD_REQUEST_COMMAND:
448 Say(caller, true, NULL, substring(command, argv_start_index(1), argv_end_index(-1) - argv_start_index(1)), 1);
449 return; // never fall through to usage
453 case CMD_REQUEST_USAGE:
455 sprint(caller, "\nUsage:^3 cmd say_team <message>\n");
456 sprint(caller, " Where 'message' is the string of text to say.\n");
463 void ClientCommand_selectteam(entity caller, int request, int argc)
467 case CMD_REQUEST_COMMAND:
473 if (!IS_CLIENT(caller))
479 sprint(caller, "^7selectteam can only be used in teamgames\n");
482 if (Player_GetForcedTeamIndex(caller) > 0)
484 sprint(caller, "^7selectteam can not be used as your team is forced\n");
489 sprint(caller, "^7The game has already begun, you must wait until the next map to be able to join a team.\n");
497 selection = NUM_TEAM_1;
502 selection = NUM_TEAM_2;
507 selection = NUM_TEAM_3;
512 selection = NUM_TEAM_4;
525 if (caller.team == selection && selection != -1 && !IS_DEAD(caller))
527 sprint(caller, "^7You already are on that team.\n");
530 if (CS(caller).wasplayer && autocvar_g_changeteam_banned)
532 sprint(caller, "^1You cannot change team, forbidden by the server.\n");
535 if ((selection != -1) && autocvar_g_balance_teams &&
536 autocvar_g_balance_teams_prevent_imbalance)
538 entity balance = TeamBalance_CheckAllowedTeams(caller);
539 TeamBalance_GetTeamCounts(balance, caller);
540 if ((Team_IndexToBit(Team_TeamToIndex(selection)) &
541 TeamBalance_FindBestTeams(balance, caller, false)) == 0)
543 Send_Notification(NOTIF_ONE, caller, MSG_INFO, INFO_TEAMCHANGE_LARGERTEAM);
544 TeamBalance_Destroy(balance);
547 TeamBalance_Destroy(balance);
549 ClientKill_TeamChange(caller, selection);
550 if (!IS_PLAYER(caller))
552 caller.team_selected = true; // avoids asking again for team selection on join
557 sprint(caller, "Incorrect parameters for ^2selectteam^7\n");
558 case CMD_REQUEST_USAGE:
560 sprint(caller, "\nUsage:^3 cmd selectteam team\n");
561 sprint(caller, " Where 'team' is the prefered team to try and join.\n");
562 sprint(caller, " Full list of options here: \"red, blue, yellow, pink, auto\"\n");
568 void ClientCommand_selfstuff(entity caller, int request, string command)
572 case CMD_REQUEST_COMMAND:
576 stuffcmd(caller, substring(command, argv_start_index(1), argv_end_index(-1) - argv_start_index(1)));
582 sprint(caller, "Incorrect parameters for ^2selfstuff^7\n");
583 case CMD_REQUEST_USAGE:
585 sprint(caller, "\nUsage:^3 cmd selfstuff <command>\n");
586 sprint(caller, " Where 'command' is the string to be stuffed to your client.\n");
592 void ClientCommand_sentcvar(entity caller, int request, int argc, string command)
596 case CMD_REQUEST_COMMAND:
603 if (argc == 2) // undefined cvar: use the default value on the server then
605 s = strcat(substring(command, argv_start_index(0), argv_end_index(1) - argv_start_index(0)), " \"", cvar_defstring(argv(1)), "\"");
609 GetCvars(caller, CS(caller), 1);
616 sprint(caller, "Incorrect parameters for ^2sentcvar^7\n");
617 case CMD_REQUEST_USAGE:
619 sprint(caller, "\nUsage:^3 cmd sentcvar <cvar>\n");
620 sprint(caller, " Where 'cvar' is the cvar plus arguments to send to the server.\n");
626 void ClientCommand_spectate(entity caller, int request)
630 case CMD_REQUEST_COMMAND:
632 if (!intermission_running && IS_CLIENT(caller))
634 if((IS_SPEC(caller) || IS_OBSERVER(caller)) && argv(1) != "")
636 entity client = GetFilteredEntity(argv(1));
637 int spec_accepted = VerifyClientEntity(client, false, false);
638 if(spec_accepted > 0 && IS_PLAYER(client))
640 if(Spectate(caller, client))
641 return; // fall back to regular handling
645 int mutator_returnvalue = MUTATOR_CALLHOOK(ClientCommand_Spectate, caller);
647 if (mutator_returnvalue == MUT_SPECCMD_RETURN) return;
649 if ((IS_PLAYER(caller) || mutator_returnvalue == MUT_SPECCMD_FORCE))
650 if (autocvar_sv_spectate == 1)
651 ClientKill_TeamChange(caller, -2); // observe
653 return; // never fall through to usage
657 case CMD_REQUEST_USAGE:
659 sprint(caller, "\nUsage:^3 cmd spectate <client>\n");
660 sprint(caller, " Where 'client' can be the player to spectate.\n");
666 void ClientCommand_suggestmap(entity caller, int request, int argc)
670 case CMD_REQUEST_COMMAND:
674 sprint(caller, strcat(MapVote_Suggest(caller, argv(1)), "\n"));
680 sprint(caller, "Incorrect parameters for ^2suggestmap^7\n");
681 case CMD_REQUEST_USAGE:
683 sprint(caller, "\nUsage:^3 cmd suggestmap map\n");
684 sprint(caller, " Where 'map' is the name of the map to suggest.\n");
690 void ClientCommand_tell(entity caller, int request, int argc, string command)
694 case CMD_REQUEST_COMMAND:
698 if(!IS_CLIENT(caller) && IS_REAL_CLIENT(caller)) // connecting
700 print_to(caller, "You can't ^2tell^7 a message while connecting.");
704 entity tell_to = GetIndexedEntity(argc, 1);
705 float tell_accepted = VerifyClientEntity(tell_to, true, false);
707 if (tell_accepted > 0) // the target is a real client
709 if (tell_to != caller) // and we're allowed to send to them :D
711 // workaround for argv indexes indexing ascii chars instead of utf8 chars
712 // In this case when the player name contains utf8 chars
713 // the message gets partially trimmed in the beginning.
714 // Potentially this bug affects any substring call that uses
715 // argv_start_index and argv_end_index.
717 string utf8_enable_save = cvar_string("utf8_enable");
718 cvar_set("utf8_enable", "0");
719 string msg = substring(command, argv_start_index(next_token), argv_end_index(-1) - argv_start_index(next_token));
720 cvar_set("utf8_enable", utf8_enable_save);
722 Say(caller, false, tell_to, msg, true);
725 else { print_to(caller, "You can't ^2tell^7 a message to yourself."); return; }
727 else if (argv(1) == "#0")
729 trigger_magicear_processmessage_forallears(caller, -1, NULL, substring(command, argv_start_index(next_token), argv_end_index(-1) - argv_start_index(next_token)));
732 else { print_to(caller, strcat("tell: ", GetClientErrorString(tell_accepted, argv(1)), ".")); return; }
737 sprint(caller, "Incorrect parameters for ^2tell^7\n");
738 case CMD_REQUEST_USAGE:
740 sprint(caller, "\nUsage:^3 cmd tell client <message>\n");
741 sprint(caller, " Where 'client' is the entity number or name of the player to send 'message' to.\n");
747 void ClientCommand_voice(entity caller, int request, int argc, string command)
751 case CMD_REQUEST_COMMAND:
755 entity e = GetVoiceMessage(argv(1));
758 sprint(caller, sprintf("Invalid voice. Use one of: %s\n", allvoicesamples));
763 msg = substring(command, argv_start_index(2), argv_end_index(-1) - argv_start_index(2));
764 VoiceMessage(caller, e, msg);
771 sprint(caller, "Incorrect parameters for ^2voice^7\n");
772 case CMD_REQUEST_USAGE:
774 sprint(caller, "\nUsage:^3 cmd voice messagetype <soundname>\n");
775 sprint(caller, " 'messagetype' is the type of broadcast to do, like team only or such,\n");
776 sprint(caller, " and 'soundname' is the string/filename of the sound/voice message to play.\n");
782 /* use this when creating a new command, making sure to place it in alphabetical order... also,
783 ** ADD ALL NEW COMMANDS TO commands.cfg WITH PROPER ALIASES IN THE SAME FASHION!
784 void ClientCommand_(entity caller, int request)
788 case CMD_REQUEST_COMMAND:
791 return; // never fall through to usage
795 case CMD_REQUEST_USAGE:
797 sprint(caller, "\nUsage:^3 cmd \n");
798 sprint(caller, " No arguments required.\n");
806 // =====================================
807 // Macro system for networked commands
808 // =====================================
810 // Do not hard code aliases for these, instead create them in commands.cfg... also: keep in alphabetical order, please ;)
811 #define CLIENT_COMMANDS(ent, request, arguments, command) \
812 CLIENT_COMMAND("autoswitch", ClientCommand_autoswitch(ent, request, arguments), "Whether or not to switch automatically when getting a better weapon") \
813 CLIENT_COMMAND("clientversion", ClientCommand_clientversion(ent, request, arguments), "Release version of the game") \
814 CLIENT_COMMAND("join", ClientCommand_join(ent, request), "Become a player in the game") \
815 CLIENT_COMMAND("kill", ClientCommand_kill(ent, request), "Become a member of the dead") \
816 CLIENT_COMMAND("minigame", ClientCommand_minigame(ent, request, arguments, command), "Start a minigame") \
817 CLIENT_COMMAND("mv_getpicture", ClientCommand_mv_getpicture(ent, request, arguments), "Retrieve mapshot picture from the server") \
818 CLIENT_COMMAND("physics", ClientCommand_physics(ent, request, arguments), "Change physics set") \
819 CLIENT_COMMAND("ready", ClientCommand_ready(ent, request), "Qualify as ready to end warmup stage (or restart server if allowed)") \
820 CLIENT_COMMAND("say", ClientCommand_say(ent, request, arguments, command), "Print a message to chat to all players") \
821 CLIENT_COMMAND("say_team", ClientCommand_say_team(ent, request, arguments, command), "Print a message to chat to all team mates") \
822 CLIENT_COMMAND("selectteam", ClientCommand_selectteam(ent, request, arguments), "Attempt to choose a team to join into") \
823 CLIENT_COMMAND("selfstuff", ClientCommand_selfstuff(ent, request, command), "Stuffcmd a command to your own client") \
824 CLIENT_COMMAND("sentcvar", ClientCommand_sentcvar(ent, request, arguments, command), "New system for sending a client cvar to the server") \
825 CLIENT_COMMAND("spectate", ClientCommand_spectate(ent, request), "Become an observer") \
826 CLIENT_COMMAND("suggestmap", ClientCommand_suggestmap(ent, request, arguments), "Suggest a map to the mapvote at match end") \
827 CLIENT_COMMAND("tell", ClientCommand_tell(ent, request, arguments, command), "Send a message directly to a player") \
828 CLIENT_COMMAND("voice", ClientCommand_voice(ent, request, arguments, command), "Send voice message via sound") \
829 CLIENT_COMMAND("wpeditor", ClientCommand_wpeditor(ent, request, arguments), "Waypoint editor commands") \
832 void ClientCommand_macro_help(entity caller)
834 #define CLIENT_COMMAND(name, function, description) \
835 { sprint(caller, " ^2", name, "^7: ", description, "\n"); }
837 CLIENT_COMMANDS(NULL, 0, 0, "");
838 #undef CLIENT_COMMAND
841 float ClientCommand_macro_command(int argc, entity caller, string command)
843 #define CLIENT_COMMAND(name, function, description) \
844 { if (name == strtolower(argv(0))) { function; return true; } }
846 CLIENT_COMMANDS(caller, CMD_REQUEST_COMMAND, argc, command);
847 #undef CLIENT_COMMAND
852 float ClientCommand_macro_usage(int argc, entity caller)
854 #define CLIENT_COMMAND(name, function, description) \
855 { if (name == strtolower(argv(1))) { function; return true; } }
857 CLIENT_COMMANDS(caller, CMD_REQUEST_USAGE, argc, "");
858 #undef CLIENT_COMMAND
863 void ClientCommand_macro_write_aliases(float fh)
865 #define CLIENT_COMMAND(name, function, description) \
866 { CMD_Write_Alias("qc_cmd_cmd", name, description); }
868 CLIENT_COMMANDS(NULL, 0, 0, "");
869 #undef CLIENT_COMMAND
872 // ======================================
873 // Main Function Called By Engine (cmd)
874 // ======================================
875 // If this function exists, server game code parses clientcommand before the engine code gets it.
877 void SV_ParseClientCommand(entity this, string command)
879 // If invalid UTF-8, don't even parse it
880 string command2 = "";
881 float len = strlen(command);
883 for (i = 0; i < len; ++i)
884 command2 = strcat(command2, chr2str(str2chr(command, i)));
885 if (command != command2) return;
887 // if we're banned, don't even parse the command
888 if (Ban_MaybeEnforceBanOnce(this)) return;
890 int argc = tokenize_console(command);
892 // Guide for working with argc arguments by example:
893 // argc: 1 - 2 - 3 - 4
894 // argv: 0 - 1 - 2 - 3
895 // cmd vote - master - login - password
898 switch (strtolower(argv(0)))
900 // exempt commands which are not subject to floodcheck
901 case "begin": break; // handled by engine in host_cmd.c
902 case "download": break; // handled by engine in cl_parse.c
903 case "mv_getpicture": break; // handled by server in this file
904 case "wpeditor": break; // handled by server in this file
905 case "pause": break; // handled by engine in host_cmd.c
906 case "prespawn": break; // handled by engine in host_cmd.c
907 case "sentcvar": break; // handled by server in this file
908 case "spawn": break; // handled by engine in host_cmd.c
909 case "c2s": Net_ClientCommand(this, command); return; // handled by net.qh
912 if (SV_ParseClientCommand_floodcheck(this)) break; // "true": continue, as we're not flooding yet
913 else return; // "false": not allowed to continue, halt // print("^1ERROR: ^7ANTISPAM CAUGHT: ", command, ".\n");
916 /* NOTE: should this be disabled? It can be spammy perhaps, but hopefully it's okay for now */
917 if (argv(0) == "help")
921 sprint(this, "\nClient networked commands:\n");
922 ClientCommand_macro_help(this);
924 sprint(this, "\nCommon networked commands:\n");
925 CommonCommand_macro_help(this);
927 sprint(this, "\nUsage:^3 cmd COMMAND...^7, where possible commands are listed above.\n");
928 sprint(this, "For help about a specific command, type cmd help COMMAND\n");
931 else if (CommonCommand_macro_usage(argc, this)) // Instead of trying to call a command, we're going to see detailed information about it
935 else if (ClientCommand_macro_usage(argc, this)) // same, but for normal commands now
940 else if (MUTATOR_CALLHOOK(SV_ParseClientCommand, this, strtolower(argv(0)), argc, command))
942 return; // handled by a mutator
944 else if (CheatCommand(this, argc))
946 return; // handled by server/cheats.qc
948 else if (CommonCommand_macro_command(argc, this, command))
950 return; // handled by server/command/common.qc
952 else if (ClientCommand_macro_command(argc, this, command)) // continue as usual and scan for normal commands
954 return; // handled by one of the above ClientCommand_* functions
958 clientcommand(this, command);