mirror of
https://github.com/AlecM33/Werewolf.git
synced 2025-12-26 15:57:50 +01:00
207 lines
7.1 KiB
JavaScript
207 lines
7.1 KiB
JavaScript
const debugMode = Array.from(process.argv.map( (arg)=>arg.trim().toLowerCase() )).includes("debug");
|
|
const LOGGER = require("./javascript/modules/logger")(debugMode);
|
|
|
|
module.exports = class {
|
|
|
|
constructor(CronJob) {
|
|
// TODO: do better than a plain object
|
|
this.activeGames = {};
|
|
this.timers = {};
|
|
|
|
// cron job for periodically clearing finished games
|
|
const scope = this;
|
|
this.job = new CronJob('0 0 */2 * * *', function() {
|
|
console.log(scope.activeGames);
|
|
for (const key in scope.activeGames) {
|
|
if (scope.activeGames.hasOwnProperty(key) && (Math.abs((new Date()) - (new Date(scope.activeGames[key].startTime))) / 36e5) >= 2) {
|
|
delete scope.activeGames[key];
|
|
}
|
|
}
|
|
console.log("Games pruned at: " + (new Date().toDateString()) + " " + (new Date()).toTimeString());
|
|
});
|
|
console.log("cron job created");
|
|
this.job.start();
|
|
}
|
|
|
|
killPlayer(id, code) {
|
|
let game = this.findGame(code);
|
|
if (game) {
|
|
let player = game.players.find((player) => player.id === id);
|
|
if (player) {
|
|
player.dead = true;
|
|
player.deadAt = new Date().toJSON();
|
|
game.killedPlayer = player.name;
|
|
game.lastKilled = player.id;
|
|
game.killedRole = player.card.role;
|
|
game.message = game.reveals
|
|
? player.name + ", a " + player.card.role + ", was killed!"
|
|
: player.name + " has died!";
|
|
console.log(game.message);
|
|
if (player.card.isTypeOfWerewolf && game.hasDreamWolf) {
|
|
this.activateDreamWolvesIfNeeded(game);
|
|
}
|
|
const winCheck = module.exports.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";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
endGameDueToTimeExpired(code) {
|
|
if (this.timers[code]) {
|
|
clearInterval(this.timers[code]);
|
|
}
|
|
let game = this.findGame(code);
|
|
if (game) {
|
|
LOGGER.debug("Game " + code + " has ended due to expired timer.");
|
|
game.winningTeam = "wolf";
|
|
game.status = "ended";
|
|
}
|
|
}
|
|
|
|
clearGameTimer(code) {
|
|
if (this.timers[code]) {
|
|
clearInterval(this.timers[code]);
|
|
LOGGER.debug("game paused and timer cleared for " + code);
|
|
}
|
|
}
|
|
|
|
resumeGame(code) {
|
|
let game = this.findGame(code);
|
|
if (game) {
|
|
game.paused = false;
|
|
let newTime = new Date(game.endTime).getTime() + (new Date().getTime() - new Date(game.pauseTime).getTime());
|
|
let newDate = new Date(game.endTime);
|
|
newDate.setTime(newTime);
|
|
game.endTime = newDate.toJSON();
|
|
LOGGER.debug("Game " + code + " timer has been unpaused, starting clock anew...");
|
|
this.startGameClock(code, newDate - Date.now());
|
|
}
|
|
}
|
|
|
|
pauseGame(code) {
|
|
let game = this.findGame(code);
|
|
if (game) {
|
|
game.pauseTime = (new Date()).toJSON();
|
|
game.paused = true;
|
|
this.clearGameTimer(code);
|
|
}
|
|
}
|
|
|
|
startGameClock(code, time) {
|
|
LOGGER.debug("timer started for game " + code);
|
|
let moduleScope = this;
|
|
if (this.timers[code]) {
|
|
clearInterval(this.timers[code]);
|
|
}
|
|
this.timers[code] = setInterval(function() {
|
|
moduleScope.endGameDueToTimeExpired(code)
|
|
}, time);
|
|
}
|
|
|
|
startGame(gameData) {
|
|
let game = this.findGame(gameData.code);
|
|
if (game) {
|
|
LOGGER.debug("game " + gameData.code + " started");
|
|
game.status = "started";
|
|
game.players = gameData.players;
|
|
if (game.time) {
|
|
let d = new Date();
|
|
d.setMinutes(d.getMinutes() + parseInt(game.time));
|
|
game.endTime = d.toJSON();
|
|
this.startGameClock(gameData.code, game.time * 60 * 1000); // provided time is in minutes
|
|
}
|
|
}
|
|
}
|
|
|
|
requestState(data, socket) {
|
|
const game = this.findGame(data.code);
|
|
if (game && Object.keys(socket.rooms).includes(data.code) === false) {
|
|
socket.join(data.code, function() {
|
|
socket.emit('state', game);
|
|
});
|
|
} else {
|
|
if (game) {
|
|
socket.emit('state', game);
|
|
}
|
|
}
|
|
}
|
|
|
|
joinGame(playerInfo, socket) {
|
|
|
|
const game = this.findGame(playerInfo.code);
|
|
if (game && game.players.length < game.size && !game.players.find((player) => player.id === playerInfo.id)) {
|
|
game.players.push({name: playerInfo.name, id: playerInfo.id});
|
|
console.log(playerInfo.name + " joined the game!");
|
|
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");
|
|
}
|
|
}
|
|
}
|
|
|
|
newGame(game, onSuccess) {
|
|
this.activeGames[game.accessCode] = game;
|
|
this.activeGames[game.accessCode].startTime = (new Date()).toJSON();
|
|
console.log("Game created at " + (new Date().toDateString()) + " " + (new Date()).toTimeString());
|
|
onSuccess();
|
|
}
|
|
|
|
findGame(code) {
|
|
return this.activeGames[Object.keys(this.activeGames).find((key) => key === code)];
|
|
}
|
|
|
|
// If there are multiple dream wolves, convert them all.
|
|
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!");
|
|
}
|
|
})
|
|
}
|
|
|
|
static teamWon(game) {
|
|
let wolvesAlive = 0;
|
|
let villagersAlive = 0;
|
|
let totalAlive = 0;
|
|
let hunterAlive = false;
|
|
for (const player of game.players) {
|
|
if (!player.card.isTypeOfWerewolf && !player.dead) {
|
|
villagersAlive ++;
|
|
}
|
|
if (player.card.isTypeOfWerewolf && !player.dead) {
|
|
wolvesAlive ++;
|
|
}
|
|
if (player.card.role === "Hunter" && !player.dead) {
|
|
hunterAlive = true;
|
|
}
|
|
if (!player.dead) {
|
|
totalAlive ++;
|
|
}
|
|
}
|
|
if (wolvesAlive === 0) {
|
|
return "village"
|
|
}
|
|
if ((wolvesAlive >= villagersAlive) && (totalAlive !== 2)) {
|
|
return "wolf";
|
|
}
|
|
if (totalAlive === 2) {
|
|
return hunterAlive ? "village" : "wolf"
|
|
}
|
|
return false;
|
|
}
|
|
};
|
|
|