Super Text Adventure

NPCs & Dialogue

NPCs are characters the player can talk to, give items to, and interact with. They support branching dialogue trees with gated topics and quest mechanics.

Schema

"npc_id": {
  "name": "Old Wizard",
  "description": "A wizened old man in flowing robes.",
  "keywords": ["wizard", "old man", "mage"],
  "dialogue": { /* dialogue system */ },
  "movement": { /* optional patrol/triggered movement */ },
  "accepts_item": "magic_gem",
  "gives_item": "spell_book",
  "accept_message": "The wizard takes the gem eagerly...",
  "sets_flag": "helped_wizard"
}

Base Fields

FieldTypeRequiredDescription
name string required Display name shown to the player.
description string required Text shown when the player examines the NPC.
keywords array optional Alternative names for fuzzy matching.
dialogue object optional The NPC's dialogue tree. See below.
movement object optional Patrol or trigger-based movement. See Movement.

Dialogue System

The dialogue object defines what the NPC says when talked to.

"dialogue": {
  "greeting": "Welcome, traveler! What brings you to these parts?",
  "default": "I don't know about that.",
  "sets_flag": "met_wizard",
  "topics": {
    /* topic definitions */
  }
}
FieldTypeDescription
greeting string Response when the player talks to the NPC without specifying a topic.
default string Fallback response when a topic isn't recognized. Used if greeting is not set.
sets_flag string Flag set when the player first greets this NPC.
topics object Named conversation topics the player can ask about.

Dialogue Topics

Topics allow branching conversations. Players trigger them with talk to wizard about quest.

"topics": {
  "quest": {
    "keywords": ["quest", "mission", "task"],
    "text": "I need you to retrieve the Crystal of Power from the dark cave.",
    "sets_flag": "quest_started",
    "leads_to": ["crystal", "cave"]
  },
  "crystal": {
    "keywords": ["crystal", "crystal of power"],
    "text": "The Crystal glows with ancient magic. Handle it carefully.",
    "requires_flag": "quest_started",
    "locked_text": "I have nothing to say about that yet."
  },
  "cave": {
    "keywords": ["cave", "dark cave"],
    "text": "The cave lies to the north. Beware the guardian.",
    "requires_item": "map",
    "locked_text": "Find a map first, then we can discuss the cave."
  }
}

Topic Fields

FieldTypeDescription
keywords array Words or phrases that trigger this topic. Case-insensitive.
text string The NPC's response when this topic is discussed.
sets_flag string Flag set when the player hears this topic.
requires_flag string Topic is locked until this flag is true.
requires_item string Topic is locked unless the player has this item.
locked_text string Message shown when the topic is locked.
leads_to array Topic IDs that become available after this topic is discussed.

Dialogue Flow

1. Player says talk to wizard → Shows greeting or default

2. Player says talk to wizard about quest → Engine matches "quest" against topic keywords

3. If the topic is gated by requires_flag or requires_item, checks those conditions

4. If locked, shows locked_text. If unlocked, shows text

5. If the topic has leads_to, those topics become accessible

6. If the topic has sets_flag, that flag is set to true

Topic gating with leads_to:

Topics listed in leads_to are unlocked only when the parent topic has been discussed. This creates natural conversation progression where the player must first ask about a general topic before specific follow-ups become available.

Quest Mechanics (Item Trading)

NPCs can accept items from the player and optionally give items in return. This is the core quest/trade mechanic.

"blacksmith": {
  "name": "Blacksmith",
  "description": "A burly smith working the forge.",
  "accepts_item": "iron_ore",
  "gives_item": "iron_sword",
  "accept_message": "The blacksmith takes the ore and hammers it into a fine blade. 'Here you go!'",
  "sets_flag": "sword_forged"
}
FieldTypeDescription
accepts_item string Item ID that this NPC will accept from the player.
gives_item string Item ID given to the player in return (optional).
accept_message string Custom message shown when the item is accepted.
sets_flag string Flag set when the NPC accepts the item.

