From: Samual Date: Sun, 11 Dec 2011 07:34:00 +0000 (-0500) Subject: Finish re-write of VoteCount() and ReadyCount() -- now with several new X-Git-Tag: xonotic-v0.6.0~188^2~28^2~168 X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=cf54cc6fde4e2f28f19bbc35f36279ec46cac3de;p=xonotic%2Fxonotic-data.pk3dir.git Finish re-write of VoteCount() and ReadyCount() -- now with several new features, like g_warmup_majority_factor --- diff --git a/commands.cfg b/commands.cfg index 2d12a80f7..019e90efa 100644 --- a/commands.cfg +++ b/commands.cfg @@ -177,12 +177,13 @@ set sv_vote_master_commands "movetoteam_red movetoteam_blue movetoteam_yellow mo set sv_vote_master 1 "Allows the use of the vote master system" set sv_vote_master_callable 1 "When set, users can use \"vmaster\" to call a vote to become master of voting commands" set sv_vote_master_password "" "when set, users can use \"vlogin PASSWORD\" to log in as master" +set sv_vote_master_playerlimit 2 "Minimum number of players needed for a player to be allowed to vote for master" set sv_vote_singlecount 0 "set to 1 to count votes once after timeout or to 0 to count with every vote" set sv_vote_timeout 30 "a vote will timeout after this many seconds" set sv_vote_wait 120 "a player can not call a vote again for this many seconds when his vote was not accepted" set sv_vote_stop 15 "a player can not call a vote again for this many seconds when he stopped this vote (e.g. to correct it)" -set sv_vote_majority_factor 0.5 "which quotient of the PLAYERS constitute a majority? (try: 0.666, 0.75 when using the above)" -set sv_vote_simple_majority_factor 0.666 "which quotient of the VOTERS constitute a majority too? (0 = off, otherwise it must be higher than or equal to sv_vote_majority_factor)" +set sv_vote_majority_factor 0.5 "What percentage of the PLAYERS constitute a majority? (Must be at least 0.5, recommended: 0.5)" +set sv_vote_majority_factor_of_voted 0.5 "What percentage of the VOTERS constitute a majority too? (Must be at least 0.5, recommended: 0.5)" // when disabled, don't allow game type changes "note: set these two equal to JUST support simple majorities" set sv_vote_override_mostrecent 0 diff --git a/defaultXonotic.cfg b/defaultXonotic.cfg index 00fdf00bf..1dc796e56 100644 --- a/defaultXonotic.cfg +++ b/defaultXonotic.cfg @@ -297,11 +297,12 @@ set teamplay_lockonrestart 0 "it set to 1 in a team-based game, the teams are lo set g_maxplayers 0 "maximum number of players allowed to play at the same time, set to 0 to allow all players to join the game" set g_maxplayers_spectator_blocktime 5 "if the players voted for the \"nospectators\" command, this setting defines the number of seconds a observer/spectator has time to join the game before he gets kicked" -//tournament mod +// tournament mod set g_warmup 0 "split the game into a warmup- and match-stage when set to 1" set g_warmup_limit 60 "if set to -1 the warmup-stage is not affected by any timelimit, if set to 0 the usual timelimit also affects warmup-stage, otherwise warmup will be limited to this time in SECONDS (useful for public matches)" set g_warmup_allow_timeout 0 "if set to 1 timeouts can also be called in the warmup-stage, when sv_timeout is set to 1" set g_warmup_allguns 0 "if set players start with all guns in warmup mode" +set g_warmup_majority_factor 0.8 "minimum percentage of players ready needed for warmup to end" set g_chat_nospectators 0 "if 0 spec/observer chat is always visible to the player, if 1 it is never visible to players, if 2 it is only visible to players during warmup stage" set sv_vote_nospectators 0 "if set only players can call a vote (thus spectators and observers can't call a vote)" diff --git a/qcsrc/server/autocvars.qh b/qcsrc/server/autocvars.qh index 97ffc89df..93244177d 100644 --- a/qcsrc/server/autocvars.qh +++ b/qcsrc/server/autocvars.qh @@ -1163,14 +1163,15 @@ float autocvar_sv_vote_call; float autocvar_sv_vote_change; string autocvar_sv_vote_commands; float autocvar_sv_vote_majority_factor; +float autocvar_sv_vote_majority_factor_of_voted; float autocvar_sv_vote_master; float autocvar_sv_vote_master_callable; string autocvar_sv_vote_master_commands; string autocvar_sv_vote_master_password; +float autocvar_sv_vote_master_playerlimit; float autocvar_sv_vote_nospectators; string autocvar_sv_vote_only_commands; float autocvar_sv_vote_override_mostrecent; -float autocvar_sv_vote_simple_majority_factor; float autocvar_sv_vote_singlecount; float autocvar_sv_vote_stop; float autocvar_sv_vote_timeout; diff --git a/qcsrc/server/vote.qc b/qcsrc/server/vote.qc index abf119664..2ed9f4f9e 100644 --- a/qcsrc/server/vote.qc +++ b/qcsrc/server/vote.qc @@ -70,7 +70,7 @@ float Nagger_SendEntity(entity to, float sendflags) { WriteByte(MSG_ENTITY, vote_accept_count); WriteByte(MSG_ENTITY, vote_reject_count); - WriteByte(MSG_ENTITY, vote_needed_absolute); + WriteByte(MSG_ENTITY, vote_needed_overall); WriteChar(MSG_ENTITY, to.vote_selection); } @@ -228,14 +228,24 @@ void VoteSpam(float notvoters, float mincount, string result) void VoteCount() { - float vote_player_count, is_player; + // declarations + vote_accept_count = vote_reject_count = vote_abstain_count = 0; + + float spectators_allowed = ((autocvar_sv_vote_nospectators != 2) + || ((autocvar_sv_vote_nospectators == 1) && inWarmupStage) + || (autocvar_sv_vote_nospectators == 0)); + + float vote_player_count, is_player, notvoters; float vote_real_player_count, vote_real_accept_count; float vote_real_reject_count, vote_real_abstain_count; - vote_accept_count = vote_reject_count = vote_abstain_count = 0; + float vote_needed_of_voted, final_needed_votes; + float vote_factor_overall, vote_factor_of_voted; + entity tmp_player; Nagger_VoteCountChanged(); - + + // add up all the votes from each connected client FOR_EACH_REALCLIENT(tmp_player) { is_player = (tmp_player.classname == "player"); @@ -245,109 +255,86 @@ void VoteCount() switch(tmp_player.vote_selection) { - case VOTE_SELECT_REJECT: - { - ++vote_reject_count; - if(is_player) { ++vote_real_reject_count; } - break; - } - - case VOTE_SELECT_ACCEPT: - { - ++vote_accept_count; - if(is_player) { ++vote_real_accept_count; } - break; - } - - case VOTE_SELECT_ABSTAIN: - { - ++vote_abstain_count; - if(is_player) { ++vote_real_abstain_count; } - break; - } - + case VOTE_SELECT_REJECT: { ++vote_reject_count; { if(is_player) ++vote_real_reject_count; } break; } + case VOTE_SELECT_ACCEPT: { ++vote_accept_count; { if(is_player) ++vote_real_reject_count; } break; } + case VOTE_SELECT_ABSTAIN: { ++vote_abstain_count; { if(is_player) ++vote_real_abstain_count; } break; } default: break; } } - /* TODO - // in tournament mode, if we have at least one player then don't make the vote dependent on spectators (so specs don't have to press F1) - if(autocvar_sv_vote_nospectators) - if(realplayercount > 0) + // Check to see if there are enough players on the server to allow master voting... otherwise, vote master could be used for evil. + if(votecalledmaster && autocvar_sv_vote_master_playerlimit > vote_player_count) { - vote_accept_count = realplayeryescount; - vote_reject_count = realplayernocount; - vote_abstain_count = realplayerabstaincount; - playercount = realplayercount; + if(votecaller) { votecaller.vote_next = 0; } + print_to(votecaller, "^1There are not enough players on this server to allow you to become vote master."); + VoteReset(); + return; } - - float votefactor, simplevotefactor; - votefactor = bound(0.5, autocvar_sv_vote_majority_factor, 0.999); - simplevotefactor = autocvar_sv_vote_simple_majority_factor; - - // FIXME this number is a guess - vote_needed_absolute = floor((playercount - vote_abstain_count) * votefactor) + 1; - if(simplevotefactor) + + // 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. + if(!spectators_allowed && (vote_real_player_count > 0)) { - simplevotefactor = bound(votefactor, simplevotefactor, 0.999); - vote_needed_simple = floor((vote_accept_count + vote_reject_count) * simplevotefactor) + 1; + vote_accept_count = vote_real_accept_count; + vote_reject_count = vote_real_reject_count; + vote_abstain_count = vote_real_abstain_count; + vote_player_count = vote_real_player_count; } - else - vote_needed_simple = 0; + + // people who have no opinion in any way :D + notvoters = (vote_player_count - vote_accept_count - vote_reject_count - vote_abstain_count); - if(votecalledmaster && playercount == 1) + // determine the goal for the vote to be passed or rejected normally + vote_factor_overall = bound(0.5, autocvar_sv_vote_majority_factor, 0.999); + vote_needed_overall = floor((vote_player_count - vote_abstain_count) * vote_factor_overall) + 1; + + // if the vote times out, determine the amount of votes needed of the people who actually already voted + vote_factor_of_voted = bound(0.5, autocvar_sv_vote_majority_factor_of_voted, 0.999); + vote_needed_of_voted = floor((vote_accept_count + vote_reject_count) * vote_factor_of_voted) + 1; + + + // finally calculate the result of the vote + if(vote_accept_count >= vote_needed_overall) { - // if only one player is on the server becoming vote - // master is not allowed. This could be used for - // trolling or worse. 'self' is the user who has - // called the vote because this function is called - // by SV_ParseClientCommand. Maybe all voting should - // be disabled for a single player? - print_to(votecaller, "^1You are the only player on this server so you can not become vote master."); - if(votecaller) { - votecaller.vote_next = 0; - } - VoteReset(); - } - else + VoteSpam(notvoters, -1, "yes"); // there is enough acceptions to pass the vote + VoteAccept(); + return; + } + + if(vote_reject_count > vote_player_count - vote_abstain_count - vote_needed_overall) { - if(vote_accept_count >= vote_needed_absolute) - { - VoteSpam(playercount - vote_accept_count - vote_reject_count - vote_abstain_count, -1, "yes"); - VoteAccept(); - } - else if(vote_reject_count > playercount - vote_abstain_count - vote_needed_absolute) // that means, vote_accept_count cannot reach vote_needed_absolute any more - { - VoteSpam(playercount - vote_accept_count - vote_reject_count - vote_abstain_count, -1, "no"); - VoteReject(); - } - else if(time > votefinished) + VoteSpam(notvoters, -1, "no"); // there is enough rejections to deny the vote + VoteReject(); + return; + } + + // there is not enough votes in either direction, now lets just calculate what the voters have said + if(time > votefinished) + { + final_needed_votes = vote_needed_overall; + + if(autocvar_sv_vote_majority_factor_of_voted) { - if(simplevotefactor) + if(vote_accept_count >= vote_needed_of_voted) { - string result; - if(vote_accept_count >= vote_needed_simple) - result = "yes"; - else if(vote_accept_count + vote_reject_count > 0) - result = "no"; - else - result = "timeout"; - VoteSpam(playercount - vote_accept_count - vote_reject_count - vote_abstain_count, min(vote_needed_absolute, vote_needed_simple), result); - if(result == "yes") - VoteAccept(); - else if(result == "no") - VoteReject(); - else - VoteTimeout(); + VoteSpam(notvoters, min(vote_needed_overall, vote_needed_of_voted), "yes"); + VoteAccept(); + return; } - else + + if(vote_accept_count + vote_reject_count > 0) { - VoteSpam(playercount - vote_accept_count - vote_reject_count - vote_abstain_count, vote_needed_absolute, "timeout"); - VoteTimeout(); + VoteSpam(notvoters, min(vote_needed_overall, vote_needed_of_voted), "no"); + VoteReject(); + return; } + + final_needed_votes = min(vote_needed_overall, vote_needed_of_voted); } + + // it didn't pass or fail, so not enough votes to even make a decision. + VoteSpam(notvoters, final_needed_votes, "timeout"); + VoteTimeout(); } - */ } @@ -439,6 +426,7 @@ void ReadyRestart() void ReadyCount() { entity tmp_player; + float ready_needed_factor, ready_needed_count; float t_ready, t_players; FOR_EACH_REALPLAYER(tmp_player) @@ -451,10 +439,13 @@ void ReadyCount() Nagger_ReadyCounted(); - // TODO: check percentage of ready players - if(t_ready) // at least one is ready - if(t_ready == t_players) // and, everyone is ready + ready_needed_factor = bound(0.5, cvar("g_warmup_majority_factor"), 0.999); + ready_needed_count = floor(t_players * ready_needed_factor) + 1; + + if(readycount >= ready_needed_count) + { ReadyRestart(); + } return; } diff --git a/qcsrc/server/vote.qh b/qcsrc/server/vote.qh index 580070754..fb34ba2f9 100644 --- a/qcsrc/server/vote.qh +++ b/qcsrc/server/vote.qh @@ -10,8 +10,7 @@ float votefinished; float vote_accept_count; float vote_reject_count; float vote_abstain_count; -float vote_needed_absolute; -float vote_needed_simple; +float vote_needed_overall; string VoteCommand_getname(entity caller); void VoteCommand(float request, entity caller, float argc, string vote_command);