Xonotic QuakeC
The free, fast arena FPS with crisp movement and a wide array of weapons
cmd.qc
Go to the documentation of this file.
1#include "cmd.qh"
2
4#include <common/constants.qh>
8#include <common/mapinfo.qh>
16#include <common/teams.qh>
17#include <common/util.qh>
20#include <server/bot/api.qh>
21#include <server/bot/default/cvars.qh> // for autocvar_bot_vs_human
23#include <server/campaign.qh>
24#include <server/chat.qh>
25#include <server/cheats.qh>
26#include <server/client.qh>
27#include <server/clientkill.qh>
32#include <server/ipban.qh>
33#include <server/mapvoting.qh>
35#include <server/player.qh>
36#include <server/race.qh>
37#include <server/scores.qh>
38#include <server/teamplay.qh>
39#include <server/world.qh>
40
47void ignore_remove_player(entity this, entity ignore, bool from_db_too)
48{
49 if (from_db_too && ignore.crypto_idfp && ignore.crypto_idfp != "" && this.crypto_idfp && this.crypto_idfp != "")
50 {
51 for(int j = 0; j < IGNORE_MAXPLAYERS; ++j)
52 {
53 string pos = db_get(ServerProgsDB, strcat("/ignore/", this.crypto_idfp, "/", ftos(j)));
54 if(pos == ignore.crypto_idfp)
55 {
56 db_remove(ServerProgsDB, strcat("/ignore/", this.crypto_idfp, "/", ftos(j)));
57 break;
58 }
59 }
60 }
61
62 if (this.ignore_list == "")
63 return;
64
65 string newlist = "";
66 string theid = ftos(etof(ignore));
67
68 // we use a tempstring here because if the input string of FOREACH_WORD is strzoned
69 // then it can no longer be strunzoned and updated correctly
70 string ignore_list_copy = strcat(this.ignore_list);
71 FOREACH_WORD(ignore_list_copy, it != theid,
72 newlist = cons(newlist, it););
73 strcpy(this.ignore_list, newlist);
74
75 this.ignore_list_send_time = time + 0.2;
76}
77
88int ignore_add_player(entity this, entity ignore, bool to_db_too)
89{
90 int r = 1;
91 // permanent ignores work if both the player and the sender have a stats UID
92 if (to_db_too && ignore.crypto_idfp && ignore.crypto_idfp != "" && this.crypto_idfp && this.crypto_idfp != "")
93 {
94 for (int j = 0; j < IGNORE_MAXPLAYERS; ++j)
95 {
96 string pos = db_get(ServerProgsDB, strcat("/ignore/", this.crypto_idfp, "/", ftos(j)));
97 if(pos == "")
98 {
99 db_put(ServerProgsDB, strcat("/ignore/", this.crypto_idfp, "/", ftos(j)), ignore.crypto_idfp);
100 r = 2;
101 break;
102 }
103 }
104 if (r != 2)
105 return 0;
106 }
107
108 string list = cons(this.ignore_list, ftos(etof(ignore)));
109 strcpy(this.ignore_list, list);
110
111 this.ignore_list_send_time = time + 0.2;
112
113 return r;
114}
115
118{
119 if(this.crypto_idfp && this.crypto_idfp != "" && pl.crypto_idfp && pl.crypto_idfp != "")
120 {
121 string thelist = "";
122 for(int j = 0; j < IGNORE_MAXPLAYERS; ++j)
123 {
124 string pos = db_get(ServerProgsDB, strcat("/ignore/", this.crypto_idfp, "/", ftos(j)));
125 thelist = cons(thelist, pos);
126 }
127
128 return ((thelist != "") ? PlayerInList(pl, thelist) : false);
129 }
130 return false;
131}
132
135{
136 if (!this.ignore_list || this.ignore_list == "")
137 return false;
138
139 string theid = ftos(etof(pl));
140
141 // we use a tempstring here because if the input string of FOREACH_WORD is strzoned
142 // then it can no longer be strunzoned and updated correctly
143 string ignore_list_copy = strcat(this.ignore_list);
144 FOREACH_WORD(ignore_list_copy, it == theid,
145 return true;
146 );
147
148 return false;
149}
150
154{
155 if (!this)
156 return;
157
158 FOREACH_CLIENT(it != this && IS_REAL_CLIENT(it),
159 {
160 if (ignore_playerindb(this, it))
161 ignore_add_player(this, it, false); // update ignore list of the connecting player
162
163 if (ignore_playerindb(it, this))
164 ignore_add_player(it, this, false); // update ignore list of other players
165 });
166}
167
169{
170 ClientData_Touch(this, false);
171 // changing ignore_list_send_time to IGNORE_LIST_SEND_NOW is needed
172 // to send ignore_list correctly in ClientData_Send
174}
175
177{
178 for(int j = 0; j < IGNORE_MAXPLAYERS; ++j)
179 {
180 string pos = db_get(ServerProgsDB, strcat("/ignore/", this.crypto_idfp, "/", ftos(j)));
181 if(pos != "")
182 {
183 db_remove(ServerProgsDB, strcat("/ignore/", this.crypto_idfp, "/", ftos(j)));
184 FOREACH_CLIENT(it != this && IS_REAL_CLIENT(it),
185 {
186 if(pos == it.crypto_idfp)
187 {
188 // permanent ignores already removed from db, remove only from list now
189 ignore_remove_player(this, it, false);
191 }
192 });
193 }
194 }
195}
196
197// =======================
198// Command Sub-Functions
199// =======================
200
201void ClientCommand_autoswitch(entity caller, int request, int argc)
202{
203 switch (request)
204 {
206 {
207 if (argv(1) != "")
208 {
209 CS_CVAR(caller).cvar_cl_autoswitch = InterpretBoolean(argv(1));
210 sprint(caller, strcat("^1autoswitch is currently turned ", (CS_CVAR(caller).cvar_cl_autoswitch ? "on" : "off"), ".\n"));
211 return;
212 }
213 }
214
215 default:
216 sprint(caller, sprintf("Incorrect parameters for ^2%s^7\n", argv(0)));
218 {
219 sprint(caller, "\nUsage:^3 cmd autoswitch <selection>\n");
220 sprint(caller, " Where <selection> controls if autoswitch is on or off.\n");
221 return;
222 }
223 }
224}
225
226void ClientCommand_clear_ignores(entity caller, int request)
227{
228 switch (request)
229 {
231 {
232 if(!(caller.crypto_idfp && caller.crypto_idfp != ""))
233 {
234 sprint(caller, "You don't have a stats UID, unable to clear your ignore list.\n");
235 return;
236 }
237
238 ignore_clearall(caller);
239 sprint(caller, "All permanent ignores cleared!\n");
240 return;
241 }
242
243 default:
245 {
246 sprint(caller, "\nUsage:^3 cmd clear_ignores\n");
247 sprint(caller, " Removes all existing ignored clients whose are kept out of personal chat log.\n");
248 return;
249 }
250 }
251}
252
254{
255 switch (request)
256 {
258 {
260 return;
261 }
262
263 default:
265 {
266 sprint(caller, "\nUsage:^3 cmd clear_bestcptimes\n");
267 sprint(caller, " Clear all your checkpoint times for this game.\n");
268 return;
269 }
270 }
271}
272
273void ClientCommand_clientversion(entity caller, int request, int argc) // internal command, used only by code
274{
275 switch (request)
276 {
278 {
279 if (argv(1) != "")
280 {
281 if (IS_CLIENT(caller))
282 {
283 CS(caller).version = ((argv(1) == "$gameversion") ? 1 : stof(argv(1)));
284
285 if (CS(caller).version < autocvar_gameversion_min || CS(caller).version > autocvar_gameversion_max)
286 {
287 CS(caller).version_mismatch = true;
288 ClientKill_TeamChange(caller, -2); // observe
289 }
291 {
292 // JoinBestTeam(caller, false, true);
293 }
294 else if (teamplay && !autocvar_sv_spectate && !(Player_GetForcedTeamIndex(caller) > 0))
295 {
296 TRANSMUTE(Observer, caller); // really?
297 stuffcmd(caller, "team_selection_show\n");
298 }
299 }
300
301 return;
302 }
303 }
304
305 default:
306 sprint(caller, sprintf("Incorrect parameters for ^2%s^7\n", argv(0)));
308 {
309 sprint(caller, "\nUsage:^3 cmd clientversion <version>\n");
310 sprint(caller, " Where <version> is the game version reported by caller.\n");
311 return;
312 }
313 }
314}
315
316void ClientCommand_mv_getpicture(entity caller, int request, int argc) // internal command, used only by code
317{
318 switch (request)
319 {
321 {
322 if (argv(1) != "")
323 {
325
326 return;
327 }
328 }
329
330 default:
331 sprint(caller, sprintf("Incorrect parameters for ^2%s^7\n", argv(0)));
333 {
334 sprint(caller, "\nUsage:^3 cmd mv_getpicture <mapid>\n");
335 sprint(caller, " Where <mapid> is the id number of the map to request an image of on the map vote selection menu.\n");
336 return;
337 }
338 }
339}
340
341void ClientCommand_wpeditor(entity caller, int request, int argc)
342{
343 switch (request)
344 {
346 {
348 {
349 sprint(caller, "ERROR: this command works only if the waypoint editor is on\n");
350 return;
351 }
352
353 if (argv(1) != "")
354 {
355 if (argv(1) == "spawn")
356 {
357 string s = argv(2);
358 if (!IS_PLAYER(caller))
359 sprint(caller, "ERROR: this command works only if you are player\n");
360 else
361 waypoint_spawn_fromeditor(caller, (s == "crosshair"), (s == "jump"), (s == "crouch"), (s == "support"));
362 return;
363 }
364 else if (argv(1) == "remove")
365 {
366 if (!IS_PLAYER(caller))
367 sprint(caller, "ERROR: this command works only if you are player\n");
368 else
370 return;
371 }
372 else if (argv(1) == "hardwire")
373 {
374 string s = argv(2);
375 waypoint_start_hardwiredlink(caller, (s == "crosshair"));
376 return;
377 }
378 else if (argv(1) == "lock")
379 {
380 waypoint_lock(caller);
381 return;
382 }
383 else if (argv(1) == "unreachable")
384 {
385 if (!IS_PLAYER(caller))
386 sprint(caller, "ERROR: this command works only if you are player\n");
387 else
388 waypoint_unreachable(caller);
389 return;
390 }
391 else if (argv(1) == "saveall")
392 {
394 return;
395 }
396 else if (argv(1) == "relinkall")
397 {
399 return;
400 }
401 else if (argv(1) == "symaxis")
402 {
403 if (argv(2) == "set" || argv(2) == "get")
404 {
405 waypoint_getSymmetricalAxis_cmd(caller, (argv(2) == "set"), 3);
406 return;
407 }
408 }
409 else if (argv(1) == "symorigin")
410 {
411 if (argv(2) == "set" || argv(2) == "get")
412 {
413 waypoint_getSymmetricalOrigin_cmd(caller, (argv(2) == "set"), 3);
414 return;
415 }
416 }
417 }
418 }
419
420 default:
421 sprint(caller, sprintf("Incorrect parameters for ^2%s^7\n", argv(0)));
423 {
424 sprint(caller, "\nUsage:^3 cmd wpeditor <action>\n");
425 sprint(caller, " Where <action> can be:\n");
426 sprint(caller, " ^2spawn^7: spawns a waypoint at player's position\n");
427 sprint(caller, " ^2remove^7: removes player's nearest waypoint\n");
428 sprint(caller, " ^2unreachable^7: reveals waypoints and items unreachable from the current position and spawnpoints without a nearest waypoint\n");
429 sprint(caller, " ^2saveall^7: saves all waypoints and links to file\n");
430 sprint(caller, " ^2relinkall^7: relinks all waypoints as if they were respawned\n");
431 sprint(caller, " ^2spawn crosshair^7: spawns a waypoint at crosshair's position\n");
432 sprint(caller, " ^7 in general useful to create special and hardwired links with ease from existing waypoints\n");
433 sprint(caller, " ^7 in particular it's the only way to create custom jumppad waypoints (spawn another waypoint to create destination))\n");
434 sprint(caller, " ^2spawn jump^7: spawns a jump waypoint (place it at least 60 qu before jump start, spawn another waypoint to create destination)\n");
435 sprint(caller, " ^2spawn crouch^7: spawns a crouch waypoint (it links only to very close waypoints)\n");
436 sprint(caller, " ^2spawn support^7: spawns a support waypoint (spawn another waypoint to create destination from which all incoming links are removed)\n");
437 sprint(caller, " ^7 useful to replace links to problematic jumppad/teleport waypoints\n");
438 sprint(caller, " ^2hardwire^7: marks the nearest waypoint as origin of a new hardwired link (spawn another waypoint over an existing one to create destination)\n");
439 sprint(caller, " ^2hardwire crosshair^7: marks the waypoint at crosshair instead of the nearest waypoint\n");
440 sprint(caller, " ^2lock^7: locks link display of the aimed waypoint (unlocks if no waypoint is found at crosshair's position)\n");
441 sprint(caller, " ^2symorigin get|set\n");
442 sprint(caller, " ^2symorigin get|set <p1> <p2> ... <pX>\n");
443 sprint(caller, " ^2symaxis get|set <p1> <p2>\n");
444 sprint(caller, " ^7 where <p1> <p2> ... <pX> are positions (\"x y z\", z can be omitted) that you know are perfectly symmetrical"
445 " so you can determine origin/axis of symmetry of maps without ctf flags or where flags aren't perfectly symmetrical\n");
446 sprint(caller, " See ^5wpeditor_menu^7 for a selectable list of various commands and useful settings to edit waypoints.\n");
447 return;
448 }
449 }
450}
451
452void ClientCommand_ignore(entity caller, int request, int argc, string command)
453{
454 switch (request)
455 {
457 {
458 if (argc >= 2)
459 {
460 if(!argv(1) || argv(1) == "")
461 {
462 sprint(caller, "This command requires an argument. Use a player's name or their ID from the ^2status^7 command.\n");
463 return;
464 }
465
466 entity ignore_to = GetIndexedEntity(argc, 1);
467 float ignore_accepted = VerifyClientEntity(ignore_to, true, false);
468
469 if (ignore_accepted > 0 && IS_REAL_CLIENT(ignore_to)) // the target is a real client
470 {
471 if (ignore_to != caller) // and we're allowed to ignore them heh
472 {
473 if(ignore_playerinlist(caller, ignore_to))
474 {
475 sprint(caller, ignore_to.netname, " ^7is already ignored!\n");
476 return;
477 }
478
479 int r = ignore_add_player(caller, ignore_to, true);
480 if (r == 2)
481 sprint(caller, "You will no longer receive messages from ", ignore_to.netname, "^7, use ^2unignore^7 to hear them again.\n");
482 else if (r == 1)
483 sprint(caller, "You will no longer receive messages from ", ignore_to.netname, "^7 for this match, use ^2unignore^7 to hear them again.\n");
484 else // r == 0
485 sprint(caller, "You may only ignore up to ", ftos(IGNORE_MAXPLAYERS), " players, remove one before trying again.\n");
486
487 }
488 else { sprint(caller, "You can't ^2ignore^7 yourself.\n"); }
489 }
490 else { print_to(caller, strcat("ignore: ", GetClientErrorString(ignore_accepted, argv(1)), ".\nUnable to ignore this player, check their ID.")); }
491
492 return;
493 }
494 }
495
496 default:
497 sprint(caller, sprintf("Incorrect parameters for ^2%s^7\n", argv(0)));
499 {
500 sprint(caller, "\nUsage:^3 cmd ignore <client>\n");
501 sprint(caller, " Where <client> is the entity number or name of the player to ignore keeping out of personal chat log.\n");
502 return;
503 }
504 }
505}
506
507void ClientCommand_join(entity caller, int request)
508{
509 switch (request)
510 {
512 {
513 if (!game_stopped && IS_CLIENT(caller) && !IS_PLAYER(caller))
514 {
515 if (joinAllowed(caller, caller.wants_join))
516 Join(caller, teamplay);
517 else if(time < CS(caller).jointime + MIN_SPEC_TIME)
518 CS(caller).autojoin_checked = -1;
519 }
520 CS(caller).parm_idlesince = time;
521
522 return; // never fall through to usage
523 }
524
525 default:
527 {
528 sprint(caller, "\nUsage:^3 cmd join\n");
529 sprint(caller, " No arguments required.\n");
530 return;
531 }
532 }
533}
534
535void ClientCommand_kill(entity caller, int request)
536{
537 switch (request)
538 {
540 {
541 if(IS_SPEC(caller) || IS_OBSERVER(caller))
542 return; // no point warning about this, command does nothing
543
544 if(GetResource(caller, RES_HEALTH) <= 0)
545 {
546 sprint(caller, "Can't die - you are already dead!\n");
547 return;
548 }
549
550 ClientKill(caller);
551
552 return; // never fall through to usage
553 }
554
555 default:
557 {
558 sprint(caller, "\nUsage:^3 cmd kill\n");
559 sprint(caller, " No arguments required.\n");
560 return;
561 }
562 }
563}
564
565void ClientCommand_physics(entity caller, int request, int argc)
566{
567 switch (request)
568 {
570 {
571 string command = strtolower(argv(1));
572
574 {
575 sprint(caller, "Client physics selection is currently disabled.\n");
576 return;
577 }
578
579 if (command == "list" || command == "help")
580 {
581 sprint(caller, strcat("Available physics sets: \n\n", autocvar_g_physics_clientselect_options, " default\n"));
582 return;
583 }
584
585 if (Physics_Valid(command) || command == "default")
586 {
587 stuffcmd(caller, strcat("\nseta cl_physics ", command, "\n"));
588 sprint(caller, strcat("^2Physics set successfully changed to ^3", command, "\n"));
589 return;
590 }
591 }
592
593 default:
594 sprint(caller, strcat("Current physics set: ^3", CS_CVAR(caller).cvar_cl_physics, "\n"));
596 {
597 sprint(caller, "\nUsage:^3 cmd physics <physics>\n");
598 sprint(caller, " See 'cmd physics list' for available physics sets.\n");
599 sprint(caller, " Argument 'default' resets to standard physics.\n");
600 return;
601 }
602 }
603}
604
605void ClientCommand_ready(entity caller, int request)
606{
607 switch (request)
608 {
610 {
612 if (IS_PLAYER(caller) || INGAME_JOINED(caller))
613 {
614 if (caller.ready) // toggle
615 {
616 caller.ready = false;
617 bprint(playername(caller.netname, caller.team, false), "^2 is ^1NOT^2 ready\n");
618 }
619 else
620 {
621 caller.ready = true;
622 bprint(playername(caller.netname, caller.team, false), "^2 is ready\n");
623 }
624 ReadyCount();
625 }
626 return; // never fall through to usage
627 }
628
629 default:
631 {
632 sprint(caller, "\nUsage:^3 cmd ready\n");
633 sprint(caller, " No arguments required.\n");
634 return;
635 }
636 }
637}
638
639void ClientCommand_say(entity caller, int request, int argc, string command)
640{
641 switch (request)
642 {
644 {
645 if (argc >= 2) Say(caller, false, NULL, substring(command, argv_start_index(1), argv_end_index(-1) - argv_start_index(1)), 1);
646 return; // never fall through to usage
647 }
648
649 default:
651 {
652 sprint(caller, "\nUsage:^3 cmd say <message>\n");
653 sprint(caller, " Where <message> is the string of text to say.\n");
654 return;
655 }
656 }
657}
658
659void ClientCommand_say_team(entity caller, int request, int argc, string command)
660{
661 switch (request)
662 {
664 {
665 if (argc >= 2)
666 Say(caller, true, NULL, substring(command, argv_start_index(1), argv_end_index(-1) - argv_start_index(1)), 1);
667 return; // never fall through to usage
668 }
669
670 default:
672 {
673 sprint(caller, "\nUsage:^3 cmd say_team <message>\n");
674 sprint(caller, " Where <message> is the string of text to say.\n");
675 return;
676 }
677 }
678}
679
680void ClientCommand_selectteam(entity caller, int request, int argc)
681{
682 switch (request)
683 {
685 {
686 if (argv(1) == "")
687 {
688 return;
689 }
690 if (!IS_CLIENT(caller) || intermission_running)
691 {
692 return;
693 }
694 if (!teamplay)
695 {
696 sprint(caller, "^7selectteam can only be used in teamgames\n");
697 return;
698 }
699 if (Player_GetForcedTeamIndex(caller) > 0)
700 {
701 sprint(caller, "^7selectteam can not be used as your team is forced\n");
702 return;
703 }
704 if (lockteams)
705 {
706 Send_Notification(NOTIF_ONE_ONLY, caller, MSG_INFO, INFO_TEAMCHANGE_LOCKED);
707 Send_Notification(NOTIF_ONE_ONLY, caller, MSG_CENTER, CENTER_TEAMCHANGE_LOCKED);
708 return;
709 }
710
711 // TEAMNUMBERS_THAT_ARENT_STUPID FIXME: 0 and -1 mean different things to different funcs
712 float team_num = Team_ColorToTeam(argv(1));
713 if (team_num == -1) // invalid
714 return;
715 int team_index = Team_TeamToIndex(team_num);
716
717 // players queued to change teams may leave the queue by selecting their current team or autoselect
718 if (caller.team > 0 && caller.wants_join && (!team_num || caller.team == team_num))
719 {
720 if (caller.killindicator_teamchange > 0)
721 return; // teams would be unbalanced by cancelling change during g_balance_kill_delay
722 Kill_Notification(NOTIF_ONE_ONLY, caller, MSG_CENTER, CPID_PREVENT_JOIN);
723 Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_QUIT_QUEUE, caller.netname);
724 caller.wants_join = caller.team_selected = 0;
725 return;
726 }
727
728 if (caller.team == team_num && team_num)
729 {
730 Send_Notification(NOTIF_ONE_ONLY, caller, MSG_INFO, INFO_TEAMCHANGE_SAME);
731 Send_Notification(NOTIF_ONE_ONLY, caller, MSG_CENTER, CENTER_TEAMCHANGE_SAME);
732 return;
733 }
734 if (team_num)
735 {
736 entity balance = TeamBalance_CheckAllowedTeams(caller);
737 if (!TeamBalance_IsTeamAllowed(balance, team_index))
738 {
739 Send_Notification(NOTIF_ONE_ONLY, caller, MSG_INFO, INFO_TEAMCHANGE_NOTALLOWED);
740 Send_Notification(NOTIF_ONE_ONLY, caller, MSG_CENTER, CENTER_TEAMCHANGE_NOTALLOWED);
741 TeamBalance_Destroy(balance);
742 return;
743 }
745 {
746 TeamBalance_GetTeamCounts(balance, caller);
747 if ((Team_IndexToBit(Team_TeamToIndex(team_num)) &
748 TeamBalance_FindBestTeams(balance, caller, false)) == 0)
749 {
750 Send_Notification(NOTIF_ONE_ONLY, caller, MSG_INFO, INFO_TEAMCHANGE_LARGERTEAM);
751 Send_Notification(NOTIF_ONE_ONLY, caller, MSG_CENTER, CENTER_TEAMCHANGE_LARGERTEAM);
752 TeamBalance_Destroy(balance);
753 return;
754 }
755 }
756 TeamBalance_Destroy(balance);
757 }
758
759 if (joinAllowed(caller, team_num ? team_index : -1))
760 ClientKill_TeamChange(caller, team_num ? team_num : -1);
761
762 return;
763 }
764 default:
765 sprint(caller, sprintf("Incorrect parameters for ^2%s^7\n", argv(0)));
767 {
768 sprint(caller, "\nUsage:^3 cmd selectteam <team>\n");
769 sprint(caller, " Where <team> is the prefered team to try and join.\n");
770 sprint(caller, " Full list of options here: red, blue, yellow, pink, auto.\n");
771 return;
772 }
773 }
774}
775
776void ClientCommand_selfstuff(entity caller, int request, string command)
777{
778 switch (request)
779 {
781 {
782 if (argv(1) != "")
783 {
784 stuffcmd(caller, substring(command, argv_start_index(1), argv_end_index(-1) - argv_start_index(1)));
785 return;
786 }
787 }
788
789 default:
790 sprint(caller, sprintf("Incorrect parameters for ^2%s^7\n", argv(0)));
792 {
793 sprint(caller, "\nUsage:^3 cmd selfstuff <command>\n");
794 sprint(caller, " Where <command> is the string to be stuffed to your client.\n");
795 return;
796 }
797 }
798}
799
800void ClientCommand_sentcvar(entity caller, int request, int argc)
801{
802 switch (request)
803 {
805 {
806 if (argc >= 3)
807 {
808 // NOTE: client-side settings do not exist on the server, this functionality has been deprecated
809 #if 0
810 if (argc == 2) // undefined cvar: use the default value on the server then
811 {
812 string s = strcat(substring(command, argv_start_index(0), argv_end_index(1) - argv_start_index(0)), " \"", cvar_defstring(argv(1)), "\"");
814 }
815 #endif
816
817 GetCvars(caller, CS_CVAR(caller), 1);
818
819 return;
820 }
821 }
822
823 default:
824 sprint(caller, sprintf("Incorrect parameters for ^2%s^7\n", argv(0)));
826 {
827 sprint(caller, "\nUsage:^3 cmd sentcvar <cvar> <arguments>\n");
828 sprint(caller, " Where <cvar> is the cvar plus arguments to send to the server.\n");
829 return;
830 }
831 }
832}
833
834void ClientCommand_spectate(entity caller, int request)
835{
836 switch (request)
837 {
839 {
840 if (!intermission_running && IS_CLIENT(caller))
841 {
842 if(argv(1) != "")
843 {
844 if (!(IS_SPEC(caller) || IS_OBSERVER(caller)))
845 sprint(caller, "cmd spectate <client> only works when you are spectator/observer\n");
846 else if (argv(1) == "0")
847 { // switch back to observing without leaving the CA team or join queue (like +attack2)
848 if (!IS_OBSERVER(caller))
849 {
850 TRANSMUTE(Observer, caller);
851 PutClientInServer(caller);
852 }
853 }
854 else if (autocvar_sv_spectate == 2 && !warmup_stage && !caller.vote_master)
855 Send_Notification(NOTIF_ONE_ONLY, caller, MSG_INFO, INFO_SPECTATE_SPEC_NOTALLOWED);
856 else
857 {
858 entity client = GetFilteredEntity(argv(1));
859 if (IS_PLAYER(client)
860 && VerifyClientEntity(client, false, false)
861 && Spectate(caller, client)) // mutator hook might say no
862 { }
863 else
864 sprint(caller, "Can't spectate ", argv(1), "^7\n");
865 }
866 return;
867 }
868
869 int mutator_returnvalue = MUTATOR_CALLHOOK(ClientCommand_Spectate, caller);
870
871 if (mutator_returnvalue == MUT_SPECCMD_RETURN) return;
872
873 if (caller.wants_join)
874 {
875 if (caller.killindicator_teamchange > 0)
876 return; // teams would be unbalanced by cancelling change during g_balance_kill_delay
877 Kill_Notification(NOTIF_ONE_ONLY, caller, MSG_CENTER, CPID_PREVENT_JOIN);
878 Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_QUIT_QUEUE, caller.netname);
879 caller.wants_join = caller.team_selected = 0;
880 }
881
882 if (IS_PLAYER(caller) || mutator_returnvalue == MUT_SPECCMD_FORCE)
883 {
885 ClientKill_TeamChange(caller, -2); // observe
886 else
887 Send_Notification(NOTIF_ONE_ONLY, caller, MSG_MULTI, SPECTATE_NOTALLOWED);
888 }
889 }
890 return; // never fall through to usage
891 }
892
893 default:
895 {
896 sprint(caller, "\nUsage:^3 cmd spectate [<client>]\n");
897 sprint(caller, " Where <client> can be the player to spectate.\n");
898 return;
899 }
900 }
901}
902
903void ClientCommand_suggestmap(entity caller, int request, int argc)
904{
905 switch (request)
906 {
908 {
909 if (argv(1) != "")
910 {
911 sprint(caller, strcat(MapVote_Suggest(caller, argv(1)), "\n"));
912 return;
913 }
914 }
915
916 default:
917 sprint(caller, sprintf("Incorrect parameters for ^2%s^7\n", argv(0)));
919 {
920 sprint(caller, "\nUsage:^3 cmd suggestmap <map>\n");
921 sprint(caller, " Where <map> is the name of the map to suggest.\n");
922 return;
923 }
924 }
925}
926
927void ClientCommand_tell(entity caller, int request, int argc, string command)
928{
929 switch (request)
930 {
932 {
933 if (argc >= 3)
934 {
935 if(!IS_CLIENT(caller) && IS_REAL_CLIENT(caller)) // connecting
936 {
937 print_to(caller, "You can't ^2tell^7 a message while connecting.");
938 return;
939 }
940
941 entity tell_to = GetIndexedEntity(argc, 1);
942 float tell_accepted = VerifyClientEntity(tell_to, true, false);
943
944 if (tell_accepted > 0) // the target is a real client
945 {
946 if (tell_to != caller) // and we're allowed to send to them :D
947 {
948 // workaround for argv indexes indexing ascii chars instead of utf8 chars
949 // In this case when the player name contains utf8 chars
950 // the message gets partially trimmed in the beginning.
951 // Potentially this bug affects any substring call that uses
952 // argv_start_index and argv_end_index.
953
954 string utf8_enable_save = cvar_string("utf8_enable");
955 cvar_set("utf8_enable", "0");
957 cvar_set("utf8_enable", utf8_enable_save);
958
959 Say(caller, false, tell_to, msg, true);
960 return;
961 }
962 else { print_to(caller, "You can't ^2tell^7 a message to yourself."); return; }
963 }
964 else if (argv(1) == "#0")
965 {
967 return;
968 }
969 else { print_to(caller, strcat("tell: ", GetClientErrorString(tell_accepted, argv(1)), ".")); return; }
970 }
971 }
972
973 default:
974 sprint(caller, sprintf("Incorrect parameters for ^2%s^7\n", argv(0)));
976 {
977 sprint(caller, "\nUsage:^3 cmd tell <client> <message>\n");
978 sprint(caller, " Where <client> is the entity number or name of the player to send <message> to.\n");
979 return;
980 }
981 }
982}
983
984void ClientCommand_unignore(entity caller, int request, int argc, string command)
985{
986 switch (request)
987 {
989 {
990 if (argc >= 2)
991 {
992 if(!argv(1) || argv(1) == "")
993 {
994 sprint(caller, "This command requires an argument. Use a player's name or their ID from the ^2status^7 command.\n");
995 return;
996 }
997
998 entity unignore_to = GetIndexedEntity(argc, 1);
999 float unignore_accepted = VerifyClientEntity(unignore_to, true, false);
1000
1001 if (unignore_accepted > 0 && IS_REAL_CLIENT(unignore_to)) // the target is a real client
1002 {
1003 if (unignore_to != caller)
1004 {
1005 // remove ignores both from db (if permanent) and list
1006 ignore_remove_player(caller, unignore_to, true);
1007 sprint(caller, "You can now receive messages from ", unignore_to.netname, " ^7again.\n");
1008 return;
1009 }
1010 else { sprint(caller, "You can't ^2unignore^7 yourself.\n"); }
1011 }
1012 else { print_to(caller, strcat("unignore: ", GetClientErrorString(unignore_accepted, argv(1)), ".\nUnable to stop ignoring this player, check their ID.")); }
1013
1014 return;
1015 }
1016 }
1017
1018 default:
1019 sprint(caller, sprintf("Incorrect parameters for ^2%s^7\n", argv(0)));
1020 case CMD_REQUEST_USAGE:
1021 {
1022 sprint(caller, "\nUsage:^3 cmd unignore <client>\n");
1023 sprint(caller, " Where <client> is the entity number or name of the player to stop ignoring when is keeping out of personal chat log.\n");
1024 return;
1025 }
1026 }
1027}
1028
1029void ClientCommand_voice(entity caller, int request, int argc, string command)
1030{
1031 switch (request)
1032 {
1034 {
1035 if (argv(1) != "")
1036 {
1037 entity e = GetVoiceMessage(argv(1));
1038 if (!e)
1039 {
1040 sprint(caller, sprintf("Invalid voice. Use one of: %s\n", allvoicesamples));
1041 return;
1042 }
1043 if (IS_DEAD(caller))
1044 {
1045 // don't warn the caller when trying to taunt while dead, just don't play any sounds!
1046 // we still allow them to see warnings if it's invalid, so a dead player can find out the sounds in peace
1047 return;
1048 }
1049 if (IS_SPEC(caller) || IS_OBSERVER(caller))
1050 {
1051 // observers/spectators have no player model of their own to play taunts from
1052 // again, allow them to see warnings
1053 return;
1054 }
1055 string msg = "";
1056 if (argc >= 3)
1057 msg = substring(command, argv_start_index(2), argv_end_index(-1) - argv_start_index(2));
1058 VoiceMessage(caller, e, msg);
1059
1060 return;
1061 }
1062 }
1063
1064 default:
1065 sprint(caller, sprintf("Incorrect parameters for ^2%s^7\n", argv(0)));
1066 case CMD_REQUEST_USAGE:
1067 {
1068 sprint(caller, "\nUsage:^3 cmd voice <voicetype> [<message>]\n");
1069 sprint(caller, " <voicetype> is the type of voice message, it can be one of these:\n");
1070 sprint(caller, sprintf(" %s\n", allvoicesamples));
1071 sprint(caller, " and <message> is the text message to send.\n");
1072 return;
1073 }
1074 }
1075}
1076
1077/* use this when creating a new command, making sure to place it in alphabetical order... also,
1078** ADD ALL NEW COMMANDS TO commands.cfg WITH PROPER ALIASES IN THE SAME FASHION!
1079void ClientCommand_(entity caller, int request)
1080{
1081 switch(request)
1082 {
1083 case CMD_REQUEST_COMMAND:
1084 {
1085
1086 return; // never fall through to usage
1087 }
1088
1089 default:
1090 case CMD_REQUEST_USAGE:
1091 {
1092 sprint(caller, "\nUsage:^3 cmd \n");
1093 sprint(caller, " No arguments required.\n");
1094 return;
1095 }
1096 }
1097}
1098*/
1099
1100
1101// =====================================
1102// Macro system for networked commands
1103// =====================================
1104
1105// Do not hard code aliases for these, instead create them in commands.cfg... also: keep in alphabetical order, please ;)
1106CLIENT_COMMAND(autoswitch, "Whether or not to switch automatically when getting a better weapon") { ClientCommand_autoswitch(caller, request, arguments); }
1107CLIENT_COMMAND(clear_bestcptimes, "Clear all your best checkpoint times for this Race/CTS match") { ClientCommand_clear_bestcptimes(caller, request); }
1108CLIENT_COMMAND(clear_ignores, "Remove all existing ignores of players") { ClientCommand_clear_ignores(caller, request); }
1109CLIENT_COMMAND(clientversion, "Release version of the game") { ClientCommand_clientversion(caller, request, arguments); }
1110CLIENT_COMMAND(ignore, "Ignore a player in the game keeping them out of your personal chat log") { ClientCommand_ignore(caller, request, arguments, command); }
1111CLIENT_COMMAND(join, "Become a player in the game") { ClientCommand_join(caller, request); }
1112CLIENT_COMMAND(kill, "Become a member of the dead") { ClientCommand_kill(caller, request); }
1113CLIENT_COMMAND(minigame, "Start a minigame") { ClientCommand_minigame(caller, request, arguments, command); }
1114CLIENT_COMMAND(mv_getpicture, "Retrieve mapshot picture from the server") { ClientCommand_mv_getpicture(caller, request, arguments); }
1115CLIENT_COMMAND(physics, "Change physics set") { ClientCommand_physics(caller, request, arguments); }
1116CLIENT_COMMAND(ready, "Qualify as ready to end warmup-stage") { ClientCommand_ready(caller, request); }
1117CLIENT_COMMAND(say, "Send a public chat message to all players") { ClientCommand_say(caller, request, arguments, command); }
1118CLIENT_COMMAND(say_team, "Send a chat message to all teammates") { ClientCommand_say_team(caller, request, arguments, command); }
1119CLIENT_COMMAND(selectteam, "Attempt to choose a team to join into") { ClientCommand_selectteam(caller, request, arguments); }
1120CLIENT_COMMAND(selfstuff, "Stuffcmd a command to your own client") { ClientCommand_selfstuff(caller, request, command); }
1121CLIENT_COMMAND(sentcvar, "New system for sending a client cvar to the server") { ClientCommand_sentcvar(caller, request, arguments); }
1122CLIENT_COMMAND(spectate, "Become a spectator") { ClientCommand_spectate(caller, request); }
1123CLIENT_COMMAND(suggestmap, "Suggest a map to appear at the map voting screen") { ClientCommand_suggestmap(caller, request, arguments); }
1124CLIENT_COMMAND(tell, "Send a private chat message to a player which may be visible to server admins") { ClientCommand_tell(caller, request, arguments, command); }
1125CLIENT_COMMAND(voice, "Send voice message via sound") { ClientCommand_voice(caller, request, arguments, command); }
1126CLIENT_COMMAND(unignore, "Remove an existing ignore of a player") { ClientCommand_unignore(caller, request, arguments, command); }
1127CLIENT_COMMAND(wpeditor, "Waypoint editor commands") { ClientCommand_wpeditor(caller, request, arguments); }
1128
1130{
1131 FOREACH(CLIENT_COMMANDS, true, { print_to(caller, sprintf(" ^2%s^7: %s", it.m_name, it.m_description)); });
1132}
1133
1134float ClientCommand_macro_command(int argc, entity caller, string command)
1135{
1136 string c = strtolower(argv(0));
1137 FOREACH(CLIENT_COMMANDS, it.m_name == c, {
1138 it.m_invokecmd(it, CMD_REQUEST_COMMAND, caller, argc, command);
1139 return true;
1140 });
1141
1142 return false;
1143}
1144
1145float ClientCommand_macro_usage(int argc, entity caller)
1146{
1147 string c = strtolower(argv(1));
1148 FOREACH(CLIENT_COMMANDS, it.m_name == c, {
1149 it.m_invokecmd(it, CMD_REQUEST_USAGE, caller, argc, "");
1150 return true;
1151 });
1152
1153 return false;
1154}
1155
1157{
1158 FOREACH(CLIENT_COMMANDS, true, { CMD_Write_Alias("qc_cmd_cmd", it.m_name, it.m_description); });
1159}
1160
1161// ======================================
1162// Main Function Called By Engine (cmd)
1163// ======================================
1164// If this function exists, server game code parses clientcommand before the engine code gets it.
1165
1166void SV_ParseClientCommand(entity this, string command)
1167{
1168 // If invalid UTF-8, don't even parse it
1169 string command2 = "";
1170 float len = strlen(command);
1171 float i;
1172 for (i = 0; i < len; ++i)
1173 command2 = strcat(command2, chr2str(str2chr(command, i)));
1174 if (command != command2) return;
1175
1176 // if we're banned, don't even parse the command
1177 if (Ban_MaybeEnforceBanOnce(this)) return;
1178
1179 int argc = tokenize_console(command);
1180
1181 // Guide for working with argc arguments by example:
1182 // argc: 1 - 2 - 3 - 4
1183 // argv: 0 - 1 - 2 - 3
1184 // cmd vote - master - login - password
1185
1186 // for floodcheck
1187 switch (strtolower(argv(0)))
1188 {
1189 // exempt commands which are not subject to floodcheck
1190 case "begin": break; // handled by engine in host_cmd.c
1191 case "download": break; // handled by engine in cl_parse.c
1192 case "mv_getpicture": break; // handled by server in this file
1193 case "wpeditor": break; // handled by server in this file
1194 case "pause": break; // handled by engine in host_cmd.c
1195 case "prespawn": break; // handled by engine in host_cmd.c
1196 case "sentcvar": break; // handled by server in this file
1197 case "spawn": break; // handled by engine in host_cmd.c
1198 case "say": case "say_team": case "tell": break; // chat has its own flood control in chat.qc
1199 case "minigame": // flood control only for common commands
1200 string arg = argv(1);
1201 if (arg == "")
1202 goto flood_control;
1203 for (int i = 0; i < MINIGAME_COMMON_CMD_COUNT; ++i)
1204 {
1205 if (MINIGAME_COMMON_CMD[i] == arg)
1206 goto flood_control;
1207 }
1208 // if we get here we haven't found any common command, so no flood control for other commands
1209 // individual minigame commands shouldn't be limited for gameplay reasons
1210 // FIXME unknown/wrong minigame commands have no flood control
1211 break;
1212 case "color": case "topcolor": case "bottomcolor": // handled by engine in host_cmd.c
1213 if(!IS_CLIENT(this)) // on connection
1214 {
1215 // since gamecode doesn't have any calls earlier than this, do the connecting message here
1216 Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_CONNECTING, this.netname);
1217 }
1218 if(teamplay)
1219 return;
1220 break;
1221 case "c2s": Net_ClientCommand(this, command); return; // handled by net.qh
1222
1223 // on connection, client sends all of these
1224 case "name": case "rate": case "rate_burstsize": case "playermodel": case "playerskin": case "clientversion":
1225 if(!IS_CLIENT(this)) break;
1226 // else fall through to default: flood control
1227 default:
1228 LABEL(flood_control)
1229 if(MUTATOR_CALLHOOK(ClientCommand_FloodControl, this, strtolower(argv(0)), argc, command))
1230 break; // a mutator has prevented flood control
1231
1232 // this is basically the same as the chat flood control
1233 entity store = IS_CLIENT(this) ? CS(this) : this; // unfortunately, we need to store these on the client initially
1234 // NOTE: using mod_time instead of time here to avoid initializing both this.cmd_floodtime
1235 // and CS(this).cmd_floodtime to -(antispam_count * antispam_time) (or -999999)
1237 if (mod_time < store.cmd_floodtime)
1238 {
1239 sprint(this, strcat("^3CMD FLOOD CONTROL: wait ^1", ftos(store.cmd_floodtime - mod_time),
1240 "^3 seconds, command was: ", command, "\n"));
1241 return; // too much spam, halt
1242 }
1243 else
1244 // micro-optimization: replaced mod_time - max_delay with time here as they are equal
1245 store.cmd_floodtime = max(gettime(GETTIME_FRAMESTART), store.cmd_floodtime) + autocvar_sv_clientcommand_antispam_time;
1246 break; // continue, as we're not flooding yet
1247 }
1248
1249 /* NOTE: should this be disabled? It can be spammy perhaps, but hopefully it's okay for now */
1250 if (argv(0) == "help")
1251 {
1252 if (argc == 1)
1253 {
1254 sprint(this, "\nClient networked commands:\n");
1256
1257 sprint(this, "\nCommon networked commands:\n");
1259
1260 sprint(this, "\nUsage:^3 cmd <command>^7, where possible commands are listed above.\n");
1261 sprint(this, "For help about a specific command, type cmd help <command>\n");
1262 return;
1263 }
1264 else if (CommonCommand_macro_usage(argc, this)) // Instead of trying to call a command, we're going to see detailed information about it
1265 {
1266 return;
1267 }
1268 else if (ClientCommand_macro_usage(argc, this)) // same, but for normal commands now
1269 {
1270 return;
1271 }
1272 }
1273 else if (MUTATOR_CALLHOOK(SV_ParseClientCommand, this, strtolower(argv(0)), argc, command))
1274 {
1275 return; // handled by a mutator
1276 }
1277 else if (CheatCommand(this, argc))
1278 {
1279 return; // handled by server/cheats.qc
1280 }
1281 else if (CommonCommand_macro_command(argc, this, command))
1282 {
1283 return; // handled by server/command/common.qc
1284 }
1285 else if (ClientCommand_macro_command(argc, this, command)) // continue as usual and scan for normal commands
1286 {
1287 return; // handled by one of the above ClientCommand_* functions
1288 }
1289 else
1290 {
1291 clientcommand(this, command);
1292 }
1293}
void waypoint_lock(entity pl)
Definition waypoints.qc:270
void waypoint_schedulerelinkall()
void waypoint_getSymmetricalAxis_cmd(entity caller, bool save, int arg_idx)
Definition waypoints.qc:137
void waypoint_getSymmetricalOrigin_cmd(entity caller, bool save, int arg_idx)
Definition waypoints.qc:169
void waypoint_unreachable(entity pl)
Definition waypoints.qc:28
void waypoint_remove_fromeditor(entity pl)
Definition waypoints.qc:838
void waypoint_spawn_fromeditor(entity pl, bool at_crosshair, bool is_jump_wp, bool is_crouch_wp, bool is_support_wp)
Definition waypoints.qc:568
void waypoint_saveall()
void waypoint_start_hardwiredlink(entity pl, bool at_crosshair)
Definition waypoints.qc:532
#define MUTATOR_CALLHOOK(id,...)
Definition base.qh:143
ERASEABLE float InterpretBoolean(string input)
Definition bool.qh:13
float CheatCommand(entity this, int argc)
Definition cheats.qc:291
var entity(vector mins, vector maxs,.entity tofield) findbox_tofield_OrFallback
#define CLIENT_COMMAND(id, description)
Definition cl_cmd.qh:16
float GetResource(entity e, Resource res_type)
Returns the current amount of resource the given entity has.
string netname
Definition powerups.qc:20
bool ready
Definition main.qh:88
string ignore_list
Definition main.qh:130
bool warmup_stage
Definition main.qh:120
void ClientKill_TeamChange(entity this, float targetteam)
Definition clientkill.qc:95
void ignore_list_update_on_connection(entity this)
Updates ignore list of all the players.
Definition cmd.qc:153
void ClientCommand_unignore(entity caller, int request, int argc, string command)
Definition cmd.qc:984
bool ignore_playerinlist(entity this, entity pl)
Checks if pl is ignored by this (permanently or for the current match)
Definition cmd.qc:134
void ClientCommand_wpeditor(entity caller, int request, int argc)
Definition cmd.qc:341
void ignore_list_send(entity this)
Definition cmd.qc:168
void ClientCommand_clear_bestcptimes(entity caller, int request)
Definition cmd.qc:253
void ignore_remove_player(entity this, entity ignore, bool from_db_too)
Removes a player from the ignore list of another player.
Definition cmd.qc:47
void ClientCommand_sentcvar(entity caller, int request, int argc)
Definition cmd.qc:800
float ClientCommand_macro_usage(int argc, entity caller)
Definition cmd.qc:1145
void ClientCommand_kill(entity caller, int request)
Definition cmd.qc:535
void ClientCommand_macro_write_aliases(float fh)
Definition cmd.qc:1156
int ignore_add_player(entity this, entity ignore, bool to_db_too)
Adds a player to the ignore list of another player.
Definition cmd.qc:88
void ClientCommand_physics(entity caller, int request, int argc)
Definition cmd.qc:565
void ClientCommand_macro_help(entity caller)
Definition cmd.qc:1129
void ClientCommand_tell(entity caller, int request, int argc, string command)
Definition cmd.qc:927
void ClientCommand_clear_ignores(entity caller, int request)
Definition cmd.qc:226
void ClientCommand_ignore(entity caller, int request, int argc, string command)
Definition cmd.qc:452
void ClientCommand_selectteam(entity caller, int request, int argc)
Definition cmd.qc:680
void ClientCommand_join(entity caller, int request)
Definition cmd.qc:507
float ClientCommand_macro_command(int argc, entity caller, string command)
Definition cmd.qc:1134
void ClientCommand_say(entity caller, int request, int argc, string command)
Definition cmd.qc:639
bool ignore_playerindb(entity this, entity pl)
Checks if pl is permanently ignored by this.
Definition cmd.qc:117
void ClientCommand_autoswitch(entity caller, int request, int argc)
Definition cmd.qc:201
void ClientCommand_ready(entity caller, int request)
Definition cmd.qc:605
void ClientCommand_say_team(entity caller, int request, int argc, string command)
Definition cmd.qc:659
void ClientCommand_voice(entity caller, int request, int argc, string command)
Definition cmd.qc:1029
void ClientCommand_clientversion(entity caller, int request, int argc)
Definition cmd.qc:273
void ignore_clearall(entity this)
Definition cmd.qc:176
void ClientCommand_suggestmap(entity caller, int request, int argc)
Definition cmd.qc:903
void ClientCommand_selfstuff(entity caller, int request, string command)
Definition cmd.qc:776
void ClientCommand_mv_getpicture(entity caller, int request, int argc)
Definition cmd.qc:316
void ClientCommand_spectate(entity caller, int request)
Definition cmd.qc:834
string MapVote_Suggest(entity this, string m)
Definition mapvoting.qc:130
float ignore_list_send_time
Definition cmd.qh:9
const int IGNORE_LIST_SEND_NOW
Definition cmd.qh:8
const int IGNORE_MAXPLAYERS
Definition cmd.qh:11
float autocvar_sv_clientcommand_antispam_time
Definition cmd.qh:3
int autocvar_sv_clientcommand_antispam_count
Definition cmd.qh:4
const int CMD_REQUEST_COMMAND
Definition command.qh:3
const int CMD_REQUEST_USAGE
Definition command.qh:4
bool Physics_Valid(string thecvar)
Definition player.qc:18
#define IS_CLIENT(s)
Definition player.qh:242
#define IS_DEAD(s)
Definition player.qh:245
string autocvar_g_physics_clientselect_options
Definition player.qh:39
bool autocvar_g_physics_clientselect
Definition player.qh:42
#define IS_PLAYER(s)
Definition player.qh:243
float game_stopped
Definition stats.qh:81
string playername(string thename, int teamid, bool team_colorize)
Definition util.qc:2082
string strtolower(string s)
#define LABEL(id)
Definition compiler.qh:34
float time
float GETTIME_FRAMESTART
string crypto_idfp
#define str2chr
#define argv_end_index
#define strlen
#define tokenize_console
#define argv_start_index
#define chr2str
#define CMD_Write_Alias(execute, command, description)
Definition generic.qh:34
void GetCvars(entity this, entity store, int f)
entity GetVoiceMessage(string type)
string allvoicesamples
#define VoiceMessage(this, def, msg)
bool intermission_running
bool Ban_MaybeEnforceBanOnce(entity client)
Definition ipban.qc:471
#define FOREACH_WORD(words, cond, body)
Definition iter.qh:33
#define FOREACH(list, cond, body)
Definition iter.qh:19
#define ClientKill
Definition _all.inc:250
#define SV_ParseClientCommand
Definition _all.inc:284
#define PutClientInServer
Definition _all.inc:246
void Net_ClientCommand(entity sender, string command)
Definition net.qh:177
string trigger_magicear_processmessage_forallears(entity source, float teamsay, entity privatesay, string msgin)
Definition magicear.qc:149
#define db_remove(db, key)
Definition map.qh:98
ERASEABLE string db_get(int db, string key)
Definition map.qh:91
ERASEABLE void db_put(int db, string key, string value)
Definition map.qh:101
bool autocvar_g_campaign
Definition menu.qc:747
void cvar_set(string name, string value)
float stof(string val,...)
string substring(string s, float start, float length)
void sprint(float clientnum, string text,...)
float gettime(void)
void bprint(string text,...)
void clientcommand(float client, string s)
const string cvar_string(string name)
string ftos(float f)
const string cvar_defstring(string name)
string argv(float n)
float max(float f,...)
#define etof(e)
Definition misc.qh:25
s1 s2 s1 s2 FLAG s1 s2 FLAG spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 CPID_PREVENT_JOIN
Definition all.inc:730
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:1573
void Kill_Notification(NOTIF broadcast, entity client, MSG net_type, CPID net_cpid)
Definition all.qc:1537
#define TRANSMUTE(cname, this,...)
Definition oo.qh:136
#define NULL
Definition post.qh:14
#define stuffcmd(cl,...)
Definition progsdefs.qh:23
int Say(entity source, int teamsay, entity privatesay, string msgin, bool floodcontrol)
message "": do not say, just test flood control return value: 1 = accept 0 = reject -1 = fake accept
Definition chat.qc:27
bool Spectate(entity this, entity pl)
Definition client.qc:1971
bool joinAllowed(entity this, int team_index)
Definition client.qc:2230
bool PlayerInList(entity player, string list)
Definition client.qc:1045
void Join(entity this, bool queued_join)
it's assumed this isn't called for bots (campaign_bots_may_start, centreprints)
Definition client.qc:2068
void ClientData_Touch(entity e, bool to_spectators_too)
Definition client.qc:185
float autocvar_gameversion_min
Definition client.qh:48
bool autocvar_sv_spectate
Definition client.qh:57
const int MIN_SPEC_TIME
Definition client.qh:403
float jointime
Definition client.qh:66
float autocvar_gameversion_max
Definition client.qh:49
void print_to(entity to, string input)
Definition common.qc:171
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
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
void ReadyCount()
Definition vote.qc:553
void MapVote_SendPicture(entity to, int id)
Definition mapvoting.qc:332
@ MUT_SPECCMD_RETURN
Definition events.qh:1005
@ MUT_SPECCMD_FORCE
Definition events.qh:1006
void race_ClearPlayerRecords(entity player)
Definition race.qc:1276
int g_race_qualifying
Definition race.qh:13
#define CS_CVAR(this)
Definition state.qh:51
ClientState CS(Client this)
Definition state.qh:47
#define strcpy(this, s)
Definition string.qh:52
ERASEABLE string cons(string a, string b)
Definition string.qh:276
void ClientCommand_minigame(entity caller, int request, int argc, string command)
string MINIGAME_COMMON_CMD[MINIGAME_COMMON_CMD_COUNT]
@ MINIGAME_COMMON_CMD_COUNT
#define INGAME_JOINED(it)
Definition sv_rules.qh:25
void TeamBalance_Destroy(entity balance)
Destroy the team balance entity.
Definition teamplay.qc:599
void TeamBalance_GetTeamCounts(entity balance, entity ignore)
Counts the number of players and various other information about each team.
Definition teamplay.qc:846
int Player_GetForcedTeamIndex(entity player)
Returns the index of the forced team of the given player.
Definition teamplay.qc:318
entity TeamBalance_CheckAllowedTeams(entity for_whom)
Checks whether the player can join teams according to global configuration and mutator settings.
Definition teamplay.qc:459
bool TeamBalance_IsTeamAllowed(entity balance, int index)
Returns whether the team change to the specified team is allowed.
Definition teamplay.qc:826
int TeamBalance_FindBestTeams(entity balance, entity player, bool use_score)
Returns the bitmask of the teams that will make the game most balanced if the player joins any of the...
Definition teamplay.qc:984
bool autocvar_g_balance_teams_prevent_imbalance
Definition teamplay.qh:8
bool autocvar_g_balance_teams
Definition teamplay.qh:7
bool lockteams
Definition teamplay.qh:15
int Team_TeamToIndex(int team_num)
Converts team value into team index.
Definition teams.qh:184
bool teamplay
Definition teams.qh:59
int Team_IndexToBit(int index)
Converts team index into bit value that is used in team bitmasks.
Definition teams.qh:211
float Team_ColorToTeam(string team_color)
Definition teams.qh:116
#define IS_OBSERVER(v)
Definition utils.qh:11
#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:50
bool waypointeditor_enabled
Definition waypoints.qh:3
float ServerProgsDB
Definition world.qh:128