Files
BreakEscape/docs/LOCK_KEY_QUICK_START.md
Z. Cliffe Schreuders bd8b9a4f85 docs: Add comprehensive RFID keycard lock system planning documentation
Planning documentation for new RFID keycard lock system feature:

Documentation:
- Complete planning docs in planning_notes/rfid_keycard/
- 7 planning documents (~16,000 words)
- 90+ implementation tasks with estimates
- Technical architecture and code design
- Asset specifications and creation guides

Assets Created:
- 4 keycard sprite variants (CEO, Security, Maintenance, Generic)
- RFID cloner device sprite (Flipper Zero-inspired)
- 2 icon assets (RFID icon, NFC waves)
- Helper scripts for placeholder creation

System Documentation:
- Lock & key system architecture reference
- Lock & key quick start guide

Feature Overview:
- New lock type: "rfid"
- New items: keycard, rfid_cloner
- New minigame: Flipper Zero-style RFID reader/cloner
- Ink tag support: # clone_keycard:name|hex
- Inventory integration: Click cards to clone
- Two modes: Unlock (tap/emulate) and Clone (read/save)

Implementation:
- Estimated time: 91 hours (~11 working days)
- 11 new files, 5 modified files
- Full test plan included
- Ready for immediate implementation

All placeholder assets functional for development.
Documentation provides complete roadmap from planning to deployment.
2025-11-15 23:48:15 +00:00

6.7 KiB

Lock & Key System - Quick Start Guide

Quick Reference: Where Things Are

Adding a Locked Door/Room

File: scenario.json

{
  "rooms": {
    "office": {
      "locked": true,
      "lockType": "key",        // key, pin, password, biometric, bluetooth
      "requires": "office_key",  // ID of key/password/etc.
      "keyPins": [32, 28, 35, 30]  // Optional: for pin tumbler locks
    }
  }
}

Adding a Key to Inventory

File: scenario.json

{
  "startItemsInInventory": [
    {
      "type": "key",
      "name": "Office Key",
      "key_id": "office_key",        // Must match "requires" in lock
      "keyPins": [32, 28, 35, 30],   // Must match lock's keyPins
      "observations": "A brass key"
    }
  ]
}

Adding a Key in a Container

File: scenario.json

{
  "type": "safe",
  "locked": true,
  "lockType": "password",
  "requires": "1234",
  "contents": [
    {
      "type": "key",
      "name": "CEO Key",
      "key_id": "ceo_key",
      "keyPins": [40, 35, 38, 32, 36]
    }
  ]
}

System Entry Points

When Player Clicks a Locked Object

interactions.js: handleObjectInteraction(sprite)
  → Gets scenario data from sprite
  → Calls: handleUnlock(lockable, 'door'|'item')

Unlock System Decision Tree

unlock-system.js: handleUnlock()
  ├─ Lock type: 'key'
  │   ├─ Has keys in inventory? → Key Selection Minigame
  │   └─ Has lockpick? → Lockpicking Minigame
  ├─ Lock type: 'pin' → PIN Entry Minigame
  ├─ Lock type: 'password' → Password Entry Minigame
  ├─ Lock type: 'biometric' → Check fingerprint samples
  └─ Lock type: 'bluetooth' → Check BLE devices

Key Code Files

Primary Lock Logic

js/systems/
  ├─ unlock-system.js          [400 lines] Main unlock handler
  ├─ key-lock-system.js        [370 lines] Key-lock mappings & cuts
  ├─ inventory.js              [630 lines] Item/key management
  └─ interactions.js           [600 lines] Object interaction detector

Lockpicking Minigame (Pin Tumbler)

js/minigames/lockpicking/
  ├─ lockpicking-game-phaser.js    [300+ lines] Main controller
  ├─ pin-management.js              [150+ lines] Pin creation
  ├─ key-operations.js              [100+ lines] Key handling
  ├─ hook-mechanics.js              [100+ lines] Tension simulation
  ├─ pin-visuals.js                 [80+ lines]  Rendering
  └─ lock-configuration.js          [60+ lines]  State storage

