]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/command/common.qc
Make the "time" command available to both cmd and sv_cmd as a common command
[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 void CommonCommand_time(float request)
298 {
299         switch(request)
300         {
301                 case CMD_REQUEST_COMMAND:
302                 {
303                         print("time = ", ftos(time), "\n");
304                         print("frame start = ", ftos(gettime(GETTIME_FRAMESTART)), "\n");
305                         print("realtime = ", ftos(gettime(GETTIME_REALTIME)), "\n");
306                         print("hires = ", ftos(gettime(GETTIME_HIRES)), "\n");
307                         print("uptime = ", ftos(gettime(GETTIME_UPTIME)), "\n");
308                         print("localtime = ", strftime(TRUE, "%a %b %e %H:%M:%S %Z %Y"), "\n"); // todo: Why is strftime broken? is engine problem, I think.
309                         print("gmtime = ", strftime(FALSE, "%a %b %e %H:%M:%S %Z %Y"), "\n");
310                         return;
311                 }
312                         
313                 default:
314                 case CMD_REQUEST_USAGE:
315                 {
316                         print_to(self, "\nUsage:^3 cmd time");
317                         print_to(self, "  No arguments required.");
318                         return;
319                 }
320         }
321 }
322
323 void CommonCommand_timein(float request)
324 {
325         switch(request)
326         {
327                 case CMD_REQUEST_COMMAND:
328                 {
329                         if(self.flags & FL_CLIENT)
330                         {
331                                 if(autocvar_sv_timeout)
332                                 {
333                                         if (!timeoutStatus)
334                                                 return print_to(self, "^7Error: There is no active timeout which could be aborted!");
335                                         if (self != timeoutInitiator)
336                                                 return print_to(self, "^7Error: You may not abort the active timeout. Only the player who called it can do that!");
337                                                 
338                                         if (timeoutStatus == 1) 
339                                         {
340                                                 remainingTimeoutTime = timeoutStatus = 0;
341                                                 timeoutHandler.nextthink = time; //timeoutHandler has to take care of it immediately
342                                                 bprint(strcat("^7The timeout was aborted by ", self.netname, " !\n"));
343                                         }
344                                         else if (timeoutStatus == 2) 
345                                         {
346                                                 //only shorten the remainingTimeoutTime if it makes sense
347                                                 if( remainingTimeoutTime > (autocvar_sv_timeout_resumetime + 1) ) 
348                                                 {
349                                                         bprint(strcat("^1Attention: ^7", self.netname, " resumed the game! Prepare for battle!\n"));
350                                                         remainingTimeoutTime = autocvar_sv_timeout_resumetime;
351                                                         timeoutHandler.nextthink = time; //timeoutHandler has to take care of it immediately
352                                                 }
353                                                 else
354                                                         print_to(self, "^7Error: Your resumegame call was discarded!");
355                                         }
356                                 }
357                         }
358                         return; // never fall through to usage
359                 }
360                         
361                 default:
362                 case CMD_REQUEST_USAGE:
363                 {
364                         print_to(self, "\nUsage:^3 cmd timein");
365                         print_to(self, "  No arguments required.");
366                         return;
367                 }
368         }
369 }
370
371 void CommonCommand_timeout(float request) // DEAR GOD THIS COMMAND IS TERRIBLE.
372 {
373         switch(request)
374         {
375                 case CMD_REQUEST_COMMAND:
376                 {
377                         if(self.flags & FL_CLIENT)
378                         {
379                                 if(autocvar_sv_timeout) 
380                                 {
381                                         if(self.classname == "player") 
382                                         {
383                                                 if(vote_called)
384                                                         print_to(self, "^7Error: you can not call a timeout while a vote is active!");
385                                                 else
386                                                 {
387                                                         if (inWarmupStage && !g_warmup_allow_timeout)
388                                                                 return print_to(self, "^7Error: You can not call a timeout in warmup-stage!");
389                                                         if (time < game_starttime )
390                                                                 return print_to(self, "^7Error: You can not call a timeout while the map is being restarted!");
391                                                                 
392                                                         if (timeoutStatus != 2) {
393                                                                 //if the map uses a timelimit make sure that timeout cannot be called right before the map ends
394                                                                 if (autocvar_timelimit) {
395                                                                         //a timelimit was used
396                                                                         float myTl;
397                                                                         myTl = autocvar_timelimit;
398
399                                                                         float lastPossibleTimeout;
400                                                                         lastPossibleTimeout = (myTl*60) - autocvar_sv_timeout_leadtime - 1;
401
402                                                                         if (lastPossibleTimeout < time - game_starttime)
403                                                                                 return print_to(self, "^7Error: It is too late to call a timeout now!");
404                                                                 }
405                                                         }
406                                                         
407                                                         //player may not call a timeout if he has no calls left
408                                                         if (self.allowedTimeouts < 1)
409                                                                 return print_to(self, "^7Error: You already used all your timeout calls for this map!");
410                                                                 
411                                                                 
412                                                         //now all required checks are passed
413                                                         self.allowedTimeouts -= 1;
414                                                         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)
415                                                         remainingTimeoutTime = autocvar_sv_timeout_length;
416                                                         remainingLeadTime = autocvar_sv_timeout_leadtime;
417                                                         timeoutInitiator = self;
418                                                         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
419                                                                 timeoutStatus = 1;
420                                                                 //create the timeout indicator which centerprints the information to all players and takes care of pausing/unpausing
421                                                                 timeoutHandler = spawn();
422                                                                 timeoutHandler.think = timeoutHandler_Think;
423                                                         }
424                                                         timeoutHandler.nextthink = time; //always let the entity think asap
425
426                                                         //inform all connected clients about the timeout call
427                                                         Announce("timeoutcalled");
428                                                 }
429                                         }
430                                         else
431                                                 print_to(self, "^7Error: only players can call a timeout!");
432                                 }
433                         }
434                         return; // never fall through to usage
435                 }
436                         
437                 default:
438                 case CMD_REQUEST_USAGE:
439                 {
440                         print_to(self, "\nUsage:^3 cmd timeout");
441                         print_to(self, "  No arguments required.");
442                         return;
443                 }
444         }
445 }
446
447 void CommonCommand_who(float request)
448 {
449         switch(request)
450         {
451                 case CMD_REQUEST_COMMAND:
452                 {
453                         float total_listed_players, tmp_hours, tmp_minutes, tmp_seconds;
454                         entity tmp_player;
455                         //string tmp_player_name;
456                         
457                         print_to(self, strcat("List of client information", (autocvar_sv_status_privacy ? " (some data is hidden for privacy)" : string_null), ":\n"));
458                         print_to(self, sprintf(" %-4s %-20s %-5s %-3s %-9s %-16s %s\n", "ent", "nickname", "ping", "pl", "time", "ip", "crypto_id"));
459                         
460                         FOR_EACH_CLIENT(tmp_player)
461                         {
462                                 //tmp_player_name = strlimitedlen(tmp_player.netname, "...", TRUE, 20);
463                                 
464                                 tmp_hours = tmp_minutes = tmp_seconds = 0;
465                                 
466                                 tmp_seconds = (time - tmp_player.jointime);
467                                 tmp_minutes = (tmp_seconds / 60);
468                                 
469                                 if(tmp_minutes)
470                                 {
471                                         tmp_seconds -= (tmp_minutes * 60);
472                                         tmp_hours = (tmp_minutes / 60);
473                                         
474                                         if(tmp_hours) { tmp_minutes -= (tmp_hours * 60); }
475                                 }
476                                 
477                                 print_to(self, sprintf(" %-4s %-20s %-5d %-3d %-9s %-16s %s\n", 
478                                         strcat("#", ftos(num_for_edict(tmp_player))), 
479                                         tmp_player.netname, //strcat(tmp_player_name, sprintf("%*s", (20 - strlen(strdecolorize(tmp_player_name))), "")),
480                                         tmp_player.ping, tmp_player.ping_packetloss, 
481                                         sprintf("%02d:%02d:%02d", tmp_hours, tmp_minutes, tmp_seconds),
482                                         (autocvar_sv_status_privacy ? "hidden" : tmp_player.netaddress),
483                                         (autocvar_sv_status_privacy ? "hidden" : tmp_player.crypto_idfp)));
484                                         
485                                 ++total_listed_players;
486                         }
487                         
488                         print_to(self, strcat("Finished listing ", ftos(total_listed_players), " client(s). \n"));
489                         
490                         return; // never fall through to usage
491                 }
492                         
493                 default:
494                 case CMD_REQUEST_USAGE:
495                 {
496                         print_to(self, "\nUsage:^3 cmd who");
497                         print_to(self, "  No arguments required.");
498                         return;
499                 }
500         }
501 }
502
503 /* use this when creating a new command, making sure to place it in alphabetical order.
504 void CommonCommand_(float request)
505 {
506         switch(request)
507         {
508                 case CMD_REQUEST_COMMAND:
509                 {
510                         
511                         return; // never fall through to usage
512                 }
513                         
514                 default:
515                 case CMD_REQUEST_USAGE:
516                 {
517                         print_to(self, "\nUsage:^3 cmd ");
518                         print_to(self, "  No arguments required.");
519                         return;
520                 }
521         }
522 }
523 */