NPCs Reference

Complete documentation for tabs/npcs.json.

Schema

interface NPC {
  name: string                    // ✅ Display name, must match object key
  type: string                    // ✅ Key from npc-types.json or ""
  currentLocation: string         // ✅ Key from locations.json or ""
  currentArea: string             // ✅ Area within location or ""
  gender?: string                 // ✅ "male", "female", or "non-binary"
  faction?: string                // ✅ Key from factions.json
  basicInfo?: string              // ✅ Immediately available info
  hiddenInfo?: string             // ✅ Info revealed via interaction
  visualDescription?: string      // ✅ Used for portrait generation
  visualTags?: string[]           // ✅ Only used for image caching
  personality?: string[]          // ✅ Prose descriptions of personality traits
  abilities?: string[]            // ✅ Prose descriptions of abilities
  aliases?: string[]              // ✅ Alternate names/titles matched during dialogue speaker attribution (e.g. "the captain", "Reed")
  level?: number                  // ⚠️ For premade NPCs, defaults to a 50/50 roll between 1 and 2 — set explicitly for any NPC that should be stronger. Each level adds +1 base damage
  hpMax?: number                  // ⚠️ Calculated from level + tier if undefined
  hpCurrent?: number              // ⚠️ Defaults to hpMax if undefined
  tier?: 'trivial' | 'weak' | 'average' | 'strong' | 'elite' | 'boss' | 'mythic'                  // ✅ Affects HP calculation AND combat intent complexity.
  vulnerabilities?: string[]      // ✅ 1.5× damage from these types. Unions with npc-type's vulnerabilities
  resistances?: string[]          // ✅ 0.5× damage from these types. Unions with npc-type's resistances
  immunities?: string[]           // ✅ 0× damage from these types. Unions with npc-type's immunities
  activeBuffs?: ActiveBuff[]      // ✅ See ActiveBuff schema below
  known?: boolean                 // ✅ Whether NPC appears in player journal
  lastSeenLocation?: string       // ✅ Preserved if predefined, but auto-updated when NPC is nearby. Shown in journal as "Last seen at..."
  lastSeenArea?: string           // ✅ Preserved if predefined, but auto-updated when NPC is nearby. Shown in journal with lastSeenLocation
  currentCoordinates?: number[]   // ✅ [x, y] for wilderness positioning
  detailType?: 'basic' | 'detailed'  // ⚠️ Defaults to 'detailed' if undefined. If 'detailed', generateNPCDetails won't run
  voiceTag?: string               // ✅ Voice tag for speech synthesis (see voice-tags.md)
  questOriginArcId?: string       // ✅ Auto-generated for quest-spawned NPCs. Links to the arc that spawned this NPC; provides arc theme/secrets to AI detail generation
  questOriginQuestId?: string     // ✅ Auto-generated for quest-spawned NPCs. Links to the quest that spawned this NPC; provides quest design brief to AI detail generation
  embedding?: number[]            // ✅ Auto-generated
  embeddingId?: string            // ✅ Auto-generated
  portraitUrl?: string            // ✅ .png portrait image URL
  needsDetailGeneration?: boolean // ✅ Flag to async trigger  generateNPCDetails
  deathXPAwarded?: boolean        // ✅ Whether XP will be given on death
  properName: string              // ❌ Always set to name
  status: '' | 'near death' | 'dying' | 'dead'      // ❌ Always set to ''
  relationship: number            // ❌ Always set to 0
  lastSeenTick: number            // ❌ Always set to -1. Value of -1 means immune to cleanup until first seen
}

Legend

  • Predefine-able: Can be set in config, preserved via spread
  • ⚠️ Calculated default: Has fallback logic if not predefined
  • Always overwritten: Set by initialization regardless of what exists in config

ActiveBuff Schema

interface ActiveBuff {
  type: 'resource' | 'resistance' | 'vulnerability' | 'immunity'  // Buff type
  amount: number                // Buff magnitude, only used for type 'resource' (NPC health)
  duration: number              // Ticks remaining before buff expires
  source: string                // Description of buff source
  resource: string              // For type 'resource': the world's health resource — accepts 'health', 'hp', or the configured isHealth resource name. NPCs have no other resources, so any non-health name is ignored. Otherwise use ""
  attribute: string             // Always "" for NPCs (they have no attributes)
  skill: string                 // Always "" for NPCs (they have no skills)
  damageType?: string           // For type 'resistance'|'vulnerability'|'immunity': the damage type as a string
}

Static resistances and buff resistances stack: 0.5× (static) × 0.5× (buff) = 0.25× (75% reduction).

Tier Effects

HP Multipliers

Tier Multiplier Effect
trivial 0.15 -85% HP
weak 0.5 -50% HP
average 1.0 Base HP
strong 1.25 +25% HP
elite 1.5 +50% HP
boss 1.7 +70% HP
mythic 1.85 +85% HP

Formula: (npcHealthPerLevel × level + npcMinHealth) × tierHPModifier

Damage Multipliers

Each tier also scales NPC damage output (engine constants, not configurable):

Tier Multiplier Effect
trivial 0.65 -35% damage
weak 0.8 -20% damage
average 1.0 Base damage
strong 1.12 +12% damage
elite 1.25 +25% damage
boss 1.35 +35% damage
mythic 1.55 +55% damage

Combat Intent Complexity

Tier determines how many intents an NPC generates in combat and their tactical sophistication:

Tier Intents Behavior
trivial / weak 1 Simple, direct actions
average 1-2 Basic tactics
strong 2 Uses abilities when appropriate
elite / boss / mythic 2-3 Tactical and dramatic

Death Countdown (Major NPCs)

NPCs with tier elite, boss, or mythic (and party member NPCs) use a 3-turn death countdown when they reach 0 HP:

Turn Status Description
1 near death Just went down, can be healed
2 dying Slipping closer to death
3 dead Permanently dead, cannot be revived

Standard-tier NPCs (trivial, weak, average, strong) die instantly at 0 HP.

generateNPCDetails

Only runs when detailType: 'basic' and needsDetailGeneration: 'true'

Reads basicInfo and generates: personality, hiddenInfo, faction, abilities, detailType, known, portraitUrl. Sets needsDetailGeneration to false when complete.

Cross-References

Field References
type tabs/npc-types.json
currentLocation, currentArea tabs/locations.json
faction tabs/factions.json
vulnerabilities, resistances, immunities combatSettings.damageTypes in tabs/settings.json

This site uses Just the Docs, a documentation theme for Jekyll.