From 9ada0a4d6f0efe24428145faed8947753ae9abe3 Mon Sep 17 00:00:00 2001 From: Alec Maier Date: Sat, 11 Apr 2020 14:29:02 -0400 Subject: [PATCH 1/3] Treat dream wolves as minions until they convert --- server.js | 46 +++++++++++++++++++++++++++++++--------------- static/cards.js | 2 +- static/game.js | 12 ------------ static/setup.js | 9 ++++++--- 4 files changed, 38 insertions(+), 31 deletions(-) diff --git a/server.js b/server.js index 7b118a5..0064e63 100644 --- a/server.js +++ b/server.js @@ -58,6 +58,16 @@ server.listen(process.env.PORT || 5000, function() { console.log('Starting server on port 5000'); }); +// If there are multiple dream wolves, convert them all. +function activateDreamWolvesIfNeeded(game) { + game.players.forEach((player) => { + if (!player.dead && player.card.role === "Dream Wolf") { + player.card.isTypeOfWerewolf = true; + console.log("player " + player.name + " was converted to a wolf!"); + } + }) +} + function teamWon(game) { let wolvesAlive = 0; let villagersAlive = 0; @@ -164,21 +174,27 @@ io.on('connection', function(socket) { let game = activeGames[Object.keys(activeGames).find((key) => key === code)]; if (game) { let player = game.players.find((player) => player.id === id); - game.players.find((player) => player.id === id).dead = true; - game.killedPlayer = player.name; - game.lastKilled = player.id; - game.killedRole = player.card.role; - game.message = player.name + ", a " + player.card.role + ", was killed!"; - console.log(game.message); - const winCheck = teamWon(game); - if (winCheck === "wolf") { - console.log("wolves won the game!"); - game.winningTeam = "wolf"; - game.status = "ended"; - } if (winCheck === "village") { - console.log("village won the game!"); - game.winningTeam = "village"; - game.status = "ended"; + if (player) { + player.dead = true; + game.killedPlayer = player.name; + game.lastKilled = player.id; + game.killedRole = player.card.role; + game.message = player.name + ", a " + player.card.role + ", was killed!"; + console.log(game.message); + if (player.card.role === "Werewolf" && game.hasDreamWolf) { + activateDreamWolvesIfNeeded(game); + } + const winCheck = teamWon(game); + if (winCheck === "wolf") { + console.log("wolves won the game!"); + game.winningTeam = "wolf"; + game.status = "ended"; + } + if (winCheck === "village") { + console.log("village won the game!"); + game.winningTeam = "village"; + game.status = "ended"; + } } } }); diff --git a/static/cards.js b/static/cards.js index 8a3fa4d..0d9b599 100644 --- a/static/cards.js +++ b/static/cards.js @@ -15,7 +15,7 @@ export const cards = [ role: "Dream Wolf", team: "evil", description: "If a Werewolf dies, you become a Werewolf. You do not wake up with the Werewolves until this happens.", - isTypeOfWerewolf: true + isTypeOfWerewolf: false }, { role: "Minion", diff --git a/static/game.js b/static/game.js index 62d6ab1..970d7e3 100644 --- a/static/game.js +++ b/static/game.js @@ -18,18 +18,6 @@ socket.on('state', function(game) { } }); -window.onblur = function() { // pause animations if the window is not in focus - this.document.querySelector("#overlay").style.animationPlayState = 'paused'; - this.document.querySelector("#killed-role").style.animationPlayState = 'paused'; - this.document.querySelector("#killed-name").style.animationPlayState = 'paused'; -}; - -window.onfocus = function() { // play animations when window is focused - this.document.querySelector("#overlay").style.animationPlayState = 'running'; - this.document.querySelector("#killed-role").style.animationPlayState = 'running'; - this.document.querySelector("#killed-name").style.animationPlayState = 'running'; -}; - function buildGameBasedOnState(game) { switch(game.status) { case "lobby": diff --git a/static/setup.js b/static/setup.js index d7c2ba6..54f4ac6 100644 --- a/static/setup.js +++ b/static/setup.js @@ -17,13 +17,14 @@ class Card { } class Game { - constructor(accessCode, size, deck, time) { + constructor(accessCode, size, deck, time, hasDreamWolf) { this.accessCode = accessCode; this.size = size; this.deck = deck; this.time = time; this.players = []; this.status = "lobby"; + this.hasDreamWolf = hasDreamWolf; this.endTime = null; } } @@ -230,11 +231,13 @@ function createGame() { // send a new game to the server, and then join it const playerInfo = {name: document.getElementById("name").value, code: code, id: id}; + let gameDeck = buildDeckFromQuantities(); const game = new Game( code, gameSize, - buildDeckFromQuantities(), - Math.ceil(document.getElementById("time").value) + gameDeck, + Math.ceil(document.getElementById("time").value), + gameDeck.find((card) => card.role === "Dream Wolf") !== undefined ); socket.emit('newGame', game, function() { socket.emit('joinGame', playerInfo); From 1df748bf9e83086ecb34d35b4984b0d28c6fdb4a Mon Sep 17 00:00:00 2001 From: Alec Maier Date: Sat, 11 Apr 2020 18:53:05 -0400 Subject: [PATCH 2/3] display roles that are alive/dead --- server.js | 3 +- static/game.js | 98 ++++++++++++++++++++++++++++++++++++----------- static/styles.css | 32 +++++++++++++++- static/util.js | 10 ++++- views/game.html | 4 +- 5 files changed, 119 insertions(+), 28 deletions(-) diff --git a/server.js b/server.js index 7b118a5..563cb62 100644 --- a/server.js +++ b/server.js @@ -164,7 +164,8 @@ io.on('connection', function(socket) { let game = activeGames[Object.keys(activeGames).find((key) => key === code)]; if (game) { let player = game.players.find((player) => player.id === id); - game.players.find((player) => player.id === id).dead = true; + player.dead = true; + player.deadAt = new Date().toJSON(); game.killedPlayer = player.name; game.lastKilled = player.id; game.killedRole = player.card.role; diff --git a/static/game.js b/static/game.js index 62d6ab1..1cf21ef 100644 --- a/static/game.js +++ b/static/game.js @@ -18,18 +18,6 @@ socket.on('state', function(game) { } }); -window.onblur = function() { // pause animations if the window is not in focus - this.document.querySelector("#overlay").style.animationPlayState = 'paused'; - this.document.querySelector("#killed-role").style.animationPlayState = 'paused'; - this.document.querySelector("#killed-name").style.animationPlayState = 'paused'; -}; - -window.onfocus = function() { // play animations when window is focused - this.document.querySelector("#overlay").style.animationPlayState = 'running'; - this.document.querySelector("#killed-role").style.animationPlayState = 'running'; - this.document.querySelector("#killed-name").style.animationPlayState = 'running'; -}; - function buildGameBasedOnState(game) { switch(game.status) { case "lobby": @@ -102,6 +90,7 @@ function playKilledAnimation() { function launchGame() { randomlyDealCardsToPlayers(); + utility.shuffle(currentGame.players); // put the players in a random order socket.emit('startGame', { players: currentGame.players , code: currentGame.accessCode}); } @@ -126,7 +115,7 @@ function getLiveCount() { } function renderEndSplash() { - document.getElementById("game-container").classList.add("hidden"); + document.getElementById("game-container").remove(); document.querySelector("#message-box").style.display = 'none'; currentGame.winningTeam === "village" ? document.getElementById("end-container").innerHTML ="

