+
+void ClientCommand_suggestmap(float request, float argc)
+{
+ switch(request)
+ {
+ case CC_REQUEST_HELP:
+ sprint(self, " ^2suggestmap^7: Suggest a map to the mapvote at match end\n");
+ return;
+
+ case CC_REQUEST_COMMAND:
+ sprint(self, strcat(MapVote_Suggest(argv(1)), "\n"));
+ return; // never fall through to usage
+
+ default:
+ case CC_REQUEST_USAGE:
+ sprint(self, "\nUsage:^3 cmd suggestmap map\n");
+ sprint(self, " Where 'map' is the name of the map to suggest.\n");
+ return;
+ }
+}
+
+void ClientCommand_teamstatus(float request)
+{
+ switch(request)
+ {
+ case CC_REQUEST_HELP:
+ sprint(self, " ^2teamstatus^7: Print detailed score information for all players\n");
+ return;
+
+ case CC_REQUEST_COMMAND:
+ Score_NicePrint(self);
+ return; // never fall through to usage
+
+ default:
+ case CC_REQUEST_USAGE:
+ sprint(self, "\nUsage:^3 cmd teamstatus\n");
+ sprint(self, " No arguments required.\n");
+ return;
+ }
+}
+
+void ClientCommand_tell(float request, float argc, string command)
+{
+ entity e;
+
+ switch(request)
+ {
+ case CC_REQUEST_HELP:
+ sprint(self, " ^2tell^7: Send a message directly to a player\n");
+ return;
+
+ case CC_REQUEST_COMMAND:
+ e = GetCommandPlayerSlotTargetFromTokenizedCommand(argc, 1);
+ if(e && argc > ParseCommandPlayerSlotTarget_firsttoken)
+ {
+ Say(self, FALSE, e, substring(command, argv_start_index(ParseCommandPlayerSlotTarget_firsttoken), argv_end_index(-1) - argv_start_index(ParseCommandPlayerSlotTarget_firsttoken)), TRUE);
+ }
+ else
+ {
+ if(argc > ParseCommandPlayerSlotTarget_firsttoken)
+ trigger_magicear_processmessage_forallears(self, -1, world, substring(command, argv_start_index(ParseCommandPlayerSlotTarget_firsttoken), argv_end_index(-1) - argv_start_index(ParseCommandPlayerSlotTarget_firsttoken)));
+ }
+ return; // never fall through to usage
+
+ default:
+ case CC_REQUEST_USAGE:
+ sprint(self, "\nUsage:^3 cmd tell playerid <message>\n");
+ sprint(self, " Where 'playerid' is the entity number of the player to send the 'message' to.\n");
+ return;
+ }
+}
+
+void ClientCommand_timein(float request)
+{
+ switch(request)
+ {
+ case CC_REQUEST_HELP:
+ sprint(self, " ^2timein^7: Resume the game from being paused with a timeout\n");
+ return;
+
+ case CC_REQUEST_COMMAND:
+ if(self.flags & FL_CLIENT)
+ {
+ if(autocvar_sv_timeout)
+ {
+ if (!timeoutStatus)
+ return sprint(self, "^7Error: There is no active timeout which could be aborted!\n");
+ if (self != timeoutInitiator)
+ return sprint(self, "^7Error: You may not abort the active timeout. Only the player who called it can do that!\n");
+
+ if (timeoutStatus == 1)
+ {
+ remainingTimeoutTime = timeoutStatus = 0;
+ timeoutHandler.nextthink = time; //timeoutHandler has to take care of it immediately
+ bprint(strcat("^7The timeout was aborted by ", self.netname, " !\n"));
+ }
+ else if (timeoutStatus == 2)
+ {
+ //only shorten the remainingTimeoutTime if it makes sense
+ if( remainingTimeoutTime > (autocvar_sv_timeout_resumetime + 1) )
+ {
+ bprint(strcat("^1Attention: ^7", self.netname, " resumed the game! Prepare for battle!\n"));
+ remainingTimeoutTime = autocvar_sv_timeout_resumetime;
+ timeoutHandler.nextthink = time; //timeoutHandler has to take care of it immediately
+ }
+ else
+ sprint(self, "^7Error: Your resumegame call was discarded!\n");
+ }
+ }
+ }
+ return; // never fall through to usage
+
+ default:
+ case CC_REQUEST_USAGE:
+ sprint(self, "\nUsage:^3 cmd timein\n");
+ sprint(self, " No arguments required.\n");
+ return;
+ }
+}
+
+void ClientCommand_timeout(float request) // DEAR GOD THIS COMMAND IS TERRIBLE.
+{
+ switch(request)
+ {
+ case CC_REQUEST_HELP:
+ sprint(self, " ^2timeout^7: Call a timeout which pauses the game for certain amount of time unless unpaused\n");
+ return;
+
+ case CC_REQUEST_COMMAND:
+ if(self.flags & FL_CLIENT)
+ {
+ if(autocvar_sv_timeout)
+ {
+ if(self.classname == "player")
+ {
+ if(votecalled)
+ sprint(self, "^7Error: you can not call a timeout while a vote is active!\n");
+ else
+ {
+ if (inWarmupStage && !g_warmup_allow_timeout)
+ return sprint(self, "^7Error: You can not call a timeout in warmup-stage!\n");
+ if (time < game_starttime )
+ return sprint(self, "^7Error: You can not call a timeout while the map is being restarted!\n");
+
+ if (timeoutStatus != 2) {
+ //if the map uses a timelimit make sure that timeout cannot be called right before the map ends
+ if (autocvar_timelimit) {
+ //a timelimit was used
+ float myTl;
+ myTl = autocvar_timelimit;
+
+ float lastPossibleTimeout;
+ lastPossibleTimeout = (myTl*60) - autocvar_sv_timeout_leadtime - 1;
+
+ if (lastPossibleTimeout < time - game_starttime)
+ return sprint(self, "^7Error: It is too late to call a timeout now!\n");
+ }
+ }
+
+ //player may not call a timeout if he has no calls left
+ if (self.allowedTimeouts < 1)
+ return sprint(self, "^7Error: You already used all your timeout calls for this map!\n");
+
+
+ //now all required checks are passed
+ self.allowedTimeouts -= 1;
+ bprint(self.netname, " ^7called a timeout (", ftos(self.allowedTimeouts), " timeouts left)!\n"); //write a bprint who started the timeout (and how many he has left)
+ remainingTimeoutTime = autocvar_sv_timeout_length;
+ remainingLeadTime = autocvar_sv_timeout_leadtime;
+ timeoutInitiator = self;
+ if (timeoutStatus == 0) { //if another timeout was already active, don't change its status (which was 1 or 2) to 1, only change it to 1 if no timeout was active yet
+ timeoutStatus = 1;
+ //create the timeout indicator which centerprints the information to all players and takes care of pausing/unpausing
+ timeoutHandler = spawn();
+ timeoutHandler.think = timeoutHandler_Think;
+ }
+ timeoutHandler.nextthink = time; //always let the entity think asap
+
+ //inform all connected clients about the timeout call
+ Announce("timeoutcalled");
+ }
+ }
+ else
+ sprint(self, "^7Error: only players can call a timeout!\n");
+ }
+ }
+ return; // never fall through to usage
+
+ default:
+ case CC_REQUEST_USAGE:
+ sprint(self, "\nUsage:^3 cmd timeout\n");
+ sprint(self, " No arguments required.\n");
+ return;
+ }
+}
+
+void ClientCommand_voice(float request, float argc, string command)
+{
+ switch(request)
+ {
+ case CC_REQUEST_HELP:
+ sprint(self, " ^2voice^7: Send voice message via sound\n");
+ return;
+
+ case CC_REQUEST_COMMAND:
+ if(argc >= 3)
+ VoiceMessage(argv(1), substring(command, argv_start_index(2), argv_end_index(-1) - argv_start_index(2)));
+ else
+ VoiceMessage(argv(1), "");
+ return; // never fall through to usage
+
+ default:
+ case CC_REQUEST_USAGE:
+ sprint(self, "\nUsage:^3 cmd voice\n");
+ sprint(self, " FIXME ARGUMENTS UNKNOWN.\n");
+ return;
+ }
+}
+
+/*
+void ClientCommand_(float request)
+{
+ switch(request)
+ {
+ case CC_REQUEST_HELP:
+ sprint(self, " ^2blah^7: foobar\n");
+ return;
+
+ case CC_REQUEST_COMMAND:
+
+ return; // never fall through to usage
+
+ default:
+ case CC_REQUEST_USAGE:
+ sprint(self, "\nUsage:^3 cmd \n");
+ sprint(self, " No arguments required.\n");
+ return;
+ }
+}
+*/
+
+
+// ======================================
+// Main Function Called By Engine (cmd)
+// ======================================
+// If this function exists, server game code parses clientcommand before the engine code gets it.
+
+void SV_ParseClientCommand(string command)
+{
+ float search_request_type;
+ float argc = tokenize_console(command);
+
+ // for floodcheck
+ switch(strtolower(argv(0)))
+ {
+ // exempt commands which are not subject to floodcheck
+ case "begin": break; // handled by engine in host_cmd.c
+ case "pause": break; // handled by engine in host_cmd.c
+ case "prespawn": break; // handled by engine in host_cmd.c
+ case "reportcvar": break; // handled by server in this file
+ case "sentcvar": break; // handled by server in this file
+ case "spawn": break; // handled by engine in host_cmd.c
+
+ default:
+ if(SV_ParseClientCommand_floodcheck())
+ break; // "TRUE": continue, as we're not flooding yet
+ else
+ return; // "FALSE": not allowed to continue, halt
+ }
+
+ /* NOTE: totally disabled for now, however the functionality and descriptions are there if we ever want it.
+ if(argv(0) == "help")
+ {
+ if(argc == 1)
+ {
+ sprint(self, "\nUsage:^3 cmd COMMAND...^7, where possible commands are:\n");
+ ClientCommand_autoswitch(CC_REQUEST_HELP, 0);
+ ClientCommand_checkfail(CC_REQUEST_HELP, "");
+ ClientCommand_clientversion(CC_REQUEST_HELP, 0);
+ ClientCommand_cvar_changes(CC_REQUEST_HELP);
+ ClientCommand_cvar_purechanges(CC_REQUEST_HELP);
+ ClientCommand_info(CC_REQUEST_HELP, 0);
+ ClientCommand_join(CC_REQUEST_HELP);
+ ClientCommand_ladder(CC_REQUEST_HELP);
+ ClientCommand_lsmaps(CC_REQUEST_HELP);
+ ClientCommand_lsnewmaps(CC_REQUEST_HELP);
+ ClientCommand_maplist(CC_REQUEST_HELP);
+ ClientCommand_rankings(CC_REQUEST_HELP);
+ ClientCommand_ready(CC_REQUEST_HELP);
+ ClientCommand_records(CC_REQUEST_HELP);
+ ClientCommand_reportcvar(CC_REQUEST_HELP, 0, "");
+ ClientCommand_say(CC_REQUEST_HELP, 0, "");
+ ClientCommand_say_team(CC_REQUEST_HELP, 0, "");
+ ClientCommand_selectteam(CC_REQUEST_HELP, 0);
+ ClientCommand_sentcvar(CC_REQUEST_HELP, 0, "");
+ ClientCommand_spectate(CC_REQUEST_HELP);
+ ClientCommand_suggestmap(CC_REQUEST_HELP, 0);
+ ClientCommand_teamstatus(CC_REQUEST_HELP);
+ ClientCommand_tell(CC_REQUEST_HELP, 0, "");
+ ClientCommand_timein(CC_REQUEST_HELP);
+ ClientCommand_timeout(CC_REQUEST_HELP);
+ ClientCommand_voice(CC_REQUEST_HELP, 0, "");
+ sprint(self, "For help about specific commands, type cmd help COMMAND\n");
+ return;
+ }
+ else
+ search_request_type = CC_REQUEST_USAGE; // Instead of trying to call a command, we're going to see detailed information about it
+ }
+ else*/ if(GameCommand_Vote(command, self))
+ {
+ return; // handled by server/vote.qc
+ }
+ else if(GameCommand_MapVote(argv(0)))
+ {
+ return; // handled by server/g_world.qc
+ }
+ else if(CheatCommand(argc))
+ {
+ return; // handled by server/cheats.qc
+ }
+ else
+ search_request_type = CC_REQUEST_COMMAND; // continue as usual and scan for normal commands
+
+ switch(strtolower((search_request_type == CC_REQUEST_USAGE) ? argv(1) : argv(0)))
+ {
+ // Do not hard code aliases for these, instead create them in defaultXonotic.cfg
+ // also: keep in alphabetical order, please ;)
+
+ case "autoswitch": ClientCommand_autoswitch(search_request_type, argc); break;
+ case "checkfail": ClientCommand_checkfail(search_request_type, command); break;
+ case "clientversion": ClientCommand_clientversion(search_request_type, argc); break;
+ case "cvar_changes": ClientCommand_cvar_changes(search_request_type); break;
+ case "cvar_purechanges": ClientCommand_cvar_purechanges(search_request_type); break;
+ case "info": ClientCommand_info(search_request_type, argc); break;
+ case "join": ClientCommand_join(search_request_type); break;
+ case "ladder": ClientCommand_ladder(search_request_type); break;
+ case "lsmaps": ClientCommand_lsmaps(search_request_type); break;
+ case "lsnewmaps": ClientCommand_lsnewmaps(search_request_type); break;
+ case "maplist": ClientCommand_maplist(search_request_type); break;
+ case "rankings": ClientCommand_rankings(search_request_type); break;
+ case "ready": ClientCommand_ready(search_request_type); break;
+ case "records": ClientCommand_records(search_request_type); break;
+ case "reportcvar": ClientCommand_reportcvar(search_request_type, argc, command); break;
+ case "say": ClientCommand_say(search_request_type, argc, command); break;
+ case "say_team": ClientCommand_say_team(search_request_type, argc, command); break;
+ case "selectteam": ClientCommand_selectteam(search_request_type, argc); break;
+ case "sentcvar": ClientCommand_sentcvar(search_request_type, argc, command); break;
+ case "spectate": ClientCommand_spectate(search_request_type); break;
+ case "suggestmap": ClientCommand_suggestmap(search_request_type, argc); break;
+ case "teamstatus": ClientCommand_teamstatus(search_request_type); break;
+ case "tell": ClientCommand_tell(search_request_type, argc, command); break;
+ case "timein": ClientCommand_timein(search_request_type); break;
+ case "timeout": ClientCommand_timeout(search_request_type); break;
+ case "voice": ClientCommand_voice(search_request_type, argc, command); break;
+
+ default:
+ clientcommand(self, command); //print("Invalid command. For a list of supported commands, try cmd help.\n");
+ }
+}
\ No newline at end of file