From 147c4af2251f9eab06f67f747a606cf8445df7f9 Mon Sep 17 00:00:00 2001 From: "Z. Cliffe Schreuders" Date: Tue, 18 Nov 2025 01:22:08 +0000 Subject: [PATCH] feat: Add comprehensive features reference and enhanced Ink scripting guide Add two critical enhancements to scenario development prompts: 1. FEATURES_REFERENCE.md - Complete game features documentation - All available object types (notes, PC, phone, tablet, etc.) - All lock types (key, pin, password, bluetooth, rfid, lockpick) - NPC system (physical, phone, patrol, event mappings) - RFID security protocols (EM4100, MIFARE variants, DESFire) - Ink dialogue system with tags and patterns - Event system for reactive dialogue - Room system and connections - Complete examples and best practices - Quick reference tables 2. Enhanced 07_ink_scripting.md - Detailed Ink guide with actual structure - THREE-ACT STRUCTURE AS ACTUALLY IMPLEMENTED: * Act 1: Interactive cutscene (Ink-heavy, 2-5 min, choices) * Act 2: Puzzle chain gameplay (game-heavy, 15-40 min, NPC support) * Act 3: Resolution and debrief (Ink-heavy, 2-5 min, consequences) - Complete templates for opening cutscene with choices - NPC dialogue patterns (hub pattern, guards, phone contacts) - Closing cutscene with variable callbacks - Event-driven dialogue examples - Ink tags reference (#speaker, #display, #hostile, etc.) - Testing and validation guidance - Common errors and solutions These documents provide the concrete technical details needed for AI agents to write scenarios with proper features, constraints, and narrative structure. Based on analysis of existing scenarios: - scenarios/ceo_exfil.json - scenarios/test-npc-patrol.json - scenarios/test-rfid-multiprotocol.json - scenarios/ink/security-guard.ink - scenarios/ink/alice-chat.ink --- .../story_dev_prompts/07_ink_scripting.md | 820 +++++++++++++++- .../story_dev_prompts/FEATURES_REFERENCE.md | 924 ++++++++++++++++++ 2 files changed, 1737 insertions(+), 7 deletions(-) create mode 100644 story_design/story_dev_prompts/FEATURES_REFERENCE.md diff --git a/story_design/story_dev_prompts/07_ink_scripting.md b/story_design/story_dev_prompts/07_ink_scripting.md index 70393db..17e9af5 100644 --- a/story_design/story_dev_prompts/07_ink_scripting.md +++ b/story_design/story_dev_prompts/07_ink_scripting.md @@ -19,6 +19,7 @@ You are an Ink narrative scripter for Break Escape. Your tasks: ## Required Input From previous stages: +- Stage 0: Technical challenges and ENTROPY cell - Stage 1: Narrative structure with story beats - Stage 2: Character profiles and dialogue guidelines - Stage 3: Moral choices and consequence design @@ -29,27 +30,832 @@ From previous stages: ### ESSENTIAL - Technical Documentation - **`docs/INK_INTEGRATION.md`** - How Ink integrates with the game +- **`story_design/story_dev_prompts/FEATURES_REFERENCE.md`** - All available game features - **Ink documentation** - https://github.com/inkle/ink/blob/master/Documentation/WritingWithInk.md ### Essential - Design Documentation - `story_design/universe_bible/10_reference/style_guide.md` - Writing tone - `story_design/universe_bible/04_characters/` - Character voices -- Previous stage outputs (especially Stages 2 and 3) +- Previous stage outputs (especially Stages 1, 2, and 3) + +### Reference Examples +- `scenarios/ink/security-guard.ink` - Complex NPC with patrol and confrontation +- `scenarios/ink/alice-chat.ink` - Hub pattern with trust system +- `scenarios/ink/*.json` - Compiled Ink examples + +## Understanding Break Escape's Three-Act Structure + +Break Escape scenarios follow a specific three-act structure where Ink handles Act 1 and Act 3, while Act 2 is primarily gameplay: + +### Act 1: Interactive Cutscene (Ink-Heavy) +**Duration:** 2-5 minutes +**Medium:** Ink dialogue with choices +**Purpose:** Establish mission, create player investment, set up story + +**What happens:** +- SAFETYNET handler briefs the player +- Stakes and urgency are established +- Player makes initial choices that affect approach +- Background and context provided +- Mission objectives stated +- Player is "released" into gameplay + +**Key Ink elements:** +- Multiple choice points +- Character introductions +- Variable setting for later callbacks +- Conditional dialogue based on choices +- Clear transition to gameplay + +### Act 2: Puzzle Chain Gameplay (Game-Heavy, Ink-Light) +**Duration:** 15-40 minutes +**Medium:** Gameplay with NPC dialogue support +**Purpose:** Player solves puzzles, navigates rooms, overcomes challenges + +**What happens:** +- Player navigates through rooms +- Solves puzzle chains (find code → unlock computer → get key → access room) +- Interacts with NPCs for hints, obstacles, or information +- Collects LORE fragments +- Overcomes technical challenges +- Works toward final objective + +**Ink's role:** +- NPC dialogue when encountered +- Reactive messages via phone NPCs (event-driven) +- Hints and guidance when stuck +- Optional conversations for depth +- Environmental NPC interactions (guards, witnesses) + +### Act 3: Resolution and Consequences (Ink-Heavy) +**Duration:** 2-5 minutes +**Medium:** Ink dialogue, potentially with final choice +**Purpose:** Resolve narrative, show consequences, debrief + +**What happens:** +- Player reaches final objective or location +- Final confrontation or revelation (may be dialogue, may be discovery) +- Consequences of Act 1 choices revealed +- Handler debriefs player +- Mission outcomes discussed +- Narrative closure (or setup for future) + +**Key Ink elements:** +- Callbacks to earlier choices +- Variable-dependent endings +- Character reactions to player's actions +- Mission success/failure acknowledged +- Emotional payoff ## Process -Structure Ink files, write opening cutscene, write NPC dialogues, implement choice moments, write closing cutscene(s), write mid-scenario story beats, implement dynamic content, and test/validate all syntax. +### Step 1: Structure Your Ink Files -Test all Ink files in Inky editor before finalizing. +**Recommended File Organization:** + +``` +scenarios/ink/ +├── [scenario_name]_opening.ink # Act 1: Opening cutscene +├── [scenario_name]_npc_*.ink # Act 2: Individual NPCs +├── [scenario_name]_phone_*.ink # Act 2: Phone contacts +└── [scenario_name]_closing.ink # Act 3: Closing cutscene +``` + +**Alternative (Single File):** +``` +scenarios/ink/[scenario_name].ink # All content in knots +``` + +### Step 2: Write Act 1 - Opening Interactive Cutscene + +Act 1 should be a rich, choice-driven experience that makes players care about the mission. + +#### Opening Cutscene Template + +```ink +// =========================================== +// ACT 1: OPENING CUTSCENE +// Break Escape Scenario: [Name] +// =========================================== + +// Variables for tracking player choices and state +VAR player_approach = "" // cautious, aggressive, diplomatic +VAR handler_trust = 50 // Handler's confidence in player +VAR knows_full_stakes = false // Did player ask about stakes? +VAR mission_priority = "" // speed, stealth, thoroughness + +// External variables (set by game) +EXTERNAL player_name +EXTERNAL scenario_state + +// =========================================== +// OPENING +// =========================================== + +=== start === +#speaker:handler_[name] +{player_name}, thank you for getting here on such short notice. + +[Visual: Handler in SAFETYNET briefing room, serious expression] + +Handler: We have a situation developing at [location]. + +* [Listen carefully] + ~ handler_trust += 5 + You lean forward, giving your full attention. + -> briefing_main + +* [Ask what kind of situation] + Handler: I'll explain. Pay close attention. + -> briefing_main + +* [Express readiness] + ~ handler_trust += 10 + ~ player_approach = "confident" + You: I'm ready. What's the mission? + Handler: Good. Let's get straight to it. + -> briefing_main + +// =========================================== +// MAIN BRIEFING +// =========================================== + +=== briefing_main === +Handler: [ENTROPY Cell Name] has targeted [target]. + +[Provide key context about what's at stake] + +Handler: If they succeed, [consequences]. + +* [Ask about timeline] + ~ knows_full_stakes = true + You: How much time do we have? + Handler: [Urgency explanation - hours/minutes] + -> briefing_details + +* [Ask about ENTROPY's methods] + You: What's their approach? + Handler: [Cell's typical methodology] + -> briefing_details + +* [Ask about innocent bystanders] + ~ handler_trust += 5 + You: Are there civilians at risk? + Handler: [Information about potential collateral] + ~ knows_full_stakes = true + -> briefing_details + +=== briefing_details === +Handler: Your primary objectives: + +[List 3-4 clear objectives] + +* [Ask for clarification on objectives] + -> objectives_clarification + +* [Ask about entry method] + -> cover_story + +* [Accept mission immediately] + ~ player_approach = "direct" + -> mission_approach + +=== objectives_clarification === +[Provide additional detail on objectives] + +Handler: Does that clear things up? + +* [Yes, I understand] + -> cover_story + +* [What if I can't complete all objectives?] + ~ handler_trust -= 5 + Handler: Do your best. Priority is [primary objective]. + -> cover_story + +=== cover_story === +Handler: Your cover is [cover story]. Entry point is [location]. + +{knows_full_stakes: + Handler: Remember, lives are at stake. Be thorough but fast. +} + +-> mission_approach + +// =========================================== +// CRITICAL CHOICE: Mission Approach +// =========================================== + +=== mission_approach === +Handler: How do you want to approach this? + ++ [Cautious and methodical] + ~ player_approach = "cautious" + ~ mission_priority = "thoroughness" + You: I'll be careful. Thorough investigation is key. + Handler: Smart. Take your time but stay alert. + -> final_instructions + ++ [Fast and direct] + ~ player_approach = "aggressive" + ~ mission_priority = "speed" + You: I'll move quickly and complete objectives fast. + Handler: Good. Time is critical. But don't miss anything vital. + -> final_instructions + ++ [Adaptable - assess on site] + ~ player_approach = "diplomatic" + ~ mission_priority = "stealth" + You: I'll read the situation and adapt. + Handler: Flexible thinking. Trust your instincts. + ~ handler_trust += 5 + -> final_instructions + +=== final_instructions === +Handler: Remember Field Operations Rule [relevant number from handbook]. + +{player_approach == "cautious": + Handler: Your careful approach should serve you well. Document everything. +} +{player_approach == "aggressive": + Handler: Speed is good, but don't compromise the mission for it. +} +{player_approach == "diplomatic": + Handler: Adapt as needed. We trust your judgment. +} + +Handler: You'll have comms support. I'll be monitoring. + +* [Any last advice?] + Handler: [Specific hint about first obstacle or key NPC] + -> deployment + +* [I'm ready to go] + -> deployment + +=== deployment === +Handler: Good luck, {player_name}. SAFETYNET is counting on you. + +[Transition: Fade to mission start location] + +#start_gameplay +-> END +``` + +#### Act 1 Best Practices + +1. **Front-load choices** - Give players 3-5 meaningful choices in Act 1 +2. **Set variables** - Track choices that will callback later +3. **Character voice** - Handler should sound consistent with their profile +4. **Stakes clarity** - Player must understand what they're fighting for +5. **Smooth transition** - Clear moment when dialogue ends and gameplay begins +6. **Player agency** - Choices should feel meaningful, not cosmetic + +### Step 3: Write Act 2 - NPC Dialogues + +Act 2 NPCs fall into several categories: + +#### Physical NPCs (Guards, Workers, Obstacles) + +Use the **hub pattern** for conversations with multiple topics: + +```ink +// =========================================== +// ACT 2 NPC: Security Guard +// =========================================== + +VAR influence = 0 +VAR guard_hostile = false +VAR player_warned = false +VAR topic_building = false +VAR topic_security = false + +=== start === +#speaker:security_guard +{not player_warned: + #display:guard-patrol + The guard looks up as you approach. + Guard: This is a restricted area. What's your business here? + ~ player_warned = true +} +{player_warned and not guard_hostile: + #display:guard-neutral + Guard: Back again? +} +{guard_hostile: + #display:guard-hostile + Guard: I told you to leave. Now. + #exit_conversation + -> END +} +-> hub + +=== hub === ++ {not topic_building} [Ask about building layout] + -> ask_building ++ {not topic_security} [Ask about security protocols] + -> ask_security ++ {influence >= 20} [Request access] + -> request_access ++ [Leave conversation] + #exit_conversation + #speaker:security_guard + Guard: Stay out of trouble. + -> END + +=== ask_building === +#speaker:security_guard +~ topic_building = true +~ influence += 5 + +Guard: [Provides general information about layout] + +{influence >= 15: + Guard: [Additional helpful detail] +} +-> hub + +=== ask_security === +#speaker:security_guard +~ topic_security = true +~ influence += 5 + +Guard: Standard protocols. Nothing you need to worry about. + +{influence >= 25: + Guard: Though... [reveals minor security gap] +} +-> hub + +=== request_access === +#speaker:security_guard +{influence >= 30: + ~ influence -= 10 + Guard: Alright, I'll let you through. But make it quick. + #exit_conversation + -> END +- else: + ~ influence -= 5 + Guard: Sorry, can't do that. Security protocols. + -> hub +} + +// Event-triggered knot (called by game when guard sees lockpicking) +=== on_lockpick_detected === +#speaker:security_guard +~ guard_hostile = true +~ influence = 0 + +#display:guard-hostile +Guard: HEY! What are you doing with that lock?! + +#hostile:security_guard +This is your only warning - GET OUT! + +#exit_conversation +-> END +``` + +#### Phone NPCs (Remote Support) + +Phone NPCs provide hints and react to player progress via events: + +```ink +// =========================================== +// ACT 2 PHONE NPC: Handler Support +// =========================================== + +VAR hint_lockpicking_given = false +VAR hint_password_given = false +VAR rooms_discovered = 0 + +=== start === +#speaker:handler_support +Handler: {player_name}, checking in. How's it going? + ++ [Request hint] + -> provide_hint ++ [Report progress] + -> report_progress ++ [End call] + #exit_conversation + Handler: Stay safe out there. + -> END + +=== provide_hint === +#speaker:handler_support + +{not hint_lockpicking_given: + Handler: If you have a lockpick kit, you can bypass key locks. + ~ hint_lockpicking_given = true + -> start +} +{not hint_password_given: + Handler: Check computers and notes for password clues. + ~ hint_password_given = true + -> start +} +{hint_lockpicking_given and hint_password_given: + Handler: You're doing fine. Trust your training. + -> start +} + +// Event-triggered: Called when player picks up lockpick +=== on_lockpick_pickup === +#speaker:handler_support +Handler: Good find. That lockpick will let you bypass key locks. +Handler: Remember, lockpicking takes time and makes noise. +-> END + +// Event-triggered: Called when player completes lockpick minigame +=== on_lockpick_success === +#speaker:handler_support +Handler: Nice work on that lock. Smooth technique. +-> END + +// Event-triggered: Called when player enters new room +=== on_room_discovered === +#speaker:handler_support +~ rooms_discovered += 1 + +{rooms_discovered == 1: + Handler: Good, you're making progress. Stay alert. +} +{rooms_discovered == 3: + Handler: You're covering ground quickly. Don't miss anything important. +} +{rooms_discovered >= 5: + Handler: Thorough work. ENTROPY's trail should be getting clearer. +} +-> END +``` + +#### Event Mapping (in JSON) + +Connect Ink knots to game events: + +```json +"eventMappings": [ + { + "eventPattern": "item_picked_up:lockpick", + "targetKnot": "on_lockpick_pickup", + "onceOnly": true + }, + { + "eventPattern": "minigame_completed", + "targetKnot": "on_lockpick_success", + "condition": "data.minigameName && data.minigameName.includes('Lockpick')", + "cooldown": 10000 + }, + { + "eventPattern": "room_discovered", + "targetKnot": "on_room_discovered", + "cooldown": 15000, + "maxTriggers": 5 + } +] +``` + +### Step 4: Write Act 3 - Closing Cutscene + +Act 3 should: +1. Acknowledge player's performance +2. Callback to Act 1 choices +3. Show consequences +4. Provide narrative closure +5. Potentially set up future stories + +#### Closing Cutscene Template + +```ink +// =========================================== +// ACT 3: CLOSING CUTSCENE +// =========================================== + +// Variables from Act 1 (carried forward) +EXTERNAL player_approach +EXTERNAL handler_trust +EXTERNAL knows_full_stakes +EXTERNAL mission_priority + +// Variables from Act 2 (set by game) +EXTERNAL objectives_completed +EXTERNAL lore_collected +EXTERNAL stealth_rating +EXTERNAL time_taken + +=== start === +[Location: SAFETYNET Debrief Room] + +#speaker:handler_[name] + +{objectives_completed >= 4: + -> full_success_debrief +} +{objectives_completed >= 2: + -> partial_success_debrief +} +{objectives_completed < 2: + -> minimal_success_debrief +} + +// =========================================== +// FULL SUCCESS PATH +// =========================================== + +=== full_success_debrief === +Handler: Excellent work, {player_name}. All primary objectives completed. + +{player_approach == "cautious": + Handler: Your methodical approach paid off. Nothing was missed. +} +{player_approach == "aggressive": + Handler: You moved fast and got results. Well executed. +} +{player_approach == "diplomatic": + Handler: Your adaptability was key. You read the situation perfectly. +} + +-> mission_details + +=== mission_details === +Handler: [Summary of what was accomplished] + +{knows_full_stakes: + Handler: And yes, you prevented [the stakes from Act 1]. Those civilians are safe because of you. +} + +// Check for Act 1 choices and reference them +{handler_trust >= 60: + Handler: I had confidence in you from the start. You've proven that trust was well-placed. +} +{handler_trust < 40: + Handler: I'll admit, I had doubts. But you came through when it mattered. +} + +-> entropy_status + +=== entropy_status === +Handler: As for [ENTROPY cell]... + +{stealth_rating > 80: + Handler: They didn't even know you were there until it was too late. Masterful. +} +{stealth_rating > 50: + Handler: They knew someone was interfering, but couldn't stop you. +} +{stealth_rating <= 50: + Handler: You made some noise, but got the job done. That's what counts. +} + +[Specific information about ENTROPY cell's status] +[Did they escape? Get caught? What did we learn?] + +-> lore_discussion + +=== lore_discussion === +{lore_collected >= 8: + Handler: I see you found extensive intelligence. Analysis team is already going through it. + Handler: [Tease what LORE revealed about larger plot] + -> consequences +} +{lore_collected >= 4: + Handler: You gathered some useful intelligence. It's filling in our picture of their network. + -> consequences +} +{lore_collected < 4: + Handler: We got the primary objective, though more intelligence would have been helpful. + -> consequences +} + +=== consequences === +Handler: This operation has implications for [larger context]. + +[Explain broader impact] +[Set up potential future threads] + +* [Ask what happens next] + You: What's SAFETYNET's next move? + Handler: [Future operations hint] + -> debrief_end + +* [Express concern about loose ends] + You: [Express specific concern about unresolved elements] + Handler: [Acknowledgment and context] + -> debrief_end + +* [Accept mission closure] + -> debrief_end + +=== debrief_end === +Handler: Get some rest, {player_name}. You've earned it. + +{handler_trust >= 70: + Handler: And... good work. Really. We're lucky to have you. +} + +[Fade to mission complete screen] + +-> END + +// =========================================== +// PARTIAL SUCCESS PATH +// =========================================== + +=== partial_success_debrief === +Handler: Mission complete, {player_name}, though we didn't get everything. + +Handler: [What was accomplished] + +Handler: [What was missed and why it matters] + +{player_approach == "aggressive" and time_taken < 1800: + Handler: Speed was prioritized. Sometimes that means missing details. +} + +-> entropy_status + +// =========================================== +// MINIMAL SUCCESS PATH +// =========================================== + +=== minimal_success_debrief === +Handler: You completed the core objective, but... + +Handler: [Acknowledge accomplishment] + +Handler: [Note significant gaps] + +Handler: We'll need to follow up on what was missed. + +-> entropy_status +``` + +#### Act 3 Best Practices + +1. **Acknowledge everything** - Choices, performance, approach +2. **Show don't tell consequences** - Reference specific outcomes +3. **Vary endings** - Multiple variants based on performance +4. **Emotional payoff** - Match the tone to the outcome +5. **Close loops** - Answer questions raised in Acts 1 and 2 +6. **Plant seeds** - Optional: hint at future scenarios + +### Step 5: Ink Technical Best Practices + +#### Use Tags for Game Integration + +```ink +#speaker:character_name // Sets active speaker +#display:mood_state // Changes NPC visual state +#exit_conversation // Closes dialogue +#hostile:npc_id // Marks NPC as hostile +#patrol_mode:on // Enables NPC patrol +#patrol_mode:off // Disables NPC patrol +#start_gameplay // Transitions from cutscene to gameplay +``` + +#### Variable Naming Conventions + +```ink +// Choice tracking +VAR player_choice_mission_approach = "" + +// State tracking +VAR npc_trust_level = 0 +VAR knows_secret = false + +// Topic tracking (for hub pattern) +VAR topic_discussed_security = false +VAR topic_discussed_building = false + +// External variables (set by game) +EXTERNAL player_name +EXTERNAL objectives_completed +``` + +#### Hub Pattern (Recommended for Conversations) + +```ink +=== hub === ++ {condition1} [Choice 1] + -> branch1 ++ {condition2} [Choice 2] + -> branch2 ++ [Always available choice] + -> branch3 ++ [Exit conversation] + #exit_conversation + -> END + +=== branch1 === +Content here... +-> hub // Return to hub + +=== branch2 === +Content here... +-> hub + +=== branch3 === +Content here... +-> hub +``` + +### Step 6: Testing and Validation + +#### Test in Inky Editor + +1. Load each .ink file in Inky +2. Test all branches +3. Verify variables update correctly +4. Check that all diverts point to existing knots +5. Confirm tags are properly formatted + +#### Common Ink Errors + +```ink +// ERROR: Missing === +start === // Wrong +=== start === // Correct + +// ERROR: Unclosed braces +{trust_level >= 3: + Text here // Missing closing brace + +{trust_level >= 3: + Text here +} // Correct + +// ERROR: Missing -> before divert +Trust increased +hub // Wrong + +Trust increased +-> hub // Correct + +// ERROR: Typo in variable name +~ trust_levl += 1 // Creates new variable! +~ trust_level += 1 // Correct +``` + +#### Testing Checklist + +- [ ] All Ink files compile without errors in Inky +- [ ] All choice branches are reachable +- [ ] All conditional logic works correctly +- [ ] Variables are set and checked correctly +- [ ] All diverts point to existing knots +- [ ] Tags are properly formatted +- [ ] Character voices are distinct +- [ ] Dialogue flows naturally when read aloud +- [ ] Act 1 choices are referenced in Act 3 +- [ ] Event-triggered knots exist for all event mappings + +--- + +## Output Format + +```markdown +# Ink Scripts: [Scenario Name] + +## File Structure +- `[scenario]_opening.ink` - Act 1 opening cutscene +- `[scenario]_npc_guard.ink` - Security guard NPC +- `[scenario]_phone_handler.ink` - Handler phone contact +- `[scenario]_closing.ink` - Act 3 closing cutscene + +## Variables Reference + +### Act 1 Variables (Opening Cutscene) +- `player_approach` - cautious/aggressive/diplomatic +- `handler_trust` - 0-100 trust level +- `knows_full_stakes` - boolean +- `mission_priority` - speed/stealth/thoroughness + +### Act 2 Variables (NPC Dialogues) +- `guard_influence` - 0-100 persuasion level +- `topic_*` - boolean flags for conversation topics + +### External Variables (Set by Game) +- `player_name` - Player's display name +- `objectives_completed` - Number of completed objectives +- `lore_collected` - Number of LORE fragments found +- `stealth_rating` - 0-100 stealth performance + +## Integration Notes +[How Ink integrates with game systems] + +## Testing Results +[What was tested and outcomes] +``` --- Save your Ink scripts as: ``` -scenario_designs/[scenario_name]/07_ink/opening_cutscene.ink -scenario_designs/[scenario_name]/07_ink/closing_cutscene.ink -scenario_designs/[scenario_name]/07_ink/npc_dialogues.ink -scenario_designs/[scenario_name]/07_ink/choice_moments.ink +scenarios/ink/[scenario_name]_opening.ink +scenarios/ink/[scenario_name]_npc_*.ink +scenarios/ink/[scenario_name]_phone_*.ink +scenarios/ink/[scenario_name]_closing.ink ``` **Next Stage:** Pass complete scripts to Stage 8 (Review) for final validation. diff --git a/story_design/story_dev_prompts/FEATURES_REFERENCE.md b/story_design/story_dev_prompts/FEATURES_REFERENCE.md new file mode 100644 index 0000000..74d4adf --- /dev/null +++ b/story_design/story_dev_prompts/FEATURES_REFERENCE.md @@ -0,0 +1,924 @@ +# Break Escape: Available Features for Scenario Design + +**Purpose:** This document provides a comprehensive reference of all available game features, mechanics, and systems that scenario designers can use when creating Break Escape scenarios. + +**Audience:** AI agents, human designers, and anyone writing scenario JSON files or Ink dialogue. + +--- + +## Table of Contents + +1. [Scenario Structure](#scenario-structure) +2. [Room System](#room-system) +3. [Object Types](#object-types) +4. [Lock Types and Security](#lock-types-and-security) +5. [NPC System](#npc-system) +6. [Ink Dialogue System](#ink-dialogue-system) +7. [RFID System](#rfid-system) +8. [Player Configuration](#player-configuration) +9. [Puzzle Chains and Dependencies](#puzzle-chains-and-dependencies) +10. [Event System](#event-system) + +--- + +## Scenario Structure + +### Top-Level JSON Structure + +```json +{ + "name": "Scenario Name", + "description": "Brief description", + "scenario_brief": "Opening text shown to player", + "endGoal": "What player is trying to accomplish", + "startRoom": "room_id", + "globalVariables": {}, + "player": { /* player configuration */ }, + "startItemsInInventory": [ /* items */ ], + "rooms": { /* room definitions */ } +} +``` + +### Key Fields + +- **`scenario_brief`**: Opening text displayed to player (supports markdown) +- **`endGoal`**: Win condition description +- **`startRoom`**: ID of the room where player spawns +- **`startItemsInInventory`**: Array of items player starts with +- **`globalVariables`**: Shared state across scenario (optional) + +--- + +## Room System + +### Room Types + +Available room types (determines visual theme): +- `room_reception` - Lobby/entrance areas +- `room_office` - Standard office spaces +- `room_ceo` - Executive offices +- `room_servers` - Server/data center rooms +- `room_closet` - Small storage areas + +### Room Structure + +```json +"room_id": { + "name": "Display Name", + "type": "room_office", + "locked": true, + "lockType": "key", + "requires": "key_id", + "door_sign": "Optional door label", + "connections": { + "north": "room_id", + "south": ["room_id1", "room_id2"], + "east": "room_id", + "west": "room_id" + }, + "npcs": [ /* NPC definitions */ ], + "objects": [ /* object definitions */ ], + "doors": [ /* explicit door configurations */ ] +} +``` + +### Connections + +- **Single direction**: `"north": "room_id"` +- **Multiple connections**: `"north": ["room_id1", "room_id2"]` +- **All four directions supported**: north, south, east, west + +### Door Configuration + +Explicit door definitions (optional, for precise control): + +```json +{ + "roomId": "current_room", + "connectedRoom": "target_room", + "direction": "north", + "x": 200, + "y": 100, + "locked": true, + "lockType": "rfid", + "requires": ["card_id"] +} +``` + +--- + +## Object Types + +### Common Object Properties + +All objects share these base properties: + +```json +{ + "type": "object_type", + "name": "Display Name", + "takeable": true, + "x": 300, // Optional: precise positioning + "y": 200, // Optional: precise positioning + "observations": "Description shown on examine" +} +``` + +### Document/Information Objects + +**Notes** +```json +{ + "type": "notes", + "name": "Document Name", + "takeable": true, + "readable": true, + "text": "Content of the note", + "note_title": "Optional title", + "note_content": "Formatted content (supports markdown)", + "important": true, // Optional: highlight important items + "isEndGoal": true, // Optional: marks scenario completion + "observations": "Description" +} +``` + +**Phone (voicemail/messages)** +```json +{ + "type": "phone", + "name": "Phone Name", + "takeable": false, + "readable": true, + "voice": "Message content", + "text": "Alternative text content", + "sender": "Sender name", + "timestamp": "Time/date", + "phoneId": "phone_id", // For linking to NPC contacts + "npcIds": ["npc1", "npc2"], // NPCs accessible via this phone + "observations": "Description" +} +``` + +### Computer/Terminal Objects + +**PC/Computer** +```json +{ + "type": "pc", + "name": "Computer Name", + "takeable": false, + "locked": true, + "lockType": "password", + "requires": "password_string", + "showKeyboard": true, // Show on-screen keyboard + "passwordHint": "Optional hint", + "showHint": true, + "maxAttempts": 3, + "postitNote": "Password: secret", // Visible password hint + "showPostit": true, + "hasFingerprint": true, // Can be unlocked with fingerprints + "fingerprintOwner": "ceo", + "fingerprintDifficulty": "medium", + "contents": [ /* objects inside */ ], + "observations": "Description" +} +``` + +**Tablet** +```json +{ + "type": "tablet", + "name": "Tablet Device", + "takeable": true, + "locked": true, + "lockType": "bluetooth", + "requires": "bluetooth", + "mac": "00:11:22:33:44:55", + "observations": "Description" +} +``` + +### Security/Tool Objects + +**Key** +```json +{ + "type": "key", + "name": "Key Name", + "takeable": true, + "key_id": "unique_key_id", + "keyPins": [100, 0, 100, 0], // For lockpicking minigame + "observations": "Description" +} +``` + +**Lockpick Kit** +```json +{ + "type": "lockpick", + "name": "Lock Pick Kit", + "takeable": true, + "observations": "Enables lockpicking minigame" +} +``` + +**Fingerprint Kit** +```json +{ + "type": "fingerprint_kit", + "name": "Fingerprint Kit", + "takeable": true, + "observations": "Collects fingerprints from surfaces" +} +``` + +**PIN Cracker** +```json +{ + "type": "pin-cracker", + "name": "PIN Cracker", + "takeable": true, + "observations": "Provides feedback on PIN entry attempts" +} +``` + +**Bluetooth Scanner** +```json +{ + "type": "bluetooth_scanner", + "name": "Bluetooth Scanner", + "takeable": true, + "canScanBluetooth": true, + "observations": "Detects nearby Bluetooth signals" +} +``` + +**RFID Cloner** +```json +{ + "type": "rfid_cloner", + "name": "RFID Flipper", + "takeable": true, + "saved_cards": [], + "observations": "Scans and emulates RFID cards" +} +``` + +**Keycard (RFID)** +```json +{ + "type": "keycard", + "name": "Access Card", + "card_id": "unique_card_id", + "rfid_protocol": "EM4100", + "takeable": true, + "observations": "Description" +} +``` + +**Workstation** +```json +{ + "type": "workstation", + "name": "Analysis Station", + "takeable": true, + "observations": "Powerful computer for analysis tasks" +} +``` + +### Container Objects + +**Safe** +```json +{ + "type": "safe", + "name": "Safe Name", + "takeable": false, + "locked": true, + "lockType": "pin", + "requires": "9573", + "contents": [ /* objects inside */ ], + "observations": "Description" +} +``` + +**Suitcase/Briefcase** +```json +{ + "type": "suitcase", + "name": "Briefcase", + "takeable": false, + "locked": true, + "lockType": "key", + "requires": "key_id", + "keyPins": [50, 25, 0, 75], + "difficulty": "medium", + "contents": [ /* objects inside */ ], + "observations": "Description" +} +``` + +--- + +## Lock Types and Security + +### Available Lock Types + +1. **`key`** - Requires specific key item + - `requires`: key_id (string) + - `keyPins`: [array of 4 numbers] for lockpicking minigame + - `difficulty`: "easy", "medium", "hard" + +2. **`pin`** - 4-digit PIN code + - `requires`: "1234" (4-digit string) + - Can use PIN cracker for hints + +3. **`password`** - Text password + - `requires`: "password_string" + - `showKeyboard`: true (shows on-screen keyboard) + - `maxAttempts`: number (optional) + +4. **`bluetooth`** - Bluetooth pairing + - `requires`: "bluetooth" + - `mac`: "MAC address" (for bluetooth scanner) + +5. **`rfid`** - RFID card access + - `requires`: ["card_id"] or "card_id" + - Works with RFID cloner + +6. **`lockpick`** - Lockpicking minigame + - Uses keyPins array + - Requires lockpick tool in inventory + +### Lockpicking System + +Doors and containers with `lockType: "key"` can be picked: + +```json +{ + "locked": true, + "lockType": "key", + "requires": "office_key", + "keyPins": [100, 0, 100, 0], // Pin heights for minigame + "difficulty": "easy" // easy/medium/hard +} +``` + +- **keyPins**: Array of 4 numbers (0-150) representing pin heights +- **difficulty**: Affects time window and feedback + +--- + +## NPC System + +### NPC Types + +1. **`person`** - Physical NPC in the game world +2. **`phone`** - Virtual NPC accessible via phone item + +### Physical NPC Structure + +```json +{ + "id": "npc_id", + "displayName": "NPC Name", + "npcType": "person", + "position": { "x": 3, "y": 3 }, + "spriteSheet": "hacker", + "spriteTalk": "assets/characters/hacker-talk.png", + "spriteConfig": { + "idleFrameStart": 20, + "idleFrameEnd": 23 + }, + "storyPath": "scenarios/ink/dialogue.json", + "currentKnot": "start", + "avatar": "assets/npc/avatars/npc_neutral.png", + "behavior": { + "facePlayer": true, + "facePlayerDistance": 96, + "patrol": { + "enabled": true, + "speed": 100, + "changeDirectionInterval": 3000, + "bounds": { + "x": 64, + "y": 64, + "width": 192, + "height": 192 + } + } + }, + "rfidCard": { + "card_id": "employee_badge", + "rfid_protocol": "EM4100", + "name": "Employee Badge" + }, + "eventMappings": [ /* event triggers */ ] +} +``` + +### Phone NPC Structure + +```json +{ + "id": "contact_id", + "displayName": "Contact Name", + "storyPath": "scenarios/ink/dialogue.json", + "avatar": "assets/npc/avatars/npc_helper.png", + "phoneId": "player_phone", + "currentKnot": "start", + "npcType": "phone", + "timedMessages": [ + { + "delay": 5000, + "message": "Hey! Got any updates?", + "type": "text" + } + ], + "eventMappings": [ /* event triggers */ ] +} +``` + +### NPC Behaviors + +**Face Player** +```json +"behavior": { + "facePlayer": true, + "facePlayerDistance": 96 // Distance in pixels (96 = 3 tiles) +} +``` + +**Patrol** +```json +"patrol": { + "enabled": true, + "speed": 100, // Pixels per second + "changeDirectionInterval": 3000, // Milliseconds + "bounds": { + "x": 64, // Top-left X + "y": 64, // Top-left Y + "width": 192, // Width in pixels + "height": 192 // Height in pixels + } +} +``` + +### Sprite Sheets + +Available sprite sheets: +- `hacker` - Default agent sprite +- `hacker-red` - Red variant +- `hacker-green` - Green variant +- `hacker-yellow` - Yellow variant + +### RFID Cards on NPCs + +NPCs can carry RFID cards that can be scanned: + +```json +"rfidCard": { + "card_id": "employee_badge", + "rfid_protocol": "EM4100", + "name": "Employee Badge" +} +``` + +--- + +## Ink Dialogue System + +### Basic Structure + +```ink +VAR trust_level = 0 +VAR knows_secret = false + +=== start === +#speaker:npc_name +Hello! How can I help you? +-> hub + +=== hub === ++ [Ask about security] + -> topic_security ++ [Say goodbye] + #exit_conversation + See you later! + -> END +``` + +### Ink Tags (Special Commands) + +**Speaker** +```ink +#speaker:npc_name +``` +Sets who is speaking (for avatar display) + +**Display/Mood** +```ink +#display:guard-patrol +#display:guard-confrontation +#display:guard-hostile +``` +Controls NPC visual state/mood + +**Exit Conversation** +```ink +#exit_conversation +``` +Closes dialogue window + +**Hostility** +```ink +#hostile:npc_id +``` +Marks NPC as hostile (affects gameplay) + +**Patrol Control** +```ink +#patrol_mode:on +#patrol_mode:off +``` +Toggles NPC patrol behavior + +### Variables + +**Declare at top:** +```ink +VAR variable_name = 0 +VAR boolean_flag = false +``` + +**Modify:** +```ink +~ trust_level += 1 +~ knows_secret = true +``` + +**Conditional:** +```ink +{trust_level >= 3: + You seem trustworthy. +- else: + I don't know you well enough. +} +``` + +### Choices + +**Basic:** +```ink +* [Choice text] + Response text + -> next_knot +``` + +**Conditional:** +```ink ++ {trust_level >= 2} [Restricted choice] + -> privileged_content +``` + +**Once-only:** +```ink ++ {not topic_discussed} [New topic] + ~ topic_discussed = true + -> topic_knot +``` + +### Hub Pattern (Recommended) + +```ink +=== hub === ++ {condition1} [Choice 1] + -> branch1 ++ {condition2} [Choice 2] + -> branch2 ++ [Always available] + -> branch3 + +=== branch1 === +Content... +-> hub // Return to hub +``` + +--- + +## RFID System + +### RFID Protocols + +Four security levels from weakest to strongest: + +1. **EM4100** (125kHz) - Instant clone + ```json + "rfid_protocol": "EM4100" + ``` + - No encryption + - Instant cloning + - Used in old hotels, parking garages + +2. **MIFARE Classic (Weak Defaults)** - Instant crack + ```json + "rfid_protocol": "MIFARE_Classic_Weak_Defaults" + ``` + - Uses factory default keys + - Dictionary attack succeeds instantly + - Used in cheap hotels, old transit cards + +3. **MIFARE Classic (Custom Keys)** - Requires attack (~30 sec) + ```json + "rfid_protocol": "MIFARE_Classic_Custom_Keys" + ``` + - Custom encryption keys + - Requires Darkside attack (30 seconds) + - Used in corporate badges, banks + +4. **MIFARE DESFire** - UID emulation only + ```json + "rfid_protocol": "MIFARE_DESFire" + ``` + - Military-grade AES encryption + - Cannot be cracked + - Only UID emulation works (if reader is poorly configured) + - Used in government, military, high-security + +### RFID Workflow + +1. Player needs RFID cloner in inventory +2. Player approaches NPC with RFID card or scans keycard object +3. Player uses cloner to scan/attack card +4. Player emulates card at RFID reader/door + +--- + +## Player Configuration + +```json +"player": { + "id": "player", + "displayName": "Agent Name", + "spriteSheet": "hacker", + "spriteTalk": "assets/characters/hacker-talk.png", + "spriteConfig": { + "idleFrameStart": 20, + "idleFrameEnd": 23 + }, + "startX": 200, + "startY": 200 +} +``` + +--- + +## Puzzle Chains and Dependencies + +### Example: Multi-Step Puzzle Chain + +``` +1. Read note in Reception + ↓ +2. Get password from note + ↓ +3. Unlock PC in Office + ↓ +4. Read file on PC to get PIN code + ↓ +5. Use PIN to unlock Safe + ↓ +6. Get key from Safe + ↓ +7. Use key to unlock CEO office + ↓ +8. Find final evidence +``` + +### Implementation Pattern + +```json +{ + "rooms": { + "reception": { + "objects": [ + { + "type": "notes", + "text": "PIN code is 7391", + "takeable": true + } + ], + "connections": { + "north": "office" + } + }, + "office": { + "locked": true, + "lockType": "pin", + "requires": "7391", + "objects": [ + { + "type": "key", + "key_id": "final_key", + "takeable": true + } + ] + } + } +} +``` + +### Dependency Types + +1. **Information Dependencies**: Clue → Solution +2. **Tool Dependencies**: Need tool to interact with object +3. **Access Dependencies**: Need key/card/password to access area +4. **Sequential Dependencies**: A → B → C must be done in order + +--- + +## Event System + +### Event Mappings (for Phone NPCs) + +```json +"eventMappings": [ + { + "eventPattern": "item_picked_up:lockpick", + "targetKnot": "on_lockpick_pickup", + "onceOnly": true, + "cooldown": 0 + }, + { + "eventPattern": "minigame_completed", + "targetKnot": "on_lockpick_success", + "condition": "data.minigameName && data.minigameName.includes('Lockpick')", + "cooldown": 10000 + }, + { + "eventPattern": "door_unlocked", + "targetKnot": "on_door_unlocked", + "cooldown": 8000 + }, + { + "eventPattern": "room_entered:ceo", + "targetKnot": "on_ceo_office_entered", + "onceOnly": true + } +] +``` + +### Available Event Patterns + +- `item_picked_up:item_type` - When specific item is picked up +- `item_picked_up:*` - When any item is picked up +- `minigame_completed` - When minigame succeeds +- `minigame_failed` - When minigame fails +- `door_unlocked` - When any door is unlocked +- `door_unlock_attempt` - When door unlock is attempted +- `object_interacted` - When object is interacted with +- `room_entered` - When any room is entered +- `room_entered:room_id` - When specific room is entered +- `room_discovered` - When new room is discovered + +### Event Properties + +- **eventPattern**: Pattern to match (supports wildcards) +- **targetKnot**: Which Ink knot to jump to +- **condition**: JavaScript condition (optional) +- **onceOnly**: Only trigger once (default: false) +- **cooldown**: Milliseconds before can trigger again +- **maxTriggers**: Maximum number of times can trigger + +--- + +## Best Practices + +### Puzzle Design + +1. **Provide multiple clues** - Don't rely on single puzzle solution path +2. **Show don't tell** - Let players discover rather than being told +3. **Progressive difficulty** - Start easy, build complexity +4. **Clear feedback** - Let players know when they're on right track +5. **Avoid dead ends** - Always provide way forward + +### Narrative Integration + +1. **Story justifies puzzles** - Why are these obstacles here? +2. **NPCs provide hints** - Dialogue should guide without spoiling +3. **Environmental storytelling** - Objects and notes tell story +4. **Consistent world** - All elements support the scenario theme + +### Technical Constraints + +1. **Room connections** - Ensure all connected rooms are defined +2. **Object dependencies** - Verify all required items exist +3. **Lock consistency** - requires field must match available keys/codes +4. **NPC bounds** - Patrol bounds must fit within room +5. **Sprite references** - Use available sprite sheets only + +### Performance + +1. **Limit NPCs per room** - Max 8-10 NPCs per room +2. **Optimize patrol areas** - Smaller bounds = better performance +3. **Event cooldowns** - Prevent event spam with appropriate cooldowns + +--- + +## Example: Complete Mini-Scenario + +```json +{ + "scenario_brief": "Infiltrate the office and recover the stolen data.", + "startRoom": "lobby", + "startItemsInInventory": [ + { + "type": "lockpick", + "name": "Lock Pick Kit", + "takeable": true + } + ], + "rooms": { + "lobby": { + "type": "room_reception", + "connections": { + "north": "office" + }, + "objects": [ + { + "type": "notes", + "name": "Security Code", + "takeable": true, + "readable": true, + "text": "Office safe code: 9573" + } + ] + }, + "office": { + "type": "room_office", + "locked": true, + "lockType": "key", + "requires": "office_key", + "keyPins": [100, 50, 0, 150], + "connections": { + "south": "lobby" + }, + "objects": [ + { + "type": "safe", + "name": "Wall Safe", + "takeable": false, + "locked": true, + "lockType": "pin", + "requires": "9573", + "contents": [ + { + "type": "notes", + "name": "Stolen Data", + "isEndGoal": true, + "readable": true, + "text": "You found the stolen data! Mission complete!" + } + ] + } + ] + } + } +} +``` + +--- + +## Quick Reference Tables + +### Lock Type Summary + +| Lock Type | Requires | Tools Needed | Difficulty | +|-----------|----------|--------------|------------| +| key | key_id | Key or Lockpick | Varies | +| pin | "1234" | None (or PIN cracker for hints) | Easy | +| password | "password" | None | Easy | +| bluetooth | "bluetooth" | Bluetooth Scanner | Medium | +| rfid | card_id | RFID Cloner | Varies by protocol | +| lockpick | None | Lockpick Kit | Varies | + +### Object Type Summary + +| Type | Takeable | Containers | Readable | Locked | +|------|----------|------------|----------|--------| +| notes | Usually | No | Yes | No | +| phone | No | No | Yes | No | +| pc | No | Yes | Yes | Usually | +| tablet | Yes | No | No | Usually | +| key | Yes | No | No | No | +| safe | No | Yes | No | Yes | +| suitcase | No | Yes | No | Usually | +| lockpick | Yes | No | No | No | +| rfid_cloner | Yes | No | No | No | +| keycard | Yes | No | No | No | + +--- + +**Last Updated:** 2025-01-17 +**Version:** 1.0 +**For Questions:** See `docs/GAME_DESIGN.md` or `docs/ROOM_GENERATION.md`