How to create a different Round and Gamemode script?

Hi there!

I wrote a ServerScript that chooses a random ModuleScript from a folder, each of the ModuleScripts in the folder contain different game-modes. The problem I am facing now is that I do not know how to get the ServerScript to know when the selected game-mode has already finished and it is now required to select another ModuleScript from the folder. Basically a Game-Mode system.

How do I get either the ServerScript or ModuleScript to choose another ModuleScript after the game-mode is over?

Server Script:

function StartRound1()
	
	if Playercount >= 1 then 
		task.wait()
		local GM = script.GameModes:GetChildren()
		local SelectGamemode = GM[math.random(1, #GM)]
		print(SelectGamemode)
		local SG = require(SelectGamemode)

	else
		task.wait(5)
		print("StartRound1Loading")
		StartRound1()
	end
end

StartRound1()

function StartRound2(Round2)
--- I want to start round 2 here
---How do I get the script to detect that the first round is over?
	
end	
1 Like

You said different ModuleScripts contain different gamemodes, right?
You can do slight modifications to the modules so they return a table instead of a singular function structured like so:

return {
    Callback = function() end,
    FinishedEvent = Instance.new("BindableEvent")
}

Fire the “FinishedEvent” in your callback function when you want the gamemode to end. Handle the event in your main script.

I am not too sure by what you mean. Where do I put this function? At the end of modulescript or at the end of the gamemode?

I’d assume your gamemode module looks something like this:

local function gamemode()
    -- do gamemode stuff
end

return gamemode

And I’d assume your server script to randomly pick out one of the gamemode modules and calls the returned function. In the current setup there is no way to know when the gamemode is over.
I can think of two solutions on the top of my head:

Solution 1:
Make the gamemode module return a gamemode and a bindable. Fire the bindable when the gamemode ends in the gamemode function itself.

local finishedBindable = Instance.new("BindableEvent")

local function gamemode()
    -- do gamemode stuff
    -- when gamemode ends,
    finishedBindable:Fire()
end

return {Callback = gamemode, Finished = finishedBindable.Event}

and on the server script, you can achieve an infinite loop of random gamemode selection like so:

while true do
    local randomModule = getRandomModule()
    randomModule.Callback()
    randomModule.Finished:Wait()
end

Solution 2:
You can directly make the function return the bindable so you can directly deal with the module in one line:

local finishedEvent = randomModule()
finishedEvent:Wait()
2 Likes

Solution 1…I am still trying to understand.

This is my attempt or at least what I understand from Solution 2. No, it doesnt work.
If it helps I can provide you one of the game-mode module scripts.

function StartRound1(SelectGamemode)
	
	if Playercount >= 1 then 
		task.wait()
		local GM = script.GameModes:GetChildren()
		local SelectGamemode = GM[math.random(1, #GM)]
		print(SelectGamemode)
		local SG = require(SelectGamemode)
		
		local FinishedEvent = SelectGamemode()
		FinishedEvent:Wait()
	else
		task.wait(5)
		print("StartRound1Loading")
		StartRound1()
	end
end

StartRound1()

local FinishedEvent = StartRound1()
FinishedEvent:Wait()

function StartRound2()
	print("StartRound2")
	
end
StartRound2()

I don’t quite understand what you’re trying to achieve in the script there. Are you trying to wait in the chosen gamemode itself?
The reason for it to not work: I think you didn’t create a BindableEvent and return it from the gamemode function.

I do apologies if my script seems rather hard to understand, nonetheless I will try my best to break it down.

This StartRound function will run if there are at least 1 player in my game. The function will then retrieve my GameModes folder in ServerReplicatedStorage, the SelectGamemode variable will then randomly pick 1 of the ModuleScripts in my GameModes folder. The SG variable will then require() the chosen gamemode. The code after else basically runs the StartRound1 function again if there are less than 1 players.

For this I really do not understand how to properly use it. I will provide you one of the ModuleScripts that contains the gamemode function. I would really appreciate it if you can point out if there are any flaws or redundancy in my script.

Module Script

---------------------Termination Gamemode--------------------

local module = {}

local GUIT = game:GetService("ReplicatedStorage")["GUI Trigger"]


function ChooseEmployee(ChosenEmployee)
	
	
	local NOP = game:GetService("Players"):GetChildren()
	print(NOP)
	
	if #NOP >= 1 then do 
			local ChosenEmployee = NOP[math.random(1, #NOP)]
			
			local Announcement = "The Company has deemed the selected Employee as irrelevant.\nPlease terminate them."
			GUIT:FireAllClients(Announcement)
			print(ChosenEmployee)
			
			local TSE = Instance.new("StringValue")
			TSE.Name = "Terminate"
			TSE.Parent = ChosenEmployee
			
			local CEName = ChosenEmployee.Name							----- Player Name
			local CEChar = game.Workspace:FindFirstChild(CEName)		----- Player's Character
			local CEHighlight = Instance.new("Highlight")				----- Character Highli8ght
			CEHighlight.DepthMode = "Occluded"
			CEHighlight.FillTransparency = 1
			CEHighlight.OutlineColor = Color3.new(255, 0, 0)
			CEHighlight.OutlineTransparency = 0
			
			CEHighlight.Parent = CEChar
			
			local ETDebounce = false	
			
			
			local function EmployeeTerminated()
				
				while true do
					if ETDebounce == false and CEChar:WaitForChild("Humanoid").Health == 0 then
						task.wait()
						ChosenEmployee.Terminate:Destroy()	
						ETDebounce = true
						
						local Announcement = "Your cooperation has been noted."
						GUIT:FireAllClients(Announcement)
						
						print("Employee Successfully Terminated")
						
						
						
						
						
					else 
						task.wait()
						EmployeeTerminated()
					end
				end
			end
			
			
			if ETDebounce == false then
				EmployeeTerminated()
			end
		end
	else 
		task.wait(5)
		print("ChosenEmployeeWaiting")
		ChosenEmployee(ChosenEmployee)
	end
end



ChooseEmployee()


return module

Okay so as far as I understand, you are checking for 2 players to exist in the server and then start selection of random gamemodes.
Your main script can be something like:

local playersService = game:GetService("Players")

local gamemodes = pathToFolder:GetChildren()

local function selectRound()
	while true do
		local currentGamemode = gamemodes[math.random(#gamemodes)] -- choose random gamemode module
		local finished = require(currentGamemode)() -- require module and call module function
		finished:Wait() -- wait for event to be fired
	end
end

local roundThread -- save thread

-- begin round loop if 2 player eligibility criteria is met
playersService.PlayerAdded:Connect(function()
	if not roundThread and #playersService:GetPlayers() >= 2 then
		roundThread = task.spawn(selectRound)
	end
end)

-- if 2 player eligibility criteria is no longer met, stop round loop
playersService.PlayerRemoving:Connect(function()
	if roundThread and #playersService:GetPlayers() < 2 then
		task.cancel(roundThread)
		roundThread = nil
	end
end)

And your gamemode ModuleScript:

local finishedBindable = Instance.new("BindableEvent")

local function gamemode()
	-- do gamemode stuff
	
	-- if you want to terminate this gamemode (finish it), call
	finishedBindable:Fire()
	
	return finishedBindable.Event
end

return gamemode
2 Likes

Since module scripts can yield scripts, for example
The module script:

task.wait(5)

return 0

The server script

require(ModuleScript) -- this will wait 5 seconds
print("Waited 5 seconds!")

You can technically do

function StartRound1()
	if Playercount >= 1 then 
		task.wait()
		local GM = script.GameModes:GetChildren()
		local SelectGamemode = GM[math.random(1, #GM)]
		print(SelectGamemode)
		local SG = require(SelectGamemode)
		StartRound2()
	else
		task.wait(5)
		print("StartRound1Loading")
		StartRound1()
	end
end

StartRound1()

function StartRound2(Round2)
 -- round 2 code
	
end	

Tho I may be wrong because I have not read your code all the way trough.

I am testing it now but what do you mean by this line?
I understand that Finished requires the selected GameMode script but what is the other ()?

Currently there are no errors.

Since the modulescript returns a dictionary and the key “Callback” holds a function, you need to call the function.

1 Like

My apologies for the late reply. I am still trying to understand what you have taught me to write in my script.

I realized that I might not need thess lines to run the script, but I can instead op in for a loop that continuously chooses a new random module script.

-- begin round loop if 2 player eligibility criteria is met
playersService.PlayerAdded:Connect(function()
	if not roundThread and #playersService:GetPlayers() >= 2 then
		roundThread = task.spawn(selectRound)
	end
end)

-- if 2 player eligibility criteria is no longer met, stop round loop
playersService.PlayerRemoving:Connect(function()
	if roundThread and #playersService:GetPlayers() < 2 then
		task.cancel(roundThread)
		roundThread = nil
	end
end)

I still have some questions that require some further explanations.

  1. What does local finishedBindable = Instance.new("BindableEvent") and finishedBindable:Fire() return finishedBindable.Event do exactly. How does the script communication in this scenario work?

  2. I am still faced with the confusion of what I should put in between the parentheses of require(currentGamemode)(-------what do I put here------)

  3. Why do I need to put return Termination() instead of return Module at the end of the module script. I do not understand to where am I returning the function to.

I intend on replacing this line with a loop function that will wait until the module script is finish, then it will run the loop of choosing another gamemode function. Currently I have no clue on how I should approach this idea of mine, but I believe I must understand what BindableEvent is before knowing what to do next; which brings me back to the 1st question I am asking above.

local roundThread -- save thread



if #Players:GetPlayers() >= 1 then
	task.wait(1)
	roundThread = task.spawn(selectRound)	
end

My Server Script currently:

--------------------------GameModes-----------------------------

wait(15)  ---- Wait time to allow players to load first

local gamemodes = game:GetService("ServerScriptService").MainScript.GameModes:GetChildren()

local function selectRound()
	while true do
		local currentGamemode = gamemodes[math.random(#gamemodes)] -- choose random gamemode module
		local finished = require(currentGamemode)() -- require module and call module function
		finished:Wait() -- wait for event to be fired
	end
end

local roundThread -- save thread



if #Players:GetPlayers() >= 1 then
	task.wait(1)
	roundThread = task.spawn(selectRound)	
end

Module Script: *I copy pasted to test the functionality of the script, currently the module script itself works, but I am unsure if the things you suggested are functioning as intended as the questions I asked above are hindering my understanding.


---------------------Termination Gamemode--------------------

local module = {}

local finishedBindable = Instance.new("BindableEvent")
local GUIT = game:GetService("ReplicatedStorage")["GUI Trigger"]


local function Termination()
	
	local NOP = game:GetService("Players"):GetChildren()
	print(NOP)

	if #NOP >= 1 then do 
			local ChosenEmployee = NOP[math.random(1, #NOP)]

			local Announcement = "The Company has deemed the selected Employee as irrelevant.\nPlease terminate them."
			GUIT:FireAllClients(Announcement)
			print(ChosenEmployee)

			local TSE = Instance.new("StringValue")
			TSE.Name = "Terminate"
			TSE.Parent = ChosenEmployee

			local CEName = ChosenEmployee.Name							----- Player Name
			local CEChar = game.Workspace:FindFirstChild(CEName)		----- Player's Character
			local CEHighlight = Instance.new("Highlight")				----- Character Highli8ght
			CEHighlight.DepthMode = "Occluded"
			CEHighlight.FillTransparency = 1
			CEHighlight.OutlineColor = Color3.new(255, 0, 0)
			CEHighlight.OutlineTransparency = 0

			CEHighlight.Parent = CEChar

			local ETDebounce = false	


			local function EmployeeTerminated()

				while true do
					if ETDebounce == false and CEChar:WaitForChild("Humanoid").Health == 0 then
						task.wait()
						ChosenEmployee.Terminate:Destroy()	
						ETDebounce = true

						local Announcement = "Your cooperation has been noted."
						GUIT:FireAllClients(Announcement)

						print("Employee Successfully Terminated")





					else 
						task.wait()
						EmployeeTerminated()
					end
				end
			end


			if ETDebounce == false then
				EmployeeTerminated()
			end
		end
	else 
		task.wait(5)
		print("ChosenEmployeeWaiting")
		Termination()
	end
	
	finishedBindable:Fire()
	return finishedBindable.Event
end

return Termination()