I’m doing my first “storyline/tasks” system. I don’t know how to call it, but it would work like this:
- After players joined and someone pressed ready, everyone will be teleported to special spawns.
- At this point “storyline” starts, where you are given tasks to do (in order).
- Some tasks would be randomized, I mean picked from pool of random tasks.
- Trying to trigger next task before doing previous one won’t do anything.
Easiest way to explain it: Enter main area → Look at the desk → Pick up the keys → Leave the room
if keys not on the desk: Enter main area → Loot at the desk (no keys) → Look for the keys → Leave the room
THE PROBLEM IS I have no idea how to start with such system. Can’t wrap my head around this.
Was reading multiple articles about storyline and most of the talk about using Modules and RemoteEvents, which I’m already using…
So my question is: How do I create storyline system where certain actions and tasks player do will progress the game for everyone?
I already did some scripting, mainly using dicionaries and objects but it feels “wrong” in some way:
States dictionary
local TweenService = game:GetService('TweenService') local CollectionService = game:GetService('CollectionService') local EnterMainAreaPrompt = CollectionService:GetTagged("EnterMainAreaPrompt")[1] local StorageArea = CollectionService:GetTagged("StorageArea")[1] local States = { { Name = "EnterMainArea", Data = { Task = "Enter the door", Description = "Find out what wait for you...", Event = { Connect = EnterMainAreaPrompt.Triggered, To = "MainAreaEntered" }, Trigger = function(controller) print("Task:", controller.State.task, controller.State.Description) end, onEvent = function(controller, Player) local Door = workspace.Door local tweenInfo = TweenInfo.new(1, Enum.EasingStyle.Sine, Enum.EasingDirection.Out) local Tween = TweenService:Create(Door, tweenInfo, { Position = Vector3.new(Door.Position.X, Door.Position.Y + 7, Door.Position.Z) }) Tween:Play() controller:NextState() end }, }, { Name = "GoToStorageArea", Data = { Task = "Move to storage area", Description = "", Event = { Connect = StorageArea.Touched, To = "StorageAreaEntered" }, Trigger = function(controller) print("Task:", controller.State.task, controller.State.Description) end, onEvent = function(controller, Player) controller:NextState() end, }, }, } return States
MissionController
local CollectionService = game:GetService('CollectionService') local ReplicatedStorage = game:GetService('ReplicatedStorage') local Players = game:GetService('Players') local States = require(script.States) local ServerEvents = ReplicatedStorage.Events.Server local ClientEvents = ReplicatedStorage.Events.Client local StatesEvents = ReplicatedStorage.Events.States local Chairs = CollectionService:GetTagged("MissionSpawn") local MissionController = {} MissionController.State = nil MissionController.StateIndex = 1 MissionController._currentConnection = nil function MissionController:Init() ServerEvents.startMission.OnServerEvent:Connect(function(Player) ClientEvents.prepPlayers:FireAllClients() for i, player in ipairs(Players:GetPlayers()) do local HumanoidRootPart = player.Character:WaitForChild('HumanoidRootPart') HumanoidRootPart.CFrame = Chairs[i].Seat.CFrame print(Chairs) end self.StateIndex = 1 self:Start() end) return true end function MissionController:Start() self:ChangeState(States[self.StateIndex]) end function MissionController:ChangeState(state) self.State = state if self._currentConnection then self._currentConnection:Disconnect() end if state and state.Trigger then state.Trigger(self) end if state.Data and state.Data.Event and state.Data.Event.Connect then self._currentConnection = state.Data.Event.Connect:Connect(function(...) if state.Data.Event.To then local eventObj = StatesEvents:FindFirstChild(state.Data.Event.To) if eventObj then eventObj:FireAllClients() else warn("No event found for", state.event) end end if state.Data.onEvent then state.Data.onEvent(self, ...) end end) end end function MissionController:NextState() self.StateIndex += 1 if self.StateIndex <= #States then self:ChangeState(States[self.StateIndex]) else print("Mission finished!") end end return MissionController
[IMPORTANT NOTE]: return true in my controller means the :Init() was successful