mirror of
https://github.com/AlecM33/Werewolf.git
synced 2025-12-26 15:57:50 +01:00
swapping moderator
This commit is contained in:
@@ -45,6 +45,7 @@ export const globals = {
|
||||
USER_TYPE_ICONS: {
|
||||
player: ' \uD83C\uDFAE',
|
||||
moderator: ' \uD83D\uDC51',
|
||||
'player / temp mod': ' \uD83C\uDFAE\uD83D\uDC51'
|
||||
'player / temp mod': ' \uD83C\uDFAE\uD83D\uDC51',
|
||||
spectator: ' \uD83D\uDC7B'
|
||||
}
|
||||
};
|
||||
|
||||
@@ -68,7 +68,7 @@ export class GameStateRenderer {
|
||||
let modTransferButton = document.getElementById("mod-transfer-button");
|
||||
modTransferButton.addEventListener(
|
||||
"click", () => {
|
||||
this.displayAvailableModerators()
|
||||
this.displayAvailableModerators();
|
||||
ModalManager.displayModal(
|
||||
"transfer-mod-modal",
|
||||
"transfer-mod-modal-background",
|
||||
@@ -79,6 +79,15 @@ export class GameStateRenderer {
|
||||
this.renderPlayersWithRoleAndAlignmentInfo();
|
||||
}
|
||||
|
||||
renderTempModView() {
|
||||
let div = document.createElement("div");
|
||||
div.innerHTML = templates.END_GAME_PROMPT;
|
||||
document.body.appendChild(div);
|
||||
|
||||
renderPlayerRole(this.gameState);
|
||||
this.renderPlayersWithNoRoleInformationUnlessRevealed(true);
|
||||
}
|
||||
|
||||
renderPlayerView(isKilled=false) {
|
||||
if (isKilled) {
|
||||
let clientUserType = document.getElementById("client-user-type");
|
||||
@@ -87,6 +96,10 @@ export class GameStateRenderer {
|
||||
}
|
||||
}
|
||||
renderPlayerRole(this.gameState);
|
||||
this.renderPlayersWithNoRoleInformationUnlessRevealed(false);
|
||||
}
|
||||
|
||||
renderSpectatorView() {
|
||||
this.renderPlayersWithNoRoleInformationUnlessRevealed();
|
||||
}
|
||||
|
||||
@@ -123,12 +136,26 @@ export class GameStateRenderer {
|
||||
|
||||
}
|
||||
|
||||
renderPlayersWithNoRoleInformationUnlessRevealed() {
|
||||
renderPlayersWithNoRoleInformationUnlessRevealed(tempMod = false) {
|
||||
if (tempMod) {
|
||||
document.querySelectorAll('.game-player').forEach((el) => {
|
||||
let pointer = el.dataset.pointer;
|
||||
if (pointer && 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();
|
||||
});
|
||||
}
|
||||
document.querySelectorAll('.game-player').forEach((el) => el.remove());
|
||||
this.gameState.people.sort((a, b) => {
|
||||
return a.name >= b.name ? 1 : -1;
|
||||
});
|
||||
renderGroupOfPlayers(this.gameState.people, this.killPlayerHandlers);
|
||||
renderGroupOfPlayers(this.gameState, this.killPlayerHandlers, this.revealRoleHandlers, this.gameState.accessCode, null, tempMod, this.socket);
|
||||
document.getElementById("players-alive-label").innerText =
|
||||
'Players: ' + this.gameState.people.filter((person) => !person.out).length + ' / ' + this.gameState.people.length + ' Alive';
|
||||
|
||||
@@ -153,27 +180,32 @@ export class GameStateRenderer {
|
||||
});
|
||||
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);
|
||||
}
|
||||
}
|
||||
renderPotentialMods(this.gameState, this.gameState.people, this.transferModHandlers, modalContent, this.socket);
|
||||
renderPotentialMods(this.gameState, this.gameState.spectators, this.transferModHandlers, modalContent, this.socket);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function renderPotentialMods(gameState, group, transferModHandlers, modalContent, socket) {
|
||||
for (let member of group) {
|
||||
if ((member.out || member.userType === globals.USER_TYPES.SPECTATOR) && !(member.id === gameState.client.id)) {
|
||||
let container = document.createElement("div");
|
||||
container.classList.add('potential-moderator');
|
||||
container.dataset.pointer = member.id;
|
||||
container.innerText = member.name;
|
||||
transferModHandlers[member.id] = () => {
|
||||
if (confirm("Transfer moderator powers to " + member.name + "?")) {
|
||||
socket.emit(globals.COMMANDS.TRANSFER_MODERATOR, gameState.accessCode, member.id);
|
||||
}
|
||||
}
|
||||
|
||||
container.addEventListener('click', transferModHandlers[member.id]);
|
||||
modalContent.appendChild(container);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function renderLobbyPerson(name, userType) {
|
||||
let el = document.createElement("div");
|
||||
let personNameEl = document.createElement("div");
|
||||
@@ -204,12 +236,13 @@ function removeExistingTitle() {
|
||||
}
|
||||
}
|
||||
|
||||
function renderGroupOfPlayers(players, killPlayerHandlers, revealRoleHandlers, accessCode=null, alignment=null, moderator=false, socket=null) {
|
||||
for (let player of players) {
|
||||
// TODO: refactor to reduce the cyclomatic complexity of this function
|
||||
function renderGroupOfPlayers(gameState, killPlayerHandlers, revealRoleHandlers, accessCode=null, alignment=null, moderator=false, socket=null) {
|
||||
for (let player of gameState.people) {
|
||||
let container = document.createElement("div");
|
||||
container.classList.add('game-player');
|
||||
container.dataset.pointer = player.id;
|
||||
if (alignment) {
|
||||
if (moderator) {
|
||||
container.dataset.pointer = player.id;
|
||||
container.innerHTML = templates.MODERATOR_PLAYER;
|
||||
} else {
|
||||
container.innerHTML = templates.GAME_PLAYER;
|
||||
@@ -219,14 +252,24 @@ function renderGroupOfPlayers(players, killPlayerHandlers, revealRoleHandlers, a
|
||||
|
||||
if (moderator) {
|
||||
roleElement.classList.add(alignment);
|
||||
roleElement.innerText = player.gameRole;
|
||||
document.getElementById("player-list-moderator-team-" + alignment).appendChild(container);
|
||||
if (gameState.moderator.userType === globals.USER_TYPES.MODERATOR) {
|
||||
roleElement.innerText = player.gameRole;
|
||||
document.getElementById("player-list-moderator-team-" + alignment).appendChild(container);
|
||||
} else {
|
||||
if (player.revealed) {
|
||||
roleElement.innerText = player.gameRole;
|
||||
roleElement.classList.add(player.alignment);
|
||||
} else {
|
||||
roleElement.innerText = "Unknown";
|
||||
}
|
||||
document.getElementById("game-player-list").appendChild(container);
|
||||
}
|
||||
} else if (player.revealed) {
|
||||
roleElement.classList.add(player.alignment);
|
||||
roleElement.innerText = player.gameRole;
|
||||
document.getElementById("game-player-list").appendChild(container);
|
||||
} else {
|
||||
roleElement.innerText = "Unknown"
|
||||
roleElement.innerText = "Unknown";
|
||||
document.getElementById("game-player-list").appendChild(container);
|
||||
}
|
||||
|
||||
|
||||
@@ -45,11 +45,24 @@ export const templates = {
|
||||
"<label id='players-alive-label'></label>" +
|
||||
"<div id='game-player-list'></div>" +
|
||||
"</div>",
|
||||
SPECTATOR_GAME_VIEW:
|
||||
"<div id='game-header'>" +
|
||||
"<div>" +
|
||||
"<label for='game-timer'>Time Remaining</label>" +
|
||||
"<div id='game-timer'></div>" +
|
||||
"</div>" +
|
||||
"</div>" +
|
||||
"<div>" +
|
||||
"<label id='players-alive-label'></label>" +
|
||||
"<div id='game-player-list'></div>" +
|
||||
"</div>",
|
||||
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='transfer-mod-form-content'>" +
|
||||
"<h3>Transfer Mod Powers 👑</h3>" +
|
||||
"</div>" +
|
||||
"<div id='modal-button-container'>" +
|
||||
"<button id='close-modal-button'>Cancel</button>" +
|
||||
"</div>" +
|
||||
@@ -78,6 +91,41 @@ export const templates = {
|
||||
"</div>" +
|
||||
"</div>" +
|
||||
"</div>",
|
||||
TEMP_MOD_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'>" +
|
||||
"<h3>Transfer Mod Powers 👑</h3>" +
|
||||
"</div>" +
|
||||
"<div id='modal-button-container'>" +
|
||||
"<button id='close-modal-button'>Cancel</button>" +
|
||||
"</div>" +
|
||||
"</form>" +
|
||||
"</div>" +
|
||||
"<div id='game-header'>" +
|
||||
"<div class='timer-container-moderator'>" +
|
||||
"<div>" +
|
||||
"<label for='game-timer'>Time Remaining</label>" +
|
||||
"<div id='game-timer'></div>" +
|
||||
"</div>" +
|
||||
"<div id='play-pause'>" + "</div>" +
|
||||
"</div>" +
|
||||
"</div>" +
|
||||
"<div id='game-role' style='display:none'>" +
|
||||
"<h4 id='role-name'></h4>" +
|
||||
"<img alt='role' id='role-image'/>" +
|
||||
"<p id='role-description'></p>" +
|
||||
"</div>" +
|
||||
"<div id='game-role-back'>" +
|
||||
"<h4>Click to reveal your role</h4>" +
|
||||
"<p>(click again to hide)</p>" +
|
||||
"</div>" +
|
||||
"<div>" +
|
||||
"<label id='players-alive-label'></label>" +
|
||||
"<div id='game-player-list'></div>" +
|
||||
"</div>" +
|
||||
"</div>",
|
||||
MODERATOR_PLAYER:
|
||||
"<div>" +
|
||||
"<div class='game-player-name'></div>" +
|
||||
|
||||
@@ -41,7 +41,6 @@ function prepareGamePage(environment, socket, timerWorker) {
|
||||
gameTimerManager = new GameTimerManager(gameState, socket);
|
||||
}
|
||||
setClientSocketHandlers(gameStateRenderer, socket, timerWorker, gameTimerManager);
|
||||
displayClientInfo(gameState.client.name, gameState.client.userType);
|
||||
processGameState(gameState, userId, socket, gameStateRenderer);
|
||||
}
|
||||
});
|
||||
@@ -51,6 +50,7 @@ function prepareGamePage(environment, socket, timerWorker) {
|
||||
}
|
||||
|
||||
function processGameState (gameState, userId, socket, gameStateRenderer) {
|
||||
displayClientInfo(gameState.client.name, gameState.client.userType);
|
||||
switch (gameState.status) {
|
||||
case globals.STATUS.LOBBY:
|
||||
document.getElementById("game-state-container").innerHTML = templates.LOBBY;
|
||||
@@ -67,7 +67,6 @@ function processGameState (gameState, userId, socket, gameStateRenderer) {
|
||||
}
|
||||
break;
|
||||
case globals.STATUS.IN_PROGRESS:
|
||||
gameStateRenderer.gameState = gameState;
|
||||
gameStateRenderer.renderGameHeader();
|
||||
switch (gameState.client.userType) {
|
||||
case globals.USER_TYPES.PLAYER:
|
||||
@@ -75,6 +74,7 @@ function processGameState (gameState, userId, socket, gameStateRenderer) {
|
||||
gameStateRenderer.renderPlayerView();
|
||||
break;
|
||||
case globals.USER_TYPES.KILLED_PLAYER:
|
||||
document.querySelector("#end-game-prompt")?.remove();
|
||||
document.getElementById("game-state-container").innerHTML = templates.PLAYER_GAME_VIEW;
|
||||
gameStateRenderer.renderPlayerView(true);
|
||||
break;
|
||||
@@ -85,6 +85,13 @@ function processGameState (gameState, userId, socket, gameStateRenderer) {
|
||||
break;
|
||||
case globals.USER_TYPES.TEMPORARY_MODERATOR:
|
||||
document.querySelector("#start-game-prompt")?.remove();
|
||||
document.getElementById("game-state-container").innerHTML = templates.TEMP_MOD_GAME_VIEW;
|
||||
gameStateRenderer.renderTempModView();
|
||||
break;
|
||||
case globals.USER_TYPES.SPECTATOR:
|
||||
document.querySelector("#end-game-prompt")?.remove();
|
||||
document.getElementById("game-state-container").innerHTML = templates.SPECTATOR_GAME_VIEW;
|
||||
gameStateRenderer.renderSpectatorView();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -127,6 +134,8 @@ function setClientSocketHandlers(gameStateRenderer, socket, timerWorker, gameTim
|
||||
gameStateRenderer.gameState.accessCode,
|
||||
gameStateRenderer.gameState.client.cookie,
|
||||
function (gameState) {
|
||||
gameStateRenderer.gameState = gameState;
|
||||
gameTimerManager.gameState = gameState;
|
||||
processGameState(gameState, gameState.client.cookie, socket, gameStateRenderer);
|
||||
}
|
||||
);
|
||||
@@ -156,7 +165,11 @@ function setClientSocketHandlers(gameStateRenderer, socket, timerWorker, gameTim
|
||||
} else {
|
||||
toast(killedPerson.name + ' was killed!', 'warning', false, true, 6);
|
||||
}
|
||||
gameStateRenderer.renderPlayersWithNoRoleInformationUnlessRevealed();
|
||||
if (gameStateRenderer.gameState.client.userType === globals.USER_TYPES.TEMPORARY_MODERATOR) {
|
||||
gameStateRenderer.renderPlayersWithNoRoleInformationUnlessRevealed(true);
|
||||
} else {
|
||||
gameStateRenderer.renderPlayersWithNoRoleInformationUnlessRevealed(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -178,7 +191,11 @@ function setClientSocketHandlers(gameStateRenderer, socket, timerWorker, gameTim
|
||||
} else {
|
||||
toast(revealedPerson.name + ' was revealed as a ' + revealedPerson.gameRole + '!', 'warning', false, true, 6);
|
||||
}
|
||||
gameStateRenderer.renderPlayersWithNoRoleInformationUnlessRevealed();
|
||||
if (gameStateRenderer.gameState.client.userType === globals.USER_TYPES.TEMPORARY_MODERATOR) {
|
||||
gameStateRenderer.renderPlayersWithNoRoleInformationUnlessRevealed(true);
|
||||
} else {
|
||||
gameStateRenderer.renderPlayersWithNoRoleInformationUnlessRevealed(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -96,7 +96,6 @@ button:active, input[type=submit]:active {
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
width: 95%;
|
||||
max-width: 68em;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
|
||||
@@ -454,6 +454,14 @@ label[for='moderator'] {
|
||||
font-size: 25px;
|
||||
}
|
||||
|
||||
#transfer-mod-form {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#transfer-mod-form #modal-button-container {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
@media(max-width: 685px) {
|
||||
#end-game-button {
|
||||
font-size: 25px;
|
||||
|
||||
@@ -10,7 +10,8 @@ const globals = {
|
||||
RESUME_TIMER: 'resumeTimer',
|
||||
GET_TIME_REMAINING: 'getTimeRemaining',
|
||||
KILL_PLAYER: 'killPlayer',
|
||||
REVEAL_PLAYER: 'revealPlayer'
|
||||
REVEAL_PLAYER: 'revealPlayer',
|
||||
TRANSFER_MODERATOR: 'transferModerator'
|
||||
},
|
||||
STATUS: {
|
||||
LOBBY: "lobby",
|
||||
|
||||
@@ -9,6 +9,7 @@ class Game {
|
||||
this.timerParams = timerParams;
|
||||
this.isFull = false;
|
||||
this.timeRemaining = null;
|
||||
this.spectators = [];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -125,6 +125,33 @@ class GameManager {
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
socket.on(globals.CLIENT_COMMANDS.TRANSFER_MODERATOR, (accessCode, personId) => {
|
||||
let game = this.activeGameRunner.activeGames[accessCode];
|
||||
if (game) {
|
||||
let person = game.people.find((person) => person.id === personId)
|
||||
if (!person) {
|
||||
person = game.spectators.find((spectator) => spectator.id === personId)
|
||||
}
|
||||
if (person && (person.out || person.userType === globals.USER_TYPES.SPECTATOR)) {
|
||||
this.logger.debug('game ' + accessCode + ': transferring mod powers to ' + person.name);
|
||||
if (game.people.includes(game.moderator)) { // the current moderator was at one point a dealt-in player.
|
||||
game.moderator.userType = globals.USER_TYPES.KILLED_PLAYER; // restore their state from before being made mod.
|
||||
} else {
|
||||
game.moderator.userType = globals.USER_TYPES.SPECTATOR;
|
||||
if (!game.spectators.includes(game.moderator)) {
|
||||
game.spectators.push(game.moderator);
|
||||
}
|
||||
if (game.spectators.includes(person)) {
|
||||
game.spectators.splice(game.spectators.indexOf(person), 1);
|
||||
}
|
||||
}
|
||||
person.userType = globals.USER_TYPES.MODERATOR;
|
||||
game.moderator = person;
|
||||
namespace.in(accessCode).emit(globals.EVENTS.SYNC_GAME_STATE);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -265,7 +292,10 @@ function handleRequestForGameState(namespace, logger, gameRunner, accessCode, pe
|
||||
const game = gameRunner.activeGames[accessCode];
|
||||
if (game) {
|
||||
let matchingPerson = game.people.find((person) => person.cookie === personCookie);
|
||||
if (!matchingPerson && game.moderator.cookie === personCookie) {
|
||||
if (!matchingPerson) {
|
||||
matchingPerson = game.spectators.find((spectator) => spectator.cookie = personCookie);
|
||||
}
|
||||
if (game.moderator.cookie === personCookie) {
|
||||
matchingPerson = game.moderator;
|
||||
}
|
||||
if (matchingPerson) {
|
||||
|
||||
@@ -34,7 +34,6 @@ function getGameStateBasedOnPermissions(game, person, gameRunner) {
|
||||
people: game.people
|
||||
.filter((person) => {
|
||||
return person.assigned === true
|
||||
&& (person.userType !== globals.USER_TYPES.MODERATOR && person.userType !== globals.USER_TYPES.TEMPORARY_MODERATOR)
|
||||
})
|
||||
.map((filteredPerson) => mapPerson(filteredPerson)),
|
||||
timerParams: game.timerParams,
|
||||
@@ -49,7 +48,8 @@ function getGameStateBasedOnPermissions(game, person, gameRunner) {
|
||||
deck: game.deck,
|
||||
people: mapPeopleForModerator(game.people, client),
|
||||
timerParams: game.timerParams,
|
||||
isFull: game.isFull
|
||||
isFull: game.isFull,
|
||||
spectators: game.spectators
|
||||
}
|
||||
case globals.USER_TYPES.TEMPORARY_MODERATOR:
|
||||
return {
|
||||
@@ -58,19 +58,38 @@ function getGameStateBasedOnPermissions(game, person, gameRunner) {
|
||||
moderator: mapPerson(game.moderator),
|
||||
client: client,
|
||||
deck: game.deck,
|
||||
people: mapPeopleForTempModerator(game.people, client),
|
||||
people: game.people
|
||||
.filter((person) => {
|
||||
return person.assigned === true
|
||||
})
|
||||
.map((filteredPerson) => mapPerson(filteredPerson)),
|
||||
timerParams: game.timerParams,
|
||||
isFull: game.isFull
|
||||
}
|
||||
case globals.USER_TYPES.SPECTATOR:
|
||||
return {
|
||||
accessCode: game.accessCode,
|
||||
status: game.status,
|
||||
moderator: mapPerson(game.moderator),
|
||||
client: client,
|
||||
deck: game.deck,
|
||||
people: game.people
|
||||
.filter((person) => {
|
||||
return person.assigned === true
|
||||
})
|
||||
.map((filteredPerson) => mapPerson(filteredPerson)),
|
||||
timerParams: game.timerParams,
|
||||
isFull: game.isFull,
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function mapPeopleForModerator(people, client) {
|
||||
function mapPeopleForModerator(people) {
|
||||
return people
|
||||
.filter((person) => {
|
||||
return person.assigned === true && person.cookie !== client.cookie
|
||||
return person.assigned === true
|
||||
})
|
||||
.map((person) => ({
|
||||
name: person.name,
|
||||
@@ -84,20 +103,6 @@ function mapPeopleForModerator(people, client) {
|
||||
}));
|
||||
}
|
||||
|
||||
function mapPeopleForTempModerator(people, client) {
|
||||
return people
|
||||
.filter((person) => {
|
||||
return person.assigned === true && person.cookie !== client.cookie
|
||||
})
|
||||
.map((person) => ({
|
||||
name: person.name,
|
||||
id: person.id,
|
||||
userType: person.userType,
|
||||
out: person.out,
|
||||
revealed: person.revealed
|
||||
}));
|
||||
}
|
||||
|
||||
function mapPerson(person) {
|
||||
if (person.revealed) {
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user