Xonotic QuakeC
The free, fast arena FPS with crisp movement and a wide array of weapons
sv_mapvoting.qc File Reference
#include "sv_mapvoting.qh"
#include "net.qh"
#include <common/net_linked.qh>
#include <common/playerstats.qh>
#include <common/state.qh>
#include <common/stats.qh>
#include <common/util.qh>
#include <common/weapons/_all.qh>
#include <server/client.qh>
#include <server/command/cmd.qh>
#include <server/command/getreplies.qh>
#include <server/gamelog.qh>
#include <server/world.qh>
Include dependency graph for sv_mapvoting.qc:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Macros

#define REDUCE_REMOVE_THIS(idx)

Functions

bool GameTypeVote_AddVotable (string nextMode)
int GameTypeVote_AvailabilityStatus (string type_name)
bool GameTypeVote_Finished (int pos)
vector GameTypeVote_GetMask ()
string GameTypeVote_MapInfo_FixName (string m)
bool GameTypeVote_SetGametype (Gametype type, string gametype_string, bool call_hooks)
bool GameTypeVote_Start ()
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_gametype_(type_name)_type.
bool MapVote_AddVotable (int from_i)
void MapVote_AddVotableMaps (int nmax, int smax)
void MapVote_CheckRules_count ()
bool MapVote_CheckRules_decide ()
void MapVote_ClearAllVotes ()
bool MapVote_Finished (int mappos)
void MapVote_Init ()
int MapVote_ranked_cmp (int i, int j, entity pass)
void MapVote_ranked_swap (int i, int j, entity pass)
void MapVote_Start ()
string MapVote_Suggest (entity this, string m)
void MapVote_Think ()
void MapVote_Tick ()
void MapVote_UnzoneStrings ()

Variables

int current_gametype_index
bool gametypevote_finished

Macro Definition Documentation

◆ REDUCE_REMOVE_THIS

#define REDUCE_REMOVE_THIS ( idx)
Value:
(keep_exactly \
? (idx >= mv_reduce_count) \
: (mv_votes[mv_ranked[idx]] <= 0))
int mv_votes[MAPVOTE_COUNT]
(shared) number of votes for the map/gametype
Definition mapvoting.qh:19
int mv_ranked[MAPVOTE_COUNT]
(shared) maps/gametypes ranked by most votes, first = most
int mv_reduce_count

Referenced by MapVote_CheckRules_decide().

Function Documentation

◆ GameTypeVote_AddVotable()

bool GameTypeVote_AddVotable ( string nextMode)

Definition at line 669 of file sv_mapvoting.qc.

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}
int mv_count
(shared) number of maps/gametypes
Definition mapvoting.qh:14
int mv_flags[MAPVOTE_COUNT]
(shared) map/gametype flags
Definition mapvoting.qh:18
string mv_entries[MAPVOTE_COUNT]
(shared) map name or gametype name
Definition mapvoting.qh:16
string strzone(string s)
#define NULL
Definition post.qh:14
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)
int mv_ssdir_i[MAPVOTE_COUNT]
(shared) where to look for screenshots (mv_ssdirs index), set to 0 for gametype voting

References GameTypeVote_AvailabilityStatus(), GameTypeVote_Type_FromString(), mv_count, mv_entries, mv_flags, mv_ssdir_i, NULL, and strzone().

Referenced by GameTypeVote_Start().

◆ GameTypeVote_AvailabilityStatus()

int GameTypeVote_AvailabilityStatus ( string type_name)

Definition at line 27 of file sv_mapvoting.qc.

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}
#define get_nextmap()
int MapInfo_Get_ByName(string pFilename, float pAllowGenerate, Gametype pGametypeToSet)
Definition mapinfo.qc:1382
Gametype MapInfo_Type_FromString(string gtype, bool dowarn, bool is_q3compat)
Definition mapinfo.qc:620
vector MapInfo_Map_supportedGametypes
Definition mapinfo.qh:13
const int GTV_CUSTOM
Custom entry.
Definition mapvoting.qh:29
const int GTV_FORBIDDEN
Cannot be voted.
Definition mapvoting.qh:27
const int GTV_AVAILABLE
Can be voted.
Definition mapvoting.qh:28
const string cvar_string(string name)
strcat(_("^F4Countdown stopped!"), "\n^BG", _("Teams are too unbalanced."))

