tiktoktak/web-client/target/classes/static/js/app.js
2026-02-10 15:01:44 +01:00

210 lines
6 KiB
JavaScript

const menuPanel = document.getElementById('menu');
const gamePanel = document.getElementById('game');
const statusDiv = document.getElementById('connection-status');
const createBtn = document.getElementById('create-btn');
const joinBtn = document.getElementById('join-btn');
const joinInput = document.getElementById('join-code');
const displayCode = document.getElementById('display-code');
const turnStatus = document.getElementById('turn-status');
const leaveBtn = document.getElementById('leave-btn');
const surrenderBtn = document.getElementById('surrender-btn');
const cells = document.querySelectorAll('.cell');
// Game State
let mySymbol = '';
let ws = null;
let currentCode = '';
function send(msg) {
if (ws && ws.readyState === WebSocket.OPEN) {
ws.send(msg);
}
}
// Event Listeners
createBtn.addEventListener('click', () => {
send('CREATE');
});
joinBtn.addEventListener('click', () => {
const code = joinInput.value.trim();
if (code) send(`JOIN ${code}`);
});
leaveBtn.addEventListener('click', () => {
if (confirm('Are you sure you want to leave the lobby?')) {
send('LEAVE');
resetGame();
}
});
surrenderBtn.addEventListener('click', () => {
if (confirm('Are you sure you want to surrender?')) {
send('SURRENDER');
}
});
cells.forEach(cell => {
cell.addEventListener('click', () => {
if (!mySymbol) return;
const r = cell.dataset.r;
const c = cell.dataset.c;
send(`MOVE ${r} ${c}`);
});
});
// ...
function handleMessage(msg) {
console.log("Received:", msg);
const parts = msg.split(' ');
const cmd = parts[0];
switch (cmd) {
case 'WELCOME':
log("Server Handshake received.");
statusDiv.textContent = 'Connected to Server';
statusDiv.style.color = '#10b981';
break;
case 'GAME_CREATED':
currentCode = parts[1];
mySymbol = 'X';
enterGame();
updateStatus("Waiting for opponent...");
break;
case 'JOIN_SUCCESS':
currentCode = joinInput.value;
mySymbol = 'O';
enterGame();
updateStatus("Connected! Game starting soon...");
break;
case 'START':
updateStatus("Game Started! X goes first.");
break;
case 'RESTART':
updateStatus("Game Restarted! X goes first.");
cells.forEach(c => {
c.textContent = '';
c.className = 'cell';
});
break;
case 'BOARD':
const boardStr = msg.substring(6);
updateBoard(boardStr);
break;
case 'TURN':
const turn = parts[1];
if (turn === mySymbol) {
updateStatus(`Your Turn (${mySymbol})`, true);
} else {
updateStatus(`Opponent's Turn (${turn})`, false);
}
break;
case 'WIN':
const winner = msg.substring(4);
setTimeout(() => {
if (confirm(`Game Over! Winner: ${winner}\nDo you want to play again?`)) {
send('RESTART');
}
}, 100);
break;
case 'DRAW':
setTimeout(() => {
if (confirm("Game Over! It's a draw!\nDo you want to play again?")) {
send('RESTART');
}
}, 100);
break;
case 'OPPONENT_LEFT':
alert("Opponent has left the lobby.");
resetGame();
break;
case 'ERROR:':
alert(msg);
break;
}
}
function enterGame() {
menuPanel.classList.add('hidden');
gamePanel.classList.remove('hidden');
displayCode.textContent = currentCode;
// Clear board
cells.forEach(c => {
c.textContent = '';
c.className = 'cell';
});
}
function resetGame() {
menuPanel.classList.remove('hidden');
gamePanel.classList.add('hidden');
currentCode = '';
mySymbol = '';
joinInput.value = '';
statusDiv.textContent = 'Connected to Server';
statusDiv.style.color = '#10b981';
}
const visibleDebug = document.getElementById('visible-debug');
function log(text) {
if (!visibleDebug) return;
const now = new Date().toLocaleTimeString();
visibleDebug.innerHTML += `<div>[${now}] ${text}</div>`;
console.log(text);
}
function connect() {
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
const url = `${protocol}//${window.location.host}/game`;
log(`Connecting to WebSocket: ${url}`);
ws = new WebSocket(url);
ws.onopen = () => {
log('WebSocket: OnOpen fired. Connected.');
statusDiv.textContent = 'Connected to Server';
statusDiv.style.color = '#10b981';
};
ws.onclose = (event) => {
log(`WebSocket: OnClose fired. Code: ${event.code}, Reason: ${event.reason}`);
statusDiv.textContent = 'Disconnected. Reconnecting...';
statusDiv.style.color = '#ef4444';
setTimeout(connect, 2000);
};
ws.onerror = (error) => {
log(`WebSocket: OnError fired. State: ${ws.readyState}`);
console.error("WebSocket Error:", error);
};
ws.onmessage = (event) => {
// log(`Received: ${event.data}`); // don't log every message to avoid spam
handleMessage(event.data);
};
}
function updateBoard(boardStr) {
cells.forEach((cell, i) => {
if (i < boardStr.length) {
const char = boardStr.charAt(i);
cell.textContent = char === ' ' ? '' : char;
cell.className = 'cell';
if (char === 'X') cell.classList.add('x');
if (char === 'O') cell.classList.add('o');
}
});
}
function updateStatus(text, isAction = false) {
turnStatus.textContent = text;
if (isAction) {
turnStatus.style.color = '#10b981'; // Green for 'your turn'
} else {
turnStatus.style.color = '#a1a1aa';
}
}
connect();