Skip to content

Dialog Text

Borys Stelmakh edited this page Jun 15, 2026 · 1 revision

Dialog Text

Give a runtime NPC its own spoken line in Sacred's native talk window — the real dialog box with the portrait and the OK button, not an overlay.

Verified on Sacred Gold Steam, build 2.0.2.28 (2006-10-13).

The problem it solves

When you spawn an NPC at runtime it reuses a vanilla creature type, and that type already belongs to a vanilla quest. When the player talks to your NPC, Sacred plays that quest's dialog line. So your "Captain Miles" greets the hero with the stock "I hope that you will be able to track down the murderer. Good luck."

The talk window resolves its text by name: it takes the vanilla dialog node name (e.g. DQ_15024_OFFEN), hashes it, and looks the string up in global.res. SacredSDK intercepts that lookup and substitutes your baked text for the vanilla node — so the engine renders your line through its own dialog box.

Usage

Two steps: bake your text, then point a vanilla node at it.

-- 1. Bake the line into global.res under a name of your choosing.
require("text").named("CAPMILES_GREET",
  "Amon-Shi, I don't mean to interrupt your well-deserved rest, but in light "
  .. "of current events, relaxing at your watermill is... well, never mind.\n\n"
  .. "We're from Rocheford. Ready to go?")

-- 2. When the NPC speaks, give say() the vanilla node it should replace.
cap:say("CAPMILES_GREET", "DQ_15024_OFFEN")

Npc:say(text_key, vanilla_node):

  • text_key — the name you baked the line under with require("text").named(...).
  • vanilla_node — the vanilla dialog node this NPC plays in the talk window (see Finding the node below). Omit it to leave the vanilla line untouched.

Multi-paragraph text works — use \n\n between paragraphs. Stick to ASCII punctuation (', ...) for the safest glyph coverage in the game font.

Finding the node for your NPC

You don't have to guess. Talk to your NPC once with the SDK running and watch sdk/logs/sdk_loaded.log — it prints a copy-paste hint:

[dlgname] vanilla node "DQ_15024_OFFEN" (hash 06048666) — to override:
          o:say("YOUR_TEXT_KEY", "DQ_15024_OFFEN")

Copy the node name into your say() call. The full catalogue of vanilla nodes (599 of them, grouped by quest) is on the Dialog Nodes page.

Naming convention: <DQ|HQ|NQ>_<questId>_<STATE> — DQ village/side, HQ main, NQ other. Common STATE: OFFEN (given / greeting), START, ZIEL (goal), SIEG (won). Different quest states are different nodes, so an NPC that says different things at different points has one node per state — override each with its own say().

Npc:say warns in the log if the node isn't in the catalogue (typo guard).

Direct API

say() is sugar over one binding you can also call directly:

sacred.dialog_override(vanilla_node, our_text_key)
-- e.g. sacred.dialog_override("DQ_15024_ZIEL", "ROCHEFORD_GREET")

It registers a name→name substitution applied inside Sacred's dialog resolver.

Scope & conflicts

  • The override fires only inside the dialog-walker code path — it does not affect the quest journal, tooltips, or any other UI; only the talk window.
  • It is global by node name: every resolution of that vanilla node returns your text. For a total-conversion mod (your NPC is the replacement for that quest) there is no conflict. If a partial mod leaves the original vanilla quest reachable elsewhere, that instance would show your text too — pick a node from a quest you're fully replacing.

How it works (one line)

The talk window calls FUN_00672cf0(name) → sacred_hash(name) → FUN_0080eaf0/FUN_0080f5e0(hash) to fetch the string. dialog_override maps the vanilla node's hash to your baked text's hash at that final resolver, so the window renders your line natively. See Reverse Engineering for the deeper trace.

Clone this wiki locally