Coding a Murder Mystery Game - In-depth Coding Tutorial

Could look into that, though this does get the job done.

4 Likes

MAJOR BUG FIX

If the sheriff were to be killed, originally, the script would create a gun above the player for all the innocents to get. But, if the sheriff was holding it, the clone wouldn’t be created. This would give an unfair advantage for the innocent. To fix this, add the following in EventHandling:

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
8 Likes

Wow very good! Thanks for adding an uncopylocked version so I can examine the code and review through it to understand more coding!

3 Likes

It’s kinda uncopylocked, the assets are there but the code is in the post. Have fun!

2 Likes

I was really waiting for this! Thanks!

2 Likes

New Update!!!

In the Extra Features section, you can now add in characters and murder chance to change up the game. A model is attached for you to get so that you can work off of those!

Let me know if there’s any problems or any concerns! Thanks!

3 Likes

Just reviewing, this is actually extremely inefficient.
First you could just use

repeat
    Status.Value = "In order for the round to begin, there must be at least 2 players in the server."
    wait(2)
until #game.Players:GetPlayers() > 2

(That removes the need for putting all the players into a new table)

And even then I would recommend not utilizing loops, and using events instead

game.Players.PlayerAdded:Connect(function(player)
   if #game.Players:GetPlayers() > 2 then
      startRounds()
   end
end

Just some feedback :stuck_out_tongue:

5 Likes

The problem with this code is it will only prompt if someone new joins, and if there’s a current game going on, it will just stop that game.

I appreciate the feedback nonetheless!!

4 Likes

getting this error for some reason ServerScriptService.Master.Round:50: attempt to index nil with 'Character' - Server - Round:50

Did you create the character string value in playeradded?

1 Like

What’s the error? Where are you experiencing it?

Please show me that line area for Round

1 Like

oh ive been getting it all wrong : / welp here is the actual error:

function module.TeleportSheriff(player, mapSpawns)
	if player.Character then --error is this (line 51)
		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

Show me the lines where you determine the sheriff in Master and the function. I’m sorry if I’m making you jump around a lot but seeing all of this will help.

2 Likes

Master (put the full part just in case):

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

function (the one in the module?):

function module.ChooseSheriff(players)
	local RandomObj = Random.new()

	local chosenSheriff = players[RandomObj:NextInteger(1, #players)]

	return chosenSheriff
end

Upon attempting to join the “Murder Mystery - Tutorial” place I get kicked because “Testing in session!” but there are no people playing and I was on a brand new server every time I got kicked. I assume this means the place is subject to testing for a while more before it’s open to the public?

If you’re interested to see how a final product would like, then here is a game I made using 50% of his system.
https://web.roblox.com/games/6447977074/Massacre-Mystery-BETA

1 Like

So sorry for the inconvenience, I’ve allowed entry once again. Thank you!

Hi friend. I am starting with coding and stuff. This thing you made is awesome.
I have a question… maybe silly question…
here:

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

You made a function in the module script. Why did you call it module.Intermission instead of only Intermission? Is it mandatory the dot?

Then in the master you called it as round.Intermission.. why? Why not calling it using the module.Intermission name? I am confused in this. hope you can help me … :wink:

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

thanks for tutorial!

Hi! No worries, I’m happy to help! we do module.Intermission because when we call the round module, we want that specific function. If we did just Intermission() that function is local to the module, can’t be called anywhere else.

1 Like