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:
Z. Cliffe Schreuders
2025-11-24 02:21:31 +00:00
parent 48e7860e0f
commit 2c8757de3e
29 changed files with 1415 additions and 119 deletions

View File

@@ -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

View File

@@ -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..."