//---------------------------------------------------------------------------------------------------- // Leader3 vote: !voteleader / !vl . Passes at sm_leader_vote_ratio of eligible voters. // Eligible = in-game, not a bot, not AFK (AFKManager, when loaded). //---------------------------------------------------------------------------------------------------- int g_iVoteCount[MAXPLAYERS + 1]; // votes received, per candidate int g_iVotedForSerial[MAXPLAYERS + 1]; // per voter: client serial of their candidate public Action Cmd_VoteLeader(int client, int args) { if (client == 0) { ReplyToCommand(client, "%s Cannot use this from the console.", PREFIX_PLAIN); return Plugin_Handled; } if (!g_cvAllowVotes.BoolValue) { ReplyToCommand(client, "%s Voting for leader is disabled.", PREFIX_PLAIN); return Plugin_Handled; } if (args < 1) { ReplyToCommand(client, "%s Usage: sm_voteleader ", PREFIX_PLAIN); return Plugin_Handled; } char arg[65]; GetCmdArg(1, arg, sizeof(arg)); int target = FindTarget(client, arg, true, false); if (target == -1) return Plugin_Handled; if (g_bIsLeader[target]) { ReplyToCommand(client, "%s %N is already a leader!", PREFIX_PLAIN, target); return Plugin_Handled; } if (g_alLeaders.Length >= g_cvMaxLeaders.IntValue) { ReplyToCommand(client, "%s The maximum of %d leaders is already reached.", PREFIX_PLAIN, g_cvMaxLeaders.IntValue); return Plugin_Handled; } int previous = GetClientFromSerial(g_iVotedForSerial[client]); if (previous == target) { ReplyToCommand(client, "%s You have already voted for this player!", PREFIX_PLAIN); return Plugin_Handled; } if (previous != 0) g_iVoteCount[previous]--; g_iVoteCount[target]++; g_iVotedForSerial[client] = GetClientSerial(target); PrintToChatAll("%s\x04%N\x01 voted for \x04%N\x01 to become a leader (\x04%d/%d\x01 votes).", PREFIX, client, target, g_iVoteCount[target], Vote_Needed()); Vote_Check(target); return Plugin_Handled; } int Vote_EligibleCount() { int afkTime = g_cvVoteAfkTime.IntValue; int count = 0; for (int i = 1; i <= MaxClients; i++) { if (!IsClientInGame(i) || IsFakeClient(i)) continue; if (g_bAFKManager && afkTime > 0 && GetClientIdleTime(i) >= afkTime) continue; count++; } return count; } int Vote_Needed() { int needed = RoundToCeil(float(Vote_EligibleCount()) * g_cvVoteRatio.FloatValue); return needed < 2 ? 2 : needed; } void Vote_Check(int candidate) { if (!IsValidClient(candidate) || g_iVoteCount[candidate] <= 0) return; if (g_iVoteCount[candidate] < Vote_Needed()) return; Vote_ClearCandidate(candidate); PrintToChatAll("%s\x04%N\x01 has been voted to become a leader!", PREFIX, candidate); if (AddLeader(candidate)) ShowLeaderMenu(candidate); } void Vote_ClearCandidate(int candidate) { g_iVoteCount[candidate] = 0; int serial = GetClientSerial(candidate); for (int i = 1; i <= MaxClients; i++) { if (g_iVotedForSerial[i] == serial) g_iVotedForSerial[i] = 0; } } // A shrinking voter pool can push a pending candidate over the threshold. void Vote_RecheckAll() { for (int i = 1; i <= MaxClients; i++) { if (g_iVoteCount[i] > 0) Vote_Check(i); } } void Vote_OnClientDisconnect(int client) { int previous = GetClientFromSerial(g_iVotedForSerial[client]); if (previous != 0) g_iVoteCount[previous]--; g_iVotedForSerial[client] = 0; if (g_iVoteCount[client] > 0) Vote_ClearCandidate(client); Vote_RecheckAll(); }