const INTRO_IMAGE_PATH = "/static/images/entrée-manoir.png"; const INTERROGATION_IMAGE_PATH = "/static/images/salle-interrogation.png"; const RESULTS_IMAGE_PATH = "/static/images/salle-resultats.png"; const NPC_REACTION_PATH = "/api/v1/getNpcReaction?npcid="; const NPC_IMAGE_PATH = "/api/v1/getNpcImage?npcid="; let npcsIds = []; let gameData = {}; let currentNpc = null; let username = null; /* * Set the current game background to the first element with the current_background CSS class. */ function setGameBackground(backgroundPath) { document.querySelector(".current_background").style.backgroundImage = 'url("' + backgroundPath + '")'; } /** * Set listeners to introduction and interrogation navigation buttons. */ function setIntroductionAndInterrogationListeners() { document.getElementById("introduction_next_btn") .addEventListener("click", showInterrogationViewFromIntroduction); document.getElementById("interrogation_suspect_previous_btn") .addEventListener("click", goBackToInterrogation); document.getElementById("interrogation_next_btn") .addEventListener("click", showEmotionAndCulpritChoicesView); } /** * Set listeners to questions buttons. */ function setQuestionButtonsListeners() { document.getElementById("QA_0") .addEventListener("click", askTypeZeroQuestion); document.getElementById("QA_1") .addEventListener("click", askTypeOneQuestion); } /** * Unset listeners to questions buttons. */ function unsetQuestionButtonsListeners() { document.getElementById("QA_0") .removeEventListener("click", askTypeZeroQuestion); document.getElementById("QA_1") .removeEventListener("click", askTypeOneQuestion); } /** * Go back to interrogation view, by hiding the interrogation suspect view. */ function goBackToInterrogation() { hideFirstClassElement("interrogation_suspect"); showFirstClassElement("interrogation"); } /** * Show the interrogation view from the introduction one and hide the interrogation one. */ function showInterrogationViewFromIntroduction() { hideFirstClassElement("introduction"); showFirstClassElement("interrogation"); setGameBackground(INTERROGATION_IMAGE_PATH); } /** * Show the emotion and culprit choices view and hide the interrogation one. */ function showEmotionAndCulpritChoicesView() { hideFirstClassElement("interrogation"); showFirstClassElement("emotion_and_culprit_choices"); } function getNpcLocationAndPartner(npcid) { const data = {}; const npcidInt = parseInt(npcid); for (const room in gameData["rooms"]) { if (gameData["rooms"][room]["npcs"].includes(npcidInt)) { data["room"] = gameData["rooms"][room]["name"]; if (gameData["rooms"][room]["npcs"].length === 1) { do { const random = Math.floor(Math.random() * npcsIds.length); data["partner"] = npcsIds[random]; } while (data["partner"] === npcidInt); } else { data["partner"] = gameData["rooms"][room]["npcs"] [gameData["rooms"][room]["npcs"][1] === npcidInt ? 0 : 1]; } } } return data; } function disableCulpritButtons(culprit_choices_element, selected_suspect) { let childrenCulpritChoicesElement = culprit_choices_element.children; for (let index = 0; index < childrenCulpritChoicesElement.length; index++) { let child = childrenCulpritChoicesElement[index]; if (selected_suspect != child) { child.querySelector(".culprit_btn").classList.add("hidden"); } else { child.querySelector(".culprit_unchecked_icon").classList.add("hidden"); child.querySelector(".culprit_checked_icon").classList.remove("hidden"); child.querySelector(".culprit_btn").classList.add("culprit_btn_checked"); } } } function getCulprit() { let culprit = null; Object.values(gameData["rooms"]).forEach(element => { if (element['npcs'].length === 1) { culprit = element['npcs'][0]; return; } }); return culprit; } async function askTypeOneQuestion() { askQuestion(npcLocationAndPartner => gameData["npcs"][currentNpc]["QA_1"].replace( "{NPC}", gameData["npcs"][npcLocationAndPartner["partner"]]["name"])); } async function askTypeZeroQuestion() { askQuestion(npcLocationAndPartner => gameData["npcs"][currentNpc]["QA_0"].replace( "{SALLE}", npcLocationAndPartner["room"])); } async function askQuestion(buildAnswer) { unsetQuestionButtonsListeners(); document.querySelector(".suspect_answer").textContent = buildAnswer( getNpcLocationAndPartner(currentNpc)); showFirstClassElement("question_answer"); document.getElementById("currentNpcPicure").src = NPC_REACTION_PATH + currentNpc; //TODO: change this code which produces strange behaviors // Sleep for 4 sec await new Promise(r => setTimeout(r, 4000)); document.getElementById("currentNpcPicure").src = NPC_REACTION_PATH + currentNpc; hideFirstClassElement("question_answer"); document.querySelector(".suspect_answer").textContent = ""; setQuestionButtonsListeners(); } async function sendAnswers() { const selections = document.getElementsByClassName("suspect_emotion_chooser"); const playerResponses = {}; for (let index = 0; index < selections.length; index++) { select = selections[index]; playerResponses[select.id] = select.value; } const data = {}; data["responses"] = JSON.stringify(playerResponses); return await makeAPIRequest("submitAnswers", data); } function renderAnswerSelectionPanel() { npcsIds.forEach(element => { const suspect = document.createElement("div"); suspect.classList.add("suspect"); const suspectEmotionChooser = document.createElement("select"); suspectEmotionChooser.classList.add("suspect_emotion_chooser") suspectEmotionChooser.setAttribute("id", element); gameData["traits"].forEach(trait => { const option = document.createElement("option"); option.value = trait; option.text = trait; suspectEmotionChooser.appendChild(option); }); suspect.appendChild(suspectEmotionChooser); const img = document.createElement('img'); img.classList.add("suspect_picture"); img.src = NPC_IMAGE_PATH + element; suspect.appendChild(img); const button = document.createElement("button"); button.classList.add("culprit_btn", "action_button"); button.innerHTML = '
Couplable
'; const culpritChoices = document.getElementById("culprits_choices"); button.addEventListener("click", () => { disableCulpritButtons(culpritChoices, suspect); sendAnswers(); }); suspect.appendChild(button); culpritChoices.appendChild(suspect); }); } function renderInterrogation() { document.getElementById("QA_0").textContent = gameData["questions"]["QA_0"]; document.getElementById("QA_1").textContent = gameData["questions"]["QA_1"]; const interrogationSuspects = document.getElementById("interrogation_suspects"); npcsIds.forEach(element => { const suspect = document.createElement("div"); suspect.classList.add("suspect"); const img = document.createElement('img'); img.classList.add("suspect_picture"); img.src = NPC_IMAGE_PATH + element; suspect.appendChild(img); const button = document.createElement("button"); button.classList.add("ask_button", "action_button"); button.textContent = "Interroger"; button.addEventListener("click", () => { // TODO remove this listener when we know the questions has already been asked; currentNpc = element; document.getElementById("currentNpcPicure").src = NPC_IMAGE_PATH + element; hideFirstClassElement("interrogation"); showFirstClassElement("interrogation_suspect"); }); suspect.appendChild(button); interrogationSuspects.appendChild(suspect); }); } function initSock() { const socket = io({ auth : { game_id: gameData["game_id"] } }); socket.on("connect", () => { console.log("Connected to the server!"); }); //TODO Send and receive userprogress when they have sent their responses socket.on("gameprogress", username => { console.log(username); }); socket.on("gamefinished", finalResults => { hideFirstClassElement("emotion_and_culprit_choices"); document.querySelector(".reveal_score").textContent = Object.values(finalResults["player"][username]) .filter(x => x == true).length + " / 5"; const playerListElement = document.querySelector(".players_list"); for (const player in finalResults["player"]) { if (player === username) { continue; } const playerNode = document.createElement("h3"); playerNode.classList.add("player_name_and_score"); const playerResultArray = Object.values(finalResults["player"][player]); playerNode.textContent = "" + player + " : " + playerResultArray.filter(x => x == true).length; playerListElement.appendChild(playerNode); } const culprit = getCulprit(); const culpritName = gameData["npcs"][culprit]["name"]; document.querySelector(".reveal_culprit_title").textContent += " " + culpritName; const culpritElement = document.getElementById("culprit"); culpritElement.src = NPC_IMAGE_PATH + culprit; culpritElement.setAttribute("alt", "Image du ou de la coupable, " + culpritName); showFirstClassElement("results_game"); setGameBackground(RESULTS_IMAGE_PATH); const suspectListElement = document.querySelector(".suspects_list"); npcsIds.filter(x => x != culprit) .forEach(npcid => { const suspect = document.createElement("div"); suspect.classList.add("summary_suspect"); const img = document.createElement("img"); img.src = NPC_IMAGE_PATH + npcid; suspect.appendChild(img); const emotionTitle = document.createElement("h2"); emotionTitle.classList.add("explain_suspect_emotion_title"); emotionTitle.textContent = "Ce suspect était " + finalResults["npcs"][npcid]["reaction"] + "."; suspect.appendChild(emotionTitle); const emotionDesc = document.createElement("p"); emotionDesc.classList.add("explain_suspect_emotion_description"); emotionDesc.textContent = "Cette émotion se caractérise par " + finalResults["npcs"][npcid]["description"]; suspect.appendChild(emotionDesc); suspectListElement.appendChild(suspect); }); }); } async function setGameData() { const response = await makeAPIRequest("getGameData"); gameData = response["gamedata"]; username = response["username"]; npcsIds = Object.keys(gameData["npcs"]).sort(() => 0.5 - Math.random()); } /** * Initialize the game, by setting the game data, initializing the socket, rendering the answer * selection panel, rendering the interrogation view, setting questions buttons listeners, * setting introduction and interrogation listeners, showing the introduction view and setting the * introduction image as the game background. */ async function initGame() { await setGameData(); initSock(); renderAnswerSelectionPanel(); renderInterrogation(); setQuestionButtonsListeners() setIntroductionAndInterrogationListeners(); showFirstClassElement("introduction"); setGameBackground(INTRO_IMAGE_PATH); } initGame();