Replace the single shared `npc` stat template (+ npc_card_types) with an `npcs` section: each NPC keyed by a stable id, carrying its own name, description, trigger keys, and its OWN stats block. The AI addresses NPCs as npc.<id>.<stat> (id shown in context), which also fixes the old card-id-guessing problem. On adventure creation each NPC auto-creates a story card (name/keys/desc) for lore + in-scene detection, unless a same-name card already exists. All NPCs instantiate up front. - engine: npcs instantiate/apply/render/reference, npc_name/npc_triggers - builder: _visible_npcs matches each NPC's own keys - create_adventure: auto-create story cards from npcs - WorldStateDrawer: render defined NPCs with their own stats + desc tooltip - demo seed: Gwen (health/trust) + Bandit Leader (health/aggression) - tests updated (34 pass); no new migration (npcs lives in stat_schema JSON) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
86 lines
4.5 KiB
JSON
86 lines
4.5 KiB
JSON
{
|
|
"title": "[Demo] The Bandit Camp (RPG world state)",
|
|
"description": "A short RPG scene showing the built-in world-state system: the AI tracks your HP and mana, an in-game day counter, an NPC ally's health and trust, and story milestones. No scripting — the engine keeps the numbers honest. Open the World State panel on the left to watch it change.",
|
|
"prompt": "Dawn breaks grey over the treeline as you and Gwen crouch at the edge of the bandit camp. Smoke curls from a dying fire; three bedrolls lie empty. Somewhere ahead, the stolen caravan strongbox waits.\n\nGwen checks her bowstring and looks to you. \"Quiet, or loud?\"",
|
|
"memory": "The player and Gwen, a loyal ranger ally, are raiding a bandit camp to recover a stolen strongbox. The player is a capable adventurer. This is a dangerous but winnable encounter.",
|
|
"authors_note": "Keep it tense and consequential. Reckless moves should cost health; clever ones should pay off. Gwen reacts to how the player treats her.",
|
|
"ai_instructions": "Write in second person, present tense. End each reply where the player can act. Let the world state guide the fiction — if the player is badly hurt, show it.",
|
|
"tags": "demo, rpg, world-state, combat, short",
|
|
"stat_schema": {
|
|
"world": {
|
|
"day": { "type": "counter", "min": 1, "initial": 1, "desc": "Which in-game day it is; only ever counts up." }
|
|
},
|
|
"player": {
|
|
"hp": {
|
|
"desc": "The player's physical health. At 0 they fall.",
|
|
"min": 0, "max": 100, "initial": 100, "max_delta_per_turn": 35,
|
|
"bands": [[0, 1, "dead"], [1, 25, "gravely wounded"], [25, 50, "hurt"],
|
|
[50, 80, "scratched"], [80, 100, "healthy"], [100, 101, "full health"]]
|
|
},
|
|
"mana": {
|
|
"desc": "Magical energy for spells; spent casting, restored by resting.",
|
|
"min": 0, "max": 50, "initial": 30, "max_delta_per_turn": 25,
|
|
"bands": [[0, 10, "drained"], [10, 30, "steady"], [30, 51, "brimming"]]
|
|
}
|
|
},
|
|
"flags": {
|
|
"alarm_raised": { "desc": "True once the bandits know they're under attack; stealth is blown.", "initial": false },
|
|
"player_hidden": { "desc": "True while the player is out of sight in cover.", "initial": true }
|
|
},
|
|
"npcs": {
|
|
"gwen": {
|
|
"name": "Gwen",
|
|
"keys": "Gwen, ranger, her",
|
|
"desc": "A loyal ranger and the player's ally. Quick with a bow, dry-humoured, fiercely protective. Her trust rises when the player fights smart and watches her back, and falls when they are reckless with her life.",
|
|
"stats": {
|
|
"health": {
|
|
"desc": "Gwen's physical health.",
|
|
"min": 0, "max": 100, "initial": 100, "max_delta_per_turn": 35,
|
|
"bands": [[0, 1, "dead"], [1, 25, "gravely wounded"], [25, 50, "hurt"],
|
|
[50, 80, "scratched"], [80, 101, "healthy"]]
|
|
},
|
|
"trust": {
|
|
"desc": "How much Gwen trusts the player; rises with smart, loyal play and falls with recklessness.",
|
|
"min": -100, "max": 100, "initial": 20, "max_delta_per_turn": 20,
|
|
"bands": [[-100, -30, "hostile"], [-30, 30, "wary"], [30, 70, "friendly"],
|
|
[70, 101, "devoted"]]
|
|
}
|
|
}
|
|
},
|
|
"bandit_leader": {
|
|
"name": "Bandit Leader",
|
|
"keys": "leader, chief, boss, scarred",
|
|
"desc": "The scarred leader of the bandit camp, guarding the strongbox. Fights harder the more cornered he becomes.",
|
|
"stats": {
|
|
"health": {
|
|
"desc": "The leader's physical health.",
|
|
"min": 0, "max": 120, "initial": 120, "max_delta_per_turn": 40,
|
|
"bands": [[0, 1, "dead"], [1, 30, "near death"], [30, 70, "bloodied"],
|
|
[70, 121, "unhurt"]]
|
|
},
|
|
"aggression": {
|
|
"desc": "How aggressively the leader fights; climbs as the fight turns against him.",
|
|
"min": 0, "max": 100, "initial": 40, "max_delta_per_turn": 25,
|
|
"bands": [[0, 30, "cautious"], [30, 70, "fierce"], [70, 101, "berserk"]]
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"milestones": {
|
|
"camp_cleared": { "desc": "Clear the bandit camp of enemies" },
|
|
"strongbox_found": { "desc": "Recover the stolen strongbox" },
|
|
"gwen_survives": { "desc": "Escape with Gwen still alive" }
|
|
}
|
|
},
|
|
"story_cards": [
|
|
{
|
|
"type": "location",
|
|
"name": "Bandit Camp",
|
|
"keys": "camp, bandits, strongbox",
|
|
"entry": "A rough camp of bandits in a forest clearing, holding a stolen caravan strongbox.",
|
|
"notes": ""
|
|
}
|
|
],
|
|
"scripts": []
|
|
}
|