diff --git a/assets/images/question_mark.svg b/assets/images/question_mark.svg new file mode 100644 index 0000000..a90b9f9 --- /dev/null +++ b/assets/images/question_mark.svg @@ -0,0 +1,14 @@ + + + + background + + + + + + + Layer 1 + + + diff --git a/javascript/game.js b/javascript/game.js index 4932124..e1b4dae 100644 --- a/javascript/game.js +++ b/javascript/game.js @@ -70,14 +70,19 @@ function triggerEntranceAnimation(selector, entranceClass, exitClass, image) { transitionEl.entranceClass = entranceClass; transitionEl.exitClass = exitClass; transitionEl.offsetWidth; - if (image && standardRoles.includes(currentGame.killedRole)) { - transitionEl.classList.remove("killed-role-custom"); - transitionEl.setAttribute("src", "../assets/images/roles/" + currentGame.killedRole.replace(/\s/g, '') + ".png"); - } else { - if (image) { - transitionEl.setAttribute("src", "../assets/images/custom.svg"); - transitionEl.setAttribute("class", "killed-role-custom"); + if (currentGame.reveals) { + if (image && standardRoles.includes(currentGame.killedRole)) { + transitionEl.classList.remove("killed-role-custom"); + transitionEl.setAttribute("src", "../assets/images/roles/" + currentGame.killedRole.replace(/\s/g, '') + ".png"); + } else { + if (image) { + transitionEl.setAttribute("src", "../assets/images/custom.svg"); + transitionEl.setAttribute("class", "killed-role-custom"); + } } + } else { + transitionEl.setAttribute("src", "../assets/images/question_mark.svg"); + transitionEl.setAttribute("class", "killed-role-hidden"); } transitionEl.classList.add(entranceClass); } @@ -148,7 +153,9 @@ function renderGame() { document.querySelector("#message-box").style.display = 'block'; if (currentGame.killedRole && currentGame.lastKilled !== lastKilled) { // a new player has been killed lastKilled = currentGame.lastKilled; - document.getElementById("killed-name").innerText = currentGame.killedPlayer + " was a " + currentGame.killedRole + "!"; + document.getElementById("killed-name").innerText = currentGame.reveals + ? currentGame.killedPlayer + " was a " + currentGame.killedRole + "!" + : currentGame.killedPlayer + " has died!"; playKilledAnimation(); document.getElementById("message-box").innerText = currentGame.message; } @@ -205,11 +212,12 @@ function renderGame() { function renderDeadAndAliveInformation() { // TODO: Refactor this function. - let infoContainer = document.getElementById("info-container"); - let alivePlayers = currentGame.players.filter((player) => !player.dead).sort((a, b) => + currentGame.players = currentGame.players.sort((a, b) => { return a.card.role > b.card.role ? 1 : -1; }); + let infoContainer = document.getElementById("info-container"); + let alivePlayers = currentGame.players.filter((player) => !player.dead); let deadPlayers = currentGame.players.filter((player) => player.dead); deadPlayers.sort((a, b) => { // sort players by the time they died return new Date(a.deadAt) > new Date(b.deadAt) ? -1 : 1; @@ -220,49 +228,24 @@ function renderDeadAndAliveInformation() { let killedHeader = document.createElement("h2"); killedHeader.innerText = "Killed Players"; killedContainer.appendChild(killedHeader); - deadPlayers.forEach((player) => { - let deadPlayerClass = player.card.team === "good" ? "dead-player-village" : "dead-player-evil"; - if (player.card.isTypeOfWerewolf) { - deadPlayerClass += " dead-player-wolf"; - } - const killedPlayer = document.createElement("div"); - killedPlayer.setAttribute("class", "killed-player " + deadPlayerClass); - killedPlayer.innerText = player.name + ": " + player.card.role; - killedContainer.appendChild(killedPlayer); - }); + + addDeadPlayers(deadPlayers, killedContainer); let aliveContainer = document.createElement("div"); aliveContainer.setAttribute("id", "alive-container"); let aliveHeader = document.createElement("h2"); aliveContainer.appendChild(aliveHeader); - aliveHeader.innerText = "Roles Still Alive"; + aliveHeader.innerText = currentGame.reveals + ? "Roles Still Alive" + : "Roles in the Game"; var rollCounter = {}; // RTM - alivePlayers.forEach((player) => { - let alivePlayerClass = player.card.team === "good" ? "alive-player-village" : "alive-player-evil"; - if (player.card.isTypeOfWerewolf) { - alivePlayerClass += " alive-player-wolf"; - } - //RTM - if (rollCounter.hasOwnProperty(player.card.role)) { - rollCounter[player.card.role] += 1; - } - else { - rollCounter[player.card.role] = 1; - //RTM - const alivePlayer = document.createElement("div"); - alivePlayer.setAttribute("class", "alive-player " + alivePlayerClass); - alivePlayer.innerHTML = "

" + player.card.role + "

"; - let roleCount = document.createElement("span"); // RTM - roleCount.setAttribute("class","rolecount"); - //Add hidden description span - RTM 4/18/2020 - let playerCardInfo=document.createElement("span"); - playerCardInfo.setAttribute("class","tooltiptext"); - playerCardInfo.innerText=player.card.description; - alivePlayer.prepend(roleCount); - alivePlayer.appendChild(playerCardInfo); - aliveContainer.appendChild(alivePlayer); - } - }); + + if (currentGame.reveals) { + addAlivePlayers(alivePlayers, aliveContainer, rollCounter); + } else { + addAlivePlayers(currentGame.players, aliveContainer, rollCounter); + } + if (infoContainer === null) { infoContainer = document.createElement("div"); infoContainer.setAttribute("id", "info-container"); @@ -271,7 +254,7 @@ function renderDeadAndAliveInformation() { document.getElementById("game-container").appendChild(infoContainer); // Has to be done AFTER the infoContainer is rendered in the DOM to insert the updated counts for (let x of document.getElementsByClassName("alive-player")) { - x.getElementsByClassName("rolecount")[0].innerText = rollCounter[x.getElementsByTagName("p")[0].innerText]; + x.getElementsByClassName("rolecount")[0].innerText = rollCounter[x.getElementsByTagName("p")[0].innerText]; } } else { document.getElementById("killed-container").remove(); @@ -280,11 +263,58 @@ function renderDeadAndAliveInformation() { document.getElementById("info-container").append(aliveContainer); // Has to be done AFTER the infoContainer is rendered in the DOM to insert the updated counts for (let x of document.getElementsByClassName("alive-player")) { - x.getElementsByClassName("rolecount")[0].innerText = rollCounter[x.getElementsByTagName("p")[0].innerText]; + x.getElementsByClassName("rolecount")[0].innerText = rollCounter[x.getElementsByTagName("p")[0].innerText]; } } } +function addDeadPlayers(deadPlayers, killedContainer) { + deadPlayers.forEach((player) => { + let deadPlayerClass = player.card.team === "good" ? "dead-player-village" : "dead-player-evil"; + if (player.card.isTypeOfWerewolf) { + deadPlayerClass += " dead-player-wolf"; + } + const killedPlayer = document.createElement("div"); + if (currentGame.reveals) { + killedPlayer.setAttribute("class", "killed-player " + deadPlayerClass); + } else { + killedPlayer.setAttribute("class", "killed-player dead-player-no-reveals"); + } + killedPlayer.innerText = currentGame.reveals + ? player.name + ": " + player.card.role + : player.name; + killedContainer.appendChild(killedPlayer); + }); +} + +function addAlivePlayers(alivePlayers, aliveContainer, rollCounter) { + alivePlayers.forEach((player) => { + let alivePlayerClass = player.card.team === "good" ? "alive-player-village" : "alive-player-evil"; + if (player.card.isTypeOfWerewolf) { + alivePlayerClass += " alive-player-wolf"; + } + //RTM + if (rollCounter.hasOwnProperty(player.card.role)) { + rollCounter[player.card.role] += 1; + } else { + rollCounter[player.card.role] = 1; + //RTM + const alivePlayer = document.createElement("div"); + alivePlayer.setAttribute("class", "alive-player " + alivePlayerClass); + alivePlayer.innerHTML = "

" + player.card.role + "

"; + let roleCount = document.createElement("span"); // RTM + roleCount.setAttribute("class", "rolecount"); + //Add hidden description span - RTM 4/18/2020 + let playerCardInfo=document.createElement("span"); + playerCardInfo.setAttribute("class","tooltiptext"); + playerCardInfo.innerText=player.card.description; + alivePlayer.prepend(roleCount); + alivePlayer.appendChild(playerCardInfo); + aliveContainer.appendChild(alivePlayer); + } + }); +} + function renderPlayerCard(player) { const card = player.card; const cardArt = standardRoles.includes(card.role) ? diff --git a/javascript/index.js b/javascript/index.js new file mode 100644 index 0000000..419cfa1 --- /dev/null +++ b/javascript/index.js @@ -0,0 +1,27 @@ +let gameModeSelect = false; + +window.onload = function() { + document.getElementById("create-game").addEventListener("click", toggleGameModeSelect); + document.getElementById("game-mode-back").addEventListener("click", toggleGameModeSelect) +}; + +function toggleGameModeSelect() { + gameModeSelect = !gameModeSelect; + let mainButtons = document.getElementById("main-buttons"); + let gameModes = document.getElementById("game-mode-select"); + if (gameModeSelect) { + mainButtons.classList.remove("slide-in"); + mainButtons.offsetWidth; + mainButtons.classList.add("slide-out"); + mainButtons.addEventListener("animationend", function() { mainButtons.style.display = "none" }, {capture: true, once: true}); + + gameModes.style.display = "flex"; + } else { + gameModes.style.display = "none"; + + mainButtons.style.display = "flex"; + mainButtons.classList.remove("slide-out"); + mainButtons.offsetWidth; + mainButtons.classList.add("slide-in"); + } +} diff --git a/javascript/setup.js b/javascript/setup.js index 7dd1766..79d9a5f 100644 --- a/javascript/setup.js +++ b/javascript/setup.js @@ -5,8 +5,9 @@ import {CardManager} from './modules/card-manager.js' const socket = io(); class Game { - constructor(accessCode, size, deck, time, hasDreamWolf) { + constructor(accessCode, reveals, size, deck, time, hasDreamWolf) { this.accessCode = accessCode; + this.reveals = reveals; this.size = size; this.deck = deck; this.time = time; @@ -37,6 +38,10 @@ Array.from(document.getElementsByClassName("close")).forEach(function(element) { // render all of the available cards to the user window.onload = function() { + const urlParams = new URLSearchParams(window.location.search); + document.getElementById("create-game-header").innerText = urlParams.get('reveals') === "true" + ? "Create Reveal Game" + : "Create No-Reveal Game"; readInUserCustomRoles(); renderAvailableCards(false); }; @@ -411,6 +416,9 @@ function buildDeckFromQuantities() { function createGame() { if (document.getElementById("name").value.length > 0 && atLeastOnePlayer) { + const urlParams = new URLSearchParams(window.location.search); + const revealParam = urlParams.get('reveals'); + // generate 6 digit access code let code = ""; let charPool = "abcdefghijklmnopqrstuvwxyz0123456789"; @@ -430,6 +438,7 @@ function createGame() { let gameDeck = buildDeckFromQuantities(); const game = new Game( code, + revealParam === "true", gameSize, gameDeck, Math.ceil(document.getElementById("time").value), diff --git a/server-helper.js b/server-helper.js index 3ed2a21..60270e1 100644 --- a/server-helper.js +++ b/server-helper.js @@ -32,7 +32,9 @@ module.exports = class { game.killedPlayer = player.name; game.lastKilled = player.id; game.killedRole = player.card.role; - game.message = player.name + ", a " + player.card.role + ", was killed!"; + game.message = game.reveals + ? player.name + ", a " + player.card.role + ", was killed!" + : player.name + " has died!"; console.log(game.message); if (player.card.role === "Werewolf" && game.hasDreamWolf) { this.activateDreamWolvesIfNeeded(game); diff --git a/stylesheets/styles.css b/stylesheets/styles.css index 6ce63e5..77563d1 100644 --- a/stylesheets/styles.css +++ b/stylesheets/styles.css @@ -238,7 +238,7 @@ width: 35em; } - #main-buttons a { + #main-buttons a, #main-buttons button { max-width: 15em; } @@ -324,6 +324,7 @@ html, body { margin: 0 auto; + height: 100%; color: #bfb8b8; font-family: 'sitewide-sans-serif', sans-serif; background-color: #23282b !important; @@ -342,7 +343,7 @@ html, body { @keyframes slide-fade { from { opacity: 0; - transform: translateX(-80px) + transform: translateX(80px) } to { @@ -351,6 +352,18 @@ html, body { } } +@keyframes slide-fade-remove { + from { + opacity: 1; + transform: translateX(0px) + + } + to { + opacity: 0; + transform: translateX(-80px); + } +} + #app-content { text-align: center; margin: 0 auto; @@ -360,6 +373,7 @@ html, body { #landing-container { width: 100%; height: 100%; + position: relative; text-align: center; background: linear-gradient(0deg, rgba(35,40,43,0.7959558823529411) 18%, rgba(131,131,131,0.6222864145658263) 100%); } @@ -766,29 +780,9 @@ button { flex-direction: column; align-items: center; justify-content: center; -} - -#main-buttons a:nth-child(1) { - animation: fadein 0.3s ease-in; - animation-fill-mode: backwards; -} - -#main-buttons a:nth-child(2) { - animation: fadein 0.3s ease-in; - animation-fill-mode: backwards; - animation-delay: 0.1s; -} - -#main-buttons a:nth-child(3) { - animation: fadein 0.3s ease-in; - animation-fill-mode: backwards; - animation-delay: 0.2s; -} - -#main-buttons a:nth-child(4) { - animation: fadein 0.3s ease-in; - animation-fill-mode: backwards; - animation-delay: 0.3s; + max-width: 18em; + margin: 0 auto; + overflow: hidden; } #main-buttons button { @@ -801,7 +795,60 @@ button { } #main-buttons a { - width: 75%; + width: 100%; +} + +#game-mode-select { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + position: absolute; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); +} + +#landing-container .slide-in { + animation: slide-fade 0.25s; + animation-delay: 0.125s; + animation-fill-mode: both; +} + +#landing-container .slide-out { + animation: slide-fade-remove 0.25s; +} + + +#game-mode-select .game-mode { + width: 7em; + background-color: transparent; + color: whitesmoke; + border: 1px solid whitesmoke; + font-size: 30px; + font-weight: bold; + padding: 5px; + margin-bottom: 0.5em; + border-radius: 5px; +} + +#game-mode-select .game-mode:hover { + cursor: pointer; + background-color: #494f52; +} + +#game-mode-select span { + font-size: 50px; + font-weight: bold; + cursor: pointer; + margin-bottom: 0.2em; + text-align: left; + width: 100%; +} + +#game-mode-select span:hover { + color: #333243; } #card-select-header { @@ -813,11 +860,19 @@ button { flex-direction: column; } -#card-select-header a { +#card-select-header a, #landing-container #game-mode-select a:nth-child(2) { text-decoration: underline; color: #b8c4ff; } +#landing-container #game-mode-select a:nth-child(2) { + text-decoration: underline; + color: #b8c4ff; + text-align: left; + width: 100%; + margin-bottom: 1em; +} + #card-select-header span > div { display: flex; align-items: center; @@ -1462,6 +1517,10 @@ label { font-size: 40px; } +.faq-question { + max-width: 60em; +} + #learn-container button, #faq-container button { margin-top: 1em; } @@ -1562,6 +1621,10 @@ label { color: #bd2a2a; } +.dead-player-no-reveals { + color: whitesmoke !important; +} + .alive-player-wolf, .dead-player-wolf { border: 2px solid #bd2a2a; } @@ -1596,6 +1659,10 @@ label { padding: 95px; } +.killed-role-hidden { + padding-top: 3em; +} + @keyframes slide-fade-in-top { 0% { opacity: 0; diff --git a/views/create_game.html b/views/create_game.html index b06c6e0..d43bd71 100644 --- a/views/create_game.html +++ b/views/create_game.html @@ -62,7 +62,7 @@
-

Create A Game

+

Create A Game

+
+

What does it mean when a game is "Reveal" or "No-Reveal"?

+

If you are playing a game with "reveals," players' roles will be revealed when they die. Otherwise, they remain a mystery.

+
diff --git a/views/index.html b/views/index.html index fcfc0b5..7ce2218 100644 --- a/views/index.html +++ b/views/index.html @@ -13,9 +13,7 @@ Where Are the Wolves?
- - - + @@ -26,6 +24,16 @@
+ +