Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local ReplicatedStorage = game:GetService("ReplicatedStorage")
- local Players = game:GetService("Players")
- local AllQuestData = require(ReplicatedStorage:WaitForChild("ObjectiveData"))
- local eventsFolder = ReplicatedStorage:FindFirstChild("ObjectiveEvents") or Instance.new("Folder")
- eventsFolder.Name = "ObjectiveEvents"
- eventsFolder.Parent = ReplicatedStorage
- local function ensureEvent(name)
- local event = eventsFolder:FindFirstChild(name) or Instance.new("RemoteEvent")
- event.Name = name
- event.Parent = eventsFolder
- return event
- end
- local updateEvent = ensureEvent("UpdateObjective")
- local initEvent = ensureEvent("InitObjectives")
- local questStartEvent = ensureEvent("QuestStarted")
- local questCompleteEvent = ensureEvent("QuestCompleted")
- local playerData = {}
- local globalProgress = {}
- for _, quest in ipairs(AllQuestData) do
- globalProgress[quest.QuestName] = {}
- for _, obj in ipairs(quest.Objectives) do
- if obj.Type == "Global" then
- globalProgress[quest.QuestName][obj.Name] = false
- end
- end
- end
- local function hasTool(player, required)
- if not required then return true end
- local backpack = player:FindFirstChildOfClass("Backpack")
- local character = player.Character
- if not backpack or not character then return false end
- return (backpack:FindFirstChild(required) or character:FindFirstChild(required)) ~= nil
- end
- local function isQuestComplete(player, questName)
- local data = playerData[player.UserId]
- if not data or not data.Quests[questName] then return false end
- for _, completed in pairs(data.Quests[questName].Completed) do
- if not completed then return false end
- end
- return true
- end
- local function startQuestline(player, questName)
- local data = playerData[player.UserId]
- if not data then return end
- if data.Quests[questName] and data.Quests[questName].Started then
- initEvent:FireClient(player, questName, data.Quests[questName].Completed)
- return
- end
- local quest
- for _, q in ipairs(AllQuestData) do
- if q.QuestName == questName then
- quest = q
- break
- end
- end
- if not quest then
- warn("Questline not found:", questName)
- return
- end
- data.Quests[questName] = { Started = true, Completed = {} }
- for _, obj in ipairs(quest.Objectives) do
- data.Quests[questName].Completed[obj.Name] = globalProgress[quest.QuestName][obj.Name] or false
- end
- initEvent:FireClient(player, questName, data.Quests[questName].Completed)
- questStartEvent:FireClient(player, questName)
- end
- local function startNextObjective(player, quest, currentObj)
- local nextName = currentObj.NextObjective
- if not nextName then return end
- local data = playerData[player.UserId]
- if not data or not data.Quests[quest.QuestName] then return end
- if data.Quests[quest.QuestName].Completed[nextName] ~= nil then
- data.Quests[quest.QuestName].Completed[nextName] = false
- updateEvent:FireClient(player, quest.QuestName, nextName, false)
- end
- end
- local function completeObjective(player, quest, obj)
- local questName, objName = quest.QuestName, obj.Name
- local data = playerData[player.UserId]
- if not data or not data.Quests[questName] then return end
- if data.Quests[questName].Completed[objName] then return end
- if obj.Type == "Global" then
- if not globalProgress[questName][objName] then
- globalProgress[questName][objName] = true
- end
- data.Quests[questName].Completed[objName] = true
- for _, plr in ipairs(Players:GetPlayers()) do
- local pdata = playerData[plr.UserId]
- if pdata and pdata.Quests[questName] and pdata.Quests[questName].Started then
- if not pdata.Quests[questName].Completed[objName] then
- pdata.Quests[questName].Completed[objName] = true
- updateEvent:FireClient(plr, questName, objName, true)
- end
- end
- end
- else
- data.Quests[questName].Completed[objName] = true
- updateEvent:FireClient(player, questName, objName, true)
- end
- if isQuestComplete(player, questName) then
- questCompleteEvent:FireClient(player, questName)
- end
- if obj.NextQuestline then
- task.wait(1)
- startQuestline(player, obj.NextQuestline)
- elseif obj.EndQuest then
- questCompleteEvent:FireClient(player, questName)
- else
- startNextObjective(player, quest, obj)
- end
- end
- for _, quest in ipairs(AllQuestData) do
- for _, obj in ipairs(quest.Objectives) do
- local trigger = obj.Trigger
- if not trigger then continue end
- if trigger:IsA("ProximityPrompt") then
- trigger.Triggered:Connect(function(player)
- if hasTool(player, obj.Requires) then
- completeObjective(player, quest, obj)
- end
- end)
- elseif trigger:IsA("BasePart") then
- trigger.Touched:Connect(function(hit)
- local player = Players:GetPlayerFromCharacter(hit.Parent)
- if player and hasTool(player, obj.Requires) then
- completeObjective(player, quest, obj)
- end
- end)
- elseif obj.TriggerType == "CanCollideChange" then
- trigger:GetPropertyChangedSignal("CanCollide"):Connect(function()
- if trigger.CanCollide then
- for _, plr in ipairs(Players:GetPlayers()) do
- local pdata = playerData[plr.UserId]
- if pdata and pdata.Quests[quest.QuestName] and pdata.Quests[quest.QuestName].Started then
- completeObjective(plr, quest, obj)
- end
- end
- end
- end)
- elseif obj.TriggerType == "ColorChange" and obj.ColorTarget then
- trigger:GetPropertyChangedSignal("Color"):Connect(function()
- if trigger.Color == obj.ColorTarget then
- for _, plr in ipairs(Players:GetPlayers()) do
- local pdata = playerData[plr.UserId]
- if pdata and pdata.Quests[quest.QuestName] and pdata.Quests[quest.QuestName].Started then
- completeObjective(plr, quest, obj)
- end
- end
- end
- end)
- else
- warn("Unsupported trigger type for", obj.Name)
- end
- end
- end
- for _, quest in ipairs(AllQuestData) do
- if quest.StartTrigger then
- local start = quest.StartTrigger
- local function startQuest(player)
- startQuestline(player, quest.QuestName)
- end
- if start:IsA("BasePart") then
- start.Touched:Connect(function(hit)
- local player = Players:GetPlayerFromCharacter(hit.Parent)
- if player then startQuest(player) end
- end)
- elseif start:IsA("ProximityPrompt") then
- start.Triggered:Connect(startQuest)
- else
- warn("Invalid StartTrigger type for quest:", quest.QuestName)
- end
- end
- end
- Players.PlayerAdded:Connect(function(player)
- playerData[player.UserId] = playerData[player.UserId] or { Quests = {} }
- player.CharacterAdded:Connect(function()
- task.wait(1)
- local data = playerData[player.UserId]
- if not data then return end
- for questName, questInfo in pairs(data.Quests) do
- if questInfo.Started then
- for objName, _ in pairs(questInfo.Completed) do
- if globalProgress[questName] and globalProgress[questName][objName] then
- questInfo.Completed[objName] = true
- end
- end
- initEvent:FireClient(player, questName, questInfo.Completed)
- end
- end
- end)
- end)
- Players.PlayerRemoving:Connect(function(player)
- playerData[player.UserId] = nil
- end)
Advertisement
Add Comment
Please, Sign In to add comment