Village

wins!
" @@ -149,6 +138,12 @@ function renderEndSplash() { } function renderGame() { + // remove lobby components if present + if (document.getElementById("lobby-container") !== null && document.getElementById("launch") !== null) { + document.getElementById("lobby-container").remove(); + document.getElementById("launch").remove(); + } + document.querySelector("#message-box").style.display = 'block'; if (currentGame.killedRole && currentGame.lastKilled !== lastKilled) { // a new player has been killed lastKilled = currentGame.lastKilled; @@ -159,8 +154,6 @@ function renderGame() { const player = currentGame.players.find((player) => player.id === sessionStorage.getItem("id")); // render the header - document.getElementById("lobby-container").setAttribute("class", "hidden"); - document.getElementById("launch").setAttribute("class", "hidden"); document.getElementById("game-container").setAttribute("class", "game-container"); const gameHeader = document.createElement("div"); gameHeader.setAttribute("id", "game-header"); @@ -169,9 +162,9 @@ function renderGame() { "
" + "
"; if (document.getElementById("game-header")) { - document.getElementById("game-container").removeChild(document.getElementById("game-header")); + document.getElementById("card-container").removeChild(document.getElementById("game-header")); } - document.getElementById("game-container").prepend(gameHeader); + document.getElementById("card-container").prepend(gameHeader); // render the card if it hasn't been yet if (!cardRendered) { @@ -200,10 +193,64 @@ function renderGame() { killedBtn.innerText = "I'm dead"; } if (document.getElementById("dead-btn")) { - document.getElementById("game-container").removeChild(document.getElementById("dead-btn")); + document.getElementById("card-container").removeChild(document.getElementById("dead-btn")); } - document.getElementById("game-container").appendChild(killedBtn); + document.getElementById("card-container").appendChild(killedBtn); document.getElementById("dead-btn").addEventListener("click", killPlayer); + + // add the list of dead/alive players + renderDeadAndAliveInformation(); +} + +function renderDeadAndAliveInformation() { + let infoContainer = document.getElementById("info-container"); + let alivePlayers = currentGame.players.filter((player) => !player.dead).sort((a, b) => + { + return a.card.role > b.card.role ? 1 : -1; + }); + let deadPlayers = currentGame.players.filter((player) => player.dead); + console.log(deadPlayers); + deadPlayers.sort((a, b) => { // sort players by the time they died + return new Date(a.deadAt) > new Date(b.deadAt) ? -1 : 1; + }); + + let killedContainer = document.createElement("div"); + killedContainer.setAttribute("id", "killed-container"); + let killedHeader = document.createElement("h2"); + killedHeader.innerText = "Killed Players"; + killedContainer.appendChild(killedHeader); + deadPlayers.forEach((player) => { + const killedPlayer = document.createElement("div"); + killedPlayer.setAttribute("class", "killed-player"); + killedPlayer.innerText = player.name + ": " + player.card.role; + killedContainer.appendChild(killedPlayer); + }); + + let aliveContainer = document.createElement("div"); + aliveContainer.setAttribute("id", "alive-container"); + let aliveHeader = document.createElement("h2"); + aliveContainer.appendChild(aliveHeader); + aliveHeader.innerText = "Roles Still Alive"; + alivePlayers.forEach((player) => { + const alivePlayer = document.createElement("div"); + alivePlayer.setAttribute("class", "alive-player"); + alivePlayer.innerText = player.card.role; + aliveContainer.appendChild(alivePlayer); + }); + if (infoContainer === null) { + infoContainer = document.createElement("div"); + infoContainer.setAttribute("id", "info-container"); + infoContainer.appendChild(killedContainer); + infoContainer.appendChild(aliveContainer); + document.getElementById("game-container").appendChild(infoContainer); + } else { + document.getElementById("killed-container").remove(); + document.getElementById("alive-container").remove(); + document.getElementById("info-container").append(killedContainer); + document.getElementById("info-container").append(aliveContainer); + } + + } function renderPlayerCard(player) { @@ -227,7 +274,7 @@ function renderPlayerCard(player) { "" + "
" + ""; - document.getElementById("game-container").appendChild(playerCard); + document.getElementById("card-container").appendChild(playerCard); document.getElementById("game-card").addEventListener("click", flipCard); } @@ -274,10 +321,15 @@ function renderClock() { if (delta <= 0) { endGameDueToTimeExpired(); } else { - let minutes = Math.floor((delta % (1000 * 60 * 60)) / (1000 * 60)); - let seconds = Math.floor((delta % (1000 * 60)) / 1000); + let seconds = Math.floor( (delta / 1000) % 60); + let minutes = Math.floor( (delta / 1000 / 60) % 60); + let hours = Math.floor( (delta / (1000*60*60)) % 24); seconds = seconds < 10 ? "0" + seconds : seconds; - document.getElementById("clock").innerText = minutes + ":" + seconds; + minutes = minutes < 10 ? "0" + minutes : minutes; + document.getElementById("clock").innerText = hours > 0 + ? hours + ":" + minutes + ":" + seconds + : minutes + ":" + seconds; + } }, 1000); } diff --git a/static/styles.css b/static/styles.css index f4c98a6..f455eb0 100644 --- a/static/styles.css +++ b/static/styles.css @@ -9,10 +9,19 @@ margin: 0.3em 0; } + + #game-container #card-container { + min-width: 20em; + } + h3 { font-size: 20px; } + #game-container { + flex-direction: column; + } + #app-content { width: 92%; } @@ -114,6 +123,11 @@ margin: 0.5em 0; } + + #game-container #card-container { + min-width: 25em; + } + .app-header-secondary { font-size: 70px; margin: 0.3em 0; @@ -904,7 +918,7 @@ label { border-radius: 3px; height: 23em; margin: 0 auto 2em auto; - width: 72%; + width: 100%; box-shadow: 0 13px 17px rgba(0,0,0,0.6); perspective: 1000px; transform-style: preserve-3d; @@ -1027,7 +1041,7 @@ label { #clock { font-size: 1.5em; width: 3.8em; - margin-bottom: 0.5em; + margin: 0 0.5em 0.5em 0; } #flip-instruction { @@ -1042,6 +1056,20 @@ label { justify-content: center; } +#game-container { + display: flex; + justify-content: center; + align-items: center; +} + +#game-container .killed-player, #game-container .alive-player { + background-color: #494f52; + border-radius: 5px; + padding: 5px; + filter: drop-shadow(3px 10px 10px rgba(0,0,0,0.6)); + margin: 0.3em; +} + #play-pause { width: 2.5em; height: 2.5em; diff --git a/static/util.js b/static/util.js index 525b9cd..402e832 100644 --- a/static/util.js +++ b/static/util.js @@ -11,5 +11,13 @@ export const utility = getRandomInt(max) { return Math.floor(Math.random() * Math.floor(max)); - } + }, + + shuffle(array) { + for (let i = array.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [array[i], array[j]] = [array[j], array[i]]; + } + return array; +} }; diff --git a/views/game.html b/views/game.html index 32f13fa..34f65fc 100644 --- a/views/game.html +++ b/views/game.html @@ -16,7 +16,9 @@
-
+
+
+
From 9631507271c3385e8941fc81f436e80811d789c1 Mon Sep 17 00:00:00 2001 From: Alec Maier Date: Sun, 12 Apr 2020 14:00:24 -0400 Subject: [PATCH 3/3] Clear clock on game end --- server.js | 2 +- static/game.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/server.js b/server.js index 563cb62..72f1ca1 100644 --- a/server.js +++ b/server.js @@ -80,7 +80,7 @@ function teamWon(game) { if (wolvesAlive === 0) { return "village" } - if ((wolvesAlive === villagersAlive) && (totalAlive !== 2)) { + if ((wolvesAlive >= villagersAlive) && (totalAlive !== 2)) { return "wolf"; } if (totalAlive === 2) { diff --git a/static/game.js b/static/game.js index 1cf21ef..ceec169 100644 --- a/static/game.js +++ b/static/game.js @@ -115,6 +115,7 @@ function getLiveCount() { } function renderEndSplash() { + clearInterval(clock); document.getElementById("game-container").remove(); document.querySelector("#message-box").style.display = 'none'; currentGame.winningTeam === "village" @@ -209,7 +210,6 @@ function renderDeadAndAliveInformation() { return a.card.role > b.card.role ? 1 : -1; }); let deadPlayers = currentGame.players.filter((player) => player.dead); - console.log(deadPlayers); deadPlayers.sort((a, b) => { // sort players by the time they died return new Date(a.deadAt) > new Date(b.deadAt) ? -1 : 1; });