Introduction
Hello everyone! In this topic, you’ll be learning to create a murder mystery game! This took me about 6-7 hours in total (writing and coding of this tutorial) so I’ve put a lot of work and effort into this! This code is considered a beginner/intermediate level. Anywho, if there are any questions and/or concerns, please let me know! Onto coding!
Part 0 - Getting started
In order to actually start coding, you’ll need the assets to work with. Go here and edit it: Murder Mystery Template It’s uncopylocked too! Open it and move onto the actual coding!
Part 1 - Coding the backend
As you can see, in ServerStorage, you can see the map. You can also see in ReplicatedStorage, an event, items, and status value in the Value folder. We will need to go to master in ServerScriptService to code access to the status stringvalue and require the module that is parented to it. To do so, we will need to code this:
local Status = game.ReplicatedStorage.Values:WaitForChild("status")
local round = require(script.Round)
Now, since this is a round-based game, we will need this game to run forever. We will need to add in a while loop below the variables like so:
local Status = game.ReplicatedStorage.Values:WaitForChild("status")
local round = require(script.Round)
while wait() do
end
Next, in all most games, in order to begin it, you’ll need to detect if there are 2 or more players in the game. in order to do so, we will need to put this into repeat-until loop. This way, it’ll wait until there are two players. Inside of this loop, we will need a table and add the players into that table. This way, we can detect how many players are actually ready. We will need to also add in a for loop through all of the players and add them into the table. Your code should look like this:
local Status = game.ReplicatedStorage.Values:WaitForChild("status")
local round = require(script.Round)
while wait() do
repeat
local availablePlayers = {}
for i, plr in pairs(game.Players:GetPlayers()) do
table.insert(availablePlayers, plr)
end
Status.Value = "In order for the round to begin, there must be at least 2 players in the server."
wait(2)
until #availablePlayers >= 2
end
Now that we have that, we need to move to the Round module. Modules allow you to create functions to which you can call those functions. In our case, we will need to create a function that will run intermission. We want to add a parameter so taht we can set any value for the countdown. We will need to also add in a for loop to count it down. We will also need to set the status equal to the text like this (MAKE SURE YOU CALL FOR THE STATUS STRING VALUE!!): Next round begins in… . To code this, do the following:
local status = game.ReplicatedStorage.Values:WaitForChild("status")
function module.Intermission(length)
for i = length, 0, -1 do
status.Value = "Next round in "..i.." seconds"
wait(1)
end
end
Nice! Now we just need to call this function in our main script so that it runs intermission. Since length is our parameter, set it to a positive integer. For me, I’ll set it to 5. In Master, type the following:
local Status = game.ReplicatedStorage.Values:WaitForChild("status")
local round = require(script.Round)
while wait() do
repeat
local availablePlayers = {}
for i, plr in pairs(game.Players:GetPlayers()) do
table.insert(availablePlayers, plr)
end
Status.Value = "In order for the round to begin, there must be at least 2 players in the server."
wait(2)
until #availablePlayers >= 2
round.Intermission(5)
end
Now, we will need to code a function for choosing a random map. If you look in ReplicatedStorage, you can see the map. It may look very similar to you. It’s because it was created by @Stickmasterluke back when he created the Mad Bloxxer tutorial series! Now, we will need to create the function in the module. It needs to choose a random map from that folder. Do the following in that script:
function module.SelectMap()
local random = Random.new()
local maps = game.ReplicatedStorage.Maps:GetChildren() -- Table of all of the maps
local chosenMap = maps[random:NextInteger(1,#maps)]
return chosenMap
end
It’s going to return a special value to us, the map’s name! Now, we need to get that in the Master code, clone it, and name it Map (THIS IS VERY IMPORTANT FOR TELEPORTING PLAYERS!!!). Do the following code:
local Status = game.ReplicatedStorage.Values:WaitForChild("status")
local round = require(script.Round)
while wait() do
repeat
local availablePlayers = {}
for i, plr in pairs(game.Players:GetPlayers()) do
table.insert(availablePlayers, plr)
end
Status.Value = "In order for the round to begin, there must be at least 2 players in the server."
wait(2)
until #availablePlayers >= 2
round.Intermission(5)
local chosenMap = round.SelectMap()
local clonedMap = chosenMap:Clone()
clonedMap.Name = "Map"
clonedMap.Parent = game.Workspace
end
Now that we have that, we will need to identify both the sheriff and murderer. In round module, we will need to decide who it will be using the random.new() function. In the code:
function module.ChooseMurderer(players)
local RandomObj = Random.new()
local chosenMurderer = players[RandomObj:NextInteger(1, #players)]
return chosenMurderer
end
function module.ChooseSheriff(players)
local RandomObj = Random.new()
local chosenSheriff = players[RandomObj:NextInteger(1, #players)]
return chosenSheriff
end
We will need the players function for a very important reason! We need to identify all of the players and put them into a table. This way, one person can be a murderer and another becomes a sheriff. Please, do the following in master:
local Status = game.ReplicatedStorage.Values:WaitForChild("status")
local round = require(script.Round)
while wait() do
repeat
local availablePlayers = {}
for i, plr in pairs(game.Players:GetPlayers()) do
table.insert(availablePlayers, plr)
end
Status.Value = "In order for the round to begin, there must be at least 2 players in the server."
wait(2)
until #availablePlayers >= 2
round.Intermission(5)
local chosenMap = round.SelectMap()
local clonedMap = chosenMap:Clone()
clonedMap.Name = "Map"
clonedMap.Parent = game.Workspace
local innocentPlayers = {}
local murderer = {}
local sheriff = {}
for i, v in pairs(game.Players:GetPlayers()) do
table.insert(innocentPlayers, v)
end
local chosenMurdererPlayer = round.ChooseMurderer(innocentPlayers)
for i, v in pairs(innocentPlayers) do
if v == chosenMurdererPlayer then
table.remove(innocentPlayers,i)
table.insert(murderer, i)
end
end
local chosenSheriffPlayer = round.ChooseSheriff(innocentPlayers)
for i, v in pairs(innocentPlayers) do
if v == chosenSheriffPlayer then
table.remove(innocentPlayers,i)
table.insert(sheriff, i)
end
end
wait(2)
We identified the innocent players, murderer, and sheriff by removing both the murderer and sheriff out of the innocent players table. Next we will need to havea string value attached to each player identifying who they are so that our gun can identify who is who when shooting. Create the function in round:
function module.InsertTag(players, tagName)
for i, player in pairs(players) do
local Tag = Instance.new("StringValue")
Tag.Name = tagName
Tag.Parent = player
end
end
Then, add this into master by giving the murderer, sheriff, and innocent users their respective tags like so:
round.InsertTag(innocentPlayers, "Innocent")
round.InsertTag({chosenSheriffPlayer}, "Sheriff")
round.InsertTag({chosenMurdererPlayer}, "Murderer")
Now, we need to teleport everyone as well as their items! The murderer will have a cool sword while the sheriff gets the gun. Do the following in round module:
function module.TeleportMurderer(player, mapSpawns)
if player.Character then
local knife = game.ServerStorage.Items.ClassicSword:Clone()
knife.Parent = player.Backpack
if player.Character:FindFirstChild("HumanoidRootPart") then
local rand = Random.new()
player.Character.HumanoidRootPart.CFrame = mapSpawns[rand:NextInteger(1, #mapSpawns)].CFrame + Vector3.new(0,10,0)
end
end
end
function module.TeleportSheriff(player, mapSpawns)
if player.Character then
local gun = game.ServerStorage.Items.Revolver:Clone()
gun.Parent = player.Backpack
if player.Character:FindFirstChild("HumanoidRootPart") then
local rand = Random.new()
player.Character.HumanoidRootPart.CFrame = mapSpawns[rand:NextInteger(1, #mapSpawns)].CFrame + Vector3.new(0,10,0)
end
end
end
We will also need to teleport the innocent users. Because there is more than one of them, it’ll be a little different:
function module.TeleportPlayers(player, mapSpawns)
for i, player in pairs(player) do
if player.Character then
local character = player.Character
if character:FindFirstChild("HumanoidRootPart") then
local rand = Random.new()
player.Character.HumanoidRootPart.CFrame = mapSpawns[rand:NextInteger(1, #mapSpawns)].CFrame + Vector3.new(0,10,0)
end
end
end
end
local function toMS(s)
return ("%02i:%02i"):format(s/60%60, s%60)
end
Now, we will need to call this in master! Do the following:
if clonedMap:FindFirstChild("PlayerSpawns") then
round.TeleportPlayers(innocentPlayers, clonedMap.PlayerSpawns:GetChildren())
round.TeleportSheriff(chosenSheriffPlayer, clonedMap.PlayerSpawns:GetChildren())
round.TeleportMurderer(chosenMurdererPlayer, clonedMap.PlayerSpawns:GetChildren())
else
warn("Fatal Error: no PlayerSpawns Folder")
end
Now that everyone is teleported, we need to start the round! We will need a parameter for identifying the time, murderer, and map (just in case they weren’t teleported). We will need to code the outcomes too such as who won and time being possible up. Earlier, you may have seen this function:
local function toMS(s)
return ("%02i:%02i"):format(s/60%60, s%60)
end
This function coverts seconds to minutes. It’s very important for starting the round in the function in round module:
function module.StartRound(length, murderer, map) -- in seconds
local outcome
game.ReplicatedStorage.Events.IdentifyPlayer:FireAllClients()
for i = length, 0, -1 do
local innocentPlayers = {}
local murderer = {}
local murdererHere = false
module.TeleportPlayers({murderer}, map.PlayerSpawns:GetChildren())
for i, player in pairs(game.Players:GetPlayers()) do
if player:FindFirstChild("Innocent") then
table.insert(innocentPlayers, player)
elseif player:FindFirstChild("Sheriff") then
table.insert(innocentPlayers, player)
elseif player:FindFirstChild("Murderer") then
wait(.3)
murdererHere = true
table.insert(murderer, player)
end
end
status.Value = toMS(i)
if not murdererHere then
outcome = "murderer-left"
break
end
if #murderer == 0 then
outcome = "murderer-died"
break
end
if #innocentPlayers == 0 then
outcome = "murderer-wins"
break
end
if i == 0 then
outcome = "time-up"
break
end
wait(1)
end
if outcome == "murderer-wins" then
status.Value = "Murderer wins!"
elseif outcome == "time-up" then
status.Value = "Times up!"
elseif outcome == "murderer-left" then
status.Value = "Murderer lost! Innocents win!"
elseif outcome == "murderer-died" then
status.Value = "Murderer has died! Innocents win!"
end
wait(5)
end
Now, we just need to call it in master! Like so:
round.StartRound(600, chosenMurdererPlayer, clonedMap)
Now! Since the outcomes will occur, we will need to end the game at some point. We will need to remove all of the items and return everyone back to the lobby. Do the following:
function module.RemoveTags()
for i, v in pairs(game.Players:GetPlayers()) do
if v:FindFirstChild("Murderer") then
v.Murderer:Destroy()
if v.Backpack:FindFirstChild("ClassicSword") then v.Backpack.ClassicSword:Destroy() end
if v.Character:FindFirstChild("ClassicSword") then v.Character.ClassicSword:Destroy() end
v:LoadCharacter()
end
if v:FindFirstChild("Innocent") then
v.Innocent:Destroy()
for _, p in pairs(v.Backpack:GetChildren()) do
if p:IsA("Tool") then
p:Destroy()
end
end
for _, p in pairs(v.Character:GetChildren()) do
if p:IsA("Tool") then
p:Destroy()
end
end
v:LoadCharacter()
end
if v:FindFirstChild("Sheriff") then
v.Sheriff:Destroy()
v:LoadCharacter()
for _, p in pairs(v.Backpack:GetChildren()) do
if p:IsA("Tool") then
p:Destroy()
end
end
for _, p in pairs(v.Character:GetChildren()) do
if p:IsA("Tool") then
p:Destroy()
end
end
v:LoadCharacter()
end
v:LoadCharacter()
end
end
Now, we just need to call this function as well as destroy the map like so:
clonedMap:Destroy()
round.RemoveTags()
wait(2)
Finally, if the sheriff dies, we will need to make sure that the gun can still be accessed by innocent users. In EventHandling, type the following:
game.Players.PlayerAdded:Connect(function(player)
player.CharacterAdded:Connect(function(character)
character:WaitForChild("Humanoid").Died:Connect(function()
if player:FindFirstChild("Murderer") ~= nil then
player:FindFirstChild("Murderer"):Destroy()
elseif player:FindFirstChild("Sheriff") ~= nil then
player:FindFirstChild("Sheriff"):Destroy()
for _, p in pairs(player.Backpack:GetChildren()) do
if p:IsA("Tool") then
local decoyGun = game.ServerStorage.Items.DecoyGun:Clone()
decoyGun.Parent = game.Workspace:FindFirstChild("Map")
decoyGun.CFrame = character.HumanoidRootPart.CFrame + Vector3.new(0,2,0)
p:Destroy()
end
end
elseif player:FindFirstChild("Innocent") ~= nil then
player:FindFirstChild("Innocent"):Destroy()
end
end)
end)
end)
Congratulations! You have the backend stuff coded. if you had troubles or just want to make sure your code is correct, take a look at the key below
MASTER:
local Status = game.ReplicatedStorage.Values:WaitForChild("status")
local round = require(script.Round)
while wait() do
repeat
local availablePlayers = {}
for i, plr in pairs(game.Players:GetPlayers()) do
table.insert(availablePlayers, plr)
end
Status.Value = "In order for the round to begin, there must be at least 2 players in the server."
wait(2)
until #availablePlayers >= 2
round.Intermission(5)
local chosenMap = round.SelectMap()
local clonedMap = chosenMap:Clone()
clonedMap.Name = "Map"
clonedMap.Parent = game.Workspace
local innocentPlayers = {}
local murderer = {}
local sheriff = {}
for i, v in pairs(game.Players:GetPlayers()) do
table.insert(innocentPlayers, v)
end
local chosenMurdererPlayer = round.ChooseMurderer(innocentPlayers)
for i, v in pairs(innocentPlayers) do
if v == chosenMurdererPlayer then
table.remove(innocentPlayers,i)
table.insert(murderer, i)
end
end
local chosenSheriffPlayer = round.ChooseSheriff(innocentPlayers)
for i, v in pairs(innocentPlayers) do
if v == chosenSheriffPlayer then
table.remove(innocentPlayers,i)
table.insert(sheriff, i)
end
end
wait(2)
round.InsertTag(innocentPlayers, "Innocent")
round.InsertTag({chosenSheriffPlayer}, "Sheriff")
round.InsertTag({chosenMurdererPlayer}, "Murderer")
if clonedMap:FindFirstChild("PlayerSpawns") then
round.TeleportPlayers(innocentPlayers, clonedMap.PlayerSpawns:GetChildren())
round.TeleportSheriff(chosenSheriffPlayer, clonedMap.PlayerSpawns:GetChildren())
round.TeleportMurderer(chosenMurdererPlayer, clonedMap.PlayerSpawns:GetChildren())
else
warn("Fatal Error: no PlayerSpawns Folder")
end
round.StartRound(600, chosenMurdererPlayer, clonedMap)
clonedMap:Destroy()
round.RemoveTags()
wait(2)
end
ROUND MODULE (PARENTED TO MASTER):
local module = {}
local status = game.ReplicatedStorage.Values:WaitForChild("status")
function module.Intermission(length)
for i = length, 0, -1 do
status.Value = "Next round in "..i.." seconds"
wait(1)
end
end
function module.SelectMap()
local random = Random.new()
local maps = game.ReplicatedStorage.Maps:GetChildren() -- Table of all of the maps
local chosenMap = maps[random:NextInteger(1,#maps)]
return chosenMap
end
function module.ChooseMurderer(players)
local RandomObj = Random.new()
local chosenMurderer = players[RandomObj:NextInteger(1, #players)]
return chosenMurderer
end
function module.ChooseSheriff(players)
local RandomObj = Random.new()
local chosenSheriff = players[RandomObj:NextInteger(1, #players)]
return chosenSheriff
end
function module.InsertTag(players, tagName)
for i, player in pairs(players) do
local Tag = Instance.new("StringValue")
Tag.Name = tagName
Tag.Parent = player
end
end
function module.TeleportMurderer(player, mapSpawns)
if player.Character then
local knife = game.ServerStorage.Items.ClassicSword:Clone()
knife.Parent = player.Backpack
if player.Character:FindFirstChild("HumanoidRootPart") then
local rand = Random.new()
player.Character.HumanoidRootPart.CFrame = mapSpawns[rand:NextInteger(1, #mapSpawns)].CFrame + Vector3.new(0,10,0)
end
end
end
function module.TeleportSheriff(player, mapSpawns)
if player.Character then
local gun = game.ServerStorage.Items.Revolver:Clone()
gun.Parent = player.Backpack
if player.Character:FindFirstChild("HumanoidRootPart") then
local rand = Random.new()
player.Character.HumanoidRootPart.CFrame = mapSpawns[rand:NextInteger(1, #mapSpawns)].CFrame + Vector3.new(0,10,0)
end
end
end
function module.TeleportPlayers(player, mapSpawns)
for i, player in pairs(player) do
if player.Character then
local character = player.Character
if character:FindFirstChild("HumanoidRootPart") then
local rand = Random.new()
player.Character.HumanoidRootPart.CFrame = mapSpawns[rand:NextInteger(1, #mapSpawns)].CFrame + Vector3.new(0,10,0)
end
end
end
end
local function toMS(s)
return ("%02i:%02i"):format(s/60%60, s%60)
end
function module.StartRound(length, murderer, map) -- in seconds
local outcome
game.ReplicatedStorage.Events.IdentifyPlayer:FireAllClients()
for i = length, 0, -1 do
local innocentPlayers = {}
local murderer = {}
local murdererHere = false
module.TeleportPlayers({murderer}, map.PlayerSpawns:GetChildren())
for i, player in pairs(game.Players:GetPlayers()) do
if player:FindFirstChild("Innocent") then
table.insert(innocentPlayers, player)
elseif player:FindFirstChild("Sheriff") then
table.insert(innocentPlayers, player)
elseif player:FindFirstChild("Murderer") then
wait(.3)
murdererHere = true
table.insert(murderer, player)
end
end
print(innocentPlayers[1])
status.Value = toMS(i)
if not murdererHere then
outcome = "murderer-left"
break
end
if #murderer == 0 then
outcome = "murderer-died"
break
end
if #innocentPlayers == 0 then
outcome = "murderer-wins"
break
end
if i == 0 then
outcome = "time-up"
break
end
wait(1)
end
if outcome == "murderer-wins" then
status.Value = "Murderer wins!"
elseif outcome == "time-up" then
status.Value = "Times up!"
elseif outcome == "murderer-left" then
status.Value = "Murderer lost! Innocents win!"
elseif outcome == "murderer-died" then
status.Value = "Murderer has died! Innocents win!"
end
wait(5)
end
function module.RemoveTags()
for i, v in pairs(game.Players:GetPlayers()) do
if v:FindFirstChild("Murderer") then
v.Murderer:Destroy()
if v.Backpack:FindFirstChild("ClassicSword") then v.Backpack.ClassicSword:Destroy() end
if v.Character:FindFirstChild("ClassicSword") then v.Character.ClassicSword:Destroy() end
v:LoadCharacter()
end
if v:FindFirstChild("Innocent") then
v.Innocent:Destroy()
for _, p in pairs(v.Backpack:GetChildren()) do
if p:IsA("Tool") then
p:Destroy()
end
end
for _, p in pairs(v.Character:GetChildren()) do
if p:IsA("Tool") then
p:Destroy()
end
end
v:LoadCharacter()
end
if v:FindFirstChild("Sheriff") then
v.Sheriff:Destroy()
v:LoadCharacter()
for _, p in pairs(v.Backpack:GetChildren()) do
if p:IsA("Tool") then
p:Destroy()
end
end
for _, p in pairs(v.Character:GetChildren()) do
if p:IsA("Tool") then
p:Destroy()
end
end
v:LoadCharacter()
end
v:LoadCharacter()
end
end
return module
EVENTHANDLING:
game.Players.PlayerAdded:Connect(function(player)
player.CharacterAdded:Connect(function(character)
character:WaitForChild("Humanoid").Died:Connect(function()
if player:FindFirstChild("Murderer") ~= nil then
player:FindFirstChild("Murderer"):Destroy()
elseif player:FindFirstChild("Sheriff") ~= nil then
player:FindFirstChild("Sheriff"):Destroy()
for _, p in pairs(player.Backpack:GetChildren()) do
if p:IsA("Tool") then
local decoyGun = game.ServerStorage.Items.DecoyGun:Clone()
decoyGun.Parent = game.Workspace:FindFirstChild("Map")
decoyGun.CFrame = character.HumanoidRootPart.CFrame * CFrame.new(0,2,0)
p:Destroy()
end
end
for _, p in pairs(player.Character:GetChildren()) do
if p:IsA("Tool") then
local decoyGun = game.ServerStorage.Items.DecoyGun:Clone()
decoyGun.Parent = game.Workspace:FindFirstChild("Map")
decoyGun.CFrame = character.HumanoidRootPart.CFrame * CFrame.new(0,2,0)
p:Destroy()
end
end
end
elseif player:FindFirstChild("Innocent") ~= nil then
player:FindFirstChild("Innocent"):Destroy()
end
end)
end)
end)
Part 2 - UI
Now that we have the actual game done, we need to code the UI related things such as the status bar and identifying the player. You may have seen the remote event called earlier, it’s for the identifying he player box. Code the following in the local script in StarterGUI:
local replicatedStorage = game:GetService("ReplicatedStorage")
local status = replicatedStorage.Values:WaitForChild("status")
local topStatus = script.Parent:WaitForChild("Status")
topStatus.Text = status.Value
topStatus.Visible = true
local IdentificationBox = script.Parent.PlayerIdentification
status:GetPropertyChangedSignal("Value"):Connect(function()
topStatus.Text = status.Value
end)
game.ReplicatedStorage.Events.IdentifyPlayer.OnClientEvent:Connect(function()
local player = game.Players.LocalPlayer
IdentificationBox.Visible = true
wait(2)
if player:FindFirstChild("Murderer") then
IdentificationBox.Murderer.Visible = true
elseif player:FindFirstChild("Sheriff") then
IdentificationBox.Sheriff.Visible = true
elseif player:FindFirstChild("Innocent") then
IdentificationBox.Innocent.Visible = true
end
wait(2)
IdentificationBox.Visible = false
IdentificationBox.Murderer.Visible = false
IdentificationBox.Sheriff.Visible = false
IdentificationBox.Innocent.Visible = false
end)
Extra Features
These are extra things that you can add to the game to make it a lot more enjoyable! For starters, please get this model: Murder Mystery Tuturial - Addons - Roblox
Please put the available characters folder into ReplicatedStorage and the MurderChance into StarterGui > ScreenGui. You can delete that model that was a part of the model you got as it’s no longer needed.
Characters
To start, go into the EventHandling. We will need to have a string value for the character that’s chosen so it’s easier to dress up the player. In the PlayerAdded function, add the following:
local Character = Instance.new("StringValue")
Character.Name = "Character"
Character.Value = "None"
Character.Parent = player
Now, in the round module, we will need to decide what character each player gets. We don’t want duplicates either, so we will need to create a table like so:
function module.ChooseCharacter()
local AvailableCharacters = {}
end
Now we will need to loop through each player and choose a character for the player to play as, do the following:
function module.ChooseCharacter()
local AvailableCharacters = {}
for i, v in pairs(game.ReplicatedStorage.AvailableCharacters:GetChildren()) do
table.insert(AvailableCharacters, v.Name)
end
for i, v in pairs(game.Players:GetPlayers()) do
local randomCharacter = math.random(1, #AvailableCharacters)
local ChosenCharacter = AvailableCharacters[randomCharacter]
end
end
Finally, we will need to set that random character to that character stringvalue value and remove that character from the table so no duplicates occur. Do the following:
function module.ChooseCharacter()
local AvailableCharacters = {}
for i, v in pairs(game.ReplicatedStorage.AvailableCharacters:GetChildren()) do
table.insert(AvailableCharacters, v.Name)
end
for i, v in pairs(game.Players:GetPlayers()) do
local randomCharacter = math.random(1, #AvailableCharacters)
local ChosenCharacter = AvailableCharacters[randomCharacter]
v:FindFirstChild("Character").Value = ChosenCharacter
table.remove(AvailableCharacters, randomCharacter)
end
end
Now that the player has a character chosen, we will need to dress that player. In the round module in a new function, do the following:
function module.DressPlayers()
for i, player in pairs(game.Players:GetPlayers()) do
local character
if player:FindFirstChild("Character").Value ~= "" then
character = game.ReplicatedStorage.AvailableCharacters[player:FindFirstChild("Character").Value]:Clone()
end
character.Name = player.Name
player.Character = character
character.Parent = workspace
end
end
What this will do is check to see if it exists. I’d that character exists, set the player as the character.
Add these two functions after choosing the sheriff in master like here:
local chosenSheriffPlayer = round.ChooseSheriff(innocentPlayers)
for i, v in pairs(innocentPlayers) do
if v == chosenSheriffPlayer then
table.remove(innocentPlayers,i)
table.insert(sheriff, i)
end
end
wait(.01)
round.ChooseCharacter()
round.DressPlayers()
wait(.01)
round.InsertTag(innocentPlayers, "Innocent")
round.InsertTag({chosenSheriffPlayer}, "Sheriff")
round.InsertTag({chosenMurdererPlayer}, "Murderer")
Murder Chance
Now, with that MurderChance textlabel, we will need to update the choosing the murderer function. We want it create a table and insert the number of times the player has for murder chance into that table. In the PlayerAdded function in EventHandling, create the following intvalue:
local MurderChance = Instance.new("IntValue")
MurderChance.Name = "MurderChance"
MurderChance.Value = 1
MurderChance.Parent = player
Now in the Choose Murder function, do the following:
function module.ChooseMurderer(players)
local RandomObj = Random.new()
local PossibleMurderers = {}
for _, v in pairs(players) do
local MurderChance = v.MurderChance.Value
for i = 1, MurderChance do
table.insert(PossibleMurderers, v.UserId)
end
end
local chosenMurderer = PossibleMurderers[RandomObj:NextInteger(1, #PossibleMurderers)]
local ChosenMurdererPlayer = game.Players:GetPlayerByUserId(chosenMurderer)
for _, v in pairs(players) do
if v.UserId ~= ChosenMurdererPlayer then
v.MurderChance.Value += 1
end
end
ChosenMurdererPlayer.MurderChance.Value = 1
return ChosenMurdererPlayer
end
What this will do is based on the number for the MurderChance, it will add the number of the playerids to the table. Then choose the id from the table. If the others weren’t chosen, the chance will go up by one and the murderer will be set back to 1. In the local script in StarterGui > ScreenGui, we want to show this value to the player and only show an updated number if the value property changes. Do the following in that script:
player:WaitForChild("MurderChance"):GetPropertyChangedSignal("Value"):Connect(function()
script.Parent.MurderChance.Text = "Murder Chance: ".. player.MurderChance.Value .. "%"
end)
Nice work! You just added in character selction and murder chances to the game for more enjoyment!
Conclusion
Thank you so much for reading! This took me a while to finish but I am glad to have finished it! You may have noticed that this code is similar to @Alvin_Blox’s, however, it was used for the murder mystery game. All round-based games will have something similar to this, though it may be different based on developer’s preference. Anyways, thank you so much and if you wanted to try the real game, here is the link: Murder Mystery - Tutorial - Roblox
Thank you and happy developing!
~ WooleyWool