Files
wnsrc/lua/sam/modules/vote.lua

486 lines
12 KiB
Lua
Raw Normal View History

2024-08-04 22:55:00 +03:00
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
if SAM_LOADED then return end
-- DONT EVER TALK TO ME ABOUT THIS CODE
local sam, command = sam, sam.command
command.set_category("Voting")
local start_vote, end_vote
if SERVER then
local vote_on = false
local options, players_voted
local shuffle = function(tbl) -- https://gist.github.com/Uradamus/10323382
for i = #tbl, 2, -1 do
local j = math.random(i)
tbl[i], tbl[j] = tbl[j], tbl[i]
end
return tbl
end
end_vote = function(ply, callback)
if not vote_on then
return ply:sam_add_text(color_white, "There is no vote to end.")
end
vote_on = false
sam.set_global("Vote", nil)
if callback then
local tbl = {}
local total_count = 0
for i = 1, #options do
local count = sam.get_global("Votings" .. i)
total_count = total_count + count
table.insert(tbl, {i, count})
sam.set_global("Votings" .. i, nil)
end
if total_count == 0 then
return sam.player.add_text(nil, color_white, "The vote have been canceled because nobody voted.")
end
table.sort(shuffle(tbl), function(a,b) return a[2] > b[2] end)
local v = tbl[1]
local winner, count = v[1], v[2]
callback(winner, options[winner], count, total_count)
else
for i = 1, #options do
sam.set_global("Votings" .. i, nil)
end
end
options, players_voted = nil, nil
timer.Remove("SAM.Vote")
end
start_vote = function(ply, callback, title, ...)
if vote_on then
return ply:sam_add_text(color_white, "There is an active vote, wait for it to finish.")
end
vote_on = true
options, players_voted = {}, {}
local args, n = {...}, select("#", ...)
for i = 1, n do
local v = args[i]
if v then
table.insert(options, v)
end
end
sam.set_global("Vote", {title, options, CurTime()})
for k in ipairs(options) do
sam.set_global("Votings" .. k, 0)
end
timer.Create("SAM.Vote", 25, 1, function()
end_vote(ply, callback)
end)
return true
end
sam.netstream.Hook("Vote", function(ply, index)
if not sam.isnumber(index) or index > 5 then return end
local votings = sam.get_global("Votings" .. index)
if not votings then return end
local old_index = players_voted[ply:AccountID()]
if old_index == index then return end
if old_index then
sam.set_global("Votings" .. old_index, sam.get_global("Votings" .. old_index) - 1)
end
sam.set_global("Votings" .. index, votings + 1)
players_voted[ply:AccountID()] = index
end)
end
if CLIENT then
local SUI = sam.SUI
-- https://github.com/Facepunch/garrysmod/blob/master/garrysmod/lua/includes/extensions/client/player.lua
local VOTING_TITLE = SUI.CreateFont("VotingTitle", "Roboto Bold", 15)
local VOTING_OPTION = SUI.CreateFont("VotingTitle", "Roboto Medium", 14)
local bind_translation = {}
for i = 0, 9 do
bind_translation["slot" .. i] = i
end
local voting_frame
end_vote = function()
if IsValid(voting_frame) then
voting_frame:Remove()
end
hook.Remove("PlayerBindPress", "SAM.Voting")
hook.Remove("SAM.ChangedGlobalVar", "SAM.VotingCount")
end
hook.Add("SAM.ChangedGlobalVar", "Voting", function(key, value)
if key ~= "Vote" then return end
if not value then
end_vote()
return
end
local title, options, start_time = value[1], value[2], value[3]
sui.TDLib.Start()
voting_frame = vgui.Create("EditablePanel")
voting_frame:SetSize(SUI.Scale(165), SUI.Scale(230))
voting_frame:SetPos(5, ScrH() * 0.25)
voting_frame:DockPadding(4, 4, 4, 4)
voting_frame:Blur()
:Background(Color(30, 30, 30, 240))
local voting_title = voting_frame:Add("SAM.Label")
voting_title:Dock(TOP)
voting_title:SetFont(VOTING_TITLE)
voting_title:TextColor(Color(220, 220, 220))
voting_title:SetText(title)
voting_title:SetWrap(true)
voting_title:SetAutoStretchVertical(true)
local line = voting_frame:Add("SAM.Label")
line:Dock(TOP)
line:TextColor(Color(220, 220, 220))
line:SetText("-")
local options_added = {}
for i, v in ipairs(options) do
local option = voting_frame:Add("SAM.Label")
option:Dock(TOP)
option:SetFont(VOTING_OPTION)
option:TextColor(Color(220, 220, 220), true)
option:SetText(i .. ". " .. v .. " (0)")
option:SetWrap(true)
option:SetAutoStretchVertical(true)
options_added[i] = option
end
function voting_frame:Think() -- fucking gmod
self:SizeToChildren(false, true)
local time_left = math.floor(25 - (CurTime() - start_time))
if time_left <= 0 then
end_vote()
voting_frame.Think = nil
return
end
voting_title:SetText(title .. " (" .. time_left .. ")")
end
line = voting_frame:Add("SAM.Label")
line:Dock(TOP)
line:TextColor(Color(220, 220, 220))
line:SetText("-")
local option = voting_frame:Add("SAM.Label")
option:Dock(TOP)
option:SetFont(VOTING_OPTION)
option:TextColor(Color(220, 220, 220), true)
option:SetText("0. Close")
option:SetWrap(true)
option:SetAutoStretchVertical(true)
sui.TDLib.End()
local current_index
hook.Add("PlayerBindPress", "SAM.Voting", function(_, bind, down)
if not down then return end
local index = bind_translation[bind]
if not index then return end
if index == 0 then
end_vote()
return true
end
if not options[index] then return true end
if current_index then
options_added[current_index]:TextColor(Color(220, 220, 220), true)
end
options_added[index]:TextColor(Color(65, 185, 255), true)
current_index = index
sam.netstream.Start("Vote", index)
return true
end)
hook.Add("SAM.ChangedGlobalVar", "SAM.VotingCount", function(key2, count)
if key2:sub(1, 7) ~= "Votings" then return end
if not count then return end
local index = tonumber(key2:sub(8))
options_added[index]:SetText(index .. ". " .. options[index] .. " (" .. count .. ")")
end)
end)
end
local vote_check = function(str)
return str:match("%S") ~= nil
end
command.new("vote")
:SetPermission("vote", "admin")
:AddArg("text", {hint = "title", check = vote_check})
:AddArg("text", {hint = "option", check = vote_check})
:AddArg("text", {hint = "option", check = vote_check})
:AddArg("text", {hint = "option", optional = true, check = vote_check})
:AddArg("text", {hint = "option", optional = true, check = vote_check})
:AddArg("text", {hint = "option", optional = true, check = vote_check})
:Help("Start a vote!")
:OnExecute(function(ply, title, ...)
local callback = function(_, option, count, total_count)
sam.player.send_message(nil, "Vote {V} for {V_2} has been passed. ({V_3}/{V_4})", {
V = title, V_2 = option, V_3 = count, V_4 = total_count
})
end
if start_vote(ply, callback, title, ...) then
sam.player.send_message(nil, "{A} started a vote with title {V}.", {
A = ply, V = title
})
end
end)
:End()
command.new("endvote")
:SetPermission("endvote", "admin")
:Help("End current vote.")
:OnExecute(function(ply)
end_vote(ply)
end)
:End()
command.new("votekick")
:SetPermission("votekick", "admin")
:AddArg("player", {single_target = true})
:AddArg("text", {hint = "reason", optional = true})
:GetRestArgs()
:Help("Start a vote to kick a player.")
:OnExecute(function(ply, targets, reason)
local target = targets[1]
local target_name = target:Name()
local callback = function(index, option, count, total_count)
if not IsValid(ply) then
sam.player.send_message(nil, "Vote was canceled because {T} left.", {
T = target_name
})
return
end
if index == 1 then
target:Kick("Vote was successful (" .. (reason or "none") .. ")")
sam.player.send_message(nil, "Vote was successful, {T} has been kicked. ({V})", {
T = targets, V = reason
})
else
sam.player.send_message(nil, "Vote was unsuccessful, {T} won't be kicked.", {
T = target_name
})
end
end
local title = "Kick " .. target_name .. "?"
if reason then
title = title .. " (" .. reason .. ")"
end
if start_vote(ply, callback, title, "Yes", "No") then
if reason then
sam.player.send_message(nil, "{A} started a votekick against {T} ({V})", {
A = ply, T = targets, V = reason
})
else
sam.player.send_message(nil, "{A} started a votekick against {T}", {
A = ply, T = targets
})
end
end
end)
:End()
command.new("voteban")
:SetPermission("voteban", "admin")
:AddArg("player", {single_target = true})
:AddArg("length", {optional = true, default = 60, min = 30, max = 120})
:AddArg("text", {hint = "reason", optional = true})
:GetRestArgs()
:Help("Start a vote to ban a player.")
:OnExecute(function(ply, targets, length, reason)
local target = targets[1]
local target_steamid, target_name = target:SteamID(), target:Name()
local ply_steamid = ply:SteamID()
local callback = function(index, option, count, total_count)
if index == 1 then
sam.player.ban_id(target_steamid, length, "Vote was successful (" .. (reason or "none") .. ")", ply_steamid)
sam.player.send_message(nil, "Vote was successful, {T} has been banned. ({V})", {
T = target_name, V = reason
})
else
sam.player.send_message(nil, "Vote was unsuccessful, {T} won't be banned.", {
T = target_name
})
end
end
local title = "Ban " .. target_name .. "?"
if reason then
title = title .. " (" .. reason .. ")"
end
if start_vote(ply, callback, title, "Yes", "No") then
if reason then
sam.player.send_message(nil, "{A} started a voteban against {T} for {V} ({V_2})", {
A = ply, T = targets, V = sam.format_length(length), V_2 = reason
})
else
sam.player.send_message(nil, "{A} started a voteban against {T} for {V}", {
A = ply, T = targets, V = sam.format_length(length)
})
end
end
end)
:End()
command.new("votemute")
:SetPermission("votemute", "admin")
:AddArg("player", {single_target = true})
:AddArg("text", {hint = "reason", optional = true})
:GetRestArgs()
:Help("Start a vote to mute and gag a player.")
:OnExecute(function(ply, targets, reason)
local _reason = reason and (" (" .. reason .. ")") or ""
local target = targets[1]
local target_name = target:Name()
local callback = function(index, option, count, total_count)
if not IsValid(target) then
sam.player.send_message(nil, "Vote was canceled because {T} left.", {
T = target_name
})
return
end
if index == 1 then
RunConsoleCommand("sam", "mute", "#" .. target:EntIndex(), 0, "votemute" .. _reason)
RunConsoleCommand("sam", "gag", "#" .. target:EntIndex(), 0, "votemute" .. _reason)
sam.player.send_message(nil, "Vote was successful, {T} has been muted. ({V})", {
T = target_name, V = reason
})
else
sam.player.send_message(nil, "Vote was unsuccessful, {T} won't be muted.", {
T = target_name
})
end
end
local title = "Mute " .. target_name .. "?" .. _reason
if start_vote(ply, callback, title, "Yes", "No") then
if reason then
sam.player.send_message(nil, "{A} started a votemute against {T} ({V}).", {
A = ply, T = targets, V = reason
})
else
sam.player.send_message(nil, "{A} started a votemute against {T}.", {
A = ply, T = targets
})
end
end
end)
:End()
command.new("votemap")
:SetPermission("votemap", "admin")
:AddArg("map", {exclude_current = true})
:AddArg("map", {optional = true, exclude_current = true})
:AddArg("map", {optional = true, exclude_current = true})
:GetRestArgs()
:Help("Start a vote to change map.")
:OnExecute(function(ply, ...)
local callback = function(_, option, count, total_count)
sam.player.send_message(nil, "Map vote for {V} has been passed. ({V_2}/{V_3})", {
V = option, V_2 = count, V_3 = total_count
})
if sam.is_valid_map(option) then
RunConsoleCommand("sam", "map", option)
end
end
local args = {...}
for i = select("#", ...), 1, -1 do
if args[i] == "None" then
args[i] = nil
end
end
table.insert(args, "Extend Current Map")
if start_vote(ply, callback, "Vote for the next map!", unpack(args)) then
sam.player.send_message(nil, "{A} started a map change vote.", {
A = ply
})
end
end)
:End()