How it works:
When a player activates a button they will be given a job and after a certain amount of time they will earn money. Then, when they end their shift or leave the job area the earned money will be added to their leaderstats.
I will make a second part on how to give the player task like in work at a pizza place or bloxburg, but for now this is just a simple job system.
This tutorial is recommended for intermediate coders but its explained thoroughly so I’m sure a beginner wouldn’t have much problem following along (but if you don’t feel free to comment questions)
Step 1: Set up
First, you will need a proximity prompt where you want the player to take the job. I would recommend putting it in a invisible part above something like a cash register then edit the properties how you feel it should be.
Next create a “floor” everywhere you want the player to be able to walk while in the job, and name it “JobArea”. We will make it so that when the player isn’t standing on the floor their shift will end so, make sure it covers where you need it to.
Now, create a script in server script service. Also create a remote in replicated storage
You will need to create a GUI that looks like this:
The “End Shift” is a button and should have a local script inside it.
This is what your workspace should look like:
Step 2: Scripting The Basics
First, in the server script, define services, module etc…
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Remote = ReplicatedStorage:WaitForChild("RemoteEvent")
local Zone = workspace:WaitForChild("JobArea")
local Prompt = workspace:WaitForChild("Prompt").ProximityPrompt
Make sure that the Zone and Prompt lead to where you put yours.
local Hired = false
local Coro = nil --will be explained later
local Wage = 10
local Earned = 0
local ShiftLength = 5 -- in seconds
These are just variables that will be used later. Wage and Shift Length can be changed but for testing you should keep them as they are.
Next, create these empty functions we will fill in later:
Prompt.Triggered:Connect(function(Player)
end)
RunService.Heartbeat:Connect(function()
end)
Remote.OnServerEvent:Connect(function(Player, Job)
end)
Players.PlayerAdded:Connect(function(Player)
end)
Players.PlayerRemoving:Connect(function(Player)
end)
Step 3: Functions
Step 3a: Handling Hiring and Paying
Now, we have to create the actual functions. Above the code you just wrote type this:
local function IsInJob(Position)
local pos = Zone.CFrame:PointToObjectSpace(Position)
return (math.abs(pos.X) <= Part.Size.X / 2)
and (math.abs(pos.Z) <= Part.Size.Z / 2)
and (pos.Y >= 0)
end
What this will do is compare the players position (not yet defined) with the position of the
JobArea (pos) we created earlier. Later we will use this to fire the player if they leave that area.
If you want the player to continuously earn money no matter where they are simple don’t include this function and remove any other lines that include it too. If you do include it you should add a pop up gui to alert the player that they must be standing on the zone or teleport them there.
Next, we will need to actually pay the player with this function:
local function PayPlayer(Player)
local JobGui = Player:WaitForChild("PlayerGui"):WaitForChild("JobGui")
if Hired then
Earned += Wage
JobGui.Frame.CashEarned.Text = "Cash Earned: " .. Earned
elseif Hired == false then
Earned = 0
JobGui.Frame.CashEarned.Text = "Cash Earned: " .. Earned
end
end
First, we define where our job gui is. Next, we check if the variable “Hired” is true or not. Then we add how much the player has earned to the wage. If you used different named for the variables make sure to change it. The next line edits the job guis text. The elseif is what happens when the player is fired; resetting how much they earned and their gui.
This is where is starts getting a little complicated at the functions start intertwining. The next function is what will actually hire the player:
local function HirePlayer(Player)
local HRP = (Player.Character ~= nil) and Player.Character:FindFirstChild("HumanoidRootPart")
if Hired == false and IsInJob(HRP.Position, Zone) then
Hired = true
This function will define the players Humanoid Root Part (will be used in the earlier function to test if they are in the job area), it will also check if the player is already hired or not. If the player meets all these conditions they will then finally be hired.
Continuing under the if-statement, type this:
Coro = coroutine.wrap(function()
while Hired == true do
task.wait(ShiftLength)
if Hired == true then
PayPlayer(Player)
end
end
coroutine.yield()
end)
Coro()
end
We will be using coroutines to continually pay the player during their shift. Coroutines are kinda hard to explain but to put it simply, it allows us to run the pay player function while also running all the other parts of the script. I would highly recommend reading the api reference for coroutines if you don’t understand.
Step 3b: Handling Firing/Quitting
Now to handle what will happen when the player wants to quit their job.
function FirePlayer(Player)
local JobGui = Player:WaitForChild("PlayerGui"):WaitForChild("JobGui")
local Cash = Player:WaitForChild("leaderstats").Cash -- Whatever your money is called
Cash.Value += Earned
Hired = false
PayPlayer(Player)
JobGui.Enabled = false
Prompt.Enabled = true
Coro()
end
This essentially pays the player how much they earned, removes the gui, and sets hired to false.
function UpdatePlayer(Player, HRP)
local JobGui = Player:WaitForChild("PlayerGui"):WaitForChild("JobGui")
if IsInJob(HRP.Position, Zone) then
JobGui.Enabled = true
Prompt.Enabled = false
elseif not IsInJob(HRP.Position, Zone) or not Hired then
FirePlayer(Player)
end
end
All this function does is check if the player leaves their job area then fires them.
Step 4: Finishing System
OK now we can finally go back to those functions we didn’t finish in Step 2.
In the “PromptButtonHoldEnded” function, simply put:
HirePlayer(Player)
In the “Heartbeat” function put:
for _, Player in ipairs(Players:GetPlayers()) do
if Hired == true then
local HRP = (Player.Character ~= nil) and Player.Character:FindFirstChild("HumanoidRootPart")
UpdatePlayer(Player, HRP)
end
end
This is a loop that will run on a heartbeat to check if the player leaves the job zone.
And for the last two:
Remote.OnServerEvent:Connect(function(Player, Job)
if Job == "Job" then
FirePlayer(Player)
end
end)
Players.PlayerAdded:Connect(function(Player)
local LS = Instance.new("Folder", Player)
LS.Name = "leaderstats"
local Cash = Instance.new("IntValue", LS)
Cash.Name = "Cash"
end)
Players.PlayerRemoving:Connect(function(Player)
FirePlayer(Player)
end)
Now, at this point you should be able to test the game. You wont be able to quit the job using the GUI yet but after standing in position and earning money you should see you points in your leader stat go up. It should work as you see in this video:
Step 5: Finishing up
We are basically done the only thing you need to do is put this code inside the “End Shift”
local Button = script.Parent
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Remote = RS:WaitForChild("RemoteEvent")
Button.Activated:Connect(function()
Remote:FireServer("Job")
end)
Another thing you should do is datastores. A datastore will save a players total amount of money so that when they rejoin the game it’ll all be there.
I’m not going to explain how to create a datastore in this tutorial but there are many good tutorials that will work I recommend AlvinBlox’s.
Congratulations! You have reached the end of tutorial! Have fun using this for your roleplaying games, simulators, etc… and if you have any issues please comment them!