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 (caller.team == -666) // because FIXME join and selectteam are separate commands
516 caller.team = -1;
517 else if (joinAllowed(caller, caller.wants_join))
518 Join(caller, teamplay);
519 else if(time < CS(caller).jointime + MIN_SPEC_TIME)
520 CS(caller).autojoin_checked = -1;
521 }
522 CS(caller).parm_idlesince = time;
523
524 return; // never fall through to usage
525 }
526
527 default:
529 {
530 sprint(caller, "\nUsage:^3 cmd join\n");
531 sprint(caller, " No arguments required.\n");
532 return;
533 }
534 }
535}
536
537void ClientCommand_kill(entity caller, int request)
538{
539 switch (request)
540 {
542 {
543 if(IS_SPEC(caller) || IS_OBSERVER(caller))
544 return; // no point warning about this, command does nothing
545
546 if(GetResource(caller, RES_HEALTH) <= 0)
547 {
548 sprint(caller, "Can't die - you are already dead!\n");
549 return;
550 }
551
552 ClientKill(caller);
553
554 return; // never fall through to usage
555 }
556
557 default:
559 {
560 sprint(caller, "\nUsage:^3 cmd kill\n");
561 sprint(caller, " No arguments required.\n");
562 return;
563 }
564 }
565}
566
567void ClientCommand_physics(entity caller, int request, int argc)
568{
569 switch (request)
570 {
572 {
573 string command = strtolower(argv(1));
574
576 {
577 sprint(caller, "Client physics selection is currently disabled.\n");
578 return;
579 }
580
581 if (command == "list" || command == "help")
582 {
583 sprint(caller, strcat("Available physics sets: \n\n", autocvar_g_physics_clientselect_options, " default\n"));
584 return;
585 }
586
587 if (Physics_Valid(command) || command == "default")
588 {
589 stuffcmd(caller, strcat("\nseta cl_physics ", command, "\n"));
590 sprint(caller, strcat("^2Physics set successfully changed to ^3", command, "\n"));
591 return;
592 }
593 }
594
595 default:
596 sprint(caller, strcat("Current physics set: ^3", CS_CVAR(caller).cvar_cl_physics, "\n"));
598 {
599 sprint(caller, "\nUsage:^3 cmd physics <physics>\n");
600 sprint(caller, " See 'cmd physics list' for available physics sets.\n");
601 sprint(caller, " Argument 'default' resets to standard physics.\n");
602 return;
603 }
604 }
605}
606
607void ClientCommand_ready(entity caller, int request)
608{
609 switch (request)
610 {
612 {
614 if (IS_PLAYER(caller) || INGAME_JOINED(caller))
615 {
616 if (caller.ready) // toggle
617 {
618 caller.ready = false;
619 bprint(playername(caller.netname, caller.team, false), "^2 is ^1NOT^2 ready\n");
620 }
621 else
622 {
623 caller.ready = true;
624 bprint(playername(caller.netname, caller.team, false), "^2 is ready\n");
625 }
626 ReadyCount();
627 }
628 return; // never fall through to usage
629 }
630
631 default:
633 {
634 sprint(caller, "\nUsage:^3 cmd ready\n");
635 sprint(caller, " No arguments required.\n");
636 return;
637 }
638 }
639}
640
641void ClientCommand_say(entity caller, int request, int argc, string command)
642{
643 switch (request)
644 {
646 {
647 if (argc >= 2) Say(caller, false, NULL, substring(command, argv_start_index(1), argv_end_index(-1) - argv_start_index(1)), 1);
648 return; // never fall through to usage
649 }
650
651 default:
653 {
654 sprint(caller, "\nUsage:^3 cmd say <message>\n");
655 sprint(caller, " Where <message> is the string of text to say.\n");
656 return;
657 }
658 }
659}
660
661void ClientCommand_say_team(entity caller, int request, int argc, string command)
662{
663 switch (request)
664 {
666 {
667 if (argc >= 2)
668 Say(caller, true, NULL, substring(command, argv_start_index(1), argv_end_index(-1) - argv_start_index(1)), 1);
669 return; // never fall through to usage
670 }
671
672 default:
674 {
675 sprint(caller, "\nUsage:^3 cmd say_team <message>\n");
676 sprint(caller, " Where <message> is the string of text to say.\n");
677 return;
678 }
679 }
680}
681
682void ClientCommand_selectteam(entity caller, int request, int argc)
683{
684 switch (request)
685 {
687 {
688 if (argv(1) == "")
689 {
690 return;
691 }
692 if (!IS_CLIENT(caller) || intermission_running)
693 {
694 return;
695 }
696 if (!teamplay)
697 {
698 sprint(caller, "^7selectteam can only be used in teamgames\n");
699 return;
700 }
701 if (Player_GetForcedTeamIndex(caller) > 0)
702 {
703 sprint(caller, "^7selectteam can not be used as your team is forced\n");
704 return;
705 }
706 if (lockteams)
707 {
708 Send_Notification(NOTIF_ONE_ONLY, caller, MSG_INFO, INFO_TEAMCHANGE_LOCKED);
709 Send_Notification(NOTIF_ONE_ONLY, caller, MSG_CENTER, CENTER_TEAMCHANGE_LOCKED);
710 return;
711 }
712
713 // TEAMNUMBERS_THAT_ARENT_STUPID FIXME: 0 and -1 mean different things to different funcs
714 float team_num = Team_ColorToTeam(argv(1));
715 if (team_num == -1) // invalid
716 return;
717 int team_index = Team_TeamToIndex(team_num);
718
719 // players queued to change teams may leave the queue by selecting their current team or autoselect
720 if (caller.team > 0 && caller.wants_join && (!team_num || caller.team == team_num))
721 {
722 if (caller.killindicator_teamchange > 0)
723 return; // teams would be unbalanced by cancelling change during g_balance_kill_delay
724 Kill_Notification(NOTIF_ONE_ONLY, caller, MSG_CENTER, CPID_PREVENT_JOIN);
725 Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_QUIT_QUEUE, caller.netname);
726 caller.wants_join = caller.team_selected = 0;
727 return;
728 }
729
730 if (caller.team == team_num && team_num)
731 {
732 Send_Notification(NOTIF_ONE_ONLY, caller, MSG_INFO, INFO_TEAMCHANGE_SAME);
733 Send_Notification(NOTIF_ONE_ONLY, caller, MSG_CENTER, CENTER_TEAMCHANGE_SAME);
734 return;
735 }
736 if (team_num)
737 {
738 entity balance = TeamBalance_CheckAllowedTeams(caller);
739 if (!TeamBalance_IsTeamAllowed(balance, team_index))
740 {
741 Send_Notification(NOTIF_ONE_ONLY, caller, MSG_INFO, INFO_TEAMCHANGE_NOTALLOWED);
742 Send_Notification(NOTIF_ONE_ONLY, caller, MSG_CENTER, CENTER_TEAMCHANGE_NOTALLOWED);
743 TeamBalance_Destroy(balance);
744 return;
745 }
747 && (!autocvar_g_balance_teams_queue || caller.team > 0))
748 {
749 TeamBalance_GetTeamCounts(balance, caller);
750 if ((Team_IndexToBit(Team_TeamToIndex(team_num)) & TeamBalance_FindBestTeams(balance, caller, true)) == 0)
751 {
752 if (caller.team <= 0)
753 caller.team = -666; // workaround: cancel the subsequent join command
754 Send_Notification(NOTIF_ONE_ONLY, caller, MSG_INFO, INFO_TEAMCHANGE_STRONGERTEAM);
755 Send_Notification(NOTIF_ONE_ONLY, caller, MSG_CENTER, CENTER_TEAMCHANGE_STRONGERTEAM);
756 TeamBalance_Destroy(balance);
757 return;
758 }
759 }
760 TeamBalance_Destroy(balance);
761 }
762
763 if (joinAllowed(caller, team_num ? team_index : -1))
764 ClientKill_TeamChange(caller, team_num ? team_num : -1);
765
766 return;
767 }
768 default:
769 sprint(caller, sprintf("Incorrect parameters for ^2%s^7\n", argv(0)));
771 {
772 sprint(caller, "\nUsage:^3 cmd selectteam <team>\n");
773 sprint(caller, " Where <team> is the prefered team to try and join.\n");
774 sprint(caller, " Full list of options here: red, blue, yellow, pink, auto.\n");
775 return;
776 }
777 }
778}
779
780void ClientCommand_selfstuff(entity caller, int request, string command)
781{
782 switch (request)
783 {
785 {
786 if (argv(1) != "")
787 {
788 stuffcmd(caller, substring(command, argv_start_index(1), argv_end_index(-1) - argv_start_index(1)));
789 return;
790 }
791 }
792
793 default:
794 sprint(caller, sprintf("Incorrect parameters for ^2%s^7\n", argv(0)));
796 {
797 sprint(caller, "\nUsage:^3 cmd selfstuff <command>\n");
798 sprint(caller, " Where <command> is the string to be stuffed to your client.\n");
799 return;
800 }
801 }
802}
803
804void ClientCommand_sentcvar(entity caller, int request, int argc)
805{
806 switch (request)
807 {
809 {
810 if (argc >= 3)
811 {
812 // NOTE: client-side settings do not exist on the server, this functionality has been deprecated
813 #if 0
814 if (argc == 2) // undefined cvar: use the default value on the server then
815 {
816 string s = strcat(substring(command, argv_start_index(0), argv_end_index(1) - argv_start_index(0)), " \"", cvar_defstring(argv(1)), "\"");
818 }
819 #endif
820
821 GetCvars(caller, CS_CVAR(caller), 1);
822
823 return;
824 }
825 }
826
827 default:
828 sprint(caller, sprintf("Incorrect parameters for ^2%s^7\n", argv(0)));
830 {
831 sprint(caller, "\nUsage:^3 cmd sentcvar <cvar> <arguments>\n");
832 sprint(caller, " Where <cvar> is the cvar plus arguments to send to the server.\n");
833 return;
834 }
835 }
836}
837
838void ClientCommand_spectate(entity caller, int request)
839{
840 switch (request)
841 {
843 {
844 if (!intermission_running && IS_CLIENT(caller))
845 {
846 if(argv(1) != "")
847 {
848 if (!(IS_SPEC(caller) || IS_OBSERVER(caller)))
849 sprint(caller, "cmd spectate <client> only works when you are spectator/observer\n");
850 else if (argv(1) == "0")
851 { // switch back to observing without leaving the CA team or join queue (like +attack2)
852 if (!IS_OBSERVER(caller))
853 {
854 TRANSMUTE(Observer, caller);
855 PutClientInServer(caller);
856 }
857 }
858 else if (autocvar_sv_spectate == 2 && !warmup_stage && !caller.vote_master)
859 Send_Notification(NOTIF_ONE_ONLY, caller, MSG_INFO, INFO_SPECTATE_SPEC_NOTALLOWED);
860 else
861 {
862 entity client = GetFilteredEntity(argv(1));
863 if (IS_PLAYER(client)
864 && VerifyClientEntity(client, false, false)
865 && Spectate(caller, client)) // mutator hook might say no
866 { }
867 else
868 sprint(caller, "Can't spectate ", argv(1), "^7\n");
869 }
870 return;
871 }
872
873 int mutator_returnvalue = MUTATOR_CALLHOOK(ClientCommand_Spectate, caller);
874
875 if (mutator_returnvalue == MUT_SPECCMD_RETURN) return;
876
877 if (caller.wants_join)
878 {
879 if (caller.killindicator_teamchange > 0)
880 return; // teams would be unbalanced by cancelling change during g_balance_kill_delay
881 Kill_Notification(NOTIF_ONE_ONLY, caller, MSG_CENTER, CPID_PREVENT_JOIN);
882 Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_QUIT_QUEUE, caller.netname);
883 caller.wants_join = caller.team_selected = 0;
884 }
885
886 if (IS_PLAYER(caller) || mutator_returnvalue == MUT_SPECCMD_FORCE)
887 {
889 ClientKill_TeamChange(caller, -2); // observe
890 else
891 Send_Notification(NOTIF_ONE_ONLY, caller, MSG_MULTI, SPECTATE_NOTALLOWED);
892 }
893 }
894 return; // never fall through to usage
895 }
896
897 default:
899 {
900 sprint(caller, "\nUsage:^3 cmd spectate [<client>]\n");
901 sprint(caller, " Where <client> can be the player to spectate.\n");
902 return;
903 }
904 }
905}
906
907void ClientCommand_suggestmap(entity caller, int request, int argc)
908{
909 switch (request)
910 {
912 {
913 if (argv(1) != "")
914 {
915 sprint(caller, strcat(MapVote_Suggest(caller, argv(1)), "\n"));
916 return;
917 }
918 }
919
920 default:
921 sprint(caller, sprintf("Incorrect parameters for ^2%s^7\n", argv(0)));
923 {
924 sprint(caller, "\nUsage:^3 cmd suggestmap <map>\n");
925 sprint(caller, " Where <map> is the name of the map to suggest.\n");
926 return;
927 }
928 }
929}
930
931void ClientCommand_tell(entity caller, int request, int argc, string command)
932{
933 switch (request)
934 {
936 {
937 if (argc >= 3)
938 {
939 if(!IS_CLIENT(caller) && IS_REAL_CLIENT(caller)) // connecting
940 {
941 print_to(caller, "You can't ^2tell^7 a message while connecting.");
942 return;
943 }
944
945 entity tell_to = GetIndexedEntity(argc, 1);
946 float tell_accepted = VerifyClientEntity(tell_to, true, false);
947
948 if (tell_accepted > 0) // the target is a real client
949 {
950 if (tell_to != caller) // and we're allowed to send to them :D
951 {
952 // workaround for argv indexes indexing ascii chars instead of utf8 chars
953 // In this case when the player name contains utf8 chars
954 // the message gets partially trimmed in the beginning.
955 // Potentially this bug affects any substring call that uses
956 // argv_start_index and argv_end_index.
957
958 string utf8_enable_save = cvar_string("utf8_enable");
959 cvar_set("utf8_enable", "0");
961 cvar_set("utf8_enable", utf8_enable_save);
962
963 Say(caller, false, tell_to, msg, true);
964 return;
965 }
966 else { print_to(caller, "You can't ^2tell^7 a message to yourself."); return; }
967 }
968 else if (argv(1) == "#0")
969 {
971 return;
972 }
973 else { print_to(caller, strcat("tell: ", GetClientErrorString(tell_accepted, argv(1)), ".")); return; }
974 }
975 }
976
977 default:
978 sprint(caller, sprintf("Incorrect parameters for ^2%s^7\n", argv(0)));
980 {
981 sprint(caller, "\nUsage:^3 cmd tell <client> <message>\n");
982 sprint(caller, " Where <client> is the entity number or name of the player to send <message> to.\n");
983 return;
984 }
985 }
986}
987
988void ClientCommand_unignore(entity caller, int request, int argc, string command)
989{
990 switch (request)
991 {
993 {
994 if (argc >= 2)
995 {
996 if(!argv(1) || argv(1) == "")
997 {
998 sprint(caller, "This command requires an argument. Use a player's name or their ID from the ^2status^7 command.\n");
999 return;
1000 }
1001
1002 entity unignore_to = GetIndexedEntity(argc, 1);
1003 float unignore_accepted = VerifyClientEntity(unignore_to, true, false);
1004
1005 if (unignore_accepted > 0 && IS_REAL_CLIENT(unignore_to)) // the target is a real client
1006 {
1007 if (unignore_to != caller)
1008 {
1009 // remove ignores both from db (if permanent) and list
1010 ignore_remove_player(caller, unignore_to, true);
1011 sprint(caller, "You can now receive messages from ", unignore_to.netname, " ^7again.\n");
1012 return;
1013 }
1014 else { sprint(caller, "You can't ^2unignore^7 yourself.\n"); }
1015 }
1016 else { print_to(caller, strcat("unignore: ", GetClientErrorString(unignore_accepted, argv(1)), ".\nUnable to stop ignoring this player, check their ID.")); }
1017
1018 return;
1019 }
1020 }
1021
1022 default:
1023 sprint(caller, sprintf("Incorrect parameters for ^2%s^7\n", argv(0)));
1024 case CMD_REQUEST_USAGE:
1025 {
1026 sprint(caller, "\nUsage:^3 cmd unignore <client>\n");
1027 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");
1028 return;
1029 }
1030 }
1031}
1032
1033void ClientCommand_voice(entity caller, int request, int argc, string command)
1034{
1035 switch (request)
1036 {
1038 {
1039 if (argv(1) != "")
1040 {
1041 entity e = GetVoiceMessage(argv(1));
1042 if (!e)
1043 {
1044 sprint(caller, sprintf("Invalid voice. Use one of: %s\n", allvoicesamples));
1045 return;
1046 }
1047 if (IS_DEAD(caller))
1048 {
1049 // don't warn the caller when trying to taunt while dead, just don't play any sounds!
1050 // we still allow them to see warnings if it's invalid, so a dead player can find out the sounds in peace
1051 return;
1052 }
1053 if (IS_SPEC(caller) || IS_OBSERVER(caller))
1054 {
1055 // observers/spectators have no player model of their own to play taunts from
1056 // again, allow them to see warnings
1057 return;
1058 }
1059 string msg = "";
1060 if (argc >= 3)
1061 msg = substring(command, argv_start_index(2), argv_end_index(-1) - argv_start_index(2));
1062 VoiceMessage(caller, e, msg);
1063
1064 return;
1065 }
1066 }
1067
1068 default:
1069 sprint(caller, sprintf("Incorrect parameters for ^2%s^7\n", argv(0)));
1070 case CMD_REQUEST_USAGE:
1071 {
1072 sprint(caller, "\nUsage:^3 cmd voice <voicetype> [<message>]\n");
1073 sprint(caller, " <voicetype> is the type of voice message, it can be one of these:\n");
1074 sprint(caller, sprintf(" %s\n", allvoicesamples));
1075 sprint(caller, " and <message> is the text message to send.\n");
1076 return;
1077 }
1078 }
1079}
1080
1081/* use this when creating a new command, making sure to place it in alphabetical order... also,
1082** ADD ALL NEW COMMANDS TO commands.cfg WITH PROPER ALIASES IN THE SAME FASHION!
1083void ClientCommand_(entity caller, int request)
1084{
1085 switch(request)
1086 {
1087 case CMD_REQUEST_COMMAND:
1088 {
1089
1090 return; // never fall through to usage
1091 }
1092
1093 default:
1094 case CMD_REQUEST_USAGE:
1095 {
1096 sprint(caller, "\nUsage:^3 cmd \n");
1097 sprint(caller, " No arguments required.\n");
1098 return;
1099 }
1100 }
1101}
1102*/
1103
1104
1105// =====================================
1106// Macro system for networked commands
1107// =====================================
1108
1109// Do not hard code aliases for these, instead create them in commands.cfg... also: keep in alphabetical order, please ;)
1110CLIENT_COMMAND(autoswitch, "Whether or not to switch automatically when getting a better weapon") { ClientCommand_autoswitch(caller, request, arguments); }
1111CLIENT_COMMAND(clear_bestcptimes, "Clear all your best checkpoint times for this Race/CTS match") { ClientCommand_clear_bestcptimes(caller, request); }
1112CLIENT_COMMAND(clear_ignores, "Remove all existing ignores of players") { ClientCommand_clear_ignores(caller, request); }
1113CLIENT_COMMAND(clientversion, "Release version of the game") { ClientCommand_clientversion(caller, request, arguments); }
1114CLIENT_COMMAND(ignore, "Ignore a player in the game keeping them out of your personal chat log") { ClientCommand_ignore(caller, request, arguments, command); }
1115CLIENT_COMMAND(join, "Become a player in the game") { ClientCommand_join(caller, request); }
1116CLIENT_COMMAND(kill, "Become a member of the dead") { ClientCommand_kill(caller, request); }
1117CLIENT_COMMAND(minigame, "Start a minigame") { ClientCommand_minigame(caller, request, arguments, command); }
1118CLIENT_COMMAND(mv_getpicture, "Retrieve mapshot picture from the server") { ClientCommand_mv_getpicture(caller, request, arguments); }
1119CLIENT_COMMAND(physics, "Change physics set") { ClientCommand_physics(caller, request, arguments); }
1120CLIENT_COMMAND(ready, "Qualify as ready to end warmup-stage") { ClientCommand_ready(caller, request); }
1121CLIENT_COMMAND(say, "Send a public chat message to all players") { ClientCommand_say(caller, request, arguments, command); }
1122CLIENT_COMMAND(say_team, "Send a chat message to all teammates") { ClientCommand_say_team(caller, request, arguments, command); }
1123CLIENT_COMMAND(selectteam, "Attempt to choose a team to join into") { ClientCommand_selectteam(caller, request, arguments); }
1124CLIENT_COMMAND(selfstuff, "Stuffcmd a command to your own client") { ClientCommand_selfstuff(caller, request, command); }
1125CLIENT_COMMAND(sentcvar, "New system for sending a client cvar to the server") { ClientCommand_sentcvar(caller, request, arguments); }
1126CLIENT_COMMAND(spectate, "Become a spectator") { ClientCommand_spectate(caller, request); }
1127CLIENT_COMMAND(suggestmap, "Suggest a map to appear at the map voting screen") { ClientCommand_suggestmap(caller, request, arguments); }
1128CLIENT_COMMAND(tell, "Send a private chat message to a player which may be visible to server admins") { ClientCommand_tell(caller, request, arguments, command); }
1129CLIENT_COMMAND(voice, "Send voice message via sound") { ClientCommand_voice(caller, request, arguments, command); }
1130CLIENT_COMMAND(unignore, "Remove an existing ignore of a player") { ClientCommand_unignore(caller, request, arguments, command); }
1131CLIENT_COMMAND(wpeditor, "Waypoint editor commands") { ClientCommand_wpeditor(caller, request, arguments); }
1132
1134{
1135 FOREACH(CLIENT_COMMANDS, true, { print_to(caller, sprintf(" ^2%s^7: %s", it.m_name, it.m_description)); });
1136}
1137
1138float ClientCommand_macro_command(int argc, entity caller, string command)
1139{
1140 string c = strtolower(argv(0));
1141 FOREACH(CLIENT_COMMANDS, it.m_name == c, {
1142 it.m_invokecmd(it, CMD_REQUEST_COMMAND, caller, argc, command);
1143 return true;
1144 });
1145
1146 return false;
1147}
1148
1149float ClientCommand_macro_usage(int argc, entity caller)
1150{
1151 string c = strtolower(argv(1));
1152 FOREACH(CLIENT_COMMANDS, it.m_name == c, {
1153 it.m_invokecmd(it, CMD_REQUEST_USAGE, caller, argc, "");
1154 return true;
1155 });
1156
1157 return false;
1158}
1159
1161{
1162 FOREACH(CLIENT_COMMANDS, true, { CMD_Write_Alias("qc_cmd_cmd", it.m_name, it.m_description); });
1163}
1164
1165// ======================================
1166// Main Function Called By Engine (cmd)
1167// ======================================
1168// If this function exists, server game code parses clientcommand before the engine code gets it.
1169
1170void SV_ParseClientCommand(entity this, string command)
1171{
1172 // If invalid UTF-8, don't even parse it
1173 string command2 = "";
1174 float len = strlen(command);
1175 float i;
1176 for (i = 0; i < len; ++i)
1177 command2 = strcat(command2, chr2str(str2chr(command, i)));
1178 if (command != command2) return;
1179
1180 // if we're banned, don't even parse the command
1181 if (Ban_MaybeEnforceBanOnce(this)) return;
1182
1183 int argc = tokenize_console(command);
1184
1185 // Guide for working with argc arguments by example:
1186 // argc: 1 - 2 - 3 - 4
1187 // argv: 0 - 1 - 2 - 3
1188 // cmd vote - master - login - password
1189
1190 // for floodcheck
1191 switch (strtolower(argv(0)))
1192 {
1193 // exempt commands which are not subject to floodcheck
1194 case "begin": break; // handled by engine in host_cmd.c
1195 case "download": break; // handled by engine in cl_parse.c
1196 case "mv_getpicture": break; // handled by server in this file
1197 case "wpeditor": break; // handled by server in this file
1198 case "pause": break; // handled by engine in host_cmd.c
1199 case "prespawn": break; // handled by engine in host_cmd.c
1200 case "sentcvar": break; // handled by server in this file
1201 case "spawn": break; // handled by engine in host_cmd.c
1202 case "say": case "say_team": case "tell": break; // chat has its own flood control in chat.qc
1203 case "minigame": // flood control only for common commands
1204 string arg = argv(1);
1205 if (arg == "")
1206 goto flood_control;
1207 for (int i = 0; i < MINIGAME_COMMON_CMD_COUNT; ++i)
1208 {
1209 if (MINIGAME_COMMON_CMD[i] == arg)
1210 goto flood_control;
1211 }
1212 // if we get here we haven't found any common command, so no flood control for other commands
1213 // individual minigame commands shouldn't be limited for gameplay reasons
1214 // FIXME unknown/wrong minigame commands have no flood control
1215 break;
1216 case "color": case "topcolor": case "bottomcolor": // handled by engine in host_cmd.c
1217 if(!IS_CLIENT(this)) // on connection
1218 {
1219 // since gamecode doesn't have any calls earlier than this, do the connecting message here
1220 Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_CONNECTING, this.netname);
1221 }
1222 if(teamplay)
1223 return;
1224 break;
1225 case "c2s": Net_ClientCommand(this, command); return; // handled by net.qh
1226
1227 // on connection, client sends all of these
1228 case "name": case "rate": case "rate_burstsize": case "playermodel": case "playerskin": case "clientversion":
1229 if(!IS_CLIENT(this)) break;
1230 // else fall through to default: flood control
1231 default:
1232 LABEL(flood_control)
1233 if(MUTATOR_CALLHOOK(ClientCommand_FloodControl, this, strtolower(argv(0)), argc, command))
1234 break; // a mutator has prevented flood control
1235
1236 // this is basically the same as the chat flood control
1237 entity store = IS_CLIENT(this) ? CS(this) : this; // unfortunately, we need to store these on the client initially
1238 // NOTE: using mod_time instead of time here to avoid initializing both this.cmd_floodtime
1239 // and CS(this).cmd_floodtime to -(antispam_count * antispam_time) (or -999999)
1241 if (mod_time < store.cmd_floodtime)
1242 {
1243 sprint(this, strcat("^3CMD FLOOD CONTROL: wait ^1", ftos(store.cmd_floodtime - mod_time),
1244 "^3 seconds, command was: ", command, "\n"));
1245 return; // too much spam, halt
1246 }
1247 else
1248 // micro-optimization: replaced mod_time - max_delay with time here as they are equal
1249 store.cmd_floodtime = max(gettime(GETTIME_FRAMESTART), store.cmd_floodtime) + autocvar_sv_clientcommand_antispam_time;
1250 break; // continue, as we're not flooding yet
1251 }
1252
1253 /* NOTE: should this be disabled? It can be spammy perhaps, but hopefully it's okay for now */
1254 if (argv(0) == "help")
1255 {
1256 if (argc == 1)
1257 {
1258 sprint(this, "\nClient networked commands:\n");
1260
1261 sprint(this, "\nCommon networked commands:\n");
1263
1264 sprint(this, "\nUsage:^3 cmd <command>^7, where possible commands are listed above.\n");
1265 sprint(this, "For help about a specific command, type cmd help <command>\n");
1266 return;
1267 }
1268 else if (CommonCommand_macro_usage(argc, this)) // Instead of trying to call a command, we're going to see detailed information about it
1269 {
1270 return;
1271 }
1272 else if (ClientCommand_macro_usage(argc, this)) // same, but for normal commands now
1273 {
1274 return;
1275 }
1276 }
1277 else if (MUTATOR_CALLHOOK(SV_ParseClientCommand, this, strtolower(argv(0)), argc, command))
1278 {
1279 return; // handled by a mutator
1280 }
1281 else if (CheatCommand(this, argc))
1282 {
1283 return; // handled by server/cheats.qc
1284 }
1285 else if (CommonCommand_macro_command(argc, this, command))
1286 {
1287 return; // handled by server/command/common.qc
1288 }
1289 else if (ClientCommand_macro_command(argc, this, command)) // continue as usual and scan for normal commands
1290 {
1291 return; // handled by one of the above ClientCommand_* functions
1292 }
1293 else
1294 {
1295 clientcommand(this, command);
1296 }
1297}
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)
Get true/false value of a string with multiple different inputs.
Definition bool.qh:13
float CheatCommand(entity this, int argc)
Definition cheats.qc:290
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:94
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:988
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:804
float ClientCommand_macro_usage(int argc, entity caller)
Definition cmd.qc:1149
void ClientCommand_kill(entity caller, int request)
Definition cmd.qc:537
void ClientCommand_macro_write_aliases(float fh)
Definition cmd.qc:1160
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:567
void ClientCommand_macro_help(entity caller)
Definition cmd.qc:1133
void ClientCommand_tell(entity caller, int request, int argc, string command)
Definition cmd.qc:931
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:682
void ClientCommand_join(entity caller, int request)
Definition cmd.qc:507
float ClientCommand_macro_command(int argc, entity caller, string command)
Definition cmd.qc:1138
void ClientCommand_say(entity caller, int request, int argc, string command)
Definition cmd.qc:641
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:607
void ClientCommand_say_team(entity caller, int request, int argc, string command)
Definition cmd.qc:661
void ClientCommand_voice(entity caller, int request, int argc, string command)
Definition cmd.qc:1033
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:907
void ClientCommand_selfstuff(entity caller, int request, string command)
Definition cmd.qc:780
void ClientCommand_mv_getpicture(entity caller, int request, int argc)
Definition cmd.qc:316
void ClientCommand_spectate(entity caller, int request)
Definition cmd.qc:838
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:241
#define IS_DEAD(s)
Definition player.qh:244
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:242
float game_stopped
Definition stats.qh:81
string playername(string thename, int teamid, bool team_colorize)
Definition util.qc:2178
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:254
#define SV_ParseClientCommand
Definition _all.inc:289
#define PutClientInServer
Definition _all.inc:250
void Net_ClientCommand(entity sender, string command)
Definition net.qh:222
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:100
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
bool autocvar_g_campaign
Definition menu.qc:752
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:735
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
void Kill_Notification(NOTIF broadcast, entity client, MSG net_type, CPID net_cpid)
Definition all.qc:1464
#define TRANSMUTE(cname, this,...)
Definition oo.qh:139
#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:1972
bool joinAllowed(entity this, int team_index)
Definition client.qc:2253
bool PlayerInList(entity player, string list)
Definition client.qc:1047
void Join(entity this, bool queued_join)
it's assumed this isn't called for bots (campaign_bots_may_start, centreprints)
Definition client.qc:2069
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:1250
int g_race_qualifying
Definition race.qh:11
#define CS_CVAR(this)
Definition state.qh:51
ClientState CS(Client this)
Definition state.qh:47
#define strcpy(this, s)
Definition string.qh:51
ERASEABLE string cons(string a, string b)
Definition string.qh:277
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:597
void TeamBalance_GetTeamCounts(entity balance, entity ignore)
Counts the number of players and various other information about each team.
Definition teamplay.qc:827
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
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:1002
bool autocvar_g_balance_teams_queue
Definition teamplay.qh:9
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:20
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:52
bool waypointeditor_enabled
Definition waypoints.qh:3
float ServerProgsDB
Definition world.qh:128