mirror of
https://github.com/cliffe/BreakEscape.git
synced 2026-02-20 13:50:46 +00:00
Add character registry and NPC management features
- Implemented a global character registry to manage player and NPC data. - Added methods for setting the player, registering NPCs, and retrieving character information. - Integrated character registry updates into the NPC manager for seamless NPC registration. - Created test scenarios for line prefix speaker format, including narrator modes and background changes. - Developed comprehensive NPC sprite test scenario with various NPC interactions and items.
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
# Global Character Registry Implementation
|
||||
|
||||
## Overview
|
||||
Implemented a global character registry system that maintains all available characters (player + NPCs) for the game, enabling reliable speaker resolution in multi-character conversations.
|
||||
|
||||
## Architecture
|
||||
|
||||
### Character Registry System (`js/systems/character-registry.js`)
|
||||
Global object `window.characterRegistry` with methods:
|
||||
- **setPlayer(playerData)** - Register player at game initialization
|
||||
- **registerNPC(npcId, npcData)** - Register NPC when npcManager registers it
|
||||
- **getCharacter(characterId)** - Get specific character by ID
|
||||
- **getAllCharacters()** - Get complete dictionary of all characters
|
||||
- **hasCharacter(characterId)** - Check if character exists
|
||||
- **clearNPCs()** - Clear all NPCs (for scenario transitions)
|
||||
- **debug()** - Log registry state
|
||||
|
||||
### Data Flow
|
||||
|
||||
1. **Initialization Phase** (game.js):
|
||||
```
|
||||
createPlayer()
|
||||
→ window.player = player
|
||||
→ characterRegistry.setPlayer(playerData)
|
||||
```
|
||||
|
||||
2. **NPC Registration Phase** (npc-manager.js):
|
||||
```
|
||||
npcManager.registerNPC(id, opts)
|
||||
→ this.npcs.set(id, entry)
|
||||
→ characterRegistry.registerNPC(id, entry) ← NEW
|
||||
```
|
||||
|
||||
3. **Person-Chat Minigame Phase** (person-chat-minigame.js):
|
||||
```
|
||||
buildCharacterIndex()
|
||||
→ if window.characterRegistry exists
|
||||
→ return characterRegistry.getAllCharacters()
|
||||
→ Otherwise fallback to legacy local building
|
||||
```
|
||||
|
||||
## Key Features
|
||||
|
||||
✅ **Automatic Population**: NPCs automatically added when registered via npcManager
|
||||
✅ **Global Access**: Available to any minigame or system that needs speaker resolution
|
||||
✅ **Early Availability**: Player and room NPCs available before person-chat minigame starts
|
||||
✅ **Backward Compatible**: Falls back to legacy local character index building if registry unavailable
|
||||
✅ **Clean Separation**: Registry only knows about character data, not minigame logic
|
||||
|
||||
## Files Modified
|
||||
|
||||
1. **NEW: `js/systems/character-registry.js`**
|
||||
- 100+ lines of character registry implementation
|
||||
- Self-documenting with comprehensive JSDoc comments
|
||||
|
||||
2. **`js/main.js`**
|
||||
- Added import: `import './systems/character-registry.js';`
|
||||
- Ensures registry available before any scripts that need it
|
||||
|
||||
3. **`js/core/game.js`**
|
||||
- After `window.player = player`, added:
|
||||
```javascript
|
||||
if (window.characterRegistry && window.player) {
|
||||
const playerData = { id, displayName, spriteSheet, ... };
|
||||
window.characterRegistry.setPlayer(playerData);
|
||||
}
|
||||
```
|
||||
|
||||
4. **`js/systems/npc-manager.js`**
|
||||
- In `registerNPC()` method, after `this.npcs.set(realId, entry)`:
|
||||
```javascript
|
||||
if (window.characterRegistry) {
|
||||
window.characterRegistry.registerNPC(realId, entry);
|
||||
}
|
||||
```
|
||||
|
||||
5. **`js/minigames/person-chat/person-chat-minigame.js`**
|
||||
- Simplified `buildCharacterIndex()` to:
|
||||
```javascript
|
||||
if (window.characterRegistry) {
|
||||
return characterRegistry.getAllCharacters();
|
||||
}
|
||||
// Fallback to legacy local building...
|
||||
```
|
||||
|
||||
## Test Verification
|
||||
|
||||
To verify the system is working:
|
||||
|
||||
1. **Check Console Logs**:
|
||||
```
|
||||
✅ Character Registry system initialized
|
||||
✅ Character Registry: Added player (Agent 0x00)
|
||||
✅ Character Registry: Added NPC test_npc_front (displayName: Helper NPC)
|
||||
✅ Character Registry: Added NPC test_npc_back (displayName: Back NPC)
|
||||
```
|
||||
|
||||
2. **Check Character Resolution**:
|
||||
```
|
||||
👥 Using global character registry with 3 characters: ['player', 'test_npc_front', 'test_npc_back']
|
||||
```
|
||||
|
||||
3. **Check Speaker Display**:
|
||||
- When `test_npc_back: "Welcome..."` appears in dialogue
|
||||
- Should resolve to "Back NPC" (from registry displayName)
|
||||
- Not show raw ID "test_npc_back"
|
||||
|
||||
## Browser Console Debug
|
||||
|
||||
Available in browser console:
|
||||
```javascript
|
||||
window.characterRegistry.debug()
|
||||
// Output:
|
||||
// 📋 Character Registry: {
|
||||
// playerCount: 1,
|
||||
// npcCount: 5,
|
||||
// totalCharacters: 6,
|
||||
// characters: ['player', 'test_npc_front', 'test_npc_back', ...]
|
||||
// }
|
||||
|
||||
window.characterRegistry.getCharacter('test_npc_back')
|
||||
// Returns: { id, displayName: 'Back NPC', spriteSheet, ... }
|
||||
```
|
||||
|
||||
## Benefits
|
||||
|
||||
1. **No More Missing Secondary NPCs**: All room NPCs automatically available before minigame starts
|
||||
2. **Consistent Speaker Resolution**: Single source of truth for all characters
|
||||
3. **Extensible**: Easy to add more features (character filtering, abilities, etc.)
|
||||
4. **Debuggable**: Clear logging and debug methods for troubleshooting
|
||||
5. **Maintainable**: Centralized character management separate from minigame logic
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. Reload game with hard refresh to clear cache
|
||||
2. Test line-prefix speaker format with secondary NPCs
|
||||
3. Verify both `test_npc_front` and `test_npc_back` display correct names
|
||||
4. Check console for character registry logs
|
||||
@@ -0,0 +1,126 @@
|
||||
# Global Character Registry - Quick Reference
|
||||
|
||||
## What It Does
|
||||
Maintains a single, global registry of all characters (player + NPCs) that's populated automatically as the game loads. Used by person-chat minigame for reliable speaker resolution in conversations.
|
||||
|
||||
## How to Use (Developer)
|
||||
|
||||
### Access the Registry
|
||||
```javascript
|
||||
// Get all characters
|
||||
window.characterRegistry.getAllCharacters()
|
||||
// Returns: { player: {...}, npc_id_1: {...}, npc_id_2: {...} }
|
||||
|
||||
// Get specific character
|
||||
window.characterRegistry.getCharacter('test_npc_back')
|
||||
// Returns: { id, displayName, spriteSheet, ... }
|
||||
|
||||
// Check if character exists
|
||||
window.characterRegistry.hasCharacter('some_npc')
|
||||
// Returns: true or false
|
||||
|
||||
// Debug current state
|
||||
window.characterRegistry.debug()
|
||||
```
|
||||
|
||||
### NPCs Added Automatically When:
|
||||
1. **Game initializes**: Player registered via `game.js`
|
||||
2. **NPC is registered**: Via `npcManager.registerNPC(id, opts)` in npc-lazy-loader.js
|
||||
3. **Room loads**: NPCs from scenario json automatically registered by npc-lazy-loader
|
||||
|
||||
### How Person-Chat Uses It
|
||||
```javascript
|
||||
// In person-chat-minigame.js buildCharacterIndex():
|
||||
buildCharacterIndex() {
|
||||
if (window.characterRegistry) {
|
||||
// Use global registry (has all characters already)
|
||||
return characterRegistry.getAllCharacters();
|
||||
}
|
||||
// Fallback to legacy local building if needed
|
||||
}
|
||||
```
|
||||
|
||||
## Console Debug Commands
|
||||
|
||||
```javascript
|
||||
// See all registered characters
|
||||
window.characterRegistry.debug()
|
||||
|
||||
// Check if specific NPC is registered
|
||||
window.characterRegistry.hasCharacter('test_npc_back')
|
||||
|
||||
// Get NPC display name
|
||||
window.characterRegistry.getCharacter('test_npc_back').displayName
|
||||
// Should output: "Back NPC"
|
||||
|
||||
// Get all character IDs
|
||||
Object.keys(window.characterRegistry.getAllCharacters())
|
||||
// Should output: ['player', 'test_npc_front', 'test_npc_back', ...]
|
||||
|
||||
// Clear all NPCs (for scenario transitions)
|
||||
window.characterRegistry.clearNPCs()
|
||||
```
|
||||
|
||||
## Expected Console Output
|
||||
|
||||
When game loads:
|
||||
```
|
||||
✅ Character Registry system initialized
|
||||
✅ Character Registry: Added player (Agent 0x00)
|
||||
✅ Character Registry: Added NPC test_npc_front (displayName: Helper NPC)
|
||||
✅ Character Registry: Added NPC test_npc_back (displayName: Back NPC)
|
||||
```
|
||||
|
||||
When person-chat starts:
|
||||
```
|
||||
👥 Using global character registry with 3 characters: ['player', 'test_npc_front', 'test_npc_back']
|
||||
```
|
||||
|
||||
## Files Changed
|
||||
|
||||
| File | Change |
|
||||
|------|--------|
|
||||
| `js/systems/character-registry.js` | NEW: 100+ lines |
|
||||
| `js/main.js` | Added import of character-registry.js |
|
||||
| `js/core/game.js` | Register player in registry after initialization |
|
||||
| `js/systems/npc-manager.js` | Register NPCs in registry when they're registered |
|
||||
| `js/minigames/person-chat/person-chat-minigame.js` | Use global registry instead of building local index |
|
||||
|
||||
## How It Fixes the Bug
|
||||
|
||||
**Before**: Secondary NPCs like `test_npc_back` weren't in the character index when person-chat minigame started, so speaker resolution failed.
|
||||
|
||||
**After**:
|
||||
1. `test_npc_back` registered in npcManager → immediately added to characterRegistry
|
||||
2. When person-chat minigame starts, it uses characterRegistry
|
||||
3. `test_npc_back` is already there with displayName "Back NPC"
|
||||
4. Line-prefix parsing works: `test_npc_back:` → resolves to "Back NPC" ✅
|
||||
|
||||
## Scenario Example
|
||||
|
||||
Room with 3 NPCs in `scenario.json`:
|
||||
```json
|
||||
"test_room": {
|
||||
"npcs": [
|
||||
{ "id": "test_npc_front", "displayName": "Helper NPC", ... },
|
||||
{ "id": "test_npc_back", "displayName": "Back NPC", ... },
|
||||
{ "id": "test_npc_influence", "displayName": "Expert", ... }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Character Registry after room loads:
|
||||
```javascript
|
||||
{
|
||||
player: { id: 'player', displayName: 'Agent 0x00', ... },
|
||||
test_npc_front: { id: 'test_npc_front', displayName: 'Helper NPC', ... },
|
||||
test_npc_back: { id: 'test_npc_back', displayName: 'Back NPC', ... },
|
||||
test_npc_influence: { id: 'test_npc_influence', displayName: 'Expert', ... }
|
||||
}
|
||||
```
|
||||
|
||||
When dialogue line is `test_npc_back: "Welcome..."`:
|
||||
1. Parser extracts speaker: `test_npc_back`
|
||||
2. Looks up in characterRegistry: ✅ found
|
||||
3. Gets displayName: "Back NPC"
|
||||
4. Shows: "Back NPC: Welcome..."
|
||||
Reference in New Issue
Block a user