]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/command/generic.qc
Fix some things in generic.qc
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / command / generic.qc
1 // =========================================================
2 //  Generic program common command code, written by Samual
3 //  Last updated: December 28th, 2011
4 // =========================================================
5
6 // used by generic commands for better help/usage information
7 string GetProgramCommandPrefix(void)
8 {
9         #ifdef SVQC
10         return "sv_cmd";
11         #endif
12         #ifdef CSQC
13         return "cl_cmd";
14         #endif
15         #ifdef MENUQC
16         return "menu_cmd";
17         #endif
18 }
19
20 void GenericCommand_addtolist(float request, float argc)
21 {
22         switch(request)
23         {
24                 case CMD_REQUEST_COMMAND:
25                 {
26                         float i;
27                         
28                         if(argc >= 2)
29                         {
30                                 if(cvar_string(argv(1)) == "") // cvar was empty
31                                 {
32                                         cvar_set(argv(1), argv(2));
33                                 }
34                                 else // add it to the end of the list if the list doesn't already have it
35                                 {
36                                         argc = tokenizebyseparator(cvar_string(argv(1)), " ");
37                                         for(i = 0; i < argc; ++i)
38                                                 if(argv(i) == argv(2))
39                                                         return; // already in list
40                                                         
41                                         cvar_set(argv(1), strcat(argv(2), " ", cvar_string(argv(1))));
42                                 }
43                                 return;
44                         }
45                 }
46                         
47                 default:
48                         // todo
49                 case CMD_REQUEST_USAGE:
50                 {
51                         print(strcat("\nUsage:^3 ", GetProgramCommandPrefix(), " addtolist variable [value]"));
52                         print("  Where 'variable' is what to add to the list,\n");
53                         print("  and 'value' is any extra optional paramaters to add with quotes.");
54                         return;
55                 }
56         }
57 }
58
59 void GenericCommand_dumpcommands(float request)
60 {
61         switch(request)
62         {
63                 case CMD_REQUEST_COMMAND:
64                 {
65                         float fh;
66                         string filename = strcat(GetProgramCommandPrefix(), "_dump.txt");
67                         fh = fopen(filename, FILE_WRITE);
68                         
69                         if(fh >= 0)
70                         {
71                                 #ifdef SVQC
72                                         
73                                         CMD_Write("dump of server console commands:\n");
74                                         GameCommand_macro_write_aliases(fh);
75                                         
76                                         CMD_Write("\ndump of networked client only commands:\n");
77                                         ClientCommand_macro_write_aliases(fh);
78                                         
79                                         CMD_Write("\ndump of common commands:\n");
80                                         CommonCommand_macro_write_aliases(fh);
81
82                                         CMD_Write("\ndump of ban commands:\n");
83                                         // todo
84                                         
85                                 #endif
86                                                                 
87                                 #ifdef CSQC
88                                         
89                                         CMD_Write("dump of client commands:\n");
90                                         LocalCommand_macro_write_aliases(fh);
91                                         
92                                 #endif
93                                 
94                                 CMD_Write("\ndump of generic commands:\n");
95                                 GenericCommand_macro_write_aliases(fh);
96                                 
97                                 print("Completed dump of aliases in ^2", GetProgramCommandPrefix(), "_dump.txt^7.\n");
98                                 
99                                 fclose(fh);
100                         }
101                         else
102                         {
103                                 print("^1Error: ^7Could not dump to file!\n");
104                         }
105                         return;
106                 }
107                         
108                 default:
109                 case CMD_REQUEST_USAGE:
110                 {
111                         print(strcat("\nUsage:^3 ", GetProgramCommandPrefix(), " dumpcommands"));
112                         print("  No arguments required.\n");
113                         return;
114                 }
115         }
116 }
117
118 void GenericCommand_maplist(float request, float argc)
119 {
120         switch(request)
121         {
122                 case CMD_REQUEST_COMMAND:
123                 {
124                         string tmp_string;
125                         float i;
126                         
127                         switch(argv(1))
128                         {
129                                 case "add": // appends new maps to the maplist
130                                 {
131                                         if(argc == 3)
132                                         {
133                                                 if (!fexists(strcat("maps/", argv(2), ".bsp")))
134                                                 {
135                                                         print("maplist: ERROR: ", argv(2), " does not exist!\n");
136                                                         break;
137                                                 }
138                                                 
139                                                 if(cvar_string("g_maplist") == "")
140                                                         cvar_set("g_maplist", argv(2));
141                                                 else
142                                                         cvar_set("g_maplist", strcat(argv(2), " ", cvar_string("g_maplist")));
143                                                         
144                                                 return;
145                                         }
146                                         break; // go to usage
147                                 }
148                                 
149                                 case "remove": // scans maplist and only adds back whatever maps were not provided in argv(2)
150                                 {
151                                         if(argc == 3)
152                                         {
153                                                 argc = tokenizebyseparator(cvar_string("g_maplist"), " ");
154                                                 
155                                                 for(i = 0; i < argc; ++i)
156                                                         if(argv(i) != argv(2))
157                                                                 tmp_string = strcat(tmp_string, " ", argv(i));
158                                                                 
159                                                 tmp_string = substring(tmp_string, 1, strlen(tmp_string) - 1);
160                                                 cvar_set("g_maplist", tmp_string);
161                                                 
162                                                 return;
163                                         }
164                                         break; // go to usage
165                                 }
166                                 
167                                 case "shuffle": // randomly shuffle the maplist
168                                 {
169                                         cvar_set("g_maplist", shufflewords(cvar_string("g_maplist")));
170                                         return;
171                                 }
172                                 
173                                 case "cleanup": // scans maplist and only adds back the ones which are really usable
174                                 {
175                                         MapInfo_Enumerate();
176                                         MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0);
177                                         argc = tokenizebyseparator(cvar_string("g_maplist"), " ");
178                                         
179                                         for(i = 0; i < argc; ++i)
180                                                 if(MapInfo_CheckMap(argv(i)))
181                                                         tmp_string = strcat(tmp_string, " ", argv(i));
182                                                         
183                                         tmp_string = substring(tmp_string, 1, strlen(tmp_string) - 1);
184                                         cvar_set("g_maplist", tmp_string);
185                                         
186                                         return;
187                                 }
188                                         
189                                 default: break;
190                         }
191                 }
192                         
193                 default:
194                         print("Incorrect parameters for ^2maplist^7\n");
195                 case CMD_REQUEST_USAGE:
196                 {
197                         print(strcat("\nUsage:^3 ", GetProgramCommandPrefix(), " maplist command [map]")); // todo
198                         print("  No arguments required.\n");
199                         return;
200                 }
201         }
202 }
203
204 void GenericCommand_settemp(float request, float argc)
205 {
206         switch(request)
207         {
208                 case CMD_REQUEST_COMMAND:
209                 {
210                         if(argc >= 3)
211                         {
212                                 if(cvar_settemp(argv(1), argv(2)))
213                                         dprint("Creating new settemp tracker for ", argv(1), " and setting it to \"", argv(2), "\" temporarily.\n"); 
214                                 else
215                                         dprint("Already had a tracker for ", argv(1), ", updating it to \"", argv(2), "\".\n");
216                         
217                                 return;
218                         }
219                 }
220                         
221                 default:
222                         print("Incorrect parameters for ^2settemp^7\n");
223                 case CMD_REQUEST_USAGE:
224                 {
225                         print(strcat("\nUsage:^3 ", GetProgramCommandPrefix(), " settemp \"cvar\" \"arguments\"\n"));
226                         print("  Where 'cvar' is the cvar you want to temporarily set with 'arguments'.\n");
227                         return;
228                 }
229         }
230 }
231
232 void GenericCommand_settemp_restore(float request, float argc)
233 {
234         switch(request)
235         {
236                 case CMD_REQUEST_COMMAND:
237                 {
238                         float i = cvar_settemp_restore();
239                         
240                         if(i)
241                                 dprint("Restored ", ftos(i), " temporary cvar settings to their original values.\n");
242                         else
243                                 dprint("Nothing to restore.\n");
244                         
245                         return;
246                 }
247                         
248                 default:
249                 case CMD_REQUEST_USAGE:
250                 {
251                         print(strcat("\nUsage:^3 ", GetProgramCommandPrefix(), " settemp_restore\n"));
252                         print("  No arguments required.\n");
253                         return;
254                 }
255         }
256 }
257
258 /* use this when creating a new command, making sure to place it in alphabetical order... also,
259 ** ADD ALL NEW COMMANDS TO commands.cfg WITH PROPER ALIASES IN THE SAME FASHION!
260 void GenericCommand_(float request)
261 {
262         switch(request)
263         {
264                 case CMD_REQUEST_COMMAND:
265                 {
266                         
267                         return;
268                 }
269                         
270                 default:
271                 case CMD_REQUEST_USAGE:
272                 {
273                         print(strcat("\nUsage:^3 ", GetProgramCommandPrefix(), " "));
274                         print("  No arguments required.\n");
275                         return;
276                 }
277         }
278 }
279 */
280
281 // ==================================
282 //  Macro system for server commands
283 // ==================================
284
285 // Do not hard code aliases for these, instead create them in commands.cfg... also: keep in alphabetical order, please ;)
286 #define GENERIC_COMMANDS(request,arguments,command) \
287         GENERIC_COMMAND("addtolist", GenericCommand_addtolist(request, arguments), "Add a string to a cvar at the end of a list") \
288         GENERIC_COMMAND("dumpcommands", GenericCommand_dumpcommands(request), "Dump all commands on the program to *_cmd_dump.txt") \
289         GENERIC_COMMAND("maplist", GenericCommand_maplist(request, arguments), "Automatic control of maplist") \
290         GENERIC_COMMAND("rpn", GenericCommand_rpn(request, arguments, command), "RPN calculator") \
291         GENERIC_COMMAND("settemp", GenericCommand_settemp(request, arguments), "Temporarily set a value to a cvar which is restored later") \
292         GENERIC_COMMAND("settemp_restore", GenericCommand_settemp_restore(request, arguments), "Restore all cvars set by settemp command") \
293         /* nothing */
294
295 void GenericCommand_macro_help()
296 {
297         #define GENERIC_COMMAND(name,function,description) \
298                 { print("  ^2", name, "^7: ", description, "\n"); }
299                 
300         GENERIC_COMMANDS(0, 0, "")
301         #undef GENERIC_COMMAND
302         
303         return;
304 }
305
306 float GenericCommand_macro_command(float argc, string command)
307 {
308         #define GENERIC_COMMAND(name,function,description) \
309                 { if(name == strtolower(argv(0))) { function; return TRUE; } }
310                 
311         GENERIC_COMMANDS(CMD_REQUEST_COMMAND, argc, command)
312         #undef GENERIC_COMMAND
313         
314         return FALSE;
315 }
316
317 float GenericCommand_macro_usage(float argc)
318 {
319         #define GENERIC_COMMAND(name,function,description) \
320                 { if(name == strtolower(argv(1))) { function; return TRUE; } }
321                 
322         GENERIC_COMMANDS(CMD_REQUEST_USAGE, argc, "")
323         #undef GENERIC_COMMAND
324         
325         return FALSE;
326 }
327
328 void GenericCommand_macro_write_aliases(float fh)
329 {
330         #define GENERIC_COMMAND(name,function,description) \
331                 { CMD_Write_Alias("qc_cmd_svmenu", name, description); }
332         
333         GENERIC_COMMANDS(0, 0, "")
334         #undef GENERIC_COMMAND
335         
336         return;
337 }
338         
339
340 // ===========================================
341 //  Main Common Function For Generic Commands
342 // ===========================================
343 // Commands spread out among all programs (menu, client, and server) 
344
345 float GenericCommand(string command)
346 {
347         float argc = tokenize_console(command);
348         float n, j, f, i;
349         string s, s2, c;
350         vector rgb;
351
352         // Guide for working with argc arguments by example:
353         // argc:   1    - 2      - 3     - 4
354         // argv:   0    - 1      - 2     - 3 
355         // cmd     vote - master - login - password
356         
357         if(GenericCommand_macro_command(argc, command)) // continue as usual and scan for normal commands
358         {
359                 return TRUE; // handled by one of the above GenericCommand_* functions
360         }
361         else if(argc >= 3 && argv(0) == "red")
362         {
363                 s = substring(command, argv_start_index(2), argv_end_index(-1) - argv_start_index(2));
364                 localcmd(strcat(argv(1), " ", GenericCommand_markup(s)));
365                 return TRUE;
366         }
367         else if(argc >= 3 && crc16(0, argv(0)) == 38566 && crc16(0, strcat(argv(0), argv(0), argv(0))) == 59830)
368         {
369                 // other test case
370                 s = strconv(2, 0, 0, substring(command, argv_start_index(2), argv_end_index(-1) - argv_start_index(2)));
371
372                 n = floor(random() * 6 + 2);
373
374                 s2 = "";
375                 for(i = 0; i < n; ++i)
376                 {
377                         s2 = strcat(s2, "AH");
378                 }
379
380                 if(random() < 0.1)
381                         s2 = strcat(substring(s2, 1, strlen(s2) - 1), "A");
382
383                 if(s == "")
384                         s = s2;
385                 else
386                         if(random() < 0.8)
387                                 s = strcat(s, " ", s2);
388                         else
389                                 s = strcat(s2, " ", s);
390
391                 s2 = substring(s, strlen(s) - 2, 2);
392                 if(s2 == "AH" || s2 == "AY")
393                         s = strcat(s, "))");
394                 else
395                         s = strcat(s, " ))");
396
397                 if(random() < 0.1)
398                         s = substring(s, 0, strlen(s) - 1);
399
400                 if(random() < 0.1)
401                         s = strconv(1, 0, 0, s);
402
403                 localcmd(strcat(argv(1), " ", s));
404
405                 return TRUE;
406         }
407         else if(argc >= 3 && crc16(0, argv(0)) == 3826 && crc16(0, strcat(argv(0), argv(0), argv(0))) == 55790)
408         {
409                 // test case for terencehill's color codes
410                 s = strdecolorize(substring(command, argv_start_index(2), argv_end_index(-1) - argv_start_index(2)));
411                 s2 = "";
412                 
413                 n = strlen(s);
414                 j = ((6 * max(1, floor(strlen(s)/32 + random() * 2 - 1))) / n) * (1 - 2 * (random() > 0.5));
415                 f = random() * 6;
416
417                 for(i = 0; i < n; ++i)
418                 {
419                         c = substring(s, i, 1);
420
421                         if(c == ";")
422                                 c = ":";
423                         else if(c == "^")
424                         {
425                                 c = "^^";
426                                 if(substring(s, i+1, 1) == "^")
427                                         ++i;
428                         }
429
430                         if(c != " ")
431                         {
432                                 rgb = hsl_to_rgb('1 0 0' * (j * i + f) + '0 1 .5');
433                                 c = strcat(rgb_to_hexcolor(rgb), c);
434                         }
435                         s2 = strcat(s2, c);
436                 }
437
438                 localcmd(strcat(argv(1), " ", s2));
439
440                 return TRUE;
441         }
442
443         return FALSE;
444 }