References cvar_string(), get_nextmap, GTV_AVAILABLE, GTV_CUSTOM, GTV_FORBIDDEN, MapInfo_Get_ByName(), MapInfo_Map_supportedGametypes, MapInfo_Type_FromString(), NULL, and strcat().

Referenced by GameTypeVote_AddVotable().

◆ GameTypeVote_Finished()

bool GameTypeVote_Finished ( int pos)

Definition at line 649 of file sv_mapvoting.qc.

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}
bool gametypevote
Gametype MapInfo_CurrentGametype()
Definition mapinfo.qc:1482
void cvar_set(string name, string value)
#define strcpy(this, s)
Definition string.qh:51
bool GameTypeVote_SetGametype(Gametype type, string gametype_string, bool call_hooks)
bool gametypevote_finished
Gametype match_gametype
Gametype voted_gametype
string voted_gametype_string

References cvar_set(), gametypevote, gametypevote_finished, GameTypeVote_SetGametype(), GameTypeVote_Type_FromString(), GTV_CUSTOM, MapInfo_CurrentGametype(), match_gametype, mv_entries, mv_flags, strcpy, voted_gametype, and voted_gametype_string.

Referenced by MapVote_Finished().

◆ GameTypeVote_GetMask()

vector GameTypeVote_GetMask ( )

Definition at line 52 of file sv_mapvoting.qc.

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}
#define tokenizebyseparator
const int MAPVOTE_COUNT
Max number of votable maps/gametypes.
Definition mapvoting.qh:6
float min(float f,...)
string argv(float n)
vector
Definition self.qh:96
string autocvar_sv_vote_gametype_options

References argv(), autocvar_sv_vote_gametype_options, GameTypeVote_Type_FromString(), MapInfo_CurrentGametype(), MAPVOTE_COUNT, min(), tokenizebyseparator, and vector.

Referenced by GameTypeVote_MapInfo_FixName().

◆ GameTypeVote_MapInfo_FixName()

string GameTypeVote_MapInfo_FixName ( string m)

Definition at line 66 of file sv_mapvoting.qc.

67{
69 {
72 }
73 return MapInfo_FixName(m);
74}
int MapInfo_RequiredFlags()
Definition mapinfo.qc:1670
float _MapInfo_FilterGametype(vector pGametype, int pFeatures, int pFlagsRequired, int pFlagsForbidden, bool pAbortOnGenerate)
Definition mapinfo.qc:180
int MapInfo_ForbiddenFlags()
Definition mapinfo.qc:1655
void MapInfo_Enumerate()
Definition mapinfo.qc:134
string MapInfo_FixName(string s)
Definition mapinfo.qc:1466
vector GameTypeVote_GetMask()
bool autocvar_sv_vote_gametype

References _MapInfo_FilterGametype(), autocvar_sv_vote_gametype, GameTypeVote_GetMask(), MapInfo_Enumerate(), MapInfo_FixName(), MapInfo_ForbiddenFlags(), and MapInfo_RequiredFlags().

Referenced by DoNextMapOverride(), GotoMap(), and MapVote_Suggest().

◆ GameTypeVote_SetGametype()

bool GameTypeVote_SetGametype ( Gametype type,
string gametype_string,
bool call_hooks )

Definition at line 590 of file sv_mapvoting.qc.

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}
string lsmaps_reply
Definition util.qh:161
float CVAR_TYPEFLAG_EXISTS
string getlsmaps()
float MapInfo_FilterGametype(Gametype pGametype, int pFeatures, int pFlagsRequired, int pFlagsForbidden, bool pAbortOnGenerate)
Definition mapinfo.qc:176
string MapInfo_Type_ToString(Gametype t)
Definition mapinfo.qc:655
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
float MapInfo_count
Definition mapinfo.qh:166
void localcmd(string command,...)
void bprint(string text,...)
void strunzone(string s)
bool autocvar_sv_vote_gametype_maplist_reset
bool gametype_custom_enabled
Definition world.qh:52

