Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
0

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

Asked by 4 years ago

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
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. fighterkirbyzx 102 — 4y
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. BreckleShrimp 23 — 4y

1 answer

Log in to vote
0
Answered by 4 years ago

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.

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 BreckleShrimp 23 — 4y
0
Is your FE enabled? that might be why it uses LocalPlayer correctly SerpentineKing 3885 — 4y
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. BreckleShrimp 23 — 4y
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 SerpentineKing 3885 — 4y
View all comments (4 more)
0
Will that cause problems in the future for shops, player guis, etc? I can try to change everything up if it will. BreckleShrimp 23 — 4y
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. SerpentineKing 3885 — 4y
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 SerpentineKing 3885 — 4y
1
Thank you! BreckleShrimp 23 — 4y
Ad

Answer this question