mirror of
https://github.com/AlecM33/Werewolf.git
synced 2025-12-26 15:57:50 +01:00
Detection of end-game scenarios, end games with splash screen listing winning team and who wolves were.
This commit is contained in:
@@ -14,7 +14,10 @@
|
||||
<form>
|
||||
<label>
|
||||
Name
|
||||
<span>
|
||||
<input id="name" type="text"/>
|
||||
<p id="name-error"></p>
|
||||
</span>
|
||||
</label>
|
||||
<label>
|
||||
Time (Minutes, Optional)
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
<div id="message-box"></div>
|
||||
<div id="lobby-container"></div>
|
||||
<div id="game-container"></div>
|
||||
<div id="end-container"></div>
|
||||
<div id="launch"></div>
|
||||
</div>
|
||||
<script type="module" src="/static/game.js"></script>
|
||||
|
||||
@@ -14,11 +14,17 @@
|
||||
<form>
|
||||
<label>
|
||||
Name
|
||||
<input id="name" type="text"/>
|
||||
<span>
|
||||
<input id="name" type="text"/>
|
||||
<p id="name-error"></p>
|
||||
</span>
|
||||
</label>
|
||||
<label>
|
||||
Access Code
|
||||
<input id="code" type="text"/>
|
||||
<span>
|
||||
<input id="code" type="text"/>
|
||||
<p id="join-error"></p>
|
||||
</span>
|
||||
</label>
|
||||
</form>
|
||||
<a href="/">
|
||||
|
||||
70
server.js
70
server.js
@@ -32,24 +32,69 @@ server.listen(process.env.PORT || 5000, function() {
|
||||
console.log('Starting server on port 5000');
|
||||
});
|
||||
|
||||
function didVillageWin(game) {
|
||||
let liveCount = 0;
|
||||
for (const player of game.players) {
|
||||
if (player.card.role === "Werewolf" && !player.dead) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function teamWon(game) {
|
||||
let wolvesAlive = 0;
|
||||
let villagersAlive = 0;
|
||||
let hunterAlive = false;
|
||||
for (const player of game.players) {
|
||||
if (player.card.team === "village" && !player.dead) {
|
||||
villagersAlive++;
|
||||
}
|
||||
if (player.card.team === "wolf" && !player.dead) {
|
||||
wolvesAlive++;
|
||||
}
|
||||
if (player.card.role === "Hunter" && !player.dead) {
|
||||
hunterAlive = true;
|
||||
}
|
||||
}
|
||||
console.log("wolves: " + wolvesAlive + " villagers: " + villagersAlive);
|
||||
if ((wolvesAlive === villagersAlive) && (wolvesAlive + villagersAlive !== 2)) {
|
||||
return "wolf";
|
||||
}
|
||||
if (wolvesAlive === 0) {
|
||||
return "village"
|
||||
}
|
||||
if (wolvesAlive + villagersAlive === 2) {
|
||||
return hunterAlive ? "village" : "wolf"
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add the WebSocket handlers
|
||||
io.on('connection', function(socket) {
|
||||
socket.on('newGame', function(game, onSucess) {
|
||||
socket.on('newGame', function(game, onSuccess) {
|
||||
activeGames[game.accessCode] = game;
|
||||
onSucess();
|
||||
onSuccess();
|
||||
});
|
||||
socket.on('joinGame', function(playerInfo) {
|
||||
activeGames[Object.keys(activeGames).find((key) => key === playerInfo.code)].players.push({name: playerInfo.name, id: playerInfo.id});
|
||||
const game = activeGames[Object.keys(activeGames).find((key) => key === playerInfo.code)];
|
||||
if (game && game.players.length < game.size) {
|
||||
activeGames[Object.keys(activeGames).find((key) => key === playerInfo.code)].players.push({name: playerInfo.name, id: playerInfo.id});
|
||||
socket.emit('success');
|
||||
} else {
|
||||
if (game && game.players.length === game.size) {
|
||||
socket.emit("joinError", "This game is full - sorry!")
|
||||
} else {
|
||||
socket.emit("joinError", "No game found");
|
||||
}
|
||||
}
|
||||
});
|
||||
socket.on('requestState', function(data) {
|
||||
if(Object.keys(socket.rooms).includes(data.code) === false) {
|
||||
console.log("new socket");
|
||||
socket.join(data.code, function() {
|
||||
console.log("request for state");
|
||||
io.to(data.code).emit('state', activeGames[Object.keys(activeGames).find((key) => key === data.code)]);
|
||||
});
|
||||
} else {
|
||||
console.log("old socket");
|
||||
io.to(data.code).emit('state', activeGames[Object.keys(activeGames).find((key) => key === data.code)]);
|
||||
}
|
||||
});
|
||||
@@ -84,7 +129,18 @@ io.on('connection', function(socket) {
|
||||
let player = game.players.find((player) => player.id === id);
|
||||
game.players.find((player) => player.id === id).dead = true;
|
||||
game.message = player.name + ", a " + player.card.role + ", has been killed!";
|
||||
io.to(code).emit('state', game);
|
||||
const winCheck = teamWon(game);
|
||||
if (winCheck === "wolf") {
|
||||
game.winningTeam = "wolf";
|
||||
game.state = "ended";
|
||||
io.to(code).emit('state', game);
|
||||
} else if (winCheck === "village") {
|
||||
game.winningTeam = "village";
|
||||
game.state = "ended";
|
||||
io.to(code).emit('state', game);
|
||||
} else {
|
||||
io.to(code).emit('state', game);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ socket.on('state', function(game) {
|
||||
if (game.message) {
|
||||
document.getElementById("message-box").innerText = game.message;
|
||||
}
|
||||
console.log(currentGame);
|
||||
buildGameBasedOnState();
|
||||
});
|
||||
|
||||
@@ -24,6 +23,9 @@ function buildGameBasedOnState() {
|
||||
case "started":
|
||||
renderGame();
|
||||
break;
|
||||
case "ended":
|
||||
renderEndSplash();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -54,6 +56,26 @@ function getLiveCount() {
|
||||
return liveCount;
|
||||
}
|
||||
|
||||
function renderEndSplash() {
|
||||
document.getElementById("game-container").classList.add("hidden");
|
||||
document.getElementById("message-box").classList.add("hidden");
|
||||
currentGame.winningTeam === "village"
|
||||
? document.getElementById("end-container").innerHTML ="<div class='winner-header'><p class='winner-village'>Village</p> wins!</div>"
|
||||
: document.getElementById("end-container").innerHTML ="<div class='winner-header'><p class='winner-wolf'>Wolves</p>win!</div>";
|
||||
const wolfContainer = document.createElement("div");
|
||||
wolfContainer.setAttribute("id", "wolves");
|
||||
let wolfContent = "<div class='evil-header'><span>The</span><p class='evil-subheader'>evil</p> <span>players were:</span></div>";
|
||||
for (const player of currentGame.players) {
|
||||
if (player.card.role === "Werewolf" || player.card.role === "Minion") {
|
||||
wolfContent += "<div class='evil-list-item'>" + player.name + ": " + player.card.role + "</div>"
|
||||
}
|
||||
}
|
||||
wolfContent += "<a href='/'><button class='app-btn'>Home</button></a>";
|
||||
wolfContainer.innerHTML = wolfContent;
|
||||
document.getElementById("end-container").appendChild(wolfContainer);
|
||||
|
||||
}
|
||||
|
||||
function renderGame() {
|
||||
const player = currentGame.players.find((player) => player.id === sessionStorage.getItem("id"));
|
||||
|
||||
@@ -133,17 +155,29 @@ function pauseOrResumeGame() {
|
||||
}
|
||||
|
||||
function getFlipState() {
|
||||
console.log(cardFlippedOver);
|
||||
return cardFlippedOver ? "flip-down" : "flip-up";
|
||||
}
|
||||
|
||||
function flipCard() {
|
||||
cardFlippedOver ?
|
||||
document.getElementById("game-card").setAttribute("class", "flip-down")
|
||||
: document.getElementById("game-card").setAttribute("class", "flip-up");
|
||||
cardFlippedOver
|
||||
? flipUp()
|
||||
: flipDown();
|
||||
|
||||
cardFlippedOver = !cardFlippedOver;
|
||||
}
|
||||
|
||||
function flipUp(){
|
||||
const card = document.getElementById("game-card");
|
||||
card.classList.add("flip-up");
|
||||
card.classList.remove("flip-down");
|
||||
}
|
||||
|
||||
function flipDown(){
|
||||
const card = document.getElementById("game-card");
|
||||
card.classList.add("flip-down");
|
||||
card.classList.remove("flip-up");
|
||||
}
|
||||
|
||||
function renderClock() {
|
||||
clock = setInterval(function() {
|
||||
const start = currentGame.paused ? new Date(currentGame.pauseTime) : new Date();
|
||||
@@ -166,7 +200,6 @@ function renderClock() {
|
||||
|
||||
function endGame(timeExpired) {
|
||||
if (timeExpired) {
|
||||
console.log("expired");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,40 @@
|
||||
const socket = io();
|
||||
import { utility } from './util.js'
|
||||
|
||||
document.getElementById("join-btn").addEventListener("click", function() {
|
||||
sessionStorage.setItem("code", document.getElementById("code").value);
|
||||
let playerId = utility.generateID();
|
||||
sessionStorage.setItem("id", playerId);
|
||||
const playerInfo = {name: document.getElementById("name").value, id: playerId, code: document.getElementById("code").value};
|
||||
socket.emit('joinGame', playerInfo);
|
||||
// respond to the game state received from the server
|
||||
socket.on('joinError', function(message) {
|
||||
document.getElementById("code").classList.add("error");
|
||||
document.getElementById("join-error").innerText = message;
|
||||
});
|
||||
|
||||
// respond to the game state received from the server
|
||||
socket.on('success', function() {
|
||||
if (document.getElementById("code").classList.contains("error")) {
|
||||
document.getElementById("code").classList.remove("error");
|
||||
document.getElementById("join-error").innerText = "";
|
||||
}
|
||||
// If a player was a host of a previous game, don't make them the host of this one
|
||||
if (sessionStorage.getItem("host")) {
|
||||
sessionStorage.removeItem("host");
|
||||
}
|
||||
window.location.replace('/' + document.getElementById("code").value);
|
||||
});
|
||||
|
||||
document.getElementById("join-btn").addEventListener("click", function() {
|
||||
if (document.getElementById("name").value.length > 0) {
|
||||
if (document.getElementById("name").classList.contains("error")) {
|
||||
document.getElementById("name").classList.remove("error");
|
||||
document.getElementById("name-error").innerText = "";
|
||||
}
|
||||
sessionStorage.setItem("code", document.getElementById("code").value);
|
||||
let playerId = utility.generateID();
|
||||
sessionStorage.setItem("id", playerId);
|
||||
const playerInfo = {name: document.getElementById("name").value, id: playerId, code: document.getElementById("code").value};
|
||||
socket.emit('joinGame', playerInfo);
|
||||
} else {
|
||||
document.getElementById("name").classList.add("error");
|
||||
document.getElementById("name-error").innerText = "Name is required.";
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
@@ -52,7 +52,6 @@ window.onload = function() {
|
||||
if(!newCard.powerRole || (newCard.powerRole && newCard.quantity === 0)) {
|
||||
newCard.quantity += 1;
|
||||
}
|
||||
console.log(newCard);
|
||||
cardContainer.getElementsByClassName("card-quantity")[0].innerHTML = newCard.quantity;
|
||||
updateGameSize();
|
||||
});
|
||||
@@ -92,32 +91,36 @@ function buildDeckFromQuantities() {
|
||||
}
|
||||
|
||||
function createGame() {
|
||||
// generate 6 digit access code
|
||||
let code = "";
|
||||
let charPool = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
for (let i = 0; i < 6; i++) {
|
||||
code += charPool[utility.getRandomInt(61)]
|
||||
if (document.getElementById("name").value.length > 0) {
|
||||
// generate 6 digit access code
|
||||
let code = "";
|
||||
let charPool = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
for (let i = 0; i < 6; i++) {
|
||||
code += charPool[utility.getRandomInt(61)]
|
||||
}
|
||||
|
||||
// generate unique player Id for session
|
||||
let id = utility.generateID();
|
||||
sessionStorage.setItem("id", id);
|
||||
|
||||
// player who creates the game is the host
|
||||
sessionStorage.setItem("host", true);
|
||||
|
||||
// send a new game to the server, and then join it
|
||||
const playerInfo = {name: document.getElementById("name").value, code: code, id: id};
|
||||
const game = new Game(
|
||||
code,
|
||||
gameSize,
|
||||
buildDeckFromQuantities(),
|
||||
document.getElementById("time").value
|
||||
);
|
||||
socket.emit('newGame', game, function(data) {
|
||||
socket.emit('joinGame', playerInfo);
|
||||
sessionStorage.setItem('code', code);
|
||||
window.location.replace('/' + code);
|
||||
});
|
||||
} else {
|
||||
document.getElementById("name").classList.add("error");
|
||||
document.getElementById("name-error").innerText = "Name is required.";
|
||||
}
|
||||
|
||||
// generate unique player Id for session
|
||||
let id = utility.generateID();
|
||||
sessionStorage.setItem("id", id);
|
||||
|
||||
// player who creates the game is the host
|
||||
sessionStorage.setItem("host", true);
|
||||
|
||||
// send a new game to the server, and then join it
|
||||
const playerInfo = {name: document.getElementById("name").value, code: code, id: id};
|
||||
const game = new Game(
|
||||
code,
|
||||
gameSize,
|
||||
buildDeckFromQuantities(),
|
||||
document.getElementById("time").value
|
||||
);
|
||||
socket.emit('newGame', game, function(data) {
|
||||
console.log(data);
|
||||
socket.emit('joinGame', playerInfo);
|
||||
sessionStorage.setItem('code', code);
|
||||
window.location.replace('/' + code);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -122,6 +122,33 @@ button {
|
||||
font-family: 'sitewide-sans-serif', sans-serif;
|
||||
}
|
||||
|
||||
.error {
|
||||
border: 1px solid #bd2a2a !important;
|
||||
background-color: rgba(189, 42, 42, 0.1) !important;
|
||||
}
|
||||
|
||||
#join-error, #name-error {
|
||||
color: #bd2a2a;
|
||||
font-size: 0.9em;
|
||||
height: 2em;
|
||||
margin: 0;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#join-game-container span {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#join-game-container form {
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
|
||||
#join-game-container input[type=text], #create-game-container input[type=text] {
|
||||
margin-right: 0.5em;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.app-btn {
|
||||
background-color: #f8f8f8;
|
||||
color: #bd2a2a;
|
||||
@@ -245,6 +272,7 @@ input[type=text] {
|
||||
margin: 0.5em 0 1em 0;
|
||||
color: gray;
|
||||
padding: 0.7em;
|
||||
height: 1.2em;
|
||||
width: 9em;
|
||||
border-radius: 5px;
|
||||
font-size: 1.1em;
|
||||
@@ -258,6 +286,7 @@ input[type=number] {
|
||||
margin: 0.5em 0 1em 0;
|
||||
color: gray;
|
||||
padding: 0.7em;
|
||||
height: 1.2em;
|
||||
width: 4em;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
@@ -486,3 +515,53 @@ label {
|
||||
opacity: 0.4;
|
||||
transform: scale(0.90);
|
||||
}
|
||||
|
||||
/* end splash */
|
||||
|
||||
#end-container {
|
||||
margin: 0 auto;
|
||||
display: inline-block;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#end-container .winner-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 0;
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
#end-container .evil-subheader {
|
||||
font-family: 'diavlo', sans-serif;
|
||||
color: #7d0b0b;
|
||||
margin: 0 0.3em;
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
#end-container .evil-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 20px;
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
|
||||
|
||||
#end-container p {
|
||||
font-weight: bold;
|
||||
margin-right: 0.3em;
|
||||
font-size: 50px;
|
||||
}
|
||||
|
||||
#end-container button {
|
||||
margin-top: 3em;
|
||||
}
|
||||
|
||||
#end-container .winner-village {
|
||||
font-family: 'diavlo', sans-serif;
|
||||
color: #171469;
|
||||
}
|
||||
|
||||
#end-container .winner-wolf {
|
||||
font-family: 'diavlo', sans-serif;
|
||||
color: #7d0b0b;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user