<!-- Copyright (C) 2021 Thomas Van Acker This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. This project is hosted on https://git.bitscuit.be/bitscuit/ReverseQuiz --> <html> <head> <title>Reverse Quiz</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link href="https://fonts.googleapis.com/css?family=Raleway:400,300,600" rel="stylesheet" type="text/css"> <link href="css/normalize.css" rel="stylesheet"> <link href="css/skeleton.css" rel="stylesheet"> <link href="css/extra.css" rel="stylesheet"> <link href="css/fontawesome/css/all.css" rel="stylesheet"> </head> <body style="padding-top: 10px;"> <div id="main" class="container" style="text-align:center;"> <h1>Reverse Quiz</h1> <p>Please enter a username to get started with the game.</p> <input id="input_username" type="text" placeholder="Your username" /> <button id="button_username" class="button button-primary"><i class="fas fa-check"></i></button> </div> <div class="footer"> <p>Copyright © 2021 Thomas Van Acker<br/>Project hosted on <a href="https://git.bitscuit.be/bitscuit/ReverseQuiz">Gitscuit</a></p> </div> <!-- Socket.io stuff --> <script src="/socket.io/socket.io.js"></script> <script> // Start socket.io var socket = io(); // Init vars var username; var RANK_ICONS = ["🥇","🥈","🥉"]; var config = { categories: [], answerPreview: true, timer: 60, }; // Init listeners // Username submit document.getElementById("button_username").onclick = function(){ // Submit username username = document.getElementById("input_username").value; socket.emit("JOIN", username); // Show loading page document.getElementById("main").innerHTML = "<p>Loading, please wait.</p>"; } // Lobby change socket.on("LOBBY", function(users){ var page = "<h1>Waiting for other players...</h1><button id='button_lobby_start' class='button button-primary'><i class='fas fa-play'></i> Start game!</button><p>Currently in lobby:</p><ol>"; for(var i=0; i<users.length; i++){ page += "<li>"+users[i]+"</li>"; } page += "</ol>"; // Config area page += "<div id='config'></div>"; document.getElementById("main").innerHTML = page; // Lobby start button listener (can only be set when element is added to page document.getElementById("button_lobby_start").onclick = function(){ // Send START to server socket.emit("START"); // Show loading page document.getElementById("main").innerHTML = "<p>Loading, please wait.</p>"; } // Disable button if not enough players if(users.length < 2){ document.getElementById("button_lobby_start").style.display = "none"; } reconstructConfig(); }); // CONFIG function updateConfig(){ // Create new config from inputs c = { categories: [], timer: 60, answerPreview: true, } // Get categories for(var i=0; i<config.categories.length; i++){ var cat = { id: config.categories[i].id, name: config.categories[i].name, enabled: config.categories[i].enabled, }; cat.enabled = document.getElementById("config-categories-"+cat.id).checked; c.categories.push(cat); } // Get timer c.timer = document.getElementById("config-timer").value; // Get preview c.answerPreview = document.getElementById("config-preview").checked; // Send to server socket.emit("CONFIG", {config: c}); } function reconstructConfig(){ var page = ""; page += "<hr>"; page += "<h3>Game Config</h3>"; page += "<div>"; page += "<h5>Timer</h5>"; page += "<p>Number of seconds each player has to complete each step of the game.</p>"; page += "<input type='number' name='config-timer' id='config-timer' value='"+config.timer+"' onchange='updateConfig()' />"; page += "</div>"; page += "<hr>"; page += "<div>"; page += "<h5>Answer Preview</h5>"; page += "<p>Whether to display one of the possible answers to a question while writing false answers. This may help with formatting of the false answers.</p>"; page += "<span>"; page += "<input type='checkbox' name='config-preview' id='config-preview' "+(config.answerPreview ? "checked" : "")+" onchange='updateConfig()' />"; page += "<label for='config-preview'>Answer Preview</label>"; page += "</span>"; page += "</div>"; page += "<hr>"; page += "<div>"; page += "<h5>Categories</h5>"; for(var i=0; i<config.categories.length; i++){ page += "<span>"; page += "<input type='checkbox' name='config-categories' id='config-categories-"+config.categories[i].id+"' value='"+config.categories[i].id+"' "+(config.categories[i].enabled?"checked":"")+" onchange='updateConfig()' />"; page += "<label for='config-categories-"+config.categories[i].id+"'>"+config.categories[i].name+"</label>"; page += "</span>"; page += "<br>"; } page += "</div>"; document.getElementById("config").innerHTML = page; } socket.on("CONFIG", function(data){ config = data.config; reconstructConfig(); }); // LOBBY_CLOSED socket.on("LOBBY_CLOSED", function(){ // When game busy var page = ""; page += "<h1>Reverse Quiz</h1><p>The lobby is currently closed. Please come back in a few moments.</p>"; document.getElementById("main").innerHTML = page; }); // LOADING socket.on("LOADING", function(){ // Show loading screen document.getElementById("main").innerHTML = "<p>Loading, please wait.</p>"; }); // START socket.on("START", function(data){ // Parse game data and show to user var page = ""; page += "<h1>Get ready!</h1>"; page += "<p>The game is about to begin.</p>"; page += "<p>Come up with false answers to a trivia quiz question to fool the other players. Afterwards, find the correct answer to the question, but don't get fooled by your friends wrong answers.</p>"; page += "<p>If you answer a question correctly, you gain 3 points. If someone else thought your false answer was correct, you gain 1 point. Get the most points to win the game!</p>"; page += "<button id='button_ok' class='button button-primary' onclick='button_ok()'><i class='fas fa-arrow-right'></i> Let's begin!</button>"; // Show page document.getElementById("main").innerHTML = page; }); // WRITE socket.on("WRITE", function(data){ // Received new question var page = ""; page += "<p>Question "+data.questionNr+" of "+data.questionsTotal+"</p>"; page += "<h4>"+data.question+"</h4>"; page += "<p>Enter a <b>false</b> answer.</p>"; page += "<input type='text' placeholder='Wrong answer' id='input_write' /><br/>"; page += "<p id='text_write_error' style='display: none; color: #BB2266; '></p>"; page += "<button id='button_ok' class='button button-primary' onclick='button_write()'><i class='fas fa-check'></i> Submit</button>"; // Show page document.getElementById("main").innerHTML = page; }); // WRITE button pressed function button_write(){ // Disable button and input document.getElementById("button_ok").disabled = true; document.getElementById("button_ok").classList.remove("button-primary"); document.getElementById("input_write").disabled = true; // Hide error text document.getElementById("text_write_error").style.display = "none"; // Send OK to server socket.emit("WRITE", {write:document.getElementById("input_write").value}); } socket.on("WRITE_REPLY", function(data){ // When something wrong with write // Enable button and input document.getElementById("button_ok").disabled = false; document.getElementById("button_ok").classList.add("button-primary"); document.getElementById("input_write").disabled = false; // Show message document.getElementById("text_write_error").innerHTML = "<i class='fas fa-exclamation-triangle'></i> "+data.error; document.getElementById("text_write_error").style.display = "block"; }); // PICK socket.on("PICK", function(data){ // Received all possible answers var page = ""; page += "<p>Question "+data.questionNr+" of "+data.questionsTotal+"</p>"; page += "<h4>"+data.question+"</h4>"; page += "<div id='pick_buttons'>"; page += "<p>Select the <b>correct</b> answer.</p>"; for(y=0; y<data.answers.length/4+1; y++){ page += "<div class='row'>"; for(x=0; x<Math.min(4, data.answers.length-y*4); x++){ page += "<div class='three columns'>"; page += "<button class='button button-primary u-full-width' onclick='button_pick("+(y*4+x)+")'>"; page += data.answers[y*4+x]; page += "</button>"; page += "</div>"; } page += "</div>"; } page += "</div>"; // Show page document.getElementById("main").innerHTML = page; }); // PICK button function button_pick(id){ // Disable all buttons and show waiting text document.getElementById("pick_buttons").innerHTML = "<button class='button' id='button_ok' disabled>Loading...</button>"; // Send to server socket.emit("PICK", id); } // ANSWER socket.on("ANSWER", function(data){ // Received answer var page = ""; page += "<p>Question "+data.questionNr+" of "+data.questionsTotal+"</p>"; page += "<h4>"+data.question+"</h4>"; page += "<p>Correct answer: <b>"+data.answers[data.correctAnswer]+"</b></p>"; // Table with results page += "<table class='u-full-width'>"; page += "<thead>"; page += "<th></th>"; page += "<th></th>"; page += "<th>Answered</th>"; page += "<th>Wrote</th>"; page += "<th>Change</th>"; page += "<th>Points</th>"; page += "</thead>"; page += "<tbody>"; for(i=0; i<data.usernames.length; i++){ page += "<tr>"; page += "<td>"+data.usernames[i]+"</td>"; page += "<td>"+(data.userPick[i] == data.correctAnswer ? "<i class='fas fa-check' style='color: #22BB66;'></i>" : "<i class='fas fa-times' style='color: #BB2266;'></i>")+"</td>"; page += "<td>"+data.answers[data.userPick[i]]+"</td>"; page += "<td>"+data.userWrite[i]+"</td>"; page += "<td>+"+data.pointsDiff[i]+"</td>"; page += "<td>"+data.userPoints[i]+"</td>"; page += "</tr>"; } page += "</tbody>"; page += "</table>"; // Button to continue page += "<button class='button button-primary' id='button_ok' onclick='button_ok()'><i class='fas fa-arrow-right'></i> Next</button>"; // Show page document.getElementById("main").innerHTML = page; }); // STOP socket.on("STOP", function(data){ // Game ends // Show page var page = ""; page += "<h1>We're done!</h1>"; page += "<p>All questions were answered. Let's see who's the winner!</p>"; // Scoreboard page += "<table class='u-full-width'>"; page += "<thead>"; page += "<th>#</th>"; page += "<th>Username</th>"; page += "<th>Points</th>"; page += "</thead>"; page += "<tbody>"; for(i=0; i<data.ranks.length; i++){ page += "<tr>"; page += "<td>"+(data.ranks[i].rank <= 3 ? RANK_ICONS[data.ranks[i].rank-1] : data.ranks[i].rank)+"</td>"; page += "<td>"+data.ranks[i].name+"</td>"; page += "<td>"+data.ranks[i].score+"</td>"; page += "</tr>"; } page += "</tbody>"; page += "</table>"; page += "<button class='button button-primary' onclick='button_restart()'><i class='fas fa-redo'></i> Restart game</button>"; document.getElementById("main").innerHTML = page; }); // Restart button clicked function button_restart(){ // Join the lobby socket.emit("JOIN", username); } // OK button pressed function button_ok(){ // Disable button document.getElementById("button_ok").disabled = true; document.getElementById("button_ok").classList.remove("button-primary"); // Send OK to server socket.emit("OK"); } // OK_REPLY socket.on("OK_REPLY", (data) => { // Check if already sent OK if(document.getElementById("button_ok").disabled){ // Parse data and set ok button text users = data.users; var text = "<i class='fas fa-spinner fa-pulse'></i> "; if(users.length == 1){ text += "Waiting for "+users[0]; }else if(users.length == 2){ text += "Waiting for "+users[0]+" and "+users[1]; }else{ text += "Waiting for "+users.length+" players"; } document.getElementById("button_ok").innerHTML = text; } }); // DISCONNECT socket.on("DISCONNECT", function(name){ // When player disconnected alert(name+" left the game"); }); </script> </body> </html>