Xonotic QuakeC
The free, fast arena FPS with crisp movement and a wide array of weapons
sv_cmd.qc
Go to the documentation of this file.
1#include "sv_cmd.qh"
2
3#include <common/constants.qh>
6#include <common/mapinfo.qh>
11#include <common/teams.qh>
12#include <common/util.qh>
13#include <server/anticheat.qh>
14#include <server/bot/api.qh>
15#include <server/campaign.qh>
16#include <server/client.qh>
19#include <server/command/cmd.qh>
24#include <server/ipban.qh>
26#include <server/player.qh>
28#include <server/teamplay.qh>
29#include <server/world.qh>
30
31// used by GameCommand_make_mapinfo()
33{
35 {
36 LOG_INFO("Done rebuiling mapinfos.");
38 delete(this);
39 }
40 else
41 {
43 this.nextthink = time;
44 }
45}
46
47// used by GameCommand_extendmatchtime() and GameCommand_reducematchtime()
48void changematchtime(float delta, float mi, float ma)
49{
50 float cur;
51 float update;
52 float lim;
53
54 if (delta == 0) return;
55 if (autocvar_timelimit < 0) return;
56
57 if (mi <= 10) mi = 10; // at least ten sec in the future
58 cur = time - game_starttime;
59 if (cur > 0) mi += cur; // from current time!
60
61 lim = autocvar_timelimit * 60;
62
63 if (delta > 0)
64 {
65 if (lim == 0) return; // cannot increase any further
66 else if (lim < ma) update = min(ma, lim + delta);
67 else // already above maximum: FAIL
68 return;
69 }
70 else
71 {
72 if (lim == 0) // infinite: try reducing to max, if we are allowed to
73 update = max(mi, ma);
74 else if (lim > mi) // above minimum: decrease
75 update = max(mi, lim + delta);
76 else // already below minimum: FAIL
77 return;
78 }
79
80 cvar_set("timelimit", ftos(update / 60));
81}
82
83
84// =======================
85// Command Sub-Functions
86// =======================
87
88void GameCommand_adminmsg(int request, int argc)
89{
90 switch (request)
91 {
93 {
95 {
96 LOG_HELPF("This command works only when the server is running.");
97 return;
98 }
99 entity client;
100 float accepted;
101
102 string targets = strreplace(",", " ", argv(1));
103 string original_targets = strreplace(" ", ", ", targets);
104 string admin_message = argv(2);
105 float infobartime = stof(argv(3));
106
107 string successful, t;
108 successful = string_null;
109
110 if ((targets) && (admin_message))
111 {
112 for ( ; targets; )
113 {
114 t = car(targets);
115 targets = cdr(targets);
116
117 // Check to see if the player is a valid target
118 client = GetFilteredEntity(t);
119 accepted = VerifyClientEntity(client, true, false);
120
121 if (accepted <= 0)
122 {
123 LOG_INFO("adminmsg: ", GetClientErrorString(accepted, t), (targets ? ", skipping to next player.\n" : "."));
124 continue;
125 }
126
127 // send the centerprint/console print or infomessage
128 if (infobartime)
129 {
130 stuffcmd(client, sprintf("\ninfobar %f \"%s\"\n", infobartime, MakeConsoleSafe(admin_message)));
131 }
132 else
133 {
134 centerprint(client, strcat("^3", GetCallerName(NULL), ":\n^7", admin_message));
135 sprint(client, strcat("\{1}\{13}^3", GetCallerName(NULL), "^7: ", admin_message, "\n"));
136 }
137
138 successful = strcat(successful, (successful ? ", " : ""), playername(client.netname, client.team, false));
139 LOG_TRACE("Message sent to ", playername(client.netname, client.team, false));
140 continue;
141 }
142
143 if (successful) bprint("Successfully sent message '", admin_message, "' to ", successful, ".\n");
144 else LOG_INFO("No players given (", original_targets, ") could receive the message.");
145
146 return;
147 }
148 }
149
150 default:
151 LOG_HELPF("Incorrect parameters for ^2%s^7", argv(0));
153 {
154 LOG_HELP("Usage:^3 sv_cmd adminmsg <clients> \"<message>\" [<infobartime>]");
155 LOG_HELP(" <clients> is a list (separated by commas) of player entity ID's or nicknames");
156 LOG_HELP(" If <infobartime> is provided, the message will be sent to infobar.");
157 LOG_HELP(" Otherwise, it will just be sent as a centerprint message.");
158 LOG_HELP("Examples: adminmsg 2,4 \"this infomessage will last for ten seconds\" 10");
159 LOG_HELP(" adminmsg 2,5 \"this message will be a centerprint\"");
160 return;
161 }
162 }
163}
164
165void GameCommand_allready(int request)
166{
167 switch (request)
168 {
170 {
172 {
173 LOG_HELPF("This command works only when the server is running.");
174 return;
175 }
176 if(warmup_stage)
177 {
178 ReadyRestart(true);
179 }
180 else
181 LOG_INFO("Not in warmup.");
182
183 return;
184 }
185
186 default:
188 {
189 LOG_HELP("Usage:^3 sv_cmd allready");
190 LOG_HELP(" No arguments required.");
191 return;
192 }
193 }
194}
195
196void GameCommand_allspec(int request, int argc)
197{
198 switch (request)
199 {
201 {
203 {
204 LOG_HELPF("This command works only when the server is running.");
205 return;
206 }
207 string reason = argv(1);
208 int n = 0;
210 PutObserverInServer(it, true, true);
211 ++n;
212 });
213 if (n)
214 bprint(strcat("Successfully forced all (", ftos(n), ") players to spectate",
215 (reason ? strcat(" for reason: '", reason, "'") : ""), ".\n"));
216 else
217 LOG_INFO("No players found to spectate.");
218 return;
219 }
220
221 default:
223 {
224 LOG_HELP("Usage:^3 sv_cmd allspec [<reason>]");
225 LOG_HELP(" Where <reason> is an optional argument for explanation of allspec command.");
226 LOG_HELP("See also: ^2moveplayer, shuffleteams^7");
227 return;
228 }
229 }
230}
231
232void GameCommand_anticheat(int request, int argc)
233{
234 switch (request)
235 {
237 {
239 {
240 LOG_HELPF("This command works only when the server is running.");
241 return;
242 }
243 entity client = GetIndexedEntity(argc, 1);
244 float accepted = VerifyClientEntity(client, false, false);
245
246 if (accepted > 0)
247 {
249 return;
250 }
251 else
252 {
253 LOG_INFO("anticheat: ", GetClientErrorString(accepted, argv(1)), ".");
254 }
255 }
256
257 default:
258 LOG_HELPF("Incorrect parameters for ^2%s^7", argv(0));
260 {
261 LOG_HELP("Usage:^3 sv_cmd anticheat <client>");
262 LOG_HELP(" <client> is the entity number or name of the player.");
263 return;
264 }
265 }
266}
267
268void GameCommand_bbox(int request)
269{
270 switch (request)
271 {
273 {
274 vector size_min = '0 0 0';
275 vector size_max = '0 0 0';
276 tracebox('1 0 0' * world.absmin.x,
277 '0 1 0' * world.absmin.y + '0 0 1' * world.absmin.z,
278 '0 1 0' * world.absmax.y + '0 0 1' * world.absmax.z,
279 '1 0 0' * world.absmax.x,
281 NULL);
282 size_min.x = (trace_startsolid) ? world.absmin.x : trace_endpos.x;
283
284 tracebox('0 1 0' * world.absmin.y,
285 '1 0 0' * world.absmin.x + '0 0 1' * world.absmin.z,
286 '1 0 0' * world.absmax.x + '0 0 1' * world.absmax.z,
287 '0 1 0' * world.absmax.y,
289 NULL);
290 size_min.y = (trace_startsolid) ? world.absmin.y : trace_endpos.y;
291
292 tracebox('0 0 1' * world.absmin.z,
293 '1 0 0' * world.absmin.x + '0 1 0' * world.absmin.y,
294 '1 0 0' * world.absmax.x + '0 1 0' * world.absmax.y,
295 '0 0 1' * world.absmax.z,
297 NULL);
298 size_min.z = (trace_startsolid) ? world.absmin.z : trace_endpos.z;
299
300 tracebox('1 0 0' * world.absmax.x,
301 '0 1 0' * world.absmin.y + '0 0 1' * world.absmin.z,
302 '0 1 0' * world.absmax.y + '0 0 1' * world.absmax.z,
303 '1 0 0' * world.absmin.x,
305 NULL);
306 size_max.x = (trace_startsolid) ? world.absmax.x : trace_endpos.x;
307
308 tracebox('0 1 0' * world.absmax.y,
309 '1 0 0' * world.absmin.x + '0 0 1' * world.absmin.z,
310 '1 0 0' * world.absmax.x + '0 0 1' * world.absmax.z,
311 '0 1 0' * world.absmin.y,
313 NULL);
314 size_max.y = (trace_startsolid) ? world.absmax.y : trace_endpos.y;
315
316 tracebox('0 0 1' * world.absmax.z,
317 '1 0 0' * world.absmin.x + '0 1 0' * world.absmin.y,
318 '1 0 0' * world.absmax.x + '0 1 0' * world.absmax.y,
319 '0 0 1' * world.absmin.z,
321 NULL);
322 size_max.z = (trace_startsolid) ? world.absmax.z : trace_endpos.z;
323
324 LOG_INFOF("Original size: %v %v", world.absmin, world.absmax);
325 LOG_INFOF("Currently set size: %v %v", world.mins, world.maxs);
326 LOG_INFOF("Solid bounding box size: %v %v", size_min, size_max);
327 return;
328 }
329
330 default:
332 {
333 LOG_HELP("Usage:^3 sv_cmd bbox");
334 LOG_HELP(" No arguments required.");
335 LOG_HELP("See also: ^2gettaginfo, trace^7");
336 return;
337 }
338 }
339}
340
341void GameCommand_bot_cmd(int request, int argc, string command)
342{
343 switch (request)
344 {
346 {
348 {
349 LOG_HELPF("This command works only when the server is running.");
350 return;
351 }
352 entity bot;
353
354 if (argv(1) == "reset")
355 {
357 return;
358 }
359 else if (argv(1) == "setbots")
360 {
361 cvar_settemp("bot_vs_human", "0");
362 cvar_settemp("minplayers", "0");
363 cvar_settemp("minplayers_per_team", "0");
364 cvar_settemp("bot_number", "0");
365 bot_fixcount(false); // Kill all bots.
366 cvar_settemp("bot_number", argv(2));
367 if (!bot_fixcount(true)) LOG_INFO("Sorry, could not set requested bot count");
368 return;
369 }
370 else if (argv(1) == "load" && argc == 3)
371 {
372 float fh, i;
373 string s;
374 fh = fopen(argv(2), FILE_READ);
375 if (fh < 0)
376 {
377 LOG_INFO("cannot open the file");
378 return;
379 }
380
381 i = 0;
382 while ((s = fgets(fh)))
383 {
384 argc = tokenize_console(s);
385
386 if (argc >= 3 && argv(0) == "sv_cmd" && argv(1) == "bot_cmd")
387 {
388 if (argv(2) == "reset")
389 {
391 }
392 else if (argv(2) == "setbots")
393 {
394 cvar_settemp("bot_vs_human", "0");
395 cvar_settemp("minplayers", "0");
396 cvar_settemp("minplayers_per_team", "0");
397 cvar_settemp("bot_number", "0");
398 bot_fixcount(false); // Kill all bots.
399 cvar_settemp("bot_number", argv(3));
400 if (!bot_fixcount(true)) LOG_INFO("Sorry, could not set requested bot count");
401 }
402 else
403 {
404 if(argv(2) == "*" || argv(2) == "all")
407 });
408 else
409 {
410 bot = find_bot_by_number(stof(argv(2)));
411 if (bot == NULL) bot = find_bot_by_name(argv(2));
412 if (bot) bot_queuecommand(bot, substring(s, argv_start_index(3), -1));
413 }
414 }
415 }
416 else
417 {
418 localcmd(strcat(s, "\n"));
419 }
420
421 ++i;
422 }
423 LOG_INFO(ftos(i), " commands read");
424 fclose(fh);
425 return;
426 }
427 else if (argv(1) == "help")
428 {
429 if (argv(2)) bot_cmdhelp(argv(2));
430 else bot_list_commands();
431 return;
432 }
433 else if (argc >= 3) // this comes last
434 {
435 if(argv(1) == "*" || argv(1) == "all")
436 {
437 int bot_num = 0;
439 bot_queuecommand(it, substring(command, argv_start_index(2), -1));
440 ++bot_num;
441 });
442 if(bot_num)
443 LOG_INFO("Command '", substring(command, argv_start_index(2), -1), "' sent to all bots (", ftos(bot_num), ")");
444 return;
445 }
446 else
447 {
448 bot = find_bot_by_number(stof(argv(1)));
449 if (bot == NULL) bot = find_bot_by_name(argv(1));
450 if (bot)
451 {
452 LOG_INFO("Command '", substring(command, argv_start_index(2), -1), "' sent to bot ", bot.netname);
453 bot_queuecommand(bot, substring(command, argv_start_index(2), -1));
454 return;
455 }
456 else
457 {
458 LOG_INFO("Error: Can't find bot with the name or id '", argv(1), "' - Did you mistype the command?"); // don't return so that usage is shown
459 }
460 }
461 }
462 }
463
464 default:
465 LOG_HELPF("Incorrect parameters for ^2%s^7", argv(0));
467 {
468 LOG_HELP("Usage:^3 sv_cmd bot_cmd <client> <command> [<arguments>]");
469 LOG_HELP(" <client> can be either the name of the bot or a progressive number (not the entity number!)");
470 LOG_HELP(" can also be '*' or 'all' to allow sending the command to all the bots");
471 LOG_HELP(" For full list of commands, see bot_cmd help [<command>].");
472 LOG_HELP("Examples: sv_cmd bot_cmd 1 cc say something");
473 LOG_HELP(" sv_cmd bot_cmd 1 presskey jump");
474 LOG_HELP(" sv_cmd bot_cmd * pause");
475 return;
476 }
477 }
478}
479
480void GameCommand_cointoss(int request, int argc)
481{
482 switch (request)
483 {
485 {
487 {
488 LOG_HELPF("This command works only when the server is running.");
489 return;
490 }
491 string result1 = (argv(2) ? strcat("^7", argv(1)) : "^1HEADS");
492 string result2 = (argv(2) ? strcat("^7", argv(2)) : "^4TAILS");
493 string choice = ((random() > 0.5) ? result1 : result2);
494
495 Send_Notification(NOTIF_ALL, NULL, MSG_MULTI, MULTI_COINTOSS, choice);
496 return;
497 }
498
499 default:
501 {
502 LOG_HELP("Usage:^3 sv_cmd cointoss [<result1> <result2>]");
503 LOG_HELP(" Where <result1> and <result2> are user created options.");
504 return;
505 }
506 }
507}
508
509void GameCommand_database(int request, int argc)
510{
511 switch (request)
512 {
514 {
515 if (argc == 3)
516 {
517 if (argv(1) == "save")
518 {
520 LOG_INFO("Copied serverprogs database to '", argv(2), "' in the data directory.");
521 return;
522 }
523 else if (argv(1) == "dump")
524 {
526 LOG_INFO("DB dumped."); // wtf does this do?
527 return;
528 }
529 else if (argv(1) == "load")
530 {
533 LOG_INFO("Loaded '", argv(2), "' as new serverprogs database.");
534 return;
535 }
536 }
537 }
538
539 default:
540 LOG_HELPF("Incorrect parameters for ^2%s^7", argv(0));
542 {
543 LOG_HELP("Usage:^3 sv_cmd database <action> <filename>");
544 LOG_HELP(" Where <action> is the command to complete,");
545 LOG_HELP(" and <filename> is what it acts upon.");
546 LOG_HELP(" Full list of commands here: save, dump, load.");
547 return;
548 }
549 }
550}
551
552void GameCommand_defer_clear(int request, int argc)
553{
554 switch (request)
555 {
557 {
559 {
560 LOG_HELPF("This command works only when the server is running.");
561 return;
562 }
563 entity client;
564 float accepted;
565
566 if (argc >= 2)
567 {
568 client = GetIndexedEntity(argc, 1);
569 accepted = VerifyClientEntity(client, true, false);
570
571 if (accepted > 0)
572 {
573 stuffcmd(client, "defer clear\n");
574 LOG_INFO("defer clear stuffed to ", playername(client.netname, client.team, false));
575 }
576 else { LOG_INFO("defer_clear: ", GetClientErrorString(accepted, argv(1)), "."); }
577
578 return;
579 }
580 }
581
582 default:
583 LOG_HELPF("Incorrect parameters for ^2%s^7", argv(0));
585 {
586 LOG_HELP("Usage:^3 sv_cmd defer_clear <client>");
587 LOG_HELP(" <client> is the entity number or name of the player.");
588 LOG_HELP("See also: ^2defer_clear_all^7");
589 return;
590 }
591 }
592}
593
595{
596 switch (request)
597 {
599 {
601 {
602 LOG_HELPF("This command works only when the server is running.");
603 return;
604 }
605 int n = 0;
606 int argc;
607
608 FOREACH_CLIENT(true, {
609 argc = tokenize_console(strcat("defer_clear ", ftos(etof(it))));
611 ++n;
612 });
613 if (n) LOG_INFO("Successfully stuffed defer clear to all clients (", ftos(n), ")"); // should a message be added if no players were found?
614 return;
615 }
616
617 default:
619 {
620 LOG_HELP("Usage:^3 sv_cmd defer_clear_all");
621 LOG_HELP(" No arguments required.");
622 LOG_HELP("See also: ^2defer_clear^7");
623 return;
624 }
625 }
626}
627
628void GameCommand_delrec(int request, int argc) // perhaps merge later with records and printstats and such?
629{
630 switch (request)
631 {
633 {
634 if (argv(1))
635 {
636 if (argv(2)) race_deleteTime(argv(2), stof(argv(1)));
637 else race_deleteTime(GetMapname(), stof(argv(1)));
638 return;
639 }
640 }
641
642 default:
643 LOG_HELPF("Incorrect parameters for ^2%s^7", argv(0));
645 {
646 LOG_HELP("Usage:^3 sv_cmd delrec <ranking> [<map>]");
647 LOG_HELP(" <ranking> is which ranking level to clear up to, ");
648 LOG_HELP(" it will clear all records up to nth place.");
649 LOG_HELP(" if <map> is not provided it will use current map.");
650 return;
651 }
652 }
653}
654
655void print_Effect_Index(int d, string effect_name)
656{
657 // this is inside a function to avoid expanding it on compilation everytime
658 LOG_INFO("effect ", effect_name, " is ", ftos(_particleeffectnum(effect_name)), "\n");
659 db_put(d, effect_name, "1");
660}
661
663{
664 switch (request)
665 {
667 {
668 float fh, d;
669 string s;
670
671 d = db_create();
672 LOG_INFO("begin of effects list");
673
674 print_Effect_Index(d, "TE_GUNSHOT");
675 print_Effect_Index(d, "TE_GUNSHOTQUAD");
676 print_Effect_Index(d, "TE_SPIKE");
677 print_Effect_Index(d, "TE_SPIKEQUAD");
678 print_Effect_Index(d, "TE_SUPERSPIKE");
679 print_Effect_Index(d, "TE_SUPERSPIKEQUAD");
680 print_Effect_Index(d, "TE_WIZSPIKE");
681 print_Effect_Index(d, "TE_KNIGHTSPIKE");
682 print_Effect_Index(d, "TE_EXPLOSION");
683 print_Effect_Index(d, "TE_EXPLOSIONQUAD");
684 print_Effect_Index(d, "TE_TAREXPLOSION");
685 print_Effect_Index(d, "TE_TELEPORT");
686 print_Effect_Index(d, "TE_LAVASPLASH");
687 print_Effect_Index(d, "TE_SMALLFLASH");
688 print_Effect_Index(d, "TE_FLAMEJET");
689 print_Effect_Index(d, "EF_FLAME");
690 print_Effect_Index(d, "TE_BLOOD");
691 print_Effect_Index(d, "TE_SPARK");
692 print_Effect_Index(d, "TE_PLASMABURN");
693 print_Effect_Index(d, "TE_TEI_G3");
694 print_Effect_Index(d, "TE_TEI_SMOKE");
695 print_Effect_Index(d, "TE_TEI_BIGEXPLOSION");
696 print_Effect_Index(d, "TE_TEI_PLASMAHIT");
697 print_Effect_Index(d, "EF_STARDUST");
698 print_Effect_Index(d, "TR_ROCKET");
699 print_Effect_Index(d, "TR_GRENADE");
700 print_Effect_Index(d, "TR_BLOOD");
701 print_Effect_Index(d, "TR_WIZSPIKE");
702 print_Effect_Index(d, "TR_SLIGHTBLOOD");
703 print_Effect_Index(d, "TR_KNIGHTSPIKE");
704 print_Effect_Index(d, "TR_VORESPIKE");
705 print_Effect_Index(d, "TR_NEHAHRASMOKE");
706 print_Effect_Index(d, "TR_NEXUIZPLASMA");
707 print_Effect_Index(d, "TR_GLOWTRAIL");
708 print_Effect_Index(d, "TR_SEEKER");
709 print_Effect_Index(d, "SVC_PARTICLE");
710
711 fh = fopen("effectinfo.txt", FILE_READ);
712 while ((s = fgets(fh)))
713 {
715 if (argv(0) == "effect")
716 {
717 if (db_get(d, argv(1)) != "1")
718 {
719 int i = _particleeffectnum(argv(1));
720 if (i >= 0) LOG_INFO("effect ", argv(1), " is ", ftos(i));
721 db_put(d, argv(1), "1");
722 }
723 }
724 }
725 LOG_INFO("end of effects list");
726
727 db_close(d);
728 return;
729 }
730
731 default:
733 {
734 LOG_HELP("Usage:^3 sv_cmd effectindexdump");
735 LOG_HELP(" No arguments required.");
736 return;
737 }
738 }
739}
740
742{
743 switch (request)
744 {
746 {
748 {
749 LOG_HELPF("This command works only when the server is running.");
750 return;
751 }
753 return;
754 }
755
756 default:
758 {
759 LOG_HELP("Usage:^3 sv_cmd extendmatchtime");
760 LOG_HELP(" No arguments required.");
761 LOG_HELP("See also: ^2reducematchtime^7");
762 return;
763 }
764 }
765}
766
767void GameCommand_gametype(int request, int argc)
768{
769 switch (request)
770 {
772 {
774 {
775 LOG_HELPF("This command works only when the server is running.");
776 return;
777 }
778 if (argv(1) != "")
779 {
780 string s = argv(1);
781 Gametype t = MapInfo_Type_FromString(s, false, false);
782
783 if (t)
784 {
785 // don't execute gametype hooks because they can change active
786 // gametype rules if executed during the game
787 GameTypeVote_SetGametype(t, "", false);
788 }
789 else
790 bprint("Failed to switch to ", s, ": this gametype does not exist!\n");
791
792 return;
793 }
794 }
795
796 default:
797 LOG_HELPF("Incorrect parameters for ^2%s^7", argv(0));
799 {
800 LOG_HELP("Usage:^3 sv_cmd gametype <mode>");
801 LOG_HELP(" Where <mode> is the gametype mode to switch to.");
802 LOG_HELP("See also: ^2gotomap^7");
803 return;
804 }
805 }
806}
807
808void GameCommand_gettaginfo(int request, int argc)
809{
810 switch (request)
811 {
813 {
814 entity tmp_entity;
815 float i;
816 vector v;
817
818 if (argc >= 4)
819 {
820 tmp_entity = spawn();
821 if (argv(1) == "w")
822 {
823 .entity weaponentity = weaponentities[0];
824 _setmodel(tmp_entity, (nextent(NULL)).(weaponentity).model);
825 }
826 else
827 {
828 precache_model(argv(1));
829 _setmodel(tmp_entity, argv(1));
830 }
831 tmp_entity.frame = stof(argv(2));
832 if (substring(argv(3), 0, 1) == "#") i = stof(substring(argv(3), 1, -1));
833 else i = gettagindex(tmp_entity, argv(3));
834 if (i)
835 {
836 v = gettaginfo(tmp_entity, i);
837 LOG_HELPF("model %s frame %s tag %s index %s parent %s",
838 tmp_entity.model, ftos(tmp_entity.frame), gettaginfo_name, ftos(i), ftos(gettaginfo_parent)
839 );
840 LOG_HELPF(" vector = %s %s %s", ftos(v.x), ftos(v.y), ftos(v.z));
844 LOG_HELPF(" up = %s %s %s", ftos(gettaginfo_up.x), ftos(gettaginfo_up.y), ftos(gettaginfo_up.z));
845 if (argc >= 6)
846 {
847 v.y = -v.y;
848 localcmd(strcat(argv(4), vtos(v), argv(5), "\n"));
849 }
850 }
851 else
852 {
853 LOG_INFO("bone not found");
854 }
855
856 delete(tmp_entity);
857 return;
858 }
859 }
860
861 default:
862 LOG_HELPF("Incorrect parameters for ^2%s^7", argv(0));
864 {
865 LOG_HELP("Usage:^3 sv_cmd gettaginfo <model> <frame> <index> [<command1>] [<command2>]");
866 LOG_HELP("See also: ^2bbox, trace^7");
867 return;
868 }
869 }
870}
871
872void GameCommand_animbench(int request, int argc)
873{
874 switch (request)
875 {
877 {
878 entity tmp_entity;
879
880 if (argc >= 4)
881 {
882 tmp_entity = spawn();
883 if (argv(1) == "w")
884 {
885 .entity weaponentity = weaponentities[0];
886 _setmodel(tmp_entity, (nextent(NULL)).(weaponentity).model);
887 }
888 else
889 {
890 precache_model(argv(1));
891 _setmodel(tmp_entity, argv(1));
892 }
893 float f1 = stof(argv(2));
894 float f2 = stof(argv(3));
895 float t0;
896 float t1 = 0;
897 float t2 = 0;
898 float n = 0;
899
900 while (t1 + t2 < 1)
901 {
902 tmp_entity.frame = f1;
904 getsurfacepoint(tmp_entity, 0, 0);
905 t1 += gettime(GETTIME_HIRES) - t0;
906 tmp_entity.frame = f2;
908 getsurfacepoint(tmp_entity, 0, 0);
909 t2 += gettime(GETTIME_HIRES) - t0;
910 ++n;
911 }
912 LOG_INFO("model ", tmp_entity.model, " frame ", ftos(f1), " animtime ", ftos(n / t1), "/s");
913 LOG_INFO("model ", tmp_entity.model, " frame ", ftos(f2), " animtime ", ftos(n / t2), "/s");
914
915 delete(tmp_entity);
916 return;
917 }
918 }
919
920 default:
921 LOG_HELPF("Incorrect parameters for ^2%s^7", argv(0));
923 {
924 LOG_HELP("Usage:^3 sv_cmd animbench <model> <frame1> <frame2>");
925 LOG_HELP("See also: ^2bbox, trace^7");
926 return;
927 }
928 }
929}
930
931void GameCommand_gotomap(int request, int argc)
932{
933 switch (request)
934 {
936 {
938 {
939 LOG_HELPF("This command works only when the server is running.");
940 return;
941 }
942 if (argv(1))
943 {
944 LOG_INFO(GotoMap(argv(1)));
945 return;
946 }
947 }
948
949 default:
950 LOG_HELPF("Incorrect parameters for ^2%s^7", argv(0));
952 {
953 LOG_HELP("Usage:^3 sv_cmd gotomap <map>");
954 LOG_HELP(" Where <map> is the *.bsp file to change to.");
955 LOG_HELP("See also: ^2gametype^7");
956 return;
957 }
958 }
959}
960
961void GameCommand_lockteams(int request)
962{
963 switch (request)
964 {
966 {
968 {
969 LOG_HELPF("This command works only when the server is running.");
970 return;
971 }
972 if (teamplay)
973 {
974 lockteams = 1;
975 Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_TEAMS_LOCKED);
976 // nobody can join or change teams now so remove everyone from the queue
977 FOREACH_CLIENT(it.wants_join, it.wants_join = it.team_selected = 0);
978 }
979 else
980 {
981 bprint("lockteams command can only be used in a team-based gametype.\n");
982 }
983 return;
984 }
985
986 default:
988 {
989 LOG_HELP("Usage:^3 sv_cmd lockteams");
990 LOG_HELP(" No arguments required.");
991 LOG_HELP("See also: ^2unlockteams^7");
992 return;
993 }
994 }
995}
996
998{
999 switch (request)
1000 {
1002 {
1003 entity tmp_entity = new(make_mapinfo);
1004 setthink(tmp_entity, make_mapinfo_Think);
1005 tmp_entity.nextthink = time;
1007 return;
1008 }
1009
1010 default:
1011 case CMD_REQUEST_USAGE:
1012 {
1013 LOG_HELP("Usage:^3 sv_cmd make_mapinfo");
1014 LOG_HELP(" No arguments required.");
1015 LOG_HELP("See also: ^2radarmap^7");
1016 return;
1017 }
1018 }
1019}
1020
1021void GameCommand_moveplayer(int request, int argc)
1022{
1023 switch (request)
1024 {
1026 {
1027 if (!world_initialized)
1028 {
1029 LOG_HELPF("This command works only when the server is running.");
1030 return;
1031 }
1032 float accepted;
1033 entity client;
1034
1035 string targets = strreplace(",", " ", argv(1));
1036 string original_targets = strreplace(" ", ", ", targets);
1037 string destination = argv(2);
1038 if (destination == "spec")
1039 destination = "spectator";
1040
1041 if ((targets) && (destination))
1042 {
1043 string successful = string_null;
1044 string t;
1045 for ( ; targets; )
1046 {
1047 t = car(targets);
1048 targets = cdr(targets);
1049
1050 // Check to see if the player is a valid target
1051 client = GetFilteredEntity(t);
1052 accepted = VerifyClientEntity(client, false, false);
1053 string client_num_str = ftos(etof(client));
1054
1055 if (accepted <= 0)
1056 {
1057 LOG_INFO("moveplayer: ", GetClientErrorString(accepted, t), ".");
1058 }
1059 else if (destination == "spectator")
1060 {
1061 string pl_name = playername(client.netname, client.team, false);
1062 if (!(IS_SPEC(client) || IS_OBSERVER(client)) || INGAME(client))
1063 {
1064 PutObserverInServer(client, true, true);
1065
1066 successful = strcat(successful, (successful ? ", " : ""), pl_name);
1067 }
1068 else
1069 {
1070 LOG_INFO("Player #", client_num_str, " (", pl_name, ") is already spectating.");
1071 }
1072 }
1073 else
1074 {
1075 if (!teamplay)
1076 {
1077 LOG_INFO("Can't change teams when currently not playing a team game.");
1078 return;
1079 }
1080
1081 string pl_name = playername(client.netname, client.team, false);
1082 if (IS_SPEC(client) || IS_OBSERVER(client))
1083 {
1084 // well technically we could, but should we allow that? :P
1085 LOG_INFO("Player #", client_num_str, " (", pl_name, ") is not in the game.");
1086 continue;
1087 }
1088
1089 // find the team to move the player to
1090 int team_num = Team_ColorToTeam(destination);
1091 entity balance;
1092 if (team_num == client.team) // already on the destination team
1093 {
1094 LOG_INFO("Player #", client_num_str, " (", pl_name, ") is already on the ",
1095 Team_ColoredFullName(team_num), ".");
1096 continue;
1097 }
1098 else if (team_num == 0) // auto team
1099 {
1100 balance = TeamBalance_CheckAllowedTeams(client);
1101 team_num = Team_IndexToTeam(TeamBalance_FindBestTeam(balance, client, false));
1102 }
1103 else
1104 {
1105 balance = TeamBalance_CheckAllowedTeams(client);
1106 }
1107
1108 // Check to see if the destination team is even available
1109 int team_id = Team_TeamToIndex(team_num);
1110 if (team_id == -1)
1111 {
1112 LOG_INFO("Can't move player to ", destination, " team because it doesn't exist.");
1113 TeamBalance_Destroy(balance);
1114 return;
1115 }
1116 if (!(teamplay_bitmask & Team_TeamToBit(team_num)))
1117 {
1118 LOG_INFO("Can't move player to ", destination, " team because it isn't available.");
1119 TeamBalance_Destroy(balance);
1120 return;
1121 }
1122 if (!TeamBalance_IsTeamAllowed(balance, team_id))
1123 {
1124 LOG_INFO("Player #", client_num_str, " (", pl_name, ") is not allowed to join the ",
1125 Team_ColoredFullName(team_num), ".");
1126 TeamBalance_Destroy(balance);
1127 continue;
1128 }
1129 TeamBalance_Destroy(balance);
1130
1131 // If so, lets continue and finally move the player
1132 if (MoveToTeam(client, team_id, 6))
1133 {
1134 successful = strcat(successful, (successful ? ", " : ""), pl_name);
1135 LOG_INFO("Player #", client_num_str, " (", pl_name, ") has been moved to the ",
1136 Team_ColoredFullName(team_num), ".");
1137 }
1138 else
1139 {
1140 LOG_INFO("Unable to move player #", client_num_str, " (", pl_name, ")");
1141 }
1142 }
1143 } // loop end
1144
1145 if (successful) bprint("Successfully moved players ", successful, " to destination ", destination, ".\n");
1146 else LOG_INFO("No players given (", original_targets, ") are able to move.");
1147
1148 return; // still correct parameters so return to avoid usage print
1149 }
1150 }
1151
1152 default:
1153 LOG_HELPF("Incorrect parameters for ^2%s^7", argv(0));
1154 case CMD_REQUEST_USAGE:
1155 {
1156 LOG_HELP("Usage:^3 sv_cmd moveplayer <clients> <destination>");
1157 LOG_HELP(" <clients> is a list (separated by commas) of player entity ID's or nicknames");
1158 LOG_HELP(" <destination> is what to send the player to, be it team or spectating");
1159 LOG_HELP(" Full list of destinations here: spec, spectator, red, blue, yellow, pink, auto.");
1160 LOG_HELP("Examples: sv_cmd moveplayer 1,3,5 red");
1161 LOG_HELP(" sv_cmd moveplayer 2 spec");
1162 LOG_HELP("See also: ^2allspec, shuffleteams^7");
1163 return;
1164 }
1165 }
1166}
1167
1168void GameCommand_nextmap(int request, int argc)
1169{
1170 switch (request)
1171 {
1173 {
1174 if (argc >= 2) // nextmap with mapname arg
1175 {
1176 if (argc > 2)
1177 LOG_HELP("Warning: nextmap only takes 1 argument");
1178
1179 string map = ValidateMap(argv(1), NULL);
1180 if (map != "" && map != get_nextmap())
1181 Set_NextMap(map);
1182 }
1183 else // nextmap without args
1184 {
1185 if (get_nextmap() != "")
1187 else
1188 LOG_HELP("none");
1189 }
1190 return; // never fall through to usage
1191 }
1192
1193 default:
1194 case CMD_REQUEST_USAGE:
1195 {
1196 LOG_HELP("Usage:^3 sv_cmd nextmap [<mapname>]");
1197 LOG_HELP(" Without arguments it prints current nextmap if one is set");
1198 LOG_HELP(" With arguments it attempts to set nextmap");
1199 return;
1200 }
1201 }
1202}
1203
1205{
1206 switch (request)
1207 {
1209 {
1210 if (!world_initialized)
1211 {
1212 LOG_HELPF("This command works only when the server is running.");
1213 return;
1214 }
1215 cvar_settemp("sv_spectate", "0");
1216 // if sv_spectate was enabled PlayerFrame() sends SPECTATE_WARNING notifications
1217 return;
1218 }
1219
1220 default:
1221 case CMD_REQUEST_USAGE:
1222 {
1223 LOG_HELP("Usage:^3 sv_cmd nospectators");
1224 LOG_HELP(" No arguments required.");
1225 LOG_HELP("Temporarily disables the ^3sv_spectate ^7cvar.");
1226 return;
1227 }
1228 }
1229}
1230
1231void GameCommand_printstats(int request)
1232{
1233 switch (request)
1234 {
1236 {
1237 if (!world_initialized)
1238 {
1239 LOG_HELPF("This command works only when the server is running.");
1240 return;
1241 }
1242 DumpStats(false);
1243 LOG_INFO("stats dumped.");
1244 return;
1245 }
1246
1247 default:
1248 case CMD_REQUEST_USAGE:
1249 {
1250 LOG_HELP("Usage:^3 sv_cmd printstats");
1251 LOG_HELP(" No arguments required.");
1252 return;
1253 }
1254 }
1255}
1256
1257void GameCommand_radarmap(int request, int argc)
1258{
1259 switch (request)
1260 {
1262 {
1263 if (RadarMap_Make(argc)) return;
1264 }
1265
1266 default:
1267 LOG_HELPF("Incorrect parameters for ^2%s^7", argv(0));
1268 case CMD_REQUEST_USAGE:
1269 {
1270 LOG_HELP("Usage:^3 sv_cmd radarmap [--force] [--loop] [--quit] [--block | --trace | --sample | --lineblock] [--sharpen N] [--res W H] [--qual Q]");
1271 LOG_HELP(" The quality factor Q is roughly proportional to the time taken.");
1272 LOG_HELP(" trace supports no quality factor; its result should look like --block with infinite quality factor.");
1273 LOG_HELP("See also: ^2make_mapinfo^7");
1274 return;
1275 }
1276 }
1277}
1278
1280{
1281 switch (request)
1282 {
1284 {
1285 if (!world_initialized)
1286 {
1287 LOG_HELPF("This command works only when the server is running.");
1288 return;
1289 }
1291 return;
1292 }
1293
1294 default:
1295 case CMD_REQUEST_USAGE:
1296 {
1297 LOG_HELP("Usage:^3 sv_cmd reducematchtime");
1298 LOG_HELP(" No arguments required.");
1299 LOG_HELP("See also: ^2extendmatchtime^7");
1300 return;
1301 }
1302 }
1303}
1304
1305void GameCommand_setbots(int request, int argc)
1306{
1307 switch (request)
1308 {
1310 {
1311 if (argc >= 2)
1312 {
1313 cvar_settemp("minplayers", "0");
1314 cvar_settemp("minplayers_per_team", "0");
1315 cvar_settemp("bot_number", argv(1));
1316 bot_fixcount(true);
1317 return;
1318 }
1319 }
1320
1321 default:
1322 LOG_HELPF("Incorrect parameters for ^2%s^7", argv(0));
1323 case CMD_REQUEST_USAGE:
1324 {
1325 LOG_HELP("Usage:^3 sv_cmd setbots <botnumber>");
1326 LOG_HELP(" Where <botnumber> is the amount of bots to set bot_number cvar to.");
1327 LOG_HELP("See also: ^2bot_cmd^7");
1328 return;
1329 }
1330 }
1331}
1332
1334{
1335 if (!teamplay)
1336 {
1337 LOG_INFO("Can't shuffle teams when currently not playing a team game.");
1338 return;
1339 }
1340
1341 FOREACH_CLIENT(IS_PLAYER(it) || INGAME(it), {
1342 if (Player_HasRealForcedTeam(it)) {
1343 // we could theoretically assign forced players to their teams
1344 // and shuffle the rest to fill the empty spots but in practise
1345 // either all players or none are gonna have forced teams
1346 LOG_INFO("Can't shuffle teams because at least one player has a forced team.");
1347 return;
1348 }
1349 });
1350
1351 int number_of_teams = 0;
1353 for (int i = 1; i <= AVAILABLE_TEAMS; ++i)
1354 {
1355 if (TeamBalance_IsTeamAllowed(balance, i))
1356 {
1357 number_of_teams = max(i, number_of_teams);
1358 }
1359 }
1360 TeamBalance_Destroy(balance);
1361
1362 int team_index = 0;
1364 int target_team_index = team_index + 1;
1365 if (Entity_GetTeamIndex(it) != target_team_index)
1366 {
1367 MoveToTeam(it, target_team_index, 6);
1368 }
1369 team_index = (team_index + 1) % number_of_teams;
1370 });
1371
1372 bprint("Successfully shuffled the players around randomly.\n");
1373}
1374
1376{
1377 switch (request)
1378 {
1380 {
1381 if (!world_initialized)
1382 {
1383 LOG_HELPF("This command works only when the server is running.");
1384 return;
1385 }
1387 {
1388 bprint("Players will be shuffled when this round is over.\n");
1390 }
1391 else
1392 shuffleteams();
1393 return;
1394 }
1395
1396 default:
1397 case CMD_REQUEST_USAGE:
1398 {
1399 LOG_HELP("Usage:^3 sv_cmd shuffleteams");
1400 LOG_HELP(" No arguments required.");
1401 LOG_HELP("See also: ^2moveplayer, allspec^7");
1402 return;
1403 }
1404 }
1405}
1406
1407void GameCommand_resetmatch(int request)
1408{
1409 switch (request)
1410 {
1412 {
1413 if (!world_initialized)
1414 {
1415 LOG_HELPF("This command works only when the server is running.");
1416 return;
1417 }
1418 ReadyRestart(false);
1419 return;
1420 }
1421
1422 default:
1423 case CMD_REQUEST_USAGE:
1424 {
1425 LOG_HELP("Usage:^3 sv_cmd resetmatch");
1426 LOG_HELP(" No arguments required.");
1427 return;
1428 }
1429 }
1430}
1431
1432void GameCommand_stuffto(int request, int argc)
1433{
1434 // This... is a fairly dangerous and powerful command... - It allows any arguments to be sent to a client via rcon.
1435 // Because of this, it is disabled by default and must be enabled by the server owner when doing compilation. That way,
1436 // we can be certain they understand the risks of it... So to enable, compile server with -DSTUFFTO_ENABLED argument.
1437
1438#ifdef STUFFTO_ENABLED
1439 switch (request)
1440 {
1442 {
1443 if (!world_initialized)
1444 {
1445 LOG_HELPF("This command works only when the server is running.");
1446 return;
1447 }
1448 if (argv(2))
1449 {
1450 entity client = GetIndexedEntity(argc, 1);
1451 float accepted = VerifyClientEntity(client, true, false);
1452
1453 if (accepted > 0)
1454 {
1455 stuffcmd(client, strcat("\n", argv(next_token), "\n"));
1456 LOG_INFO("Command: \"", argv(next_token), "\" sent to ", GetCallerName(client), " (", argv(1), ").");
1457 }
1458 else
1459 {
1460 LOG_INFO("stuffto: ", GetClientErrorString(accepted, argv(1)), ".");
1461 }
1462
1463 return;
1464 }
1465 }
1466
1467 default:
1468 LOG_HELPF("Incorrect parameters for ^2%s^7", argv(0));
1469 case CMD_REQUEST_USAGE:
1470 {
1471 LOG_HELP("Usage:^3 sv_cmd stuffto <client> \"<command>\"");
1472 LOG_HELP(" <client> is the entity number or name of the player,");
1473 LOG_HELP(" and <command> is the command to be sent to that player.");
1474 return;
1475 }
1476 }
1477#else
1478 if (request)
1479 {
1480 LOG_HELP("stuffto command is not enabled on this server.");
1481 return;
1482 }
1483#endif
1484}
1485
1486void GameCommand_trace(int request, int argc)
1487{
1488 switch (request)
1489 {
1491 {
1492 entity e;
1493 vector org, delta, start, end, p, q, q0, pos, vv, dv;
1494 float i, f, safe, unsafe, dq, dqf;
1495
1496 switch (argv(1))
1497 {
1498 case "debug":
1499 {
1500 float hitcount = 0;
1501 LOG_INFO("TEST CASE. If this returns the runaway loop counter error, possibly everything is oaky.");
1502 float worst_endpos_bug = 0;
1503 for ( ; ; )
1504 {
1505 org = world.mins;
1506 delta = world.maxs - world.mins;
1507
1508 start.x = org.x + random() * delta.x;
1509 start.y = org.y + random() * delta.y;
1510 start.z = org.z + random() * delta.z;
1511
1512 end.x = org.x + random() * delta.x;
1513 end.y = org.y + random() * delta.y;
1514 end.z = org.z + random() * delta.z;
1515
1516 start = stov(vtos(start));
1517 end = stov(vtos(end));
1518
1519 tracebox(start, PL_MIN_CONST, PL_MAX_CONST, end, MOVE_NOMONSTERS, NULL);
1520 if (!trace_startsolid && trace_fraction < 1)
1521 {
1522 p = trace_endpos;
1523 tracebox(p, PL_MIN_CONST, PL_MAX_CONST, p, MOVE_NOMONSTERS, NULL);
1524 if (trace_startsolid)
1525 {
1526 rint(42); // do an engine breakpoint on VM_rint so you can get the trace that errnoeously returns startsolid
1527 tracebox(start, PL_MIN_CONST, PL_MAX_CONST, end, MOVE_NOMONSTERS, NULL);
1528
1529 // how much do we need to back off?
1530 safe = 1;
1531 unsafe = 0;
1532 for ( ; ; )
1533 {
1534 pos = p * (1 - (safe + unsafe) * 0.5) + start * ((safe + unsafe) * 0.5);
1535 tracebox(pos, PL_MIN_CONST, PL_MAX_CONST, pos, MOVE_NOMONSTERS, NULL);
1536 if (trace_startsolid)
1537 {
1538 if ((safe + unsafe) * 0.5 == unsafe) break;
1539 unsafe = (safe + unsafe) * 0.5;
1540 }
1541 else
1542 {
1543 if ((safe + unsafe) * 0.5 == safe) break;
1544 safe = (safe + unsafe) * 0.5;
1545 }
1546 }
1547
1548 LOG_INFO("safe distance to back off: ", ftos(safe * vlen(p - start)), "qu");
1549 LOG_INFO("unsafe distance to back off: ", ftos(unsafe * vlen(p - start)), "qu");
1550
1551 tracebox(p, PL_MIN_CONST + '0.1 0.1 0.1', PL_MAX_CONST - '0.1 0.1 0.1', p, MOVE_NOMONSTERS, NULL);
1552 if (trace_startsolid) LOG_INFO("trace_endpos much in solid when tracing from ", vtos(start), " to ", vtos(end), " endpos ", vtos(p));
1553 else LOG_INFO("trace_endpos just in solid when tracing from ", vtos(start), " to ", vtos(end), " endpos ", vtos(p));
1554 if (++hitcount >= 10) break;
1555 }
1556 else
1557 {
1558 q0 = p;
1559 dq = 0;
1560 dqf = 1;
1561 for ( ; ; )
1562 {
1563 q = p + normalize(end - p) * (dq + dqf);
1564 if (q == q0) break;
1565 tracebox(p, PL_MIN_CONST, PL_MAX_CONST, q, MOVE_NOMONSTERS, NULL);
1566 if (trace_startsolid) error("THIS ONE cannot happen");
1567 if (trace_fraction > 0) dq += dqf * trace_fraction;
1568 dqf *= 0.5;
1569 q0 = q;
1570 }
1571 if (dq > worst_endpos_bug)
1572 {
1573 worst_endpos_bug = dq;
1574 LOG_INFO("trace_endpos still before solid when tracing from ", vtos(start), " to ", vtos(end), " endpos ", vtos(p));
1575 LOG_INFO("could go ", ftos(dq), " units further to ", vtos(q));
1576 if (++hitcount >= 10) break;
1577 }
1578 }
1579 }
1580 }
1581 return;
1582 }
1583
1584 case "debug2":
1585 {
1586 e = nextent(NULL);
1587 tracebox(e.origin + '0 0 32', e.mins, e.maxs, e.origin + '0 0 -1024', MOVE_NORMAL, e);
1588 vv = trace_endpos;
1589 if (trace_fraction == 1)
1590 {
1591 LOG_INFO("not above ground, aborting");
1592 return;
1593 }
1594 f = 0;
1595 for (i = 0; i < 100000; ++i)
1596 {
1597 dv = randomvec();
1598 if (dv.z > 0) dv = -1 * dv;
1599 tracebox(vv, e.mins, e.maxs, vv + dv, MOVE_NORMAL, e);
1600 if (trace_startsolid) LOG_INFO("bug 1");
1601 if (trace_fraction == 1)
1602 {
1603 if (dv.z < f)
1604 {
1605 LOG_INFO("bug 2: ", ftos(dv.x), " ", ftos(dv.y), " ", ftos(dv.z));
1606 LOG_INFO(" (", ftos(asin(dv.z / vlen(dv)) * 180 / M_PI), " degrees)");
1607 f = dv.z;
1608 }
1609 }
1610 }
1611 LOG_INFO("highest possible dist: ", ftos(f));
1612 return;
1613 }
1614
1615 case "walk":
1616 {
1617 if (argc == 4 || argc == 5)
1618 {
1619 e = nextent(NULL);
1620 int dphitcontentsmask_save = e.dphitcontentsmask;
1622 if (tracewalk(e, stov(argv(2)), e.mins, e.maxs, stov(argv(3)), stof(argv(4)), MOVE_NORMAL))
1623 LOG_INFO("can walk");
1624 else
1625 LOG_INFO("cannot walk");
1626 e.dphitcontentsmask = dphitcontentsmask_save;
1627 return;
1628 }
1629 }
1630
1631 case "showline":
1632 {
1633 if (argc == 4)
1634 {
1635 vv = stov(argv(2));
1636 dv = stov(argv(3));
1637 traceline(vv, dv, MOVE_NORMAL, NULL);
1638 __trailparticles(NULL, particleeffectnum(EFFECT_TR_NEXUIZPLASMA), vv, trace_endpos);
1639 __trailparticles(NULL, particleeffectnum(EFFECT_TR_CRYLINKPLASMA), trace_endpos, dv);
1640 return;
1641 }
1642 }
1643
1644 // no default case, just go straight to invalid
1645 }
1646 }
1647
1648 default:
1649 LOG_HELPF("Incorrect parameters for ^2%s^7", argv(0));
1650 case CMD_REQUEST_USAGE:
1651 {
1652 LOG_HELP("Usage:^3 sv_cmd trace <command> [<startpos> <endpos>] [<endpos_height>]");
1653 LOG_HELP(" Where <startpos> and <endpos> are parameters for the 'walk' and 'showline' commands,");
1654 LOG_HELP(" <endpos_height> is an optional parameter for the 'walk' command,");
1655 LOG_HELP(" Full list of commands here: debug, debug2, walk, showline.");
1656 LOG_HELP("See also: ^2bbox, gettaginfo^7");
1657 return;
1658 }
1659 }
1660}
1661
1663{
1664 switch (request)
1665 {
1667 {
1668 if (!world_initialized)
1669 {
1670 LOG_HELPF("This command works only when the server is running.");
1671 return;
1672 }
1673 if (teamplay)
1674 {
1675 lockteams = 0;
1676 Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_TEAMS_UNLOCKED);
1677 }
1678 else
1679 {
1680 bprint("unlockteams command can only be used in a team-based gametype.\n");
1681 }
1682 return;
1683 }
1684
1685 default:
1686 case CMD_REQUEST_USAGE:
1687 {
1688 LOG_HELP("Usage:^3 sv_cmd unlockteams");
1689 LOG_HELP(" No arguments required.");
1690 LOG_HELP("See also: ^2lockteams^7");
1691 return;
1692 }
1693 }
1694}
1695
1696void GameCommand_warp(int request, int argc)
1697{
1698 switch (request)
1699 {
1701 {
1702 if (!world_initialized)
1703 {
1704 LOG_HELPF("This command works only when the server is running.");
1705 return;
1706 }
1708 {
1709 if (argc >= 2)
1710 {
1712 LOG_INFO("Successfully warped to campaign level ", argv(1), ".");
1713 }
1714 else
1715 {
1717 LOG_INFO("Successfully warped to next campaign level.");
1718 }
1719 }
1720 else
1721 {
1722 LOG_INFO("Not in campaign, can't level warp");
1723 }
1724 return;
1725 }
1726
1727 default:
1728 case CMD_REQUEST_USAGE:
1729 {
1730 LOG_HELP("Usage:^3 sv_cmd warp [<level>]");
1731 LOG_HELP(" <level> is the level to change campaign mode to.");
1732 LOG_HELP(" if <level> is not provided it will change to the next level.");
1733 return;
1734 }
1735 }
1736}
1737
1738/* use this when creating a new command, making sure to place it in alphabetical order... also,
1739** ADD ALL NEW COMMANDS TO commands.cfg WITH PROPER ALIASES IN THE SAME FASHION!
1740void GameCommand_(int request)
1741{
1742 switch(request)
1743 {
1744 case CMD_REQUEST_COMMAND:
1745 {
1746 if (!world_initialized)
1747 {
1748 LOG_HELPF("This command works only when the server is running.");
1749 return;
1750 }
1751
1752 return;
1753 }
1754
1755 default:
1756 case CMD_REQUEST_USAGE:
1757 {
1758 LOG_HELP("Usage:^3 sv_cmd ");
1759 LOG_HELP(" No arguments required.");
1760 return;
1761 }
1762 }
1763}
1764*/
1765
1766
1767// ==================================
1768// Macro system for server commands
1769// ==================================
1770
1771// Do not hard code aliases for these, instead create them in commands.cfg... also: keep in alphabetical order, please ;)
1772SERVER_COMMAND(adminmsg, "Send an admin message to a client directly") { GameCommand_adminmsg(request, arguments); }
1773SERVER_COMMAND(allready, "Ends warmup and starts the match") { GameCommand_allready(request); }
1774SERVER_COMMAND(allspec, "Force all players to spectate") { GameCommand_allspec(request, arguments); }
1775SERVER_COMMAND(anticheat, "Create an anticheat report for a client") { GameCommand_anticheat(request, arguments); }
1776SERVER_COMMAND(animbench, "Benchmark model animation (LAGS)") { GameCommand_animbench(request, arguments); }
1777SERVER_COMMAND(bbox, "Print detailed information about world size") { GameCommand_bbox(request); }
1778SERVER_COMMAND(bot_cmd, "Control and send commands to bots") { GameCommand_bot_cmd(request, arguments, command); }
1779SERVER_COMMAND(cointoss, "Flip a virtual coin and give random result") { GameCommand_cointoss(request, arguments); }
1780SERVER_COMMAND(database, "Extra controls of the serverprogs database") { GameCommand_database(request, arguments); }
1781SERVER_COMMAND(defer_clear, "Clear all queued defer commands for a specific client") { GameCommand_defer_clear(request, arguments); }
1782SERVER_COMMAND(defer_clear_all, "Clear all queued defer commands for all clients") { GameCommand_defer_clear_all(request); }
1783SERVER_COMMAND(delrec, "Delete race time record for a map") { GameCommand_delrec(request, arguments); }
1784SERVER_COMMAND(effectindexdump, "Dump list of effects from code and effectinfo.txt") { GameCommand_effectindexdump(request); }
1785SERVER_COMMAND(extendmatchtime, "Increase the timelimit value incrementally") { GameCommand_extendmatchtime(request); }
1786SERVER_COMMAND(gametype, "Simple command to change the active gametype") { GameCommand_gametype(request, arguments); }
1787SERVER_COMMAND(gettaginfo, "Get specific information about a weapon model") { GameCommand_gettaginfo(request, arguments); }
1788SERVER_COMMAND(gotomap, "Simple command to switch to another map") { GameCommand_gotomap(request, arguments); }
1789SERVER_COMMAND(lockteams, "Disable the ability for players to switch or enter teams") { GameCommand_lockteams(request); }
1790SERVER_COMMAND(make_mapinfo, "Automatically rebuild mapinfo files") { GameCommand_make_mapinfo(request); }
1791SERVER_COMMAND(moveplayer, "Change the team/status of a player") { GameCommand_moveplayer(request, arguments); }
1792SERVER_COMMAND(nextmap, "Set/Query the next map") { GameCommand_nextmap(request, arguments); }
1793SERVER_COMMAND(nospectators, "Automatically remove spectators from a match") { GameCommand_nospectators(request); }
1794SERVER_COMMAND(printstats, "Dump eventlog player stats and other score information") { GameCommand_printstats(request); }
1795SERVER_COMMAND(radarmap, "Generate a radar image of the map") { GameCommand_radarmap(request, arguments); }
1796SERVER_COMMAND(reducematchtime, "Decrease the timelimit value incrementally") { GameCommand_reducematchtime(request); }
1797SERVER_COMMAND(resetmatch, "Soft restart the game without changing teams; goes back to warmup if enabled") { GameCommand_resetmatch(request); }
1798SERVER_COMMAND(setbots, "Adjust how many bots are in the match") { GameCommand_setbots(request, arguments); }
1799SERVER_COMMAND(shuffleteams, "Randomly move players to different teams") { GameCommand_shuffleteams(request); }
1800SERVER_COMMAND(stuffto, "Send a command to be executed on a client") { GameCommand_stuffto(request, arguments); }
1801SERVER_COMMAND(trace, "Various debugging tools with tracing") { GameCommand_trace(request, arguments); }
1802SERVER_COMMAND(unlockteams, "Enable the ability for players to switch or enter teams") { GameCommand_unlockteams(request); }
1803SERVER_COMMAND(warp, "Choose different level in campaign") { GameCommand_warp(request, arguments); }
1804
1806{
1807 FOREACH(SERVER_COMMANDS, true, { LOG_HELPF(" ^2%s^7: %s", it.m_name, it.m_description); });
1808}
1809
1810float GameCommand_macro_command(int argc, string command)
1811{
1812 string c = strtolower(argv(0));
1813 FOREACH(SERVER_COMMANDS, it.m_name == c, {
1814 it.m_invokecmd(it, CMD_REQUEST_COMMAND, NULL, argc, command);
1815 return true;
1816 });
1817 return false;
1818}
1819
1821{
1822 string c = strtolower(argv(1));
1823 FOREACH(SERVER_COMMANDS, it.m_name == c, {
1824 it.m_invokecmd(it, CMD_REQUEST_USAGE, NULL, argc, "");
1825 return true;
1826 });
1827 return false;
1828}
1829
1831{
1832 FOREACH(SERVER_COMMANDS, true, { CMD_Write_Alias("qc_cmd_sv", it.m_name, it.m_description); });
1833}
1834
1835
1836// =========================================
1837// Main Function Called By Engine (sv_cmd)
1838// =========================================
1839// If this function exists, game code handles gamecommand instead of the engine code.
1840
1841void GameCommand(string command)
1842{
1843 int argc = tokenize_console(command);
1844
1845 // Guide for working with argc arguments by example:
1846 // argc: 1 - 2 - 3 - 4
1847 // argv: 0 - 1 - 2 - 3
1848 // cmd vote - master - login - password
1849
1850 if (strtolower(argv(0)) == "help")
1851 {
1852 if (argc == 1)
1853 {
1854 LOG_HELP("Server console commands:");
1856
1857 LOG_HELP("\nBanning commands:");
1859
1860 LOG_HELP("\nCommon networked commands:");
1862
1863 LOG_HELP("\nGeneric commands shared by all programs:");
1865
1866 LOG_HELP("\nUsage:^3 sv_cmd <command>^7, where possible commands are listed above.\n"
1867 "For help about a specific command, type sv_cmd help <command>");
1868
1869 return;
1870 }
1871 else if (BanCommand_macro_usage(argc)) // Instead of trying to call a command, we're going to see detailed information about it
1872 {
1873 return;
1874 }
1875 else if (CommonCommand_macro_usage(argc, NULL)) // same here, but for common commands instead
1876 {
1877 return;
1878 }
1879 else if (GenericCommand_macro_usage(argc)) // same here, but for generic commands instead
1880 {
1881 return;
1882 }
1883 else if (GameCommand_macro_usage(argc)) // finally try for normal commands too
1884 {
1885 return;
1886 }
1887 }
1888 else if (MUTATOR_CALLHOOK(SV_ParseServerCommand, strtolower(argv(0)), argc, command))
1889 {
1890 return; // handled by a mutator
1891 }
1892 else if (BanCommand(command))
1893 {
1894 return; // handled by server/command/ipban.qc
1895 }
1896 else if (CommonCommand_macro_command(argc, NULL, command))
1897 {
1898 return; // handled by server/command/common.qc
1899 }
1900 else if (GenericCommand(command))
1901 {
1902 return; // handled by common/command/generic.qc
1903 }
1904 else if (GameCommand_macro_command(argc, command)) // continue as usual and scan for normal commands
1905 {
1906 return; // handled by one of the above GameCommand_* functions
1907 }
1908
1909 // nothing above caught the command, must be invalid
1910 LOG_INFO(((command != "") ? strcat("Unknown server command \"", command, "\"") : "No command provided"), ". For a list of supported commands, try sv_cmd help.");
1911}
void bot_resetqueues()
entity find_bot_by_number(float number)
Definition scripting.qc:246
bool bot_fixcount(bool multiple_per_frame)
Definition bot.qc:623
entity find_bot_by_name(string name)
Definition scripting.qc:235
void bot_queuecommand(entity bot, string cmdstring)
Definition scripting.qc:30
void bot_cmdhelp(string scmd)
Definition scripting.qc:331
bool tracewalk(entity e, vector start, vector m1, vector m2, vector end, float end_height, float movemode)
void bot_list_commands()
Definition scripting.qc:444
void BanCommand_macro_help()
Definition banning.qc:480
float BanCommand_macro_usage(int argc)
Definition banning.qc:500
float BanCommand(string command)
Definition banning.qc:520
#define MUTATOR_CALLHOOK(id,...)
Definition base.qh:143
var entity(vector mins, vector maxs,.entity tofield) findbox_tofield_OrFallback
bool warmup_stage
Definition main.qh:120
entity gametype
Definition main.qh:43
const int CMD_REQUEST_COMMAND
Definition command.qh:3
const int CMD_REQUEST_USAGE
Definition command.qh:4
#define IS_PLAYER(s)
Definition player.qh:242
#define autocvar_timelimit
Definition stats.qh:92
float game_starttime
Definition stats.qh:82
string playername(string thename, int teamid, bool team_colorize)
Definition util.qc:2190
float cvar_settemp(string tmp_cvar, string tmp_value)
Definition util.qc:819
string strtolower(string s)
const vector PL_MIN_CONST
Definition constants.qh:53
const vector PL_MAX_CONST
Definition constants.qh:52
const float MOVE_NOMONSTERS
float DPCONTENTS_BOTCLIP
float GETTIME_HIRES
float gettaginfo_parent
float DPCONTENTS_SOLID
const float MOVE_NORMAL
float DPCONTENTS_BODY
vector gettaginfo_forward
string gettaginfo_name
const float FILE_READ
float DPCONTENTS_PLAYERCLIP
float time
vector trace_endpos
float trace_startsolid
float nextthink
float MOVE_WORLDONLY
vector gettaginfo_right
vector gettaginfo_up
float trace_fraction
vector gettaginfo_offset
#define spawn
ERASEABLE string MakeConsoleSafe(string input)
Escape the string to make it safe for consoles.
Definition cvar.qh:24
#define gettagindex
#define tokenize_console
#define argv_start_index
#define particleeffectnum(e)
Definition effect.qh:3
model
Definition ent_cs.qc:164
float GenericCommand_macro_usage(int argc)
Definition generic.qc:582
void GenericCommand_macro_help()
Definition generic.qc:567
float GenericCommand(string command)
Definition generic.qc:603
#define CMD_Write_Alias(execute, command, description)
Definition generic.qh:34
void Set_NextMap(string mapname)
string GetMapname()
string GotoMap(string m)
#define get_nextmap()
#define FOREACH(list, cond, body)
Definition iter.qh:19
#define LOG_HELP(...)
Definition log.qh:83
#define LOG_INFO(...)
Definition log.qh:62
#define LOG_TRACE(...)
Definition log.qh:74
#define LOG_HELPF(...)
Definition log.qh:84
#define LOG_INFOF(...)
Definition log.qh:63
ERASEABLE void db_close(int db)
Definition map.qh:86
ERASEABLE int db_load(string filename)
Definition map.qh:35
ERASEABLE int db_create()
Definition map.qh:25
ERASEABLE void db_save(int db, string filename)
Definition map.qh:8
ERASEABLE string db_get(int db, string key)
Definition map.qh:93
ERASEABLE void db_put(int db, string key, string value)
Definition map.qh:103
ERASEABLE void db_dump(int db, string filename)
Definition map.qh:70
float MapInfo_FilterGametype(Gametype pGametype, int pFeatures, int pFlagsRequired, int pFlagsForbidden, bool pAbortOnGenerate)
Definition mapinfo.qc:176
int MapInfo_RequiredFlags()
Definition mapinfo.qc:1670
float _MapInfo_FilterGametype(vector pGametype, int pFeatures, int pFlagsRequired, int pFlagsForbidden, bool pAbortOnGenerate)
Definition mapinfo.qc:180
Gametype MapInfo_CurrentGametype()
Definition mapinfo.qc:1482
int MapInfo_ForbiddenFlags()
Definition mapinfo.qc:1655
int MapInfo_CurrentFeatures()
Definition mapinfo.qc:1472
Gametype MapInfo_Type_FromString(string gtype, bool dowarn, bool is_q3compat)
Definition mapinfo.qc:620
void MapInfo_Enumerate()
Definition mapinfo.qc:134
vector MAPINFO_TYPE_ALL
Definition mapinfo.qh:27
#define M_PI
pi
Definition mathlib.qh:114
bool autocvar_g_campaign
Definition menu.qc:752
void localcmd(string command,...)
void cvar_set(string name, string value)
string fgets(float fhandle)
void fclose(float fhandle)
float stof(string val,...)
entity nextent(entity e)
string substring(string s, float start, float length)
void sprint(float clientnum, string text,...)
float fopen(string filename, float mode)
float gettime(void)
vector stov(string s)
float random(void)
void bprint(string text,...)
float vlen(vector v)
vector randomvec(void)
void centerprint(string text,...)
string vtos(vector v)
float min(float f,...)
float rint(float f)
vector normalize(vector v)
string ftos(float f)
string argv(float n)
float max(float f,...)
#define etof(e)
Definition misc.qh:25
string string_null
Definition nil.qh:9
spree_inf s1 s2 s3loc s2 spree_inf s1 s2 s3loc s2 spree_inf s1 s2 s3loc s2 s1 s2loc s1 s2loc s1 s2loc s1 s2loc s1 s2loc s1 s2loc s1 s2 f1points f2
Definition all.inc:370
f1
Definition all.inc:569
strcat(_("^F4Countdown stopped!"), "\n^BG", _("Teams are too unbalanced."))
void Send_Notification(NOTIF broadcast, entity client, MSG net_type, Notification net_name,...count)
Definition all.qc:1500
#define NULL
Definition post.qh:14
#define world
Definition post.qh:15
#define gettaginfo
Definition post.qh:32
#define error
Definition pre.qh:6
#define stuffcmd(cl,...)
Definition progsdefs.qh:23
bool RadarMap_Make(int argc)
Definition radarmap.qh:3
#define AVAILABLE_TEAMS
Number of teams that exist currently.
entity bot_cmd
Definition scripting.qh:59
#define setthink(e, f)
vector
Definition self.qh:96
vector org
Definition self.qh:96
void CampaignLevelWarp(float n)
Definition campaign.qc:262
void PutObserverInServer(entity this, bool is_forced, bool use_spawnpoint)
putting a client as observer in the server
Definition client.qc:261
entity GetIndexedEntity(int argc, int start_index)
Definition common.qc:82
int VerifyClientEntity(entity client, bool must_be_real, bool must_be_bots)
Definition common.qc:47
string GetCallerName(entity caller)
Definition common.qc:33
entity GetFilteredEntity(string input)
Definition common.qc:143
float CommonCommand_macro_usage(int argc, entity caller)
Definition common.qh:178
void CommonCommand_macro_help(entity caller)
Definition common.qh:163
#define GetClientErrorString(clienterror, original_input)
Definition common.qh:87
int next_token
Definition common.qh:71
float CommonCommand_macro_command(int argc, entity caller, string command)
Definition common.qh:168
#define SERVER_COMMAND(id, description)
Definition reg.qh:9
string ValidateMap(string validated_map, entity caller)
Definition vote.qc:672
void ReadyRestart(bool forceWarmupEnd)
Definition vote.qc:526
void anticheat_report_to_eventlog(entity this)
Definition anticheat.qc:210
ERASEABLE string car(string s)
Returns first word.
Definition string.qh:258
ERASEABLE string cdr(string s)
Returns all but first word.
Definition string.qh:268
void GameCommand_stuffto(int request, int argc)
Definition sv_cmd.qc:1432
void GameCommand_effectindexdump(int request)
Definition sv_cmd.qc:662
void GameCommand_cointoss(int request, int argc)
Definition sv_cmd.qc:480
void GameCommand_unlockteams(int request)
Definition sv_cmd.qc:1662
void GameCommand_radarmap(int request, int argc)
Definition sv_cmd.qc:1257
void GameCommand_delrec(int request, int argc)
Definition sv_cmd.qc:628
void GameCommand_gotomap(int request, int argc)
Definition sv_cmd.qc:931
void GameCommand_allready(int request)
Definition sv_cmd.qc:165
float GameCommand_macro_command(int argc, string command)
Definition sv_cmd.qc:1810
void GameCommand_resetmatch(int request)
Definition sv_cmd.qc:1407
void print_Effect_Index(int d, string effect_name)
Definition sv_cmd.qc:655
void GameCommand_animbench(int request, int argc)
Definition sv_cmd.qc:872
void changematchtime(float delta, float mi, float ma)
Definition sv_cmd.qc:48
void shuffleteams()
Definition sv_cmd.qc:1333
void GameCommand_database(int request, int argc)
Definition sv_cmd.qc:509
void GameCommand_bbox(int request)
Definition sv_cmd.qc:268
void GameCommand_defer_clear_all(int request)
Definition sv_cmd.qc:594
void GameCommand_extendmatchtime(int request)
Definition sv_cmd.qc:741
void GameCommand_setbots(int request, int argc)
Definition sv_cmd.qc:1305
void make_mapinfo_Think(entity this)
Definition sv_cmd.qc:32
void GameCommand_make_mapinfo(int request)
Definition sv_cmd.qc:997
void GameCommand_shuffleteams(int request)
Definition sv_cmd.qc:1375
void GameCommand_gettaginfo(int request, int argc)
Definition sv_cmd.qc:808
void GameCommand_lockteams(int request)
Definition sv_cmd.qc:961
void GameCommand_nospectators(int request)
Definition sv_cmd.qc:1204
void GameCommand_warp(int request, int argc)
Definition sv_cmd.qc:1696
void GameCommand_allspec(int request, int argc)
Definition sv_cmd.qc:196
void GameCommand_bot_cmd(int request, int argc, string command)
Definition sv_cmd.qc:341
void GameCommand_adminmsg(int request, int argc)
Definition sv_cmd.qc:88
void GameCommand_nextmap(int request, int argc)
Definition sv_cmd.qc:1168
void GameCommand_anticheat(int request, int argc)
Definition sv_cmd.qc:232
void GameCommand_moveplayer(int request, int argc)
Definition sv_cmd.qc:1021
void GameCommand_reducematchtime(int request)
Definition sv_cmd.qc:1279
void GameCommand(string command)
Definition sv_cmd.qc:1841
void GameCommand_macro_help()
Definition sv_cmd.qc:1805
float GameCommand_macro_usage(int argc)
Definition sv_cmd.qc:1820
void GameCommand_defer_clear(int request, int argc)
Definition sv_cmd.qc:552
void GameCommand_gametype(int request, int argc)
Definition sv_cmd.qc:767
void GameCommand_macro_write_aliases(float fh)
Definition sv_cmd.qc:1830
void GameCommand_printstats(int request)
Definition sv_cmd.qc:1231
void GameCommand_trace(int request, int argc)
Definition sv_cmd.qc:1486
bool shuffleteams_on_reset_map
Definition sv_cmd.qh:7
void race_deleteTime(string map, float pos)
Definition race.qc:461
bool GameTypeVote_SetGametype(Gametype type, string gametype_string, bool call_hooks)
#define INGAME(it)
Definition sv_rules.qh:24
int Entity_GetTeamIndex(entity this)
Returns the team index of the given entity.
Definition teamplay.qc:210
void TeamBalance_Destroy(entity balance)
Destroy the team balance entity.
Definition teamplay.qc:528
bool Player_HasRealForcedTeam(entity player)
Returns whether player has real forced team.
Definition teamplay.qc:340
entity TeamBalance_CheckAllowedTeams(entity for_whom)
Checks whether the player can join teams according to global configuration and mutator settings.
Definition teamplay.qc:424
bool TeamBalance_IsTeamAllowed(entity balance, int index)
Returns whether the team change to the specified team is allowed.
Definition teamplay.qc:738
int TeamBalance_FindBestTeam(entity balance, entity player, bool ignore_player)
Finds the team that will make the game most balanced if the player joins it.
Definition teamplay.qc:892
bool MoveToTeam(entity client, int team_index, int type)
Moves player to the specified team.
Definition teamplay.qc:331
int teamplay_bitmask
The set of currently available teams (AVAILABLE_TEAMS is the number of them).
Definition teamplay.qh:18
bool lockteams
Definition teamplay.qh:20
int Team_TeamToBit(int team_num)
Converts team value into bit value that is used in team bitmasks.
Definition teams.qh:199
int Team_TeamToIndex(int team_num)
Converts team value into team index.
Definition teams.qh:184
#define Team_ColoredFullName(teamid)
Definition teams.qh:232
int Team_IndexToTeam(int index)
Converts team index into team value.
Definition teams.qh:169
bool teamplay
Definition teams.qh:59
float Team_ColorToTeam(string team_color)
Definition teams.qh:116
#define IS_OBSERVER(v)
Definition utils.qh:11
#define FOREACH_CLIENT_RANDOM(cond, body)
Definition utils.qh:58
#define IS_SPEC(v)
Definition utils.qh:10
#define IS_REAL_CLIENT(v)
Definition utils.qh:17
#define FOREACH_CLIENT(cond, body)
Definition utils.qh:52
#define IS_BOT_CLIENT(v)
want: (IS_CLIENT(v) && !IS_REAL_CLIENT(v))
Definition utils.qh:15
entity weaponentities[MAX_WEAPONSLOTS]
Definition weapon.qh:17
void DumpStats(float final)
Definition world.qc:1262
float autocvar_timelimit_max
Definition world.qh:27
int world_initialized
Definition world.qh:43
float autocvar_timelimit_min
Definition world.qh:26
float autocvar_timelimit_decrement
Definition world.qh:25
float autocvar_timelimit_increment
Definition world.qh:24
float ServerProgsDB
Definition world.qh:128