mirror of
https://github.com/cliffe/BreakEscape.git
synced 2026-02-21 11:18:08 +00:00
- Added a visual problem-solution summary for debugging NPC event handling. - Resolved cooldown bug in NPCManager by implementing explicit null/undefined checks. - Modified PersonChatMinigame to prioritize event parameters over state restoration. - Updated security guard dialogue in Ink scenarios to improve interaction flow. - Adjusted vault key parameters in npc-patrol-lockpick.json for consistency. - Changed inventory stylesheet references to hud.css in test HTML files for better organization.
418 lines
14 KiB
HTML
418 lines
14 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>NPC Interaction Test</title>
|
|
<link rel="stylesheet" href="css/main.css">
|
|
<link rel="stylesheet" href="css/panels.css">
|
|
<link rel="stylesheet" href="css/modals.css">
|
|
<link rel="stylesheet" href="css/hud.css">
|
|
<link rel="stylesheet" href="css/person-chat-minigame.css">
|
|
<link rel="stylesheet" href="css/npc-interactions.css">
|
|
<style>
|
|
body {
|
|
margin: 0;
|
|
padding: 20px;
|
|
background-color: #222;
|
|
color: #fff;
|
|
font-family: Arial, sans-serif;
|
|
}
|
|
.test-container {
|
|
max-width: 1200px;
|
|
margin: 0 auto;
|
|
}
|
|
h1 {
|
|
color: #4da6ff;
|
|
border-bottom: 2px solid #4da6ff;
|
|
padding-bottom: 10px;
|
|
}
|
|
.test-section {
|
|
background-color: #333;
|
|
border: 2px solid #4da6ff;
|
|
border-radius: 4px;
|
|
padding: 15px;
|
|
margin: 15px 0;
|
|
}
|
|
.test-button {
|
|
background-color: #4da6ff;
|
|
color: #000;
|
|
border: none;
|
|
padding: 10px 20px;
|
|
margin: 5px;
|
|
cursor: pointer;
|
|
font-weight: bold;
|
|
border-radius: 4px;
|
|
font-size: 14px;
|
|
}
|
|
.test-button:hover {
|
|
background-color: #6dbfff;
|
|
}
|
|
.test-output {
|
|
background-color: #222;
|
|
border: 1px solid #666;
|
|
border-radius: 4px;
|
|
padding: 10px;
|
|
margin-top: 10px;
|
|
font-family: monospace;
|
|
font-size: 12px;
|
|
max-height: 400px;
|
|
overflow-y: auto;
|
|
white-space: pre-wrap;
|
|
word-wrap: break-word;
|
|
}
|
|
.status {
|
|
display: inline-block;
|
|
padding: 3px 8px;
|
|
border-radius: 3px;
|
|
font-weight: bold;
|
|
margin: 0 5px;
|
|
}
|
|
.status.ok {
|
|
background-color: #4db84d;
|
|
color: white;
|
|
}
|
|
.status.error {
|
|
background-color: #d9534f;
|
|
color: white;
|
|
}
|
|
.status.warning {
|
|
background-color: #f0ad4e;
|
|
color: black;
|
|
}
|
|
#gameContainer {
|
|
margin-top: 20px;
|
|
border: 2px solid #666;
|
|
background-color: #000;
|
|
}
|
|
.instructions {
|
|
background-color: #1a3a1a;
|
|
border-left: 4px solid #4db84d;
|
|
padding: 10px;
|
|
margin: 10px 0;
|
|
border-radius: 3px;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="test-container">
|
|
<h1>🎭 NPC Interaction System Test</h1>
|
|
|
|
<div class="instructions">
|
|
<strong>Test Procedure:</strong>
|
|
<ol>
|
|
<li>Click "Load NPC Test Scenario" to start the game</li>
|
|
<li>Walk the player character near either NPC</li>
|
|
<li>Look for "Press E to talk to [NPC Name]" prompt at the bottom</li>
|
|
<li>Press E to trigger the conversation</li>
|
|
<li>Verify the conversation UI appears with portraits and dialogue</li>
|
|
</ol>
|
|
</div>
|
|
|
|
<div class="test-section">
|
|
<h2>🔧 System Checks</h2>
|
|
<button class="test-button" onclick="checkNPCSystem()">Check NPC System</button>
|
|
<button class="test-button" onclick="checkNPCProximity()">Check Proximity Detection</button>
|
|
<button class="test-button" onclick="listNPCs()">List All NPCs</button>
|
|
<button class="test-button" onclick="testInteractionPrompt()">Test Interaction Prompt</button>
|
|
<button class="test-button" onclick="clearConsole()">Clear Output</button>
|
|
<div id="systemOutput" class="test-output">Waiting for tests...</div>
|
|
</div>
|
|
|
|
<div class="test-section">
|
|
<h2>🎮 Game Controls</h2>
|
|
<button class="test-button" onclick="startGame()">Load NPC Test Scenario</button>
|
|
<button class="test-button" onclick="resetGame()">Reset Game</button>
|
|
<div id="gameOutput" class="test-output">Game status: Ready</div>
|
|
</div>
|
|
|
|
<div class="test-section">
|
|
<h2>📊 Debug Info</h2>
|
|
<button class="test-button" onclick="showDebugInfo()">Show Full Debug Info</button>
|
|
<button class="test-button" onclick="manuallyTriggerInteraction()">Manually Trigger E-Key</button>
|
|
<div id="debugOutput" class="test-output">Debug info will appear here...</div>
|
|
</div>
|
|
|
|
<div id="gameContainer"></div>
|
|
</div>
|
|
|
|
<script type="module">
|
|
import('./js/main.js').then(() => {
|
|
updateGameStatus('Game module loaded');
|
|
});
|
|
|
|
window.testFunctions = {
|
|
checkNPCSystem,
|
|
checkNPCProximity,
|
|
listNPCs,
|
|
testInteractionPrompt,
|
|
clearConsole,
|
|
startGame,
|
|
resetGame,
|
|
showDebugInfo,
|
|
manuallyTriggerInteraction
|
|
};
|
|
|
|
function log(message, type = 'info') {
|
|
console.log(`[${type.toUpperCase()}] ${message}`);
|
|
}
|
|
|
|
function output(text, elementId = 'systemOutput') {
|
|
const elem = document.getElementById(elementId);
|
|
if (elem) {
|
|
elem.textContent += text + '\n';
|
|
elem.scrollTop = elem.scrollHeight;
|
|
}
|
|
}
|
|
|
|
function clearOutput(elementId = 'systemOutput') {
|
|
const elem = document.getElementById(elementId);
|
|
if (elem) {
|
|
elem.textContent = '';
|
|
}
|
|
}
|
|
|
|
function checkNPCSystem() {
|
|
clearOutput('systemOutput');
|
|
output('🔍 Checking NPC System...\n');
|
|
|
|
const checks = [
|
|
{ name: 'window.npcManager', check: () => window.npcManager },
|
|
{ name: 'window.player', check: () => window.player },
|
|
{ name: 'window.MinigameFramework', check: () => window.MinigameFramework },
|
|
{ name: 'window.checkNPCProximity', check: () => window.checkNPCProximity },
|
|
{ name: 'window.tryInteractWithNearest', check: () => window.tryInteractWithNearest }
|
|
];
|
|
|
|
let passed = 0;
|
|
let failed = 0;
|
|
|
|
checks.forEach(({ name, check }) => {
|
|
try {
|
|
const result = check();
|
|
if (result) {
|
|
output(`✅ ${name}`);
|
|
passed++;
|
|
} else {
|
|
output(`❌ ${name} - exists but is falsy`);
|
|
failed++;
|
|
}
|
|
} catch (e) {
|
|
output(`❌ ${name} - ${e.message}`);
|
|
failed++;
|
|
}
|
|
});
|
|
|
|
output(`\n📊 Results: ${passed} passed, ${failed} failed`);
|
|
}
|
|
|
|
function checkNPCProximity() {
|
|
clearOutput('systemOutput');
|
|
output('🔍 Checking NPC Proximity Detection...\n');
|
|
|
|
if (!window.npcManager) {
|
|
output('❌ npcManager not available');
|
|
return;
|
|
}
|
|
|
|
output(`NPCs registered: ${window.npcManager.npcs.size}\n`);
|
|
|
|
if (window.npcManager.npcs.size === 0) {
|
|
output('⚠️ No NPCs registered. Load a scenario first.\n');
|
|
return;
|
|
}
|
|
|
|
if (!window.player) {
|
|
output('❌ Player not available');
|
|
return;
|
|
}
|
|
|
|
output(`Player position: (${window.player.x}, ${window.player.y})\n`);
|
|
|
|
// Calculate distances to all NPCs
|
|
let found = false;
|
|
window.npcManager.npcs.forEach((npc) => {
|
|
if (npc._sprite) {
|
|
const dx = npc._sprite.x - window.player.x;
|
|
const dy = npc._sprite.y - window.player.y;
|
|
const distance = Math.sqrt(dx * dx + dy * dy);
|
|
const inRange = distance <= 64;
|
|
|
|
output(`${inRange ? '✅' : '⚠️'} ${npc.displayName} (${npc.id})`);
|
|
output(` Position: (${npc._sprite.x}, ${npc._sprite.y})`);
|
|
output(` Distance: ${distance.toFixed(2)}px (${inRange ? 'IN RANGE' : 'OUT OF RANGE'})`);
|
|
output(` Type: ${npc.npcType}`);
|
|
output(` Sprite active: ${npc._sprite.active}\n`);
|
|
|
|
if (inRange) found = true;
|
|
}
|
|
});
|
|
|
|
if (found) {
|
|
output('🎯 At least one NPC is in range!\n');
|
|
} else {
|
|
output('⚠️ No NPCs are in range. Move player closer.\n');
|
|
}
|
|
|
|
// Manually run proximity check
|
|
if (window.checkNPCProximity) {
|
|
output('Running checkNPCProximity()...\n');
|
|
window.checkNPCProximity();
|
|
|
|
const prompt = document.getElementById('npc-interaction-prompt');
|
|
if (prompt) {
|
|
output(`✅ Prompt created: "${prompt.querySelector('.prompt-text').textContent}"`);
|
|
} else {
|
|
output('⚠️ No prompt created');
|
|
}
|
|
}
|
|
}
|
|
|
|
function listNPCs() {
|
|
clearOutput('systemOutput');
|
|
output('📋 NPC Listing\n');
|
|
|
|
if (!window.npcManager) {
|
|
output('❌ npcManager not available');
|
|
return;
|
|
}
|
|
|
|
const count = window.npcManager.npcs.size;
|
|
output(`Total NPCs: ${count}\n`);
|
|
|
|
if (count === 0) {
|
|
output('No NPCs registered.');
|
|
return;
|
|
}
|
|
|
|
window.npcManager.npcs.forEach((npc, id) => {
|
|
output(`\n📌 ${npc.displayName} (${id})`);
|
|
output(` Type: ${npc.npcType}`);
|
|
output(` Phone ID: ${npc.phoneId || 'none'}`);
|
|
output(` Story: ${npc.storyPath || 'none'}`);
|
|
output(` Room: ${npc.roomId || 'none'}`);
|
|
|
|
if (npc._sprite) {
|
|
output(` Sprite: YES @ (${npc._sprite.x}, ${npc._sprite.y})`);
|
|
output(` Active: ${npc._sprite.active}`);
|
|
} else {
|
|
output(` Sprite: NO`);
|
|
}
|
|
});
|
|
}
|
|
|
|
function testInteractionPrompt() {
|
|
clearOutput('systemOutput');
|
|
output('🧪 Testing Interaction Prompt\n');
|
|
|
|
if (!window.npcManager) {
|
|
output('❌ npcManager not available');
|
|
return;
|
|
}
|
|
|
|
const npcs = Array.from(window.npcManager.npcs.values());
|
|
if (npcs.length === 0) {
|
|
output('❌ No NPCs to test');
|
|
return;
|
|
}
|
|
|
|
const testNpc = npcs[0];
|
|
output(`Testing with: ${testNpc.displayName}\n`);
|
|
|
|
// Manually create prompt
|
|
output('Creating prompt...\n');
|
|
if (window.updateNPCInteractionPrompt) {
|
|
window.updateNPCInteractionPrompt(testNpc);
|
|
|
|
const prompt = document.getElementById('npc-interaction-prompt');
|
|
if (prompt) {
|
|
output('✅ Prompt created');
|
|
output(` Element: ${prompt.id}`);
|
|
output(` Text: ${prompt.querySelector('.prompt-text').textContent}`);
|
|
output(` NPC ID: ${prompt.dataset.npcId}\n`);
|
|
|
|
output('Prompt is visible on screen\n');
|
|
|
|
// Clear it
|
|
output('Clearing prompt...\n');
|
|
window.updateNPCInteractionPrompt(null);
|
|
|
|
if (!document.getElementById('npc-interaction-prompt')) {
|
|
output('✅ Prompt cleared successfully');
|
|
} else {
|
|
output('❌ Prompt still exists');
|
|
}
|
|
} else {
|
|
output('❌ Prompt not created');
|
|
}
|
|
} else {
|
|
output('❌ updateNPCInteractionPrompt not available');
|
|
}
|
|
}
|
|
|
|
function clearConsole() {
|
|
clearOutput('systemOutput');
|
|
output('🗑️ Output cleared');
|
|
}
|
|
|
|
function startGame() {
|
|
clearOutput('gameOutput');
|
|
output('🎮 Loading NPC Test Scenario...', 'gameOutput');
|
|
|
|
// Redirect to scenario_select with test scenario
|
|
window.location.href = 'scenario_select.html?scenario=npc-sprite-test';
|
|
}
|
|
|
|
function resetGame() {
|
|
clearOutput('gameOutput');
|
|
output('🔄 Resetting game...', 'gameOutput');
|
|
|
|
// Reload page
|
|
location.reload();
|
|
}
|
|
|
|
function showDebugInfo() {
|
|
clearOutput('debugOutput');
|
|
const info = {
|
|
'Player': window.player ? `(${window.player.x}, ${window.player.y})` : 'Not loaded',
|
|
'NPC Manager': window.npcManager ? `${window.npcManager.npcs.size} NPCs` : 'Not loaded',
|
|
'Current Prompt': document.getElementById('npc-interaction-prompt') ? 'Yes' : 'No',
|
|
'MinigameFramework': window.MinigameFramework ? 'Loaded' : 'Not loaded',
|
|
'E-Key Handler': window.tryInteractWithNearest ? 'Ready' : 'Not ready'
|
|
};
|
|
|
|
output('📊 DEBUG INFO\n');
|
|
Object.entries(info).forEach(([key, value]) => {
|
|
output(`${key}: ${value}`);
|
|
});
|
|
}
|
|
|
|
function manuallyTriggerInteraction() {
|
|
clearOutput('debugOutput');
|
|
output('🎯 Manually triggering E-Key interaction...\n');
|
|
|
|
if (!window.tryInteractWithNearest) {
|
|
output('❌ tryInteractWithNearest not available');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
window.tryInteractWithNearest();
|
|
output('✅ Interaction triggered');
|
|
} catch (e) {
|
|
output(`❌ Error: ${e.message}`);
|
|
}
|
|
}
|
|
|
|
function updateGameStatus(msg) {
|
|
const elem = document.getElementById('gameOutput');
|
|
if (elem) {
|
|
elem.textContent = `📊 ${msg}`;
|
|
}
|
|
}
|
|
|
|
window.updateGameStatus = updateGameStatus;
|
|
</script>
|
|
</body>
|
|
</html>
|