References autocvar_sv_vote_gametype_maplist_reset, bprint(), cvar_set(), cvar_string(), CVAR_TYPEFLAG_EXISTS, gametype_custom_enabled, getlsmaps(), localcmd(), lsmaps_reply, MapInfo_count, MapInfo_CurrentFeatures(), MapInfo_CurrentGametype(), MapInfo_Enumerate(), MapInfo_FilterGametype(), MapInfo_ForbiddenFlags(), MapInfo_ListAllowedMaps(), MapInfo_RequiredFlags(), MapInfo_SwitchGameType(), MapInfo_Type_ToString(), match_gametype, strcat(), strunzone(), and strzone().

Referenced by GameCommand_gametype(), GameTypeVote_Finished(), MapVote_Init(), and MapVote_Think().

◆ GameTypeVote_Start()

bool GameTypeVote_Start ( )

Definition at line 687 of file sv_mapvoting.qc.

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}
float time
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_detail
(shared) how much information about the votes/results is revealed
Definition mapvoting.qh:20
float mv_reduce_time
Definition mapvoting.qh:22
int mv_count_real
(shared) number of maps/gametypes, excluding abstain
Definition mapvoting.qh:15
float mv_timeout
Definition mapvoting.qh:23
int current_gametype_index
void MapVote_ClearAllVotes()
bool MapVote_Finished(int mappos)
void MapVote_UnzoneStrings()
bool GameTypeVote_AddVotable(string nextMode)
float autocvar_sv_vote_gametype_reduce_time
float autocvar_sv_vote_gametype_timeout
bool autocvar_sv_vote_gametype_default_current
int autocvar_sv_vote_gametype_reduce_count
int autocvar_sv_vote_gametype_detail
string loaded_gametype_custom_string
Definition world.qh:53

References argv(), autocvar_sv_vote_gametype_default_current, autocvar_sv_vote_gametype_detail, autocvar_sv_vote_gametype_options, autocvar_sv_vote_gametype_reduce_count, autocvar_sv_vote_gametype_reduce_time, autocvar_sv_vote_gametype_timeout, current_gametype_index, gametype_custom_enabled, gametypevote, GameTypeVote_AddVotable(), GTV_AVAILABLE, loaded_gametype_custom_string, MapInfo_CurrentGametype(), MapInfo_Type_ToString(), MapVote_ClearAllVotes(), MAPVOTE_COUNT, MapVote_Finished(), MapVote_Spawn(), MapVote_UnzoneStrings(), min(), mv_abstain, mv_count, mv_count_real, mv_detail, mv_entries, mv_flags, mv_reduce_count, mv_reduce_time, mv_timeout, strunzone(), strzone(), time, and tokenizebyseparator.

Referenced by MapVote_Think().

◆ GameTypeVote_Type_FromString()

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_gametype_(type_name)_type.

Definition at line 18 of file sv_mapvoting.qc.

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}

References cvar_string(), MapInfo_Type_FromString(), NULL, and strcat().

Referenced by GameTypeVote_AddVotable(), GameTypeVote_Finished(), and GameTypeVote_GetMask().

◆ MapVote_AddVotable()

bool MapVote_AddVotable ( int from_i)

Definition at line 129 of file sv_mapvoting.qc.

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}
#define strstrofs
string GetNextMap(void)
float MapInfo_CheckMap(string s)
Definition mapinfo.qc:1502
int mv_ssdirs_count
Definition mapvoting.qh:10
string mv_ssdirs[MAPVOTE_SSDIRS_COUNT]
Definition mapvoting.qh:9
string mv_suggester[MAPVOTE_COUNT]
(maps) .netname of the player who suggested the map
Definition mapvoting.qh:17
string substring(string s, float start, float length)
float random(void)
string string_null
Definition nil.qh:9
float mv_rng[MAPVOTE_COUNT]
(shared) random() value for each map/gametype to determine tiebreakers
string mv_pakfile[MAPVOTE_COUNT]
(maps) pk3 file location
string mv_suggestions[MAPVOTE_COUNT]
(maps) name of the suggested map, later copied into mv_entries

