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