mirror of
https://github.com/cliffe/BreakEscape.git
synced 2026-02-20 13:50:46 +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.
578 lines
22 KiB
HTML
578 lines
22 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Phone Chat Minigame Test</title>
|
||
|
||
<!-- VT323 font for pixel-art aesthetic -->
|
||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||
<link href="https://fonts.googleapis.com/css2?family=VT323&display=swap" rel="stylesheet">
|
||
|
||
<!-- Minigame styles -->
|
||
<link rel="stylesheet" href="css/main.css">
|
||
<link rel="stylesheet" href="css/minigames-framework.css">
|
||
<link rel="stylesheet" href="css/phone-chat-minigame.css">
|
||
|
||
<style>
|
||
body {
|
||
font-family: 'VT323', monospace;
|
||
background: #1a1a1a;
|
||
color: #fff;
|
||
padding: 20px;
|
||
}
|
||
|
||
h1 {
|
||
color: #5fcf69;
|
||
text-align: center;
|
||
margin-bottom: 30px;
|
||
}
|
||
|
||
.test-controls {
|
||
max-width: 800px;
|
||
margin: 0 auto 30px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 15px;
|
||
}
|
||
|
||
.test-section {
|
||
background: #2a2a2a;
|
||
border: 2px solid #5fcf69;
|
||
padding: 20px;
|
||
}
|
||
|
||
.test-section h2 {
|
||
color: #5fcf69;
|
||
margin-top: 0;
|
||
font-size: 24px;
|
||
}
|
||
|
||
.button-group {
|
||
display: flex;
|
||
gap: 10px;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.test-btn {
|
||
background: #333;
|
||
color: #5fcf69;
|
||
border: 2px solid #555;
|
||
padding: 12px 20px;
|
||
cursor: pointer;
|
||
font-family: 'VT323', monospace;
|
||
font-size: 18px;
|
||
transition: all 0.3s ease;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.test-btn:hover {
|
||
background: #555;
|
||
border-color: #5fcf69;
|
||
box-shadow: 0 0 10px rgba(95, 207, 105, 0.5);
|
||
}
|
||
|
||
.console-output {
|
||
background: #000;
|
||
border: 2px solid #5fcf69;
|
||
padding: 15px;
|
||
font-family: 'VT323', monospace;
|
||
font-size: 14px;
|
||
max-height: 300px;
|
||
overflow-y: auto;
|
||
color: #5fcf69;
|
||
}
|
||
|
||
.console-output .log-entry {
|
||
margin-bottom: 4px;
|
||
}
|
||
|
||
.console-output .log-entry.error {
|
||
color: #ff6b6b;
|
||
}
|
||
|
||
.console-output .log-entry.success {
|
||
color: #6acc6a;
|
||
}
|
||
|
||
.console-output .log-entry.info {
|
||
color: #4a9eff;
|
||
}
|
||
|
||
#minigame-container {
|
||
display: none;
|
||
}
|
||
|
||
#minigame-container.active {
|
||
display: block;
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<h1>📱 Phone Chat Minigame Test</h1>
|
||
|
||
<div class="test-controls">
|
||
<div class="test-section">
|
||
<h2>1. Setup & Initialization</h2>
|
||
<div class="button-group">
|
||
<button class="test-btn" onclick="testSetup()">Initialize Systems</button>
|
||
<button class="test-btn" onclick="testRegisterNPCs()">Register Test NPCs</button>
|
||
<button class="test-btn" onclick="checkSystems()">Check Systems Status</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="test-section">
|
||
<h2>2. Phone Chat Tests</h2>
|
||
<div class="button-group">
|
||
<button class="test-btn" onclick="testAliceChat()">Test Alice Chat</button>
|
||
<button class="test-btn" onclick="testBobChat()">Test Bob Chat</button>
|
||
<button class="test-btn" onclick="testPhoneWithMultipleNPCs()">Open Phone</button>
|
||
<button class="test-btn" onclick="testSimpleMessageConversion()" style="background: #4CAF50;">🔄 Test Simple Message Conversion</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="test-section">
|
||
<h2>3. History Tests</h2>
|
||
<div class="button-group">
|
||
<button class="test-btn" onclick="testSendMessages()">Send Test Messages</button>
|
||
<button class="test-btn" onclick="testViewHistory()">View Conversation History</button>
|
||
<button class="test-btn" onclick="testClearHistory()">Clear History</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="test-section">
|
||
<h2>Console Output</h2>
|
||
<div class="console-output" id="console-output">
|
||
<div class="log-entry info">📝 Waiting for tests to run...</div>
|
||
</div>
|
||
<button class="test-btn" onclick="clearConsole()" style="margin-top: 10px;">Clear Console</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Minigame container -->
|
||
<div id="minigame-container"></div>
|
||
|
||
<!-- Load dependencies -->
|
||
<script src="assets/vendor/ink.js"></script>
|
||
<script type="module">
|
||
import InkEngine from './js/systems/ink/ink-engine.js';
|
||
import NPCEventDispatcher from './js/systems/npc-events.js';
|
||
import NPCManager from './js/systems/npc-manager.js';
|
||
import NPCBarkSystem from './js/systems/npc-barks.js';
|
||
import { MinigameFramework } from './js/minigames/framework/minigame-manager.js';
|
||
import { PhoneChatMinigame } from './js/minigames/phone-chat/phone-chat-minigame.js';
|
||
|
||
// Make available globally for test functions
|
||
window.InkEngine = InkEngine;
|
||
window.NPCEventDispatcher = NPCEventDispatcher;
|
||
window.NPCManager = NPCManager;
|
||
window.NPCBarkSystem = NPCBarkSystem;
|
||
window.MinigameFramework = MinigameFramework;
|
||
window.PhoneChatMinigame = PhoneChatMinigame;
|
||
|
||
// Register minigame
|
||
MinigameFramework.registerScene('phone-chat', PhoneChatMinigame);
|
||
|
||
log('✅ Modules loaded successfully', 'success');
|
||
</script>
|
||
|
||
<script>
|
||
// Console logging
|
||
function log(message, type = 'info') {
|
||
const output = document.getElementById('console-output');
|
||
const entry = document.createElement('div');
|
||
entry.className = `log-entry ${type}`;
|
||
entry.textContent = `[${new Date().toLocaleTimeString()}] ${message}`;
|
||
output.appendChild(entry);
|
||
output.scrollTop = output.scrollHeight;
|
||
console.log(message);
|
||
}
|
||
|
||
function clearConsole() {
|
||
document.getElementById('console-output').innerHTML = '';
|
||
log('Console cleared', 'info');
|
||
}
|
||
|
||
// Test functions
|
||
function testSetup() {
|
||
log('🔧 Initializing systems...', 'info');
|
||
|
||
try {
|
||
// Initialize event dispatcher
|
||
window.eventDispatcher = new window.NPCEventDispatcher();
|
||
log('✅ Event dispatcher initialized', 'success');
|
||
|
||
// Initialize bark system
|
||
window.barkSystem = new window.NPCBarkSystem();
|
||
window.barkSystem.init();
|
||
log('✅ Bark system initialized', 'success');
|
||
|
||
// Initialize NPC manager
|
||
window.npcManager = new window.NPCManager(window.eventDispatcher, window.barkSystem);
|
||
log('✅ NPC manager initialized', 'success');
|
||
|
||
log('✅ All systems initialized!', 'success');
|
||
} catch (error) {
|
||
log(`❌ Error during setup: ${error.message}`, 'error');
|
||
console.error(error);
|
||
}
|
||
}
|
||
|
||
function testRegisterNPCs() {
|
||
log('👥 Registering test NPCs...', 'info');
|
||
|
||
if (!window.npcManager) {
|
||
log('❌ NPC manager not initialized. Run Setup first.', 'error');
|
||
return;
|
||
}
|
||
|
||
try {
|
||
// Register Alice with her complex story
|
||
window.npcManager.registerNPC('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'
|
||
});
|
||
log('✅ Registered Alice', 'success');
|
||
|
||
// Register Bob with generic story
|
||
window.npcManager.registerNPC('bob', {
|
||
displayName: 'Bob - IT Manager',
|
||
storyPath: 'scenarios/compiled/generic-npc.json',
|
||
avatar: 'assets/npc/avatars/npc_bob.png',
|
||
currentKnot: 'start',
|
||
phoneId: 'player_phone',
|
||
npcType: 'phone'
|
||
});
|
||
log('✅ Registered Bob', 'success');
|
||
|
||
// Register Charlie with generic story
|
||
window.npcManager.registerNPC('charlie', {
|
||
displayName: 'Charlie - Security Guard',
|
||
storyPath: 'scenarios/compiled/generic-npc.json',
|
||
avatar: null,
|
||
currentKnot: 'start',
|
||
phoneId: 'player_phone',
|
||
npcType: 'phone'
|
||
});
|
||
log('✅ Registered Charlie', 'success');
|
||
|
||
// Register Security Team with simple one-way message
|
||
window.npcManager.registerNPC('security_team', {
|
||
displayName: 'Security Team',
|
||
storyPath: 'scenarios/compiled/simple-message.json',
|
||
avatar: null,
|
||
currentKnot: 'start',
|
||
phoneId: 'player_phone',
|
||
npcType: 'phone'
|
||
});
|
||
log('✅ Registered Security Team (simple message)', 'success');
|
||
|
||
// Register IT Team with voice message
|
||
window.npcManager.registerNPC('it_team', {
|
||
displayName: 'IT Team',
|
||
storyPath: 'scenarios/compiled/voice-message-example.json',
|
||
avatar: null,
|
||
currentKnot: 'start',
|
||
phoneId: 'player_phone',
|
||
npcType: 'phone'
|
||
});
|
||
log('✅ Registered IT Team (voice message)', 'success');
|
||
|
||
// Register David with mixed message types (text + voice)
|
||
window.npcManager.registerNPC('david', {
|
||
displayName: 'David - Tech Support',
|
||
storyPath: 'scenarios/compiled/mixed-message-example.json',
|
||
avatar: null,
|
||
currentKnot: 'start',
|
||
phoneId: 'player_phone',
|
||
npcType: 'phone'
|
||
});
|
||
log('✅ Registered David (mixed messages)', 'success');
|
||
|
||
log('✅ All NPCs registered!', 'success');
|
||
|
||
// Start timed messages system
|
||
window.npcManager.startTimedMessages();
|
||
log('✅ Timed messages system started!', 'success');
|
||
|
||
// Schedule some timed messages for testing
|
||
window.npcManager.scheduleTimedMessage({
|
||
npcId: 'alice',
|
||
text: '⏰ Hey! This is a timed message arriving 5 seconds after game start.',
|
||
triggerTime: 5000, // 5 seconds
|
||
phoneId: 'player_phone'
|
||
});
|
||
|
||
window.npcManager.scheduleTimedMessage({
|
||
npcId: 'bob',
|
||
text: '⏰ Bob here! This message arrives 10 seconds in.',
|
||
triggerTime: 10000, // 10 seconds
|
||
phoneId: 'player_phone'
|
||
});
|
||
|
||
window.npcManager.scheduleTimedMessage({
|
||
npcId: 'alice',
|
||
text: '⏰ Follow-up from Alice at 15 seconds!',
|
||
triggerTime: 15000, // 15 seconds
|
||
phoneId: 'player_phone'
|
||
});
|
||
|
||
log('✅ Scheduled 3 timed messages (5s, 10s, 15s)', 'success');
|
||
} catch (error) {
|
||
log(`❌ Error registering NPCs: ${error.message}`, 'error');
|
||
console.error(error);
|
||
}
|
||
}
|
||
|
||
function checkSystems() {
|
||
log('🔍 Checking systems status...', 'info');
|
||
|
||
const systems = {
|
||
'InkEngine': window.InkEngine,
|
||
'NPCEventDispatcher': window.eventDispatcher,
|
||
'NPCBarkSystem': window.barkSystem,
|
||
'NPCManager': window.npcManager,
|
||
'MinigameFramework': window.MinigameFramework
|
||
};
|
||
|
||
for (const [name, system] of Object.entries(systems)) {
|
||
if (system) {
|
||
log(`✅ ${name}: Ready`, 'success');
|
||
} else {
|
||
log(`❌ ${name}: Not initialized`, 'error');
|
||
}
|
||
}
|
||
|
||
// Check NPCs
|
||
if (window.npcManager) {
|
||
const npcCount = window.npcManager.npcs.size;
|
||
log(`📊 Registered NPCs: ${npcCount}`, 'info');
|
||
|
||
window.npcManager.npcs.forEach((npc, id) => {
|
||
const historyCount = window.npcManager.getConversationHistory(id).length;
|
||
log(` - ${npc.displayName}: ${historyCount} messages in history`, 'info');
|
||
});
|
||
}
|
||
}
|
||
|
||
function testAliceChat() {
|
||
log('💬 Opening chat with Alice...', 'info');
|
||
|
||
if (!window.npcManager) {
|
||
log('❌ NPC manager not initialized', 'error');
|
||
return;
|
||
}
|
||
|
||
try {
|
||
window.MinigameFramework.startMinigame('phone-chat', null, {
|
||
npcId: 'alice',
|
||
npcName: 'Alice - Security Consultant',
|
||
title: 'Chat with Alice'
|
||
});
|
||
log('✅ Phone chat opened', 'success');
|
||
} catch (error) {
|
||
log(`❌ Error opening chat: ${error.message}`, 'error');
|
||
console.error(error);
|
||
}
|
||
}
|
||
|
||
function testBobChat() {
|
||
log('💬 Opening chat with Bob...', 'info');
|
||
|
||
if (!window.npcManager) {
|
||
log('❌ NPC manager not initialized', 'error');
|
||
return;
|
||
}
|
||
|
||
try {
|
||
window.MinigameFramework.startMinigame('phone-chat', null, {
|
||
npcId: 'bob',
|
||
npcName: 'Bob - IT Manager',
|
||
title: 'Chat with Bob'
|
||
});
|
||
log('✅ Phone chat opened', 'success');
|
||
} catch (error) {
|
||
log(`❌ Error opening chat: ${error.message}`, 'error');
|
||
console.error(error);
|
||
}
|
||
}
|
||
|
||
function testPhoneWithMultipleNPCs() {
|
||
log('📱 Opening phone with multiple NPCs...', 'info');
|
||
|
||
if (!window.npcManager) {
|
||
log('❌ NPC manager not initialized', 'error');
|
||
return;
|
||
}
|
||
|
||
try {
|
||
window.MinigameFramework.startMinigame('phone-chat', null, {
|
||
phoneId: 'player_phone',
|
||
title: 'Messages'
|
||
});
|
||
log('✅ Phone opened with contact list', 'success');
|
||
} catch (error) {
|
||
log(`❌ Error opening phone: ${error.message}`, 'error');
|
||
console.error(error);
|
||
}
|
||
}
|
||
|
||
async function testSimpleMessageConversion() {
|
||
log('🔄 Testing simple message conversion...', 'info');
|
||
|
||
try {
|
||
// Import the converter
|
||
const { default: PhoneMessageConverter } = await import('./js/utils/phone-message-converter.js');
|
||
|
||
// Use a static phone ID to avoid duplicates on repeated clicks
|
||
const testNpcId = 'test_reception_phone';
|
||
|
||
// Check if already registered
|
||
if (window.npcManager.getNPC(testNpcId)) {
|
||
log('ℹ️ Test NPC already registered, skipping...', 'info');
|
||
|
||
// Just open the phone
|
||
window.MinigameFramework.startMinigame('phone-chat', null, {
|
||
phoneId: 'default_phone',
|
||
title: 'Test Simple Message'
|
||
});
|
||
|
||
log('✅ Opened existing test message', 'success');
|
||
return;
|
||
}
|
||
|
||
// Create a simple phone object (old format)
|
||
const simplePhone = {
|
||
"type": "phone",
|
||
"name": "Reception Phone",
|
||
"takeable": false,
|
||
"voice": "Welcome to the Computer Science Department! The CyBOK backup is in the Professor's safe. The door through to the offices is also locked, so I guess it's safe for now.",
|
||
"sender": "Receptionist",
|
||
"timestamp": "Now",
|
||
"observations": "The reception phone plays back a voicemail message",
|
||
"phoneId": "default_phone"
|
||
};
|
||
|
||
log('📞 Old format phone object:', 'info');
|
||
console.log(simplePhone);
|
||
|
||
// Convert to Ink JSON
|
||
const inkJSON = PhoneMessageConverter.toInkJSON(simplePhone);
|
||
log('✅ Converted to Ink JSON:', 'success');
|
||
console.log(inkJSON);
|
||
|
||
// Create virtual NPC with static ID
|
||
const virtualNPC = PhoneMessageConverter.createVirtualNPC(simplePhone);
|
||
// Override the timestamp-based ID with our static one
|
||
virtualNPC.id = testNpcId;
|
||
|
||
log('✅ Created virtual NPC:', 'success');
|
||
console.log(virtualNPC);
|
||
|
||
// Register it
|
||
window.npcManager.registerNPC(virtualNPC);
|
||
log(`✅ Registered as NPC: ${virtualNPC.id}`, 'success');
|
||
|
||
// Open the phone to test
|
||
window.MinigameFramework.startMinigame('phone-chat', null, {
|
||
phoneId: 'default_phone',
|
||
title: 'Test Simple Message'
|
||
});
|
||
|
||
log('✅ Test complete - check the phone UI!', 'success');
|
||
} catch (error) {
|
||
log(`❌ Error: ${error.message}`, 'error');
|
||
console.error(error);
|
||
}
|
||
}
|
||
|
||
function testSendMessages() {
|
||
log('📤 Sending test messages...', 'info');
|
||
|
||
if (!window.npcManager) {
|
||
log('❌ NPC manager not initialized', 'error');
|
||
return;
|
||
}
|
||
|
||
try {
|
||
// Add test messages to Alice
|
||
window.npcManager.addMessage('alice', 'npc', 'Hey! I need to talk to you about something important.');
|
||
window.npcManager.addMessage('alice', 'player', 'What\'s up?');
|
||
window.npcManager.addMessage('alice', 'npc', 'I found some anomalies in the security logs.');
|
||
log('✅ Added messages to Alice conversation', 'success');
|
||
|
||
// Add test messages to Bob
|
||
window.npcManager.addMessage('bob', 'npc', 'Quick question about the server room access.');
|
||
window.npcManager.addMessage('bob', 'player', 'Go ahead');
|
||
log('✅ Added messages to Bob conversation', 'success');
|
||
} catch (error) {
|
||
log(`❌ Error sending messages: ${error.message}`, 'error');
|
||
console.error(error);
|
||
}
|
||
}
|
||
|
||
function testViewHistory() {
|
||
log('📜 Viewing conversation history...', 'info');
|
||
|
||
if (!window.npcManager) {
|
||
log('❌ NPC manager not initialized', 'error');
|
||
return;
|
||
}
|
||
|
||
try {
|
||
const npcs = ['alice', 'bob', 'charlie'];
|
||
|
||
npcs.forEach(npcId => {
|
||
const history = window.npcManager.getConversationHistory(npcId);
|
||
const npc = window.npcManager.getNPC(npcId);
|
||
|
||
if (history.length === 0) {
|
||
log(` ${npc?.displayName || npcId}: No messages`, 'info');
|
||
} else {
|
||
log(` ${npc?.displayName || npcId}: ${history.length} messages`, 'info');
|
||
history.forEach((msg, idx) => {
|
||
log(` ${idx + 1}. [${msg.type}] ${msg.text.substring(0, 50)}...`, 'info');
|
||
});
|
||
}
|
||
});
|
||
} catch (error) {
|
||
log(`❌ Error viewing history: ${error.message}`, 'error');
|
||
console.error(error);
|
||
}
|
||
}
|
||
|
||
function testClearHistory() {
|
||
log('🗑️ Clearing conversation history...', 'info');
|
||
|
||
if (!window.npcManager) {
|
||
log('❌ NPC manager not initialized', 'error');
|
||
return;
|
||
}
|
||
|
||
try {
|
||
const npcs = ['alice', 'bob', 'charlie'];
|
||
|
||
npcs.forEach(npcId => {
|
||
window.npcManager.clearConversationHistory(npcId);
|
||
log(`✅ Cleared history for ${npcId}`, 'success');
|
||
});
|
||
} catch (error) {
|
||
log(`❌ Error clearing history: ${error.message}`, 'error');
|
||
console.error(error);
|
||
}
|
||
}
|
||
|
||
// Auto-run setup on page load
|
||
window.addEventListener('load', () => {
|
||
log('🚀 Page loaded, ready for testing', 'success');
|
||
log('💡 Click "Initialize Systems" to begin', 'info');
|
||
});
|
||
</script>
|
||
</body>
|
||
</html>
|