Files
Escapepage/assets/game1.js
2026-01-08 15:34:43 +01:00

258 lines
8.6 KiB
JavaScript

/* Game1 entry point built with Webpack Encore */
import './styles/game1.css';
let sequenceFinished = false;
let stillPlayingSound = true;
function subscribeToMercure(mercurePublicUrl, topic, myScreen) {
try {
const url = mercurePublicUrl + '?topic=' + encodeURIComponent(topic);
const es = new EventSource(url);
es.onmessage = (event) => {
try {
const data = JSON.parse(event.data);
console.log('[Mercure][game1] Update:', data);
// data is [sendTo, message]
if (Array.isArray(data) && data.length >= 2) {
const sendTo = parseInt(data[0]);
// Filter: 0 means everyone, otherwise must match myScreen
if (sendTo !== 0 && sendTo !== parseInt(myScreen)) {
console.log('[Mercure][game1] Message not for this player, skipping.');
return;
}
const messageContainer = document.getElementById('message-container');
if (messageContainer) {
const msgEl = document.createElement('div');
msgEl.className = 'message';
msgEl.textContent = data[1];
msgEl.style.color = '#0F0'; // Green for incoming messages
msgEl.style.marginBottom = '10px';
messageContainer.appendChild(msgEl);
window.scrollTo(0, document.body.scrollHeight);
if(stillPlayingSound)
playSound();
console.log('[Mercure][game1] sequenceFinished status:', sequenceFinished);
if (sequenceFinished) {
flashRed();
}
}
}
} catch (e) {
console.log('[Mercure][game1] Raw event:', event.data);
}
};
es.onerror = (err) => {
console.warn('[Mercure][game1] EventSource error:', err);
};
console.log('[Mercure][game1] Subscribed to', url);
} catch (e) {
console.error('[Mercure][game1] Failed to subscribe:', e);
}
}
function playSound() {
const sound = document.getElementById('message-sound');
if (sound) {
sound.currentTime = 0;
sound.play().catch(e => console.warn('[Audio] Playback failed:', e));
}
}
function flashRed() {
console.log('[Game1] Triggering flashRed');
const body = document.body;
body.classList.remove('flash-red');
void body.offsetWidth; // Trigger reflow to restart animation
body.classList.add('flash-red');
// Also remove it after animation finishes so it's clean for inspection
setTimeout(() => {
body.classList.remove('flash-red');
console.log('[Game1] Removed flash-red class');
}, 150);
}
async function fetchJson(url, options = {}) {
const opts = { ...options };
const headers = new Headers(opts.headers || {});
headers.set('Accept', 'application/json');
if (opts.body !== undefined && typeof opts.body !== 'string') {
headers.set('Content-Type', 'application/json');
opts.body = JSON.stringify(opts.body);
}
// Useful convention for server-side checks
if (!headers.has('X-Requested-With')) {
headers.set('X-Requested-With', 'XMLHttpRequest');
}
opts.headers = headers;
const res = await fetch(url, opts);
const text = await res.text();
let data;
try { data = text ? JSON.parse(text) : null; } catch (e) { data = text; }
if (!res.ok) {
const err = new Error('HTTP ' + res.status + ' ' + res.statusText);
console.error('[API][game1]', err, data);
throw err;
}
return data;
}
document.addEventListener('DOMContentLoaded', async () => {
// Simple boot log so you can verify it in the browser console
// and confirm this specific bundle is loaded on the Game Hub page.
console.log('Game1 bundle loaded');
// Example: add a CSS class to <body> so page-specific styles can apply
document.body.classList.add('game1-page');
// Look for config injected by Twig in the page
const cfgEl = document.getElementById('mercure-config');
// Prevent/warn on page reload
window.addEventListener('beforeunload', (event) => {
// Standard way to trigger the browser's confirmation dialog
event.preventDefault();
// Included for compatibility with older browsers
event.returnValue = '';
});
if (!cfgEl) {
console.warn('[Mercure][game1] #mercure-config element not found on page');
return;
}
const mercurePublicUrl = cfgEl.dataset.mercurePublicUrl;
const topic = cfgEl.dataset.topic;
const screen = cfgEl.dataset.screen;
const apiPingUrl = cfgEl.dataset.apiPingUrl;
const apiEchoUrl = cfgEl.dataset.apiEchoUrl;
if (mercurePublicUrl && topic) {
subscribeToMercure(mercurePublicUrl, topic, screen);
} else {
console.warn('[Mercure][game1] Missing data attributes on #mercure-config');
}
// Demo API calls
try {
if (apiPingUrl) {
const ping = await fetchJson(apiPingUrl);
console.log('[API][game1] ping →', ping);
} else {
console.warn('[API][game1] data-api-ping-url missing');
}
if (apiEchoUrl) {
const echo = await fetchJson(apiEchoUrl, {
method: 'POST',
body: { message: 'from game1.js', ts: new Date().toISOString() },
});
console.log('[API][game1] echo →', echo);
} else {
console.warn('[API][game1] data-api-echo-url missing');
}
} catch (e) {
console.error('[API][game1] Request failed:', e);
}
// Add messages to message-container
const messageContainer = document.getElementById('message-container');
if (messageContainer) {
let messages = [
['System initializing...', 500],
['Connection established.', 200],
['Welcome agent to the mainframe.', 1000],
['Scanning...', 3000],
['Virus detected.', 500],
['Starting Mainframe help modus...', 2000],
['Help modus activated.', 500],
['Blocking virus activated', 0]
];
let currentMessageIndex = 0;
const printNextMessage = () => {
if (currentMessageIndex < messages.length) {
const msg = messages[currentMessageIndex];
const msgEl = document.createElement('div');
let extraClass = '';
if(msg[2])
extraClass = msg[2];
msgEl.className = 'message ' + extraClass;
msgEl.textContent = msg[0];
msgEl.style.marginBottom = '10px';
messageContainer.appendChild(msgEl);
window.scrollTo(0, document.body.scrollHeight);
playSound();
currentMessageIndex++;
setTimeout(printNextMessage, msg[1]);
if (sequenceFinished) {
flashRed();
}
} else {
// After it has printed a set of messages, it has to start a timer of 2 seconds
console.log('[Game1] All messages printed. Starting 2s timer to expand message-container height...');
setTimeout(() => {
messageContainer.style.height = '400vh';
const inputField = document.getElementById('input-message');
inputField.disabled = false;
// Add event listener for Enter key
inputField.addEventListener('keypress', async (e) => {
if (e.key === 'Enter') {
stillPlayingSound = false;
sequenceFinished = false;
const message = inputField.value.trim();
const msgEl = document.createElement('div');
msgEl.className = 'message';
msgEl.textContent = message;
msgEl.style.marginBottom = '10px';
messageContainer.appendChild(msgEl);
if (message && apiEchoUrl) {
inputField.value = '';
try {
const response = await fetchJson(apiEchoUrl, {
method: 'POST',
body: { message, ts: new Date().toISOString() },
});
console.log('[API][game1] message sent →', response);
if (response && response.result && Array.isArray(response.result.result)) {
response.result.result.forEach(text => {
const msgEl = document.createElement('div');
msgEl.className = 'message';
msgEl.textContent = text;
msgEl.style.marginBottom = '10px';
messageContainer.appendChild(msgEl);
});
window.scrollTo(0, document.body.scrollHeight);
}
} catch (err) {
console.error('[API][game1] Failed to send message:', err);
}
}
}
});
console.log('[Game1] message-container height changed to 400vh and input enabled');
sequenceFinished = true;
console.log('[Game1] sequenceFinished is now TRUE');
}, 2000);
}
};
printNextMessage();
}
});