Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
✓ ANSWER ACCEPTED

What is wrong with my map voter script with timer and maps?

Hello. I have some code here whose function is to wait 15 seconds for the intermission, then wait 10 seconds for map voting. At the start of these 10 seconds, 3 maps are randomly chosen to be displayed on the display pads. Players will vote on which map they want by stepping on the part that correlates with the map of their choice (kind of like in Murder Mystery 2). After map voting, the maps on the display pads and their votes disappear and the game goes on by telling everyone which map was the winner. Then it plays the round for 10 seconds and it loops, etc.

Everything works up until picking a winner. It seems as if the first time around, it works perfectly, but it seems to become inconsistent in the next rounds as it randomly picks a map on the display pads to win, rather than picking the map with the most votes. If you can find an error with my code, please let me know.

Thank you.

local rep = game:GetService("ReplicatedStorage")
local players = game:GetService("Players")
local minutesvalue = rep:WaitForChild("Minutes")
local secondsvalue = rep:WaitForChild("Seconds")
local minutes = 0 --minutes
local seconds = 11 --seconds
local status = game.Players.LocalPlayer.PlayerGui.Status:WaitForChild("Status")
local VotingSystem = game.Workspace:WaitForChild("VotingSystem")
local Pad1 = VotingSystem:WaitForChild("Pad1")
local Pad2 = VotingSystem:WaitForChild("Pad2")
local Pad3 = VotingSystem:WaitForChild("Pad3")
local title1 = VotingSystem.VotingDisplay.SurfaceGui.Pad1:WaitForChild("Header")
local title2 = VotingSystem.VotingDisplay.SurfaceGui.Pad2:WaitForChild("Header")
local title3 = VotingSystem.VotingDisplay.SurfaceGui.Pad3:WaitForChild("Header")

local ReplicatedStorage = game:GetService("ReplicatedStorage")

