]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/gamecommand.qc
Comment something out to compile temporarily
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / gamecommand.qc
1 // =====================================================
2 //  Server side game commands code, reworked by Samual
3 //  Last updated: November 6th, 2011
4 // =====================================================
5
6 #define GC_REQUEST_HELP 1
7 #define GC_REQUEST_COMMAND 2
8 #define GC_REQUEST_USAGE 3
9
10 float RadarMap_Make(float argc);
11
12 string GotoMap(string m);
13
14 void race_deleteTime(string map, float pos);
15
16
17 // ============================
18 //  Misc. Supporting Functions
19 // ============================
20
21 //  used by GameCommand_make_mapinfo()
22 void make_mapinfo_Think()
23 {
24         if(MapInfo_FilterGametype(MAPINFO_TYPE_ALL, 0, 0, 0, 1))
25         {
26                 print("Done rebuiling mapinfos.\n");
27                 MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0);
28                 remove(self);
29         }
30         else
31         {
32                 self.think = make_mapinfo_Think;
33                 self.nextthink = time;
34         }
35 }
36
37 //  used by GameCommand_extendmatchtime() and GameCommand_reducematchtime()
38 void changematchtime(float delta, float mi, float ma)
39 {
40         float cur;
41         float new;
42         float lim;
43
44         if(delta == 0)
45                 return;
46         if(autocvar_timelimit < 0)
47                 return;
48
49         if(mi <= 10)
50                 mi = 10; // at least ten sec in the future
51         cur = time - game_starttime;
52         if(cur > 0)
53                 mi += cur; // from current time!
54
55         lim = autocvar_timelimit * 60;
56
57         if(delta > 0)
58         {
59                 if(lim == 0)
60                         return; // cannot increase any further
61                 else if(lim < ma)
62                         new = min(ma, lim + delta);
63                 else // already above maximum: FAIL
64                         return;
65         }
66         else
67         {
68                 if(lim == 0) // infinite: try reducing to max, if we are allowed to
69                         new = max(mi, ma);
70                 else if(lim > mi) // above minimum: decrease
71                         new = max(mi, lim + delta);
72                 else // already below minimum: FAIL
73                         return;
74         }
75
76         cvar_set("timelimit", ftos(new / 60));
77 }
78
79 //  used by GameCommand_modelbug() // TODO: is this even needed?
80 float g_clientmodel_genericsendentity (entity to, float sf);
81 void modelbug_make_svqc();
82 void modelbug_make_csqc()
83 {
84         Net_LinkEntity(self, TRUE, 0, g_clientmodel_genericsendentity);
85         self.think = modelbug_make_svqc;
86         self.nextthink = time + 1;
87         setorigin(self, self.origin - '0 0 8');
88 }
89 void modelbug_make_svqc()
90 {
91         self.SendEntity = func_null;
92         self.think = modelbug_make_csqc;
93         self.nextthink = time + 1;
94         setorigin(self, self.origin + '0 0 8');
95 }
96 void modelbug()
97 {
98         entity e;
99         e = spawn();
100         setorigin(e, nextent(world).origin);
101         precache_model("models_portal.md3");
102         setmodel(e, "models/portal.md3");
103         e.think = modelbug_make_svqc;
104         e.nextthink = time + 1;
105 }
106
107
108 // =======================
109 //  Command Sub-Functions
110 // =======================
111
112 void GameCommand_adminmsg(float request, float argc)
113 {
114         switch(request)
115         {
116                 case GC_REQUEST_HELP:
117                 {
118                         print("  ^2adminmsg^7: Send an admin message to a client directly\n");
119                         return;
120                 }
121                         
122                 case GC_REQUEST_COMMAND:
123                 {
124                         entity client;
125                         float entno = stof(argv(1)); 
126                         float n, i;
127                         string s;
128                         
129                         if(argc >= 3 && argc <= 4) {
130                                 if((entno < 0) | (entno > maxclients)) {
131                                         print("Player ", argv(1), " doesn't exist\n");
132                                         return;
133                                 }
134                                 n = 0;
135                                 for(i = (entno ? entno : 1); i <= (entno ? entno : maxclients); ++i)
136                                 {
137                                         client = edict_num(i);
138                                         if(client.flags & FL_CLIENT)
139                                         {
140                                                 if(argc == 4)
141                                                 {
142                                                         // make the string console safe
143                                                         s = argv(2);
144                                                         s = strreplace("\n", "", s);
145                                                         s = strreplace("\\", "\\\\", s);
146                                                         s = strreplace("$", "$$", s);
147                                                         s = strreplace("\"", "\\\"", s);
148                                                         stuffcmd(client, sprintf("\ninfobar %f \"%s\"\n", stof(argv(3)), s));
149                                                 }
150                                                 else
151                                                 {
152                                                         centerprint(client, strcat("^3", admin_name(), ":\n\n^7", argv(2)));
153                                                         sprint(client, strcat("\{1}\{13}^3", admin_name(), "^7: ", argv(2), "\n"));
154                                                 }
155                                                 dprint("Message sent to ", client.netname, "\n");
156                                                 ++n;
157                                         }
158                                 }
159                                 if(!n) { print(strcat("Client (", argv(1) ,") not found.\n")); } 
160                                 return;
161                         }
162                 }
163                 
164                 default:
165                         print("Incorrect parameters for ^2adminmsg^7\n");
166                 case GC_REQUEST_USAGE:
167                 {
168                         print("\nUsage:^3 sv_cmd adminmsg clientnumber \"message\" [infobartime]\n");
169                         print("  If infobartime is provided, the message will be sent to infobar.\n");
170                         print("  Otherwise, it will just be sent as a centerprint message.\n");
171                         print("Examples: adminmsg 4 \"this infomessage will last for ten seconds\" 10\n");
172                         print("          adminmsg 2 \"this message will be a centerprint\"\n");
173                         return;
174                 }
175         }
176 }
177
178 void GameCommand_allready(float request)
179 {
180         switch(request)
181         {
182                 case GC_REQUEST_HELP:
183                 {
184                         print("  ^2allready^7: Restart the server and reset the players\n");
185                         return;
186                 }
187                         
188                 case GC_REQUEST_COMMAND:
189                 {
190                         ReadyRestart();
191                         return;
192                 }
193                         
194                 default:
195                 case GC_REQUEST_USAGE:
196                 {
197                         print("\nUsage:^3 sv_cmd allready\n");
198                         print("  No arguments required.\n");
199                         return;
200                 }
201         }
202 }
203
204 void GameCommand_allspec(float request, float argc)
205 {       
206         switch(request)
207         {
208                 case GC_REQUEST_HELP:
209                 {
210                         print("  ^2allspec^7: Force all players to spectate\n");
211                         return;
212                 }
213                         
214                 case GC_REQUEST_COMMAND:
215                 {
216                         entity client;
217                         string reason = argv(1);
218                         float i;
219                         
220                         FOR_EACH_PLAYER(client)
221                         {
222                                 self = client;
223                                 PutObserverInServer();
224                                 ++i;
225                         }
226                         if(i) { bprint(strcat("Successfully forced all (", ftos(i), ") players to spectate", (reason ? strcat(" for reason: '", reason, "'") : ""), ".\n")); }
227                         else { print("No players found to spectate.\n"); }
228                         return;
229                 }
230                         
231                 default:
232                 case GC_REQUEST_USAGE:
233                 {
234                         print("\nUsage:^3 sv_cmd allspec [reason]\n");
235                         print("  Where 'reason' is an optional argument for explanation of allspec command.\n");
236                         print("See also: ^2moveplayer^7\n");
237                         return;
238                 }
239         }
240 }
241
242 void GameCommand_anticheat(float request, float argc) // FIXME: player entity is never found
243 {
244         switch(request)
245         {
246                 case GC_REQUEST_HELP:
247                 {
248                         print("  ^2anticheat^7: Create an anticheat report for a client\n");
249                         return;
250                 }
251                         
252                 case GC_REQUEST_COMMAND:
253                 {
254                         entity client;
255                         float entno = stof(argv(1)); 
256                         
257                         if((entno < 1) | (entno > maxclients)) {
258                                 print("Player ", argv(1), " doesn't exist\n");
259                                 return;
260                         }
261                         client = edict_num(entno);
262                         if(clienttype(client) != CLIENTTYPE_REAL && clienttype(client) != CLIENTTYPE_BOT) {
263                                 print("Player ", client.netname, " is not active\n");
264                                 return;
265                         }
266                         self = client;
267                         anticheat_report();
268                         return;
269                 }
270                         
271                 default:
272                         print("Incorrect parameters for ^2anticheat^7\n");
273                 case GC_REQUEST_USAGE:
274                 {
275                         print("\nUsage:^3 sv_cmd anticheat clientnumber\n");
276                         print("  where 'clientnumber' is player entity number.\n");
277                         return;
278                 }
279         }
280 }
281
282 void GameCommand_bbox(float request)
283 {
284         switch(request)
285         {
286                 case GC_REQUEST_HELP:
287                 {
288                         print("  ^2bbox^7: Print detailed information about world size\n");
289                         return;
290                 }
291                         
292                 case GC_REQUEST_COMMAND:
293                 {
294                         print("Original size: ", ftos(world.absmin_x), " ", ftos(world.absmin_y), " ", ftos(world.absmin_z));
295                         print(" ", ftos(world.absmax_x), " ", ftos(world.absmax_y), " ", ftos(world.absmax_z), "\n");
296                         print("Currently set size: ", ftos(world.mins_x), " ", ftos(world.mins_y), " ", ftos(world.mins_z));
297                         print(" ", ftos(world.maxs_x), " ", ftos(world.maxs_y), " ", ftos(world.maxs_z), "\n");
298                         print("Solid bounding box size:");
299
300                         tracebox('1 0 0' * world.absmin_x,
301                                                         '0 1 0' * world.absmin_y + '0 0 1' * world.absmin_z,
302                                                         '0 1 0' * world.absmax_y + '0 0 1' * world.absmax_z,
303                                                         '1 0 0' * world.absmax_x,
304                                         MOVE_WORLDONLY,
305                                         world);
306                         if(trace_startsolid)
307                                 print(" ", ftos(world.absmin_x));
308                         else
309                                 print(" ", ftos(trace_endpos_x));
310
311                         tracebox('0 1 0' * world.absmin_y,
312                                                         '1 0 0' * world.absmin_x + '0 0 1' * world.absmin_z,
313                                                         '1 0 0' * world.absmax_x + '0 0 1' * world.absmax_z,
314                                                         '0 1 0' * world.absmax_y,
315                                         MOVE_WORLDONLY,
316                                         world);
317                         if(trace_startsolid)
318                                 print(" ", ftos(world.absmin_y));
319                         else
320                                 print(" ", ftos(trace_endpos_y));
321
322                         tracebox('0 0 1' * world.absmin_z,
323                                                         '1 0 0' * world.absmin_x + '0 1 0' * world.absmin_y,
324                                                         '1 0 0' * world.absmax_x + '0 1 0' * world.absmax_y,
325                                                         '0 0 1' * world.absmax_z,
326                                         MOVE_WORLDONLY,
327                                         world);
328                         if(trace_startsolid)
329                                 print(" ", ftos(world.absmin_z));
330                         else
331                                 print(" ", ftos(trace_endpos_z));
332
333                         tracebox('1 0 0' * world.absmax_x,
334                                                         '0 1 0' * world.absmin_y + '0 0 1' * world.absmin_z,
335                                                         '0 1 0' * world.absmax_y + '0 0 1' * world.absmax_z,
336                                                         '1 0 0' * world.absmin_x,
337                                         MOVE_WORLDONLY,
338                                         world);
339                         if(trace_startsolid)
340                                 print(" ", ftos(world.absmax_x));
341                         else
342                                 print(" ", ftos(trace_endpos_x));
343
344                         tracebox('0 1 0' * world.absmax_y,
345                                                         '1 0 0' * world.absmin_x + '0 0 1' * world.absmin_z,
346                                                         '1 0 0' * world.absmax_x + '0 0 1' * world.absmax_z,
347                                                         '0 1 0' * world.absmin_y,
348                                         MOVE_WORLDONLY,
349                                         world);
350                         if(trace_startsolid)
351                                 print(" ", ftos(world.absmax_y));
352                         else
353                                 print(" ", ftos(trace_endpos_y));
354
355                         tracebox('0 0 1' * world.absmax_z,
356                                                         '1 0 0' * world.absmin_x + '0 1 0' * world.absmin_y,
357                                                         '1 0 0' * world.absmax_x + '0 1 0' * world.absmax_y,
358                                                         '0 0 1' * world.absmin_z,
359                                         MOVE_WORLDONLY,
360                                         world);
361                         if(trace_startsolid)
362                                 print(" ", ftos(world.absmax_z));
363                         else
364                                 print(" ", ftos(trace_endpos_z));
365                                 
366                         print("\n");
367                         return;
368                 }
369                         
370                 default:
371                 case GC_REQUEST_USAGE:
372                 {
373                         print("\nUsage:^3 sv_cmd bbox\n");
374                         print("  No arguments required.\n");
375                         print("See also: ^2gettaginfo^7\n");
376                         return;
377                 }
378         }
379 }
380
381 void GameCommand_bot_cmd(float request, float argc) // what a mess... old old code.
382 {
383         switch(request)
384         {
385                 case GC_REQUEST_HELP:
386                 {
387                         print("  ^2bot_cmd^7: Control and send commands to bots\n");
388                         return;
389                 }
390                         
391                 case GC_REQUEST_COMMAND:
392                 {
393                         entity bot;
394                         
395                         if(argv(1) == "reset")
396                         {
397                                 bot_resetqueues();
398                                 return;
399                         }
400                         else if(argv(1) == "load" && argc == 3)
401                         {
402                                 float fh, i;
403                                 string s;
404                                 fh = fopen(argv(2), FILE_READ);
405                                 if(fh < 0)
406                                 {
407                                         print("cannot open the file\n");
408                                         return;
409                                 }
410
411                                 i = 0;
412                                 while((s = fgets(fh)))
413                                 {
414                                         argc = tokenize_console(s);
415
416                                         if(argc >= 3 && argv(0) == "sv_cmd" && argv(1) == "bot_cmd")
417                                         {
418                                                 if(argv(2) == "reset")
419                                                 {
420                                                         bot_resetqueues();
421                                                 }
422                                                 else if(argv(2) == "setbots")
423                                                 {
424                                                         cvar_settemp("minplayers", "0");
425                                                         cvar_settemp("bot_number", argv(3));
426                                                         if(!bot_fixcount())
427                                                                 print("Sorry, could not set requested bot count\n");
428                                                 }
429                                                 else
430                                                 {
431                                                         // let's start at token 2 so we can skip sv_cmd bot_cmd
432                                                         bot = find_bot_by_number(stof(argv(2)));
433                                                         if(bot == world)
434                                                                 bot = find_bot_by_name(argv(2));
435                                                         if(bot)
436                                                                 bot_queuecommand(bot, strcat(argv(3), " ", argv(4)));
437                                                 }
438                                         }
439                                         else
440                                                 localcmd(strcat(s, "\n"));
441
442                                         ++i;
443                                 }
444                                 print(ftos(i), " commands read\n");
445                                 fclose(fh);
446                                 return;
447                         }
448                         else if(argv(1) == "help")
449                         {
450                                 if(argv(2))
451                                         bot_cmdhelp(argv(2));
452                                 else
453                                         bot_list_commands();
454                                 return;
455                         }
456                         else if(argc >= 3) // this comes last
457                         {
458                                 bot = find_bot_by_number(stof(argv(1)));
459                                 if(bot == world)
460                                         bot = find_bot_by_name(argv(1));
461                                 if(bot)
462                                 {
463                                         print(strcat("Command '", strcat(argv(2), " ", argv(3)), "' sent to bot ", bot.netname, "\n"));
464                                         bot_queuecommand(bot, strcat(argv(2), " ", argv(3)));
465                                         return;
466                                 }
467                                 else
468                                         print(strcat("Error: Can't find bot with the name or id '", argv(1),"' - Did you mistype the command?\n")); // don't return so that usage is shown
469                         }
470                 }
471                         
472                 default:
473                         print("Incorrect parameters for ^2bot_cmd^7\n");
474                 case GC_REQUEST_USAGE:
475                 {
476                         print("\nUsage:^3 sv_cmd bot_cmd client command [argument]\n");
477                         print("  'client' can be either the name or entity id of the bot\n");
478                         print("  For full list of commands, see bot_cmd help [command].\n");
479                         print("Examples: bot_cmd <id> cc \"say something\"\n");
480                         print("          bot_cmd <id> presskey jump\n");
481                         return;
482                 }
483         }
484 }
485
486 void GameCommand_cointoss(float request, float argc)
487 {
488         switch(request)
489         {
490                 case GC_REQUEST_HELP:
491                 {
492                         print("  ^2cointoss^7: Flip a virtual coin and give random result\n");
493                         return;
494                 }
495                         
496                 case GC_REQUEST_COMMAND:
497                 {
498                         entity client;
499                         string result1 = (argv(2) ? strcat("^7", argv(1), "^3!\n") : "^1HEADS^3!\n");
500                         string result2 = (argv(2) ? strcat("^7", argv(2), "^3!\n") : "^4TAILS^3!\n");
501                         string choice = ((random() > 0.5) ? result1 : result2);
502                         
503                         FOR_EACH_CLIENT(client)
504                                 centerprint(client, strcat("^3Throwing coin... Result: ", choice));
505                         bprint(strcat("^3Throwing coin... Result: ", choice));
506                         return;
507                 }
508                 
509                 default:
510                 case GC_REQUEST_USAGE:
511                 {
512                         print("\nUsage:^3 sv_cmd cointoss [result1 result2]\n");
513                         print("  Where 'result1' and 'result2' are user created options.\n");
514                         return;
515                 }
516         }
517 }
518
519 void GameCommand_cvar_changes(float request)
520 {
521         switch(request)
522         {
523                 case GC_REQUEST_HELP:
524                 {
525                         print("  ^2cvar_changes^7: Prints a list of all changed server cvars\n");
526                         return;
527                 }
528                         
529                 case GC_REQUEST_COMMAND:
530                 {
531                         print(cvar_changes);
532                         return;
533                 }
534                         
535                 default:
536                 case GC_REQUEST_USAGE:
537                 {
538                         print("\nUsage:^3 sv_cmd cvar_changes\n");
539                         print("  No arguments required.\n");
540                         print("See also: ^2cvar_purechanges^7\n");
541                         return;
542                 }
543         }
544 }
545
546 void GameCommand_cvar_purechanges(float request)
547 {
548         switch(request)
549         {
550                 case GC_REQUEST_HELP:
551                 {
552                         print("  ^2cvar_purechanges^7: Prints a list of all changed gameplay cvars\n");
553                         return;
554                 }
555                         
556                 case GC_REQUEST_COMMAND:
557                 {
558                         print(cvar_purechanges);
559                         return;
560                 }
561                         
562                 default:
563                 case GC_REQUEST_USAGE:
564                 {
565                         print("\nUsage:^3 sv_cmd cvar_purechanges\n");
566                         print("  No arguments required.\n");
567                         print("See also: ^2cvar_changes^7\n");
568                         return;
569                 }
570         }
571 }
572
573 void GameCommand_database(float request, float argc)
574 {
575         switch(request)
576         {
577                 case GC_REQUEST_HELP:
578                 {
579                         print("  ^2database^7: Extra controls of the serverprogs database\n");
580                         return;
581                 }
582                         
583                 case GC_REQUEST_COMMAND:
584                 {
585                         if(argc == 3)
586                         {
587                                 if(argv(1) == "save")
588                                 {
589                                         db_save(ServerProgsDB, argv(2));
590                                         print(strcat("Copied serverprogs database to '", argv(2), "' in the data directory.\n"));
591                                         return;
592                                 }
593                                 else if(argv(1) == "dump")
594                                 {
595                                         db_dump(ServerProgsDB, argv(2));
596                                         print("DB dumped.\n"); // wtf does this do?
597                                         return;
598                                 }
599                                 else if(argv(1) == "load")
600                                 {
601                                         db_close(ServerProgsDB);
602                                         ServerProgsDB = db_load(argv(2));
603                                         print(strcat("Loaded '", argv(2), "' as new serverprogs database.\n"));
604                                         return;
605                                 }
606                         }
607                 }
608                         
609                 default:
610                         print("Incorrect parameters for ^2database^7\n");
611                 case GC_REQUEST_USAGE:
612                 {
613                         print("\nUsage:^3 sv_cmd database action filename\n");
614                         print("  Where 'action' is the command to complete,\n");
615                         print("  and 'filename' is what it acts upon.\n");
616                         print("  Full list of commands here: \"save, dump, load.\"\n");
617                         return;
618                 }
619         }
620 }
621
622 void GameCommand_defer_clear(float request, float argc)
623 {       
624         switch(request)
625         {
626                 case GC_REQUEST_HELP:
627                 {
628                         print("  ^2defer_clear^7: Clear all queued defer commands for client\n");
629                         return;
630                 }
631                         
632                 case GC_REQUEST_COMMAND:
633                 {
634                         entity client;
635                         float entno = stof(argv(1));
636                         
637                         if(argc == 2)
638                         {
639                                 // player_id is out of range
640                                 if((entno < 1) | (entno > maxclients)) {
641                                         print("Player ", argv(1), " doesn't exist\n");
642                                         return;
643                                 }
644                                 client = edict_num(entno);
645                                 if not(client.flags & FL_CLIENT) {
646                                         print("Player ", argv(1), " doesn't exist\n");
647                                         return;
648                                 }
649                                 if(clienttype(client) == CLIENTTYPE_BOT) {
650                                         print("Player ", argv(1), " (", client.netname, ") is a bot\n");
651                                         return;
652                                 }
653                                 stuffcmd(client, "defer clear\n");
654                                 print("defer clear stuffed to ", argv(1), " (", client.netname, ")\n");
655                                 return;
656                         }
657                 }
658                 
659                 default:
660                         print("Incorrect parameters for ^2defer_clear^7\n");
661                 case GC_REQUEST_USAGE:
662                 {
663                         print("\nUsage:^3 sv_cmd defer_clear clientnumber\n");
664                         print("  where 'clientnumber' is player entity number.\n");
665                         print("See also: ^2defer_clear_all^7\n");
666                         return;
667                 }
668         }
669 }
670
671 void GameCommand_defer_clear_all(float request)
672 {       
673         switch(request)
674         {
675                 case GC_REQUEST_HELP:
676                 {
677                         print("  ^2defer_clear_all^7: Clear all queued defer commands for all clients\n");
678                         return;
679                 }
680                         
681                 case GC_REQUEST_COMMAND:
682                 {
683                         entity client;
684                         float i;
685                         float argc;
686                         
687                         FOR_EACH_CLIENT(client)
688                         {
689                                 argc = tokenize_console(strcat("defer_clear ", ftos(num_for_edict(client))));
690                                 GameCommand_defer_clear(GC_REQUEST_COMMAND, argc);      
691                                 ++i;
692                         }
693                         if(i) { bprint(strcat("Successfully stuffed defer clear to all clients (", ftos(i), ")\n")); } // should a message be added if no players were found? 
694                         return;
695                 }
696                 
697                 default:
698                 case GC_REQUEST_USAGE:
699                 {
700                         print("\nUsage:^3 sv_cmd defer_clear_all\n");
701                         print("  No arguments required.\n");
702                         print("See also: ^2defer_clear^7\n");
703                         return;
704                 }
705         }
706 }
707
708 void GameCommand_delrec(float request, float argc) // UNTESTED // perhaps merge later with records and printstats and such?
709 {
710         switch(request)
711         {
712                 case GC_REQUEST_HELP:
713                 {
714                         print("  ^2delrec^7: Delete race time record for a map\n");
715                         return;
716                 }
717                         
718                 case GC_REQUEST_COMMAND:
719                 {
720                         if(argv(1))
721                         {
722                                 if(argv(2))
723                                         race_deleteTime(argv(2), stof(argv(1)));
724                                 else
725                                         race_deleteTime(GetMapname(), stof(argv(1)));
726                                 return;
727                         }
728                 }       
729                 
730                 default:
731                         print("Incorrect parameters for ^2delrec^7\n");
732                 case GC_REQUEST_USAGE:
733                 {
734                         print("\nUsage:^3 sv_cmd delrec ranking [map]\n");
735                         print("  'ranking' is which ranking level to clear up to, \n");
736                         print("  it will clear all records up to nth place.\n");
737                         print("  if 'map' is not provided it will use current map.\n");
738                         return;
739                 }
740         }
741 }
742
743 void GameCommand_effectindexdump(float request)
744 {
745         switch(request)
746         {
747                 case GC_REQUEST_HELP:
748                 {
749                         print("  ^2effectindexdump^7: Dump list of effects from code and effectinfo.txt\n");
750                         return;
751                 }
752                         
753                 case GC_REQUEST_COMMAND:
754                 {
755                         float fh, d;
756                         string s;
757                         
758                         d = db_create();
759                         print("begin of effects list\n");
760                         db_put(d, "TE_GUNSHOT", "1"); print("effect TE_GUNSHOT is ", ftos(particleeffectnum("TE_GUNSHOT")), "\n");
761                         db_put(d, "TE_GUNSHOTQUAD", "1"); print("effect TE_GUNSHOTQUAD is ", ftos(particleeffectnum("TE_GUNSHOTQUAD")), "\n");
762                         db_put(d, "TE_SPIKE", "1"); print("effect TE_SPIKE is ", ftos(particleeffectnum("TE_SPIKE")), "\n");
763                         db_put(d, "TE_SPIKEQUAD", "1"); print("effect TE_SPIKEQUAD is ", ftos(particleeffectnum("TE_SPIKEQUAD")), "\n");
764                         db_put(d, "TE_SUPERSPIKE", "1"); print("effect TE_SUPERSPIKE is ", ftos(particleeffectnum("TE_SUPERSPIKE")), "\n");
765                         db_put(d, "TE_SUPERSPIKEQUAD", "1"); print("effect TE_SUPERSPIKEQUAD is ", ftos(particleeffectnum("TE_SUPERSPIKEQUAD")), "\n");
766                         db_put(d, "TE_WIZSPIKE", "1"); print("effect TE_WIZSPIKE is ", ftos(particleeffectnum("TE_WIZSPIKE")), "\n");
767                         db_put(d, "TE_KNIGHTSPIKE", "1"); print("effect TE_KNIGHTSPIKE is ", ftos(particleeffectnum("TE_KNIGHTSPIKE")), "\n");
768                         db_put(d, "TE_EXPLOSION", "1"); print("effect TE_EXPLOSION is ", ftos(particleeffectnum("TE_EXPLOSION")), "\n");
769                         db_put(d, "TE_EXPLOSIONQUAD", "1"); print("effect TE_EXPLOSIONQUAD is ", ftos(particleeffectnum("TE_EXPLOSIONQUAD")), "\n");
770                         db_put(d, "TE_TAREXPLOSION", "1"); print("effect TE_TAREXPLOSION is ", ftos(particleeffectnum("TE_TAREXPLOSION")), "\n");
771                         db_put(d, "TE_TELEPORT", "1"); print("effect TE_TELEPORT is ", ftos(particleeffectnum("TE_TELEPORT")), "\n");
772                         db_put(d, "TE_LAVASPLASH", "1"); print("effect TE_LAVASPLASH is ", ftos(particleeffectnum("TE_LAVASPLASH")), "\n");
773                         db_put(d, "TE_SMALLFLASH", "1"); print("effect TE_SMALLFLASH is ", ftos(particleeffectnum("TE_SMALLFLASH")), "\n");
774                         db_put(d, "TE_FLAMEJET", "1"); print("effect TE_FLAMEJET is ", ftos(particleeffectnum("TE_FLAMEJET")), "\n");
775                         db_put(d, "EF_FLAME", "1"); print("effect EF_FLAME is ", ftos(particleeffectnum("EF_FLAME")), "\n");
776                         db_put(d, "TE_BLOOD", "1"); print("effect TE_BLOOD is ", ftos(particleeffectnum("TE_BLOOD")), "\n");
777                         db_put(d, "TE_SPARK", "1"); print("effect TE_SPARK is ", ftos(particleeffectnum("TE_SPARK")), "\n");
778                         db_put(d, "TE_PLASMABURN", "1"); print("effect TE_PLASMABURN is ", ftos(particleeffectnum("TE_PLASMABURN")), "\n");
779                         db_put(d, "TE_TEI_G3", "1"); print("effect TE_TEI_G3 is ", ftos(particleeffectnum("TE_TEI_G3")), "\n");
780                         db_put(d, "TE_TEI_SMOKE", "1"); print("effect TE_TEI_SMOKE is ", ftos(particleeffectnum("TE_TEI_SMOKE")), "\n");
781                         db_put(d, "TE_TEI_BIGEXPLOSION", "1"); print("effect TE_TEI_BIGEXPLOSION is ", ftos(particleeffectnum("TE_TEI_BIGEXPLOSION")), "\n");
782                         db_put(d, "TE_TEI_PLASMAHIT", "1"); print("effect TE_TEI_PLASMAHIT is ", ftos(particleeffectnum("TE_TEI_PLASMAHIT")), "\n");
783                         db_put(d, "EF_STARDUST", "1"); print("effect EF_STARDUST is ", ftos(particleeffectnum("EF_STARDUST")), "\n");
784                         db_put(d, "TR_ROCKET", "1"); print("effect TR_ROCKET is ", ftos(particleeffectnum("TR_ROCKET")), "\n");
785                         db_put(d, "TR_GRENADE", "1"); print("effect TR_GRENADE is ", ftos(particleeffectnum("TR_GRENADE")), "\n");
786                         db_put(d, "TR_BLOOD", "1"); print("effect TR_BLOOD is ", ftos(particleeffectnum("TR_BLOOD")), "\n");
787                         db_put(d, "TR_WIZSPIKE", "1"); print("effect TR_WIZSPIKE is ", ftos(particleeffectnum("TR_WIZSPIKE")), "\n");
788                         db_put(d, "TR_SLIGHTBLOOD", "1"); print("effect TR_SLIGHTBLOOD is ", ftos(particleeffectnum("TR_SLIGHTBLOOD")), "\n");
789                         db_put(d, "TR_KNIGHTSPIKE", "1"); print("effect TR_KNIGHTSPIKE is ", ftos(particleeffectnum("TR_KNIGHTSPIKE")), "\n");
790                         db_put(d, "TR_VORESPIKE", "1"); print("effect TR_VORESPIKE is ", ftos(particleeffectnum("TR_VORESPIKE")), "\n");
791                         db_put(d, "TR_NEHAHRASMOKE", "1"); print("effect TR_NEHAHRASMOKE is ", ftos(particleeffectnum("TR_NEHAHRASMOKE")), "\n");
792                         db_put(d, "TR_NEXUIZPLASMA", "1"); print("effect TR_NEXUIZPLASMA is ", ftos(particleeffectnum("TR_NEXUIZPLASMA")), "\n");
793                         db_put(d, "TR_GLOWTRAIL", "1"); print("effect TR_GLOWTRAIL is ", ftos(particleeffectnum("TR_GLOWTRAIL")), "\n");
794                         db_put(d, "TR_SEEKER", "1"); print("effect TR_SEEKER is ", ftos(particleeffectnum("TR_SEEKER")), "\n");
795                         db_put(d, "SVC_PARTICLE", "1"); print("effect SVC_PARTICLE is ", ftos(particleeffectnum("SVC_PARTICLE")), "\n");
796
797                         fh = fopen("effectinfo.txt", FILE_READ);
798                         while((s = fgets(fh)))
799                         {
800                                 tokenize_console(s);
801                                 if(argv(0) == "effect")
802                                 {
803                                         if(db_get(d, argv(1)) != "1")
804                                         {
805                                                 if(particleeffectnum(argv(1)) >= 0)
806                                                         print("effect ", argv(1), " is ", ftos(particleeffectnum(argv(1))), "\n");
807                                                 db_put(d, argv(1), "1");
808                                         }
809                                 }
810                         }
811                         print("end of effects list\n");
812
813                         db_close(d);
814                         return;
815                 }
816                         
817                 default:
818                 case GC_REQUEST_USAGE:
819                 {
820                         print("\nUsage:^3 sv_cmd effectindexdump\n");
821                         print("  No arguments required.\n");
822                         return;
823                 }
824         }
825 }
826
827 void GameCommand_extendmatchtime(float request)
828 {
829         switch(request)
830         {
831                 case GC_REQUEST_HELP:
832                 {
833                         print("  ^2extendmatchtime^7: Increase the timelimit value incrementally\n");
834                         return;
835                 }
836                         
837                 case GC_REQUEST_COMMAND:
838                 {
839                         changematchtime(autocvar_timelimit_increment* 60, autocvar_timelimit_min*60, autocvar_timelimit_max*60);
840                         return;
841                 }
842                         
843                 default:
844                 case GC_REQUEST_USAGE:
845                 {
846                         print("\nUsage:^3 sv_cmd extendmatchtime\n");
847                         print("  No arguments required.\n");
848                         print("See also: ^2reducematchtime^7\n");
849                         return;
850                 }
851         }
852 }
853
854 void GameCommand_find(float request, float argc)
855 {       
856         switch(request)
857         {
858                 case GC_REQUEST_HELP:
859                 {
860                         print("  ^2find^7: Search through entities for matching classname\n");
861                         return;
862                 }
863                         
864                 case GC_REQUEST_COMMAND:
865                 {
866                         entity client;
867                         
868                         for(client = world; (client = find(client, classname, argv(1))); )
869                                 print(etos(client), "\n");
870                                 
871                         return;
872                 }
873                         
874                 default:
875                         print("Incorrect parameters for ^2find^7\n");
876                 case GC_REQUEST_USAGE:
877                 {
878                         print("\nUsage:^3 sv_cmd find classname\n");
879                         print("  Where 'classname' is the classname to search for.\n");
880                         return;
881                 }
882         }
883 }
884
885 void GameCommand_gametype(float request, float argc)
886 {       
887         switch(request)
888         {
889                 case GC_REQUEST_HELP:
890                 {
891                         print("  ^2gametype^7: Simple command to change the active gametype\n");
892                         return;
893                 }
894                         
895                 case GC_REQUEST_COMMAND:
896                 {
897                         string s = argv(1);
898                         float t = MapInfo_Type_FromString(s), tsave = MapInfo_CurrentGametype();
899                         
900                         if(t)
901                         {
902                                 MapInfo_SwitchGameType(t);
903                                 MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0);
904                                 if(MapInfo_count > 0)
905                                         bprint("Game type successfully switched to ", s, "\n");
906                                 else
907                                 {
908                                         bprint("Cannot use this game type: no map for it found\n");
909                                         MapInfo_SwitchGameType(tsave);
910                                         MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0);
911                                 }
912                         }
913                         else
914                                 bprint("Game type switch to ", s, " failed: this type does not exist!\n");
915                         return;
916                 }
917                         
918                 default:
919                         print("Incorrect parameters for ^2gametype^7\n");
920                 case GC_REQUEST_USAGE:
921                 {
922                         print("\nUsage:^3 sv_cmd gametype mode\n");
923                         print("  Where 'mode' is the gametype mode to switch to.\n");
924                         print("See also: ^2gotomap^7\n");
925                         return;
926                 }
927         }
928 }
929
930 void GameCommand_gettaginfo(float request, float argc) // UNTESTED // todo: finish usage description for it (but, must first learn this shit)
931 {       
932         switch(request)
933         {
934                 case GC_REQUEST_HELP:
935                 {
936                         print("  ^2gettaginfo^7: Get specific information about a weapon model\n");
937                         return;
938                 }
939                         
940                 case GC_REQUEST_COMMAND:
941                 {
942                         entity tmp_entity;
943                         float i;
944                         vector v;
945                         
946                         if(argc >= 4)
947                         {
948                                 tmp_entity = spawn();
949                                 if(argv(1) == "w")
950                                         setmodel(tmp_entity, (nextent(world)).weaponentity.model);
951                                 else
952                                 {
953                                         precache_model(argv(1));
954                                         setmodel(tmp_entity, argv(1));
955                                 }
956                                 tmp_entity.frame = stof(argv(2));
957                                 if(substring(argv(3), 0, 1) == "#")
958                                         i = stof(substring(argv(3), 1, -1));
959                                 else
960                                         i = gettagindex(tmp_entity, argv(3));
961                                 if(i)
962                                 {
963                                         v = gettaginfo(tmp_entity, i);
964                                         print("model ", tmp_entity.model, " frame ", ftos(tmp_entity.frame), " tag ", gettaginfo_name);
965                                         print(" index ", ftos(i), " parent ", ftos(gettaginfo_parent), "\n");
966                                         print(" vector = ", ftos(v_x), " ", ftos(v_y), " ", ftos(v_z), "\n");
967                                         print(" offset = ", ftos(gettaginfo_offset_x), " ", ftos(gettaginfo_offset_y), " ", ftos(gettaginfo_offset_z), "\n");
968                                         print(" forward = ", ftos(gettaginfo_forward_x), " ", ftos(gettaginfo_forward_y), " ", ftos(gettaginfo_forward_z), "\n");
969                                         print(" right = ", ftos(gettaginfo_right_x), " ", ftos(gettaginfo_right_y), " ", ftos(gettaginfo_right_z), "\n");
970                                         print(" up = ", ftos(gettaginfo_up_x), " ", ftos(gettaginfo_up_y), " ", ftos(gettaginfo_up_z), "\n");
971                                         if(argc >= 6)
972                                         {
973                                                 v_y = -v_y;
974                                                 localcmd(strcat(argv(4), vtos(v), argv(5), "\n"));
975                                         }
976                                 }
977                                 else
978                                         print("bone not found\n");
979                                         
980                                 remove(tmp_entity);
981                                 return;
982                         }
983                 }
984                         
985                 default:
986                         print("Incorrect parameters for ^2gettaginfo^7\n");
987                 case GC_REQUEST_USAGE:
988                 {
989                         print("\nUsage:^3 sv_cmd gettaginfo\n");
990                         print("  FIXME: Arguments currently unknown\n");
991                         print("See also: ^2bbox^7\n");
992                         return;
993                 }
994         }
995 }
996
997 void GameCommand_gotomap(float request, float argc)
998 {
999         switch(request)
1000         {
1001                 case GC_REQUEST_HELP:
1002                 {
1003                         print("  ^2gotomap^7: Simple command to switch to another map\n");
1004                         return;
1005                 }
1006                         
1007                 case GC_REQUEST_COMMAND:
1008                 {
1009                         if(argc == 2)
1010                         {
1011                                 print(GotoMap(argv(1)), "\n");
1012                                 return;
1013                         }
1014                 }
1015                         
1016                 default:
1017                         print("Incorrect parameters for ^2gotomap^7\n");
1018                 case GC_REQUEST_USAGE:
1019                 {
1020                         print("\nUsage:^3 sv_cmd gotomap map\n");
1021                         print("  Where 'map' is the *.bsp file to change to.\n");
1022                         print("See also: ^2gametype^7\n");
1023                         return;
1024                 }
1025         }
1026 }
1027
1028 void GameCommand_ladder(float request)
1029 {
1030         switch(request)
1031         {
1032                 case GC_REQUEST_HELP:
1033                 {
1034                         print("  ^2ladder^7: Get information about top players if supported\n");
1035                         return;
1036                 }
1037                         
1038                 case GC_REQUEST_COMMAND:
1039                 {
1040                         print(ladder_reply);
1041                         return;
1042                 }
1043                         
1044                 default:
1045                 case GC_REQUEST_USAGE:
1046                 {
1047                         print("\nUsage:^3 sv_cmd ladder\n");
1048                         print("  No arguments required.\n");
1049                         return;
1050                 }
1051         }
1052 }
1053
1054 void GameCommand_lockteams(float request)
1055 {
1056         switch(request)
1057         {
1058                 case GC_REQUEST_HELP:
1059                 {
1060                         print("  ^2lockteams^7: Disable the ability for players to switch or enter teams\n");
1061                         return;
1062                 }
1063                         
1064                 case GC_REQUEST_COMMAND:
1065                 {
1066                         if(teamplay)
1067                         {
1068                                 lockteams = 1;
1069                                 bprint("^1The teams are now locked.\n");
1070                         }
1071                         else
1072                                 bprint("That command can only be used in a team-based gamemode.\n");
1073                         return;
1074                 }
1075                         
1076                 default:
1077                 case GC_REQUEST_USAGE:
1078                 {
1079                         print("\nUsage:^3 sv_cmd lockteams\n");
1080                         print("  No arguments required.\n");
1081                         print("See also: ^2unlockteams^7\n");
1082                         return;
1083                 }
1084         }
1085 }
1086
1087 void GameCommand_make_mapinfo(float request) // UNTESTED
1088 {
1089         switch(request)
1090         {
1091                 case GC_REQUEST_HELP:
1092                 {
1093                         print("  ^2make_mapinfo^7: Automatically rebuild mapinfo files\n");
1094                         return;
1095                 }
1096                         
1097                 case GC_REQUEST_COMMAND:
1098                 { 
1099                         entity tmp_entity;
1100                         
1101                         tmp_entity = spawn();
1102                         tmp_entity.classname = "make_mapinfo";
1103                         tmp_entity.think = make_mapinfo_Think;
1104                         tmp_entity.nextthink = time; // this sucks... todo: re-write this -- Use initializeentity later
1105                         MapInfo_Enumerate();
1106                         return;
1107                 }
1108                         
1109                 default:
1110                 case GC_REQUEST_USAGE:
1111                 {
1112                         print("\nUsage:^3 sv_cmd make_mapinfo\n");
1113                         print("  No arguments required.\n");
1114                         return;
1115                 }
1116         }
1117 }
1118
1119 void GameCommand_modelbug(float request) // UNTESTED // is this even needed anymore? 
1120 {
1121         switch(request)
1122         {
1123                 case GC_REQUEST_HELP:
1124                 {
1125                         print("  ^2modelbug^7: foobar\n");
1126                         return;
1127                 }
1128                         
1129                 case GC_REQUEST_COMMAND:
1130                 {
1131                         modelbug();
1132                         return;
1133                 }
1134                         
1135                 default:
1136                 case GC_REQUEST_USAGE:
1137                 {
1138                         print("\nUsage:^3 sv_cmd modelbug\n");
1139                         print("  No arguments required.\n");
1140                         return;
1141                 }
1142         }
1143 }
1144
1145 void GameCommand_moveplayer(float request, float argc)
1146 {
1147         switch(request)
1148         {
1149                 case GC_REQUEST_HELP:
1150                 {
1151                         print("  ^2moveplayer^7: Change the team/status of a player\n");
1152                         return;
1153                 }
1154                         
1155                 case GC_REQUEST_COMMAND:
1156                 {
1157                         entity client;
1158         
1159                         string targets = strreplace(",", " ", argv(1));
1160                         string original_targets = strreplace(" ", ", ", targets);
1161                         string destination = argv(2);
1162                         string notify = argv(3);
1163                         
1164                         string successful, t;
1165                         
1166                         // lets see if the target(s) even actually exist.
1167                         if((targets) && (destination))
1168                         { 
1169                                 for(;targets;)
1170                                 {
1171                                         t = car(targets); targets = cdr(targets);
1172
1173                                         // Check to see if the player is a valid target
1174                                         if((GetFilteredNumber(t) < 1) || (GetFilteredNumber(t) > maxclients)) // player_id is out of range
1175                                         {
1176                                                 print("Player ", ftos(GetFilteredNumber(t)), " doesn't exist (out of range)", (targets ? ", skipping to next player.\n" : ".\n"));
1177                                                 continue; 
1178                                         }
1179                                         client = edict_num(GetFilteredNumber(t));
1180                                         if not(client.flags & FL_CLIENT) // player entity is not a client
1181                                         {
1182                                                 print("Player ", ftos(GetFilteredNumber(t)), " doesn't exist (not a client)", (targets ? ", skipping to next player.\n" : ".\n"));
1183                                                 continue;
1184                                         }
1185                                         
1186                                         // Where are we putting this player?
1187                                         if(destination == "spec" || destination == "spectator") 
1188                                         {
1189                                                 if(client.classname != "spectator" && client.classname != "observer")
1190                                                 {
1191                                                         self = client;
1192                                                         PutObserverInServer();
1193                                                         
1194                                                         successful = strcat(successful, (successful ? ", " : ""), client.netname);
1195                                                 }
1196                                                 else
1197                                                 {
1198                                                         print("Player ", ftos(GetFilteredNumber(t)), " (", client.netname, ") is already spectating.\n");
1199                                                 }
1200                                                 continue;
1201                                         }
1202                                         else
1203                                         {
1204                                                 if(client.classname != "spectator" && client.classname != "observer")
1205                                                 {
1206                                                         if(teamplay)
1207                                                         {
1208                                                                 // set up
1209                                                                 float team_color;
1210                                                                 float save = client.team_forced;
1211                                                                 client.team_forced = 0;
1212
1213                                                                 // find the team to move the player to
1214                                                                 team_color = ColourToNumber(destination);
1215                                                                 if(team_color == client.team) // already on the destination team
1216                                                                 {
1217                                                                         // keep the forcing undone
1218                                                                         print("Player ", ftos(GetFilteredNumber(t)), " (", client.netname, ") is already on the ", ColoredTeamName(client.team), (targets ? ", skipping to next player.\n" : ".\n"));
1219                                                                         continue;
1220                                                                 } 
1221                                                                 else if(team_color == 0)  // auto team
1222                                                                 {
1223                                                                         team_color = NumberToTeamNumber(FindSmallestTeam(client, FALSE));
1224                                                                 }
1225                                                                 else
1226                                                                 {
1227                                                                         CheckAllowedTeams(client);
1228                                                                 }
1229                                                                 client.team_forced = save;
1230                                                                 
1231                                                                 // Check to see if the destination team is even available
1232                                                                 switch(team_color) 
1233                                                                 {
1234                                                                         case COLOR_TEAM1: if(c1 == -1) { print("Sorry, can't move player to red team if it doesn't exist.\n"); return; } break;
1235                                                                         case COLOR_TEAM2: if(c2 == -1) { print("Sorry, can't move player to blue team if it doesn't exist.\n"); return; } break;
1236                                                                         case COLOR_TEAM3: if(c3 == -1) { print("Sorry, can't move player to yellow team if it doesn't exist.\n"); return; } break;
1237                                                                         case COLOR_TEAM4: if(c4 == -1) { print("Sorry, can't move player to pink team if it doesn't exist.\n"); return; } break;
1238                                                                         
1239                                                                         default: print("Sorry, can't move player here if team ", destination, " doesn't exist.\n"); return;
1240                                                                 }
1241                                                                 
1242                                                                 // If so, lets continue and finally move the player
1243                                                                 client.team_forced = 0;
1244                                                                 MoveToTeam(client, team_color, 6, stof(notify));
1245                                                                 successful = strcat(successful, (successful ? ", " : ""), client.netname);
1246                                                                 print("Player ", ftos(GetFilteredNumber(t)), " (", client.netname, ") has been moved to the ", ColoredTeamName(team_color), ".\n");
1247                                                                 continue;
1248                                                         }
1249                                                         else
1250                                                         {
1251                                                                 print("Can't change teams when currently not playing a team game.\n");
1252                                                                 return;
1253                                                         }
1254                                                 }
1255                                                 else
1256                                                 {
1257                                                         print("Can't change teams if the player isn't in the game.\n"); // well technically we could, but should we allow that? :P 
1258                                                         return;
1259                                                 }
1260                                         }
1261                                 }
1262                                 
1263                                 if(successful)
1264                                         print("Successfully moved players ", successful, " to destination ", destination, ".\n");
1265                                 else
1266                                         print("No players given (", original_targets, ") are able to move.\n");
1267                                         
1268                                 return; // still correct parameters so return to avoid usage print
1269                         }
1270                 }
1271                         
1272                 default:
1273                         print("Incorrect parameters for ^2moveplayer^7\n");
1274                 case GC_REQUEST_USAGE:
1275                 {
1276                         print("\nUsage:^3 sv_cmd moveplayer clientnumbers destination [notify]\n");
1277                         print("  'clientnumbers' is a list (separated by commas) of player entity ID's\n");
1278                         print("  'destination' is what to send the player to, be it team or spectating\n");
1279                         print("  Full list of destinations here: \"spec, spectator, red, blue, yellow, pink, auto.\"\n");
1280                         print("  'notify' is whether or not to send messages notifying of the move. Detail below.\n");
1281                         print("    0 (00) automove centerprint, admin message; 1 (01) automove centerprint, no admin message\n");
1282                         print("    2 (10) no centerprint, admin message; 3 (11) no centerprint, no admin message\n");
1283                         print("Examples: moveplayer 1,3,5 red 3\n");
1284                         print("          moveplayer 2 spec \n");
1285                         print("See also: ^2allspec^7\n");
1286                         return;
1287                 }
1288         }
1289 }
1290
1291 void GameCommand_nospectators(float request)
1292 {
1293         switch(request)
1294         {
1295                 case GC_REQUEST_HELP:
1296                 {
1297                         print("  ^2nospectators^7: Automatically remove spectators from a match\n");
1298                         return;
1299                 }
1300                         
1301                 case GC_REQUEST_COMMAND:
1302                 {
1303                         blockSpectators = 1;
1304                         entity plr;
1305                         FOR_EACH_CLIENT(plr) //give every spectator <g_maxplayers_spectator_blocktime> seconds time to become a player
1306                         {
1307                                 if(plr.classname == "spectator" || plr.classname == "observer")
1308                                 {
1309                                         plr.spectatortime = time;
1310                                         sprint(plr, strcat("^7You have to become a player within the next ", ftos(autocvar_g_maxplayers_spectator_blocktime), " seconds, otherwise you will be kicked, because spectators aren't allowed at this time!\n"));
1311                                 }
1312                         }
1313                         bprint(strcat("^7All spectators will be automatically kicked when not joining the game after ", ftos(autocvar_g_maxplayers_spectator_blocktime), " seconds!\n"));
1314                         return;
1315                 }
1316                         
1317                 default:
1318                 case GC_REQUEST_USAGE:
1319                 {
1320                         print("\nUsage:^3 sv_cmd nospectators\n");
1321                         print("  No arguments required.\n");
1322                         return;
1323                 }
1324         }
1325 }
1326
1327 void GameCommand_onslaught_updatelinks(float request) // UNTESTED // should this be here? Perhaps some mutatorhook call instead....
1328 {
1329         switch(request)
1330         {
1331                 case GC_REQUEST_HELP:
1332                 {
1333                         print("  ^2onslaught_updatelinks^7: Refresh link status for onslaught\n");
1334                         return;
1335                 }
1336                         
1337                 case GC_REQUEST_COMMAND:
1338                 {
1339                         onslaught_updatelinks();
1340                         print("ONS links updated\n");
1341                         return;
1342                 }
1343                         
1344                 default:
1345                 case GC_REQUEST_USAGE:
1346                 {
1347                         print("\nUsage:^3 sv_cmd onslaught_updatelinks\n");
1348                         print("  No arguments required.\n");
1349                         return;
1350                 }
1351         }
1352 }
1353
1354 void GameCommand_playerdemo(float request, float argc) // UNTESTED // TODO: change the if statements for sub arguments to switches
1355 {       
1356         switch(request)
1357         {
1358                 case GC_REQUEST_HELP:
1359                 {
1360                         print("  ^2playerdemo^7: Control the ability to save demos of players\n");
1361                         return;
1362                 }
1363                         
1364                 case GC_REQUEST_COMMAND:
1365                 {
1366                         entity client;
1367                         float i, n, entno;
1368                         string s;
1369                         
1370                         if(argv(1) == "read")
1371                         {
1372                                 // TODO: Create a general command for looking this up, save a lot of space everywhere in this file
1373                                 entno = stof(argv(2));
1374                                 if((entno < 1) | (entno > maxclients)) {
1375                                         print("Player ", argv(2), " doesn't exist\n");
1376                                         return;
1377                                 }
1378                                 client = edict_num(entno);
1379                                 if(clienttype(client) != CLIENTTYPE_BOT) {
1380                                         print("Player ", client.netname, " is not a bot\n");
1381                                         return;
1382                                 }
1383                                 self = client;
1384                                 playerdemo_open_read(argv(3));
1385                                 return;
1386                         }
1387                         else if(argv(1) == "write")
1388                         {
1389                                 entno = stof(argv(2));
1390                                 if((entno < 1) | (entno > maxclients)) {
1391                                         print("Player ", argv(2), " doesn't exist\n");
1392                                         return;
1393                                 }
1394                                 client = edict_num(entno);
1395                                 self = client;
1396                                 playerdemo_open_write(argv(3));
1397                                 return;
1398                         }
1399                         else if(argv(1) == "auto_read_and_write")
1400                         {
1401                                 s = argv(2);
1402                                 n = stof(argv(3));
1403                                 cvar_set("bot_number", ftos(n));
1404                                 localcmd("wait; wait; wait\n");
1405                                 for(i = 0; i < n; ++i)
1406                                         localcmd("sv_cmd playerdemo read ", ftos(i+2), " ", s, ftos(i+1), "\n");
1407                                 localcmd("sv_cmd playerdemo write 1 ", ftos(n+1), "\n");
1408                                 return;
1409                         }
1410                         else if(argv(1) == "auto_read")
1411                         {
1412                                 s = argv(2);
1413                                 n = stof(argv(3));
1414                                 cvar_set("bot_number", ftos(n));
1415                                 localcmd("wait; wait; wait\n");
1416                                 for(i = 0; i < n; ++i)
1417                                         localcmd("sv_cmd playerdemo read ", ftos(i+2), " ", s, ftos(i+1), "\n");
1418                                 return;
1419                         }
1420                         return;
1421                 }
1422                         
1423                 default:
1424                         print("Incorrect parameters for ^2radarmap^7\n");
1425                 case GC_REQUEST_USAGE:
1426                 {
1427                         print("\nUsage:^3 sv_cmd \n");
1428                         print("  FIXME: Arguments currently unknown\n");
1429                         return;
1430                 }
1431         }
1432 }
1433
1434 void GameCommand_printstats(float request)
1435 {
1436         switch(request)
1437         {
1438                 case GC_REQUEST_HELP:
1439                 {
1440                         print("  ^2printstats^7: foobar\n");
1441                         return;
1442                 }
1443                         
1444                 case GC_REQUEST_COMMAND:
1445                 {
1446                         DumpStats(FALSE);
1447                         print("stats dumped.\n");
1448                         return;
1449                 }
1450                         
1451                 default:
1452                 case GC_REQUEST_USAGE:
1453                 {
1454                         print("\nUsage:^3 sv_cmd printstats\n");
1455                         print("  No arguments required.\n");
1456                         return;
1457                 }
1458         }
1459 }
1460
1461 void GameCommand_radarmap(float request, float argc)
1462 {
1463         switch(request)
1464         {
1465                 case GC_REQUEST_HELP:
1466                 {
1467                         print("  ^2radarmap^7: Generate a radar image of the map\n");
1468                         return;
1469                 }
1470                         
1471                 case GC_REQUEST_COMMAND:
1472                 {
1473                         if(RadarMap_Make(argc))
1474                                 return;
1475                 }
1476                         
1477                 default:
1478                         print("Incorrect parameters for ^2radarmap^7\n");
1479                 case GC_REQUEST_USAGE:
1480                 {
1481                         print("\nUsage:^3 sv_cmd radarmap [--force] [--loop] [--quit] [--block | --trace | --sample | --lineblock] [--sharpen N] [--res W H] [--qual Q]\n");
1482                         print("  The quality factor Q is roughly proportional to the time taken.\n");
1483                         print("  trace supports no quality factor; its result should look like --block with infinite quality factor.\n");
1484                         return;
1485                 }
1486         }
1487 }
1488
1489 void GameCommand_rankings(float request) // this is OLD.... jeez.
1490 {
1491         switch(request)
1492         {
1493                 case GC_REQUEST_HELP:
1494                 {
1495                         print("  ^2rankings^7: Print information about rankings\n");
1496                         return;
1497                 }
1498                         
1499                 case GC_REQUEST_COMMAND:
1500                 {
1501                         strunzone(rankings_reply);
1502                         rankings_reply = strzone(getrankings());
1503                         print(rankings_reply);
1504                         return;
1505                 }
1506                         
1507                 default:
1508                 case GC_REQUEST_USAGE:
1509                 {
1510                         print("\nUsage:^3 sv_cmd rankings\n");
1511                         print("  No arguments required.\n");
1512                         return;
1513                 }
1514         }
1515 }
1516
1517 void GameCommand_records(float request)
1518 {
1519         switch(request)
1520         {
1521                 case GC_REQUEST_HELP:
1522                 {
1523                         print("  ^2records^7: List top 10 records for the current map\n");
1524                         return;
1525                 }
1526                         
1527                 case GC_REQUEST_COMMAND:
1528                 {
1529                         float i;
1530                         
1531                         for (i = 0; i < 10; ++i)
1532                                 print(records_reply[i]);
1533                                 
1534                         return;
1535                 }
1536                         
1537                 default:
1538                 case GC_REQUEST_USAGE:
1539                 {
1540                         print("\nUsage:^3 sv_cmd records\n");
1541                         print("  No arguments required.\n");
1542                         return;
1543                 }
1544         }
1545 }
1546
1547 void GameCommand_reducematchtime(float request)
1548 {
1549         switch(request)
1550         {
1551                 case GC_REQUEST_HELP:
1552                 {
1553                         print("  ^2reducematchtime^7: Decrease the timelimit value incrementally\n");
1554                         return;
1555                 }
1556                         
1557                 case GC_REQUEST_COMMAND:
1558                 {
1559                         changematchtime(autocvar_timelimit_decrement*-60, autocvar_timelimit_min*60, autocvar_timelimit_max*60);
1560                         return;
1561                 }
1562                         
1563                 default:
1564                 case GC_REQUEST_USAGE:
1565                 {
1566                         print("\nUsage:^3 sv_cmd reducematchtime\n");
1567                         print("  No arguments required.\n");
1568                         print("See also: ^2extendmatchtime^7\n");
1569                         return;
1570                 }
1571         }
1572 }
1573
1574 void GameCommand_setbots(float request, float argc)
1575 {
1576         switch(request)
1577         {
1578                 case GC_REQUEST_HELP:
1579                 {
1580                         print("  ^2setbots^7: Change the values of bot_number and minplayers immediately to change the bot count\n");
1581                         return;
1582                 }
1583                         
1584                 case GC_REQUEST_COMMAND:
1585                 {
1586                         if(argc >= 3 && argv(1) == "setbots")
1587                         {
1588                                 cvar_settemp("minplayers", "0");
1589                                 cvar_settemp("bot_number", argv(2));
1590                                 bot_fixcount();
1591                                 return;
1592                         }
1593                 }
1594                         
1595                 default:
1596                 case GC_REQUEST_USAGE:
1597                 {
1598                         print("\nUsage:^3 sv_cmd setbots botnumber\n");
1599                         print("  Where 'botnumber' is the amount of bots to set bot_number cvar to.\n");
1600                         print("See also: ^2bot_cmd^7\n");
1601                         return;
1602                 }
1603         }
1604 }
1605
1606 void GameCommand_stuffto(float request, float argc)
1607 {
1608         // This... is a fairly dangerous and powerful command... - It allows any arguments to be sent to a client via rcon.
1609         // Because of this, it is disabled by default and must be enabled by the server owner when doing compilation. That way,
1610         // we can be certain they understand the risks of it... So to enable, compile server with -DSTUFFTO_ENABLED argument.
1611         
1612         #ifdef STUFFTO_ENABLED
1613         switch(request)
1614         {
1615                 case GC_REQUEST_HELP:
1616                 {
1617                         print("  ^2stuffto^7: Send a command to be executed on a client\n");
1618                         return;
1619                 }
1620                         
1621                 case GC_REQUEST_COMMAND:
1622                 {
1623                         entity client;
1624                         float entno;
1625                         
1626                         if(argc == 3)
1627                         {
1628                                 entno = stof(argv(1));
1629                                 client = world;
1630                                 if(entno <= maxclients)
1631                                         client = edict_num(entno);
1632                                 if(client.flags & FL_CLIENT)
1633                                 {
1634                                         stuffcmd(client, strcat("\n", argv(2), "\n"));
1635                                         print(strcat("Command: \"", argv(2), "\" sent to ", client.netname, " (", argv(1) ,").\n"));
1636                                 }
1637                                 else
1638                                         print(strcat("Client (", argv(1) ,") not found.\n"));
1639                                 
1640                                 return;
1641                         }
1642                 }
1643                         
1644                 default:
1645                         print("Incorrect parameters for ^2stuffto^7\n");
1646                 case GC_REQUEST_USAGE:
1647                 {
1648                         print("\nUsage:^3 sv_cmd stuffto clientnumber command\n");
1649                         print("  FIXME: Arguments currently unknown\n");
1650                         return;
1651                 }
1652         }
1653         #else // give the response for missing command to fake them out ;3
1654         if(request == GC_REQUEST_COMMAND)
1655         {
1656                 print("Invalid command. For a list of supported commands, try sv_cmd help.\n");
1657                 return;
1658         }
1659         #endif
1660 }
1661
1662 void GameCommand_teamstatus(float request)
1663 {
1664         switch(request)
1665         {
1666                 case GC_REQUEST_HELP:
1667                 {
1668                         print("  ^2teamstatus^7: Show information about player and team scores\n");
1669                         return;
1670                 }
1671                         
1672                 case GC_REQUEST_COMMAND:
1673                 {
1674                         Score_NicePrint(world);
1675                         return;
1676                 }
1677                         
1678                 default:
1679                 case GC_REQUEST_USAGE:
1680                 {
1681                         print("\nUsage:^3 sv_cmd teamstatus\n");
1682                         print("  No arguments required.\n");
1683                         return;
1684                 }
1685         }
1686 }
1687
1688 void GameCommand_time(float request)
1689 {
1690         switch(request)
1691         {
1692                 case GC_REQUEST_HELP:
1693                 {
1694                         print("  ^2time^7: Print different formats/readouts of time\n");
1695                         return;
1696                 }
1697                         
1698                 case GC_REQUEST_COMMAND:
1699                 {
1700                         print("time = ", ftos(time), "\n");
1701                         print("frame start = ", ftos(gettime(GETTIME_FRAMESTART)), "\n");
1702                         print("realtime = ", ftos(gettime(GETTIME_REALTIME)), "\n");
1703                         print("hires = ", ftos(gettime(GETTIME_HIRES)), "\n");
1704                         print("uptime = ", ftos(gettime(GETTIME_UPTIME)), "\n");
1705                         print("localtime = ", strftime(TRUE, "%a %b %e %H:%M:%S %Z %Y"), "\n"); // FIXME: Why is strftime broken? is engine problem, I think.
1706                         print("gmtime = ", strftime(FALSE, "%a %b %e %H:%M:%S %Z %Y"), "\n");
1707                         return;
1708                 }
1709                         
1710                 default:
1711                 case GC_REQUEST_USAGE:
1712                 {
1713                         print("\nUsage:^3 sv_cmd time\n");
1714                         print("  No arguments required.\n");
1715                         return;
1716                 }
1717         }
1718 }
1719
1720 void GameCommand_trace(float request, float argc)
1721 {                                               
1722         switch(request)
1723         {
1724                 case GC_REQUEST_HELP:
1725                 {
1726                         print("  ^2trace^7: Various debugging tools with tracing\n");
1727                         return;
1728                 }
1729                         
1730                 case GC_REQUEST_COMMAND:
1731                 {
1732                         // TODO: Clean up all of these variables and merge the code below to use only a few
1733                         entity e;
1734                         vector org, delta, start, end, p, q, q0, pos, vv, dv;
1735                         float i, f, safe, unsafe, dq, dqf;
1736         
1737                         switch(argv(1))
1738                         {
1739                                 case "debug":
1740                                         print("TEST CASE. If this returns the runaway loop counter error, possibly everything is oaky.\n");
1741                                         for(;;)
1742                                         {
1743                                                 org = world.mins;
1744                                                 delta = world.maxs - world.mins;
1745
1746                                                 start_x = org_x + random() * delta_x;
1747                                                 start_y = org_y + random() * delta_y;
1748                                                 start_z = org_z + random() * delta_z;
1749
1750                                                 end_x = org_x + random() * delta_x;
1751                                                 end_y = org_y + random() * delta_y;
1752                                                 end_z = org_z + random() * delta_z;
1753
1754                                                 start = stov(vtos(start));
1755                                                 end = stov(vtos(end));
1756
1757                                                 tracebox(start, PL_MIN, PL_MAX, end, MOVE_NOMONSTERS, world);
1758                                                 if(!trace_startsolid)
1759                                                 {
1760                                                         p = trace_endpos;
1761                                                         tracebox(p, PL_MIN, PL_MAX, p, MOVE_NOMONSTERS, world);
1762                                                         if(trace_startsolid || trace_fraction == 1)
1763                                                         {
1764                                                                 rint(42); // do an engine breakpoint on VM_rint so you can get the trace that errnoeously returns startsolid
1765                                                                 tracebox(start, PL_MIN, PL_MAX, end, MOVE_NOMONSTERS, world);
1766                                                                 tracebox(p, PL_MIN, PL_MAX, q, MOVE_NOMONSTERS, world);
1767
1768                                                                 if(trace_startsolid)
1769                                                                 {
1770                                                                         // how much do we need to back off?
1771                                                                         safe = 1;
1772                                                                         unsafe = 0;
1773                                                                         for(;;)
1774                                                                         {
1775                                                                                 pos = p * (1 - (safe + unsafe) * 0.5) + start * ((safe + unsafe) * 0.5);
1776                                                                                 tracebox(pos, PL_MIN, PL_MAX, pos, MOVE_NOMONSTERS, world);
1777                                                                                 if(trace_startsolid)
1778                                                                                 {
1779                                                                                         if((safe + unsafe) * 0.5 == unsafe)
1780                                                                                                 break;
1781                                                                                         unsafe = (safe + unsafe) * 0.5;
1782                                                                                 }
1783                                                                                 else
1784                                                                                 {
1785                                                                                         if((safe + unsafe) * 0.5 == safe)
1786                                                                                                 break;
1787                                                                                         safe = (safe + unsafe) * 0.5;
1788                                                                                 }
1789                                                                         }
1790
1791                                                                         print("safe distance to back off: ", ftos(safe * vlen(p - start)), "qu\n");
1792                                                                         print("unsafe distance to back off: ", ftos(unsafe * vlen(p - start)), "qu\n");
1793
1794                                                                         tracebox(p, PL_MIN + '0.1 0.1 0.1', PL_MAX - '0.1 0.1 0.1', p, MOVE_NOMONSTERS, world);
1795                                                                         if(trace_startsolid)
1796                                                                                 print("trace_endpos much in solid when tracing from ", vtos(start), " to ", vtos(end), " endpos ", vtos(p), "\n");
1797                                                                         else
1798                                                                                 print("trace_endpos just in solid when tracing from ", vtos(start), " to ", vtos(end), " endpos ", vtos(p), "\n");
1799                                                                         break;
1800                                                                 }
1801
1802                                                                 q0 = p;
1803                                                                 dq = 0;
1804                                                                 dqf = 1;
1805                                                                 for(;;)
1806                                                                 {
1807                                                                         q = p + normalize(end - p) * (dq + dqf);
1808                                                                         if(q == q0)
1809                                                                                 break;
1810                                                                         tracebox(p, PL_MIN, PL_MAX, q, MOVE_NOMONSTERS, world);
1811                                                                         if(trace_startsolid)
1812                                                                                 error("THIS ONE cannot happen");
1813                                                                         if(trace_fraction > 0)
1814                                                                                 dq += dqf * trace_fraction;
1815                                                                         dqf *= 0.5;
1816                                                                         q0 = q;
1817                                                                 }
1818                                                                 if(dq > 0)
1819                                                                 {
1820                                                                         print("trace_endpos still before solid when tracing from ", vtos(start), " to ", vtos(end), " endpos ", vtos(p), "\n");
1821                                                                         print("could go ", ftos(dq), " units further to ", vtos(q), "\n");
1822                                                                         break;
1823                                                                 }
1824                                                         }
1825                                                 }
1826                                         }
1827                                         return;
1828                                         
1829                                 case "debug2":
1830                                         e = nextent(world);
1831                                         tracebox(e.origin + '0 0 32', e.mins, e.maxs, e.origin + '0 0 -1024', MOVE_NORMAL, e);
1832                                         vv = trace_endpos;
1833                                         if(trace_fraction == 1)
1834                                         {
1835                                                 print("not above ground, aborting\n");
1836                                                 return;
1837                                         }
1838                                         f = 0;
1839                                         for(i = 0; i < 100000; ++i)
1840                                         {
1841                                                 dv = randomvec();
1842                                                 if(dv_z > 0)
1843                                                         dv = -1 * dv;
1844                                                 tracebox(vv, e.mins, e.maxs, vv + dv, MOVE_NORMAL, e);
1845                                                 if(trace_startsolid)
1846                                                         print("bug 1\n");
1847                                                 if(trace_fraction == 1)
1848                                                 if(dv_z < f)
1849                                                 {
1850                                                         print("bug 2: ", ftos(dv_x), " ", ftos(dv_y), " ", ftos(dv_z));
1851                                                         print(" (", ftos(asin(dv_z / vlen(dv)) * 180 / M_PI), " degrees)\n");
1852                                                         f = dv_z;
1853                                                 }
1854                                         }
1855                                         print("highest possible dist: ", ftos(f), "\n");
1856                                         return;
1857                                 
1858                                 case "walk":
1859                                         if(argc == 3)
1860                                         {
1861                                                 e = nextent(world);
1862                                                 if(tracewalk(e, stov(argv(1)), e.mins, e.maxs, stov(argv(2)), MOVE_NORMAL))
1863                                                         print("can walk\n");
1864                                                 else
1865                                                         print("cannot walk\n");
1866                                                 return;
1867                                         }
1868                                                 
1869                                 case "showline":
1870                                         if(argc == 3)
1871                                         {
1872                                                 vv = stov(argv(1));
1873                                                 dv = stov(argv(2));
1874                                                 traceline(vv, dv, MOVE_NORMAL, world);
1875                                                 trailparticles(world, particleeffectnum("TR_NEXUIZPLASMA"), vv, trace_endpos);
1876                                                 trailparticles(world, particleeffectnum("TR_CRYLINKPLASMA"), trace_endpos, dv);
1877                                                 return;
1878                                         }
1879                                 // no default case, just go straight to "invalid arguments"
1880                         }
1881                 }
1882                         
1883                 default:
1884                 case GC_REQUEST_USAGE:
1885                 {
1886                         print("\nUsage:^3 sv_cmd trace command [arguments]\n");
1887                         print("  FIXME: Arguments currently unknown\n");
1888                         return;
1889                 }
1890         }
1891 }
1892
1893 void GameCommand_unlockteams(float request)
1894 {
1895         switch(request)
1896         {
1897                 case GC_REQUEST_HELP:
1898                 {
1899                         print("  ^2unlockteams^7: Enable the ability for players to switch or enter teams\n");
1900                         return;
1901                 }
1902                         
1903                 case GC_REQUEST_COMMAND:
1904                 {
1905                         if(teamplay)
1906                         {
1907                                 lockteams = 0;
1908                                 bprint("^1The teams are now unlocked.\n");
1909                         }
1910                         else
1911                                 bprint("That command can only be used in a team-based gamemode.\n");
1912                         return;
1913                 }
1914                         
1915                 default:
1916                 case GC_REQUEST_USAGE:
1917                 {
1918                         print("\nUsage:^3 sv_cmd unlockteams\n");
1919                         print("  No arguments required.\n");
1920                         print("See also: ^2lockteams^7\n");
1921                         return;
1922                 }
1923         }
1924 }
1925
1926 void GameCommand_warp(float request, float argc)
1927 {
1928         switch (request)
1929         {
1930                 case GC_REQUEST_HELP:
1931                 {
1932                         print("  ^2warp^7: Choose different level in campaign\n");
1933                         return;
1934                 }
1935                 
1936                 case GC_REQUEST_COMMAND:
1937                 {
1938                         if(autocvar_g_campaign)
1939                         {
1940                                 
1941                                 if(argc >= 2)
1942                                 {
1943                                         CampaignLevelWarp(stof(argv(1)));
1944                                         print("Successfully warped to campaign level ", stof(argv(1)), ".\n");
1945                                 }       
1946                                 else
1947                                 {
1948                                         CampaignLevelWarp(-1);
1949                                         print("Successfully warped to next campaign level.\n");
1950                                 }
1951                         }
1952                         else
1953                                 print("Not in campaign, can't level warp\n");
1954                         return;
1955                 }
1956                 
1957                 default:
1958                 case GC_REQUEST_USAGE:
1959                 {
1960                         print("\nUsage:^3 sv_cmd level\n");
1961                         print("  'level' is the level to change campaign mode to.\n");
1962                         return;
1963                 }
1964         }
1965 }
1966
1967
1968 // ===========================
1969 //  Macro system for commands
1970 // ===========================
1971
1972 #define SERVER_COMMANDS(request,arguments) \
1973         SERVER_COMMAND("adminmsg", GameCommand_adminmsg(request, arguments)) \
1974         SERVER_COMMAND("allready", GameCommand_allready(request)) \
1975         SERVER_COMMAND("allspec", GameCommand_allspec(request, arguments)) \
1976         SERVER_COMMAND("anticheat", GameCommand_anticheat(request, arguments)) \
1977         SERVER_COMMAND("bbox", GameCommand_bbox(request)) \
1978         SERVER_COMMAND("bot_cmd", GameCommand_bot_cmd(request, arguments)) \
1979         SERVER_COMMAND("cointoss", GameCommand_cointoss(request, arguments)) \
1980         SERVER_COMMAND("cvar_changes", GameCommand_cvar_changes(request)) \
1981         SERVER_COMMAND("cvar_purechanges", GameCommand_cvar_purechanges(request)) \
1982         SERVER_COMMAND("database", GameCommand_database(request, arguments)) \
1983         SERVER_COMMAND("defer_clear", GameCommand_defer_clear(request, arguments)) \
1984         SERVER_COMMAND("defer_clear_all", GameCommand_defer_clear_all(request)) \
1985         SERVER_COMMAND("delrec", GameCommand_delrec(request, arguments)) \
1986         //SERVER_COMMAND("effectindexdump", GameCommand_effectindexdump(request)) \
1987         /* nothing */
1988         
1989 void GameCommand_macro_help()
1990 {
1991         #define SERVER_COMMAND(name,function) function;
1992         SERVER_COMMANDS(GC_REQUEST_HELP, 0)
1993         #undef SERVER_COMMAND
1994         
1995         return;
1996 }
1997
1998 float GameCommand_macro_command(float argc)
1999 {
2000         #define SERVER_COMMAND(name,function) if(name == strtolower(argv(0))) { function; return TRUE; } 
2001         SERVER_COMMANDS(GC_REQUEST_COMMAND, argc)
2002         #undef SERVER_COMMAND
2003         
2004         return FALSE;
2005 }
2006
2007 float GameCommand_macro_usage(float argc)
2008 {
2009         #define SERVER_COMMAND(name,function) if(name == strtolower(argv(1))) { function; return TRUE; }
2010         SERVER_COMMANDS(GC_REQUEST_USAGE, argc)
2011         #undef SERVER_COMMAND
2012         
2013         return FALSE;
2014 }
2015         
2016
2017 // =========================================
2018 //  Main Function Called By Engine (sv_cmd)
2019 // =========================================
2020 // If this function exists, game code handles gamecommand instead of the engine code.
2021
2022 void GameCommand(string command)
2023 {
2024         float argc = tokenize_console(command);
2025
2026         if(strtolower(argv(0)) == "help") 
2027         {
2028                 if(argc == 1) 
2029                 {
2030                         print("\nUsage:^3 sv_cmd COMMAND...^7, where possible commands are:\n");
2031                         GameCommand_macro_help();
2032                         GameCommand_Vote("help", world);
2033                         GameCommand_Ban("help");
2034                         GameCommand_Generic("help");
2035                         print("For help about specific commands, type sv_cmd help COMMAND\n");
2036                         return;
2037                 } 
2038                 else if(GameCommand_macro_usage(argc)) // Instead of trying to call a command, we're going to see detailed information about it
2039                 {
2040                         return;
2041                 }
2042         } 
2043         else if(GameCommand_Vote(command, world)) 
2044         {
2045                 return; // handled by server/vote.qc 
2046         }
2047         else if(GameCommand_Ban(command)) 
2048         {
2049                 return; // handled by server/ipban.qc
2050         }
2051         else if(GameCommand_Generic(command)) 
2052         {
2053                 return; // handled by common/gamecommand.qc
2054         }
2055         else if(GameCommand_macro_command(argc)) // continue as usual and scan for normal commands
2056         {
2057                 return; // handled by one of the above GameCommand_* functions
2058         }
2059         
2060         // nothing above caught the command, must be invalid
2061         //print("Invalid command. For a list of supported commands, try sv_cmd help.\n");
2062 }