Players give items with: give iron_ore to blacksmith

Movement

NPCs (and creatures) can move between rooms on their own. Movement ticks once per player action and fires depart_msg and arrive_msg when the entity enters or leaves the room the player is currently in.

There are two movement types: patrol for cyclic routes and triggered for one-shot moves tied to a game flag. The schema applies equally to entries in both npcs and creatures.

In combat:

A creature currently engaged in combat with the player will not move, even if its movement schedule says it should. Combat always wins.

Patrol Movement

Patrol movement cycles an entity through a list of rooms, each with a duration (in turns). When the duration is up, the entity moves to the next step. The schedule loops forever.

"movement": {
  "type": "patrol",
  "schedule": [
    { "room": "tavern_floor", "duration": 3 },
    { "room": "village_square", "duration": 3 }
  ],
  "depart_msg": "Bardric slings his lute over his shoulder and wanders off.",
  "arrive_msg": "Bardric strolls in, already mid-song."
}
FieldTypeDescription
type string Must be "patrol".
schedule array Ordered list of schedule steps. Each step has a room and duration. The entity cycles through them in order, looping back to the first once the last is complete.
depart_msg string Message shown when the entity leaves the player's current room. Defaults to "The [name] leaves."
arrive_msg string Message shown when the entity arrives in the player's current room. Defaults to "The [name] arrives."

Schedule Step Fields

FieldTypeDescription
room string Room ID where the entity sits for this step.
duration number Number of player turns the entity stays in this room before moving to the next step.
blocked_while_player_in array Optional list of room IDs. If the player is currently in any of them, the transition to this step is deferred until the player leaves. Use this to prevent an NPC from awkwardly walking into the player's face.

Triggered Movement

Triggered movement is a one-shot: the entity moves to a destination room the first time a given flag is true, then stops moving forever. Use it for an NPC that arrives after a quest milestone, or a creature that storms in after the player rings a bell.

"movement": {
  "type": "triggered",
  "trigger_flag": "bell_rung",
  "destination": "village_square",
  "depart_msg": "The guard marches out, hand on her sword.",
  "arrive_msg": "A guard storms into the square, summoned by the alarm."
}
FieldTypeDescription
type string Must be "triggered".
trigger_flag string Global flag that must be true for the move to fire. The move fires once and then the entity will not move again.
destination string Room ID the entity should move to when triggered.
depart_msg string Message shown when the entity leaves the player's current room.
arrive_msg string Message shown when the entity arrives in the player's current room.

Full Example

"mysterious_wizard": {
  "name": "Mysterious Wizard",
  "description": "An ancient wizard with a long silver beard. His eyes shimmer with arcane knowledge.",
  "keywords": ["wizard", "mage", "old man"],
  "dialogue": {
    "greeting": "Ah, an adventurer! I have been expecting you. Ask me about the quest if you dare.",
    "default": "Hmm, I know not of such things.",
    "sets_flag": "met_wizard",
    "topics": {
      "quest": {
        "keywords": ["quest", "adventure", "mission"],
        "text": "Deep in the Darkwood Forest lies a crystal of immense power. Retrieve it, and I shall reward you greatly.",
        "sets_flag": "quest_accepted",
        "leads_to": ["forest", "reward"]
      },
      "forest": {
        "keywords": ["forest", "darkwood", "woods"],
        "text": "The forest entrance is to the north. Take a torch — the darkness there is unnatural.",
        "locked_text": "First, ask me about the quest."
      },
      "reward": {
        "keywords": ["reward", "payment"],
        "text": "Bring me the crystal and I will grant you a powerful spell.",
        "locked_text": "Complete the quest first, then we can discuss compensation."
      }
    }
  },
  "accepts_item": "power_crystal",
  "gives_item": "spell_book",
  "accept_message": "The wizard's eyes light up. 'You found it! As promised, take this spell book. May it serve you well.'",
  "sets_flag": "quest_complete"
}