§ How to · with Forge AI

How to make a Roblox quest system (with AI)

By Sametcan Tasgiran, Founder & Developer·Published ·Updated

A Roblox quest system needs five pieces: NPC quest givers, objective tracking, progress saves, reward delivery, and a quest log UI. Forge AI generates all five in 1m 18s — including branching dialogue and step-by-step objective text.

9 files · 310 lines · 1m 18s · 1 credit. ProfileService-style save flow.

NPC quest givers

Tag any character model with CollectionService 'QuestGiver' and a QuestId attribute. The proximity prompt + dialogue UI is automatic.

Objective types

Kill X enemies, collect X items, reach X location, talk to X NPC. Mix-and-match per quest. Objectives complete in any order or sequentially (configurable).

Progress tracking

Server stores per-player quest state — active quests, completed objectives, completed quests. DataStore-backed with retry.

Branching objectives

Quest can have multiple choice paths (kill the dragon OR negotiate with it). Player choice locks the path; downstream quests reference the choice.

Reward delivery

Cash, items, XP, gamepass-style unlocks. Multiple rewards per quest. Delivered atomically on quest completion.

Quest log UI

Slide-out panel showing active quests, current objectives, completed quests. Tabbed by category (main, side, daily). Tap a quest to set it as the tracked quest on the HUD.

Files Forge AI ships for this prompt

9 files · 310 lines · 1m 18s · 1 credit

ServerScriptService/QuestManager.lua

Quest state, objective progress, reward delivery

96 lines

ServerScriptService/QuestSaveService.lua

Per-player quest state DataStore

42 lines

ReplicatedStorage/Modules/QuestConfig.lua

Quest definitions — objectives, rewards, prerequisites

78 lines

ReplicatedStorage/Remotes/QuestAccept

Player accepts quest from NPC

instance

ReplicatedStorage/Remotes/QuestUpdate

Server → client progress update

instance

ReplicatedStorage/Remotes/QuestTurnIn

Player turns in to NPC

instance

StarterGui/QuestLog.lua

Slide-out quest log panel

52 lines

StarterGui/QuestHUD.lua

Currently tracked quest objective overlay

24 lines

StarterGui/QuestPrompt.lua

NPC dialogue + accept/decline UI

28 lines

Sample output: ServerScriptService/QuestManager.lua

--!strict
-- ServerScriptService/QuestManager.lua  (Forge AI · excerpt)
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local QuestConfig = require(ReplicatedStorage.Modules.QuestConfig)
local SaveService = require(script.Parent.QuestSaveService)
local QuestUpdate = ReplicatedStorage:WaitForChild("Remotes"):WaitForChild("QuestUpdate")

type Quest = { id: string, active: { [string]: number }, completed: { [string]: boolean } }

local function getState(player: Player): Quest
    return SaveService:Get(player) or { id = "", active = {}, completed = {} }
end

local function notifyProgress(player: Player, questId: string, objectiveId: string, current: number)
    QuestUpdate:FireClient(player, { questId = questId, objective = objectiveId, current = current })
end

local QuestManager = {}

function QuestManager:reportEvent(player: Player, eventType: string, target: string?)
    -- eventType: "kill", "collect", "reach", "talk"
    local state = getState(player)
    for activeId, _ in pairs(state.active) do
        local def = QuestConfig[activeId]
        if not def then continue end
        for _, obj in ipairs(def.objectives) do
            if obj.type == eventType and (not obj.target or obj.target == target) then
                local key = activeId .. ":" .. obj.id
                state.active[key] = (state.active[key] or 0) + 1
                notifyProgress(player, activeId, obj.id, state.active[key])

                if state.active[key] >= obj.required then
                    -- Check if all objectives done → complete quest
                    QuestManager:tryComplete(player, activeId, def, state)
                end
            end
        end
    end
    SaveService:Set(player, state)
end

return QuestManager

Building a Roblox quest system

Quest systems are the backbone of RPG-style Roblox games. The defining property of a good quest system is that adding new quests does not require touching the engine — only adding data. Forge AI ships exactly that pattern.

The Forge AI quest prompt produces a 9-file system in 1m 18s. QuestConfig.lua is the data layer — adding a new quest is adding a table entry. QuestManager.lua is the engine layer — it reads QuestConfig and never needs to change. This separation is why production RPG games scale to hundreds of quests without becoming unmaintainable.

Objective tracking is event-driven. The Combat system calls QuestManager:reportEvent(player, 'kill', 'goblin') on every kill. QuestManager checks every active quest for objectives matching ('kill' + 'goblin') and increments their counters. The player gets a HUD popup ('3/10 goblins defeated'). Adding a new objective type is one method, not a refactor.

Branching paths are the design depth. A quest can have a 'choice' group — kill the dragon or negotiate with it. Completing either locks the others, the choice is recorded, and downstream quests can read the choice from state.completed. This enables player-driven story arcs without scripting each branch separately.

The quest log UI is the player-facing payoff. A slide-out panel shows active quests, current objective text, and completed quests. Tap any active quest to set it as the 'tracked quest' — its current objective shows in a HUD overlay. Players never lose track of what to do next, which is the single biggest retention factor in quest-driven games.

See more on the Luau generator, the game builder, or browse the full blog.

Frequently asked

How do I add a new quest?+

Add an entry to QuestConfig.lua: id, name, description, objectives table, rewards table. The QuestManager picks it up automatically — no code changes. Forge generates new quest entries on follow-up prompts.

Can quests have prerequisites (must complete Quest A before Quest B)?+

Yes. Each quest definition has a 'requires' field listing prerequisite quest IDs. QuestManager:canAccept() checks the player's completed quests before allowing acceptance.

How do branching quests work?+

An objective can have multiple sub-objectives marked with a 'choice' group. Completing any one locks the others. Downstream quests can check which path was taken via state.completed['questA:choiceB'].

How is progress saved?+

QuestSaveService writes the state table to DataStore on every objective progress event. To minimize writes, the actual save is debounced — the table updates in memory immediately, but DataStore writes happen at most every 30 seconds (or on PlayerRemoving).

Can I have repeatable daily quests?+

Yes. Daily quests reset every 24 hours via the server clock authority pattern. Forge integrates with the daily-rewards system if you have one already — the clock check is shared.

Related Forge AI prompts