mirror of
https://github.com/AlecM33/Werewolf.git
synced 2025-12-26 15:57:50 +01:00
Merge pull request #4 from AlecM33/develop
Deal and display cards to players, click a button to say you are dead…
This commit is contained in:
@@ -9,8 +9,10 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-content">
|
||||
<div id="message-box"></div>
|
||||
<div id="lobby-container"></div>
|
||||
<div id="launch-btn"></div>
|
||||
<div id="game-container"></div>
|
||||
<div id="launch"></div>
|
||||
</div>
|
||||
<script type="module" src="/static/game.js"></script>
|
||||
</body>
|
||||
|
||||
15
server.js
15
server.js
@@ -39,7 +39,7 @@ io.on('connection', function(socket) {
|
||||
onSucess();
|
||||
});
|
||||
socket.on('joinGame', function(playerInfo) {
|
||||
activeGames[Object.keys(activeGames).find((key) => key === playerInfo.code)].players[socket.id] = {name: playerInfo.name, id: playerInfo.id};
|
||||
activeGames[Object.keys(activeGames).find((key) => key === playerInfo.code)].players.push({name: playerInfo.name, id: playerInfo.id});
|
||||
});
|
||||
socket.on('requestState', function(data) {
|
||||
if(Object.keys(socket.rooms).includes(data.code) === false) {
|
||||
@@ -53,5 +53,18 @@ io.on('connection', function(socket) {
|
||||
io.to(data.code).emit('state', activeGames[Object.keys(activeGames).find((key) => key === data.code)]);
|
||||
}
|
||||
});
|
||||
socket.on('startGame', function(gameData) {
|
||||
let game = activeGames[Object.keys(activeGames).find((key) => key === gameData.code)];
|
||||
game.state = "started";
|
||||
game.players = gameData.players;
|
||||
io.to(gameData.code).emit('state', game);
|
||||
});
|
||||
socket.on('killPlayer', function(id, code) {
|
||||
let game = activeGames[Object.keys(activeGames).find((key) => key === code)];
|
||||
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);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
100
static/game.js
100
static/game.js
@@ -1,10 +1,17 @@
|
||||
import {utility} from './util.js'
|
||||
|
||||
const socket = io();
|
||||
var currentGame = null;
|
||||
|
||||
document.getElementById("launch").addEventListener("click", launchGame);
|
||||
|
||||
// respond to the game state received from the server
|
||||
socket.on('state', function(game) {
|
||||
currentGame = game;
|
||||
console.log(game);
|
||||
if (game.message) {
|
||||
document.getElementById("message-box").innerText = game.message;
|
||||
}
|
||||
console.log(currentGame);
|
||||
buildGameBasedOnState();
|
||||
});
|
||||
|
||||
@@ -12,10 +19,80 @@ function buildGameBasedOnState() {
|
||||
switch(currentGame.state) {
|
||||
case "lobby":
|
||||
renderLobby();
|
||||
break;
|
||||
case "started":
|
||||
renderGame();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function launchGame() {
|
||||
randomlyDealCardsToPlayers();
|
||||
socket.emit('startGame', { players: currentGame.players , code: currentGame.accessCode});
|
||||
}
|
||||
|
||||
function randomlyDealCardsToPlayers() {
|
||||
for (let player of currentGame.players) {
|
||||
player.card = drawRandomCard();
|
||||
}
|
||||
}
|
||||
|
||||
function drawRandomCard() {
|
||||
return currentGame.deck.splice(utility.getRandomInt(currentGame.deck.length) - 1, 1)[0];
|
||||
}
|
||||
|
||||
function getLiveCount() {
|
||||
let liveCount = 0;
|
||||
for (let player of currentGame.players) {
|
||||
if (!player.dead) {
|
||||
liveCount ++;
|
||||
}
|
||||
}
|
||||
return liveCount;
|
||||
}
|
||||
|
||||
function renderGame() {
|
||||
const player = currentGame.players.find((player) => player.id === sessionStorage.getItem("id"));
|
||||
const card = player.card;
|
||||
|
||||
// render the players card
|
||||
document.getElementById("lobby-container").setAttribute("class", "hidden");
|
||||
document.getElementById("launch").setAttribute("class", "hidden");
|
||||
document.getElementById("game-container").setAttribute("class", "game-container");
|
||||
document.getElementById("game-container").innerHTML =
|
||||
"<div id='players-remaining'>" + getLiveCount() + "/" + currentGame.size + " Players alive</div>" +
|
||||
"<div class='game-card'>" +
|
||||
"<div class='game-card-inner'" +
|
||||
"<div class='game-card-front'>" +
|
||||
"<h2>" + card.role + "</h2>" +
|
||||
"<p>" + card.description + "</p>" +
|
||||
"</div>" +
|
||||
"<div class='game-card-back'></div>" +
|
||||
"</div>" +
|
||||
"</div>";
|
||||
let killedBtn = document.createElement("button");
|
||||
killedBtn.setAttribute("id", "dead-btn");
|
||||
|
||||
// render the "I'm dead" button based on the player's state
|
||||
if (player.dead) {
|
||||
killedBtn.setAttribute("class", "app-btn-secondary killed-btn disabled");
|
||||
killedBtn.innerText = "Killed"
|
||||
} else {
|
||||
killedBtn.setAttribute("class", "app-btn-secondary killed-btn");
|
||||
killedBtn.innerText = "I'm dead";
|
||||
}
|
||||
document.getElementById("game-container").appendChild(killedBtn);
|
||||
document.getElementById("dead-btn").addEventListener("click", killPlayer);
|
||||
}
|
||||
|
||||
function killPlayer() {
|
||||
socket.emit("killPlayer", currentGame.players.find((player) => player.id === sessionStorage.getItem("id")).id, currentGame.accessCode);
|
||||
}
|
||||
|
||||
function renderLobby() {
|
||||
// Render lobby header
|
||||
if (document.getElementsByClassName("lobby-player").length === 0) {
|
||||
let header = document.createElement("h2");
|
||||
header.setAttribute("class", "app-header");
|
||||
@@ -24,36 +101,39 @@ function renderLobby() {
|
||||
let subHeader = document.createElement("div");
|
||||
subHeader.setAttribute("id", "lobby-subheader");
|
||||
subHeader.innerHTML = "<div>" +
|
||||
"<span id='join-count'>" + Object.keys(currentGame.players).length + "</span>" +
|
||||
"<span id='join-count'>" + currentGame.players.length + "</span>" +
|
||||
"<span id='deck-size'>/" + currentGame.size + " Players</span>" +
|
||||
"</div>" +
|
||||
"<br>" +
|
||||
"<div id='game-code'>Access Code: " + currentGame.accessCode + "</div>";
|
||||
document.getElementById("lobby-container").appendChild(subHeader);
|
||||
}
|
||||
// Render all players that are new
|
||||
let i = 1;
|
||||
for (let key in currentGame.players) {
|
||||
for (let player of currentGame.players) {
|
||||
if(!document.getElementById("player-" + i)) {
|
||||
const playerContainer = document.createElement("div");
|
||||
currentGame.players[key].id === sessionStorage.getItem("id") ?
|
||||
player.id === sessionStorage.getItem("id") ?
|
||||
playerContainer.setAttribute("class", "lobby-player highlighted")
|
||||
: playerContainer.setAttribute("class", "lobby-player");
|
||||
playerContainer.setAttribute("id", "player-" + i);
|
||||
playerContainer.innerHTML = "<p>" + currentGame.players[key].name + "</p>";
|
||||
playerContainer.innerHTML = "<p>" + player.name + "</p>";
|
||||
document.getElementById("lobby-container").appendChild(playerContainer);
|
||||
document.getElementById("join-count").innerText = Object.keys(currentGame.players).length.toString();
|
||||
document.getElementById("join-count").innerText = currentGame.players.length.toString();
|
||||
}
|
||||
i ++;
|
||||
}
|
||||
// display the launch button if the player is the host
|
||||
if (sessionStorage.getItem("host")) {
|
||||
Object.keys(currentGame.players).length === currentGame.size ?
|
||||
document.getElementById("launch-btn").innerHTML = "<button class='app-btn'>Start Game</button>"
|
||||
: document.getElementById("launch-btn").innerHTML = "<button class='app-btn disabled'>Start Game</button>"
|
||||
currentGame.players.length === currentGame.size ?
|
||||
document.getElementById("launch").innerHTML = "<button class='app-btn'>Start Game</button>"
|
||||
: document.getElementById("launch").innerHTML = "<button class='app-btn disabled'>Start Game</button>"
|
||||
} else {
|
||||
document.getElementById("launch").innerHTML = "<p>The host will start the game.</p>"
|
||||
}
|
||||
}
|
||||
|
||||
// request the current state of the game from the server
|
||||
window.onload = function() {
|
||||
socket.emit('requestState', {code: sessionStorage.getItem("code")});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,23 +1,12 @@
|
||||
const socket = io();
|
||||
import { utility } from './util.js'
|
||||
|
||||
document.getElementById("join-btn").addEventListener("click", function() {
|
||||
sessionStorage.setItem("code", document.getElementById("code").value);
|
||||
let playerId = generateID();
|
||||
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);
|
||||
window.location.replace('/' + document.getElementById("code").value);
|
||||
});
|
||||
|
||||
function generateID() {
|
||||
let code = "";
|
||||
let charPool = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
for (let i = 0; i < 10; i++) {
|
||||
code += charPool[getRandomInt(61)]
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
function getRandomInt(max) {
|
||||
return Math.floor(Math.random() * Math.floor(max));
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {cards} from './cards.js'
|
||||
import {utility} from './util.js'
|
||||
|
||||
const socket = io();
|
||||
var games = [];
|
||||
@@ -6,6 +7,7 @@ var games = [];
|
||||
// important declarations
|
||||
class Card {
|
||||
constructor(role, team, description, powerRole) {
|
||||
this.id = null;
|
||||
this.role = role;
|
||||
this.team = team;
|
||||
this.description = description;
|
||||
@@ -15,17 +17,17 @@ class Card {
|
||||
}
|
||||
|
||||
class Game {
|
||||
constructor(accessCode, size, deck, time, players) {
|
||||
constructor(accessCode, size, deck, time) {
|
||||
this.accessCode = accessCode;
|
||||
this.size = size;
|
||||
this.deck = deck;
|
||||
this.time = time;
|
||||
this.players = players;
|
||||
this.players = [];
|
||||
this.state = "lobby";
|
||||
}
|
||||
}
|
||||
|
||||
var deck = [];
|
||||
var fullDeck = [];
|
||||
var gameSize = 0;
|
||||
var time = null;
|
||||
|
||||
@@ -40,7 +42,7 @@ window.onload = function() {
|
||||
const newCard = new Card(card.role, card.team, card.description, card.powerRole);
|
||||
const cardContainer = document.createElement("div");
|
||||
|
||||
deck.push(newCard);
|
||||
fullDeck.push(newCard);
|
||||
|
||||
cardContainer.setAttribute("class", "card");
|
||||
cardContainer.innerHTML = "<p class='card-role'>" + newCard.role + "</p><br><p class='card-quantity'>" + newCard.quantity + "</p>";
|
||||
@@ -60,14 +62,14 @@ window.onload = function() {
|
||||
|
||||
function updateGameSize() {
|
||||
gameSize = 0;
|
||||
for (let card of deck) {
|
||||
for (let card of fullDeck) {
|
||||
gameSize += card.quantity;
|
||||
}
|
||||
document.getElementById("game-size").innerText = gameSize + " Players";
|
||||
}
|
||||
|
||||
function resetCardQuantities() {
|
||||
for (let card of deck) {
|
||||
for (let card of fullDeck) {
|
||||
card.quantity = 0;
|
||||
}
|
||||
updateGameSize();
|
||||
@@ -76,17 +78,28 @@ function resetCardQuantities() {
|
||||
});
|
||||
}
|
||||
|
||||
function buildDeckFromQuantities() {
|
||||
let playerDeck = [];
|
||||
for (const card of fullDeck) {
|
||||
for (let i = 0; i < card.quantity; i++) {
|
||||
let newCard = new Card(card.role, card.team, card.description, card.powerRole);
|
||||
newCard.id = utility.generateID();
|
||||
playerDeck.push(newCard);
|
||||
}
|
||||
}
|
||||
return playerDeck;
|
||||
}
|
||||
|
||||
function createGame() {
|
||||
// generate 6 digit access code
|
||||
let code = "";
|
||||
let charPool = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
for (let i = 0; i < 6; i++) {
|
||||
code += charPool[getRandomInt(61)]
|
||||
code += charPool[utility.getRandomInt(61)]
|
||||
}
|
||||
console.log(code);
|
||||
|
||||
// generate unique player Id for session
|
||||
let id = generateID();
|
||||
let id = utility.generateID();
|
||||
sessionStorage.setItem("id", id);
|
||||
|
||||
// player who creates the game is the host
|
||||
@@ -97,9 +110,8 @@ function createGame() {
|
||||
const game = new Game(
|
||||
code,
|
||||
gameSize,
|
||||
deck,
|
||||
document.getElementById("time").value,
|
||||
{ [socket.id]: playerInfo}
|
||||
buildDeckFromQuantities(),
|
||||
document.getElementById("time").value
|
||||
);
|
||||
socket.emit('newGame', game, function(data) {
|
||||
console.log(data);
|
||||
@@ -108,17 +120,3 @@ function createGame() {
|
||||
window.location.replace('/' + code);
|
||||
});
|
||||
}
|
||||
|
||||
function generateID() {
|
||||
let code = "";
|
||||
let charPool = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
for (let i = 0; i < 10; i++) {
|
||||
code += charPool[getRandomInt(61)]
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
|
||||
function getRandomInt(max) {
|
||||
return Math.floor(Math.random() * Math.floor(max));
|
||||
}
|
||||
|
||||
@@ -39,7 +39,6 @@
|
||||
html, body {
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
margin-bottom: 2em;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
@@ -197,6 +196,12 @@ label {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#message-box {
|
||||
margin: 1em 1em;
|
||||
border-bottom: 1px solid #7d0b0b;
|
||||
padding: 0.5em;
|
||||
}
|
||||
|
||||
|
||||
/* lobby */
|
||||
|
||||
@@ -230,6 +235,10 @@ label {
|
||||
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#lobby-subheader {
|
||||
text-align: left;
|
||||
margin-bottom: 2em;
|
||||
@@ -246,3 +255,86 @@ label {
|
||||
#launch-btn {
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
/* GAME */
|
||||
|
||||
@keyframes flip {
|
||||
0% {
|
||||
transform: rotateY(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotateY(-180deg);
|
||||
}
|
||||
}
|
||||
|
||||
.game-card {
|
||||
border: 1px solid #7d0b0b;
|
||||
background-color: #f0f0f0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
max-width: 17em;
|
||||
border-radius: 3px;
|
||||
height: 25em;
|
||||
margin: 0 auto 2em auto;
|
||||
width: 82%;
|
||||
box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.3);
|
||||
perspective: 1000px;
|
||||
animation: flip 0.7s;
|
||||
animation-fill-mode: forwards;
|
||||
animation-direction: reverse;
|
||||
transform-style: preserve-3d;
|
||||
}
|
||||
|
||||
.game-card h2 {
|
||||
font-size: 2em;
|
||||
color: #7d0b0b;
|
||||
}
|
||||
|
||||
.game-card p {
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
.game-container {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
/* This container is needed to position the front and back side */
|
||||
.game-card-inner {
|
||||
position: relative;
|
||||
width: 95%;
|
||||
height: 97%;
|
||||
margin: auto auto;
|
||||
border-radius: 3px;
|
||||
text-align: center;
|
||||
border: 1px solid gray;
|
||||
}
|
||||
|
||||
.game-card:hover {
|
||||
}
|
||||
|
||||
/* Position the front and back side */
|
||||
.game-card-front, .game-card-back {
|
||||
background-color: #f0f0f0;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
backface-visibility: hidden;
|
||||
}
|
||||
|
||||
.game-card-back {
|
||||
transform: rotateY(180deg);
|
||||
}
|
||||
|
||||
.killed-btn {
|
||||
border-radius: 5px;
|
||||
width: 13em;
|
||||
font-size: 1.2em;
|
||||
margin: 0
|
||||
}
|
||||
|
||||
#players-remaining {
|
||||
font-size: 1.7em;
|
||||
color: gray;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
15
static/util.js
Normal file
15
static/util.js
Normal file
@@ -0,0 +1,15 @@
|
||||
export const utility =
|
||||
{
|
||||
generateID() {
|
||||
let code = "";
|
||||
let charPool = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
for (let i = 0; i < 10; i++) {
|
||||
code += charPool[this.getRandomInt(61)]
|
||||
}
|
||||
return code;
|
||||
},
|
||||
|
||||
getRandomInt(max) {
|
||||
return Math.floor(Math.random() * Math.floor(max));
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user