/* server/utilities/command_parser.qc Contains SV_ParseClientCommand(), helper functions for server commands, and a table storing command information. Modeled after pr_cmds. Copyright (C) 2021-2024 NZ:P Team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to: Free Software Foundation, Inc. 59 Temple Place - Suite 330 Boston, MA 02111-1307, USA */ void(vector where, float type) Spawn_Powerup; void(entity who, float value, float impacted_by_2x_points) Player_ChangeScore; // Whether the command prohibits client-sending. float client_parse_override; // Success/Failure return codes #define COMMAND_SUCCESS 0 #define COMMAND_FAILURE 1 // // Command_give(params) // Usage: give // float(string params) Command_give = { // Anti-Cheat in Co-Op. if (player_count && cheats_have_been_activated == false) { bprint(PRINT_HIGH, "Someone tried to issue Give in a Co-Op match. Nice try!\n"); return COMMAND_FAILURE; } float wep = stof(argv(1)); if (wep) { Weapon_GiveWeapon(wep, 0, 0); return COMMAND_SUCCESS; } return COMMAND_FAILURE; } // // Command_addmoney(params) // Usage: addmoney // Gives amount of points to the client // who requested it. // float(string params) Command_addmoney = { // Anti-Cheat in Co-Op. if (player_count && cheats_have_been_activated == false) { bprint(PRINT_HIGH, "Someone tried to issue Add Money in a Co-Op match. Nice try!\n"); return COMMAND_FAILURE; } // Grab parameters. tokenize(params); float point_value = stof(argv(0)); // Safety checks if (point_value == 0) { sprint(self, 1, "Command_addmoney: is either zero or blank string. Failing.\n"); return COMMAND_FAILURE; } // Assign points to the player. Player_ChangeScore(self, point_value, false); return COMMAND_SUCCESS; } // // Command_softrestart() // Executes the Soft_Restart QuakeC function. // Useful for debugging its functionality. // float(string params) Command_softrestart = { Soft_Restart(); return COMMAND_SUCCESS; } // // Command_godmode() // Toggles God Mode. // float(string params) Command_godmode = { // Anti-Cheat in Co-Op. if (player_count && cheats_have_been_activated == false) { bprint(PRINT_HIGH, "Someone tried to issue God Mode in a Co-Op match. Nice try!\n"); return COMMAND_FAILURE; } client_parse_override = false; return COMMAND_SUCCESS; } // // Command_noclip() // Toggles No Clip. // float(string params) Command_noclip = { // Anti-Cheat in Co-Op. if (player_count && cheats_have_been_activated == false) { bprint(PRINT_HIGH, "Someone tried to issue No-Clip in a Co-Op match. Nice try!\n"); return COMMAND_FAILURE; } if (self.model == "") { setmodel(self, "models/player.mdl"); setsize(self, VEC_HULL_MIN, VEC_HULL_MAX); } else { setmodel(self, ""); } client_parse_override = false; return COMMAND_SUCCESS; } // // Command_powerup() // Spawns a Power-Up of a given ID in front of you. // float(string params) Command_powerup = { // Anti-Cheat in Co-Op. if (player_count && cheats_have_been_activated == false) { bprint(PRINT_HIGH, "Someone tried to issue spawn_pu in a Co-Op match. Nice try!\n"); return COMMAND_FAILURE; } // Grab parameters. tokenize(params); float value = stof(argv(0)); makevectors(self.angles); Spawn_Powerup(self.origin + v_forward * 50, value); return COMMAND_SUCCESS; }; // // Command_tracedmgmultiplier() // Multiplies damage output with weapons that fire Traces. // float(string params) Command_tracedmgmultiplier = { // Anti-Cheat in Co-Op. if (player_count && cheats_have_been_activated == false) { bprint(PRINT_HIGH, "Someone tried to issue sv_tracedmgmultiplier in a Co-Op match. Nice try!\n"); return COMMAND_FAILURE; } // Grab parameters. tokenize(params); float value = stof(argv(0)); if (value <= 0) { bprint(PRINT_HIGH, "Command_tracedmgmultiplier: 0 or less than 0 multiplier not allowed. Failing.\n"); return COMMAND_FAILURE; } global_trace_damage_multiplier = value; return COMMAND_SUCCESS; } // // Command_say() // Sends message via CSQC to other clients (FTE-only) // float(string params) Command_say = { // Grab parameters. tokenize(params); string value = argv(0); #ifdef FTE CSQC_SendChatMessage(self.playernum, params); #endif // FTE client_parse_override = false; return COMMAND_SUCCESS; } // // Server command table // command_name : Command string entered into developer console. // command_function : QuakeC function called when command is executed. // Returns 0 for success, 1 for failure. // requires_arguments : Whether or not to expect arguments to be passed // with the command. // command_description : Called when no params (when applicable) are given. // var struct { string command_name; float(string params) command_function; float requires_arguments; string command_description; } server_commands[] = { {"addmoney", Command_addmoney, true, "Usage: addmoney \n Gives `point_value` amount of points to the client who requested it.\n"}, {"give", Command_give, true, "Usage: give \n Gives `weapon` of index.\n"}, {"qc_soft_restart", Command_softrestart, false, "Executes the Soft_Restart QuakeC function. Useful for debugging its functionality.\n"}, {"god", Command_godmode, false, "Toggles God Mode.\n"}, {"noclip", Command_noclip, false, "Toggles No Clip.\n"}, {"sv_tracedmgmultiplier", Command_tracedmgmultiplier, true, "Multiplies damage output with weapons that fire Traces.\n"}, {"spawn_pu", Command_powerup, true, "Usage: spawn_pu \n Spawns a Power-Up of a given ID in front of you. -1 for random.\n"}, {"say", Command_say, true, "Usage: say \n Sends a chat message to CSQC for other clients.\n"} }; // // SV_IsCommand(command_string) // Takes a single string and references if it is a // registered command, returns true if it is. Useful // for cl_chatmode interferring with custom commands. // float(string command_string) SV_IsCommand = { for (float i = 0; i < server_commands.length; i++) { if (command_string == server_commands[i].command_name) return true; } return false; } // // SV_ParseClientCommand(command_string) // Server-Side client command parser to add special // gameplay commands that interact with QuakeC. // void(string command_string) SV_ParseClientCommand = { // If true, we will avoid sending the command info // to the client. client_parse_override = false; // Get the string ready for arg parsing tokenize(command_string); // Grab the command string string command = argv(0); // Check for 'say' prefix (`cl_chatmode 2` will append it // to everything unregistered by the client). Re-tokenize // if found. if (command == "say" && SV_IsCommand(argv(1))) { string fixed_command_string = argv(1); tokenize(fixed_command_string); command = argv(0); } // Now iterate over our commands for (float i = 0; i < server_commands.length; i++) { // Command names match if (command == server_commands[i].command_name) { // Override Client Commands client_parse_override = true; // Return description if no params are given if (argv(1) == "" && server_commands[i].requires_arguments == true) { sprint(self, 1, server_commands[i].command_description); } else { if (server_commands[i].command_function(argv(1)) == COMMAND_FAILURE) { sprint(self, 1, "Command executed but failed to complete.\n"); } } } } // Client override was disabled, so let the engine // deal with whatever was sent. #ifdef FTE if (client_parse_override == false) clientcommand(self, command_string); #endif // FTE }; #ifndef FTE void() ParseClientCommand = {SV_ParseClientCommand(CMD_STRING);} #endif // FTE