201 lines
4.5 KiB
Plaintext
201 lines
4.5 KiB
Plaintext
local VotingHandlerServer = {}
|
|
|
|
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
|
local Players = game:GetService("Players")
|
|
|
|
local Data = ReplicatedStorage:WaitForChild("Data")
|
|
local OptionsData = require(Data:WaitForChild("OptionsData"))
|
|
|
|
local Remote = ReplicatedStorage:WaitForChild("Remote")
|
|
local rev_Vote = Remote:WaitForChild("Vote")
|
|
local rev_StartVote = Remote:WaitForChild("StartVote")
|
|
local rev_EndVote = Remote:WaitForChild("EndVote")
|
|
|
|
local alreadyVoted = {} -- userId -> option
|
|
local voteCounts = {} -- option -> count
|
|
|
|
local currentOptions = {}
|
|
local moduleData = nil
|
|
|
|
local activeConnections = {}
|
|
local touchDebounce = {}
|
|
|
|
-- cleanup
|
|
local function cleanupConnections()
|
|
for _, conn in ipairs(activeConnections) do
|
|
if conn then conn:Disconnect() end
|
|
end
|
|
table.clear(activeConnections)
|
|
end
|
|
|
|
-- pick random KEYS from dictionary
|
|
local function pickRandomOptions(source, count)
|
|
local keys = {}
|
|
|
|
for key in pairs(source) do
|
|
table.insert(keys, key)
|
|
end
|
|
|
|
local selected = {}
|
|
|
|
for i = 1, math.min(count, #keys) do
|
|
local index = math.random(1, #keys)
|
|
table.insert(selected, keys[index])
|
|
table.remove(keys, index)
|
|
end
|
|
|
|
return selected
|
|
end
|
|
|
|
-- results
|
|
local function calculateResults()
|
|
local results = {}
|
|
|
|
for _, option in ipairs(currentOptions) do
|
|
results[option] = voteCounts[option] or 0
|
|
end
|
|
|
|
return results
|
|
end
|
|
|
|
-- update stands
|
|
local function updateVotingStands(votingStands, results)
|
|
if not votingStands then return end
|
|
|
|
for index, stand in ipairs(votingStands) do
|
|
local option = currentOptions[index]
|
|
if not option then continue end
|
|
|
|
local data = moduleData[option]
|
|
|
|
local gui = stand:FindFirstChild("IndicatorPart")
|
|
if gui then gui = gui:FindFirstChild("VoteGui") end
|
|
if not gui then continue end
|
|
|
|
local votesLabel = gui:FindFirstChild("Votes")
|
|
local mapLabel = gui:FindFirstChild("MapName")
|
|
|
|
if mapLabel then
|
|
mapLabel.Text = (data and data.DisplayName) or option
|
|
end
|
|
|
|
if votesLabel then
|
|
votesLabel.Text = tostring(results[option] or 0)
|
|
end
|
|
|
|
local imagePart = stand:FindFirstChild("MapImagePart")
|
|
if imagePart and imagePart:FindFirstChild("ImageGui") then
|
|
local img = imagePart.ImageGui:FindFirstChild("Picture")
|
|
if img then
|
|
img.Image = (data and data.DisplayImage) or ""
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local function broadcast(votingStands)
|
|
local results = calculateResults()
|
|
rev_Vote:FireAllClients(results)
|
|
updateVotingStands(votingStands, results)
|
|
end
|
|
|
|
-- voting logic
|
|
local function registerVote(player, option, votingStands)
|
|
if not player or not option then return end
|
|
|
|
voteCounts[option] = voteCounts[option] or 0
|
|
local userId = player.UserId
|
|
|
|
if alreadyVoted[userId] == option then
|
|
return
|
|
end
|
|
|
|
local previous = alreadyVoted[userId]
|
|
if previous and voteCounts[previous] then
|
|
voteCounts[previous] -= 1
|
|
end
|
|
|
|
alreadyVoted[userId] = option
|
|
voteCounts[option] += 1
|
|
|
|
broadcast(votingStands)
|
|
end
|
|
|
|
-- START
|
|
function VotingHandlerServer.StartVoting(optionCount, moduleKey, votingStands)
|
|
cleanupConnections()
|
|
|
|
alreadyVoted = {}
|
|
voteCounts = {}
|
|
touchDebounce = {}
|
|
|
|
moduleData = OptionsData.Get(moduleKey)
|
|
if not moduleData then
|
|
warn("No moduleData for:", moduleKey)
|
|
return
|
|
end
|
|
|
|
currentOptions = pickRandomOptions(moduleData, optionCount)
|
|
|
|
-- remote voting
|
|
table.insert(activeConnections,
|
|
rev_Vote.OnServerEvent:Connect(function(player, option)
|
|
registerVote(player, option, votingStands)
|
|
end)
|
|
)
|
|
|
|
-- stand voting
|
|
if votingStands then
|
|
for index, stand in ipairs(votingStands) do
|
|
local option = currentOptions[index]
|
|
if option then
|
|
local conn = stand.ToVotePart.Touched:Connect(function(hit)
|
|
local player = Players:GetPlayerFromCharacter(hit.Parent)
|
|
if not player then return end
|
|
|
|
local userId = player.UserId
|
|
if touchDebounce[userId] then return end
|
|
|
|
touchDebounce[userId] = true
|
|
registerVote(player, option, votingStands)
|
|
|
|
task.delay(0.5, function()
|
|
touchDebounce[userId] = nil
|
|
end)
|
|
end)
|
|
|
|
table.insert(activeConnections, conn)
|
|
end
|
|
end
|
|
end
|
|
|
|
updateVotingStands(votingStands, calculateResults())
|
|
rev_StartVote:FireAllClients(currentOptions, moduleKey)
|
|
end
|
|
|
|
-- END
|
|
function VotingHandlerServer.EndVoting()
|
|
cleanupConnections()
|
|
|
|
rev_EndVote:FireAllClients()
|
|
|
|
local results = calculateResults()
|
|
|
|
local winner
|
|
local highest = -1
|
|
|
|
for option, votes in pairs(results) do
|
|
if votes > highest then
|
|
highest = votes
|
|
winner = option
|
|
end
|
|
end
|
|
|
|
if not winner and #currentOptions > 0 then
|
|
winner = currentOptions[math.random(1, #currentOptions)]
|
|
end
|
|
|
|
return winner, moduleData and moduleData[winner]
|
|
end
|
|
|
|
return VotingHandlerServer |