mirror of
https://github.com/AlecM33/Werewolf.git
synced 2025-12-26 15:57:50 +01:00
reveal role functionality, beginnings of mod transfer
This commit is contained in:
@@ -12,7 +12,9 @@ export const globals = {
|
|||||||
PAUSE_TIMER: 'pauseTimer',
|
PAUSE_TIMER: 'pauseTimer',
|
||||||
RESUME_TIMER: 'resumeTimer',
|
RESUME_TIMER: 'resumeTimer',
|
||||||
GET_TIME_REMAINING: 'getTimeRemaining',
|
GET_TIME_REMAINING: 'getTimeRemaining',
|
||||||
KILL_PLAYER: 'killPlayer'
|
KILL_PLAYER: 'killPlayer',
|
||||||
|
REVEAL_PLAYER: 'revealPlayer',
|
||||||
|
TRANSFER_MODERATOR: 'transferModerator'
|
||||||
},
|
},
|
||||||
STATUS: {
|
STATUS: {
|
||||||
LOBBY: "lobby",
|
LOBBY: "lobby",
|
||||||
@@ -26,12 +28,15 @@ export const globals = {
|
|||||||
PLAYER_JOINED: "playerJoined",
|
PLAYER_JOINED: "playerJoined",
|
||||||
SYNC_GAME_STATE: "syncGameState",
|
SYNC_GAME_STATE: "syncGameState",
|
||||||
START_TIMER: "startTimer",
|
START_TIMER: "startTimer",
|
||||||
KILL_PLAYER: "killPlayer"
|
KILL_PLAYER: "killPlayer",
|
||||||
|
REVEAL_PLAYER: 'revealPlayer'
|
||||||
},
|
},
|
||||||
USER_TYPES: {
|
USER_TYPES: {
|
||||||
MODERATOR: "moderator",
|
MODERATOR: "moderator",
|
||||||
PLAYER: "player",
|
PLAYER: "player",
|
||||||
TEMPORARY_MODERATOR: "player / temp mod"
|
TEMPORARY_MODERATOR: "player / temp mod",
|
||||||
|
KILLED_PLAYER: "killed",
|
||||||
|
SPECTATOR: "spectator"
|
||||||
},
|
},
|
||||||
ENVIRONMENT: {
|
ENVIRONMENT: {
|
||||||
LOCAL: "local",
|
LOCAL: "local",
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
import { globals } from "../config/globals.js";
|
import { globals } from "../config/globals.js";
|
||||||
import { toast } from "./Toast.js";
|
import { toast } from "./Toast.js";
|
||||||
import {templates} from "./Templates.js";
|
import {templates} from "./Templates.js";
|
||||||
|
import {ModalManager} from "./ModalManager.js";
|
||||||
|
|
||||||
export class GameStateRenderer {
|
export class GameStateRenderer {
|
||||||
constructor(gameState, socket) {
|
constructor(gameState, socket) {
|
||||||
this.gameState = gameState;
|
this.gameState = gameState;
|
||||||
this.socket = socket;
|
this.socket = socket;
|
||||||
this.killPlayerHandlers = {};
|
this.killPlayerHandlers = {};
|
||||||
|
this.revealRoleHandlers = {};
|
||||||
|
this.transferModHandlers = {};
|
||||||
this.cardFlipped = false;
|
this.cardFlipped = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -20,12 +23,6 @@ export class GameStateRenderer {
|
|||||||
lobbyPlayersContainer.appendChild(renderLobbyPerson(person.name,person.userType))
|
lobbyPlayersContainer.appendChild(renderLobbyPerson(person.name,person.userType))
|
||||||
}
|
}
|
||||||
let playerCount = this.gameState.people.filter((person) => person.userType === globals.USER_TYPES.PLAYER).length;
|
let playerCount = this.gameState.people.filter((person) => person.userType === globals.USER_TYPES.PLAYER).length;
|
||||||
if (this.gameState.moderator.userType === globals.USER_TYPES.TEMPORARY_MODERATOR) {
|
|
||||||
playerCount += 1;
|
|
||||||
}
|
|
||||||
if (this.gameState.client.userType === globals.USER_TYPES.PLAYER) {
|
|
||||||
playerCount += 1;
|
|
||||||
}
|
|
||||||
document.querySelector("label[for='lobby-players']").innerText =
|
document.querySelector("label[for='lobby-players']").innerText =
|
||||||
"People (" + playerCount + "/" + getGameSize(this.gameState.deck) + " Players)";
|
"People (" + playerCount + "/" + getGameSize(this.gameState.deck) + " Players)";
|
||||||
}
|
}
|
||||||
@@ -67,19 +64,37 @@ export class GameStateRenderer {
|
|||||||
let div = document.createElement("div");
|
let div = document.createElement("div");
|
||||||
div.innerHTML = templates.END_GAME_PROMPT;
|
div.innerHTML = templates.END_GAME_PROMPT;
|
||||||
document.body.appendChild(div);
|
document.body.appendChild(div);
|
||||||
|
|
||||||
|
let modTransferButton = document.getElementById("mod-transfer-button");
|
||||||
|
modTransferButton.addEventListener(
|
||||||
|
"click", () => {
|
||||||
|
this.displayAvailableModerators()
|
||||||
|
ModalManager.displayModal(
|
||||||
|
"transfer-mod-modal",
|
||||||
|
"transfer-mod-modal-background",
|
||||||
|
"close-modal-button"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
this.renderPlayersWithRoleAndAlignmentInfo();
|
this.renderPlayersWithRoleAndAlignmentInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
renderPlayerView() {
|
renderPlayerView(isKilled=false) {
|
||||||
|
if (isKilled) {
|
||||||
|
let clientUserType = document.getElementById("client-user-type");
|
||||||
|
if (clientUserType) {
|
||||||
|
clientUserType.innerText = globals.USER_TYPES.KILLED_PLAYER + ' \uD83D\uDC80'
|
||||||
|
}
|
||||||
|
}
|
||||||
renderPlayerRole(this.gameState);
|
renderPlayerRole(this.gameState);
|
||||||
this.renderPlayersWithNoRoleInformation();
|
this.renderPlayersWithNoRoleInformationUnlessRevealed();
|
||||||
}
|
}
|
||||||
|
|
||||||
refreshPlayerList(isModerator) {
|
refreshPlayerList(isModerator) {
|
||||||
if (isModerator) {
|
if (isModerator) {
|
||||||
this.renderPlayersWithRoleAndAlignmentInfo()
|
this.renderPlayersWithRoleAndAlignmentInfo()
|
||||||
} else {
|
} else {
|
||||||
this.renderPlayersWithNoRoleInformation();
|
this.renderPlayersWithNoRoleInformationUnlessRevealed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,7 +102,12 @@ export class GameStateRenderer {
|
|||||||
document.querySelectorAll('.game-player').forEach((el) => {
|
document.querySelectorAll('.game-player').forEach((el) => {
|
||||||
let pointer = el.dataset.pointer;
|
let pointer = el.dataset.pointer;
|
||||||
if (pointer && this.killPlayerHandlers[pointer]) {
|
if (pointer && this.killPlayerHandlers[pointer]) {
|
||||||
el.removeEventListener('click', this.killPlayerHandlers[pointer])
|
el.removeEventListener('click', this.killPlayerHandlers[pointer]);
|
||||||
|
delete this.killPlayerHandlers[pointer];
|
||||||
|
}
|
||||||
|
if (pointer && this.revealRoleHandlers[pointer]) {
|
||||||
|
el.removeEventListener('click', this.revealRoleHandlers[pointer]);
|
||||||
|
delete this.revealRoleHandlers[pointer];
|
||||||
}
|
}
|
||||||
el.remove();
|
el.remove();
|
||||||
});
|
});
|
||||||
@@ -96,14 +116,14 @@ export class GameStateRenderer {
|
|||||||
});
|
});
|
||||||
let teamGood = this.gameState.people.filter((person) => person.alignment === globals.ALIGNMENT.GOOD);
|
let teamGood = this.gameState.people.filter((person) => person.alignment === globals.ALIGNMENT.GOOD);
|
||||||
let teamEvil = this.gameState.people.filter((person) => person.alignment === globals.ALIGNMENT.EVIL);
|
let teamEvil = this.gameState.people.filter((person) => person.alignment === globals.ALIGNMENT.EVIL);
|
||||||
renderGroupOfPlayers(teamEvil, this.killPlayerHandlers, this.gameState.accessCode, globals.ALIGNMENT.EVIL, true, this.socket);
|
renderGroupOfPlayers(teamEvil, this.killPlayerHandlers, this.revealRoleHandlers, this.gameState.accessCode, globals.ALIGNMENT.EVIL, true, this.socket);
|
||||||
renderGroupOfPlayers(teamGood, this.killPlayerHandlers, this.gameState.accessCode, globals.ALIGNMENT.GOOD, true, this.socket);
|
renderGroupOfPlayers(teamGood, this.killPlayerHandlers, this.revealRoleHandlers, this.gameState.accessCode, globals.ALIGNMENT.GOOD, true, this.socket);
|
||||||
document.getElementById("players-alive-label").innerText =
|
document.getElementById("players-alive-label").innerText =
|
||||||
'Players: ' + this.gameState.people.filter((person) => !person.out).length + ' / ' + this.gameState.people.length + ' Alive';
|
'Players: ' + this.gameState.people.filter((person) => !person.out).length + ' / ' + this.gameState.people.length + ' Alive';
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
renderPlayersWithNoRoleInformation() {
|
renderPlayersWithNoRoleInformationUnlessRevealed() {
|
||||||
document.querySelectorAll('.game-player').forEach((el) => el.remove());
|
document.querySelectorAll('.game-player').forEach((el) => el.remove());
|
||||||
this.gameState.people.sort((a, b) => {
|
this.gameState.people.sort((a, b) => {
|
||||||
return a.name >= b.name ? 1 : -1;
|
return a.name >= b.name ? 1 : -1;
|
||||||
@@ -114,6 +134,44 @@ export class GameStateRenderer {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updatePlayerCardToKilledState() {
|
||||||
|
document.querySelector('#role-image').classList.add("killed-card");
|
||||||
|
document.getElementById("role-image").setAttribute(
|
||||||
|
'src',
|
||||||
|
'../images/tombstone.png'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
displayAvailableModerators() {
|
||||||
|
document.querySelectorAll('.potential-moderator').forEach((el) => {
|
||||||
|
let pointer = el.dataset.pointer;
|
||||||
|
if (pointer && this.transferModHandlers[pointer]) {
|
||||||
|
el.removeEventListener('click', this.transferModHandlers[pointer]);
|
||||||
|
delete this.transferModHandlers[pointer];
|
||||||
|
}
|
||||||
|
el.remove();
|
||||||
|
});
|
||||||
|
let modalContent = document.getElementById("transfer-mod-form-content");
|
||||||
|
if (modalContent) {
|
||||||
|
for (let player of this.gameState.people) {
|
||||||
|
if (player.out) {
|
||||||
|
let container = document.createElement("div");
|
||||||
|
container.classList.add('potential-moderator');
|
||||||
|
container.dataset.pointer = player.id;
|
||||||
|
container.innerText = player.name;
|
||||||
|
this.transferModHandlers[player.id] = () => {
|
||||||
|
if (confirm("Transfer moderator powers to " + player.name + "?")) {
|
||||||
|
socket.emit(globals.COMMANDS.TRANSFER_MODERATOR, this.gameState.accessCode, player.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
container.addEventListener('click', this.transferModHandlers[player.id]);
|
||||||
|
modalContent.appendChild(container);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderLobbyPerson(name, userType) {
|
function renderLobbyPerson(name, userType) {
|
||||||
@@ -146,7 +204,7 @@ function removeExistingTitle() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderGroupOfPlayers(players, handlers, accessCode=null, alignment=null, moderator=false, socket=null) {
|
function renderGroupOfPlayers(players, killPlayerHandlers, revealRoleHandlers, accessCode=null, alignment=null, moderator=false, socket=null) {
|
||||||
for (let player of players) {
|
for (let player of players) {
|
||||||
let container = document.createElement("div");
|
let container = document.createElement("div");
|
||||||
container.classList.add('game-player');
|
container.classList.add('game-player');
|
||||||
@@ -159,10 +217,14 @@ function renderGroupOfPlayers(players, handlers, accessCode=null, alignment=null
|
|||||||
container.querySelector('.game-player-name').innerText = player.name;
|
container.querySelector('.game-player-name').innerText = player.name;
|
||||||
let roleElement = container.querySelector('.game-player-role')
|
let roleElement = container.querySelector('.game-player-role')
|
||||||
|
|
||||||
if (alignment) {
|
if (moderator) {
|
||||||
roleElement.classList.add(alignment);
|
roleElement.classList.add(alignment);
|
||||||
roleElement.innerText = player.gameRole;
|
roleElement.innerText = player.gameRole;
|
||||||
document.getElementById("player-list-moderator-team-" + alignment).appendChild(container);
|
document.getElementById("player-list-moderator-team-" + alignment).appendChild(container);
|
||||||
|
} else if (player.revealed) {
|
||||||
|
roleElement.classList.add(player.alignment);
|
||||||
|
roleElement.innerText = player.gameRole;
|
||||||
|
document.getElementById("game-player-list").appendChild(container);
|
||||||
} else {
|
} else {
|
||||||
roleElement.innerText = "Unknown"
|
roleElement.innerText = "Unknown"
|
||||||
document.getElementById("game-player-list").appendChild(container);
|
document.getElementById("game-player-list").appendChild(container);
|
||||||
@@ -175,12 +237,27 @@ function renderGroupOfPlayers(players, handlers, accessCode=null, alignment=null
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (moderator) {
|
if (moderator) {
|
||||||
handlers[player.id] = () => {
|
killPlayerHandlers[player.id] = () => {
|
||||||
if (confirm("KILL " + player.name + "?")) {
|
if (confirm("KILL " + player.name + "?")) {
|
||||||
socket.emit(globals.COMMANDS.KILL_PLAYER, accessCode, player.id);
|
socket.emit(globals.COMMANDS.KILL_PLAYER, accessCode, player.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
container.querySelector('.kill-player-button').addEventListener('click', handlers[player.id]);
|
container.querySelector('.kill-player-button').addEventListener('click', killPlayerHandlers[player.id]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (player.revealed) {
|
||||||
|
if (moderator) {
|
||||||
|
container.querySelector('.reveal-role-button')?.remove();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (moderator) {
|
||||||
|
revealRoleHandlers[player.id] = () => {
|
||||||
|
if (confirm("REVEAL " + player.name + "?")) {
|
||||||
|
socket.emit(globals.COMMANDS.REVEAL_PLAYER, accessCode, player.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
container.querySelector('.reveal-role-button').addEventListener('click', revealRoleHandlers[player.id]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -196,19 +273,20 @@ function renderPlayerRole(gameState) {
|
|||||||
}
|
}
|
||||||
name.setAttribute("title", gameState.client.gameRole);
|
name.setAttribute("title", gameState.client.gameRole);
|
||||||
if (gameState.client.out) {
|
if (gameState.client.out) {
|
||||||
document.querySelector('#role-description').innerText = "You have been killed.";
|
document.querySelector('#role-image').classList.add("killed-card");
|
||||||
document.getElementById("role-image").setAttribute(
|
document.getElementById("role-image").setAttribute(
|
||||||
'src',
|
'src',
|
||||||
'../images/tombstone.png'
|
'../images/tombstone.png'
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
document.querySelector('#role-description').innerText = gameState.client.gameRoleDescription;
|
|
||||||
document.getElementById("role-image").setAttribute(
|
document.getElementById("role-image").setAttribute(
|
||||||
'src',
|
'src',
|
||||||
'../images/roles/' + gameState.client.gameRole.replaceAll(' ', '') + '.png'
|
'../images/roles/' + gameState.client.gameRole.replaceAll(' ', '') + '.png'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
document.querySelector('#role-description').innerText = gameState.client.gameRoleDescription;
|
||||||
|
|
||||||
document.getElementById("game-role-back").addEventListener('click', () => {
|
document.getElementById("game-role-back").addEventListener('click', () => {
|
||||||
document.getElementById("game-role").style.display = 'flex';
|
document.getElementById("game-role").style.display = 'flex';
|
||||||
document.getElementById("game-role-back").style.display = 'none';
|
document.getElementById("game-role-back").style.display = 'none';
|
||||||
|
|||||||
@@ -11,21 +11,12 @@ export class GameTimerManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// startGameTimer (hours, minutes, tickRate, soundManager, timerWorker) {
|
|
||||||
// if (window.Worker) {
|
|
||||||
// timerWorker.onmessage = function (e) {
|
|
||||||
// if (e.data.hasOwnProperty('timeRemainingInMilliseconds') && e.data.timeRemainingInMilliseconds > 0) {
|
|
||||||
// document.getElementById('game-timer').innerText = e.data.displayTime;
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
// const totalTime = convertFromHoursToMilliseconds(hours) + convertFromMinutesToMilliseconds(minutes);
|
|
||||||
// timerWorker.postMessage({ totalTime: totalTime, tickInterval: tickRate });
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
resumeGameTimer(totalTime, tickRate, soundManager, timerWorker) {
|
resumeGameTimer(totalTime, tickRate, soundManager, timerWorker) {
|
||||||
if (window.Worker) {
|
if (window.Worker) {
|
||||||
if (this.gameState.client.userType !== globals.USER_TYPES.PLAYER) {
|
if (
|
||||||
|
this.gameState.client.userType === globals.USER_TYPES.MODERATOR
|
||||||
|
|| this.gameState.client.userType === globals.USER_TYPES.TEMPORARY_MODERATOR
|
||||||
|
) {
|
||||||
this.swapToPauseButton();
|
this.swapToPauseButton();
|
||||||
}
|
}
|
||||||
let instance = this;
|
let instance = this;
|
||||||
@@ -49,7 +40,10 @@ export class GameTimerManager {
|
|||||||
|
|
||||||
pauseGameTimer(timerWorker, timeRemaining) {
|
pauseGameTimer(timerWorker, timeRemaining) {
|
||||||
if (window.Worker) {
|
if (window.Worker) {
|
||||||
if (this.gameState.client.userType !== globals.USER_TYPES.PLAYER) {
|
if (
|
||||||
|
this.gameState.client.userType === globals.USER_TYPES.MODERATOR
|
||||||
|
|| this.gameState.client.userType === globals.USER_TYPES.TEMPORARY_MODERATOR
|
||||||
|
) {
|
||||||
this.swapToPlayButton();
|
this.swapToPlayButton();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,7 +57,10 @@ export class GameTimerManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
displayPausedTime(time) {
|
displayPausedTime(time) {
|
||||||
if (this.gameState.client.userType !== globals.USER_TYPES.PLAYER) {
|
if (
|
||||||
|
this.gameState.client.userType === globals.USER_TYPES.MODERATOR
|
||||||
|
|| this.gameState.client.userType === globals.USER_TYPES.TEMPORARY_MODERATOR
|
||||||
|
) {
|
||||||
this.swapToPlayButton();
|
this.swapToPlayButton();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,18 +84,6 @@ export class GameTimerManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
attachTimerSocketListeners(socket, timerWorker, gameStateRenderer) {
|
attachTimerSocketListeners(socket, timerWorker, gameStateRenderer) {
|
||||||
// if (!socket.hasListeners(globals.EVENTS.START_TIMER)) {
|
|
||||||
// socket.on(globals.EVENTS.START_TIMER, () => {
|
|
||||||
// this.startGameTimer(
|
|
||||||
// gameStateRenderer.gameState.timerParams.hours,
|
|
||||||
// gameStateRenderer.gameState.timerParams.minutes,
|
|
||||||
// globals.CLOCK_TICK_INTERVAL_MILLIS,
|
|
||||||
// null,
|
|
||||||
// timerWorker
|
|
||||||
// )
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
if(!socket.hasListeners(globals.COMMANDS.PAUSE_TIMER)) {
|
if(!socket.hasListeners(globals.COMMANDS.PAUSE_TIMER)) {
|
||||||
socket.on(globals.COMMANDS.PAUSE_TIMER, (timeRemaining) => {
|
socket.on(globals.COMMANDS.PAUSE_TIMER, (timeRemaining) => {
|
||||||
this.pauseGameTimer(timerWorker, timeRemaining)
|
this.pauseGameTimer(timerWorker, timeRemaining)
|
||||||
@@ -152,15 +137,6 @@ export class GameTimerManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function convertFromMinutesToMilliseconds(minutes) {
|
|
||||||
return minutes * 60 * 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
function convertFromHoursToMilliseconds(hours) {
|
|
||||||
return hours * 60 * 60 * 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
function returnHumanReadableTime(milliseconds, tenthsOfSeconds=false) {
|
function returnHumanReadableTime(milliseconds, tenthsOfSeconds=false) {
|
||||||
|
|
||||||
let tenths = Math.floor((milliseconds / 100) % 10);
|
let tenths = Math.floor((milliseconds / 100) % 10);
|
||||||
|
|||||||
@@ -46,6 +46,15 @@ export const templates = {
|
|||||||
"<div id='game-player-list'></div>" +
|
"<div id='game-player-list'></div>" +
|
||||||
"</div>",
|
"</div>",
|
||||||
MODERATOR_GAME_VIEW:
|
MODERATOR_GAME_VIEW:
|
||||||
|
"<div id='transfer-mod-modal-background' class='modal-background' style='display: none'></div>" +
|
||||||
|
"<div id='transfer-mod-modal' class='modal' style='display: none'>" +
|
||||||
|
"<form id='transfer-mod-form'>" +
|
||||||
|
"<div id='transfer-mod-form-content'></div>" +
|
||||||
|
"<div id='modal-button-container'>" +
|
||||||
|
"<button id='close-modal-button'>Cancel</button>" +
|
||||||
|
"</div>" +
|
||||||
|
"</form>" +
|
||||||
|
"</div>" +
|
||||||
"<div id='game-header'>" +
|
"<div id='game-header'>" +
|
||||||
"<div class='timer-container-moderator'>" +
|
"<div class='timer-container-moderator'>" +
|
||||||
"<div>" +
|
"<div>" +
|
||||||
@@ -54,7 +63,7 @@ export const templates = {
|
|||||||
"</div>" +
|
"</div>" +
|
||||||
"<div id='play-pause'>" + "</div>" +
|
"<div id='play-pause'>" + "</div>" +
|
||||||
"</div>" +
|
"</div>" +
|
||||||
"<button class='moderator-player-button make-mod-button'>Transfer Mod Powers \uD83D\uDD00</button>" +
|
"<button id='mod-transfer-button' class='moderator-player-button make-mod-button'>Transfer Mod Powers \uD83D\uDD00</button>" +
|
||||||
"</div>" +
|
"</div>" +
|
||||||
"<div>" +
|
"<div>" +
|
||||||
"<label id='players-alive-label'></label>" +
|
"<label id='players-alive-label'></label>" +
|
||||||
|
|||||||
@@ -74,6 +74,10 @@ function processGameState (gameState, userId, socket, gameStateRenderer) {
|
|||||||
document.getElementById("game-state-container").innerHTML = templates.PLAYER_GAME_VIEW;
|
document.getElementById("game-state-container").innerHTML = templates.PLAYER_GAME_VIEW;
|
||||||
gameStateRenderer.renderPlayerView();
|
gameStateRenderer.renderPlayerView();
|
||||||
break;
|
break;
|
||||||
|
case globals.USER_TYPES.KILLED_PLAYER:
|
||||||
|
document.getElementById("game-state-container").innerHTML = templates.PLAYER_GAME_VIEW;
|
||||||
|
gameStateRenderer.renderPlayerView(true);
|
||||||
|
break;
|
||||||
case globals.USER_TYPES.MODERATOR:
|
case globals.USER_TYPES.MODERATOR:
|
||||||
document.querySelector("#start-game-prompt")?.remove();
|
document.querySelector("#start-game-prompt")?.remove();
|
||||||
document.getElementById("game-state-container").innerHTML = templates.MODERATOR_GAME_VIEW;
|
document.getElementById("game-state-container").innerHTML = templates.MODERATOR_GAME_VIEW;
|
||||||
@@ -142,8 +146,39 @@ function setClientSocketHandlers(gameStateRenderer, socket, timerWorker, gameTim
|
|||||||
toast(killedPerson.name + ' killed.', 'success', true, true, 6);
|
toast(killedPerson.name + ' killed.', 'success', true, true, 6);
|
||||||
gameStateRenderer.renderPlayersWithRoleAndAlignmentInfo()
|
gameStateRenderer.renderPlayersWithRoleAndAlignmentInfo()
|
||||||
} else {
|
} else {
|
||||||
toast(killedPerson.name + ' was killed!', 'warning', false, true, 6);
|
if (killedPerson.id === gameStateRenderer.gameState.client.id) {
|
||||||
gameStateRenderer.renderPlayersWithNoRoleInformation();
|
let clientUserType = document.getElementById("client-user-type");
|
||||||
|
if (clientUserType) {
|
||||||
|
clientUserType.innerText = globals.USER_TYPES.KILLED_PLAYER + ' \uD83D\uDC80'
|
||||||
|
}
|
||||||
|
gameStateRenderer.updatePlayerCardToKilledState();
|
||||||
|
toast('You have been killed!', 'warning', false, true, 6);
|
||||||
|
} else {
|
||||||
|
toast(killedPerson.name + ' was killed!', 'warning', false, true, 6);
|
||||||
|
}
|
||||||
|
gameStateRenderer.renderPlayersWithNoRoleInformationUnlessRevealed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!socket.hasListeners(globals.EVENTS.REVEAL_PLAYER)) {
|
||||||
|
socket.on(globals.EVENTS.REVEAL_PLAYER, (revealData) => {
|
||||||
|
let revealedPerson = gameStateRenderer.gameState.people.find((person) => person.id === revealData.id);
|
||||||
|
if (revealedPerson) {
|
||||||
|
revealedPerson.revealed = true;
|
||||||
|
revealedPerson.gameRole = revealData.gameRole;
|
||||||
|
revealedPerson.alignment = revealData.alignment;
|
||||||
|
if (gameStateRenderer.gameState.client.userType === globals.USER_TYPES.MODERATOR) {
|
||||||
|
toast(revealedPerson.name + ' revealed.', 'success', true, true, 6);
|
||||||
|
gameStateRenderer.renderPlayersWithRoleAndAlignmentInfo()
|
||||||
|
} else {
|
||||||
|
if (revealedPerson.id === gameStateRenderer.gameState.client.id) {
|
||||||
|
toast('Your role has been revealed!', 'warning', false, true, 6);
|
||||||
|
} else {
|
||||||
|
toast(revealedPerson.name + ' was revealed as a ' + revealedPerson.gameRole + '!', 'warning', false, true, 6);
|
||||||
|
}
|
||||||
|
gameStateRenderer.renderPlayersWithNoRoleInformationUnlessRevealed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -41,10 +41,33 @@ h1 {
|
|||||||
margin: 0.5em auto;
|
margin: 0.5em auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
#game-state-container > div {
|
#game-state-container > div:not(#transfer-mod-modal-background):not(#transfer-mod-modal){
|
||||||
margin: 1em;
|
margin: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.potential-moderator {
|
||||||
|
display: flex;
|
||||||
|
color: #d7d7d7;
|
||||||
|
background-color: black;
|
||||||
|
border: 2px solid transparent;
|
||||||
|
align-items: center;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 3px;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin: 0.5em 0;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.potential-moderator:hover {
|
||||||
|
border: 2px solid #d7d7d7;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.potential-moderator:active {
|
||||||
|
border: 2px solid #21ba45;
|
||||||
|
transition: border 0.2s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
#game-link {
|
#game-link {
|
||||||
user-select: none;
|
user-select: none;
|
||||||
-ms-user-select: none;
|
-ms-user-select: none;
|
||||||
@@ -234,7 +257,7 @@ label[for='moderator'] {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
z-index: 1000;
|
z-index: 3;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
font-family: 'signika-negative', sans-serif;
|
font-family: 'signika-negative', sans-serif;
|
||||||
font-weight: 100;
|
font-weight: 100;
|
||||||
@@ -326,7 +349,7 @@ label[for='moderator'] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.game-player {
|
.game-player {
|
||||||
border-left: 2px solid gray;
|
border-left: 3px solid #21ba45;
|
||||||
display: flex;
|
display: flex;
|
||||||
color: #d7d7d7;
|
color: #d7d7d7;
|
||||||
background-color: black;
|
background-color: black;
|
||||||
@@ -380,7 +403,11 @@ label[for='moderator'] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.killed, .killed .game-player-role {
|
.killed, .killed .game-player-role {
|
||||||
color: gray !important;
|
/*color: gray !important;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
.game-player.killed {
|
||||||
|
border-left: 3px solid #444444;
|
||||||
}
|
}
|
||||||
|
|
||||||
.reveal-role-button {
|
.reveal-role-button {
|
||||||
@@ -406,6 +433,10 @@ label[for='moderator'] {
|
|||||||
background-color: #9f4747;
|
background-color: #9f4747;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.killed-card {
|
||||||
|
width: 55% !important;
|
||||||
|
}
|
||||||
|
|
||||||
.game-player > div:nth-child(2) {
|
.game-player > div:nth-child(2) {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
@@ -11,10 +10,10 @@
|
|||||||
background-color: #23282b;
|
background-color: #23282b;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
max-width: 17em;
|
max-width: 19em;
|
||||||
max-height: 24em;
|
max-height: 80%;
|
||||||
|
height: fit-content;
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
font-size: 22px;
|
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
padding: 1em;
|
padding: 1em;
|
||||||
}
|
}
|
||||||
@@ -25,7 +24,7 @@
|
|||||||
left: 0;
|
left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: calc(100% + 100px);
|
height: calc(100% + 100px);
|
||||||
background-color: rgba(0, 0, 0, 0.55);
|
background-color: rgba(0, 0, 0, 0.75);
|
||||||
z-index: 50;
|
z-index: 50;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ const globals = {
|
|||||||
PAUSE_TIMER: 'pauseTimer',
|
PAUSE_TIMER: 'pauseTimer',
|
||||||
RESUME_TIMER: 'resumeTimer',
|
RESUME_TIMER: 'resumeTimer',
|
||||||
GET_TIME_REMAINING: 'getTimeRemaining',
|
GET_TIME_REMAINING: 'getTimeRemaining',
|
||||||
KILL_PLAYER: 'killPlayer'
|
KILL_PLAYER: 'killPlayer',
|
||||||
|
REVEAL_PLAYER: 'revealPlayer'
|
||||||
},
|
},
|
||||||
STATUS: {
|
STATUS: {
|
||||||
LOBBY: "lobby",
|
LOBBY: "lobby",
|
||||||
@@ -20,7 +21,9 @@ const globals = {
|
|||||||
USER_TYPES: {
|
USER_TYPES: {
|
||||||
MODERATOR: "moderator",
|
MODERATOR: "moderator",
|
||||||
PLAYER: "player",
|
PLAYER: "player",
|
||||||
TEMPORARY_MODERATOR: "player / temp mod"
|
TEMPORARY_MODERATOR: "player / temp mod",
|
||||||
|
KILLED_PLAYER: "killed",
|
||||||
|
SPECTATOR: "spectator"
|
||||||
},
|
},
|
||||||
ERROR_MESSAGE: {
|
ERROR_MESSAGE: {
|
||||||
GAME_IS_FULL: "This game is full"
|
GAME_IS_FULL: "This game is full"
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ class Person {
|
|||||||
this.alignment = alignment;
|
this.alignment = alignment;
|
||||||
this.assigned = assigned;
|
this.assigned = assigned;
|
||||||
this.out = false;
|
this.out = false;
|
||||||
|
this.revealed = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -102,10 +102,29 @@ class GameManager {
|
|||||||
let person = game.people.find((person) => person.id === personId)
|
let person = game.people.find((person) => person.id === personId)
|
||||||
if (person && !person.out) {
|
if (person && !person.out) {
|
||||||
this.logger.debug('game ' + accessCode + ': killing player ' + person.name);
|
this.logger.debug('game ' + accessCode + ': killing player ' + person.name);
|
||||||
|
person.userType = globals.USER_TYPES.KILLED_PLAYER;
|
||||||
person.out = true;
|
person.out = true;
|
||||||
namespace.in(accessCode).emit(globals.CLIENT_COMMANDS.KILL_PLAYER, person.id)
|
namespace.in(accessCode).emit(globals.CLIENT_COMMANDS.KILL_PLAYER, person.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on(globals.CLIENT_COMMANDS.REVEAL_PLAYER, (accessCode, personId) => {
|
||||||
|
let game = this.activeGameRunner.activeGames[accessCode];
|
||||||
|
if (game) {
|
||||||
|
let person = game.people.find((person) => person.id === personId)
|
||||||
|
if (person && !person.revealed) {
|
||||||
|
this.logger.debug('game ' + accessCode + ': revealing player ' + person.name);
|
||||||
|
person.revealed = true;
|
||||||
|
namespace.in(accessCode).emit(
|
||||||
|
globals.CLIENT_COMMANDS.REVEAL_PLAYER,
|
||||||
|
{
|
||||||
|
id: person.id,
|
||||||
|
gameRole: person.gameRole,
|
||||||
|
alignment: person.alignment
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
const globals = require("../config/globals")
|
const globals = require("../config/globals")
|
||||||
|
|
||||||
|
/* The purpose of this component is to only return the game state information that is necessary. For example, we only want to return player role information
|
||||||
|
to moderators. This avoids any possibility of a player having access to information that they shouldn't.
|
||||||
|
*/
|
||||||
const GameStateCurator = {
|
const GameStateCurator = {
|
||||||
getGameStateFromPerspectiveOfPerson: (game, person, gameRunner, socket, logger) => {
|
getGameStateFromPerspectiveOfPerson: (game, person, gameRunner, socket, logger) => {
|
||||||
return getGameStateBasedOnPermissions(game, person, gameRunner);
|
return getGameStateBasedOnPermissions(game, person, gameRunner);
|
||||||
@@ -21,6 +24,7 @@ function getGameStateBasedOnPermissions(game, person, gameRunner) {
|
|||||||
}
|
}
|
||||||
switch (person.userType) {
|
switch (person.userType) {
|
||||||
case globals.USER_TYPES.PLAYER:
|
case globals.USER_TYPES.PLAYER:
|
||||||
|
case globals.USER_TYPES.KILLED_PLAYER:
|
||||||
return {
|
return {
|
||||||
accessCode: game.accessCode,
|
accessCode: game.accessCode,
|
||||||
status: game.status,
|
status: game.status,
|
||||||
@@ -32,7 +36,7 @@ function getGameStateBasedOnPermissions(game, person, gameRunner) {
|
|||||||
return person.assigned === true
|
return person.assigned === true
|
||||||
&& (person.userType !== globals.USER_TYPES.MODERATOR && person.userType !== globals.USER_TYPES.TEMPORARY_MODERATOR)
|
&& (person.userType !== globals.USER_TYPES.MODERATOR && person.userType !== globals.USER_TYPES.TEMPORARY_MODERATOR)
|
||||||
})
|
})
|
||||||
.map((filteredPerson) => ({ name: filteredPerson.name, id: filteredPerson.id, userType: filteredPerson.userType, out: filteredPerson.out })),
|
.map((filteredPerson) => mapPerson(filteredPerson)),
|
||||||
timerParams: game.timerParams,
|
timerParams: game.timerParams,
|
||||||
isFull: game.isFull,
|
isFull: game.isFull,
|
||||||
}
|
}
|
||||||
@@ -75,7 +79,8 @@ function mapPeopleForModerator(people, client) {
|
|||||||
gameRole: person.gameRole,
|
gameRole: person.gameRole,
|
||||||
gameRoleDescription: person.gameRoleDescription,
|
gameRoleDescription: person.gameRoleDescription,
|
||||||
alignment: person.alignment,
|
alignment: person.alignment,
|
||||||
out: person.out
|
out: person.out,
|
||||||
|
revealed: person.revealed
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,12 +93,25 @@ function mapPeopleForTempModerator(people, client) {
|
|||||||
name: person.name,
|
name: person.name,
|
||||||
id: person.id,
|
id: person.id,
|
||||||
userType: person.userType,
|
userType: person.userType,
|
||||||
out: person.out
|
out: person.out,
|
||||||
|
revealed: person.revealed
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
function mapPerson(person) {
|
function mapPerson(person) {
|
||||||
return { name: person.name, id: person.id, userType: person.userType, out: person.out };
|
if (person.revealed) {
|
||||||
|
return {
|
||||||
|
name: person.name,
|
||||||
|
id: person.id,
|
||||||
|
userType: person.userType,
|
||||||
|
out: person.out,
|
||||||
|
revealed: person.revealed,
|
||||||
|
gameRole: person.gameRole,
|
||||||
|
alignment: person.alignment
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return { name: person.name, id: person.id, userType: person.userType, out: person.out, revealed: person.revealed };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = GameStateCurator;
|
module.exports = GameStateCurator;
|
||||||
|
|||||||
Reference in New Issue
Block a user