Minigame Framework

js/minigames/framework/
  ├─ minigame-manager.js       [180 lines] Framework lifecycle
  ├─ base-minigame.js          [150+ lines] Base class
  └─ index.js                  [96 lines]  Registration

Conversation Integration

js/minigames/helpers/
  └─ chat-helpers.js           [326 lines] Ink tag processing
js/minigames/person-chat/
  └─ person-chat-minigame.js   [300+ lines] Conversation UI

Key Data Structures

Pin Tumbler Lock (During Gameplay)

pin = {
  index: 0,
  binding: 2,                    // Which pin sets first (0-3)
  isSet: false,
  keyPinLength: 32,              // Lock pin height (pixels)
  driverPinLength: 43,           // Spring pin height
  keyPinHeight: 0,               // Current key pin position
  container: Phaser.Container
}

Key Data (In Inventory)

key = {
  scenarioData: {
    type: 'key',
    name: 'Office Key',
    key_id: 'office_key',
    keyPins: [32, 28, 35, 30],   // Lock pin heights this key opens
    observations: 'A brass key'
  },
  objectId: 'inventory_key_office_key'
}

Lock Requirements (From Scenario)

lockRequirements = {
  lockType: 'key',               // Type of lock
  requires: 'office_key',        // Key ID / password / etc.
  keyPins: [32, 28, 35, 30],    // For scenario-defined locks
  difficulty: 'medium'           // For lockpicking
}

Common Workflows

Scenario Designer: Add New Key-Protected Door

  1. Define the lock in room:

    {
      "room_name": {
        "locked": true,
        "lockType": "key",
        "requires": "storage_key",
        "keyPins": [30, 32, 28, 35]  // IMPORTANT: unique pin heights
      }
    }
    
  2. Add key to inventory or container:

    {
      "type": "key",
      "name": "Storage Key",
      "key_id": "storage_key",      // Must match "requires"
      "keyPins": [30, 32, 28, 35]   // Must match lock exactly
    }
    
  3. Test: Player should see key icon when near lock

Scenario Designer: Add PIN-Protected Door

{
  "room_name": {
    "locked": true,
    "lockType": "pin",
    "requires": "4567"              // The PIN code
  }
}

Scenario Designer: Add Password-Protected Safe

{
  "type": "safe",
  "locked": true,
  "lockType": "password",
  "requires": "correct_password",
  "contents": [
    { "type": "notes", "name": "Secret Document" }
  ]
}

Ink Writer: Give Key During Conversation

In .ink file:

=== hub ===
# speaker:npc
Here's the key you'll need!
# give_item:key|Storage Key

What else can I help with?

This triggers:

  1. NPC gives item to player
  2. Opens container minigame showing the key
  3. Player can take it to inventory

Debugging Tips

Check Key-Lock Mappings

In browser console:

window.showKeyLockMappings()  // Shows all key-lock pairs

Check Player Inventory

console.log(window.inventory.items)      // All items
console.log(window.inventory.keyRing)    // Keys specifically

Check Lock Requirements

window.getLockRequirementsForDoor(doorSprite)  // Door lock details
window.getLockRequirementsForItem(item)        // Item lock details

Force Unlock (Testing)

window.DISABLE_LOCKS = true  // Disables all locks temporarily

Common Errors & Solutions

Error Cause Solution
Key doesn't unlock door key_id doesn't match requires Ensure exact match
Wrong pins in lock keyPins mismatch Key's keyPins must match lock's keyPins
Key doesn't appear in inventory Item not in startItemsInInventory Add it to scenario or container
Conversation tag not working Tag format incorrect Use # action:param format
Minigame won't start Framework not initialized Check if MinigameFramework is loaded

Implementation Checklist

For adding a new lock type (e.g., RFID/Keycard):

  • Add case in unlock-system.js switch statement
  • Check inventory for matching keycard
  • Verify access level (if applicable)
  • Call unlockTarget() on success
  • Show appropriate alert messages
  • Update scenario schema with examples
  • Add documentation with tag examples
  • Test with example scenario