Xonotic QuakeC
The free, fast arena FPS with crisp movement and a wide array of weapons
sv_mapvoting.qc
Go to the documentation of this file.
1#include "sv_mapvoting.qh"
2
3#include "net.qh"
4
7#include <common/state.qh>
8#include <common/stats.qh>
9#include <common/util.qh>
11#include <server/client.qh>
12#include <server/command/cmd.qh>
14#include <server/gamelog.qh>
15#include <server/world.qh>
16
19{
20 Gametype type = MapInfo_Type_FromString(type_name, false, false);
21 if (type == NULL)
23 strcat("sv_vote_gametype_", type_name, "_type")), false, false);
24 return type;
25}
26
28{
29 int flag = GTV_FORBIDDEN;
30
31 Gametype type = MapInfo_Type_FromString(type_name, false, false);
32 if (type == NULL)
33 {
35 strcat("sv_vote_gametype_", type_name, "_type")), false, false);
36 flag |= GTV_CUSTOM;
37 }
38 if (type == NULL)
39 return flag;
40
41 if (get_nextmap() != "")
42 {
43 if (!MapInfo_Get_ByName(get_nextmap(), false, NULL))
44 return flag;
45 if (!(MapInfo_Map_supportedGametypes & type.gametype_flags))
46 return flag;
47 }
48
49 return flag | GTV_AVAILABLE;
50}
51
53{
54 vector gametype_mask = '0 0 0';
56 n = min(MAPVOTE_COUNT, n);
57 for (int i = 0; i < n; ++i)
58 gametype_mask |= GameTypeVote_Type_FromString(argv(i)).gametype_flags;
59
60 if (gametype_mask == '0 0 0')
61 gametype_mask = MapInfo_CurrentGametype().gametype_flags;
62
63 return gametype_mask;
64}
65
75
77{
78 FOREACH_CLIENT(true, it.mapvote = 0);
79}
80
82{
83 for (int i = 0; i < mv_count; ++i)
84 {
87 // mv_suggester is set to the netname of the suggester, so can't & doesn't need to be unzoned
88 }
89}
90
91string MapVote_Suggest(entity this, string m)
92{
93 if (m == "")
94 return "That's not how to use this command.";
96 return "Suggestions are not accepted on this server.";
98 return "Can't suggest, voting is already in progress.";
100 if (!m)
101 return "The map you suggested is not available on this server.";
103 return "This server does not allow for recent maps to be played again. Please be patient for some rounds.";
104
106 return "The map you suggested does not support the current gametype.";
107 int i;
108 for (i = 0; i < mv_suggestion_ptr; ++i)
109 if (mv_suggestions[i] == m)
110 return "This map was already suggested.";
113 else
114 {
117 }
118
119 if (mv_suggestions[i] != "")
121 mv_suggestions[i] = strzone(m);
122 mv_suggester[i] = this.netname;
123
125 GameLogEcho(strcat(":vote:suggested:", m, ":", itos(this.playerid)));
126 return strcat("Suggestion of ", m, " accepted.");
127}
128
129bool MapVote_AddVotable(int from_i)
130{
131 string next_map = "";
132 if (from_i == -1) // GetNextMap
133 next_map = GetNextMap();
134 else if (from_i == -2) // abstain
135 next_map = "don't care";
136 else
137 next_map = mv_suggestions[from_i];
138 if (next_map == "")
139 return false;
140
141 string suggester = (from_i >= 0 ? mv_suggester[from_i] : "");
142 int i;
143 if (suggester == "")
144 {
145 for (i = 0; i < mv_count; ++i)
146 if (mv_entries[i] == next_map)
147 return false;
148 }
149 else if (!MapInfo_CheckMap(next_map))
150 // suggestions might be no longer valid/allowed after gametype switch!
151 return false;
152
153 string pakfile = string_null;
154 for (i = 0; i < mv_ssdirs_count; ++i)
155 {
156 string mapfile = strcat(mv_ssdirs[i], "/", next_map);
157 pakfile = whichpack(strcat(mapfile, ".tga"));
158 if (pakfile == "")
159 pakfile = whichpack(strcat(mapfile, ".jpg"));
160 if (pakfile == "")
161 pakfile = whichpack(strcat(mapfile, ".png"));
162 if (pakfile != "")
163 break;
164 }
165 if (i >= mv_ssdirs_count)
166 i = 0; // FIXME maybe network this error case, as that means there is no mapshot on th=e server?
167 for (int o = strstrofs(pakfile, "/", 0); o >= 0; o = strstrofs(pakfile, "/", 0))
168 pakfile = substring(pakfile, o + 1, -1);
169
170 mv_entries[mv_count] = strzone(next_map);
172 mv_ssdir_i[mv_count] = i;
173 mv_pakfile[mv_count] = strzone(pakfile);
175 if (suggester != "" && from_i != mv_count)
176 {
177 // swap accepted suggestion with wherever it came from
180 mv_suggestions[mv_count] = next_map;
181 mv_suggester[mv_count] = suggester;
182 }
183
184 ++mv_count;
185 return true;
186}
187
188void MapVote_AddVotableMaps(int nmax, int smax)
189{
190 int available_maps = Maplist_Init();
191 int max_attempts = (available_maps < 2)
192 ? available_maps
193 : min(available_maps * 5, 100);
194
202 if (smax && mv_suggestion_ptr)
203 {
204 int i, last_i = mv_suggestion_ptr - 1;
206 {
207 // mv_suggestion_ptr <= smax, so mv_count + fails < mv_suggestion_ptr
208 i = floor(random() * (last_i - mv_count + 1)) + mv_count;
209 if (!MapVote_AddVotable(i))
210 {
211 // replace failed suggestion with the one at the end of the list, and shorten the list
212 mv_suggestions[i] = mv_suggestions[last_i];
213 mv_suggester[i] = mv_suggester[last_i];
214 mv_suggestions[last_i] = "";
215 mv_suggester[last_i] = "";
216 --last_i;
217 }
218 }
219 for (i = mv_count; i <= last_i; ++i) // may need to clear unused suggestions,
220 { // if g_maplist_votable_suggestions < mv_suggestion_ptr
221 mv_suggestions[i] = "";
222 mv_suggester[i] = "";
223 }
224 }
225 for (int att = 0; att < max_attempts && mv_count < nmax; ++att)
226 MapVote_AddVotable(-1); // GetNextMap
227
228 mv_ranked[0] = 0;
229
231}
232
235{
238
239 mv_count = 0;
244
245 int nmax = (mv_abstain)
249
250 // we need this for AddVotable, as that cycles through the screenshot dirs
252 if (mv_ssdirs_count == 0)
253 mv_ssdirs_count = tokenize_console("maps levelshots");
255 for (int i = 0; i < mv_ssdirs_count; ++i)
256 mv_ssdirs[i] = strzone(argv(i));
257
258 MapVote_AddVotableMaps(nmax, smax);
259
261 if (mv_abstain)
262 MapVote_AddVotable(-2); // abstain
263
264 //dprint("mapvote count is ", itos(mv_count), "\n");
265
269 if (mv_count_real < 3 || mv_reduce_time <= time)
270 mv_reduce_time = 0;
271
273
274 /* If match_gametype is set it means voted_gametype has just been applied (on gametype vote end).
275 * In this case apply back match_gametype here so that the "restart" command, if called,
276 * properly restarts the map applying the current gametype.
277 * Applying voted_gametype before map vote start is needed to properly initialize map vote.
278 */
279 if (match_gametype)
280 {
281 string gametype_custom_string = (gametype_custom_enabled)
283 : "";
284 GameTypeVote_SetGametype(match_gametype, gametype_custom_string, true);
285 }
286}
287
288bool MapVote_Finished(int mappos)
289{
291 return false;
292
294 {
295 string result = strcat(":vote:finished:", mv_entries[mappos],
296 ":", itos(mv_votes[mappos]), "::");
297 int didnt_vote = mv_voters;
298 for (int i = 0; i < mv_count; ++i)
299 if (mv_flags[i] & GTV_AVAILABLE)
300 {
301 didnt_vote -= mv_votes[i];
302 if (i != mappos)
303 result = strcat(result, ":", mv_entries[i],
304 ":", itos(mv_votes[i]));
305 }
306 result = strcat(result, ":didn't vote:", itos(didnt_vote));
307
309 if (!gametypevote && mv_suggester[mappos] != "")
310 GameLogEcho(strcat(":vote:suggestion_accepted:", mv_entries[mappos]));
311 }
312
314
315 if (gametypevote)
316 {
317 if (GameTypeVote_Finished(mappos))
318 {
319 gametypevote = false;
320 if (get_nextmap() != "")
321 {
323 Map_Goto(0);
324 alreadychangedlevel = true;
326 return true;
327 }
328 else
329 MapVote_Init();
330 }
331 return false;
332 }
333
334 mv_winner = mappos;
336 MapVote_Winner(mappos);
337 alreadychangedlevel = true;
338
339 return true;
340}
341
342void MapVote_ranked_swap(int i, int j, entity pass)
343{
344 TC(int, i); TC(int, j);
345 int tmp = mv_ranked[i];
346 mv_ranked[i] = mv_ranked[j];
347 mv_ranked[j] = tmp;
348}
350{
351 TC(int, i); TC(int, j);
352 int ri = mv_ranked[i];
353 int rj = mv_ranked[j];
354 bool avail_i = (mv_flags[ri] & GTV_AVAILABLE);
355 bool avail_j = (mv_flags[rj] & GTV_AVAILABLE);
356 if (avail_j && !avail_i) // i isn't votable, just move it to the end
357 return 1;
358 if (avail_i && !avail_j) // j isn't votable, just move it to the end
359 return -1;
360 if (!avail_i && !avail_j)
361 return 0;
362
363 int votes_i = mv_votes[ri];
364 int votes_j = mv_votes[rj];
365 if (votes_i <= 0 && rj == current_gametype_index) // j is the current and should be used
366 return 1;
367 if (votes_j <= 0 && ri == current_gametype_index) // i is the current and should be used
368 return -1;
369 if (votes_i == votes_j) // randomly choose which goes first
370 return (mv_rng[rj] > mv_rng[ri]) ? 1 : -1;
371 return votes_j - votes_i; // descending order
372}
373
375{
376 int idx, i;
377 for (i = 0; i < mv_count; ++i) // reset all votes
378 if (mv_flags[i] & GTV_AVAILABLE)
379 {
380 //dprint("Map ", itos(i), ": "); dprint(mv_entries[i], "\n");
381 mv_votes[i] = 0;
382 }
383
384 mv_voters = 0;
385 FOREACH_CLIENT(IS_REAL_CLIENT(it), // add votes
386 {
387 ++mv_voters;
388 if (it.mapvote)
389 {
390 idx = it.mapvote - 1;
391 //dprint("Player ", it.netname, " vote = ", itos(idx), "\n");
392 ++mv_votes[idx];
393 }
394 });
395
396 for (i = 0; i < mv_count; ++i) // sort by most votes, for any ties choose randomly
397 mv_ranked[i] = i; // populate up to mv_count, only bother sorting up to mv_count_real
399}
400
402{
403 if (mv_count_real == 1)
404 return MapVote_Finished(0);
405
406 int mv_voters_real = mv_voters;
407 if (mv_abstain)
408 mv_voters_real -= mv_votes[mv_count - 1]; // excluding abstainers
409
410 //dprint("1st place index: ", itos(mv_ranked[0]), "\n");
411 //dprint("1st place votes: ", itos(mv_votes[mv_ranked[0]]), "\n");
412 //dprint("2nd place index: ", itos(mv_ranked[1]), "\n");
413 //dprint("2nd place votes: ", itos(mv_votes[mv_ranked[1]]), "\n");
414
415 // these are used to check whether even if everyone else all voted for one map,
416 // ... it wouldn't be enough to push it into the top `reduce_count` maps
417 // i.e. reducing can start early
418 int votes_recent = mv_votes[mv_ranked[0]];
419 int votes_running_total = votes_recent;
420
421 if (time > mv_timeout
422 || (mv_voters_real - votes_running_total) < votes_recent
423 || mv_voters_real == 0) // all abstained
424 return MapVote_Finished(mv_ranked[0]); // choose best
425
426 // if mv_reduce_count is >= 2, we reduce to the top `reduce_count`, keeping exactly that many
427 // if it's < 2, we keep all maps that received at least 1 vote, as long as there's at least 2
428 int ri, i;
429 bool keep_exactly = (mv_reduce_count >= 2);
430#define REDUCE_REMOVE_THIS(idx) (keep_exactly \
431 ? (idx >= mv_reduce_count) \
432 : (mv_votes[mv_ranked[idx]] <= 0))
433 for (ri = 1; ri < mv_count; ++ri)
434 {
435 i = mv_ranked[ri];
436 if (REDUCE_REMOVE_THIS(ri))
437 break;
438 votes_recent = mv_votes[i];
439 votes_running_total += votes_recent;
440 }
441
442 if (mv_reduce_time)
443 if ((time > mv_reduce_time && (keep_exactly || ri >= 2))
444 || (mv_voters_real - votes_running_total) < votes_recent)
445 {
447 mv_reduce_time = 0;
448 string result = ":vote:reduce";
449 int didnt_vote = mv_voters;
450 bool remove = false;
451 for (ri = 0; ri < mv_count; ++ri)
452 {
453 i = mv_ranked[ri];
454 didnt_vote -= mv_votes[i];
455 result = strcat(result, ":", mv_entries[i],
456 ":", itos(mv_votes[i]));
457 if (!remove && REDUCE_REMOVE_THIS(ri))
458 {
459 result = strcat(result, "::"); // separator between maps kept and maps removed
460 remove = true;
461 }
462 if (remove && i < mv_count_real)
463 mv_flags[i] &= ~GTV_AVAILABLE; // make it not votable
464 }
465 result = strcat(result, ":didn't vote:", itos(didnt_vote));
468 }
469#undef REDUCE_REMOVE_THIS
470
471 return false;
472}
473
475{
478 return;
479
480 FOREACH_CLIENT(true,
481 {
482 if (!IS_REAL_CLIENT(it))
483 {
484 // apply the same special health value to bots too for consistency's sake
485 if (GetResource(it, RES_HEALTH) != 2342)
486 SetResourceExplicit(it, RES_HEALTH, 2342);
487 continue;
488 }
489 // hide scoreboard again
490 if (GetResource(it, RES_HEALTH) != 2342)
491 {
492 SetResourceExplicit(it, RES_HEALTH, 2342); // health in the voting phase
493 CS(it).impulse = 0;
494
495 msg_entity = it;
497 WriteString(MSG_ONE, "");
498 }
499
501 });
502
503 MapVote_CheckRules_count(); // just count
504}
505
507{
508 // if mapvote is already running, don't do this initialization again
509 if (mapvote_run)
510 return;
511
512 // don't start mapvote until after playerstats gamereport is sent
514 return;
515
518 mapvote_run = true;
519}
520
522{
523 // no think delay, so that impulses (votes) are checked every frame
524
525 if (!mapvote_run)
526 return;
527
528 if (mv_winner_time)
529 {
530 if (time > mv_winner_time + 1)
531 {
532 if (voted_gametype)
533 {
534 // clear match_gametype so that GameTypeVote_SetGametype
535 // prints the gametype switch message
538 }
539
541 Map_Goto(0);
543 }
544 return;
545 }
546
548 return;
549
551 {
553 {
554 cvar_set("rescan_pending", "2");
555 localcmd("\nfs_rescan\nrescan_pending 3\n");
556 return;
557 }
558 else if (autocvar_rescan_pending == 2)
559 return;
560 else if (autocvar_rescan_pending == 3)
561 {
562 // now build missing mapinfo files
564 return;
565
566 // we're done, start the timer
567 cvar_set("rescan_pending", "0");
568 }
569
570 mapvote_initialized = true;
571 if (DoNextMapOverride(0))
572 return;
574 {
575 GotoNextMap(0);
576 return;
577 }
578
581 else if (get_nextmap() == "")
582 MapVote_Init();
583 }
584
585 MapVote_Tick();
586}
587
588// if gametype_string is "" then gametype_string is inferred from Gametype type
589// otherwise gametype_string is the string (short name) of a custom gametype
590bool GameTypeVote_SetGametype(Gametype type, string gametype_string, bool call_hooks)
591{
592 if (gametype_string == "")
593 gametype_string = MapInfo_Type_ToString(type);
594 if (!call_hooks)
595 // custom gametype is disabled because gametype hooks can't be executed
597 else
598 {
599 gametype_custom_enabled = (gametype_string != MapInfo_Type_ToString(type));
600
601 localcmd("\nsv_vote_gametype_hook_all\n");
602 localcmd("\nsv_vote_gametype_hook_", gametype_string, "\n");
603 }
604
605 if (MapInfo_CurrentGametype() == type)
606 return true;
607
609
611
614 if (MapInfo_count > 0)
615 {
616 // update lsmaps in case the gametype changed, this way people can easily list maps for it
617 if (lsmaps_reply != "")
620
621 if (!match_gametype) // don't show this msg if we are temporarily switching gametype
622 bprint("Gametype successfully switched to ", MapInfo_Type_ToString(type), "\n");
623 }
624 else
625 {
626 bprint("Cannot use this gametype: no map for it found\n");
629 return false;
630 }
631
633 string gvmaplist = strcat("sv_vote_gametype_", gametype_string, "_maplist");
634 if (cvar_type(gvmaplist) & CVAR_TYPEFLAG_EXISTS)
635 {
636 // force a reset if the provided list is empty
637 if (cvar_string(gvmaplist) == "")
638 do_reset = true;
639 else
640 cvar_set("g_maplist", cvar_string(gvmaplist));
641 }
642 if (do_reset)
644
645 return true;
646}
647
650{
652 return false;
653
657
659
660 // save to a cvar so it can be applied back when gametype is temporary
661 // changed on gametype vote end of the next game
662 if (mv_flags[pos] & GTV_CUSTOM)
663 cvar_set("_sv_vote_gametype_custom", voted_gametype_string);
664
666 return true;
667}
668
669bool GameTypeVote_AddVotable(string nextMode)
670{
671 if (nextMode == "" || GameTypeVote_Type_FromString(nextMode) == NULL)
672 return false;
673
674 for (int i = 0; i < mv_count; ++i)
675 if (mv_entries[i] == nextMode)
676 return false;
677
678 mv_entries[mv_count] = strzone(nextMode);
679 mv_ssdir_i[mv_count] = 0;
680 // suggester will be uninitialized, but it's never read until map voting, before which it has been set
682
683 ++mv_count;
684 return true;
685}
686
688{
691
692 mv_count = 0;
694 mv_abstain = false;
696
698 n = min(MAPVOTE_COUNT, n);
699
700 int really_available = 0;
701 int which_available = -1;
702 int i;
703 for (i = 0; i < n; ++i)
705 && (mv_flags[i] & GTV_AVAILABLE))
706 {
707 ++really_available;
708 which_available = i;
709 }
710
712
713 gametypevote = true;
714
715 const string current_gametype_string = (gametype_custom_enabled)
718
719 if (really_available == 0)
720 {
721 if (mv_count > 0)
723 mv_entries[0] = strzone(current_gametype_string);
725 //GameTypeVote_Finished(0);
727 return false;
728 }
729 if (really_available == 1)
730 {
731 current_gametype_index = which_available;
732 //GameTypeVote_Finished(which_available);
734 return false;
735 }
737 if (autocvar_sv_vote_gametype_default_current) // find current gametype index
738 for (i = 0; i < mv_count_real; ++i)
739 if (mv_entries[i] == current_gametype_string)
740 {
742 break;
743 }
744
746
749 if (mv_count_real < 3 || mv_reduce_time <= time)
750 mv_reduce_time = 0;
751
753 return true;
754}
int player_count
Definition api.qh:103
var entity(vector mins, vector maxs,.entity tofield) findbox_tofield_OrFallback
float mv_winner_time
bool gametypevote
float GetResource(entity e, Resource res_type)
Returns the current amount of resource the given entity has.
string netname
Definition powerups.qc:20
string lsmaps_reply
Definition util.qh:161
float CVAR_TYPEFLAG_EXISTS
float time
#define strstrofs
#define tokenize_console
#define tokenizebyseparator
#define pass(name, colormin, colormax)
WriteString(chan, ent.netname)
WriteByte(chan, ent.angles.y/DEC_FACTOR)
SetResourceExplicit(ent, RES_ARMOR, ReadByte() *DEC_FACTOR)) ENTCS_PROP(NAME
void GameLogEcho(string s)
Definition gamelog.qc:15
bool autocvar_sv_eventlog
Definition gamelog.qh:3
string getlsmaps()
#define itos(i)
Definition int.qh:6
void Maplist_Close()
void Map_Goto_SetStr(string nextmapname)
bool Map_IsRecent(string m)
int Maplist_Init(void)
void Map_Goto(float reinit)
string GetNextMap(void)
float DoNextMapOverride(float reinit)
void GotoNextMap(float reinit)
bool alreadychangedlevel
#define get_nextmap()
#define TC(T, sym)
Definition _all.inc:82
float MapInfo_CheckMap(string s)
Definition mapinfo.qc:1502
float MapInfo_FilterGametype(Gametype pGametype, int pFeatures, int pFlagsRequired, int pFlagsForbidden, bool pAbortOnGenerate)
Definition mapinfo.qc:176
int MapInfo_RequiredFlags()
Definition mapinfo.qc:1670
string MapInfo_Type_ToString(Gametype t)
Definition mapinfo.qc:655
float _MapInfo_FilterGametype(vector pGametype, int pFeatures, int pFlagsRequired, int pFlagsForbidden, bool pAbortOnGenerate)
Definition mapinfo.qc:180
Gametype MapInfo_CurrentGametype()
Definition mapinfo.qc:1482
int MapInfo_Get_ByName(string pFilename, float pAllowGenerate, Gametype pGametypeToSet)
Definition mapinfo.qc:1382
int MapInfo_ForbiddenFlags()
Definition mapinfo.qc:1655
int MapInfo_CurrentFeatures()
Definition mapinfo.qc:1472
string MapInfo_ListAllowedMaps(Gametype type, float pRequiredFlags, float pForbiddenFlags)
Definition mapinfo.qc:1533
void MapInfo_SwitchGameType(Gametype t)
Definition mapinfo.qc:1509
Gametype MapInfo_Type_FromString(string gtype, bool dowarn, bool is_q3compat)
Definition mapinfo.qc:620
void MapInfo_Enumerate()
Definition mapinfo.qc:134
string MapInfo_FixName(string s)
Definition mapinfo.qc:1466
vector MapInfo_Map_supportedGametypes
Definition mapinfo.qh:13
float MapInfo_count
Definition mapinfo.qh:166
void MapVote_ReadPlayerVote(entity voter)
Definition net.qc:27
void MapVote_TouchMask()
Definition net.qc:13
void MapVote_Winner(int mappos)
Definition net.qc:17
void MapVote_Spawn()
Definition net.qc:8
bool mv_abstain
(shared) if abstaining is possible, false in gametype voting
Definition mapvoting.qh:21
int mv_count
(shared) number of maps/gametypes
Definition mapvoting.qh:14
const int GTV_CUSTOM
Custom entry.
Definition mapvoting.qh:29
const int GTV_FORBIDDEN
Cannot be voted.
Definition mapvoting.qh:27
int mv_ssdirs_count
Definition mapvoting.qh:10
int mv_flags[MAPVOTE_COUNT]
(shared) map/gametype flags
Definition mapvoting.qh:18
const int MAPVOTE_COUNT
Max number of votable maps/gametypes.
Definition mapvoting.qh:6
string mv_entries[MAPVOTE_COUNT]
(shared) map name or gametype name
Definition mapvoting.qh:16
int mv_detail
(shared) how much information about the votes/results is revealed
Definition mapvoting.qh:20
string mv_ssdirs[MAPVOTE_SSDIRS_COUNT]
Definition mapvoting.qh:9
float mv_reduce_time
Definition mapvoting.qh:22
int mv_winner
Definition mapvoting.qh:24
int mv_count_real
(shared) number of maps/gametypes, excluding abstain
Definition mapvoting.qh:15
const int GTV_AVAILABLE
Can be voted.
Definition mapvoting.qh:28
int mv_votes[MAPVOTE_COUNT]
(shared) number of votes for the map/gametype
Definition mapvoting.qh:19
const int MAPVOTE_SSDIRS_COUNT
Definition mapvoting.qh:8
string mv_suggester[MAPVOTE_COUNT]
(maps) .netname of the player who suggested the map
Definition mapvoting.qh:17
float mv_timeout
Definition mapvoting.qh:23
void localcmd(string command,...)
void cvar_set(string name, string value)
float MSG_ONE
Definition menudefs.qc:56
string substring(string s, float start, float length)
float random(void)
void bprint(string text,...)
const string cvar_string(string name)
float min(float f,...)
void strunzone(string s)
float floor(float f)
string strzone(string s)
string argv(float n)
string string_null
Definition nil.qh:9
strcat(_("^F4Countdown stopped!"), "\n^BG", _("Teams are too unbalanced."))
bool PlayerStats_GameReport_DelayMapVote
#define NULL
Definition post.qh:14
#define remove
Definition pre.qh:9
entity msg_entity
Definition progsdefs.qc:63
float SVC_FINALE
Definition progsdefs.qc:341
entity result
Definition promise.qc:45
vector
Definition self.qh:96
void FixClientCvars(entity e)
Definition client.qc:999
int playerid
Definition client.qh:82
ERASEABLE void heapsort(int n, swapfunc_t swap, comparefunc_t cmp, entity pass)
Definition sort.qh:9
ClientState CS(Client this)
Definition state.qh:47
#define strfree(this)
Definition string.qh:57
#define strcpy(this, s)
Definition string.qh:51
bool GameTypeVote_Finished(int pos)
string MapVote_Suggest(entity this, string m)
string GameTypeVote_MapInfo_FixName(string m)
void MapVote_AddVotableMaps(int nmax, int smax)
int current_gametype_index
bool GameTypeVote_SetGametype(Gametype type, string gametype_string, bool call_hooks)
vector GameTypeVote_GetMask()
void MapVote_ClearAllVotes()
bool MapVote_CheckRules_decide()
bool MapVote_Finished(int mappos)
void MapVote_Think()
void MapVote_Tick()
bool GameTypeVote_Start()
bool gametypevote_finished
void MapVote_UnzoneStrings()
void MapVote_Init()
Gametype GameTypeVote_Type_FromString(string type_name)
Returns the gamtype ID from its name, if type_name isn't a real gametype it checks for sv_vote_gamety...
int GameTypeVote_AvailabilityStatus(string type_name)
void MapVote_CheckRules_count()
bool MapVote_AddVotable(int from_i)
void MapVote_Start()
bool GameTypeVote_AddVotable(string nextMode)
void MapVote_ranked_swap(int i, int j, entity pass)
int MapVote_ranked_cmp(int i, int j, entity pass)
#define REDUCE_REMOVE_THIS(idx)
Gametype match_gametype
Gametype voted_gametype
#define autocvar_g_maplist_votable
float mv_rng[MAPVOTE_COUNT]
(shared) random() value for each map/gametype to determine tiebreakers
bool autocvar_sv_vote_gametype
int autocvar_g_maplist_votable_detail
bool mapvote_initialized
float autocvar_sv_vote_gametype_reduce_time
string autocvar_g_maplist_votable_screenshot_dir
int mv_ranked[MAPVOTE_COUNT]
(shared) maps/gametypes ranked by most votes, first = most
int mv_reduce_count
string mv_pakfile[MAPVOTE_COUNT]
(maps) pk3 file location
string voted_gametype_string
float autocvar_sv_vote_gametype_timeout
bool autocvar_g_maplist_votable_suggestions_override_mostrecent
bool autocvar_g_maplist_votable_show_suggester
int mv_suggestion_ptr
(maps) index of where the next suggestion should be (starts as 0)
bool autocvar_sv_vote_gametype_maplist_reset
int mv_voters
(shared) number of human voters present
string autocvar_sv_vote_gametype_options
float autocvar_g_maplist_votable_timeout
bool mv_show_suggester
(maps) whether to show suggesters, only for maps since you can't suggest gametypes
bool autocvar_g_maplist_votable_suggestions
bool autocvar_sv_vote_gametype_default_current
int autocvar_g_maplist_votable_reduce_count
string mv_suggestions[MAPVOTE_COUNT]
(maps) name of the suggested map, later copied into mv_entries
bool autocvar_g_maplist_votable_abstain
int autocvar_rescan_pending
int autocvar_sv_vote_gametype_reduce_count
float autocvar_g_maplist_votable_reduce_time
bool mapvote_run
int mv_ssdir_i[MAPVOTE_COUNT]
(shared) where to look for screenshots (mv_ssdirs index), set to 0 for gametype voting
int autocvar_sv_vote_gametype_detail
#define IS_REAL_CLIENT(v)
Definition utils.qh:17
#define FOREACH_CLIENT(cond, body)
Definition utils.qh:52
string loaded_gametype_custom_string
Definition world.qh:53
bool gametype_custom_enabled
Definition world.qh:52