]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Finish re-write of VoteCount() and ReadyCount() -- now with several new
authorSamual <samual@xonotic.org>
Sun, 11 Dec 2011 07:34:00 +0000 (02:34 -0500)
committerSamual <samual@xonotic.org>
Sun, 11 Dec 2011 07:34:00 +0000 (02:34 -0500)
features, like g_warmup_majority_factor

commands.cfg
defaultXonotic.cfg
qcsrc/server/autocvars.qh
qcsrc/server/vote.qc
qcsrc/server/vote.qh

index 2d12a80f7e94480812448dbce5ef584c781549e2..019e90efa483b2dc4d768b336e577cc4e09aecbe 100644 (file)
@@ -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
 
index 00fdf00bfbe3504ab088275d98cf9b4b34c71488..1dc796e567b9b7bcda556b847214a278c52329d8 100644 (file)
@@ -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)"
index 97ffc89df992c85afdb71e11fbc1beb5a1a5c755..93244177d44a14852d1a73859ebebee36cf97bdd 100644 (file)
@@ -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;
index abf119664d6c6252789ee33ffd194542dba6d63c..2ed9f4f9e1aa1b7ad42694beb2d161425aee0686 100644 (file)
@@ -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;
 }
index 580070754f3982f8ecb546f0675853145d10fa6b..fb34ba2f93a491c20e6262ba2bbc256a4ee788ea 100644 (file)
@@ -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);