diff --git a/public/index.html b/public/index.html index ab90475..4ea08eb 100644 --- a/public/index.html +++ b/public/index.html @@ -467,7 +467,6 @@ const msg = JSON.parse(e.data); if (msg.type === "room_list") updateRoomList(msg.rooms); if (msg.type === "init") { - myRole = msg.role; roomId = msg.roomId; document.getElementById("roomCode").innerText = roomId.toUpperCase(); window.history.replaceState({}, '', `?room=${roomId}`); diff --git a/server.js b/server.js index 6a0ece6..a55bef4 100644 --- a/server.js +++ b/server.js @@ -199,54 +199,68 @@ wss.on("connection", (ws, req) => { const room = rooms[roomId]; ws.roomId = roomId; + ws.sessionId = sessionId; // Store on socket for easy lookup during close let player = room.players.find(p => p.sessionId === sessionId); if (player) { - // Reconnecting existing player player.ws = ws; } else if (room.players.length < 2) { - // New player joining: logic to pick the opposite role let role; if (room.players.length === 1) { - // Pick the role that isn't taken - const takenRole = room.players[0].role; - role = (takenRole === "wolf") ? "sheep" : "wolf"; + role = (room.players[0].role === "wolf") ? "sheep" : "wolf"; } else { - // First player in the room defaults to sheep role = "sheep"; } - - player = { ws, role, sessionId }; + player = { ws, role, sessionId, isBot: false }; room.players.push(player); } - // Inform the client of their assigned role ws.send(JSON.stringify({ type: "init", role: player.role, roomId })); - broadcastRoomList(); broadcastState(roomId); - - // If a bot is involved, update its state if (room.players.some(p => p.isBot)) sendBotState(roomId); + // --- HANDLE DISCONNECT --- + ws.on("close", () => { + const currentRoom = rooms[ws.roomId]; + if (!currentRoom) return; + + // Remove the player from the room array + currentRoom.players = currentRoom.players.filter(p => p.sessionId !== ws.sessionId); + + // If the room is now empty (or only contains a bot), delete it + const humanRemaining = currentRoom.players.some(p => !p.isBot); + if (currentRoom.players.length === 0 || (!humanRemaining && currentRoom.players.some(p => p.isBot))) { + // If it was a bot room, close the bot socket before deleting + const bot = currentRoom.players.find(p => p.isBot); + if (bot && bot.socket) bot.socket.destroy(); + delete rooms[ws.roomId]; + } else { + // Room still has someone, notify them + broadcastState(ws.roomId); + } + + broadcastRoomList(); + }); + ws.on("message", msg => { let data = JSON.parse(msg); + const playerObj = room.players.find(p => p.sessionId === sessionId); + if (!playerObj) return; + if (data.type === "restart") { swapRoles(room); room.game = { wolf: 5, sheep: [0, 1, 3], turn: "sheep", moveCount: 0, winner: null, lastMove: null }; - - // Critical: Re-sync roles for all human clients on restart room.players.forEach(p => { if (p.ws && p.ws.readyState === WebSocket.OPEN) { p.ws.send(JSON.stringify({ type: "init", role: p.role, roomId })); } }); - broadcastState(roomId); if (room.players.some(p => p.isBot)) sendBotState(roomId); } else { - handleMove(roomId, player.role, data); + handleMove(roomId, playerObj.role, data); } }); });