References GetNextMap(), GTV_AVAILABLE, MapInfo_CheckMap(), mv_count, mv_entries, mv_flags, mv_pakfile, mv_rng, mv_ssdir_i, mv_ssdirs, mv_ssdirs_count, mv_suggester, mv_suggestions, random(), strcat(), string_null, strstrofs, strzone(), and substring().

Referenced by MapVote_AddVotableMaps(), and MapVote_Init().

◆ MapVote_AddVotableMaps()

void MapVote_AddVotableMaps ( int nmax,
int smax )

Before mapvoting begins, players can trigger MapVote_Suggest (suggestmap), which sets mv_suggestions and mv_suggester from index 0 onwards. When mapvoting begins, we store the other info (pakfile, flags, ssdir, rng) with MapVote_AddVotable, for the suggested maps first to filter out the invalid ones, then run MapVote_AddVotable with GetNextMap to fill in the rest of the maps.

Definition at line 188 of file sv_mapvoting.qc.

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}
void Maplist_Close()
int Maplist_Init(void)
float floor(float f)
bool MapVote_AddVotable(int from_i)
int mv_suggestion_ptr
(maps) index of where the next suggestion should be (starts as 0)

References floor(), Maplist_Close(), Maplist_Init(), MapVote_AddVotable(), min(), mv_count, mv_ranked, mv_suggester, mv_suggestion_ptr, mv_suggestions, and random().

Referenced by MapVote_Init().

◆ MapVote_CheckRules_count()

void MapVote_CheckRules_count ( )

Definition at line 374 of file sv_mapvoting.qc.

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}
ERASEABLE void heapsort(int n, swapfunc_t swap, comparefunc_t cmp, entity pass)
Definition sort.qh:9
void MapVote_ranked_swap(int i, int j, entity pass)
int MapVote_ranked_cmp(int i, int j, entity pass)
int mv_voters
(shared) number of human voters present
#define IS_REAL_CLIENT(v)
Definition utils.qh:17
#define FOREACH_CLIENT(cond, body)
Definition utils.qh:52

References FOREACH_CLIENT, GTV_AVAILABLE, heapsort(), IS_REAL_CLIENT, MapVote_ranked_cmp(), MapVote_ranked_swap(), mv_count, mv_count_real, mv_flags, mv_ranked, mv_voters, mv_votes, and NULL.

Referenced by MapVote_Tick().

◆ MapVote_CheckRules_decide()

bool MapVote_CheckRules_decide ( )

Definition at line 401 of file sv_mapvoting.qc.

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}
void GameLogEcho(string s)
Definition gamelog.qc:15
bool autocvar_sv_eventlog
Definition gamelog.qh:3
#define itos(i)
Definition int.qh:6
void MapVote_TouchMask()
Definition net.qc:13
#define remove
Definition pre.qh:9
entity result
Definition promise.qc:45
#define REDUCE_REMOVE_THIS(idx)

References autocvar_sv_eventlog, GameLogEcho(), GTV_AVAILABLE, itos, MapVote_Finished(), MapVote_TouchMask(), mv_abstain, mv_count, mv_count_real, mv_entries, mv_flags, mv_ranked, mv_reduce_count, mv_reduce_time, mv_timeout, mv_voters, mv_votes, REDUCE_REMOVE_THIS, remove, result, strcat(), and time.

Referenced by MapVote_Tick().

◆ MapVote_ClearAllVotes()

void MapVote_ClearAllVotes ( )

Definition at line 76 of file sv_mapvoting.qc.

77{
78 FOREACH_CLIENT(true, it.mapvote = 0);
79}

References FOREACH_CLIENT.

Referenced by GameTypeVote_Start(), and MapVote_Init().

◆ MapVote_Finished()

bool MapVote_Finished ( int mappos)

