Skip to content

i3Crk/DialogService

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

DialogService

A lightweight, stage-based NPC dialog system for Roblox, written in Luau. Handles dialog flow, player state, and client/server callbacks — your front-end UI is fully decoupled and implemented by you.

Licensed under the MIT License.


Features

  • Stage-based dialog — supports FirstTime, NotFirstTime, Completed, and Locked stages out of the box, with support for custom stages
  • Conditional access — lock dialog stages behind arbitrary conditions (level requirements, quest progress, whitelists, etc.)
  • Client & server callbacks — fire logic on either context when a dialog is completed or cancelled
  • Decoupled front-end — the service manages state and flow; you implement your own UI
  • Dual-context safe — modules load correctly whether required from a Script or LocalScript

Folder Structure (Default)

Set up the following hierarchy in your Roblox place:

ReplicatedStorage
└── Dialog                  ← ModuleScript (the aggregator)
    ├── Util                ← ModuleScript (DialogUtil)
    └── DialogTemplate      ← ModuleScript (one per NPC)

ReplicatedStorage
└── Remotes
    └── Events
        └── Dialog          ← RemoteEvent

ServerScriptService
└── Services                ← Folder

Note: The paths to DialogRemote and Dialog at the top of DialogService are configurable. Change them to match your project's structure before use.


Installation

  1. Copy the modules into your place following the folder structure above.
  2. Create the RemoteEvent at ReplicatedStorage.Remotes.Events.Dialog (or update the path in DialogService to match your existing remote structure).
  3. Require DialogService from a server Script where you handle NPC interactions:
    local DialogService = require(path.to.DialogService)
  4. Require the Dialog aggregator is handled automatically inside DialogService — no additional setup needed.

Creating an NPC Dialog

Each NPC gets its own ModuleScript inside the Dialog folder, based on the DialogObject template.

Usage Example | One-Shot NPC Dialog (Shop)

For NPCs that always say the same thing regardless of player progress, use only the Completed stage:

return {
    DisplayName = "Shopkeeper",
    ["Completed"] = {
        ["Welcome to my shop!"] = {"Browse", "Leave"}
    },
    ["CompletedDialog"] = {
        ["Completed"] = {
            Client = function()
                --open shop UI
            end,
            Server = function(Player: Player)
                --open shop UI, though I think you'd use the client callback for this and omit the server callback entirely.
            end
        }
    }
}

Multi-Stage Example — Quest NPC

For NPCs tied to quest or story progression, use FirstTime, NotFirstTime, and Completed:

return {
    DisplayName = "Guard",
    ["FirstTime"] = {
        ["I have a job for you."] = {"Tell me more.", "Not now."},
        ["Come back when you're ready."] = {"Will do.", "Goodbye."}
    },
    ["NotFirstTime"] = {
        ["Have you finished the task?"] = {"Not yet.", "Goodbye."}
    },
    ["Completed"] = {
        ["Well done. You've proven yourself."] = {"Thanks.", "Goodbye."}
    },
    ["CompletedDialog"] = {
        ["FirstTime"] = {
            Server = function(Player)
                --assign quest to player
            end
        },
        ["Completed"] = {
            Server = function(Player)
                --award quest rewards
            end
        }
    },
    ["CancelledDialog"] = {
        ["FirstTime"] = {
            Client = function()
                --player left early, clean up if needed
            end
        }
    }
}

Locked Stage Example

Use Locked to conditionally gate a dialog behind any requirement. The Condition function receives the Player and must return a boolean — true to allow access, false to show the locked dialog instead:

["Locked"] = {
    Condition = function(Player: Player)
        --example: require level 10
        return Player:GetAttribute("Level") >= 10
    end,
    ["You're not strong enough yet."] = {"I'll be back.", "Goodbye."}
},

The Locked stage is checked before other stages. If Condition returns false, the locked dialog plays regardless of the player's current stage.


Stage Reference

Stage Intended Use
FirstTime Player has never interacted with this NPC / started this quest
NotFirstTime Player has interacted before but not completed
Completed Player has completed the associated quest or interaction
Locked Player does not meet the condition to interact

You can define custom stages beyond these four, but you will need to implement your own logic for determining when to use them.


Starting a Dialog (Server)

Create a handler with DialogService.new(), then call :Start() with the appropriate stage:

local DialogService = require(path.to.DialogService)

-- When a player interacts with an NPC:
local handler = DialogService.new(Player, "NPCName")
handler:Start("FirstTime")

If Stage is omitted, it defaults to "Completed".


Listening for Dialog Completion (Server)

Use :Listen() to subscribe to the result of a dialog. The callback receives the DialogState ("Completed" or "Cancelled") and an optional RunServerContext boolean:

handler:Listen(function(State, RunServerContext)
    if State == "Completed" then
        print("Player completed the dialog.")
    elseif State == "Cancelled" then
        print("Player left early.")
    end
end)

Ending a Dialog (Server)

Method Behavior
handler:Cancel() Ends the dialog early and removes the listener
handler:Destroy() Same as Cancel, and clears the handler reference

Front-End Integration (Client)

DialogService fires a RemoteEvent to the client to signal dialog start and cancellation. Your client-side UI script should listen to this remote and handle rendering:

-- LocalScript (your UI handler)
local DialogRemote = ReplicatedStorage.Remotes.Events.Dialog

DialogRemote.OnClientEvent:Connect(function(DialogName, Action, Stage)
    if Action == "Start" then
        --Fetch dialog data and render your UI
        --DialogName: which NPC's dialog to show
        --Stage: which stage to display ("FirstTime", "Completed", etc.)
    elseif Action == "Cancel" then
        -- Hide your dialog UI
    end
end)

When the player selects a response in your UI, fire the remote back to the server with the result:

--signal completion
DialogRemote:FireServer("Completed", true)  --true = run server callback

--signal cancellation
DialogRemote:FireServer("Cancelled", false)

DialogUtil

DialogUtil is a client-only utility module intended for helper functions shared across dialog objects — for example, functions that open specific UI frames. It is empty by default. Add your own functions as needed:

-- In DialogUtil:
function Util.OpenShopUI()
    --your UI logic
end

-- In a DialogObject's Client callback:
local Util = require(ReplicatedStorage.Dialog.Util)
Util.OpenShopUI()

DialogUtil returns an empty table on the server to prevent errors when dialog objects are required in a server context.


Type Reference

Defined in DialogsContainer:

Type Description
DialogState "Completed" or "Cancelled"
DialogStage "FirstTime", "NotFirstTime", "Completed", or "Locked"
DialogPoint { [string]: {string} } — NPC line mapped to response options
CompletionCallback { Client: () -> ()?, Server: (Player) -> ()? }
CompletionHandler { [DialogStage]: CompletionCallback }
DialogBase Full type for a dialog object module

Notes

  • One handler per player — creating multiple handlers for the same player without destroying the previous one will overwrite the subscribed listener.
  • AttributesDialogService uses Player:SetAttribute("CurrentDialog") and Player:SetAttribute("DialogStage") to track state. Avoid using these attribute names for other purposes.
  • Custom stages — fully supported in the data structure, but routing logic (when to call Start() with a custom stage) is your responsibility on the server.

About

A service to aid Roblox developers in standardizing dialog handlers for their games' NPC interactions.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages