@@ -152,8 +155,8 @@ export const HTMLFragments = {
`,
GAME_PLAYER:
`
diff --git a/client/src/scripts/game.js b/client/src/scripts/game.js
index 995b34c..fabd6f9 100644
--- a/client/src/scripts/game.js
+++ b/client/src/scripts/game.js
@@ -99,12 +99,10 @@ function processGameState (
document.getElementById('game-state-container').innerHTML = HTMLFragments.LOBBY;
gameStateRenderer.renderLobbyHeader();
gameStateRenderer.renderLobbyPlayers();
- if (
- currentGameState.isFull
- && (
- currentGameState.client.userType === globals.USER_TYPES.MODERATOR
+ if ((
+ currentGameState.client.userType === globals.USER_TYPES.MODERATOR
|| currentGameState.client.userType === globals.USER_TYPES.TEMPORARY_MODERATOR
- )
+ )
&& refreshPrompt
) {
displayStartGamePromptForModerators(currentGameState, gameStateRenderer);
@@ -172,12 +170,10 @@ function setClientSocketHandlers (stateBucket, gameStateRenderer, socket, timerW
stateBucket.currentGameState.people.push(player);
stateBucket.currentGameState.isFull = gameIsFull;
gameStateRenderer.renderLobbyPlayers();
- if (
- gameIsFull
- && (
- stateBucket.currentGameState.client.userType === globals.USER_TYPES.MODERATOR
+ if ((
+ stateBucket.currentGameState.client.userType === globals.USER_TYPES.MODERATOR
|| stateBucket.currentGameState.client.userType === globals.USER_TYPES.TEMPORARY_MODERATOR
- )
+ )
) {
displayStartGamePromptForModerators(stateBucket.currentGameState, gameStateRenderer);
}
@@ -329,10 +325,27 @@ function setClientSocketHandlers (stateBucket, gameStateRenderer, socket, timerW
}
function displayStartGamePromptForModerators (gameState, gameStateRenderer) {
- const div = document.createElement('div');
- div.innerHTML = HTMLFragments.START_GAME_PROMPT;
- div.querySelector('#start-game-button').addEventListener('click', gameStateRenderer.startGameHandler);
- document.body.appendChild(div);
+ const existingPrompt = document.getElementById('start-game-prompt');
+ if (existingPrompt) {
+ enableOrDisableStartButton(gameState, existingPrompt, gameStateRenderer.startGameHandler);
+ } else {
+ const newPrompt = document.createElement('div');
+ newPrompt.setAttribute('id', 'start-game-prompt');
+ newPrompt.innerHTML = HTMLFragments.START_GAME_PROMPT;
+
+ document.body.appendChild(newPrompt);
+ enableOrDisableStartButton(gameState, newPrompt, gameStateRenderer.startGameHandler);
+ }
+}
+
+function enableOrDisableStartButton (gameState, buttonContainer, handler) {
+ if (gameState.isFull) {
+ buttonContainer.querySelector('#start-game-button').addEventListener('click', handler);
+ buttonContainer.querySelector('#start-game-button').classList.remove('disabled');
+ } else {
+ buttonContainer.querySelector('#start-game-button').removeEventListener('click', handler);
+ buttonContainer.querySelector('#start-game-button').classList.add('disabled');
+ }
}
function removeStartGameFunctionalityIfPresent (gameStateRenderer) {
diff --git a/client/src/styles/GLOBAL.css b/client/src/styles/GLOBAL.css
index 61fedd8..0f7e1db 100644
--- a/client/src/styles/GLOBAL.css
+++ b/client/src/styles/GLOBAL.css
@@ -251,6 +251,12 @@ button {
pointer-events: none;
}
+.disabled {
+ filter: opacity(0.5) grayscale(1);
+ pointer-events: none;
+ animation: none !important;
+}
+
.container {
padding: 5px;
border-radius: 3px;
@@ -340,7 +346,7 @@ input {
align-items: center;
padding: 5px 0;
width: 100%;
- background-color: #333243;
+ background-color: #1e1b26;
height: 45px;
z-index: 53000;
}
diff --git a/client/src/styles/create.css b/client/src/styles/create.css
index 0b3acff..70ca168 100644
--- a/client/src/styles/create.css
+++ b/client/src/styles/create.css
@@ -419,6 +419,7 @@ input[type="number"] {
color: #e7e7e7;
font-size: 30px;
padding: 10px 50px;
+ width: 100px;
}
#create-game:hover {
@@ -538,6 +539,7 @@ input[type="number"] {
margin-top: 1em;
justify-content: center;
width: 100%;
+ height: 50px;
}
#upload-custom-roles-modal input[type='file'] {
@@ -651,6 +653,10 @@ input[type="number"] {
font-size: 16px;
}
+ #create-game {
+ width: 80px;
+ }
+
.role-name {
font-size: 13px;
font-weight: bold;
diff --git a/client/src/styles/game.css b/client/src/styles/game.css
index dbbe2d9..4bcdd20 100644
--- a/client/src/styles/game.css
+++ b/client/src/styles/game.css
@@ -17,7 +17,7 @@
#lobby-players {
overflow-y: auto;
- max-height: 44em;
+ max-height: 30em;
overflow-x: hidden;
padding: 0 10px;
border-radius: 3px;
@@ -46,7 +46,7 @@
flex-wrap: wrap;
display: flex;
width: 95%;
- margin: 1em auto 100px auto;
+ margin: 1em auto 140px auto;
animation: fade-in-slide-up 2s;
}
@@ -83,6 +83,13 @@
width: 100%;
}
+#lobby-header > div:nth-child(2) {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ flex-wrap: wrap;
+}
+
h1 {
text-align: center;
margin: 0.5em auto;
@@ -434,27 +441,38 @@ label[for='moderator'] {
}
#start-game-prompt, #end-game-prompt {
+ padding: 0.5em 0;
display: flex;
+ flex-direction: column;
align-items: center;
- justify-content: center;
+ justify-content: space-evenly;
position: fixed;
z-index: 3;
- border-radius: 3px;
font-family: 'signika-negative', sans-serif;
font-weight: 100;
- box-shadow: 0 -2px 6px 0 rgb(0 0 0 / 45%);
+ box-shadow: 0 -6px 15px rgba(0, 0, 0, 0.5);
left: 0;
right: 0;
bottom: 0;
+ border-radius: 3px;
/* width: fit-content; */
font-size: 20px;
- height: 85px;
+ height: 100px;
margin: 0 auto;
- animation: fade-in-slide-up 10s ease;
- animation-fill-mode: forwards;
- animation-direction: normal;
- width: 100%;
- background-color: #333243;
+ max-width: 100%;
+ background-color: #1b1a24;
+}
+
+#start-game-prompt p {
+ color: whitesmoke;
+ font-size: 15px;
+}
+
+#start-game-prompt > div {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: space-evenly;
}
#end-game-prompt {
@@ -471,10 +489,15 @@ label[for='moderator'] {
transition: background-color, border 0.3s ease-out;
text-shadow: 0 3px 4px rgb(0 0 0 / 85%);
font-size: 25px;
+ user-select: none;
+ -ms-user-select: none;
+ -webkit-user-select: none;
+ -moz-user-select: none;
}
#start-game-button {
background-color: #1c8a36;
+ margin-bottom: 10px;
animation: shadow-pulse 1.5s infinite ease-out;
}
@@ -563,6 +586,7 @@ canvas {
margin: 0.5em 0;
position: relative;
box-shadow: 2px 3px 6px rgb(0 0 0 / 50%);
+ border-radius: 3px;
}
.game-player-name {
@@ -576,33 +600,44 @@ canvas {
}
.kill-player-button, .reveal-role-button {
+ background-color: #333243;
font-family: 'signika-negative', sans-serif !important;
border-radius: 3px;
color: #e7e7e7;
+ height: 25px;
font-size: 16px;
cursor: pointer;
border: 2px solid transparent;
- transition: background-color, border 0.3s ease-out;
+ transition: background-color, border 0.2s ease-out;
text-shadow: 0 3px 4px rgb(0 0 0 / 55%);
margin: 5px 0 5px 25px;
- width: 117px;
+ width: 65px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
+.kill-player-button:hover, .reveal-role-button:hover {
+ border: 2px solid #b1afcd;
+}
+
+#game-players-container {
+ width: 27em;
+ max-width: 100%;
+}
+
.placeholder-button {
font-family: 'signika-negative', sans-serif !important;
display: flex;
justify-content: center;
+ align-items: center;
border-radius: 3px;
color: #767676;
font-weight: bold;
font-size: 16px;
- border: 2px solid transparent;
text-shadow: 0 3px 4px rgb(0 0 0 / 55%);
- margin: 5px 0 5px 35px;
- width: 103px;
+ margin: 5px 0 5px 25px;
+ width: 65px;
}
#game-link:hover {
@@ -610,21 +645,12 @@ canvas {
border: 2px solid #d7d7d7;
}
-.reveal-role-button {
- background-color: #586a6e;
-}
-
-.reveal-role-button:hover {
- background-color: #4e5664;
-}
-
-.kill-player-button:hover {
- background-color: #b35c5c;
-}
+/*.reveal-role-button {*/
+/* background-color: #586a6e;*/
+/*}*/
.reveal-role-button img {
width: 18px;
- margin-left: 5px;
}
#game-player-list > .game-player.killed::after {
@@ -660,9 +686,9 @@ canvas {
cursor: pointer;
}
-.kill-player-button {
- background-color: #9f4747;
-}
+/*.kill-player-button {*/
+/* background-color: #9f4747;*/
+/*}*/
.killed-card {
width: 55% !important;
@@ -720,7 +746,7 @@ canvas {
#lobby-people-container , #game-people-container {
background-color: #333243;
- padding: 10px 10px 0 10px;
+ padding: 10px;
border-radius: 3px;
min-height: 25em;
max-width: 35em;
@@ -738,6 +764,14 @@ canvas {
align-items: center;
}
+@media(max-width: 800px) {
+ #start-game-prompt, #end-game-prompt {
+ border-radius: 0;
+ width: 100%;
+ bottom: 0;
+ }
+}
+
@media(max-width: 500px) {
label {
font-size: 18px;
@@ -752,7 +786,7 @@ canvas {
}
#game-state-container {
- margin: 0 auto 85px auto;
+ margin: 0 auto 105px auto;
}
button {
diff --git a/server/api/GamesAPI.js b/server/api/GamesAPI.js
index 4fa21bf..0ca2764 100644
--- a/server/api/GamesAPI.js
+++ b/server/api/GamesAPI.js
@@ -50,7 +50,7 @@ router.post('/create', function (req, res) {
if (result instanceof Error) {
res.status(500).send();
} else {
- res.send(result); // game was created successfully, and access code was returned
+ res.status(201).send(result); // game was created successfully, and access code was returned
}
}).catch((e) => {
if (e === globals.ERROR_MESSAGE.BAD_CREATE_REQUEST) {
diff --git a/server/config/globals.js b/server/config/globals.js
index b686fcb..75a3e84 100644
--- a/server/config/globals.js
+++ b/server/config/globals.js
@@ -20,7 +20,7 @@ const globals = {
res.status(400).send('Request has invalid content type.');
}
},
- STALE_GAME_HOURS: 12,
+ STALE_GAME_HOURS: 24,
CLIENT_COMMANDS: {
FETCH_GAME_STATE: 'fetchGameState',
START_GAME: 'startGame',
diff --git a/server/modules/GameManager.js b/server/modules/GameManager.js
index e83b8e1..d292f24 100644
--- a/server/modules/GameManager.js
+++ b/server/modules/GameManager.js
@@ -530,7 +530,7 @@ function pruneStaleGames (activeGames, timerThreads, logger) {
for (const [accessCode, game] of Object.entries(activeGames)) {
if (game.createTime) {
const createDate = new Date(game.createTime);
- if (createDate.setHours(createDate.getHours() + globals.STALE_GAME_HOURS) < Date.now()) { // clear games created more than 12 hours ago
+ if (createDate.setHours(createDate.getHours() + globals.STALE_GAME_HOURS) < Date.now()) {
logger.info('PRUNING STALE GAME ' + accessCode);
delete activeGames[accessCode];
if (timerThreads[accessCode]) {