Files
BreakEscape/planning_notes/npc/01_INK_STRUCTURE.md
Z. Cliffe Schreuders 887e5f6443 Add NPC integration planning documents and example scenario
- Created `05_EXAMPLE_SCENARIO.md` with a complete Ink script for the Biometric Breach scenario featuring NPCs Alice and Bob.
- Added `QUICK_REFERENCE.md` as a cheat sheet for NPC system components, event types, and common patterns.
- Introduced `README.md` as an index for NPC integration planning, outlining document structure and key concepts.
2025-10-29 00:18:22 +00:00

10 KiB

Ink Script Structure for Break Escape NPCs

Ink Language Primer

Ink is a narrative scripting language designed for branching dialogues and interactive fiction. Key concepts:

  • Knots: Major story sections (like functions)
  • Stitches: Sub-sections within knots
  • Choices: Player decisions that branch the story
  • Variables: Track state and conditions
  • External Functions: Call JavaScript from Ink
  • Tags: Metadata for custom processing

Break Escape Ink Conventions

File Structure

Each scenario has one Ink file with this structure:

// ============================================================
// Break Escape: Biometric Breach NPCs
// Compiled: 2025-10-28
// ============================================================

// Global variables for tracking player progress
VAR player_entered_lab = false
VAR player_found_fingerprint = false
VAR player_unlocked_server = false
VAR relationship_alice = 0  // -10 to +10 scale
VAR trust_level = 0

// External functions that can affect game state
EXTERNAL unlock_door(door_id)
EXTERNAL give_item(item_type)
EXTERNAL show_notification(message)

// ============================================================
// NPC: Alice (Security Analyst)
// ============================================================

=== alice_intro ===
# speaker: Alice
# type: bark
# trigger: game_start
Hey! I'm Alice from security. Things are crazy here tonight.
-> alice_hub

