Xonotic
vote.qc
Go to the documentation of this file.
1 #include "vote.qh"
2 
3 #include <common/command/_mod.qh>
4 #include <common/constants.qh>
7 #include <common/mapinfo.qh>
8 #include <common/net_linked.qh>
10 #include <common/playerstats.qh>
11 #include <common/stats.qh>
12 #include <common/util.qh>
13 #include <common/weapons/_all.qh>
14 #include <server/client.qh>
16 #include <server/command/common.qh>
17 #include <server/command/vote.qh>
18 #include <server/damage.qh>
19 #include <server/gamelog.qh>
20 #include <server/intermission.qh>
21 #include <server/mutators/_mod.qh>
22 #include <server/race.qh>
23 #include <server/round_handler.qh>
24 #include <server/scores.qh>
25 #include <server/teamplay.qh>
27 #include <server/world.qh>
28 
29 // =============================================
30 // Server side voting code, reworked by Samual
31 // Last updated: December 27th, 2011
32 // =============================================
33 
34 // Nagger for players to know status of voting
36 {
37  int nags, i, f, b;
38  entity e;
39  WriteHeader(MSG_ENTITY, ENT_CLIENT_NAGGER);
40 
41  // bits:
42  // 1 = ready
43  // 2 = player needs to ready up
44  // 4 = vote
45  // 8 = player needs to vote
46  // 16 = warmup
47  // sendflags:
48  // 64 = vote counts
49  // 128 = vote string
50 
51  nags = 0;
52  if (readycount)
53  {
54  nags |= BIT(0);
55  if (to.ready == 0) nags |= BIT(1);
56  }
57  if (vote_called)
58  {
59  nags |= BIT(2);
60  if (to.vote_selection == 0) nags |= BIT(3);
61  }
62  if (warmup_stage) nags |= BIT(4);
63 
64  if (sendflags & BIT(6)) nags |= BIT(6);
65 
66  if (sendflags & BIT(7)) nags |= BIT(7);
67 
68  if (!(nags & 4)) // no vote called? send no string
69  nags &= ~(BIT(6) | BIT(7));
70 
71  WriteByte(MSG_ENTITY, nags);
72 
73  if (nags & BIT(6))
74  {
75  WriteByte(MSG_ENTITY, vote_accept_count);
76  WriteByte(MSG_ENTITY, vote_reject_count);
77  WriteByte(MSG_ENTITY, vote_needed_overall);
78  WriteChar(MSG_ENTITY, to.vote_selection);
79  }
80 
81  if (nags & BIT(7)) WriteString(MSG_ENTITY, vote_called_display);
82 
83  if (nags & 1)
84  {
85  for (i = 1; i <= maxclients; i += 8)
86  {
87  for (f = 0, e = edict_num(i), b = BIT(0); b < BIT(8); b <<= 1, e = nextent(e))
88  if (!IS_REAL_CLIENT(e) || e.ready)
89  f |= b;
90  WriteByte(MSG_ENTITY, f);
91  }
92  }
93 
94  return true;
95 }
96 
98 {
99  Net_LinkEntity(nagger = new_pure(nagger), false, 0, Nagger_SendEntity);
100 }
101 
103 {
104  if (nagger) nagger.SendFlags |= BIT(7);
105 }
106 
108 {
109  if (nagger) nagger.SendFlags |= BIT(6);
110 }
111 
113 {
114  if (nagger) nagger.SendFlags |= BIT(0);
115 }
116 
117 // If the vote_caller is still here, return their name, otherwise vote_caller_name
119 {
120  if (IS_REAL_CLIENT(vote_caller)) return playername(vote_caller.netname, vote_caller.team, false);
121  return vote_caller_name;
122 }
123 
124 // =======================
125 // Game logic for voting
126 // =======================
127 
128 void VoteReset()
129 {
130  FOREACH_CLIENT(true, { it.vote_selection = 0; });
131 
132  if (vote_called)
133  {
137  }
138 
140  vote_caller = NULL;
141  vote_endtime = 0;
142 
145 
147 }
148 
149 void VoteStop(entity stopper)
150 {
151  bprint("\{1}^2* ^3", GetCallerName(stopper), "^2 stopped ^3", OriginalCallerName(), "^2's vote\n");
152  if (autocvar_sv_eventlog) GameLogEcho(strcat(":vote:vstop:", ftos(stopper.playerid)));
153  // Don't force them to wait for next vote, this way they can e.g. correct their vote.
154  if ((vote_caller) && (stopper == vote_caller)) vote_caller.vote_waittime = time + autocvar_sv_vote_stop;
155  VoteReset();
156 }
157 
159 {
160  bprint("\{1}^2* ^3", OriginalCallerName(), "^2's vote for ^1", vote_called_display, "^2 was accepted\n");
161 
162  if ((vote_called == VOTE_MASTER) && vote_caller) vote_caller.vote_master = 1;
163  else localcmd(strcat(vote_called_command, "\n"));
164 
165  if (vote_caller) vote_caller.vote_waittime = 0; // people like your votes, you don't need to wait to vote again
166 
167  VoteReset();
168  Send_Notification(NOTIF_ALL, NULL, MSG_ANNCE, ANNCE_VOTE_ACCEPT);
169 }
170 
172 {
173  bprint("\{1}^2* ^3", OriginalCallerName(), "^2's vote for ", vote_called_display, "^2 was rejected\n");
174  VoteReset();
175  Send_Notification(NOTIF_ALL, NULL, MSG_ANNCE, ANNCE_VOTE_FAIL);
176 }
177 
179 {
180  bprint("\{1}^2* ^3", OriginalCallerName(), "^2's vote for ", vote_called_display, "^2 timed out\n");
181  VoteReset();
182  Send_Notification(NOTIF_ALL, NULL, MSG_ANNCE, ANNCE_VOTE_FAIL);
183 }
184 
185 void VoteSpam(float notvoters, float mincount, string result)
186 {
187  bprint(strcat(
188  strcat("\{1}^2* vote results: ^1", ftos(vote_accept_count)),
189  strcat("^2:^1", ftos(vote_reject_count)),
190  ((mincount >= 0) ? strcat("^2 (^1", ftos(mincount), "^2 needed)") : "^2"),
191  strcat(", ^1", ftos(vote_abstain_count), "^2 didn't care"),
192  strcat(", ^1", ftos(notvoters), strcat("^2 didn't ", ((mincount >= 0) ? "" : "have to "), "vote\n"))));
193 
195  {
197  strcat(":vote:v", result, ":", ftos(vote_accept_count)),
200  strcat(":", ftos(notvoters)),
201  strcat(":", ftos(mincount))));
202  }
203 }
204 
205 #define spectators_allowed (!autocvar_sv_vote_nospectators || (autocvar_sv_vote_nospectators == 1 && (warmup_stage || intermission_running)))
206 
207 void VoteCount(float first_count)
208 {
209  // declarations
211 
212  float vote_player_count = 0, notvoters = 0;
213  float vote_real_player_count = 0, vote_real_accept_count = 0;
214  float vote_real_reject_count = 0, vote_real_abstain_count = 0;
215  float vote_needed_of_voted, final_needed_votes;
216  float vote_factor_overall, vote_factor_of_voted;
217 
219 
220  // add up all the votes from each connected client
222  ++vote_player_count;
223  if (IS_PLAYER(it)) ++vote_real_player_count;
224  switch (it.vote_selection)
225  {
226  case VOTE_SELECT_REJECT:
227  { ++vote_reject_count;
228  { if (IS_PLAYER(it)) ++vote_real_reject_count; } break;
229  }
230  case VOTE_SELECT_ACCEPT:
231  { ++vote_accept_count;
232  { if (IS_PLAYER(it)) ++vote_real_accept_count; } break;
233  }
234  case VOTE_SELECT_ABSTAIN:
235  { ++vote_abstain_count;
236  { if (IS_PLAYER(it)) ++vote_real_abstain_count; } break;
237  }
238  default: break;
239  }
240  });
241 
242  // Check to see if there are enough players on the server to allow master voting... otherwise, vote master could be used for evil.
243  if ((vote_called == VOTE_MASTER) && autocvar_sv_vote_master_playerlimit > vote_player_count)
244  {
245  if (vote_caller) vote_caller.vote_waittime = 0;
246  print_to(vote_caller, "^1There are not enough players on this server to allow you to become vote master.");
247  VoteReset();
248  return;
249  }
250 
251  // if spectators aren't allowed to vote and there are players in a match, then only count the players in the vote and ignore spectators.
252  if (!spectators_allowed && (vote_real_player_count > 0))
253  {
254  vote_accept_count = vote_real_accept_count;
255  vote_reject_count = vote_real_reject_count;
256  vote_abstain_count = vote_real_abstain_count;
257  vote_player_count = vote_real_player_count;
258  }
259 
260  // people who have no opinion in any way :D
261  notvoters = (vote_player_count - vote_accept_count - vote_reject_count - vote_abstain_count);
262 
263  // determine the goal for the vote to be passed or rejected normally
264  vote_factor_overall = bound(0.5, autocvar_sv_vote_majority_factor, 0.999);
265  vote_needed_overall = floor((vote_player_count - vote_abstain_count) * vote_factor_overall) + 1;
266 
267  // if the vote times out, determine the amount of votes needed of the people who actually already voted
268  vote_factor_of_voted = bound(0.5, autocvar_sv_vote_majority_factor_of_voted, 0.999);
269  vote_needed_of_voted = floor((vote_accept_count + vote_reject_count) * vote_factor_of_voted) + 1;
270 
271  // are there any players at all on the server? it could be an admin vote
272  if (vote_player_count == 0 && first_count)
273  {
274  VoteSpam(0, -1, "yes"); // no players at all, just accept it
275  VoteAccept();
276  return;
277  }
278 
279  // since there ARE players, finally calculate the result of the vote
281  {
282  VoteSpam(notvoters, -1, "yes"); // there is enough acceptions to pass the vote
283  VoteAccept();
284  return;
285  }
286 
287  if (vote_reject_count > vote_player_count - vote_abstain_count - vote_needed_overall)
288  {
289  VoteSpam(notvoters, -1, "no"); // there is enough rejections to deny the vote
290  VoteReject();
291  return;
292  }
293 
294  // there is not enough votes in either direction, now lets just calculate what the voters have said
295  if (time > vote_endtime)
296  {
297  final_needed_votes = vote_needed_overall;
298 
300  {
301  if (vote_accept_count >= vote_needed_of_voted)
302  {
303  VoteSpam(notvoters, min(vote_needed_overall, vote_needed_of_voted), "yes");
304  VoteAccept();
305  return;
306  }
307 
309  {
310  VoteSpam(notvoters, min(vote_needed_overall, vote_needed_of_voted), "no");
311  VoteReject();
312  return;
313  }
314 
315  final_needed_votes = min(vote_needed_overall, vote_needed_of_voted);
316  }
317 
318  // it didn't pass or fail, so not enough votes to even make a decision.
319  VoteSpam(notvoters, final_needed_votes, "timeout");
320  VoteTimeout();
321  }
322 }
323 
324 void VoteThink()
325 {
326  if (vote_endtime > 0) // a vote was called
327  {
328  if (time > vote_endtime) // time is up
329  VoteCount(false);
330  }
331 }
332 
333 
334 // =======================
335 // Game logic for warmup
336 // =======================
337 
338 // Resets the state of all clients, items, weapons, waypoints, ... of the map.
339 void reset_map(bool dorespawn, bool is_fake_round_start)
340 {
341  if (time <= game_starttime)
342  {
343  if (game_stopped)
344  return;
345 
346  if (!is_fake_round_start)
347  {
348  Score_ClearAll();
349  PlayerStats_GameReport_Reset_All();
350  }
351 
353  round_handler_Reset(game_starttime);
354  }
355 
357  {
358  shuffleteams();
360  }
361 
362  FOREACH_CLIENT(true, {
363  if (time <= game_starttime)
364  accuracy_reset(it); // for spectators too because weapon accuracy is persistent
365  if (!IS_PLAYER(it))
366  continue;
367  if (STAT(FROZEN, it))
368  Unfreeze(it, false);
370  entity store = PS(it);
371  if (store)
372  {
373  Inventory_clear(store.inventory);
374  Inventory_update(store);
375  }
376  });
377 
378  MUTATOR_CALLHOOK(reset_map_global);
379 
381  {
382  if(IS_CLIENT(it))
383  continue;
384  if (it.reset)
385  {
386  it.reset(it);
387  continue;
388  }
389  if (it.team_saved) it.team = it.team_saved;
390  if (it.flags & FL_PROJECTILE) delete(it); // remove any projectiles left
391  });
392 
393  // Waypoints and assault start come LAST
395  if (it.reset2) it.reset2(it);
396  });
397 
398  // Moving the player reset code here since the player-reset depends
399  // on spawnpoint entities which have to be reset first --blub
400  if (dorespawn)
401  {
402  if (!MUTATOR_CALLHOOK(reset_map_players))
403  {
405  {
406  // PlayerScore_Clear(it);
407  CS(it).killcount = 0;
408  // stop the player from moving so that he stands still once he gets respawned
409  it.velocity = '0 0 0';
410  it.avelocity = '0 0 0';
411  CS(it).movement = '0 0 0';
412  PutClientInServer(it);
413  });
414  }
415  }
416 }
417 
418 // Restarts the map after the countdown is over (and cvar sv_ready_restart_after_countdown is set)
420 {
421  reset_map(true, false);
422  delete(this);
423 }
424 
425 // Forces a restart of the game without actually reloading the map // this is a mess...
426 void ReadyRestart_force(bool is_fake_round_start)
427 {
428  if (time <= game_starttime && game_stopped)
429  return;
430  if (!is_fake_round_start)
431  bprint("^1Match is restarting...\n");
432 
433  VoteReset();
434 
435  // clear overtime, we have to decrease timelimit to its original value again.
437  cvar_set("timelimit", ftos(autocvar_timelimit - (checkrules_overtimesadded * autocvar_timelimit_overtime)));
439 
440  if(warmup_stage)
441  game_starttime = time; // Warmup: No countdown in warmup
442  else
443  game_starttime = time + RESTART_COUNTDOWN; // Go into match mode
444 
445  // clear player attributes
447  it.alivetime = 0;
448  CS(it).killcount = 0;
449  });
450 
451  // if we're ending the warmup stage call the corresponding hook
452  if(!is_fake_round_start && !warmup_stage)
453  localcmd("\nsv_hook_warmupend\n");
454 
455  // reset the .ready status of all players (also spectators)
456  FOREACH_CLIENT(IS_REAL_CLIENT(it), { it.ready = false; });
457  readycount = 0;
458  Nagger_ReadyCounted(); // NOTE: this causes a resend of that entity, and will also turn off warmup state on the client
459 
460  // lock teams with lockonrestart
463 
464  // initiate the restart-countdown-announcer entity
465  if (!is_fake_round_start && sv_ready_restart_after_countdown && !warmup_stage)
466  {
467  entity restart_timer = new_pure(restart_timer);
468  setthink(restart_timer, ReadyRestart_think);
469  restart_timer.nextthink = game_starttime;
470  }
471 
472  // after a restart every players number of allowed timeouts gets reset, too
474  {
475  FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it), { CS(it).allowed_timeouts = autocvar_sv_timeout_number; });
476  }
477 
479  reset_map(true, is_fake_round_start);
480 
481  if (autocvar_sv_eventlog) GameLogEcho(":restart");
482 }
483 
484 void ReadyRestart(bool forceWarmupEnd)
485 {
486  if (MUTATOR_CALLHOOK(ReadyRestart_Deny) || intermission_running || race_completing) localcmd("restart\n");
487  else localcmd("\nsv_hook_readyrestart\n");
488 
489  if(forceWarmupEnd)
490  warmup_stage = 0; // forcefully end warmup and go to match stage
491  else
492  warmup_stage = cvar("g_warmup"); // go into warmup if it's enabled, otherwise restart into match stage
493 
494  ReadyRestart_force(false);
495 }
496 
497 // Count the players who are ready and determine whether or not to restart the match
499 {
500  float ready_needed_factor, ready_needed_count;
501  float t_ready = 0, t_players = 0;
502 
504  ++t_players;
505  if (it.ready) ++t_ready;
506  });
507 
508  readycount = t_ready;
509 
511 
512  ready_needed_factor = bound(0.5, cvar("g_warmup_majority_factor"), 0.999);
513  ready_needed_count = floor(t_players * ready_needed_factor) + 1;
514 
515  if (readycount >= ready_needed_count) ReadyRestart(true);
516 }
517 
518 
519 // ======================================
520 // Supporting functions for VoteCommand
521 // ======================================
522 
523 float Votecommand_check_assignment(entity caller, float assignment)
524 {
525  float from_server = (!caller);
526 
527  if ((assignment == VC_ASGNMNT_BOTH)
528  || ((!from_server && assignment == VC_ASGNMNT_CLIENTONLY)
529  || (from_server && assignment == VC_ASGNMNT_SERVERONLY))) return true;
530 
531  return false;
532 }
533 
534 string VoteCommand_extractcommand(string input, float startpos, int argc)
535 {
536  string output;
537 
538  if ((argc - 1) < startpos) output = "";
539  else output = substring(input, argv_start_index(startpos), argv_end_index(-1) - argv_start_index(startpos));
540 
541  return output;
542 }
543 
544 float VoteCommand_checknasty(string vote_command)
545 {
546  if ((strstrofs(vote_command, ";", 0) >= 0)
547  || (strstrofs(vote_command, "\n", 0) >= 0)
548  || (strstrofs(vote_command, "\r", 0) >= 0)
549  || (strstrofs(vote_command, "$", 0) >= 0)) return false;
550 
551  return true;
552 }
553 
554 // NOTE: requires input to be surrounded by spaces
555 string VoteCommand_checkreplacements(string input)
556 {
557  string output = input;
558  // allow gotomap replacements
559  output = strreplace(" map ", " gotomap ", output);
560  output = strreplace(" chmap ", " gotomap ", output);
561  return output;
562 }
563 
564 float VoteCommand_checkinlist(string vote_command, string list)
565 {
566  string l = VoteCommand_checkreplacements(strcat(" ", list, " "));
567 
568  if (strstrofs(l, VoteCommand_checkreplacements(strcat(" ", vote_command, " ")), 0) >= 0) return true;
569 
570  return false;
571 }
572 
573 string ValidateMap(string validated_map, entity caller)
574 {
575  validated_map = MapInfo_FixName(validated_map);
576 
577  if (!validated_map)
578  {
579  print_to(caller, "This map is not available on this server.");
580  return string_null;
581  }
582 
584  {
585  if (Map_IsRecent(validated_map))
586  {
587  print_to(caller, "This server does not allow for recent maps to be played again. Please be patient for some rounds.");
588  return string_null;
589  }
590  }
591 
592  if (!MapInfo_CheckMap(validated_map))
593  {
594  print_to(caller, strcat("^1Invalid mapname, \"^3", validated_map, "^1\" does not support the current game mode."));
595  return string_null;
596  }
597 
598  return validated_map;
599 }
600 
601 float VoteCommand_checkargs(float startpos, int argc)
602 {
603  float p, q, check, minargs;
604  string cvarname = strcat("sv_vote_command_restriction_", argv(startpos));
605  string cmdrestriction = ""; // No we don't.
606  string charlist, arg;
607  float checkmate;
608 
609  if(cvar_type(cvarname) & CVAR_TYPEFLAG_EXISTS)
610  cmdrestriction = cvar_string(cvarname);
611  else
612  LOG_INFO("NOTE: ", cvarname, " does not exist, no restrictions will be applied.");
613 
614  if (cmdrestriction == "") return true;
615 
616  ++startpos; // skip command name
617 
618  // check minimum arg count
619 
620  // 0 args: argc == startpos
621  // 1 args: argc == startpos + 1
622  // ...
623 
624  minargs = stof(cmdrestriction);
625  if (argc - startpos < minargs) return false;
626 
627  p = strstrofs(cmdrestriction, ";", 0); // find first semicolon
628 
629  for ( ; ; )
630  {
631  // we know that at any time, startpos <= argc - minargs
632  // so this means: argc-minargs >= startpos >= argc, thus
633  // argc-minargs >= argc, thus minargs <= 0, thus all minargs
634  // have been seen already
635 
636  if (startpos >= argc) // all args checked? GOOD
637  break;
638 
639  if (p < 0) // no more args? FAIL
640  {
641  // exception: exactly minargs left, this one included
642  if (argc - startpos == minargs) break;
643 
644  // otherwise fail
645  return false;
646  }
647 
648  // cut to next semicolon
649  q = strstrofs(cmdrestriction, ";", p + 1); // find next semicolon
650  if (q < 0) charlist = substring(cmdrestriction, p + 1, -1);
651  else charlist = substring(cmdrestriction, p + 1, q - (p + 1));
652 
653  // in case we ever want to allow semicolons in VoteCommand_checknasty
654  // charlist = strreplace("^^", ";", charlist);
655 
656  if (charlist != "")
657  {
658  // verify the arg only contains allowed chars
659  arg = argv(startpos);
660  checkmate = strlen(arg);
661  for (check = 0; check < checkmate; ++check)
662  if (strstrofs(charlist, substring(arg, check, 1), 0) < 0) return false;
663  // not allowed character
664  // all characters are allowed. FINE.
665  }
666 
667  ++startpos;
668  --minargs;
669  p = q;
670  }
671 
672  return true;
673 }
674 
675 int VoteCommand_parse(entity caller, string vote_command, string vote_list, float startpos, int argc)
676 {
677  string first_command = argv(startpos);
678  int missing_chars = argv_start_index(startpos);
679 
680  if (autocvar_sv_vote_limit > 0 && strlen(vote_command) > autocvar_sv_vote_limit)
681  return 0;
682 
683  if (!VoteCommand_checkinlist(first_command, vote_list)) return 0;
684 
685  if (!VoteCommand_checkargs(startpos, argc)) return 0;
686 
687  switch (MUTATOR_CALLHOOK(VoteCommand_Parse, caller, first_command, vote_command, startpos, argc))
688  {
689  case MUT_VOTEPARSE_CONTINUE: { break; }
690  case MUT_VOTEPARSE_SUCCESS: { return 1; }
691  case MUT_VOTEPARSE_INVALID: { return -1; }
692  case MUT_VOTEPARSE_UNACCEPTABLE: { return 0; }
693  }
694 
695  switch (first_command) // now go through and parse the proper commands to adjust as needed.
696  {
697  case "kick":
698  case "kickban": // catch all kick/kickban commands
699  {
700  entity victim = GetIndexedEntity(argc, (startpos + 1));
701  float accepted = VerifyClientEntity(victim, true, false);
702 
703  if (accepted > 0)
704  {
705  string reason = "No reason provided";
706  if(argc > next_token)
707  reason = substring(vote_command, argv_start_index(next_token) - missing_chars, -1);
708 
709  string command_arguments = reason;
710  if (first_command == "kickban")
712 
713  vote_parsed_command = strcat(first_command, " # ", ftos(etof(victim)), " ", command_arguments);
714  vote_parsed_display = sprintf("^1%s #%d ^7%s^1 %s", first_command, etof(victim), victim.netname, reason);
715  }
716  else
717  {
718  print_to(caller, strcat("vcall: ", GetClientErrorString(accepted, argv(startpos + 1)), ".\n"));
719  return 0;
720  }
721 
722  break;
723  }
724 
725  case "map":
726  case "chmap":
727  case "gotomap": // re-direct all map selection commands to gotomap
728  {
729  vote_command = ValidateMap(argv(startpos + 1), caller);
730  if (!vote_command) return -1;
731  vote_parsed_command = strcat("gotomap ", vote_command);
733 
734  break;
735  }
736 
737  // TODO: replicate the old behaviour of being able to vote for maps from different modes on multimode servers (possibly support it in gotomap too)
738  // maybe fallback instead of aborting if map name is invalid?
739  case "nextmap":
740  {
741  vote_command = ValidateMap(argv(startpos + 1), caller);
742  if (!vote_command) return -1;
743  vote_parsed_command = strcat("nextmap ", vote_command);
745 
746  break;
747  }
748 
749  case "timelimit": // include restrictions on the maximum votable time limit
750  {
751  float timelimit_vote = stof(argv(startpos + 1));
752  if(timelimit_vote > autocvar_timelimit_max || timelimit_vote < autocvar_timelimit_min)
753  {
754  print_to(caller, strcat("Invalid timelimit vote, accepted values are between ", ftos(autocvar_timelimit_min), " and ", ftos(autocvar_timelimit_max), "."));
755  return -1;
756  }
757  timelimit_vote = bound(autocvar_timelimit_min, timelimit_vote, autocvar_timelimit_max);
758  vote_parsed_command = strcat("timelimit ", ftos(timelimit_vote));
760 
761  break;
762  }
763 
764  case "restart": // re-direct all match restarting to resetmatch
765  vote_command = "resetmatch"; // fall-through
766  case "resetmatch":
767  {
768  vote_parsed_command = vote_command;
769  vote_parsed_display = strzone(strcat("^1", vote_command));
770 
771  break;
772  }
773 
774  case "allready":
775  {
776  if(!warmup_stage) {
777  print_to(caller, "Game already started. Use the resetmatch command to restart the match.");
778  return -1;
779  }
780 
781  vote_parsed_command = vote_command;
782  vote_parsed_display = strzone(strcat("^1", vote_command));
783  break;
784  }
785 
786  default:
787  {
788  vote_parsed_command = vote_command;
789  vote_parsed_display = strzone(strcat("^1", vote_command));
790 
791  break;
792  }
793  }
794 
795  return 1;
796 }
797 
798 
799 // =======================
800 // Command Sub-Functions
801 // =======================
802 
803 void VoteCommand_abstain(int request, entity caller) // CLIENT ONLY
804 {
805  switch (request)
806  {
807  case CMD_REQUEST_COMMAND:
808  {
809  if (!vote_called) { print_to(caller, "^1No vote called."); }
810  else if (caller.vote_selection != VOTE_SELECT_NULL && !autocvar_sv_vote_change)
811  {
812  print_to(caller, "^1You have already voted.");
813  }
814 
815  else // everything went okay, continue changing vote
816  {
817  print_to(caller, "^1You abstained from your vote.");
818  caller.vote_selection = VOTE_SELECT_ABSTAIN;
819  msg_entity = caller;
821  VoteCount(false);
822  }
823 
824  return;
825  }
826 
827  default:
828  case CMD_REQUEST_USAGE:
829  {
830  print_to(caller, strcat("\nUsage:^3 ", GetCommandPrefix(caller), " vote abstain"));
831  print_to(caller, " No arguments required.");
832  return;
833  }
834  }
835 }
836 
838 {
839  print_to(caller, strcat("You can call a vote for or execute these commands: ^3", autocvar_sv_vote_commands, "^7 and maybe further ^3arguments^7"));
840 }
841 
842 void VoteCommand_call(int request, entity caller, int argc, string vote_command) // BOTH
843 {
844  switch (request)
845  {
846  case CMD_REQUEST_COMMAND:
847  {
848  float tmp_playercount = 0;
849  int parse_error;
850 
851  vote_command = VoteCommand_extractcommand(vote_command, 2, argc);
852 
853  if (!autocvar_sv_vote_call && caller)
854  {
855  print_to(caller, "^1Vote calling is not allowed.");
856  }
857  else if (!autocvar_sv_vote_gamestart && time < game_starttime)
858  {
859  print_to(caller, "^1Vote calling is not allowed before the match has started.");
860  }
861  else if (vote_called)
862  {
863  print_to(caller, "^1There is already a vote called.");
864  }
865  else if (!spectators_allowed && (caller && !IS_PLAYER(caller)))
866  {
867  print_to(caller, "^1Only players can call a vote.");
868  }
869  else if (caller && !IS_CLIENT(caller))
870  {
871  print_to(caller, "^1Only connected clients can vote.");
872  }
873  else if (timeout_status && vote_command != "timein")
874  {
875  print_to(caller, "^1You can not call a vote while a timeout is active.");
876  }
877  else if (caller && (time < caller.vote_waittime))
878  {
879  print_to(caller, strcat("^1You have to wait ^2", ftos(ceil(caller.vote_waittime - time)), "^1 seconds before you can again call a vote."));
880  }
881  else if (!VoteCommand_checknasty(vote_command))
882  {
883  print_to(caller, "^1Syntax error in command.");
884  }
885  else if ((parse_error = VoteCommand_parse(caller, vote_command, autocvar_sv_vote_commands, 2, argc)) <= 0)
886  {
887  if(parse_error == 0)
888  {
889  if (vote_called_command == "")
890  VoteCommand_call(CMD_REQUEST_USAGE, caller, argc, vote_command);
891  else
892  print_to(caller, "^1This command is not acceptable or not available.");
893  }
894  }
895  else // everything went okay, continue with calling the vote
896  {
897  vote_caller = caller; // remember who called the vote
903 
904  if (caller)
905  {
906  caller.vote_selection = VOTE_SELECT_ACCEPT;
907  caller.vote_waittime = time + autocvar_sv_vote_wait;
908  msg_entity = caller;
909  }
910 
911  FOREACH_CLIENT(IS_REAL_CLIENT(it), { ++tmp_playercount; });
912 
913  bprint("\{1}^2* ^3", OriginalCallerName(), "^2 calls a vote for ", vote_called_display, "\n");
915  GameLogEcho(strcat(":vote:vcall:", ftos(vote_caller.playerid), ":", vote_called_display));
917  VoteCount(true); // needed if you are the only one
918 
919  if (tmp_playercount > 1 && vote_called != VOTE_NULL)
920  Send_Notification(NOTIF_ALL, NULL, MSG_ANNCE, ANNCE_VOTE_CALL);
921  }
922 
923  return;
924  }
925 
926  default:
927  case CMD_REQUEST_USAGE:
928  {
929  print_to(caller, strcat("\nUsage:^3 ", GetCommandPrefix(caller), " vote call <command>"));
930  print_to(caller, " Where <command> is the command to request a vote upon.");
931  print_to(caller, strcat("Examples: ", GetCommandPrefix(caller), " vote call gotomap dance"));
932  print_to(caller, strcat(" ", GetCommandPrefix(caller), " vote call endmatch"));
934  print_to(caller, "Shortcuts: ^2vcall <command>, vend, vmap, vkick, ...");
935  return;
936  }
937  }
938 }
939 
940 void VoteCommand_master(int request, entity caller, int argc, string vote_command) // CLIENT ONLY
941 {
942  switch (request)
943  {
944  case CMD_REQUEST_COMMAND:
945  {
947  {
948  switch (strtolower(argv(2)))
949  {
950  case "do":
951  {
952  int parse_error;
953  vote_command = VoteCommand_extractcommand(vote_command, 3, argc);
954 
955  if (!caller.vote_master)
956  print_to(caller, "^1You do not have vote master privileges.");
957  else if (!VoteCommand_checknasty(vote_command))
958  {
959  print_to(caller, "^1Syntax error in command.");
960  }
961  else if ((parse_error = VoteCommand_parse(caller, vote_command, strcat(autocvar_sv_vote_commands, " ", autocvar_sv_vote_master_commands), 3, argc)) <= 0)
962  {
963  if(parse_error == 0)
964  {
965  if (vote_called_command == "")
966  VoteCommand_master(CMD_REQUEST_USAGE, caller, argc, vote_command);
967  else
968  print_to(caller, "^1This command is not acceptable or not available.");
969  }
970  }
971  else // everything went okay, proceed with command
972  {
974  print_to(caller, strcat("Executing command '", vote_parsed_display, "' on server."));
975  bprint("\{1}^2* ^3", GetCallerName(caller), "^2 used their ^3master^2 status to do \"^2", vote_parsed_display, "^2\".\n");
977  GameLogEcho(strcat(":vote:vdo:", ftos(caller.playerid), ":", vote_parsed_display));
978  }
979 
980  return;
981  }
982 
983  case "login":
984  {
985  if (autocvar_sv_vote_master_password == "") { print_to(caller, "^1Login to vote master is not allowed."); }
986  else if (caller.vote_master)
987  {
988  print_to(caller, "^1You are already logged in as vote master.");
989  }
990  else if (autocvar_sv_vote_master_password != argv(3))
991  {
992  print_to(caller, strcat("Rejected vote master login from ", GetCallerName(caller)));
993  }
994  else // everything went okay, proceed with giving this player master privilages
995  {
996  caller.vote_master = true;
997  print_to(caller, strcat("Accepted vote master login from ", GetCallerName(caller)));
998  bprint("\{1}^2* ^3", GetCallerName(caller), "^2 logged in as ^3master^2\n");
1000  GameLogEcho(strcat(":vote:vlogin:", ftos(caller.playerid)));
1001  }
1002 
1003  return;
1004  }
1005 
1006  default: // calling a vote for master
1007  {
1008  if (!autocvar_sv_vote_master_callable) { print_to(caller, "^1Vote to become vote master is not allowed."); }
1009  else if (vote_called)
1010  {
1011  print_to(caller, "^1There is already a vote called.");
1012  }
1013  else if (!spectators_allowed && (caller && !IS_PLAYER(caller)))
1014  {
1015  print_to(caller, "^1Only players can call a vote.");
1016  }
1017  else if (timeout_status)
1018  {
1019  print_to(caller, "^1You can not call a vote while a timeout is active.");
1020  }
1021  else // everything went okay, continue with creating vote
1022  {
1023  vote_caller = caller;
1026  vote_called_command = strzone("XXX");
1027  vote_called_display = strzone("^3master");
1029 
1030  caller.vote_selection = VOTE_SELECT_ACCEPT;
1031  caller.vote_waittime = time + autocvar_sv_vote_wait;
1032 
1033  bprint("\{1}^2* ^3", OriginalCallerName(), "^2 calls a vote to become ^3master^2.\n");
1035  GameLogEcho(strcat(":vote:vcall:", ftos(vote_caller.playerid), ":", vote_called_display));
1037  VoteCount(true); // needed if you are the only one
1038  }
1039 
1040  return;
1041  }
1042  }
1043  }
1044  else { print_to(caller, "^1Master control of voting is not allowed."); }
1045 
1046  return;
1047  }
1048 
1049  default:
1050  case CMD_REQUEST_USAGE:
1051  {
1052  print_to(caller, strcat("\nUsage:^3 ", GetCommandPrefix(caller), " vote master [<action> [<command> | <password>]]"));
1053  print_to(caller, " If <action> is left blank, it calls a vote for you to become master.");
1054  print_to(caller, " Otherwise it can be either 'do' (to run <command>) or 'login' as master.");
1055  return;
1056  }
1057  }
1058 }
1059 
1060 void VoteCommand_no(int request, entity caller) // CLIENT ONLY
1061 {
1062  switch (request)
1063  {
1064  case CMD_REQUEST_COMMAND:
1065  {
1066  if (!vote_called) { print_to(caller, "^1No vote called."); }
1067  else if (caller.vote_selection != VOTE_SELECT_NULL && !autocvar_sv_vote_change)
1068  {
1069  print_to(caller, "^1You have already voted.");
1070  }
1071  else if (((caller == vote_caller) || caller.vote_master) && autocvar_sv_vote_no_stops_vote)
1072  {
1073  VoteStop(caller);
1074  }
1075 
1076  else // everything went okay, continue changing vote
1077  {
1078  print_to(caller, "^1You rejected the vote.");
1079  caller.vote_selection = VOTE_SELECT_REJECT;
1080  msg_entity = caller;
1082  VoteCount(false);
1083  }
1084 
1085  return;
1086  }
1087 
1088  default:
1089  case CMD_REQUEST_USAGE:
1090  {
1091  print_to(caller, strcat("\nUsage:^3 ", GetCommandPrefix(caller), " vote no"));
1092  print_to(caller, " No arguments required.");
1093  return;
1094  }
1095  }
1096 }
1097 
1098 void VoteCommand_status(int request, entity caller) // BOTH
1099 {
1100  switch (request)
1101  {
1102  case CMD_REQUEST_COMMAND:
1103  {
1104  if (vote_called) print_to(caller, strcat("^7Vote for ", vote_called_display, "^7 called by ^7", OriginalCallerName(), "^7."));
1105  else print_to(caller, "^1No vote called.");
1106 
1107  return;
1108  }
1109 
1110  default:
1111  case CMD_REQUEST_USAGE:
1112  {
1113  print_to(caller, strcat("\nUsage:^3 ", GetCommandPrefix(caller), " vote status"));
1114  print_to(caller, " No arguments required.");
1115  return;
1116  }
1117  }
1118 }
1119 
1120 void VoteCommand_stop(int request, entity caller) // BOTH
1121 {
1122  switch (request)
1123  {
1124  case CMD_REQUEST_COMMAND:
1125  {
1126  if (!vote_called) print_to(caller, "^1No vote called.");
1127  else if ((caller == vote_caller) || !caller || caller.vote_master) VoteStop(caller);
1128  else print_to(caller, "^1You are not allowed to stop that vote.");
1129  return;
1130  }
1131 
1132  default:
1133  case CMD_REQUEST_USAGE:
1134  {
1135  print_to(caller, strcat("\nUsage:^3 ", GetCommandPrefix(caller), " vote stop"));
1136  print_to(caller, " No arguments required.");
1137  return;
1138  }
1139  }
1140 }
1141 
1142 void VoteCommand_yes(int request, entity caller) // CLIENT ONLY
1143 {
1144  switch (request)
1145  {
1146  case CMD_REQUEST_COMMAND:
1147  {
1148  if (!vote_called) { print_to(caller, "^1No vote called."); }
1149  else if (caller.vote_selection != VOTE_SELECT_NULL && !autocvar_sv_vote_change)
1150  {
1151  print_to(caller, "^1You have already voted.");
1152  }
1153  else // everything went okay, continue changing vote
1154  {
1155  print_to(caller, "^1You accepted the vote.");
1156  caller.vote_selection = VOTE_SELECT_ACCEPT;
1157  msg_entity = caller;
1159  VoteCount(false);
1160  }
1161 
1162  return;
1163  }
1164 
1165  default:
1166  case CMD_REQUEST_USAGE:
1167  {
1168  print_to(caller, strcat("\nUsage:^3 ", GetCommandPrefix(caller), " vote yes"));
1169  print_to(caller, " No arguments required.");
1170  return;
1171  }
1172  }
1173 }
1174 
1175 /* use this when creating a new command, making sure to place it in alphabetical order... also,
1176 ** ADD ALL NEW COMMANDS TO commands.cfg WITH PROPER ALIASES IN THE SAME FASHION!
1177 void VoteCommand_(int request)
1178 {
1179  switch(request)
1180  {
1181  case CMD_REQUEST_COMMAND:
1182  {
1183 
1184  return;
1185  }
1186 
1187  default:
1188  case CMD_REQUEST_USAGE:
1189  {
1190  print_to(caller, strcat("\nUsage:^3 ", GetCommandPrefix(caller), " vote ");
1191  print_to(caller, " No arguments required.");
1192  return;
1193  }
1194  }
1195 }
1196 */
1197 
1198 
1199 // ================================
1200 // Macro system for vote commands
1201 // ================================
1202 
1203 // Do not hard code aliases for these, instead create them in commands.cfg... also: keep in alphabetical order, please ;)
1204 #define VOTE_COMMANDS(request, caller, arguments, command) \
1205  VOTE_COMMAND("abstain", VoteCommand_abstain(request, caller), "Abstain your vote in current vote", VC_ASGNMNT_CLIENTONLY) \
1206  VOTE_COMMAND("call", VoteCommand_call(request, caller, arguments, command), "Create a new vote for players to decide on", VC_ASGNMNT_BOTH) \
1207  VOTE_COMMAND("help", VoteCommand_macro_help(caller, arguments), "Shows this information", VC_ASGNMNT_BOTH) \
1208  VOTE_COMMAND("master", VoteCommand_master(request, caller, arguments, command), "Full control over all voting and vote commands", VC_ASGNMNT_CLIENTONLY) \
1209  VOTE_COMMAND("no", VoteCommand_no(request, caller), "Select no in current vote", VC_ASGNMNT_CLIENTONLY) \
1210  VOTE_COMMAND("status", VoteCommand_status(request, caller), "Prints information about current vote", VC_ASGNMNT_BOTH) \
1211  VOTE_COMMAND("stop", VoteCommand_stop(request, caller), "Immediately end a vote", VC_ASGNMNT_BOTH) \
1212  VOTE_COMMAND("yes", VoteCommand_yes(request, caller), "Select yes in current vote", VC_ASGNMNT_CLIENTONLY) \
1213  /* nothing */
1214 
1215 void VoteCommand_macro_help(entity caller, int argc)
1216 {
1217  string command_origin = GetCommandPrefix(caller);
1218 
1219  if (argc == 2 || argv(2) == "help") // help display listing all commands
1220  {
1221  print_to(caller, "\nVoting commands:\n");
1222  #define VOTE_COMMAND(name, function, description, assignment) \
1223  { if (Votecommand_check_assignment(caller, assignment)) { print_to(caller, strcat(" ^2", name, "^7: ", description)); } }
1224 
1225  VOTE_COMMANDS(0, caller, 0, "");
1226  #undef VOTE_COMMAND
1227 
1228  print_to(caller, strcat("\nUsage:^3 ", command_origin, " vote <command>^7, where possible commands are listed above.\n"));
1229  print_to(caller, strcat("For help about a specific command, type ", command_origin, " vote help <command>"));
1231  }
1232  else // usage for individual command
1233  {
1234  #define VOTE_COMMAND(name, function, description, assignment) \
1235  { if (Votecommand_check_assignment(caller, assignment)) { if (name == strtolower(argv(2))) { function; return; } } }
1236 
1237  VOTE_COMMANDS(CMD_REQUEST_USAGE, caller, argc, "");
1238  #undef VOTE_COMMAND
1239 
1240  string cvarname = strcat("sv_vote_command_help_", argv(2));
1241  if(cvar_type(cvarname) & CVAR_TYPEFLAG_EXISTS)
1242  wordwrap_sprint(caller, cvar_string(cvarname), 1000);
1243  else if (argv(2) != "")
1244  print_to(caller, "No documentation exists for this vote");
1245  }
1246 }
1247 
1248 float VoteCommand_macro_command(entity caller, int argc, string vote_command)
1249 {
1250  #define VOTE_COMMAND(name, function, description, assignment) \
1251  { if (Votecommand_check_assignment(caller, assignment)) { if (name == strtolower(argv(1))) { function; return true; } } }
1252 
1253  VOTE_COMMANDS(CMD_REQUEST_COMMAND, caller, argc, vote_command);
1254  #undef VOTE_COMMAND
1255 
1256  return false;
1257 }
1258 
1259 
1260 // ======================================
1261 // Main function handling vote commands
1262 // ======================================
1263 
1264 void VoteCommand(int request, entity caller, int argc, string vote_command)
1265 {
1266  // Guide for working with argc arguments by example:
1267  // argc: 1 - 2 - 3 - 4
1268  // argv: 0 - 1 - 2 - 3
1269  // cmd vote - master - login - password
1270 
1271  switch (request)
1272  {
1273  case CMD_REQUEST_COMMAND:
1274  {
1275  if (VoteCommand_macro_command(caller, argc, vote_command)) return;
1276  }
1277 
1278  default:
1279  print_to(caller, strcat(((argv(1) != "") ? strcat("Unknown vote command \"", argv(1), "\"") : "No command provided"), ". For a list of supported commands, try ", GetCommandPrefix(caller), " vote help.\n"));
1280  case CMD_REQUEST_USAGE:
1281  {
1282  VoteCommand_macro_help(caller, argc);
1283  return;
1284  }
1285  }
1286 }
void print_available_commands_to(entity caller)
Definition: vote.qc:837
bool autocvar_sv_timeout
Definition: common.qh:5
float autocvar_sv_vote_majority_factor_of_voted
Definition: vote.qh:8
#define round_handler_IsActive()
float checkrules_suddendeathend
Definition: world.qh:33
void ReadyCount()
Definition: vote.qc:498
float autocvar_timelimit_overtime
Definition: world.qh:27
string OriginalCallerName()
Definition: vote.qc:118
bool autocvar_sv_vote_no_stops_vote
Definition: vote.qh:14
entity GetIndexedEntity(int argc, float start_index)
Definition: common.qc:83
string string_null
Definition: nil.qh:9
void VoteCommand_yes(int request, entity caller)
Definition: vote.qc:1142
const float VC_ASGNMNT_CLIENTONLY
Definition: vote.qh:26
void ReadyRestart_force(bool is_fake_round_start)
Definition: vote.qc:426
bool autocvar_sv_vote_change
Definition: vote.qh:4
string GetCommandPrefix(entity caller)
Definition: common.qc:26
int autocvar_sv_vote_limit
Definition: vote.qh:6
#define IS_CLIENT(v)
Definition: utils.qh:13
void Nagger_VoteChanged()
Definition: vote.qc:102
float autocvar_g_ban_default_bantime
Definition: banning.qh:3
const int CMD_REQUEST_USAGE
Definition: command.qh:4
int autocvar_sv_vote_master_playerlimit
Definition: vote.qh:13
float autocvar_sv_vote_majority_factor
Definition: vote.qh:7
bool autocvar_sv_vote_master_callable
Definition: vote.qh:10
float autocvar_sv_vote_stop
Definition: vote.qh:19
float CVAR_TYPEFLAG_EXISTS
entity() spawn
const float VOTE_MASTER
Definition: vote.qh:38
float VoteCommand_checkinlist(string vote_command, string list)
Definition: vote.qc:564
ClientState CS(Client this)
Definition: state.qh:47
void VoteCommand_call(int request, entity caller, int argc, string vote_command)
Definition: vote.qc:842
void Score_ClearAll()
Clear ALL scores (for ready-restart).
Definition: scores.qc:288
#define FOREACH_CLIENT(cond, body)
Definition: utils.qh:49
void Nagger_VoteCountChanged()
Definition: vote.qc:107
float readycount
Definition: vote.qh:65
int checkrules_overtimesadded
Definition: world.qh:34
void reset_map(bool dorespawn, bool is_fake_round_start)
Definition: vote.qc:339
bool autocvar_sv_vote_call
Definition: vote.qh:3
float checkrules_suddendeathwarning
Definition: world.qh:32
float VerifyClientEntity(entity client, float must_be_real, float must_be_bots)
Definition: common.qc:47
bool warmup_stage
Definition: main.qh:103
#define PS(this)
Definition: state.qh:18
float VoteCommand_macro_command(entity caller, int argc, string vote_command)
Definition: vote.qc:1248
float maxclients
Definition: csprogsdefs.qc:21
entity to
Definition: self.qh:96
void print_to(entity to, string input)
Definition: common.qc:172
void VoteCommand_stop(int request, entity caller)
Definition: vote.qc:1120
float vote_called
Definition: vote.qh:43
const float VOTE_SELECT_NULL
Definition: vote.qh:32
float race_completing
Definition: race.qh:27
string autocvar_sv_vote_commands
Definition: vote.qh:5
void VoteTimeout()
Definition: vote.qc:178
bool autocvar_sv_vote_master
Definition: vote.qh:9
entity result
Definition: promise.qc:43
bool autocvar_sv_vote_singlecount
Definition: vote.qh:18
void Nagger_Init()
Definition: vote.qc:97
bool g_race_qualifying
Definition: race.qh:12
void VoteReject()
Definition: vote.qc:171
const float VOTE_NULL
Definition: vote.qh:36
void VoteCommand_master(int request, entity caller, int argc, string vote_command)
Definition: vote.qc:940
void shuffleteams()
Definition: sv_cmd.qc:1245
#define FOREACH_ENTITY_ORDERED(cond, body)
Definition: iter.qh:138
float autocvar_timelimit_max
Definition: world.qh:26
#define IS_REAL_CLIENT(v)
Definition: utils.qh:17
int VoteCommand_parse(entity caller, string vote_command, string vote_list, float startpos, int argc)
Definition: vote.qc:675
float next_token
Definition: common.qh:71
void Unfreeze(entity targ, bool reset_health)
Definition: damage.qc:546
#define argv_end_index
Definition: dpextensions.qh:30
float vote_endtime
Definition: vote.qh:44
string autocvar_sv_vote_master_commands
Definition: vote.qh:11
void VoteAccept()
Definition: vote.qc:158
#define BIT(n)
Only ever assign into the first 24 bits in QC (so max is BIT(23)).
Definition: bits.qh:8
string VoteCommand_extractcommand(string input, float startpos, int argc)
Definition: vote.qc:534
float vote_accept_count
Definition: vote.qh:45
bool Nagger_SendEntity(entity this, entity to, float sendflags)
Definition: vote.qc:35
entity msg_entity
Definition: progsdefs.qc:63
bool autocvar_teamplay_lockonrestart
Definition: teamplay.qh:6
string vote_parsed_display
Definition: vote.qh:55
const float VOTE_SELECT_REJECT
Definition: vote.qh:31
#define argv_start_index
Definition: dpextensions.qh:27
spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 f1 s1 strcat(_("Level %s: "), "^BG%s\3\, _("^BGPress ^F2%s^BG to enter the game"))
const float VOTE_NORMAL
Definition: vote.qh:37
void accuracy_reset(entity e)
Definition: accuracy.qc:58
int autocvar_sv_timeout_number
Definition: common.qh:8
float autocvar_g_ban_default_masksize
Definition: banning.qh:4
float vote_needed_overall
Definition: vote.qh:48
void VoteThink()
Definition: vote.qc:324
void VoteStop(entity stopper)
Definition: vote.qc:149
string autocvar_sv_vote_master_password
Definition: vote.qh:12
#define NULL
Definition: post.qh:17
const int CMD_REQUEST_COMMAND
Definition: command.qh:3
#define LOG_INFO(...)
Definition: log.qh:70
string vote_parsed_command
Definition: vote.qh:54
bool pure_data
Definition: oo.qh:9
void round_handler_Reset(float next_think)
#define strstrofs
Definition: dpextensions.qh:42
void GameLogEcho(string s)
Definition: gamelog.qc:12
#define IS_NOT_A_CLIENT(v)
was: (clienttype(v) == CLIENTTYPE_NOTACLIENT)
Definition: utils.qh:19
string GetCallerName(entity caller)
Definition: common.qc:33
float VoteCommand_checknasty(string vote_command)
Definition: vote.qc:544
float teamplay
Definition: progsdefs.qc:31
float MapInfo_CheckMap(string s)
Definition: mapinfo.qc:1170
bool Map_IsRecent(string m)
string vote_called_display
Definition: vote.qh:53
bool autocvar_sv_vote_gamestart
Definition: vote.qh:22
void Nagger_ReadyCounted()
Definition: vote.qc:112
entity nagger
Definition: vote.qh:64
bool lockteams
Definition: teamplay.qh:13
#define GetClientErrorString(clienterror, original_input)
Definition: common.qh:87
#define VOTE_COMMANDS(request, caller, arguments, command)
Definition: vote.qc:1204
float vote_reject_count
Definition: vote.qh:46
void ReadyRestart(bool forceWarmupEnd)
Definition: vote.qc:484
string vote_caller_name
Definition: vote.qh:42
bool autocvar_sv_vote_override_mostrecent
Definition: vote.qh:17
bool shuffleteams_on_reset_map
Definition: sv_cmd.qh:7
void Inventory_clear(PlayerState this)
float Votecommand_check_assignment(entity caller, float assignment)
Definition: vote.qc:523
entity vote_caller
Definition: vote.qh:41
const float VOTE_SELECT_ACCEPT
Definition: vote.qh:33
bool sv_ready_restart_after_countdown
Definition: world.qh:119
void VoteCommand_abstain(int request, entity caller)
Definition: vote.qc:803
float vote_abstain_count
Definition: vote.qh:47
#define INGAME_JOINED(it)
Definition: sv_rules.qh:21
string ValidateMap(string validated_map, entity caller)
Definition: vote.qc:573
#define MUTATOR_CALLHOOK(id,...)
Definition: base.qh:140
void VoteCommand_status(int request, entity caller)
Definition: vote.qc:1098
void VoteCommand_no(int request, entity caller)
Definition: vote.qc:1060
#define new_pure(class)
purely logical entities (.origin doesn&#39;t work)
Definition: oo.qh:62
entity int sendflags
Definition: self.qh:96
string MapInfo_FixName(string s)
Definition: mapinfo.qc:1134
#define setthink(e, f)
#define FOREACH_ENTITY_FLOAT_ORDERED(fld, match, body)
Definition: iter.qh:175
const float VOTE_SELECT_ABSTAIN
Definition: vote.qh:30
void VoteCommand(int request, entity caller, int argc, string vote_command)
Definition: vote.qc:1264
void VoteReset()
Definition: vote.qc:128
bool intermission_running
Definition: intermission.qh:9
#define strfree(this)
Definition: string.qh:56
PutClientInServer(this)
float autocvar_sv_vote_wait
Definition: vote.qh:21
void VoteCount(float first_count)
Definition: vote.qc:207
bool autocvar_sv_eventlog
Definition: gamelog.qh:3
if(IS_DEAD(this))
Definition: impulse.qc:92
string vote_called_command
Definition: vote.qh:52
string VoteCommand_checkreplacements(string input)
Definition: vote.qc:555
float time
Definition: csprogsdefs.qc:16
const float RESTART_COUNTDOWN
Definition: vote.qh:63
void VoteCommand_macro_help(entity caller, int argc)
Definition: vote.qc:1215
const float VC_ASGNMNT_SERVERONLY
Definition: vote.qh:27
float VoteCommand_checkargs(float startpos, int argc)
Definition: vote.qc:601
#define spectators_allowed
Definition: vote.qc:205
const float VC_ASGNMNT_BOTH
Definition: vote.qh:25
void ReadyRestart_think(entity this)
Definition: vote.qc:419
void VoteSpam(float notvoters, float mincount, string result)
Definition: vote.qc:185
float autocvar_timelimit_min
Definition: world.qh:25
#define IS_PLAYER(v)
Definition: utils.qh:9
void player_powerups_remove_all(entity this)
Definition: client.qc:1457
float autocvar_sv_vote_timeout
Definition: vote.qh:20