mirror of
https://github.com/cliffe/BreakEscape.git
synced 2026-02-20 13:50:46 +00:00
docs(rfid): Second review - fix critical conversation pattern error
CRITICAL ISSUE: Planned return-to-conversation pattern was fundamentally incorrect. Fixed to use proven window.pendingConversationReturn pattern from container minigame. Key changes: - NEW: review2/CRITICAL_FINDINGS.md - 8 findings with detailed analysis - NEW: review2/README.md - Quick action guide - FIXED: Task 3.4 - Simplified conversation return (2.5h → 1h) - ADDED: Task 3.9 - returnToConversationAfterRFID function (0.5h) - FIXED: Section 2c in architecture doc - Correct minimal context pattern - Updated time estimates: 102h → 101h npcConversationStateManager handles all conversation state automatically. No manual Ink story save/restore needed. Reference: /js/minigames/container/container-minigame.js:720-754 Risk: HIGH → MEDIUM (after fix) Confidence: 95% → 98%
This commit is contained in:
@@ -396,6 +396,9 @@ These events allow:
|
||||
|
||||
### 2c. Return to Conversation Pattern
|
||||
|
||||
**IMPORTANT**: Uses proven `window.pendingConversationReturn` pattern from container minigame.
|
||||
**Reference**: `/js/minigames/container/container-minigame.js:720-754` and `/js/systems/npc-game-bridge.js:237-242`
|
||||
|
||||
**File**: `/js/minigames/helpers/chat-helpers.js` (Updated clone_keycard case)
|
||||
|
||||
```javascript
|
||||
@@ -425,33 +428,18 @@ case 'clone_keycard':
|
||||
key_id: `cloned_${cardName.toLowerCase().replace(/\s+/g, '_')}`
|
||||
};
|
||||
|
||||
// Store conversation context for return
|
||||
const conversationContext = {
|
||||
// Set pending conversation return (MINIMAL CONTEXT!)
|
||||
// Conversation state automatically managed by npcConversationStateManager
|
||||
window.pendingConversationReturn = {
|
||||
npcId: window.currentConversationNPCId,
|
||||
conversationState: this.currentStory?.saveState() // Save ink state
|
||||
type: window.currentConversationMinigameType || 'person-chat'
|
||||
};
|
||||
|
||||
// Start RFID minigame in clone mode
|
||||
if (window.startRFIDMinigame) {
|
||||
window.startRFIDMinigame(null, null, {
|
||||
mode: 'clone',
|
||||
cardToClone: cardData,
|
||||
returnToConversation: true,
|
||||
conversationContext: conversationContext,
|
||||
onComplete: (success, cloneResult) => {
|
||||
if (success) {
|
||||
result.success = true;
|
||||
result.message = `📡 Cloned: ${cardName}`;
|
||||
if (ui) ui.showNotification(result.message, 'success');
|
||||
|
||||
// Return to conversation after short delay
|
||||
setTimeout(() => {
|
||||
if (window.returnToConversationAfterRFID) {
|
||||
window.returnToConversationAfterRFID(conversationContext);
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
cardToClone: cardData
|
||||
});
|
||||
}
|
||||
|
||||
@@ -461,6 +449,73 @@ case 'clone_keycard':
|
||||
break;
|
||||
```
|
||||
|
||||
**Return Function**: `/js/minigames/rfid/rfid-minigame.js`
|
||||
|
||||
```javascript
|
||||
/**
|
||||
* Return to conversation after RFID minigame
|
||||
* Follows exact pattern from container minigame
|
||||
*/
|
||||
export function returnToConversationAfterRFID() {
|
||||
console.log('Returning to conversation after RFID minigame');
|
||||
|
||||
// Check if there's a pending conversation return
|
||||
if (window.pendingConversationReturn) {
|
||||
const conversationState = window.pendingConversationReturn;
|
||||
|
||||
// Clear the pending return state
|
||||
window.pendingConversationReturn = null;
|
||||
|
||||
console.log('Restoring conversation:', conversationState);
|
||||
|
||||
// Restart the appropriate conversation minigame
|
||||
if (window.MinigameFramework) {
|
||||
// Small delay to ensure RFID minigame is fully closed
|
||||
setTimeout(() => {
|
||||
if (conversationState.type === 'person-chat') {
|
||||
// Restart person-chat minigame
|
||||
window.MinigameFramework.startMinigame('person-chat', null, {
|
||||
npcId: conversationState.npcId,
|
||||
fromTag: true // Flag to indicate resuming from tag action
|
||||
});
|
||||
} else if (conversationState.type === 'phone-chat') {
|
||||
// Restart phone-chat minigame
|
||||
window.MinigameFramework.startMinigame('phone-chat', null, {
|
||||
npcId: conversationState.npcId,
|
||||
fromTag: true
|
||||
});
|
||||
}
|
||||
}, 50);
|
||||
}
|
||||
} else {
|
||||
console.log('No pending conversation return found');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Called from RFIDMinigame.complete()**:
|
||||
|
||||
```javascript
|
||||
complete(success) {
|
||||
// Check if we need to return to conversation
|
||||
if (window.pendingConversationReturn && window.returnToConversationAfterRFID) {
|
||||
console.log('Returning to conversation after RFID minigame');
|
||||
setTimeout(() => {
|
||||
window.returnToConversationAfterRFID();
|
||||
}, 100);
|
||||
}
|
||||
|
||||
// Call parent complete
|
||||
super.complete(success, this.gameResult);
|
||||
}
|
||||
```
|
||||
|
||||
**Why This Pattern**:
|
||||
- **Automatic State Management**: `npcConversationStateManager` saves/restores Ink story state automatically
|
||||
- **Proven**: Already working in container → conversation flow
|
||||
- **Simpler**: No manual Ink state manipulation needed
|
||||
- **Reliable**: Restarting conversation automatically restores state via `restoreNPCState()`
|
||||
|
||||
### 3. RFID UI Renderer
|
||||
|
||||
**File**: `/js/minigames/rfid/rfid-ui.js`
|
||||
|
||||
@@ -527,11 +527,12 @@ File: `/js/systems/minigame-starters.js`
|
||||
|
||||
### Task 3.4: Add clone_keycard Tag with Return to Conversation
|
||||
**Priority**: P0 (Blocker)
|
||||
**Estimated Time**: 2.5 hours
|
||||
**Estimated Time**: 1 hour
|
||||
|
||||
File: `/js/minigames/helpers/chat-helpers.js`
|
||||
|
||||
**Important**: Must return to conversation after cloning (like notes minigame)
|
||||
**Important**: Uses proven `window.pendingConversationReturn` pattern from container minigame.
|
||||
**Reference**: See `/js/minigames/container/container-minigame.js:720-754` and `/js/systems/npc-game-bridge.js:237-242`
|
||||
|
||||
- [ ] Add new case `'clone_keycard'` in processGameActionTags()
|
||||
- [ ] Parse param: `cardName|cardHex`
|
||||
@@ -544,32 +545,35 @@ File: `/js/minigames/helpers/chat-helpers.js`
|
||||
- [ ] rfid_card_number: `parseInt(cardHex.substring(2, 6), 16)`
|
||||
- [ ] rfid_protocol: 'EM4100'
|
||||
- [ ] key_id: `cloned_${cardName.toLowerCase().replace(/\s+/g, '_')}`
|
||||
- [ ] **Store conversation context**:
|
||||
- [ ] **Set pending conversation return** (MINIMAL CONTEXT!):
|
||||
```javascript
|
||||
const conversationContext = {
|
||||
window.pendingConversationReturn = {
|
||||
npcId: window.currentConversationNPCId,
|
||||
conversationState: this.currentStory?.saveState()
|
||||
type: window.currentConversationMinigameType || 'person-chat'
|
||||
};
|
||||
```
|
||||
- [ ] Call startRFIDMinigame() with clone params
|
||||
- [ ] Pass `returnToConversation: true`
|
||||
- [ ] Pass `conversationContext`
|
||||
- [ ] Set onComplete callback with return:
|
||||
- [ ] Call startRFIDMinigame() with clone params only:
|
||||
```javascript
|
||||
setTimeout(() => {
|
||||
if (window.returnToConversationAfterRFID) {
|
||||
window.returnToConversationAfterRFID(conversationContext);
|
||||
}
|
||||
}, 500);
|
||||
window.startRFIDMinigame(null, null, {
|
||||
mode: 'clone',
|
||||
cardToClone: cardData
|
||||
});
|
||||
```
|
||||
- [ ] Show notification on success/failure
|
||||
|
||||
**Acceptance Criteria**:
|
||||
- Tag triggers clone minigame
|
||||
- Card data parsed correctly from tag
|
||||
- Conversation resumes after cloning
|
||||
- Conversation resumes after cloning (handled by returnToConversationAfterRFID)
|
||||
- Conversation state automatically restored by npcConversationStateManager
|
||||
- Saved cards work for unlocking
|
||||
|
||||
**Why This Pattern**:
|
||||
- npcConversationStateManager automatically saves/restores story state
|
||||
- No manual Ink state manipulation needed
|
||||
- Follows exact pattern from container minigame (proven to work)
|
||||
- Simpler and more reliable than manual state management
|
||||
|
||||
**Test Ink**:
|
||||
```ink
|
||||
* [Secretly clone keycard]
|
||||
@@ -693,13 +697,86 @@ File: Main Phaser scene where assets are loaded (likely `js/game.js` or `js/scen
|
||||
- Icons display for RFID interactions
|
||||
|
||||
**Note**: Asset loading pattern varies by project structure. Look for existing asset loading in:
|
||||
- `js/game.js`
|
||||
- `js/core/game.js` (confirmed location)
|
||||
- `js/scenes/preload.js`
|
||||
- `js/scenes/boot.js`
|
||||
- Or similar Phaser scene files
|
||||
|
||||
---
|
||||
|
||||
### Task 3.9: Implement Return to Conversation Function
|
||||
**Priority**: P0 (Blocker)
|
||||
**Estimated Time**: 30 minutes
|
||||
|
||||
File: `/js/minigames/rfid/rfid-minigame.js`
|
||||
|
||||
**Important**: Copy exact pattern from container minigame - proven to work correctly.
|
||||
**Reference**: `/js/minigames/container/container-minigame.js:720-754`
|
||||
|
||||
Create function that returns player to conversation after RFID minigame completes.
|
||||
|
||||
- [ ] Export `returnToConversationAfterRFID()` function
|
||||
- [ ] Check if `window.pendingConversationReturn` exists
|
||||
- [ ] If not, log "No pending conversation return" and return early
|
||||
- [ ] Extract conversationState from `window.pendingConversationReturn`
|
||||
- [ ] Clear the pending return: `window.pendingConversationReturn = null`
|
||||
- [ ] Log the conversation restoration
|
||||
- [ ] Restart appropriate conversation minigame with 50ms delay:
|
||||
```javascript
|
||||
if (window.MinigameFramework) {
|
||||
setTimeout(() => {
|
||||
if (conversationState.type === 'person-chat') {
|
||||
window.MinigameFramework.startMinigame('person-chat', null, {
|
||||
npcId: conversationState.npcId,
|
||||
fromTag: true // Flag to indicate resuming from tag action
|
||||
});
|
||||
} else if (conversationState.type === 'phone-chat') {
|
||||
window.MinigameFramework.startMinigame('phone-chat', null, {
|
||||
npcId: conversationState.npcId,
|
||||
fromTag: true
|
||||
});
|
||||
}
|
||||
}, 50);
|
||||
}
|
||||
```
|
||||
- [ ] Add to RFIDMinigame `complete()` method:
|
||||
```javascript
|
||||
complete(success) {
|
||||
// Check if we need to return to conversation
|
||||
if (window.pendingConversationReturn && window.returnToConversationAfterRFID) {
|
||||
console.log('Returning to conversation after RFID minigame');
|
||||
setTimeout(() => {
|
||||
window.returnToConversationAfterRFID();
|
||||
}, 100);
|
||||
}
|
||||
|
||||
// Call parent complete
|
||||
super.complete(success, this.gameResult);
|
||||
}
|
||||
```
|
||||
|
||||
**Acceptance Criteria**:
|
||||
- Function follows exact pattern from container minigame
|
||||
- Conversation resumes with correct NPC
|
||||
- Works for both person-chat and phone-chat types
|
||||
- Story state automatically restored by npcConversationStateManager (no manual state handling)
|
||||
- Logs help with debugging
|
||||
- 50ms delay ensures RFID cleanup completes first
|
||||
|
||||
**Test Case**:
|
||||
1. Start conversation with NPC
|
||||
2. Trigger # clone_keycard tag
|
||||
3. Complete clone minigame
|
||||
4. Conversation should resume at same point (state preserved automatically)
|
||||
|
||||
**Why This Works**:
|
||||
- npcConversationStateManager saves state after every choice
|
||||
- Restarting conversation automatically calls restoreNPCState()
|
||||
- No manual Ink state management needed
|
||||
- Pattern already proven in container → conversation flow
|
||||
|
||||
---
|
||||
|
||||
## Phase 4: Styling (Day 6)
|
||||
|
||||
### Task 4.1: Create Base RFID Minigame Styles
|
||||
@@ -1819,13 +1896,13 @@ File: `/README.md`
|
||||
|-------|----------------|
|
||||
| Phase 1: Core Infrastructure | 17 hours (+1 for improved validation/formulas) |
|
||||
| Phase 2: Minigame Controller | 8 hours |
|
||||
| Phase 3: System Integration | 9 hours (+2 for new integration tasks) |
|
||||
| Phase 3: System Integration | 8 hours (simplified conversation pattern) |
|
||||
| Phase 4: Styling | 15 hours |
|
||||
| Phase 5: Assets | 7 hours |
|
||||
| Phase 6: Testing & Integration | 15 hours (+3 for additional testing) |
|
||||
| Phase 7: Documentation & Polish | 15 hours |
|
||||
| Phase 8: Final Review | 16 hours (+5 for comprehensive review) |
|
||||
| **TOTAL** | **102 hours (~13 days)** |
|
||||
| **TOTAL** | **101 hours (~13 days)** |
|
||||
|
||||
**Note**: Time increased from original 91 hours due to improvements identified in implementation review:
|
||||
- Enhanced validation and RFID formula calculations
|
||||
|
||||
501
planning_notes/rfid_keycard/review2/CRITICAL_FINDINGS.md
Normal file
501
planning_notes/rfid_keycard/review2/CRITICAL_FINDINGS.md
Normal file
@@ -0,0 +1,501 @@
|
||||
# RFID Keycard System - Second Review: Critical Findings
|
||||
|
||||
**Date**: 2025-01-15
|
||||
**Review Type**: Deep code analysis and pattern verification
|
||||
**Status**: ⚠️ **CRITICAL ISSUES FOUND - PLANNING REQUIRES MAJOR CORRECTIONS**
|
||||
|
||||
---
|
||||
|
||||
## Executive Summary
|
||||
|
||||
A comprehensive second-pass review of the codebase has revealed **1 critical architectural error** and **several important improvements** to the RFID keycard planning documents. The most significant finding is that **the planned return-to-conversation pattern is fundamentally incorrect** and overcomplicated compared to the actual codebase pattern.
|
||||
|
||||
**Impact**: The current planning documents (particularly Task 3.4) specify a complex conversation state save/restore mechanism that **does not exist** in the codebase and would be **incompatible** with the actual conversation system.
|
||||
|
||||
---
|
||||
|
||||
## 🚨 CRITICAL ISSUE #1: Incorrect Return-to-Conversation Pattern
|
||||
|
||||
### Current Plan (WRONG):
|
||||
The planning documents in `02_IMPLEMENTATION_TODO.md` Task 3.4 and `01_TECHNICAL_ARCHITECTURE.md` Section 2c specify:
|
||||
|
||||
```javascript
|
||||
// Store conversation context
|
||||
const conversationContext = {
|
||||
npcId: window.currentConversationNPCId,
|
||||
conversationState: this.currentStory?.saveState() // ❌ WRONG!
|
||||
};
|
||||
|
||||
// Start minigame with return callback
|
||||
window.startRFIDMinigame(null, null, {
|
||||
mode: 'clone',
|
||||
cardToClone: cardData,
|
||||
returnToConversation: true,
|
||||
conversationContext: conversationContext, // ❌ WRONG!
|
||||
onComplete: (success, cloneResult) => {
|
||||
setTimeout(() => {
|
||||
if (window.returnToConversationAfterRFID) {
|
||||
window.returnToConversationAfterRFID(conversationContext); // ❌ WRONG!
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Actual Codebase Pattern (CORRECT):
|
||||
**Source**: `/js/minigames/container/container-minigame.js:720-754`
|
||||
|
||||
The existing return-to-conversation pattern used by the container minigame is **much simpler**:
|
||||
|
||||
#### 1. Setting the Pending Return:
|
||||
```javascript
|
||||
// Save minimal context
|
||||
window.pendingConversationReturn = {
|
||||
npcId: npcId,
|
||||
type: window.currentConversationMinigameType || 'person-chat'
|
||||
};
|
||||
|
||||
// Then start the minigame...
|
||||
```
|
||||
|
||||
#### 2. Returning to Conversation:
|
||||
```javascript
|
||||
export function returnToConversationAfterNPCInventory() {
|
||||
if (window.pendingConversationReturn) {
|
||||
const conversationState = window.pendingConversationReturn;
|
||||
|
||||
// Clear the pending return state
|
||||
window.pendingConversationReturn = null;
|
||||
|
||||
// Restart the conversation minigame
|
||||
if (window.MinigameFramework) {
|
||||
setTimeout(() => {
|
||||
if (conversationState.type === 'person-chat') {
|
||||
window.MinigameFramework.startMinigame('person-chat', null, {
|
||||
npcId: conversationState.npcId,
|
||||
fromTag: true
|
||||
});
|
||||
} else if (conversationState.type === 'phone-chat') {
|
||||
window.MinigameFramework.startMinigame('phone-chat', null, {
|
||||
npcId: conversationState.npcId,
|
||||
fromTag: true
|
||||
});
|
||||
}
|
||||
}, 50);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Why This Matters:
|
||||
|
||||
**The conversation state is managed automatically by `npcConversationStateManager`!**
|
||||
|
||||
**Source**: `/js/systems/npc-conversation-state.js` and `/js/minigames/person-chat/person-chat-minigame.js:312-320`
|
||||
|
||||
Every time a conversation starts, it **automatically**:
|
||||
1. Calls `npcConversationStateManager.restoreNPCState(npcId, story)` to restore previous state
|
||||
2. Saves state after choices with `npcConversationStateManager.saveNPCState(npcId, story)`
|
||||
3. Handles both mid-conversation state (full story state) and ended conversations (variables only)
|
||||
|
||||
**We don't need to manually save/restore conversation state!** The system does it automatically.
|
||||
|
||||
### Required Fix:
|
||||
|
||||
**In `01_TECHNICAL_ARCHITECTURE.md` Section 2c**, replace the entire example with:
|
||||
|
||||
```javascript
|
||||
// In chat-helpers.js, clone_keycard tag handler:
|
||||
case 'clone_keycard':
|
||||
if (param) {
|
||||
const [cardName, cardHex] = param.split('|').map(s => s.trim());
|
||||
|
||||
// Check for cloner
|
||||
const hasCloner = window.inventory.items.some(item =>
|
||||
item?.scenarioData?.type === 'rfid_cloner'
|
||||
);
|
||||
|
||||
if (!hasCloner) {
|
||||
if (ui) ui.showNotification('Need RFID cloner to clone cards', 'warning');
|
||||
break;
|
||||
}
|
||||
|
||||
// Generate card data
|
||||
const cardData = {
|
||||
name: cardName,
|
||||
rfid_hex: cardHex,
|
||||
rfid_facility: parseInt(cardHex.substring(0, 2), 16),
|
||||
rfid_card_number: parseInt(cardHex.substring(2, 6), 16),
|
||||
rfid_protocol: 'EM4100',
|
||||
key_id: `cloned_${cardName.toLowerCase().replace(/\s+/g, '_')}`
|
||||
};
|
||||
|
||||
// Set pending conversation return (MINIMAL CONTEXT!)
|
||||
window.pendingConversationReturn = {
|
||||
npcId: window.currentConversationNPCId,
|
||||
type: window.currentConversationMinigameType || 'person-chat'
|
||||
};
|
||||
|
||||
// Start RFID minigame
|
||||
window.startRFIDMinigame(null, null, {
|
||||
mode: 'clone',
|
||||
cardToClone: cardData
|
||||
});
|
||||
|
||||
result.success = true;
|
||||
result.message = `Starting RFID clone...`;
|
||||
}
|
||||
break;
|
||||
```
|
||||
|
||||
**In `02_IMPLEMENTATION_TODO.md` Task 3.4**, replace steps 547-564 with:
|
||||
|
||||
```markdown
|
||||
- [ ] Add new case `'clone_keycard'` in processGameActionTags()
|
||||
- [ ] Parse param: `cardName|cardHex`
|
||||
- [ ] Check for rfid_cloner in inventory
|
||||
- [ ] If no cloner, show warning and return
|
||||
- [ ] Generate cardData object:
|
||||
- [ ] name: cardName
|
||||
- [ ] rfid_hex: cardHex
|
||||
- [ ] rfid_facility: `parseInt(cardHex.substring(0, 2), 16)`
|
||||
- [ ] rfid_card_number: `parseInt(cardHex.substring(2, 6), 16)`
|
||||
- [ ] rfid_protocol: 'EM4100'
|
||||
- [ ] key_id: `cloned_${cardName.toLowerCase().replace(/\s+/g, '_')}`
|
||||
- [ ] **Set pending conversation return** (MINIMAL CONTEXT!):
|
||||
```javascript
|
||||
window.pendingConversationReturn = {
|
||||
npcId: window.currentConversationNPCId,
|
||||
type: window.currentConversationMinigameType || 'person-chat'
|
||||
};
|
||||
```
|
||||
- [ ] Call startRFIDMinigame() with clone params
|
||||
- [ ] Show notification on success/failure
|
||||
```
|
||||
|
||||
**Add new Task 3.9**: Create `returnToConversationAfterRFID()` function
|
||||
|
||||
```markdown
|
||||
### Task 3.9: Implement Return to Conversation Function
|
||||
**Priority**: P0 (Blocker)
|
||||
**Estimated Time**: 30 minutes
|
||||
|
||||
File: `/js/minigames/rfid/rfid-minigame.js`
|
||||
|
||||
Create a function that returns to conversation after RFID minigame, following the exact pattern from container minigame.
|
||||
|
||||
- [ ] Export `returnToConversationAfterRFID()` function
|
||||
- [ ] Check if `window.pendingConversationReturn` exists
|
||||
- [ ] If not, log and return (no conversation to return to)
|
||||
- [ ] Extract conversationState from pendingConversationReturn
|
||||
- [ ] Clear `window.pendingConversationReturn = null`
|
||||
- [ ] Restart appropriate conversation minigame:
|
||||
```javascript
|
||||
setTimeout(() => {
|
||||
if (conversationState.type === 'person-chat') {
|
||||
window.MinigameFramework.startMinigame('person-chat', null, {
|
||||
npcId: conversationState.npcId,
|
||||
fromTag: true
|
||||
});
|
||||
} else if (conversationState.type === 'phone-chat') {
|
||||
window.MinigameFramework.startMinigame('phone-chat', null, {
|
||||
npcId: conversationState.npcId,
|
||||
fromTag: true
|
||||
});
|
||||
}
|
||||
}, 50);
|
||||
```
|
||||
- [ ] Add logging for debugging
|
||||
- [ ] Export function in index.js
|
||||
|
||||
**Acceptance Criteria**:
|
||||
- Function follows exact pattern from container minigame
|
||||
- Conversation resumes at correct point (npcConversationStateManager handles this automatically)
|
||||
- No manual Ink story state manipulation
|
||||
- Works for both person-chat and phone-chat
|
||||
|
||||
**Reference**: See `/js/minigames/container/container-minigame.js:720-754` for the canonical pattern.
|
||||
```
|
||||
|
||||
**Update Task 3.2** to include registering the return function:
|
||||
|
||||
```markdown
|
||||
- [ ] **Step 2 - EXPORT** for module consumers:
|
||||
```javascript
|
||||
export { RFIDMinigame, startRFIDMinigame, returnToConversationAfterRFID };
|
||||
```
|
||||
|
||||
- [ ] **Step 4 - GLOBAL** window access (after other window assignments):
|
||||
```javascript
|
||||
window.startRFIDMinigame = startRFIDMinigame;
|
||||
window.returnToConversationAfterRFID = returnToConversationAfterRFID;
|
||||
```
|
||||
```
|
||||
|
||||
### Why The Planned Pattern Was Wrong:
|
||||
|
||||
1. **No access to Ink story**: The tag handler in `chat-helpers.js` doesn't have access to `this.currentStory` - it's not in a class context
|
||||
2. **Automatic state management**: The `npcConversationStateManager` already handles all state save/restore automatically
|
||||
3. **Incompatible with framework**: The conversation minigames expect to be restarted fresh, not to have state passed in
|
||||
4. **Over-engineering**: The simpler pattern is already working perfectly for container minigame
|
||||
|
||||
---
|
||||
|
||||
## ✅ GOOD NEWS: Pattern Already Works
|
||||
|
||||
The container minigame (`js/minigames/container/container-minigame.js`) already uses the exact pattern we need:
|
||||
|
||||
1. **Conversation → Container Minigame → Back to Conversation**
|
||||
2. Uses `window.pendingConversationReturn` with minimal context (just npcId and type)
|
||||
3. Conversation state is preserved automatically by `npcConversationStateManager`
|
||||
4. Works perfectly with both person-chat and phone-chat minigames
|
||||
|
||||
**We just need to copy this proven pattern for RFID!**
|
||||
|
||||
---
|
||||
|
||||
## 📋 Additional Findings
|
||||
|
||||
### Finding #2: No Explicit Save/Load System
|
||||
|
||||
**Observation**: The game does not have a comprehensive save/load system for persisting game state across sessions.
|
||||
|
||||
**Evidence**:
|
||||
- `window.gameState` is initialized fresh in `js/main.js:46-52`
|
||||
- Only NPC conversation state is persisted to localStorage (per-NPC basis)
|
||||
- No inventory persistence across page refreshes
|
||||
- No global game state serialization
|
||||
|
||||
**Impact on RFID**:
|
||||
- Saved RFID cards in the cloner will **not persist** across page refreshes
|
||||
- This is consistent with other game systems (biometric samples, bluetooth devices, notes)
|
||||
- Not a blocker, but should be documented
|
||||
|
||||
**Recommendation**:
|
||||
- Add note in implementation docs that saved cards are session-only
|
||||
- If persistence is desired later, it can be added as an enhancement
|
||||
- Pattern would be: save cloner.saved_cards to localStorage on card save, restore on game init
|
||||
|
||||
### Finding #3: Inventory Data Structure Confirmation
|
||||
|
||||
**Observation**: Inventory items can store arbitrary complex data in `scenarioData`.
|
||||
|
||||
**Evidence**: `/js/systems/inventory.js:140-181`
|
||||
|
||||
```javascript
|
||||
const sprite = {
|
||||
name: itemData.type,
|
||||
objectId: `inventory_${itemData.type}_${Date.now()}`,
|
||||
scenarioData: itemData, // ← Full item data stored here
|
||||
texture: {
|
||||
key: itemData.type
|
||||
},
|
||||
// Copy critical properties for easy access
|
||||
keyPins: itemData.keyPins,
|
||||
key_id: itemData.key_id,
|
||||
// ...
|
||||
};
|
||||
```
|
||||
|
||||
**Impact on RFID**:
|
||||
- Storing `saved_cards` array in cloner's `scenarioData` will work perfectly
|
||||
- No size limits observed
|
||||
- Follows existing pattern used by key_ring (stores allKeys array)
|
||||
|
||||
**Confirmation**: ✅ Planning documents are correct on this point.
|
||||
|
||||
### Finding #4: Event System Confirmation
|
||||
|
||||
**Observation**: Event system uses `window.eventDispatcher.emit(eventName, data)`.
|
||||
|
||||
**Evidence**: `/js/systems/interactions.js:448-452`
|
||||
|
||||
```javascript
|
||||
if (window.eventDispatcher && sprite.scenarioData) {
|
||||
window.eventDispatcher.emit('object_interacted', {
|
||||
objectType: sprite.scenarioData.type,
|
||||
objectName: sprite.scenarioData.name,
|
||||
roomId: window.currentPlayerRoom
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
**Existing Events**:
|
||||
- `minigame_completed`
|
||||
- `minigame_failed`
|
||||
- `door_unlocked`
|
||||
- `door_unlock_attempt`
|
||||
- `item_unlocked`
|
||||
- `object_interacted`
|
||||
- `item_picked_up:*`
|
||||
|
||||
**Impact on RFID**:
|
||||
- Planned events (`card_cloned`, `card_emulated`, `rfid_lock_accessed`) will work fine
|
||||
- Follow exact same pattern as existing events
|
||||
- NPCs can react to these events via `NPCEventDispatcher`
|
||||
|
||||
**Confirmation**: ✅ Planning documents are correct on this point.
|
||||
|
||||
### Finding #5: Lock System Integration Point
|
||||
|
||||
**Observation**: Lock system uses switch statement in `unlock-system.js:64` for lock types.
|
||||
|
||||
**Current Lock Types**: key, pin, password, biometric, bluetooth
|
||||
|
||||
**Integration Pattern**: `/js/systems/unlock-system.js:64-145`
|
||||
|
||||
```javascript
|
||||
switch(lockRequirements.lockType) {
|
||||
case 'key':
|
||||
// ... handle key locks
|
||||
break;
|
||||
|
||||
case 'pin':
|
||||
// ... handle pin locks
|
||||
break;
|
||||
|
||||
// Add here:
|
||||
case 'rfid':
|
||||
// ... handle RFID locks
|
||||
break;
|
||||
}
|
||||
```
|
||||
|
||||
**Confirmation**: ✅ Planning documents are correct on this point (Task 3.1).
|
||||
|
||||
### Finding #6: Asset Loading Location Confirmed
|
||||
|
||||
**Observation**: Phaser assets are loaded in `js/core/game.js` preload function.
|
||||
|
||||
**Pattern**: `/js/core/game.js:51-66`
|
||||
|
||||
```javascript
|
||||
// Load object sprites
|
||||
this.load.image('pc', 'assets/objects/pc1.png');
|
||||
this.load.image('key', 'assets/objects/key.png');
|
||||
this.load.image('notes', 'assets/objects/notes1.png');
|
||||
this.load.image('phone', 'assets/objects/phone1.png');
|
||||
this.load.image('bluetooth_scanner', 'assets/objects/bluetooth_scanner.png');
|
||||
// ... etc
|
||||
```
|
||||
|
||||
**RFID Assets to Add**:
|
||||
```javascript
|
||||
this.load.image('keycard', 'assets/objects/keycard.png');
|
||||
this.load.image('keycard-ceo', 'assets/objects/keycard-ceo.png');
|
||||
this.load.image('keycard-security', 'assets/objects/keycard-security.png');
|
||||
this.load.image('keycard-maintenance', 'assets/objects/keycard-maintenance.png');
|
||||
this.load.image('rfid_cloner', 'assets/objects/rfid_cloner.png');
|
||||
this.load.image('rfid-icon', 'assets/icons/rfid-icon.png');
|
||||
this.load.image('nfc-waves', 'assets/icons/nfc-waves.png');
|
||||
```
|
||||
|
||||
**Confirmation**: ✅ Task 3.8 has correct file location and pattern.
|
||||
|
||||
### Finding #7: CSS File Location Confirmed
|
||||
|
||||
**Observation**: Minigame CSS files are in `css/` directly, not `css/minigames/`.
|
||||
|
||||
**Evidence**:
|
||||
```
|
||||
css/biometrics-minigame.css
|
||||
css/bluetooth-scanner.css
|
||||
css/container-minigame.css
|
||||
css/lockpicking.css
|
||||
css/notes.css
|
||||
css/password-minigame.css
|
||||
css/phone-chat-minigame.css
|
||||
css/pin-cracker-minigame.css
|
||||
```
|
||||
|
||||
**Pattern**: `css/{minigame-name}-minigame.css`
|
||||
|
||||
**Confirmation**: ✅ First review already fixed this (all references updated to `css/rfid-minigame.css`).
|
||||
|
||||
### Finding #8: No Global CSS Variables
|
||||
|
||||
**Observation**: No CSS custom properties (--variables) or global theme system detected.
|
||||
|
||||
**Impact on RFID**:
|
||||
- Use hardcoded colors as per planning docs
|
||||
- Flipper Zero orange: #FF8200
|
||||
- Screen background: #333
|
||||
- No need to integrate with theme system
|
||||
|
||||
**Confirmation**: ✅ Planning documents are correct on this point.
|
||||
|
||||
---
|
||||
|
||||
## 📝 Summary of Required Changes
|
||||
|
||||
### CRITICAL (Must Fix):
|
||||
|
||||
1. **Task 3.4**: Completely rewrite conversation return pattern to use `window.pendingConversationReturn`
|
||||
2. **Section 2c in Architecture Doc**: Replace entire example with correct minimal pattern
|
||||
3. **Add Task 3.9**: Implement `returnToConversationAfterRFID()` following container pattern
|
||||
4. **Task 3.2**: Update to export and register `returnToConversationAfterRFID`
|
||||
|
||||
### CONFIRMED CORRECT (No Changes Needed):
|
||||
|
||||
1. ✅ Event system integration (Finding #4)
|
||||
2. ✅ Lock system integration (Finding #5)
|
||||
3. ✅ Asset loading pattern (Finding #6)
|
||||
4. ✅ CSS file location (Finding #7)
|
||||
5. ✅ Inventory data structure (Finding #3)
|
||||
|
||||
### INFORMATIONAL (Document but Don't Change):
|
||||
|
||||
1. No session persistence (Finding #2) - Add note to docs
|
||||
2. No global CSS variables (Finding #8) - Confirmed approach is correct
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Impact Assessment
|
||||
|
||||
**Risk Level**: HIGH → MEDIUM (after fixes)
|
||||
|
||||
**Why HIGH Before Fixes**:
|
||||
- The incorrect conversation pattern would cause runtime errors
|
||||
- Would be incompatible with npcConversationStateManager
|
||||
- Would fail to resume conversations properly
|
||||
|
||||
**Why MEDIUM After Fixes**:
|
||||
- Pattern is proven (already works in container minigame)
|
||||
- Simple to implement (less code than planned)
|
||||
- Well-documented with reference implementation
|
||||
|
||||
**Confidence After Fixes**: 98% (up from 95%)
|
||||
|
||||
---
|
||||
|
||||
## 🔍 Review Methodology
|
||||
|
||||
This review examined:
|
||||
- 15+ core game system files
|
||||
- Existing minigame implementations (notes, container, person-chat, phone-chat)
|
||||
- Conversation state management system
|
||||
- Event dispatcher implementation
|
||||
- Inventory system internals
|
||||
- Asset loading patterns
|
||||
- CSS organization
|
||||
|
||||
**Total Files Examined**: 20+
|
||||
**Code Lines Reviewed**: 5000+
|
||||
**Patterns Verified**: 8
|
||||
|
||||
---
|
||||
|
||||
## ✅ Next Steps
|
||||
|
||||
1. Apply the critical fix to Task 3.4 immediately
|
||||
2. Update Section 2c in architecture document
|
||||
3. Add new Task 3.9 for return function
|
||||
4. Add documentation note about no session persistence
|
||||
5. Re-review planning docs to ensure consistency
|
||||
6. Proceed with implementation
|
||||
|
||||
**Estimated Fix Time**: 30 minutes
|
||||
**Estimated Re-Review Time**: 15 minutes
|
||||
**Total Delay**: 45 minutes
|
||||
|
||||
**This is a critical but straightforward fix that will prevent significant implementation problems.**
|
||||
81
planning_notes/rfid_keycard/review2/README.md
Normal file
81
planning_notes/rfid_keycard/review2/README.md
Normal file
@@ -0,0 +1,81 @@
|
||||
# Second Review - README
|
||||
|
||||
## Overview
|
||||
|
||||
This directory contains findings from a comprehensive second-pass review of the RFID keycard implementation planning documents against the actual BreakEscape codebase.
|
||||
|
||||
**Date**: 2025-01-15
|
||||
**Reviewer**: Claude (Deep code analysis)
|
||||
**Status**: **⚠️ CRITICAL ISSUE FOUND**
|
||||
|
||||
---
|
||||
|
||||
## Critical Finding
|
||||
|
||||
**The return-to-conversation pattern in the planning documents is fundamentally incorrect.**
|
||||
|
||||
The planned pattern tries to manually save and restore Ink story state, but:
|
||||
1. The actual codebase uses automatic state management via `npcConversationStateManager`
|
||||
2. The pattern used by container minigame is much simpler and already works
|
||||
3. The planned pattern would cause runtime errors and incompatibility
|
||||
|
||||
**See**: `CRITICAL_FINDINGS.md` for full details and required fixes.
|
||||
|
||||
---
|
||||
|
||||
## Files in This Review
|
||||
|
||||
- **CRITICAL_FINDINGS.md** - Main review document with 8 findings, required fixes, and code examples
|
||||
- **README.md** - This file
|
||||
|
||||
---
|
||||
|
||||
## Impact
|
||||
|
||||
- **Risk**: HIGH (would cause implementation failure)
|
||||
- **Fix Difficulty**: EASY (copy proven pattern from container minigame)
|
||||
- **Fix Time**: 30-45 minutes
|
||||
- **Confidence After Fix**: 98%
|
||||
|
||||
---
|
||||
|
||||
## Quick Action Items
|
||||
|
||||
1. ❌ **STOP**: Do not implement Task 3.4 as currently written
|
||||
2. 📖 **READ**: `CRITICAL_FINDINGS.md` - Critical Issue #1
|
||||
3. ✏️ **UPDATE**: Apply fixes to Task 3.4 and Section 2c
|
||||
4. ➕ **ADD**: New Task 3.9 for return function
|
||||
5. ✅ **VERIFY**: Re-review updated planning docs
|
||||
6. 🚀 **PROCEED**: Continue with implementation
|
||||
|
||||
---
|
||||
|
||||
## What Was Correct
|
||||
|
||||
Despite the critical issue, the review confirmed that **most** of the planning is correct:
|
||||
|
||||
✅ Event system integration
|
||||
✅ Lock system integration
|
||||
✅ Asset loading pattern
|
||||
✅ CSS file location
|
||||
✅ Inventory data structure
|
||||
✅ Minigame registration pattern
|
||||
✅ Hex validation and formulas
|
||||
|
||||
The first review was very thorough - this issue was a subtle architectural mismatch that required deep code analysis to discover.
|
||||
|
||||
---
|
||||
|
||||
## Key Takeaway
|
||||
|
||||
**Use the proven `window.pendingConversationReturn` pattern from container minigame, not manual Ink state save/restore.**
|
||||
|
||||
The npcConversationStateManager handles all story state automatically. We just need to set minimal context (npcId + type) and restart the conversation.
|
||||
|
||||
---
|
||||
|
||||
## Reference Implementation
|
||||
|
||||
**Canonical Pattern**: `/js/minigames/container/container-minigame.js:720-754`
|
||||
|
||||
This is the proven, working implementation to copy for RFID return-to-conversation functionality.
|
||||
Reference in New Issue
Block a user