Definition at line 288 of file sv_mapvoting.qc.

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}
float mv_winner_time
void Map_Goto_SetStr(string nextmapname)
void Map_Goto(float reinit)
bool alreadychangedlevel
void MapVote_Winner(int mappos)
Definition net.qc:17
int mv_winner
Definition mapvoting.qh:24
void FixClientCvars(entity e)
Definition client.qc:999
#define strfree(this)
Definition string.qh:57
bool GameTypeVote_Finished(int pos)
void MapVote_Init()

References alreadychangedlevel, autocvar_sv_eventlog, FixClientCvars(), FOREACH_CLIENT, GameLogEcho(), gametypevote, GameTypeVote_Finished(), get_nextmap, GTV_AVAILABLE, IS_REAL_CLIENT, itos, Map_Goto(), Map_Goto_SetStr(), MapVote_Init(), MapVote_Winner(), mv_count, mv_entries, mv_flags, mv_suggester, mv_voters, mv_votes, mv_winner, mv_winner_time, result, strcat(), strfree, time, and voted_gametype_string.

Referenced by GameTypeVote_Start(), and MapVote_CheckRules_decide().

◆ MapVote_Init()

void MapVote_Init ( )

Definition at line 234 of file sv_mapvoting.qc.

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}
#define tokenize_console
const int MAPVOTE_SSDIRS_COUNT
Definition mapvoting.qh:8
void MapVote_AddVotableMaps(int nmax, int smax)
#define autocvar_g_maplist_votable
int autocvar_g_maplist_votable_detail
string autocvar_g_maplist_votable_screenshot_dir
bool autocvar_g_maplist_votable_show_suggester
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
int autocvar_g_maplist_votable_reduce_count
bool autocvar_g_maplist_votable_abstain
float autocvar_g_maplist_votable_reduce_time

References argv(), autocvar_g_maplist_votable, autocvar_g_maplist_votable_abstain, autocvar_g_maplist_votable_detail, autocvar_g_maplist_votable_reduce_count, autocvar_g_maplist_votable_reduce_time, autocvar_g_maplist_votable_screenshot_dir, autocvar_g_maplist_votable_show_suggester, autocvar_g_maplist_votable_suggestions, autocvar_g_maplist_votable_timeout, current_gametype_index, gametype_custom_enabled, GameTypeVote_SetGametype(), loaded_gametype_custom_string, MapVote_AddVotable(), MapVote_AddVotableMaps(), MapVote_ClearAllVotes(), MAPVOTE_COUNT, MapVote_Spawn(), MAPVOTE_SSDIRS_COUNT, MapVote_UnzoneStrings(), match_gametype, min(), mv_abstain, mv_count, mv_count_real, mv_detail, mv_reduce_count, mv_reduce_time, mv_show_suggester, mv_ssdirs, mv_ssdirs_count, mv_suggestion_ptr, mv_timeout, strzone(), time, and tokenize_console.

Referenced by MapVote_Finished(), and MapVote_Think().

◆ MapVote_ranked_cmp()

int MapVote_ranked_cmp ( int i,
int j,
entity pass )

Definition at line 349 of file sv_mapvoting.qc.

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}
#define TC(T, sym)
Definition _all.inc:82

References current_gametype_index, entity(), GTV_AVAILABLE, mv_flags, mv_ranked, mv_rng, mv_votes, pass, and TC.

Referenced by MapVote_CheckRules_count().

◆ MapVote_ranked_swap()

void MapVote_ranked_swap ( int i,
int j,
entity pass )

Definition at line 342 of file sv_mapvoting.qc.

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}

References entity(), mv_ranked, pass, and TC.

Referenced by MapVote_CheckRules_count().

◆ MapVote_Start()

void MapVote_Start ( )

Definition at line 506 of file sv_mapvoting.qc.

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}
bool PlayerStats_GameReport_DelayMapVote
bool mapvote_run

References MapInfo_CurrentFeatures(), MapInfo_CurrentGametype(), MapInfo_Enumerate(), MapInfo_FilterGametype(), MapInfo_ForbiddenFlags(), MapInfo_RequiredFlags(), mapvote_run, and PlayerStats_GameReport_DelayMapVote.

Referenced by CheckRules_World(), and IntermissionThink().

