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