local doneVoting = ReplicatedStorage:WaitForChild("doneVoting")
title1.Text = ""
title2.Text = ""
title3.Text = ""
while true do
	
	
	status.Text = "Intermission"
	secondsvalue.Value = 15
	
	repeat
		secondsvalue.Value = secondsvalue.Value - 1
		wait(1)
	until secondsvalue.Value <= 0 and minutesvalue.Value <= 0
	
	status.Text = "Voting In Progress"
	
	secondsvalue.Value = 10
	

	game.Players.PlayerAdded:Connect(function(player)
		local Vote = Instance.new("StringValue")
		Vote.Name = "Vote"
		Vote.Parent = player
		Vote.Value = "NA"
	end)
	
	-- Vote Counter
	local function UpdateDisplay()
		VotingSystem.VotingDisplay.SurfaceGui.Pad1.Counter.Text = Pad1.Votes.Value
		VotingSystem.VotingDisplay.SurfaceGui.Pad2.Counter.Text = Pad2.Votes.Value
		VotingSystem.VotingDisplay.SurfaceGui.Pad3.Counter.Text = Pad3.Votes.Value
	end

	for i, Pad in pairs (game.Workspace.VotingSystem:GetChildren())do
		if Pad.Name ~= "VotingDisplay" then
			Pad.Touched:Connect(function(hit)
				if hit.Parent:FindFirstChild("Humanoid")then
					local char = hit.Parent
					local player = game.Players:GetPlayerFromCharacter(char)
					
					if player.Vote.Value ~= Pad then
						Pad.Votes.Value = Pad.Votes.Value + 1
						if player.Vote.Value ~= "NA" then
							local padToSubtract = VotingSystem:FindFirstChild(player.Vote.Value)
							padToSubtract.Votes.Value = padToSubtract.Votes.Value - 1
						end
						player.Vote.Value = Pad.Name
						UpdateDisplay()
					end
				end
				
			end)
		end
	end
	
	-- Picking which maps to vote between
	
	local Maps = game.Lighting.Maps:GetChildren()
	local voteMap1 = Maps[math.random(1, #Maps)]
	local voteMap2 = Maps[math.random(1, #Maps)]
	local voteMap3 = Maps[math.random(1, #Maps)]
	if voteMap2 == voteMap1 then
		repeat
			voteMap2 = Maps[math.random(1, #Maps)]
		until voteMap2 ~= voteMap1
	end
	if voteMap3 == voteMap2 or voteMap3 == voteMap1 then
		repeat
			voteMap3 = Maps[math.random(1, #Maps)]
		until voteMap3 ~= voteMap2 and voteMap3 ~= voteMap1
	end
	title1.Text = tostring(voteMap1)
	title2.Text = tostring(voteMap2)
	title3.Text = tostring(voteMap3)
	
	-- The calculating winner function
	
	local function CalculateWinner()

		local padVotes = {
			[tostring(voteMap1)] = Pad1.Votes.Value,
			[tostring(voteMap2)] = Pad2.Votes.Value,
			[tostring(voteMap3)] = Pad3.Votes.Value,
		}
		
		local highest = 0
		local pad = nil
		for i, v in pairs (padVotes) do
			if v > highest then
				highest = v
				pad = i
			end
		end
		
		return pad
	end
	
	-- Waiting for voting timer to run out
	
	repeat
		secondsvalue.Value = secondsvalue.Value - 1
		wait(1)
	until secondsvalue.Value <= 0 and minutesvalue.Value <= 0
	-- (Calculating winner before votes reset.)
	CalculateWinner()
	-- Resetting data
	
	spawn(function()
		while wait(1) do
			if secondsvalue.Value <= 0 then
				doneVoting.Value = true
				CalculateWinner()
				Pad1.Votes.Value = 0
				Pad2.Votes.Value = 0
				Pad3.Votes.Value = 0
				VotingSystem.VotingDisplay.SurfaceGui.Pad1.Counter.Text = 0
				VotingSystem.VotingDisplay.SurfaceGui.Pad2.Counter.Text = 0
				VotingSystem.VotingDisplay.SurfaceGui.Pad3.Counter.Text = 0
				title1.Text = ""
				title2.Text = ""
				title3.Text = ""
				wait(5)
				doneVoting.Value = false
			end
		end
	end)
	
	-- Stating the winning map
	
	local mapWinner = CalculateWinner()
	
	if mapWinner == nil then
		local padVotes = {tostring(voteMap1),tostring(voteMap2),tostring(voteMap3)}
		mapWinner = padVotes[math.random(1,#padVotes)]
	end
	
	status.Text = "Loading Map ".. mapWinner
	
	wait(5)
	

	
	
	status.Text = "Round In Progress"
    minutesvalue.Value = minutes
    secondsvalue.Value = seconds
   
    repeat
        if secondsvalue.Value <= 0 then
            minutesvalue.Value = minutesvalue.Value - 1
            secondsvalue.Value = 59
        else
            secondsvalue.Value = secondsvalue.Value - 1
        end
        wait(1)
    until secondsvalue.Value <= 0 and minutesvalue.Value <= 0

	status.Text = "Game Over!"

	wait(5)
	
end

2 comments

0

I'm not sure if this was done in the script or not, but maybe you need to clear out the string values value.

0

So I believe I cleared out all my string values including the new ones: voteMap1, voteMap2, voteMap3, and mapWinner. These are cleared out along with the ones already in the code. However, the problem still is occurring.

1 answer

✓ Accepted answer

Improvements

Use :GetService() for the Workspace and Players

Use :WaitForChild() to make sure an instance exists before using it

Place newly created functions outside of your loop, this makes the code more efficient as it doesn't have to create an entirely new function each time the loop is complete and is more easily read.

For code that is repeated, you can make another local function (such as with your repeats) instead

Multiple times in your code, you call CalculateWinner() but do nothing with it, thus these calls are unnecessary

You are calling tostring() on what I presume to be a model, instead just use the Name property.

When using :FindFirstChild() make sure to check the result is not nil

Issues

spawn executes the given function in a new thread, so once the while loop in the spawned function begins, you never end it and you create multiple of these after each loop. The loop will continue during the round and end of intermission as well because of the condition. Resetting it once is enough.

Under the Touched event, you have the Line 59 "if player.Vote.Value ~= Pad then", however, the Value of "Vote" is a string, while "Pad" is an object, so this condition will always return true.

Assuming this is a ServerScript, you cannot call "game.Players.LocalPlayer", if it is a LocalScript, then the values set will not coincide for all players on the server and the below code should be placed in a ServerScript in ServerScriptService instead

Revised Server Script

-- Local Variables
local players = game:GetService("Players")

local rep = game:GetService("ReplicatedStorage")
local doneVoting = rep:WaitForChild("doneVoting")
local minutesvalue = rep:WaitForChild("Minutes")
local secondsvalue = rep:WaitForChild("Seconds")

local VotingSystem = game:GetService("Workspace"):WaitForChild("VotingSystem")
local Pad1 = VotingSystem:WaitForChild("Pad1")
local Pad2 = VotingSystem:WaitForChild("Pad2")
local Pad3 = VotingSystem:WaitForChild("Pad3")
local PV1 = Pad1:WaitForChild("Votes")
local PV2 = Pad1:WaitForChild("Votes")
local PV3 = Pad1:WaitForChild("Votes")

local VGui = VotingSystem:WaitForChild("VotingDisplay"):WaitForChild("SurfaceGui")
local PC1 = VGui:WaitForChild("Pad1"):WaitForChild("Counter")
local PC2 = VGui:WaitForChild("Pad2"):WaitForChild("Counter")
local PC3 = VGui:WaitForChild("Pad3"):WaitForChild("Counter")

local title1 = VGui:WaitForChild("Pad1"):WaitForChild("Header")
local title2 = VGui:WaitForChild("Pad2"):WaitForChild("Header")
local title3 = VGui:WaitForChild("Pad3"):WaitForChild("Header")
title1.Text = ""
title2.Text = ""
title3.Text = ""

local voteMap1 = nil
local voteMap2 = nil
local voteMap3 = nil

local minutes = 0
local seconds = 11

-- Update Status for all Players
local function UpdateStatus(text)
	for _, player in pairs(players:GetPlayers()) do
		local status = player:WaitForChild("PlayerGui"):WaitForChild("Status"):WaitForChild("Status")
		status.Text = text
	end
end

-- Vote Counter
local function UpdateDisplay()
	PC1.Text = PV1.Value
	PC2.Text = PV2.Value
	PC3.Text = PV3.Value
end

-- Picks Maps to Vote For
local function RandomizeMaps()
	local Maps = game:GetService("Lighting"):WaitForChild("Maps"):GetChildren()
	voteMap1 = Maps[math.random(1, #Maps)]
	voteMap2 = Maps[math.random(1, #Maps)]
	voteMap3 = Maps[math.random(1, #Maps)]
	
	if voteMap2 == voteMap1 then
		repeat
			voteMap2 = Maps[math.random(1, #Maps)]
		until voteMap2 ~= voteMap1
	end
	if voteMap3 == voteMap2 or voteMap3 == voteMap1 then
		repeat
			voteMap3 = Maps[math.random(1, #Maps)]
		until voteMap3 ~= voteMap2 and voteMap3 ~= voteMap1
	end
	
    title1.Text = voteMap1.Name
    title2.Text = voteMap2.Name
    title3.Text = voteMap3.Name
end

-- Determine Winning Map
local function CalculateWinner()
	local padVotes = {
		[voteMap1.Name] = PV1.Value,
		[voteMap2.Name] = PV2.Value,
		[voteMap3.Name] = PV3.Value,
	}

	local highest = 0
	local pad = nil
	for map, vote in pairs(padVotes) do
		if vote > highest then
			highest = vote
			pad = map
		end
	end
	
	if pad == nil then
		local padTbl = {voteMap1.Name, voteMap2.Name, voteMap3.Name}
		pad = padTbl[math.random(1, #padTbl)]
	end
	
	return pad
end

-- Reset Pads
local function ResetVotes()
	wait(1)
	doneVoting.Value = true
	PV1.Value = 0
	PV2.Value = 0
	PV3.Value = 0
	PC1.Text = 0
	PC2.Text = 0
	PC3.Text = 0
	title1.Text = ""
	title2.Text = ""
	title3.Text = ""
	voteMap1 = nil
	voteMap2 = nil
	voteMap3 = nil

	for _, player in pairs(players:GetPlayers()) do
		local plyrVote = player:WaitForChild("Vote")
		plyrVote.Value = "NA"
	end

	wait(5)
	doneVoting.Value = false
end

local function WaitTime(min, sec)
	minutesvalue.Value = min
	secondsvalue.Value = sec
    
	repeat
		if secondsvalue.Value <= 0 then
			minutesvalue.Value = minutesvalue.Value - 1
			secondsvalue.Value = 59
		else
			secondsvalue.Value = secondsvalue.Value - 1
		end
		wait(1)
	until secondsvalue.Value <= 0 and minutesvalue.Value <= 0
end

-- Give Players Voting Tags
players.PlayerAdded:Connect(function(player)
	local Vote = Instance.new("StringValue")
	Vote.Name = "Vote"
	Vote.Parent = player
	Vote.Value = "NA"
end)

-- Prepare Pads
for _, Pad in pairs(VotingSystem:GetChildren())do
	if Pad.Name ~= "VotingDisplay" then
		Pad.Touched:Connect(function(hit)
			if hit and hit.Parent and players:GetPlayerFromCharacter(hit.Parent) then
				local player = players:GetPlayerFromCharacter(hit.Parent)
				local plyrVote = player:WaitForChild("Vote")
				if plyrVote.Value ~= Pad.Name then
					Pad:WaitForChild("Votes").Value = Pad:WaitForChild("Votes").Value + 1
					if plyrVote.Value ~= "NA" then
						local padToSubtract = VotingSystem:FindFirstChild(plyrVote.Value)
						if padToSubtract then
							padToSubtract:WaitForChild("Votes").Value = padToSubtract:WaitForChild("Votes").Value - 1
						end
					end
					plyrVote.Value = Pad.Name
					UpdateDisplay()
				end
			end
		end)
	end
end

while true do
	UpdateStatus("Intermission")
	WaitTime(0, 15)

	UpdateStatus("Voting In Progress")
	RandomizeMaps()
	WaitTime(0, 10)

	-- Declare Winning Map
	local mapWinner = CalculateWinner()
	-- Reset Pads
	ResetVotes()
	
	UpdateStatus("Loading Map "..mapWinner)
	wait(5)

	UpdateStatus("Round In Progress")
	WaitTime(minutes, seconds)

	UpdateStatus("Game Over!")
	wait(5)
end

Additionally, I would be placing your maps under ServerStorage or ReplicatedStorage instead of Lighting.

8 comments

0

I will try all of these and see if it works. Thank you! Also, it is inside a local script in a screen Gui for the timer. We've tested to make sure that it is the same for all players, and it is confirmed to be the same. And the voteMaps are variables that are supposed to hold the name of a random map so they can display 3 random maps out of a variety of maps. The toString(voteMap#) I actually figu

0

Is your FE enabled? that might be why it uses LocalPlayer correctly

1

I tried your script and it worked very cleanly! Thank you so much! I will also keep your suggestions in mind for scripts I write in the future. Thanks again! I apologize for my ignorance, but what is FE?  (Filtering Enabled) I just checked, it is enabled.

0

FE is FilteringEnabled, essentially it lets the game act like the Client and the Server are the same entity when they really aren't, changes to a single player are made for all players while it is on

0

Will that cause problems in the future for shops, player guis, etc? I can try to change everything up if it will.

0

*off, your FE must be off, anyway, if all your scripts are written with that in mind, then they'll work fine as long as the setting is kept the same.

0

However, its preferred to keep FE on since it prevents unwanted changes to the game and makes the game more secure from exploits. In the future I'd make sure to script with the server and client separate, since that will work regardless of the setting

1

Thank you!

This discussion is preserved as it was. New answers, comments, and votes are closed.