diff --git a/S2/DevWeb/Projet/src/main/webapp/WEB-INF/pages/game.jsp b/S2/DevWeb/Projet/src/main/webapp/WEB-INF/pages/game.jsp
index 036ef7b..b470f03 100644
--- a/S2/DevWeb/Projet/src/main/webapp/WEB-INF/pages/game.jsp
+++ b/S2/DevWeb/Projet/src/main/webapp/WEB-INF/pages/game.jsp
@@ -10,6 +10,7 @@
${translator.translate('game_information_created_at')} ${game.createdAt.toLocaleString()}
diff --git a/S2/DevWeb/Projet/src/main/webapp/static/css/global.css b/S2/DevWeb/Projet/src/main/webapp/static/css/global.css index d27cd7f..0bd2d15 100644 --- a/S2/DevWeb/Projet/src/main/webapp/static/css/global.css +++ b/S2/DevWeb/Projet/src/main/webapp/static/css/global.css @@ -2,6 +2,7 @@ --bulma-primary-h: 0; --bulma-primary-s: 70%; --bulma-primary-l: 35%; + --bulma-light-l: 96%; --modal-content-width: 50rem; --bulma-custom-footer-padding: 1rem 1.5rem 1rem; } @@ -18,6 +19,13 @@ label.radio.button > input[type="radio"] { display: none; } +a.is-disable { + pointer-events: none; + cursor: not-allowed; + opacity: 0.5; + color:black +} + @media screen and (min-width: 769px) { .modal-card, .modal-content { width: var(--modal-content-width) !important; diff --git a/S2/DevWeb/Projet/src/main/webapp/static/js/notification/error.js b/S2/DevWeb/Projet/src/main/webapp/static/js/notification/error.js index 64b8082..6d81fbd 100644 --- a/S2/DevWeb/Projet/src/main/webapp/static/js/notification/error.js +++ b/S2/DevWeb/Projet/src/main/webapp/static/js/notification/error.js @@ -1,4 +1,4 @@ -export function onError(error, inputs) { +export function onError(error, inputs = []) { // Animations des champs const languageSelector = document.getElementById('language-select'); @@ -25,6 +25,7 @@ export function onError(error, inputs) { const notificationMessage = document.createElement("p"); notificationMessage.classList.add("subtitle", "is-6"); + console.log(error.message) notificationMessage.innerHTML = error.message; notificationTitle.appendChild(notificationIcon); diff --git a/S2/DevWeb/Projet/src/main/webapp/static/js/notification/information.js b/S2/DevWeb/Projet/src/main/webapp/static/js/notification/information.js new file mode 100644 index 0000000..7f18901 --- /dev/null +++ b/S2/DevWeb/Projet/src/main/webapp/static/js/notification/information.js @@ -0,0 +1,25 @@ +export function onInfo(title, message) { + + // Notification + const notification = document.createElement("div"); + notification.classList.add("notification", "is-info", "is-light"); + + const notificationTitle = document.createElement("p"); + notificationTitle.classList.add("title", "is-6"); + notificationTitle.innerHTML = title; + + const notificationIcon = document.createElement("span"); + notificationIcon.classList.add("icon"); + notificationIcon.innerHTML = ""; + + const notificationMessage = document.createElement("p"); + notificationMessage.classList.add("subtitle", "is-6"); + notificationMessage.innerHTML = message; + + notificationTitle.appendChild(notificationIcon); + notification.appendChild(notificationTitle); + notification.appendChild(notificationMessage); + document.body.appendChild(notification); + + setTimeout(() => notification.remove(), 5010); +} diff --git a/S2/DevWeb/Projet/src/main/webapp/static/js/websockets/game-management-websocket.js b/S2/DevWeb/Projet/src/main/webapp/static/js/websockets/game-management-websocket.js index e69de29..3d84175 100644 --- a/S2/DevWeb/Projet/src/main/webapp/static/js/websockets/game-management-websocket.js +++ b/S2/DevWeb/Projet/src/main/webapp/static/js/websockets/game-management-websocket.js @@ -0,0 +1,271 @@ +import WebsocketToolkit from "../WebsocketToolkit.js"; +import PlayerHand from "../PlayerHand.js" +import Card from "../Card.js" +import {onInfo} from "../notification/information.js"; +import {onError} from "../notification/error.js"; +const languageSelector = document.getElementById('language-select'); + +const choice = document.querySelector('#choice'); +// Game information +const gameId = document.querySelector('#game-id'); +const gameTimer = document.querySelector('#game-timer'); + +//User session information +const userSessionId = document.querySelector('#user-id'); +const userSessionUsername = document.querySelector('#user-username'); + +let gameAdminID = -1 +const buttons = document.querySelectorAll('a#start-game-button, a#invite-player') + +function updateButtons(user) { + buttons.forEach(button => { + if (user.id !== gameAdminID ) { + console.log("not admin" + user.username) + button.classList.add('is-disable'); + button.setAttribute('title', 'Accessible uniquement par l\'admin'); + } else { + console.log("is admin" + user.username) + button.classList.remove('is-disable'); + button.removeAttribute('title'); + } + }); +} + +function updateAdmin(user) { + if (gameAdminID !== -1) { + let titleInfo; + let messageInfo; + if (languageSelector.value === "EN") { + titleInfo = "The admin has leaved the game"; + messageInfo = "You are automatically select has thenew admin"; + } else { + titleInfo = "L'admin a quitté la partie"; + messageInfo = "Vous êtes automatiquement désigné comme le nouvel admin"; + } + onInfo(titleInfo, messageInfo) + } + console.log("admin:" + user.username) + gameAdminID = user.id; +} +let havePlayed = false; + +const timer = gameTimer.value; +let remainingTime = timer; +let timerInterval; + +// Display timer +document.querySelector('#timer').innerText = remainingTime + "s"; + +const interval = () => { + remainingTime--; + + document.querySelector('#timer').innerText = remainingTime + "s"; + + if (remainingTime <= 0) clearInterval(timerInterval); +} + +choice.querySelectorAll('button').forEach(button => { + button.addEventListener('click', () => { + const message = { + type: "click", + data: button.dataset.value + } + wsgame.ws.send(JSON.stringify(message)); + + havePlayed = true; + + // Disable buttons + choice.querySelectorAll('button').forEach(button => button.disabled = true); + }); +}); + + +const url = new URL(window.location.href); +const contextPath = url.pathname.substring(0, url.pathname.indexOf("/", 1) + 1) +url.pathname = contextPath + "ws/game/"+gameId.value; +url.protocol = "ws:"; +url.searchParams.delete("id"); + +const wsgame = new WebsocketToolkit(url); +wsgame.onOpen(() => { + console.log("Connected to the server (GameWS)") + + const message = { + type: "connection", + data: JSON.stringify({ + id: userSessionId.value, + username: userSessionUsername.value + }) + } + + wsgame.ws.send(JSON.stringify(message)) +}); +wsgame.onMessage("updatePlayerList", (data) => { + players = data; + console.log(players) + if (gameAdminID === -1 || players[0].user.id !== gameAdminID) { + updateAdmin(players[0].user) + + } + players.forEach((player) => { + console.log("player:" + player.user.id) + console.log("user:" + userSessionId.value) + console.log( player.user.id.toString() == userSessionId.value) + if (player.user.id.toString() === userSessionId.value) { + updateButtons(player.user) + } + }); + updatePlayerList(); +}); +wsgame.onMessage("start", (game) => { + currentGame = game; + + document.querySelector('#gameWaiting').style.display = 'none'; + document.querySelector('#gameStarted').style.display = 'block'; + + timerInterval = setInterval(interval, 1000); + + const deck = document.querySelector('#deck'); // Column + const myCard = document.querySelector('#myCard'); // Column + const otherCards = document.querySelector('#otherCards'); // Columns + const round = document.querySelector('#round'); + + // Reset content + deck.innerHTML = ""; + myCard.innerHTML = ""; + otherCards.innerHTML = ""; + round.innerText = ""; + + // Show current round + round.innerText = (currentGame.currentRound + 1) + + // Show other player cards + game.players + .filter(p => p.user.id !== userSessionId.value) + .forEach(p => { + const playerHand = new PlayerHand(p); + otherCards.innerHTML += playerHand.render({ + textPosition: PlayerHand.TextPosition.TOP, + className: "column" + }); + }); + + // Show my card + const me = game.players.find(p => p.user.id === userSessionId.value); + + const playerHand = new PlayerHand(me); + myCard.innerHTML += playerHand.render({ + textPosition: PlayerHand.TextPosition.BOTTOM, + className: "column" + }); + + // Show deck + const deckCard = new Card(game.currentCard.color, game.currentCard.value); + deck.innerHTML = deckCard.render(); +}) +wsgame.onMessage("updatePlayer", (p) => { + document.querySelector(".player-" + p.user.id + " .card-play").style.boxShadow = "inset 0px 0px 30px 10px orange"; +}) +wsgame.onMessage("timerEnd", (game) => { + if (!havePlayed) { + const message = { + type: "click", + data: "TIMER_END" + } + wsgame.ws.send(JSON.stringify(message)); + } +}) + +wsgame.onMessage("nextRound", (game) => { + currentGame = game; + + document.querySelector('#gameWaiting').style.display = 'none'; + document.querySelector('#gameStarted').style.display = 'block'; + + const deck = document.querySelector('#deck'); // Column + const choice = document.querySelector('#choice'); + const myCard = document.querySelector('#myCard'); // Column + const otherCards = document.querySelector('#otherCards'); // Columns + const round = document.querySelector('#round'); + + clearInterval(timerInterval); + remainingTime = timer; + document.querySelector('#timer').innerText = remainingTime + "s"; + timerInterval = setInterval(interval, 1000); + + // Reset content + deck.innerHTML = ""; + myCard.innerHTML = ""; + otherCards.innerHTML = ""; + round.innerText = ""; + havePlayed = false; + choice.querySelectorAll('button').forEach(button => button.disabled = false); + + // Show the current round + round.innerText = (currentGame.currentRound + 1) + + // Show other player cards + game.players + .filter(p => p.user.id !== userSessionId.value) + .forEach(p => { + const playerHand = new PlayerHand(p); + otherCards.innerHTML += playerHand.render({ + textPosition: PlayerHand.TextPosition.TOP, + className: "column" + }); + }); + + // Show my card + const me = game.players.find(p => p.user.id === userSessionId.value); + + const playerHand = new PlayerHand(me); + myCard.innerHTML += playerHand.render({ + textPosition: PlayerHand.TextPosition.BOTTOM, + className: "column" + }); + + // Show deck + const deckCard = new Card(game.currentCard.color, game.currentCard.value); + deck.innerHTML = deckCard.render(); +}) + +wsgame.onMessage("end", (game) => { + clearInterval(timerInterval); + window.location.href = "${pageContext.request.contextPath}/game-statistics?id=${game.id}&endGame=true"; +}) + +// Close handling +wsgame.onClose(() => console.log("Disconnected from the server (GameWS)")); + +// Game +let currentGame; + +// Player List +let players = []; +const playerList = document.querySelector('#playerList tbody'); + +function updatePlayerList() { + playerList.innerHTML = ''; + players.forEach(player => { + const tr = document.createElement('tr'); + const td = document.createElement('td'); + td.textContent = player.user.username; + tr.appendChild(td); + playerList.appendChild(tr); + }); +} + +// Start Game Button +document.querySelector('#start-game-button').addEventListener('click', () => { + if (players.length < 2 || players.length > 4) { + if (languageSelector.value === "EN") { + onError(new Error("You need between 2 and 4 players to start the game")); + } else { + onError(new Error("Il faut entre 2 et 4 joueurs pour démarrer la partie")); + } + return; + } + + const message = {type: "start", data: ""} + wsgame.ws.send(JSON.stringify(message)); +});