mirror of
https://github.com/cliffe/BreakEscape.git
synced 2026-02-22 19:58:05 +00:00
- Added support for voice messages prefixed with "voice:" in Ink files. - Updated UI rendering to display voice message UI with play button and transcript. - Implemented automatic conversion for scenario JSON with voice properties. - Created test examples for pure voice messages and mixed content. - Fixed issues with NPC registration and message duplication in test scenarios. - Documented feature details, use cases, and testing procedures.
11 KiB
11 KiB
Phone Chat Minigame - Main Game Integration Guide
Overview
This guide explains how to integrate the phone-chat minigame into the main Break Escape game.
Prerequisites
Files Required
All files are already in place:
- ✅
js/systems/npc-manager.js- NPC management - ✅
js/systems/npc-events.js- Event dispatcher - ✅
js/systems/npc-barks.js- Bark notifications - ✅
js/systems/ink/ink-engine.js- Ink story engine - ✅
js/minigames/phone-chat/*.js- Phone chat minigame modules - ✅
css/phone-chat-minigame.css- Styling - ✅
css/npc-barks.css- Bark styling - ✅
assets/vendor/ink.js- Ink runtime library
Step 1: Initialize NPC Systems in Main Game
In js/main.js (or game initialization file):
import NPCEventDispatcher from './systems/npc-events.js';
import NPCBarkSystem from './systems/npc-barks.js';
import NPCManager from './systems/npc-manager.js';
// Initialize NPC systems after game engine starts
function initializeNPCSystems() {
// Create event dispatcher
window.eventDispatcher = new NPCEventDispatcher();
// Create bark system
window.barkSystem = new NPCBarkSystem(window.eventDispatcher);
// Create NPC manager
window.npcManager = new NPCManager(window.eventDispatcher, window.barkSystem);
// Start timed messages system
window.npcManager.startTimedMessages();
console.log('✅ NPC systems initialized');
}
// Call after Phaser game is ready
initializeNPCSystems();
Step 2: Load NPCs from Scenario
In scenario JSON (e.g., scenarios/biometric_breach.json):
{
"scenario_brief": "...",
"endGoal": "...",
"startRoom": "reception",
"npcs": [
{
"id": "alice",
"displayName": "Alice - Security Consultant",
"storyPath": "scenarios/compiled/alice-chat.json",
"avatar": "assets/npc/avatars/npc_alice.png",
"currentKnot": "start",
"phoneId": "player_phone",
"npcType": "phone",
"eventMappings": {
"room_entered:lab": {
"knot": "lab_discussion",
"bark": "Hey! I see you made it to the lab.",
"once": true
},
"item_picked_up:fingerprint_kit": {
"knot": "found_evidence",
"bark": "Good find! That'll help us identify the suspect.",
"once": true
}
}
},
{
"id": "bob",
"displayName": "Bob - IT Manager",
"storyPath": "scenarios/compiled/bob-chat.json",
"avatar": "assets/npc/avatars/npc_bob.png",
"currentKnot": "start",
"phoneId": "player_phone",
"npcType": "phone"
}
],
"timedMessages": [
{
"npcId": "alice",
"text": "Hey! Just got to the office. Ready to investigate?",
"triggerTime": 0,
"phoneId": "player_phone"
},
{
"npcId": "alice",
"text": "Found something interesting in the security logs. Check your phone when you can.",
"triggerTime": 60000,
"phoneId": "player_phone"
}
],
"rooms": { ... }
}
Load NPCs when scenario starts:
function loadScenario(scenarioData) {
// ... existing room/object loading ...
// Register NPCs
if (scenarioData.npcs) {
scenarioData.npcs.forEach(npcConfig => {
window.npcManager.registerNPC(npcConfig);
console.log(`Registered NPC: ${npcConfig.id}`);
});
}
// Load timed messages
if (scenarioData.timedMessages) {
window.npcManager.loadTimedMessages(scenarioData.timedMessages);
}
}
Step 3: Emit Game Events
Emit events when things happen in the game:
// When player enters a room
function enterRoom(roomId) {
// ... existing room logic ...
window.eventDispatcher.emit('room_entered', {
roomId: roomId,
timestamp: Date.now()
});
// Also emit room-specific event
window.eventDispatcher.emit(`room_entered:${roomId}`, {
roomId: roomId
});
}
// When player picks up an item
function pickupItem(itemType, itemName) {
// ... existing pickup logic ...
window.eventDispatcher.emit('item_picked_up', {
itemType: itemType,
itemName: itemName,
timestamp: Date.now()
});
// Also emit item-specific event
window.eventDispatcher.emit(`item_picked_up:${itemType}`, {
itemType: itemType,
itemName: itemName
});
}
// When player completes a minigame
function onMinigameComplete(minigameType, success) {
// ... existing minigame logic ...
window.eventDispatcher.emit('minigame_completed', {
minigameType: minigameType,
success: success,
timestamp: Date.now()
});
// Also emit specific event
window.eventDispatcher.emit(`minigame_completed:${minigameType}`, {
success: success
});
}
// When player unlocks a door
function onDoorUnlocked(doorId, method) {
window.eventDispatcher.emit('door_unlocked', {
doorId: doorId,
method: method, // 'key', 'password', 'biometric', etc.
timestamp: Date.now()
});
}
Step 4: Add Phone Access Button
Add UI button to open phone (e.g., in index.html or game UI):
<!-- Add to game UI -->
<div id="phone-button" class="ui-button">
📱
<span id="phone-unread-badge" class="unread-badge" style="display: none;">0</span>
</div>
Wire up the button:
// In UI initialization
document.getElementById('phone-button').addEventListener('click', () => {
openPhone();
});
function openPhone() {
// Start phone-chat minigame
window.MinigameFramework.startMinigame('phone-chat', null, {
phoneId: 'player_phone',
title: 'Phone'
});
}
// Update unread badge when messages arrive
function updatePhoneUnreadBadge() {
const npcs = window.npcManager.getNPCsByPhone('player_phone');
let totalUnread = 0;
npcs.forEach(npc => {
const history = window.npcManager.getConversationHistory(npc.id);
const unread = history.filter(msg => !msg.read).length;
totalUnread += unread;
});
const badge = document.getElementById('phone-unread-badge');
if (totalUnread > 0) {
badge.textContent = totalUnread;
badge.style.display = 'block';
} else {
badge.style.display = 'none';
}
}
// Call updatePhoneUnreadBadge() when messages arrive or are read
Step 5: Handle Phone Objects in Rooms
When player interacts with a phone object:
// In interaction system (js/systems/interactions.js)
function handlePhoneInteraction(phoneObject) {
const phoneId = phoneObject.scenarioData?.phoneId || 'player_phone';
// Open phone minigame for this specific phone
window.MinigameFramework.startMinigame('phone-chat', null, {
phoneId: phoneId,
title: phoneObject.name || 'Phone'
});
}
In scenario JSON, define phone objects:
{
"type": "phone",
"name": "Office Phone",
"interactable": true,
"scenarioData": {
"phoneId": "office_phone"
}
}
Step 6: Compile Ink Stories
Create Ink story files in scenarios/ink/:
// scenarios/ink/alice-chat.ink
=== start ===
# speaker: Alice
Hey! I'm Alice, the security consultant here.
What can I help you with?
+ [Who are you?] -> about_alice
+ [What happened here?] -> breach_info
+ [I need access to the lab] -> lab_access
+ [Goodbye] -> END
=== about_alice ===
# speaker: Alice
I'm the senior security analyst. Been here 3 years.
I specialize in biometric systems and access control.
-> start
// ... more knots ...
Compile to JSON:
cd scenarios/ink
inklecate alice-chat.ink -o ../compiled/alice-chat.json
Step 7: CSS Integration
Ensure CSS files are loaded in index.html:
<link rel="stylesheet" href="css/npc-barks.css">
<link rel="stylesheet" href="css/phone-chat-minigame.css">
Step 8: Testing Integration
Test checklist:
- NPCs load from scenario JSON
- Events trigger barks
- Barks appear when triggered
- Clicking bark opens phone chat
- Phone button opens phone
- Multiple NPCs appear in contact list
- Conversations work correctly
- History persists across game sessions
- Timed messages arrive correctly
- Unread badge updates
Common Integration Patterns
Pattern 1: Progress-Based Knot Changes
// When player achieves something
function onSuspectIdentified() {
const alice = window.npcManager.getNPC('alice');
if (alice) {
alice.currentKnot = 'suspect_found';
}
window.eventDispatcher.emit('progress:suspect_identified', {});
}
Pattern 2: Variable Sharing Between Game and Ink
// Set Ink variable from game
const aliceConversation = new PhoneChatConversation('alice', window.npcManager, window.inkEngine);
aliceConversation.setVariable('player_has_keycard', true);
// Get Ink variable in game
const trustLevel = aliceConversation.getVariable('alice_trust');
if (trustLevel >= 5) {
unlockSpecialContent();
}
Pattern 3: Dynamic NPC Registration
// Add NPC mid-game (e.g., when player finds their phone number)
function discoverContact(npcId) {
window.npcManager.registerNPC({
id: npcId,
displayName: 'Unknown Contact',
storyPath: `scenarios/compiled/${npcId}-chat.json`,
phoneId: 'player_phone'
});
// Schedule intro message
window.npcManager.scheduleTimedMessage({
npcId: npcId,
text: 'Hey, who is this?',
triggerTime: 5000 // 5 seconds from now
});
}
Debugging Tips
Enable debug logging:
// In browser console
window.npcManager.debug = true;
window.eventDispatcher.debug = true;
Check NPC state:
// Check registered NPCs
console.log(window.npcManager.getAllNPCs());
// Check conversation history
console.log(window.npcManager.getConversationHistory('alice'));
// Check if event has triggered
console.log(window.npcManager.hasTriggered('alice', 'room_entered:lab'));
Test events manually:
// Emit test event
window.eventDispatcher.emit('room_entered:lab', { roomId: 'lab' });
// Show test bark
window.barkSystem.showBark({
npcId: 'alice',
npcName: 'Alice',
message: 'Test bark message!',
inkStoryPath: 'scenarios/compiled/alice-chat.json'
});
Performance Considerations
- Event Throttling: Use cooldowns on frequent events (e.g., player movement)
- Message Limits: Consider limiting conversation history length (e.g., last 100 messages)
- Lazy Loading: Only load Ink stories when needed
- State Persistence: Save NPC states to localStorage periodically
File Checklist
Before integration, verify these files exist:
js/systems/npc-manager.jsjs/systems/npc-events.jsjs/systems/npc-barks.jsjs/systems/ink/ink-engine.jsjs/minigames/phone-chat/phone-chat-minigame.jsjs/minigames/phone-chat/phone-chat-ui.jsjs/minigames/phone-chat/phone-chat-conversation.jsjs/minigames/phone-chat/phone-chat-history.jscss/phone-chat-minigame.csscss/npc-barks.cssassets/vendor/ink.js- Compiled Ink stories in
scenarios/compiled/
Integration Guide Version: 1.0 Last Updated: 2025-10-30 Status: Ready for Integration