137 lines
3.4 KiB
SourcePawn
137 lines
3.4 KiB
SourcePawn
//----------------------------------------------------------------------------------------------------
|
|
// Leader3 vote: !voteleader / !vl <name>. 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 <player>", 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();
|
|
}
|