NPC Services
What This System Is
NPC services turn an NPC interaction into an overlay of shop, crafting, or direct service actions. They are authored in assets/npc/npc_service_catalog.json and linked from NPC interaction slots through service event IDs.
Every service ID uses this shape:
npc_service:<npc>|<service>
Examples:
npc_service:merchant|shopnpc_service:blacksmith|forgenpc_service:healer|healnpc_service:innkeeper|innnpc_service:toolsmith|shop
How Authors Use It
The NPC part must match the owning NPC interaction. Validation rejects malformed IDs, empty parts, and non-quest NPC interactions that point at missing service definitions.
Authoring Schema
Each service definition has:
event_id: the fullnpc_service:<npc>|<service>ID.title: overlay title.summary: short overlay description.kind:shop,service, orquest.vendor_stock_id: optional vendor stock source.crafting_recipe_ids: optional crafting recipe sources.entries: optional direct service entries.
Direct entries have:
idlabeldescriptionavailability_conditionscost_itemseffectsunlock_idsevent_idsrelationship_delta
Entry IDs are resolved case-insensitively when a player selects an overlay action.
Overlay Entry Sources
A service overlay can gather entries from three sources:
- Direct entries from the service definition.
- Vendor stock entries from
vendor_stock_id. - Crafting recipes listed in
crafting_recipe_ids.
The projection path resolves those sources into one overlay list. Prepared service catalogs index the same three entry kinds so repeated overlay builds and selected-entry lookups can reuse the prepared data when the catalog sources still match.
Rules And Invariants
Costs come from the selected entry source:
- Direct entries use
cost_items. - Vendor entries use their stock entry
cost_items. - Crafting entries use recipe
input_items.
Availability conditions use NPC-state condition tokens. If the condition parser cannot evaluate the condition or the NPC context is missing, the option is treated as unavailable rather than accepted optimistically.
Effects are projected into gameplay operations, including scene variables, quest flags, party tags, inventory deltas, reputation deltas, unlocks, runtime events, and relationship deltas. Cost items are applied as negative inventory deltas as part of the selected entry transaction.
Shipped Services
The current service catalog includes:
merchant|shop:Traveling Wares, a shop backed by vendor stockmerchant_shop_core.blacksmith|forge:Forge Services, a service backed by recipestemper_bladeandreforge_edge.healer|heal:Healing Services, direct entriesbind_woundsandrestore_spirit.innkeeper|inn:Inn Services, direct entriesrent_roomandhome_cooked_meal.toolsmith|shop:Starter Tool Shop, a shop backed by vendor stockvendor.tools.starter.
Use the full npc_service:<npc>|<service> form in NPC interactions; the shortened forms above are only for compact documentation.
NPC Interaction Links
NPC catalog interaction slots link to services by setting their interaction event_id to the service ID. For example, the merchant shop interaction points at npc_service:merchant|shop, while the blacksmith forge interaction points at npc_service:blacksmith|forge.
Validation enforces two important ownership rules:
- The service must exist for non-quest service interactions.
- The service owner NPC in the ID must match the NPC that exposes the interaction.
This keeps overlay actions from silently opening another NPC's shop or applying service effects under the wrong relationship context.
Local Vs Server Ownership
Local preview and offline flows may call the local service authority helper directly. That helper exists for editor and preview simulation.
Authoritative runtime paths must submit gameplay action requests instead. The client queues service overlay and entry requests when realtime is available, and only falls back to local preview behavior when that mode is allowed. The game server resolves the selected NpcServiceOverlay or NpcServiceEntry, loads authoritative inventory and currency state, checks availability and duplicate-output rules, then commits costs and effects through gameplay authority.
In practice: authors can preview services locally, but player-owned inventory, currency, quest, and service outcomes belong to the server.
Validation And Debugging
Run the shared bake diagnostics after editing assets/npc/npc_service_catalog.json or the NPC interactions that reference it:
cargo run --bin aether-bake -- --fail-on-diagnostics
If an overlay does not open, check the service ID shape, the owning NPC id, referenced vendor stock or recipe ids, and availability conditions before investigating runtime transport.
Examples
- Use the full
npc_service:<npc>|<service>ID in both the service catalog and NPC interaction. - Keep the NPC ID portion equal to the owning NPC.
- Choose
shopfor vendor-stock overlays,servicefor direct or crafting service overlays, andquestonly for quest-owned service flow. - For vendor services, verify the
vendor_stock_idexists in game data. - For crafting services, verify every recipe ID exists in game data.
- For direct entries, keep
idstable because it is the selected overlay action key. - Express costs in
cost_itemsfor direct entries, or let vendor stock and recipe definitions provide their own costs. - Add availability conditions only when they can be evaluated from NPC/service context.