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>
10#include <common/teams.qh>
11#include <common/util.qh>
12#include <server/anticheat.qh>
13#include <server/bot/api.qh>
14#include <server/campaign.qh>
15#include <server/client.qh>
18#include <server/command/cmd.qh>
23#include <server/ipban.qh>
24#include <server/mapvoting.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 // set up
1090 int save = Player_GetForcedTeamIndex(client);
1092
1093 // find the team to move the player to
1094 int team_num = Team_ColorToTeam(destination);
1095 entity balance;
1096 if (team_num == client.team) // already on the destination team
1097 {
1098 // keep the forcing undone
1099 LOG_INFO("Player #", client_num_str, " (", pl_name, ") is already on the ",
1100 Team_ColoredFullName(team_num), ".");
1101 continue;
1102 }
1103 else if (team_num == 0) // auto team
1104 {
1105 balance = TeamBalance_CheckAllowedTeams(client);
1106 team_num = Team_IndexToTeam(TeamBalance_FindBestTeam(balance, client, false));
1107 }
1108 else
1109 {
1110 balance = TeamBalance_CheckAllowedTeams(client);
1111 }
1112 Player_SetForcedTeamIndex(client, save);
1113
1114 // Check to see if the destination team is even available
1115 int team_id = Team_TeamToIndex(team_num);
1116 if (team_id == -1)
1117 {
1118 LOG_INFO("Can't move player to ", destination, " team because it doesn't exist.");
1119 TeamBalance_Destroy(balance);
1120 return;
1121 }
1122 if (!(teamplay_bitmask & Team_TeamToBit(team_num)))
1123 {
1124 LOG_INFO("Can't move player to ", destination, " team because it isn't available.");
1125 TeamBalance_Destroy(balance);
1126 return;
1127 }
1128 if (!TeamBalance_IsTeamAllowed(balance, team_id))
1129 {
1130 LOG_INFO("Player #", client_num_str, " (", pl_name, ") is not allowed to join the ",
1131 Team_ColoredFullName(team_num), ".");
1132 TeamBalance_Destroy(balance);
1133 continue;
1134 }
1135 TeamBalance_Destroy(balance);
1136
1137 // If so, lets continue and finally move the player
1139 if (MoveToTeam(client, team_id, 6))
1140 {
1141 successful = strcat(successful, (successful ? ", " : ""), pl_name);
1142 LOG_INFO("Player #", client_num_str, " (", pl_name, ") has been moved to the ",
1143 Team_ColoredFullName(team_num), ".");
1144 }
1145 else
1146 {
1147 LOG_INFO("Unable to move player #", client_num_str, " (", pl_name, ")");
1148 }
1149 }
1150 } // loop end
1151
1152 if (successful) bprint("Successfully moved players ", successful, " to destination ", destination, ".\n");
1153 else LOG_INFO("No players given (", original_targets, ") are able to move.");
1154
1155 return; // still correct parameters so return to avoid usage print
1156 }
1157 }
1158
1159 default:
1160 LOG_HELPF("Incorrect parameters for ^2%s^7", argv(0));
1161 case CMD_REQUEST_USAGE:
1162 {
1163 LOG_HELP("Usage:^3 sv_cmd moveplayer <clients> <destination>");
1164 LOG_HELP(" <clients> is a list (separated by commas) of player entity ID's or nicknames");
1165 LOG_HELP(" <destination> is what to send the player to, be it team or spectating");
1166 LOG_HELP(" Full list of destinations here: spec, spectator, red, blue, yellow, pink, auto.");
1167 LOG_HELP("Examples: sv_cmd moveplayer 1,3,5 red");
1168 LOG_HELP(" sv_cmd moveplayer 2 spec");
1169 LOG_HELP("See also: ^2allspec, shuffleteams^7");
1170 return;
1171 }
1172 }
1173}
1174
1175void GameCommand_nextmap(int request, int argc)
1176{
1177 switch (request)
1178 {
1180 {
1181 if (argc >= 2) // nextmap with mapname arg
1182 {
1183 if (argc > 2)
1184 LOG_HELP("Warning: nextmap only takes 1 argument");
1185
1186 string map = ValidateMap(argv(1), NULL);
1187 if (map != "" && map != get_nextmap())
1188 Set_NextMap(map);
1189 }
1190 else // nextmap without args
1191 {
1192 if (get_nextmap() != "")
1194 else
1195 LOG_HELP("none");
1196 }
1197 return; // never fall through to usage
1198 }
1199
1200 default:
1201 case CMD_REQUEST_USAGE:
1202 {
1203 LOG_HELP("Usage:^3 sv_cmd nextmap [<mapname>]");
1204 LOG_HELP(" Without arguments it prints current nextmap if one is set");
1205 LOG_HELP(" With arguments it attempts to set nextmap");
1206 return;
1207 }
1208 }
1209}
1210
1212{
1213 switch (request)
1214 {
1216 {
1217 if (!world_initialized)
1218 {
1219 LOG_HELPF("This command works only when the server is running.");
1220 return;
1221 }
1222 cvar_settemp("sv_spectate", "0");
1223 // if sv_spectate was enabled PlayerFrame() sends SPECTATE_WARNING notifications
1224 return;
1225 }
1226
1227 default:
1228 case CMD_REQUEST_USAGE:
1229 {
1230 LOG_HELP("Usage:^3 sv_cmd nospectators");
1231 LOG_HELP(" No arguments required.");
1232 LOG_HELP("Temporarily disables the ^3sv_spectate ^7cvar.");
1233 return;
1234 }
1235 }
1236}
1237
1238void GameCommand_printstats(int request)
1239{
1240 switch (request)
1241 {
1243 {
1244 if (!world_initialized)
1245 {
1246 LOG_HELPF("This command works only when the server is running.");
1247 return;
1248 }
1249 DumpStats(false);
1250 LOG_INFO("stats dumped.");
1251 return;
1252 }
1253
1254 default:
1255 case CMD_REQUEST_USAGE:
1256 {
1257 LOG_HELP("Usage:^3 sv_cmd printstats");
1258 LOG_HELP(" No arguments required.");
1259 return;
1260 }
1261 }
1262}
1263
1264void GameCommand_radarmap(int request, int argc)
1265{
1266 switch (request)
1267 {
1269 {
1270 if (RadarMap_Make(argc)) return;
1271 }
1272
1273 default:
1274 LOG_HELPF("Incorrect parameters for ^2%s^7", argv(0));
1275 case CMD_REQUEST_USAGE:
1276 {
1277 LOG_HELP("Usage:^3 sv_cmd radarmap [--force] [--loop] [--quit] [--block | --trace | --sample | --lineblock] [--sharpen N] [--res W H] [--qual Q]");
1278 LOG_HELP(" The quality factor Q is roughly proportional to the time taken.");
1279 LOG_HELP(" trace supports no quality factor; its result should look like --block with infinite quality factor.");
1280 LOG_HELP("See also: ^2make_mapinfo^7");
1281 return;
1282 }
1283 }
1284}
1285
1287{
1288 switch (request)
1289 {
1291 {
1292 if (!world_initialized)
1293 {
1294 LOG_HELPF("This command works only when the server is running.");
1295 return;
1296 }
1298 return;
1299 }
1300
1301 default:
1302 case CMD_REQUEST_USAGE:
1303 {
1304 LOG_HELP("Usage:^3 sv_cmd reducematchtime");
1305 LOG_HELP(" No arguments required.");
1306 LOG_HELP("See also: ^2extendmatchtime^7");
1307 return;
1308 }
1309 }
1310}
1311
1312void GameCommand_setbots(int request, int argc)
1313{
1314 switch (request)
1315 {
1317 {
1318 if (argc >= 2)
1319 {
1320 cvar_settemp("minplayers", "0");
1321 cvar_settemp("minplayers_per_team", "0");
1322 cvar_settemp("bot_number", argv(1));
1323 bot_fixcount(true);
1324 return;
1325 }
1326 }
1327
1328 default:
1329 LOG_HELPF("Incorrect parameters for ^2%s^7", argv(0));
1330 case CMD_REQUEST_USAGE:
1331 {
1332 LOG_HELP("Usage:^3 sv_cmd setbots <botnumber>");
1333 LOG_HELP(" Where <botnumber> is the amount of bots to set bot_number cvar to.");
1334 LOG_HELP("See also: ^2bot_cmd^7");
1335 return;
1336 }
1337 }
1338}
1339
1341{
1342 if (!teamplay)
1343 {
1344 LOG_INFO("Can't shuffle teams when currently not playing a team game.");
1345 return;
1346 }
1347
1348 FOREACH_CLIENT(IS_PLAYER(it) || INGAME(it), {
1349 if (Player_HasRealForcedTeam(it)) {
1350 // we could theoretically assign forced players to their teams
1351 // and shuffle the rest to fill the empty spots but in practise
1352 // either all players or none are gonna have forced teams
1353 LOG_INFO("Can't shuffle teams because at least one player has a forced team.");
1354 return;
1355 }
1356 });
1357
1358 int number_of_teams = 0;
1360 for (int i = 1; i <= AVAILABLE_TEAMS; ++i)
1361 {
1362 if (TeamBalance_IsTeamAllowed(balance, i))
1363 {
1364 number_of_teams = max(i, number_of_teams);
1365 }
1366 }
1367 TeamBalance_Destroy(balance);
1368
1369 int team_index = 0;
1371 int target_team_index = team_index + 1;
1372 if (Entity_GetTeamIndex(it) != target_team_index)
1373 {
1374 MoveToTeam(it, target_team_index, 6);
1375 }
1376 team_index = (team_index + 1) % number_of_teams;
1377 });
1378
1379 bprint("Successfully shuffled the players around randomly.\n");
1380}
1381
1383{
1384 switch (request)
1385 {
1387 {
1388 if (!world_initialized)
1389 {
1390 LOG_HELPF("This command works only when the server is running.");
1391 return;
1392 }
1394 {
1395 bprint("Players will be shuffled when this round is over.\n");
1397 }
1398 else
1399 shuffleteams();
1400 return;
1401 }
1402
1403 default:
1404 case CMD_REQUEST_USAGE:
1405 {
1406 LOG_HELP("Usage:^3 sv_cmd shuffleteams");
1407 LOG_HELP(" No arguments required.");
1408 LOG_HELP("See also: ^2moveplayer, allspec^7");
1409 return;
1410 }
1411 }
1412}
1413
1414void GameCommand_resetmatch(int request)
1415{
1416 switch (request)
1417 {
1419 {
1420 if (!world_initialized)
1421 {
1422 LOG_HELPF("This command works only when the server is running.");
1423 return;
1424 }
1425 ReadyRestart(false);
1426 return;
1427 }
1428
1429 default:
1430 case CMD_REQUEST_USAGE:
1431 {
1432 LOG_HELP("Usage:^3 sv_cmd resetmatch");
1433 LOG_HELP(" No arguments required.");
1434 return;
1435 }
1436 }
1437}
1438
1439void GameCommand_stuffto(int request, int argc)
1440{
1441 // This... is a fairly dangerous and powerful command... - It allows any arguments to be sent to a client via rcon.
1442 // Because of this, it is disabled by default and must be enabled by the server owner when doing compilation. That way,
1443 // we can be certain they understand the risks of it... So to enable, compile server with -DSTUFFTO_ENABLED argument.
1444
1445#ifdef STUFFTO_ENABLED
1446 switch (request)
1447 {
1449 {
1450 if (!world_initialized)
1451 {
1452 LOG_HELPF("This command works only when the server is running.");
1453 return;
1454 }
1455 if (argv(2))
1456 {
1457 entity client = GetIndexedEntity(argc, 1);
1458 float accepted = VerifyClientEntity(client, true, false);
1459
1460 if (accepted > 0)
1461 {
1462 stuffcmd(client, strcat("\n", argv(next_token), "\n"));
1463 LOG_INFO("Command: \"", argv(next_token), "\" sent to ", GetCallerName(client), " (", argv(1), ").");
1464 }
1465 else
1466 {
1467 LOG_INFO("stuffto: ", GetClientErrorString(accepted, argv(1)), ".");
1468 }
1469
1470 return;
1471 }
1472 }
1473
1474 default:
1475 LOG_HELPF("Incorrect parameters for ^2%s^7", argv(0));
1476 case CMD_REQUEST_USAGE:
1477 {
1478 LOG_HELP("Usage:^3 sv_cmd stuffto <client> \"<command>\"");
1479 LOG_HELP(" <client> is the entity number or name of the player,");
1480 LOG_HELP(" and <command> is the command to be sent to that player.");
1481 return;
1482 }
1483 }
1484#else
1485 if (request)
1486 {
1487 LOG_HELP("stuffto command is not enabled on this server.");
1488 return;
1489 }
1490#endif
1491}
1492
1493void GameCommand_trace(int request, int argc)
1494{
1495 switch (request)
1496 {
1498 {
1499 entity e;
1500 vector org, delta, start, end, p, q, q0, pos, vv, dv;
1501 float i, f, safe, unsafe, dq, dqf;
1502
1503 switch (argv(1))
1504 {
1505 case "debug":
1506 {
1507 float hitcount = 0;
1508 LOG_INFO("TEST CASE. If this returns the runaway loop counter error, possibly everything is oaky.");
1509 float worst_endpos_bug = 0;
1510 for ( ; ; )
1511 {
1512 org = world.mins;
1513 delta = world.maxs - world.mins;
1514
1515 start.x = org.x + random() * delta.x;
1516 start.y = org.y + random() * delta.y;
1517 start.z = org.z + random() * delta.z;
1518
1519 end.x = org.x + random() * delta.x;
1520 end.y = org.y + random() * delta.y;
1521 end.z = org.z + random() * delta.z;
1522
1523 start = stov(vtos(start));
1524 end = stov(vtos(end));
1525
1526 tracebox(start, PL_MIN_CONST, PL_MAX_CONST, end, MOVE_NOMONSTERS, NULL);
1527 if (!trace_startsolid && trace_fraction < 1)
1528 {
1529 p = trace_endpos;
1530 tracebox(p, PL_MIN_CONST, PL_MAX_CONST, p, MOVE_NOMONSTERS, NULL);
1531 if (trace_startsolid)
1532 {
1533 rint(42); // do an engine breakpoint on VM_rint so you can get the trace that errnoeously returns startsolid
1534 tracebox(start, PL_MIN_CONST, PL_MAX_CONST, end, MOVE_NOMONSTERS, NULL);
1535
1536 // how much do we need to back off?
1537 safe = 1;
1538 unsafe = 0;
1539 for ( ; ; )
1540 {
1541 pos = p * (1 - (safe + unsafe) * 0.5) + start * ((safe + unsafe) * 0.5);
1542 tracebox(pos, PL_MIN_CONST, PL_MAX_CONST, pos, MOVE_NOMONSTERS, NULL);
1543 if (trace_startsolid)
1544 {
1545 if ((safe + unsafe) * 0.5 == unsafe) break;
1546 unsafe = (safe + unsafe) * 0.5;
1547 }
1548 else
1549 {
1550 if ((safe + unsafe) * 0.5 == safe) break;
1551 safe = (safe + unsafe) * 0.5;
1552 }
1553 }
1554
1555 LOG_INFO("safe distance to back off: ", ftos(safe * vlen(p - start)), "qu");
1556 LOG_INFO("unsafe distance to back off: ", ftos(unsafe * vlen(p - start)), "qu");
1557
1558 tracebox(p, PL_MIN_CONST + '0.1 0.1 0.1', PL_MAX_CONST - '0.1 0.1 0.1', p, MOVE_NOMONSTERS, NULL);
1559 if (trace_startsolid) LOG_INFO("trace_endpos much in solid when tracing from ", vtos(start), " to ", vtos(end), " endpos ", vtos(p));
1560 else LOG_INFO("trace_endpos just in solid when tracing from ", vtos(start), " to ", vtos(end), " endpos ", vtos(p));
1561 if (++hitcount >= 10) break;
1562 }
1563 else
1564 {
1565 q0 = p;
1566 dq = 0;
1567 dqf = 1;
1568 for ( ; ; )
1569 {
1570 q = p + normalize(end - p) * (dq + dqf);
1571 if (q == q0) break;
1572 tracebox(p, PL_MIN_CONST, PL_MAX_CONST, q, MOVE_NOMONSTERS, NULL);
1573 if (trace_startsolid) error("THIS ONE cannot happen");
1574 if (trace_fraction > 0) dq += dqf * trace_fraction;
1575 dqf *= 0.5;
1576 q0 = q;
1577 }
1578 if (dq > worst_endpos_bug)
1579 {
1580 worst_endpos_bug = dq;
1581 LOG_INFO("trace_endpos still before solid when tracing from ", vtos(start), " to ", vtos(end), " endpos ", vtos(p));
1582 LOG_INFO("could go ", ftos(dq), " units further to ", vtos(q));
1583 if (++hitcount >= 10) break;
1584 }
1585 }
1586 }
1587 }
1588 return;
1589 }
1590
1591 case "debug2":
1592 {
1593 e = nextent(NULL);
1594 tracebox(e.origin + '0 0 32', e.mins, e.maxs, e.origin + '0 0 -1024', MOVE_NORMAL, e);
1595 vv = trace_endpos;
1596 if (trace_fraction == 1)
1597 {
1598 LOG_INFO("not above ground, aborting");
1599 return;
1600 }
1601 f = 0;
1602 for (i = 0; i < 100000; ++i)
1603 {
1604 dv = randomvec();
1605 if (dv.z > 0) dv = -1 * dv;
1606 tracebox(vv, e.mins, e.maxs, vv + dv, MOVE_NORMAL, e);
1607 if (trace_startsolid) LOG_INFO("bug 1");
1608 if (trace_fraction == 1)
1609 {
1610 if (dv.z < f)
1611 {
1612 LOG_INFO("bug 2: ", ftos(dv.x), " ", ftos(dv.y), " ", ftos(dv.z));
1613 LOG_INFO(" (", ftos(asin(dv.z / vlen(dv)) * 180 / M_PI), " degrees)");
1614 f = dv.z;
1615 }
1616 }
1617 }
1618 LOG_INFO("highest possible dist: ", ftos(f));
1619 return;
1620 }
1621
1622 case "walk":
1623 {
1624 if (argc == 4 || argc == 5)
1625 {
1626 e = nextent(NULL);
1627 int dphitcontentsmask_save = e.dphitcontentsmask;
1629 if (tracewalk(e, stov(argv(2)), e.mins, e.maxs, stov(argv(3)), stof(argv(4)), MOVE_NORMAL))
1630 LOG_INFO("can walk");
1631 else
1632 LOG_INFO("cannot walk");
1633 e.dphitcontentsmask = dphitcontentsmask_save;
1634 return;
1635 }
1636 }
1637
1638 case "showline":
1639 {
1640 if (argc == 4)
1641 {
1642 vv = stov(argv(2));
1643 dv = stov(argv(3));
1644 traceline(vv, dv, MOVE_NORMAL, NULL);
1645 __trailparticles(NULL, particleeffectnum(EFFECT_TR_NEXUIZPLASMA), vv, trace_endpos);
1646 __trailparticles(NULL, particleeffectnum(EFFECT_TR_CRYLINKPLASMA), trace_endpos, dv);
1647 return;
1648 }
1649 }
1650
1651 // no default case, just go straight to invalid
1652 }
1653 }
1654
1655 default:
1656 LOG_HELPF("Incorrect parameters for ^2%s^7", argv(0));
1657 case CMD_REQUEST_USAGE:
1658 {
1659 LOG_HELP("Usage:^3 sv_cmd trace <command> [<startpos> <endpos>] [<endpos_height>]");
1660 LOG_HELP(" Where <startpos> and <endpos> are parameters for the 'walk' and 'showline' commands,");
1661 LOG_HELP(" <endpos_height> is an optional parameter for the 'walk' command,");
1662 LOG_HELP(" Full list of commands here: debug, debug2, walk, showline.");
1663 LOG_HELP("See also: ^2bbox, gettaginfo^7");
1664 return;
1665 }
1666 }
1667}
1668
1670{
1671 switch (request)
1672 {
1674 {
1675 if (!world_initialized)
1676 {
1677 LOG_HELPF("This command works only when the server is running.");
1678 return;
1679 }
1680 if (teamplay)
1681 {
1682 lockteams = 0;
1683 Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_TEAMS_UNLOCKED);
1684 }
1685 else
1686 {
1687 bprint("unlockteams command can only be used in a team-based gametype.\n");
1688 }
1689 return;
1690 }
1691
1692 default:
1693 case CMD_REQUEST_USAGE:
1694 {
1695 LOG_HELP("Usage:^3 sv_cmd unlockteams");
1696 LOG_HELP(" No arguments required.");
1697 LOG_HELP("See also: ^2lockteams^7");
1698 return;
1699 }
1700 }
1701}
1702
1703void GameCommand_warp(int request, int argc)
1704{
1705 switch (request)
1706 {
1708 {
1709 if (!world_initialized)
1710 {
1711 LOG_HELPF("This command works only when the server is running.");
1712 return;
1713 }
1715 {
1716 if (argc >= 2)
1717 {
1719 LOG_INFO("Successfully warped to campaign level ", argv(1), ".");
1720 }
1721 else
1722 {
1724 LOG_INFO("Successfully warped to next campaign level.");
1725 }
1726 }
1727 else
1728 {
1729 LOG_INFO("Not in campaign, can't level warp");
1730 }
1731 return;
1732 }
1733
1734 default:
1735 case CMD_REQUEST_USAGE:
1736 {
1737 LOG_HELP("Usage:^3 sv_cmd warp [<level>]");
1738 LOG_HELP(" <level> is the level to change campaign mode to.");
1739 LOG_HELP(" if <level> is not provided it will change to the next level.");
1740 return;
1741 }
1742 }
1743}
1744
1745/* use this when creating a new command, making sure to place it in alphabetical order... also,
1746** ADD ALL NEW COMMANDS TO commands.cfg WITH PROPER ALIASES IN THE SAME FASHION!
1747void GameCommand_(int request)
1748{
1749 switch(request)
1750 {
1751 case CMD_REQUEST_COMMAND:
1752 {
1753 if (!world_initialized)
1754 {
1755 LOG_HELPF("This command works only when the server is running.");
1756 return;
1757 }
1758
1759 return;
1760 }
1761
1762 default:
1763 case CMD_REQUEST_USAGE:
1764 {
1765 LOG_HELP("Usage:^3 sv_cmd ");
1766 LOG_HELP(" No arguments required.");
1767 return;
1768 }
1769 }
1770}
1771*/
1772
1773
1774// ==================================
1775// Macro system for server commands
1776// ==================================
1777
1778// Do not hard code aliases for these, instead create them in commands.cfg... also: keep in alphabetical order, please ;)
1779SERVER_COMMAND(adminmsg, "Send an admin message to a client directly") { GameCommand_adminmsg(request, arguments); }
1780SERVER_COMMAND(allready, "Ends warmup and starts the match") { GameCommand_allready(request); }
1781SERVER_COMMAND(allspec, "Force all players to spectate") { GameCommand_allspec(request, arguments); }
1782SERVER_COMMAND(anticheat, "Create an anticheat report for a client") { GameCommand_anticheat(request, arguments); }
1783SERVER_COMMAND(animbench, "Benchmark model animation (LAGS)") { GameCommand_animbench(request, arguments); }
1784SERVER_COMMAND(bbox, "Print detailed information about world size") { GameCommand_bbox(request); }
1785SERVER_COMMAND(bot_cmd, "Control and send commands to bots") { GameCommand_bot_cmd(request, arguments, command); }
1786SERVER_COMMAND(cointoss, "Flip a virtual coin and give random result") { GameCommand_cointoss(request, arguments); }
1787SERVER_COMMAND(database, "Extra controls of the serverprogs database") { GameCommand_database(request, arguments); }
1788SERVER_COMMAND(defer_clear, "Clear all queued defer commands for a specific client") { GameCommand_defer_clear(request, arguments); }
1789SERVER_COMMAND(defer_clear_all, "Clear all queued defer commands for all clients") { GameCommand_defer_clear_all(request); }
1790SERVER_COMMAND(delrec, "Delete race time record for a map") { GameCommand_delrec(request, arguments); }
1791SERVER_COMMAND(effectindexdump, "Dump list of effects from code and effectinfo.txt") { GameCommand_effectindexdump(request); }
1792SERVER_COMMAND(extendmatchtime, "Increase the timelimit value incrementally") { GameCommand_extendmatchtime(request); }
1793SERVER_COMMAND(gametype, "Simple command to change the active gametype") { GameCommand_gametype(request, arguments); }
1794SERVER_COMMAND(gettaginfo, "Get specific information about a weapon model") { GameCommand_gettaginfo(request, arguments); }
1795SERVER_COMMAND(gotomap, "Simple command to switch to another map") { GameCommand_gotomap(request, arguments); }
1796SERVER_COMMAND(lockteams, "Disable the ability for players to switch or enter teams") { GameCommand_lockteams(request); }
1797SERVER_COMMAND(make_mapinfo, "Automatically rebuild mapinfo files") { GameCommand_make_mapinfo(request); }
1798SERVER_COMMAND(moveplayer, "Change the team/status of a player") { GameCommand_moveplayer(request, arguments); }
1799SERVER_COMMAND(nextmap, "Set/Query the next map") { GameCommand_nextmap(request, arguments); }
1800SERVER_COMMAND(nospectators, "Automatically remove spectators from a match") { GameCommand_nospectators(request); }
1801SERVER_COMMAND(printstats, "Dump eventlog player stats and other score information") { GameCommand_printstats(request); }
1802SERVER_COMMAND(radarmap, "Generate a radar image of the map") { GameCommand_radarmap(request, arguments); }
1803SERVER_COMMAND(reducematchtime, "Decrease the timelimit value incrementally") { GameCommand_reducematchtime(request); }
1804SERVER_COMMAND(resetmatch, "Soft restart the game without changing teams; goes back to warmup if enabled") { GameCommand_resetmatch(request); }
1805SERVER_COMMAND(setbots, "Adjust how many bots are in the match") { GameCommand_setbots(request, arguments); }
1806SERVER_COMMAND(shuffleteams, "Randomly move players to different teams") { GameCommand_shuffleteams(request); }
1807SERVER_COMMAND(stuffto, "Send a command to be executed on a client") { GameCommand_stuffto(request, arguments); }
1808SERVER_COMMAND(trace, "Various debugging tools with tracing") { GameCommand_trace(request, arguments); }
1809SERVER_COMMAND(unlockteams, "Enable the ability for players to switch or enter teams") { GameCommand_unlockteams(request); }
1810SERVER_COMMAND(warp, "Choose different level in campaign") { GameCommand_warp(request, arguments); }
1811
1813{
1814 FOREACH(SERVER_COMMANDS, true, { LOG_HELPF(" ^2%s^7: %s", it.m_name, it.m_description); });
1815}
1816
1817float GameCommand_macro_command(int argc, string command)
1818{
1819 string c = strtolower(argv(0));
1820 FOREACH(SERVER_COMMANDS, it.m_name == c, {
1821 it.m_invokecmd(it, CMD_REQUEST_COMMAND, NULL, argc, command);
1822 return true;
1823 });
1824 return false;
1825}
1826
1828{
1829 string c = strtolower(argv(1));
1830 FOREACH(SERVER_COMMANDS, it.m_name == c, {
1831 it.m_invokecmd(it, CMD_REQUEST_USAGE, NULL, argc, "");
1832 return true;
1833 });
1834 return false;
1835}
1836
1838{
1839 FOREACH(SERVER_COMMANDS, true, { CMD_Write_Alias("qc_cmd_sv", it.m_name, it.m_description); });
1840}
1841
1842
1843// =========================================
1844// Main Function Called By Engine (sv_cmd)
1845// =========================================
1846// If this function exists, game code handles gamecommand instead of the engine code.
1847
1848void GameCommand(string command)
1849{
1850 int argc = tokenize_console(command);
1851
1852 // Guide for working with argc arguments by example:
1853 // argc: 1 - 2 - 3 - 4
1854 // argv: 0 - 1 - 2 - 3
1855 // cmd vote - master - login - password
1856
1857 if (strtolower(argv(0)) == "help")
1858 {
1859 if (argc == 1)
1860 {
1861 LOG_HELP("Server console commands:");
1863
1864 LOG_HELP("\nBanning commands:");
1866
1867 LOG_HELP("\nCommon networked commands:");
1869
1870 LOG_HELP("\nGeneric commands shared by all programs:");
1872
1873 LOG_HELP("\nUsage:^3 sv_cmd <command>^7, where possible commands are listed above.\n"
1874 "For help about a specific command, type sv_cmd help <command>");
1875
1876 return;
1877 }
1878 else if (BanCommand_macro_usage(argc)) // Instead of trying to call a command, we're going to see detailed information about it
1879 {
1880 return;
1881 }
1882 else if (CommonCommand_macro_usage(argc, NULL)) // same here, but for common commands instead
1883 {
1884 return;
1885 }
1886 else if (GenericCommand_macro_usage(argc)) // same here, but for generic commands instead
1887 {
1888 return;
1889 }
1890 else if (GameCommand_macro_usage(argc)) // finally try for normal commands too
1891 {
1892 return;
1893 }
1894 }
1895 else if (MUTATOR_CALLHOOK(SV_ParseServerCommand, strtolower(argv(0)), argc, command))
1896 {
1897 return; // handled by a mutator
1898 }
1899 else if (BanCommand(command))
1900 {
1901 return; // handled by server/command/ipban.qc
1902 }
1903 else if (CommonCommand_macro_command(argc, NULL, command))
1904 {
1905 return; // handled by server/command/common.qc
1906 }
1907 else if (GenericCommand(command))
1908 {
1909 return; // handled by common/command/generic.qc
1910 }
1911 else if (GameCommand_macro_command(argc, command)) // continue as usual and scan for normal commands
1912 {
1913 return; // handled by one of the above GameCommand_* functions
1914 }
1915
1916 // nothing above caught the command, must be invalid
1917 LOG_INFO(((command != "") ? strcat("Unknown server command \"", command, "\"") : "No command provided"), ". For a list of supported commands, try sv_cmd help.");
1918}
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:2178
float cvar_settemp(string tmp_cvar, string tmp_value)
Definition util.qc:807
string strtolower(string s)
const vector PL_MIN_CONST
Definition constants.qh:56
const vector PL_MAX_CONST
Definition constants.qh:55
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:112
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:369
f1
Definition all.inc:566
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
bool GameTypeVote_SetGametype(Gametype type, string gametype_string, bool call_hooks)
Definition mapvoting.qc:835
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:1439
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:1669
void GameCommand_radarmap(int request, int argc)
Definition sv_cmd.qc:1264
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:1817
void GameCommand_resetmatch(int request)
Definition sv_cmd.qc:1414
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:1340
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:1312
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:1382
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:1211
void GameCommand_warp(int request, int argc)
Definition sv_cmd.qc:1703
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:1175
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:1286
void GameCommand(string command)
Definition sv_cmd.qc:1848
void GameCommand_macro_help()
Definition sv_cmd.qc:1812
float GameCommand_macro_usage(int argc)
Definition sv_cmd.qc:1827
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:1837
void GameCommand_printstats(int request)
Definition sv_cmd.qc:1238
void GameCommand_trace(int request, int argc)
Definition sv_cmd.qc:1493
bool shuffleteams_on_reset_map
Definition sv_cmd.qh:7
void race_deleteTime(string map, float pos)
Definition race.qc:461
#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:597
bool Player_HasRealForcedTeam(entity player)
Returns whether player has real forced team.
Definition teamplay.qc:342
int Player_GetForcedTeamIndex(entity player)
Returns the index of the forced team of the given player.
Definition teamplay.qc:347
entity TeamBalance_CheckAllowedTeams(entity for_whom)
Checks whether the player can join teams according to global configuration and mutator settings.
Definition teamplay.qc:488
bool TeamBalance_IsTeamAllowed(entity balance, int index)
Returns whether the team change to the specified team is allowed.
Definition teamplay.qc:807
void Player_SetForcedTeamIndex(entity player, int team_index)
Sets the index of the forced team of the given player.
Definition teamplay.qc:352
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:962
bool MoveToTeam(entity client, int team_index, int type)
Moves player to the specified team.
Definition teamplay.qc:328
@ TEAM_FORCE_DEFAULT
Don't force any team.
Definition teamplay.qh:153
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:1264
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