]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/command/common.qc
Merge remote branch 'origin/master' into samual/updatecommands
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / command / common.qc
1 // ====================================================
2 //  Shared code for server commands, written by Samual
3 //  Last updated: December 13th, 2011
4 // ====================================================
5
6 string GetCommandPrefix(entity caller)
7 {
8         if(caller)
9                 return "cmd";
10         else
11                 return "sv_cmd";
12 }
13
14 string GetCallerName(entity caller)
15 {
16         if(caller)
17                 return caller.netname;
18         else
19                 return ((autocvar_sv_adminnick != "") ? autocvar_sv_adminnick : autocvar_hostname);
20 }
21
22 // find a player which matches the input string, and return their entity number
23 float GetFilteredNumber(string input)
24 {
25         entity tmp_player, selection;
26         float output, matches;
27         
28         // check and see if we can get a number from input like "#3" or "3" 
29         if(substring(input, 0, 1) == "#")
30                 output = stof(substring(input, 1, -1));
31         else
32                 output = stof(input);
33                 
34         // if we can't, check and see if we can match the input to the netname of any player in the game
35         if not(output) 
36         {
37                 FOR_EACH_CLIENT(tmp_player)
38                         if (strdecolorize(tmp_player.netname) == strdecolorize(input))
39                                 selection = tmp_player;
40
41                 if (selection) { output = num_for_edict(selection); }
42         }
43                 
44         print(strcat("input: ", input, ", output: ", ftos(output), ",\n"));
45         return output;
46 }
47
48 // switch between sprint and print depending on whether the reciever is the server or a player
49 void print_to(entity to, string input)
50 {
51     if(to)
52         sprint(to, strcat(input, "\n"));
53     else
54         print(input, "\n");
55 }
56
57
58 // ===================================================
59 //  Common commands used in both sv_cmd.qc and cmd.qc
60 // ===================================================
61
62 void CommonCommand_cvar_changes(float request)
63 {
64         switch(request)
65         {
66                 case CMD_REQUEST_COMMAND:
67                 {
68                         print_to(self, cvar_changes);
69                         return; // never fall through to usage
70                 }
71                         
72                 default:
73                 case CMD_REQUEST_USAGE:
74                 {
75                         print_to(self, "\nUsage:^3 sv_cmd cvar_changes");
76                         print_to(self, "  No arguments required.");
77                         print_to(self, "See also: ^2cvar_purechanges^7");
78                         return;
79                 }
80         }
81 }
82
83 void CommonCommand_cvar_purechanges(float request)
84 {
85         switch(request)
86         {
87                 case CMD_REQUEST_COMMAND:
88                 {
89                         print_to(self, cvar_purechanges);
90                         return; // never fall through to usage
91                 }
92                         
93                 default:
94                 case CMD_REQUEST_USAGE:
95                 {
96                         print_to(self, "\nUsage:^3 sv_cmd cvar_purechanges");
97                         print_to(self, "  No arguments required.");
98                         print_to(self, "See also: ^2cvar_changes^7");
99                         return;
100                 }
101         }
102 }
103
104 void CommonCommand_info(float request, float argc) // todo: figure out how this works?
105 {       
106         switch(request)
107         {
108                 case CMD_REQUEST_COMMAND:
109                 {
110                         string command;
111                         
112                         command = builtin_cvar_string(strcat("sv_info_", argv(1))); 
113                         if(command)
114                                 wordwrap_sprint(command, 1111); // why 1111?
115                         else
116                                 print_to(self, "ERROR: unsupported info command");
117                                 
118                         return; // never fall through to usage
119                 }
120                         
121                 default:
122                 case CMD_REQUEST_USAGE:
123                 {
124                         print_to(self, "\nUsage:^3 cmd info request");
125                         print_to(self, "  Where 'request' is the suffixed string appended onto the request for cvar.");
126                         return;
127                 }
128         }
129 }
130
131 void CommonCommand_ladder(float request)
132 {
133         switch(request)
134         {
135                 case CMD_REQUEST_COMMAND:
136                 {
137                         print_to(self, ladder_reply);
138                         return; // never fall through to usage
139                 }
140                         
141                 default:
142                 case CMD_REQUEST_USAGE:
143                 {
144                         print_to(self, "\nUsage:^3 cmd ladder");
145                         print_to(self, "  No arguments required.");
146                         return;
147                 }
148         }
149 }
150
151 void CommonCommand_lsmaps(float request)
152 {
153         switch(request)
154         {
155                 case CMD_REQUEST_COMMAND:
156                 {
157                         print_to(self, lsmaps_reply);
158                         return; // never fall through to usage
159                 }
160                         
161                 default:
162                 case CMD_REQUEST_USAGE:
163                 {
164                         print_to(self, "\nUsage:^3 cmd lsmaps");
165                         print_to(self, "  No arguments required.");
166                         return;
167                 }
168         }
169 }
170
171 void CommonCommand_lsnewmaps(float request)
172 {
173         switch(request)
174         {
175                 case CMD_REQUEST_COMMAND:
176                 {
177                         print_to(self, lsnewmaps_reply);
178                         return; // never fall through to usage
179                 }
180                         
181                 default:
182                 case CMD_REQUEST_USAGE:
183                 {
184                         print_to(self, "\nUsage:^3 cmd lsnewmaps");
185                         print_to(self, "  No arguments required.");
186                         return;
187                 }
188         }
189 }
190
191 void CommonCommand_maplist(float request)
192 {
193         switch(request)
194         {
195                 case CMD_REQUEST_COMMAND:
196                 {
197                         print_to(self, maplist_reply);
198                         return; // never fall through to usage
199                 }
200                         
201                 default:
202                 case CMD_REQUEST_USAGE:
203                 {
204                         print_to(self, "\nUsage:^3 cmd maplist");
205                         print_to(self, "  No arguments required.");
206                         return;
207                 }
208         }
209 }
210
211 void GameCommand_rankings(float request) // this is OLD.... jeez.
212 {
213         switch(request)
214         {
215                 case CMD_REQUEST_COMMAND:
216                 {
217                         strunzone(rankings_reply);
218                         rankings_reply = strzone(getrankings());
219                         print(rankings_reply);
220                         return;
221                 }
222                         
223                 default:
224                 case CMD_REQUEST_USAGE:
225                 {
226                         print("\nUsage:^3 sv_cmd rankings");
227                         print("  No arguments required.");
228                         return;
229                 }
230         }
231 }
232
233 void CommonCommand_rankings(float request)
234 {
235         switch(request)
236         {
237                 case CMD_REQUEST_COMMAND:
238                 {
239                         print_to(self, rankings_reply);
240                         return; // never fall through to usage
241                 }
242                         
243                 default:
244                 case CMD_REQUEST_USAGE:
245                 {
246                         print_to(self, "\nUsage:^3 cmd rankings");
247                         print_to(self, "  No arguments required.");
248                         return;
249                 }
250         }
251 }
252
253 void CommonCommand_records(float request) // TODO: Isn't this flooding with the sprint messages? Old code, but perhaps bad?
254 {       
255         switch(request)
256         {
257                 case CMD_REQUEST_COMMAND:
258                 {
259                         float i;
260                         
261                         for(i = 0; i < 10; ++i)
262                                 print_to(self, records_reply[i]);
263                                 
264                         return; // never fall through to usage
265                 }
266                         
267                 default:
268                 case CMD_REQUEST_USAGE:
269                 {
270                         print_to(self, "\nUsage:^3 cmd records");
271                         print_to(self, "  No arguments required.");
272                         return;
273                 }
274         }
275 }
276
277 void CommonCommand_teamstatus(float request)
278 {
279         switch(request)
280         {
281                 case CMD_REQUEST_COMMAND:
282                 {
283                         Score_NicePrint(self);
284                         return; // never fall through to usage
285                 }
286                         
287                 default:
288                 case CMD_REQUEST_USAGE:
289                 {
290                         print_to(self, "\nUsage:^3 cmd teamstatus");
291                         print_to(self, "  No arguments required.");
292                         return;
293                 }
294         }
295 }
296
297
298 void CommonCommand_timein(float request)
299 {
300         switch(request)
301         {
302                 case CMD_REQUEST_COMMAND:
303                 {
304                         if(self.flags & FL_CLIENT)
305                         {
306                                 if(autocvar_sv_timeout)
307                                 {
308                                         if (!timeoutStatus)
309                                                 return print_to(self, "^7Error: There is no active timeout which could be aborted!");
310                                         if (self != timeoutInitiator)
311                                                 return print_to(self, "^7Error: You may not abort the active timeout. Only the player who called it can do that!");
312                                                 
313                                         if (timeoutStatus == 1) 
314                                         {
315                                                 remainingTimeoutTime = timeoutStatus = 0;
316                                                 timeoutHandler.nextthink = time; //timeoutHandler has to take care of it immediately
317                                                 bprint(strcat("^7The timeout was aborted by ", self.netname, " !\n"));
318                                         }
319                                         else if (timeoutStatus == 2) 
320                                         {
321                                                 //only shorten the remainingTimeoutTime if it makes sense
322                                                 if( remainingTimeoutTime > (autocvar_sv_timeout_resumetime + 1) ) 
323                                                 {
324                                                         bprint(strcat("^1Attention: ^7", self.netname, " resumed the game! Prepare for battle!\n"));
325                                                         remainingTimeoutTime = autocvar_sv_timeout_resumetime;
326                                                         timeoutHandler.nextthink = time; //timeoutHandler has to take care of it immediately
327                                                 }
328                                                 else
329                                                         print_to(self, "^7Error: Your resumegame call was discarded!");
330                                         }
331                                 }
332                         }
333                         return; // never fall through to usage
334                 }
335                         
336                 default:
337                 case CMD_REQUEST_USAGE:
338                 {
339                         print_to(self, "\nUsage:^3 cmd timein");
340                         print_to(self, "  No arguments required.");
341                         return;
342                 }
343         }
344 }
345
346 void CommonCommand_timeout(float request) // DEAR GOD THIS COMMAND IS TERRIBLE.
347 {
348         switch(request)
349         {
350                 case CMD_REQUEST_COMMAND:
351                 {
352                         if(self.flags & FL_CLIENT)
353                         {
354                                 if(autocvar_sv_timeout) 
355                                 {
356                                         if(self.classname == "player") 
357                                         {
358                                                 if(vote_called)
359                                                         print_to(self, "^7Error: you can not call a timeout while a vote is active!");
360                                                 else
361                                                 {
362                                                         if (inWarmupStage && !g_warmup_allow_timeout)
363                                                                 return print_to(self, "^7Error: You can not call a timeout in warmup-stage!");
364                                                         if (time < game_starttime )
365                                                                 return print_to(self, "^7Error: You can not call a timeout while the map is being restarted!");
366                                                                 
367                                                         if (timeoutStatus != 2) {
368                                                                 //if the map uses a timelimit make sure that timeout cannot be called right before the map ends
369                                                                 if (autocvar_timelimit) {
370                                                                         //a timelimit was used
371                                                                         float myTl;
372                                                                         myTl = autocvar_timelimit;
373
374                                                                         float lastPossibleTimeout;
375                                                                         lastPossibleTimeout = (myTl*60) - autocvar_sv_timeout_leadtime - 1;
376
377                                                                         if (lastPossibleTimeout < time - game_starttime)
378                                                                                 return print_to(self, "^7Error: It is too late to call a timeout now!");
379                                                                 }
380                                                         }
381                                                         
382                                                         //player may not call a timeout if he has no calls left
383                                                         if (self.allowedTimeouts < 1)
384                                                                 return print_to(self, "^7Error: You already used all your timeout calls for this map!");
385                                                                 
386                                                                 
387                                                         //now all required checks are passed
388                                                         self.allowedTimeouts -= 1;
389                                                         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)
390                                                         remainingTimeoutTime = autocvar_sv_timeout_length;
391                                                         remainingLeadTime = autocvar_sv_timeout_leadtime;
392                                                         timeoutInitiator = self;
393                                                         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
394                                                                 timeoutStatus = 1;
395                                                                 //create the timeout indicator which centerprints the information to all players and takes care of pausing/unpausing
396                                                                 timeoutHandler = spawn();
397                                                                 timeoutHandler.think = timeoutHandler_Think;
398                                                         }
399                                                         timeoutHandler.nextthink = time; //always let the entity think asap
400
401                                                         //inform all connected clients about the timeout call
402                                                         Announce("timeoutcalled");
403                                                 }
404                                         }
405                                         else
406                                                 print_to(self, "^7Error: only players can call a timeout!");
407                                 }
408                         }
409                         return; // never fall through to usage
410                 }
411                         
412                 default:
413                 case CMD_REQUEST_USAGE:
414                 {
415                         print_to(self, "\nUsage:^3 cmd timeout");
416                         print_to(self, "  No arguments required.");
417                         return;
418                 }
419         }
420 }
421
422 void CommonCommand_who(float request)
423 {
424         switch(request)
425         {
426                 case CMD_REQUEST_COMMAND:
427                 {
428                         float total_listed_players, tmp_hours, tmp_minutes, tmp_seconds;
429                         entity tmp_player;
430                         //string tmp_player_name;
431                         
432                         print_to(self, strcat("List of client information", (autocvar_sv_status_privacy ? " (some data is hidden for privacy)" : string_null), ":\n"));
433                         print_to(self, sprintf(" %-4s %-20s %-5s %-3s %-9s %-16s %s\n", "ent", "nickname", "ping", "pl", "time", "ip", "crypto_id"));
434                         
435                         FOR_EACH_CLIENT(tmp_player)
436                         {
437                                 //tmp_player_name = strlimitedlen(tmp_player.netname, "...", TRUE, 20);
438                                 
439                                 tmp_hours = tmp_minutes = tmp_seconds = 0;
440                                 
441                                 tmp_seconds = (time - tmp_player.jointime);
442                                 tmp_minutes = (tmp_seconds / 60);
443                                 
444                                 if(tmp_minutes)
445                                 {
446                                         tmp_seconds -= (tmp_minutes * 60);
447                                         tmp_hours = (tmp_minutes / 60);
448                                         
449                                         if(tmp_hours) { tmp_minutes -= (tmp_hours * 60); }
450                                 }
451                                 
452                                 print_to(self, sprintf(" %-4s %-20s %-5d %-3d %-9s %-16s %s\n", 
453                                         strcat("#", ftos(num_for_edict(tmp_player))), 
454                                         tmp_player.netname, //strcat(tmp_player_name, sprintf("%*s", (20 - strlen(strdecolorize(tmp_player_name))), "")),
455                                         tmp_player.ping, tmp_player.ping_packetloss, 
456                                         sprintf("%02d:%02d:%02d", tmp_hours, tmp_minutes, tmp_seconds),
457                                         (autocvar_sv_status_privacy ? "hidden" : tmp_player.netaddress),
458                                         (autocvar_sv_status_privacy ? "hidden" : tmp_player.crypto_idfp)));
459                                         
460                                 ++total_listed_players;
461                         }
462                         
463                         print_to(self, strcat("Finished listing ", ftos(total_listed_players), " client(s). \n"));
464                         
465                         return; // never fall through to usage
466                 }
467                         
468                 default:
469                 case CMD_REQUEST_USAGE:
470                 {
471                         print_to(self, "\nUsage:^3 cmd who");
472                         print_to(self, "  No arguments required.");
473                         return;
474                 }
475         }
476 }
477
478 /* use this when creating a new command, making sure to place it in alphabetical order.
479 void CommonCommand_(float request)
480 {
481         switch(request)
482         {
483                 case CMD_REQUEST_COMMAND:
484                 {
485                         
486                         return; // never fall through to usage
487                 }
488                         
489                 default:
490                 case CMD_REQUEST_USAGE:
491                 {
492                         print_to(self, "\nUsage:^3 cmd ");
493                         print_to(self, "  No arguments required.");
494                         return;
495                 }
496         }
497 }
498 */