-- src/ServerScriptService/QuestManager.server.lua local Players = game:GetService("Players") local ReplicatedStorage = game:GetService("ReplicatedStorage") local QuestConfig = require(ReplicatedStorage:WaitForChild("Shared"):WaitForChild("QuestConfig")) local QuestUpdateEvent = ReplicatedStorage:WaitForChild("Events"):WaitForChild("QuestUpdateEvent") local NotificationEvent = ReplicatedStorage:WaitForChild("Events"):WaitForChild("NotificationEvent") -- Player quest state: [userId] = { [questId] = { progress, completed } } local playerQuests = {} local function initPlayerQuests(player) playerQuests[player.UserId] = {} -- Assign starter quests for _, questId in ipairs(QuestConfig.StarterQuests) do playerQuests[player.UserId][questId] = { progress = 0, completed = false, } end -- Send initial quest data to client task.delay(4, function() if player.Parent then QuestUpdateEvent:FireClient(player, "Init", playerQuests[player.UserId]) end end) end local function isQuestActive(player, questId) local quests = playerQuests[player.UserId] if not quests then return false end local quest = quests[questId] if not quest then return false end return not quest.completed end local function progressQuest(player, questType, amount) local quests = playerQuests[player.UserId] if not quests then return end for questId, questState in pairs(quests) do if questState.completed then continue end local questDef = QuestConfig.Quests[questId] if not questDef then continue end if questDef.Type == questType then questState.progress = questState.progress + amount if questState.progress >= questDef.Target then questState.progress = questDef.Target questState.completed = true -- Grant rewards if questDef.Reward.Cash then local leaderstats = player:FindFirstChild("leaderstats") if leaderstats then local cash = leaderstats:FindFirstChild("Cash") if cash then cash.Value = cash.Value + questDef.Reward.Cash end end end NotificationEvent:FireClient(player, "Quest Complete", questDef.Title .. " completed! +" .. tostring(questDef.Reward.Cash or 0) .. " Cash") -- Unlock follow-up quests unlockNextQuests(player, questId) end -- Update client QuestUpdateEvent:FireClient(player, "Update", { questId = questId, progress = questState.progress, target = questDef.Target, completed = questState.completed, }) end end end function unlockNextQuests(player, completedQuestId) -- Simple linear progression: unlock quests based on what was completed local unlockMap = { ChopFirstTree = {"Chop10Trees"}, Chop10Trees = {"Chop50Trees"}, Chop50Trees = {"Chop200Trees"}, SellFirstWood = {"Earn5000"}, Earn5000 = {"Earn50000"}, BuildFirstStructure = {"Build10Structures"}, BuyFirstItem = {"ProcessFirstPlank"}, ProcessFirstPlank = {"ExploreAllBiomes"}, } local nextQuests = unlockMap[completedQuestId] if nextQuests then for _, nextId in ipairs(nextQuests) do if not playerQuests[player.UserId][nextId] then playerQuests[player.UserId][nextId] = { progress = 0, completed = false, } local questDef = QuestConfig.Quests[nextId] if questDef then NotificationEvent:FireClient(player, "New Quest", "New quest unlocked: " .. questDef.Title) end end end end end -- Expose globally for other managers to trigger quest progress _G.ProgressQuest = function(player, questType, amount) progressQuest(player, questType, amount or 1) end _G.GetPlayerQuests = function(player) return playerQuests[player.UserId] end Players.PlayerAdded:Connect(initPlayerQuests) Players.PlayerRemoving:Connect(function(player) playerQuests[player.UserId] = nil end) -- Handle players already in game for _, player in ipairs(Players:GetPlayers()) do task.spawn(function() initPlayerQuests(player) end) end