◆ MapVote_Suggest()

string MapVote_Suggest ( entity this,
string m )

Definition at line 91 of file sv_mapvoting.qc.

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}
string netname
Definition powerups.qc:20
bool Map_IsRecent(string m)
int playerid
Definition client.qh:82
string GameTypeVote_MapInfo_FixName(string m)
bool mapvote_initialized
bool autocvar_g_maplist_votable_suggestions_override_mostrecent

References autocvar_g_maplist_votable_suggestions, autocvar_g_maplist_votable_suggestions_override_mostrecent, autocvar_sv_eventlog, autocvar_sv_vote_gametype, entity(), floor(), GameLogEcho(), gametypevote, GameTypeVote_MapInfo_FixName(), itos, Map_IsRecent(), MapInfo_CheckMap(), MAPVOTE_COUNT, mapvote_initialized, mv_suggester, mv_suggestion_ptr, mv_suggestions, netname, playerid, random(), strcat(), strunzone(), and strzone().

Referenced by ClientCommand_suggestmap().

◆ MapVote_Think()

void MapVote_Think ( )

Definition at line 521 of file sv_mapvoting.qc.

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}
int player_count
Definition api.qh:103
float DoNextMapOverride(float reinit)
void GotoNextMap(float reinit)
void MapVote_Tick()
bool GameTypeVote_Start()
int autocvar_rescan_pending

References alreadychangedlevel, autocvar_g_maplist_votable, autocvar_rescan_pending, autocvar_sv_vote_gametype, cvar_set(), DoNextMapOverride(), GameTypeVote_SetGametype(), GameTypeVote_Start(), get_nextmap, GotoNextMap(), localcmd(), Map_Goto(), Map_Goto_SetStr(), MapInfo_CurrentFeatures(), MapInfo_CurrentGametype(), MapInfo_FilterGametype(), MapInfo_ForbiddenFlags(), MapInfo_RequiredFlags(), MapVote_Init(), mapvote_initialized, mapvote_run, MapVote_Tick(), match_gametype, mv_entries, mv_winner, mv_winner_time, NULL, player_count, strfree, time, voted_gametype, and voted_gametype_string.

Referenced by CheckRules_World().

◆ MapVote_Tick()

void MapVote_Tick ( )

Definition at line 474 of file sv_mapvoting.qc.

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}
float GetResource(entity e, Resource res_type)
Returns the current amount of resource the given entity has.
WriteString(chan, ent.netname)
WriteByte(chan, ent.angles.y/DEC_FACTOR)
SetResourceExplicit(ent, RES_ARMOR, ReadByte() *DEC_FACTOR)) ENTCS_PROP(NAME
void MapVote_ReadPlayerVote(entity voter)
Definition net.qc:27
float MSG_ONE
Definition menudefs.qc:56
entity msg_entity
Definition progsdefs.qc:63
float SVC_FINALE
Definition progsdefs.qc:341
ClientState CS(Client this)
Definition state.qh:47
bool MapVote_CheckRules_decide()
void MapVote_CheckRules_count()

References CS(), FOREACH_CLIENT, GetResource(), IS_REAL_CLIENT, MapVote_CheckRules_count(), MapVote_CheckRules_decide(), MapVote_ReadPlayerVote(), msg_entity, MSG_ONE, SetResourceExplicit(), SVC_FINALE, WriteByte(), and WriteString().

Referenced by MapVote_Think().

◆ MapVote_UnzoneStrings()

void MapVote_UnzoneStrings ( )

Definition at line 81 of file sv_mapvoting.qc.

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}

References mv_count, mv_entries, mv_pakfile, and strfree.

Referenced by GameTypeVote_Start(), and MapVote_Init().

Variable Documentation

◆ current_gametype_index

int current_gametype_index

Definition at line 233 of file sv_mapvoting.qc.

Referenced by GameTypeVote_Start(), MapVote_Init(), and MapVote_ranked_cmp().

◆ gametypevote_finished

bool gametypevote_finished

Definition at line 648 of file sv_mapvoting.qc.

Referenced by GameTypeVote_Finished().