--!strict -- NEO PORTFOLIO SOURCE SAMPLE / ROBLOX STUDIO TEST REQUIRED -- Place in ServerScriptService in a TEST experience. -- Map voting state, vote validation, countdown and winner selection only. -- No map loading, teleporting, combat or round spawning is included. local Players = game:GetService("Players") local ReplicatedStorage = game:GetService("ReplicatedStorage") local VOTE_SECONDS = 25 local RESULTS_SECONDS = 9 local MAP_NAMES = {"Neon City", "Sky Islands", "Frost Base"} local rng = Random.new() local actionRemote = Instance.new("RemoteEvent") actionRemote.Name = "NeoMapVoteAction" actionRemote.Parent = ReplicatedStorage local stateRemote = Instance.new("RemoteEvent") stateRemote.Name = "NeoMapVoteState" stateRemote.Parent = ReplicatedStorage local snapshotRemote = Instance.new("RemoteFunction") snapshotRemote.Name = "NeoMapVoteSnapshot" snapshotRemote.Parent = ReplicatedStorage local votes: {[number]: string} = {} local lastVoteAt: {[number]: number} = {} local phase = "voting" local phaseEndsAt = os.time() + VOTE_SECONDS local lastWinner: string? = nil local roundId = 0 local function isValidMap(mapName: any): boolean if type(mapName) ~= "string" then return false end for _, name in MAP_NAMES do if name == mapName then return true end end return false end local function getTotals(): {[string]: number} local counts: {[string]: number} = {} for _, name in MAP_NAMES do counts[name] = 0 end for _, name in votes do if counts[name] ~= nil then counts[name] += 1 end end return counts end local function buildSnapshot(player: Player?): {[string]: any} return { phase = phase, round = roundId, remaining = math.max(0, phaseEndsAt - os.time()), maps = MAP_NAMES, counts = getTotals(), winner = lastWinner, selected = if player then votes[player.UserId] else nil, } end local function chooseWinner(): string local totals = getTotals() local highest = -1 local ties = {} for _, name in MAP_NAMES do local score = totals[name] if score > highest then highest = score ties = {name} elseif score == highest then table.insert(ties, name) end end return ties[rng:NextInteger(1, #ties)] end snapshotRemote.OnServerInvoke = function(player: Player): {[string]: any} return buildSnapshot(player) end actionRemote.OnServerEvent:Connect(function(player: Player, mapName: any) if phase ~= "voting" or not isValidMap(mapName) then return end local id = player.UserId local now = os.clock() if now - (lastVoteAt[id] or -math.huge) < 0.3 then return -- Per-player rate limit, preventing unnecessary vote spam. end lastVoteAt[id] = now votes[id] = mapName -- Replaces old vote instead of adding another one. stateRemote:FireAllClients(buildSnapshot(nil)) stateRemote:FireClient(player, buildSnapshot(player)) end) Players.PlayerRemoving:Connect(function(player: Player) votes[player.UserId] = nil lastVoteAt[player.UserId] = nil stateRemote:FireAllClients(buildSnapshot(nil)) end) task.spawn(function() while true do roundId += 1 phase = "voting" lastWinner = nil votes = {} phaseEndsAt = os.time() + VOTE_SECONDS stateRemote:FireAllClients(buildSnapshot(nil)) while os.time() < phaseEndsAt do task.wait(1) stateRemote:FireAllClients(buildSnapshot(nil)) end lastWinner = chooseWinner() phase = "results" phaseEndsAt = os.time() + RESULTS_SECONDS stateRemote:FireAllClients(buildSnapshot(nil)) while os.time() < phaseEndsAt do task.wait(1) stateRemote:FireAllClients(buildSnapshot(nil)) end end end)