=== alice_hub ===
# speaker: Alice
# type: conversation
// Main conversation hub - player can return here
+ [What's going on?] -> alice_explain_situation
+ [Who are you?] -> alice_introduction
+ {player_found_fingerprint} [I found a fingerprint] -> alice_fingerprint_found
+ [Goodbye] -> END

=== alice_explain_situation ===
# speaker: Alice
There's been a security breach. Someone accessed the biometrics lab.
I need your help investigating - can you check the reception area?
~ relationship_alice++
-> alice_hub

// ... more conversation branches ...

Knot Naming Conventions

Format: {npc_name}_{event_or_topic}

Categories:

1. Intro Knots (Initial Contact)

  • alice_intro - First message when game starts
  • bob_first_contact - Triggered by specific event

2. Hub Knots (Conversation Menus)

  • alice_hub - Main menu with all available choices
  • bob_mission_hub - Subset menu for mission-related topics

3. Event-Triggered Knots (Barks)

  • alice_player_entered_lab - Player enters specific room
  • bob_found_item_x - Player picks up important item
  • alice_failed_minigame - React to player failure

4. Topic Knots (Dialogue Trees)

  • alice_about_suspect - Discussion about suspect
  • bob_explain_crypto - Technical explanation

5. Conditional Knots (Progress-Gated)

  • alice_late_game - Only available after certain progress
  • bob_trust_high - Requires high relationship score

Tag System

Tags provide metadata for the game engine to process Ink output.

Standard Tags

=== my_knot ===
# speaker: Alice              // NPC name
# type: bark                  // bark|conversation|hint
# trigger: player_entered_lab // Game event that triggers this
# priority: high              // low|medium|high (bark queue)
# delay: 3                    // Seconds delay before showing
# once: true                  // Only trigger once

Tag Meanings:

  • speaker: Which NPC is speaking (matches contact name)
  • type:
    • bark - Short notification during gameplay
    • conversation - Full phone chat dialogue
    • hint - Subtle clue/help message
  • trigger: Game event name (see Event System doc)
  • priority: Bark queue priority
  • delay: Wait X seconds before showing
  • once: If true, never trigger again (even on replay)

Variables and State

Player Progress Variables

Track what the player has done:

VAR player_entered_lab = false
VAR player_unlocked_door_reception = false
VAR player_collected_fingerprint_kit = false
VAR player_completed_lockpick_minigame = false
VAR current_room = "reception"

NPC Relationship Variables

Track player's relationship with each NPC:

VAR relationship_alice = 0    // -10 (hostile) to +10 (trusted)
VAR trust_bob = 0
VAR alice_knows_player_lied = false

Scenario State Variables

Track overall story progress:

VAR suspect_identified = false
VAR prototype_recovered = false
VAR mission_complete = false
VAR investigation_phase = 1  // 1, 2, 3, etc.

External Functions

Ink can call JavaScript functions to affect the game:

=== alice_gives_key ===
Here, take this access card. It'll get you into the lab.
~ give_item("keycard_lab")
~ relationship_alice++
Good luck!
-> END

Planned External Functions

// Items & Inventory
EXTERNAL give_item(item_type)           // Add item to inventory
EXTERNAL remove_item(item_type)         // Remove item
EXTERNAL has_item(item_type)            // Check if player has item

// Doors & Access
EXTERNAL unlock_door(door_id)           // Unlock a specific door
EXTERNAL lock_door(door_id)             // Lock a door
EXTERNAL is_door_unlocked(door_id)      // Check door state

// UI & Notifications
EXTERNAL show_notification(message)      // Show game notification
EXTERNAL show_hint(message)             // Show subtle hint
EXTERNAL show_mission_update(message)   // Update mission objectives

// Game State Queries
EXTERNAL get_current_room()             // Returns current room ID
EXTERNAL get_game_time()                // Returns elapsed game time
EXTERNAL has_completed_minigame(type)   // Check minigame completion

// NPC State
EXTERNAL set_npc_mood(npc, mood)        // Change NPC mood
EXTERNAL get_relationship(npc)          // Get relationship value

Choice Patterns

Basic Choices

+ [Say yes] -> yes_branch
+ [Say no] -> no_branch
+ [Ask question] -> question_branch

Conditional Choices (Only Show If...)

+ {player_found_evidence} [Show the evidence] -> show_evidence
+ {trust_level >= 5} [Tell the truth] -> tell_truth
+ {not suspect_identified} [Ask about suspects] -> suspects

Sticky Choices (Reappear After Selection)

* [One-time choice] -> branch
+ [Repeatable choice] -> branch

Fallback Choices (Always Available)

+ [Goodbye] -> END
+ [Back] -> previous_hub

Dialogue Formatting

Speaker Indication

Use tags to identify speakers:

=== conversation ===
# speaker: Alice
I need to tell you something important.
# speaker: Bob
What is it?
# speaker: Alice
The prototype is missing.

Message Timing

Use special markers for message delays (chat-like pacing):

=== alice_thinking ===
# speaker: Alice
Hmm...
# wait: 1
Let me think about that.
# wait: 2
I might have an idea.

Emotional Context

Use tags to indicate tone:

=== alice_worried ===
# speaker: Alice
# emotion: worried
I'm really concerned about this breach.

Example: Complete NPC Conversation

// ============================================================
// NPC: Alice - Security Analyst
// ============================================================

VAR alice_met = false
VAR alice_trust = 0
VAR player_asked_about_breach = false

=== alice_initial_contact ===
# speaker: Alice
# type: bark
# trigger: game_start
# once: true
Hey! Security breach detected. I need your help ASAP.
~ alice_met = true
-> END

=== alice_hub ===
# speaker: Alice
# type: conversation
{alice_trust >= 5: You've been a huge help. What else can I do for you?}
{alice_trust < 5 and alice_trust >= 0: What do you need?}
{alice_trust < 0: I'm watching you. Make it quick.}

+ {not player_asked_about_breach} [What happened?] -> alice_explain_breach
+ {player_found_fingerprint} [I found a fingerprint] -> alice_fingerprint_reaction
+ {alice_trust >= 3} [Can you help me access the server room?] -> alice_server_access
+ [I need to go] -> alice_goodbye
-> END

=== alice_explain_breach ===
# speaker: Alice
Someone broke into the biometrics lab around 2 AM.
We need to figure out who it was and what they took.
~ player_asked_about_breach = true
~ alice_trust++
+ [How can I help?] -> alice_request_help
+ [Why me?] -> alice_explain_choice
-> alice_hub

=== alice_request_help ===
# speaker: Alice
I need you to check the reception area for fingerprints.
Use your fingerprint kit on any surfaces that look suspicious.
~ show_notification("New objective: Check reception for fingerprints")
Great! Let me know what you find.
-> alice_hub

=== alice_fingerprint_reaction ===
# speaker: Alice
{alice_trust >= 5: Excellent work! Let me analyze this.}
{alice_trust < 5: Good. Send it to the lab for analysis.}
# wait: 2
This matches someone in our database...
It's the research director!
~ alice_trust++
~ suspect_identified = true
-> alice_hub

=== alice_server_access ===
{alice_trust >= 5:
    # speaker: Alice
    Sure thing. Here's my access card.
    ~ give_item("alice_keycard")
    ~ alice_trust++
    Be careful in there!
    -> alice_hub
- else:
    # speaker: Alice
    I can't give you that kind of access yet.
    Prove yourself first.
    -> alice_hub
}

=== alice_goodbye ===
# speaker: Alice
Stay safe out there.
-> END

Best Practices

  1. Keep barks short - Max 1-2 sentences for gameplay notifications
  2. Hub pattern - Always provide a way back to main menu
  3. Conditional variety - Same knot should have different text based on state
  4. Meaningful choices - Each choice should feel impactful
  5. State tracking - Update variables to reflect player decisions
  6. Graceful endings - Always provide a way to exit conversation
  7. Test conditionals - Ensure all paths are reachable
  8. Comment liberally - Explain complex logic and triggers

Debugging Tips

Testing Individual Knots

// Add a debug knot to jump to any section
=== DEBUG_START ===
+ [Test Alice intro] -> alice_intro
+ [Test Bob mission] -> bob_mission_start
+ [Test late game] -> alice_late_game

Logging State

// Use external function to log to console
~ show_notification("Trust level: {alice_trust}")
~ show_notification("Current room: {current_room}")

Commenting Out Choices

// + [Debug choice] -> test_branch
// Temporarily disabled for testing

Next Steps

See 05_EXAMPLE_SCENARIO.md for a complete working example of an NPC script for the Biometric Breach scenario.