NPC Quest Profiles
NPC Quest Profiles connect Citizens (NPCs) to quests. Each profile defines which quests an NPC offers, what dialog they show in different phases, and how they behave when a player is nearby. Profiles are JSON files stored in the quest_npc_profiles/ folder.
Overview
When a player interacts with an NPC that has a quest profile, the system determines which dialog to show based on a priority algorithm:
- Complete -- If the player has finished all objectives for a quest this NPC can turn in, show the completion dialog.
- Offer -- If the NPC has an available quest the player has not started or completed, show the offer dialog. If multiple quests are available, a selection page opens.
- Active -- If the player has an active quest from this NPC but has not finished yet, show the active/reminder dialog.
- Not Ready -- If quests exist but prerequisites are not met, show the "not ready" dialog.
- Default -- Fallback dialog when no quests are relevant.
Profile JSON Structure
Each profile is a single JSON file per NPC:
{
"citizenId": "smith_gorn",
"quests": [
{
"questId": "story_iron_forge",
"priority": 10,
"requires": ["tutorial_sustainability"],
"offer": { "speaker": "Gorn", "nodes": [/* ... */] },
"active": { "speaker": "Gorn", "lines": ["npc.smith_gorn.active.1"] },
"complete": { "speaker": "Gorn", "lines": ["..."], "action": "complete_quest" }
}
],
"proximityMessages": {
"offer": "npc.smith_gorn.proximity.offer",
"active": "npc.smith_gorn.proximity.active",
"complete": "npc.smith_gorn.proximity.complete",
"defaultMsg": "npc.smith_gorn.proximity.default"
},
"proximityRange": 20,
"proximityCooldown": 300,
"defaultDialog": { "speaker": "Gorn", "lines": ["npc.smith_gorn.default.1"] },
"notReadyDialog": { "speaker": "Gorn", "lines": ["npc.smith_gorn.not_ready.1"] }
}
Top-Level Fields
| Field | Required | Description |
|---|---|---|
citizenId | Yes | Must match the Citizen ID from the Citizens system |
_config_version | No | Schema version for auto-update detection (current: "2") |
quests | Yes | Array of quest dialog entries (at least one) |
defaultDialog | No | Fallback dialog when no quests are relevant |
notReadyDialog | No | Shown when quests exist but prerequisites are unmet |
proximityMessages | No | Chat whisper messages for proximity detection |
proximityRange | No | Detection range in blocks (default: 20) |
proximityCooldown | No | Seconds between proximity whispers (default: 300) |
Quest Dialog Entry
Each entry in the quests array ties a quest to this NPC with phase-specific dialogs:
| Field | Required | Description |
|---|---|---|
questId | Yes | Quest definition ID to link |
priority | No | Lower number = checked first (default: 10) |
requires | No | Array of quest IDs that must be completed first |
offer | No | Dialog shown when quest is available to accept |
active | No | Dialog shown while quest is in progress |
complete | No | Dialog shown when objectives are done and quest can be turned in |
Not every NPC needs all three phases. You can split quests across NPCs -- for example, NPC A has the offer phase while NPC B has the complete phase. This lets players pick up a quest from one NPC and turn it in at another.
Dialog Formats
Simple Format
Uses a flat list of text lines. For offer dialogs, add acceptButton/declineButton:
{
"speaker": "Gorn",
"lines": ["Would you like to help me forge some iron?"],
"acceptButton": "Sure!",
"declineButton": "Maybe later.",
"action": "start_quest"
}
Full Format (Nodes)
Uses a tree of dialog nodes for branching conversations. Node types: TEXT (shows lines, advances to next) and CHOICE (shows clickable options):
{
"speaker": "Gorn",
"nodes": [
{ "id": "greeting", "type": "TEXT", "lines": ["Welcome!"], "next": "accept" },
{
"id": "accept", "type": "CHOICE", "lines": ["Will you help me?"],
"choices": [
{ "text": "Of course!", "macro": "start_quest" },
{ "text": "Not now." }
]
}
]
}
Actions and Macros
| Action | Description |
|---|---|
start_quest | Starts the linked quest for the player |
complete_quest | Completes the linked quest and grants rewards |
In the full format, macros are set on individual nodes or choices via the "macro" field.
Dialog text values can be literal strings or localization keys (e.g., npc.smith_gorn.default.1). If a matching key exists in the localization files, the translated text is shown.
Multiple Quests Per NPC
A single NPC can offer multiple quests. The requires field controls ordering and priority determines check order. When two or more quests are available simultaneously, a Quest Selection Page opens letting the player choose.
Example of a sequential quest chain (quests unlock one after another):
{
"citizenId": "guide_finn",
"quests": [
{ "questId": "tutorial_awakening", "priority": 1, "requires": [] },
{ "questId": "tutorial_first_steps", "priority": 2, "requires": ["tutorial_awakening"] },
{ "questId": "tutorial_workbench", "priority": 3, "requires": ["tutorial_first_steps"] }
]
}
Proximity Detection
Chat Whispers
When a player enters the proximityRange, a colored chat whisper is sent based on the current quest phase. The message appears as [NPC Name] text in light blue. The NPC plays a wave animation when a quest is available. Placeholders {PlayerName} and {CitizenName} are replaced automatically. The cooldown prevents spam (default: 300 seconds per NPC per player).
Proximity Toast HUD
Nearby quest NPCs also appear in a Proximity Toast HUD showing the NPC's avatar, a quest indicator (! gold = available, ? green = turn-in ready), distance in blocks, and compass direction. Up to 5 NPCs display simultaneously and are removed when the player moves out of range.
Configure the toast in config.json:
{ "proximityToast": { "enabled": true, "toastRange": 20.0, "durationMs": 0 } }
Set durationMs to 0 for persistent display while in range, or a positive value for auto-hide.
World Map Markers
Quest NPCs automatically receive world map markers based on the player's quest status:
| Marker | Meaning |
|---|---|
quest_available | NPC has a quest the player can accept |
quest_turn_in | NPC can receive a completed quest |
quest_progress | Player has an active quest from this NPC |
Markers update automatically when a player accepts, completes, or abandons a quest. They are per-player, so different players see different markers on the same NPC.
File Location
Profile files are stored in configs/kyuubisoft_questbook/quest_npc_profiles/. Default profiles are extracted from the mod JAR on first startup. You can edit existing profiles or add new ones by creating additional JSON files in this folder.
The citizenId in the profile must match an existing Citizen in the Citizens system. If the Citizen does not exist, the profile is loaded but has no effect.