start of functionality

This commit is contained in:
AlecM33
2023-08-15 14:17:48 -04:00
parent 4d59d16902
commit 230e657368
9 changed files with 180 additions and 76 deletions

View File

@@ -8,6 +8,8 @@ export const PRIMITIVES = {
MAX_CUSTOM_ROLE_DESCRIPTION_LENGTH: 1000,
TOAST_DURATION_DEFAULT: 6,
ACCESS_CODE_LENGTH: 4,
MAX_MINUTES: 59,
MAX_HOURS: 5,
PLAYER_ID_COOKIE_KEY: 'play-werewolf-anon-id'
};
@@ -75,6 +77,7 @@ export const EVENT_IDS = {
ASSIGN_DEDICATED_MOD: 'assignDedicatedMod',
KICK_PERSON: 'kickPerson',
UPDATE_GAME_ROLES: 'updateGameRoles',
UPDATE_GAME_TIMER: 'updateGameTimer',
LEAVE_ROOM: 'leaveRoom'
};

View File

@@ -46,6 +46,7 @@ export const HTMLFragments = {
</div>`,
START_GAME_PROMPT:
`<button id='edit-roles-button'>Edit Roles</button>
<button id='edit-timer-button'>Edit Timer</button>
<button id='start-game-button'>Start Game</button>`,
LEAVE_GAME_PROMPT:
'<button id=\'leave-game-button\'>Leave Room</button>',
@@ -58,6 +59,11 @@ export const HTMLFragments = {
<button class="app-button" id="save-role-changes-button">
<p>Save</p><img src="../images/save-svgrepo-com.svg" alt='save'>
</button>`,
TIMER_EDIT_BUTTONS:
`<button class="app-button cancel" id="cancel-timer-changes-button">Cancel</button>
<button class="app-button" id="save-timer-changes-button">
<p>Save</p><img src="../images/save-svgrepo-com.svg" alt='save'>
</button>`,
PLAYER_GAME_VIEW:
`<div id='game-header'>
<div>

View File

@@ -53,16 +53,10 @@ export class GameCreationStepManager {
if (e.type === 'click' || e.code === 'Enter') {
let hours = parseInt(document.getElementById('game-hours').value);
let minutes = parseInt(document.getElementById('game-minutes').value);
hours = isNaN(hours) ? null : hours;
minutes = isNaN(minutes) ? null : minutes;
if ((hours === null && minutes === null)
|| (hours === null && minutes > 0 && minutes < 60)
|| (minutes === null && hours > 0 && hours < 6)
|| (hours === 0 && minutes > 0 && minutes < 60)
|| (minutes === 0 && hours > 0 && hours < 6)
|| (hours > 0 && hours < 6 && minutes >= 0 && minutes < 60)
) {
if (hasTimer(hours, minutes)) {
hours = this.standardizeNumberInput(hours);
minutes = this.standardizeNumberInput(minutes)
if (this.timerIsValid(hours, minutes)) {
if (this.hasTimer(hours, minutes)) {
this.currentGame.hasTimer = true;
this.currentGame.timerParams = {
hours: hours,
@@ -77,11 +71,7 @@ export class GameCreationStepManager {
this.incrementStep();
this.renderStep('creation-step-container', this.step);
} else {
if (hours === 0 && minutes === 0) {
toast('You must enter a non-zero amount of time.', 'error', true);
} else {
toast('Invalid timer options. Hours can be a max of 5, Minutes a max of 59.', 'error', true);
}
toast('Invalid timer options. Hours can be a max of 5, Minutes a max of 59.', 'error', true);
}
}
},
@@ -198,7 +188,7 @@ export class GameCreationStepManager {
showButtons(true, true, this.steps[step].forwardHandler, this.steps[step].backHandler);
break;
case 3:
renderTimerStep(containerId, step, this.currentGame, this.steps);
this.renderTimerStep(containerId, step, this.currentGame, this.steps);
showButtons(true, true, this.steps[step].forwardHandler, this.steps[step].backHandler);
break;
case 4:
@@ -297,6 +287,68 @@ export class GameCreationStepManager {
initializeRemainingEventListeners(this.deckManager, this.roleBox);
};
renderTimerStep (containerId, stepNumber, game, steps) {
const div = document.createElement('div');
div.setAttribute('id', 'step-' + stepNumber);
div.classList.add('step');
const timeContainer = document.createElement('div');
timeContainer.setAttribute('id', 'game-time');
const hoursDiv = document.createElement('div');
const hoursLabel = document.createElement('label');
hoursLabel.setAttribute('for', 'game-hours');
hoursLabel.innerText = 'Hours';
const hours = document.createElement('input');
hours.addEventListener('keyup', steps[stepNumber].forwardHandler);
setAttributes(hours, { type: 'number', id: 'game-hours', name: 'game-hours', min: '0', max: '5', value: game.timerParams?.hours });
const minutesDiv = document.createElement('div');
const minsLabel = document.createElement('label');
minsLabel.setAttribute('for', 'game-minutes');
minsLabel.innerText = 'Minutes';
const minutes = document.createElement('input');
minutes.addEventListener('keyup', steps[stepNumber].forwardHandler);
setAttributes(minutes, { type: 'number', id: 'game-minutes', name: 'game-minutes', min: '1', max: '60', value: game.timerParams?.minutes });
hoursDiv.appendChild(hoursLabel);
hoursDiv.appendChild(hours);
minutesDiv.appendChild(minsLabel);
minutesDiv.appendChild(minutes);
timeContainer.appendChild(hoursDiv);
timeContainer.appendChild(minutesDiv);
div.appendChild(timeContainer);
document.getElementById(containerId).appendChild(div);
}
timerIsValid(hours, minutes) {
let valid = true;
if (hours === null && minutes === null) {
return valid;
}
if (hours !== null) {
valid = hours <= PRIMITIVES.MAX_HOURS;
}
if (minutes !== null) {
valid = minutes <= PRIMITIVES.MAX_MINUTES;
}
return valid;
}
hasTimer(hours, minutes) {
return hours !== null || minutes !== null;
}
standardizeNumberInput(input) {
return (isNaN(input) || input === 0) ? null : input;
}
}
function renderNameStep (containerId, step, game, steps) {
@@ -358,41 +410,6 @@ function renderModerationTypeStep (game, containerId, stepNumber) {
document.getElementById(containerId).appendChild(stepContainer);
}
function renderTimerStep (containerId, stepNumber, game, steps) {
const div = document.createElement('div');
div.setAttribute('id', 'step-' + stepNumber);
div.classList.add('step');
const timeContainer = document.createElement('div');
timeContainer.setAttribute('id', 'game-time');
const hoursDiv = document.createElement('div');
const hoursLabel = document.createElement('label');
hoursLabel.setAttribute('for', 'game-hours');
hoursLabel.innerText = 'Hours';
const hours = document.createElement('input');
hours.addEventListener('keyup', steps[stepNumber].forwardHandler);
setAttributes(hours, { type: 'number', id: 'game-hours', name: 'game-hours', min: '0', max: '5', value: game.timerParams?.hours });
const minutesDiv = document.createElement('div');
const minsLabel = document.createElement('label');
minsLabel.setAttribute('for', 'game-minutes');
minsLabel.innerText = 'Minutes';
const minutes = document.createElement('input');
minutes.addEventListener('keyup', steps[stepNumber].forwardHandler);
setAttributes(minutes, { type: 'number', id: 'game-minutes', name: 'game-minutes', min: '1', max: '60', value: game.timerParams?.minutes });
hoursDiv.appendChild(hoursLabel);
hoursDiv.appendChild(hours);
minutesDiv.appendChild(minsLabel);
minutesDiv.appendChild(minutes);
timeContainer.appendChild(hoursDiv);
timeContainer.appendChild(minutesDiv);
div.appendChild(timeContainer);
document.getElementById(containerId).appendChild(div);
}
function renderReviewAndCreateStep (containerId, stepNumber, game, deckManager) {
const div = document.createElement('div');
div.setAttribute('id', 'step-' + stepNumber);
@@ -591,10 +608,6 @@ function processNewCustomRoleSubmission (name, description, team, deckManager, i
}
}
function hasTimer (hours, minutes) {
return hours !== null || minutes !== null;
}
function validateName (name) {
return typeof name === 'string' && name.length > 0 && name.length <= PRIMITIVES.MAX_PERSON_NAME_LENGTH;
}

View File

@@ -1,5 +1,5 @@
import { QRCode } from '../../third_party/qrcode.js';
import { toast } from '../../front_end_components/Toast.js';
import {cancelCurrentToast, toast} from '../../front_end_components/Toast.js';
import { EVENT_IDS, PRIMITIVES, SOCKET_EVENTS, USER_TYPE_ICONS, USER_TYPES } from '../../../config/globals.js';
import { HTMLFragments } from '../../front_end_components/HTMLFragments.js';
import { Confirmation } from '../../front_end_components/Confirmation.js';
@@ -60,6 +60,64 @@ export class Lobby {
});
};
this.editTimerHandler = (e) => {
e.preventDefault();
document.querySelector('#mid-game-timer-editor')?.remove();
const timerEditContainer = document.createElement('div');
const timerEditContainerBackground = document.createElement('div');
timerEditContainerBackground.setAttribute('id', 'timer-edit-container-background');
timerEditContainer.setAttribute('id', 'mid-game-timer-editor');
document.getElementById('game-content').style.display = 'none';
document.body.appendChild(timerEditContainer);
document.body.appendChild(timerEditContainerBackground);
this.gameCreationStepManager
.renderTimerStep(this.stateBucket.currentGameState, '2', this.stateBucket.currentGameState, this.gameCreationStepManager.steps);
const timerEditPrompt = document.createElement('div');
timerEditPrompt.setAttribute('id', 'timer-edit-prompt');
timerEditPrompt.innerHTML = HTMLFragments.TIMER_EDIT_BUTTONS;
timerEditPrompt.querySelector('#save-timer-changes-button').addEventListener('click', () => {
let hours = parseInt(document.getElementById('game-hours').value);
let minutes = parseInt(document.getElementById('game-minutes').value);
hours = this.gameCreationStepManager.standardizeNumberInput(hours);
minutes = this.gameCreationStepManager.standardizeNumberInput(minutes)
if (this.gameCreationStepManager.timerIsValid(hours, minutes)) {
let hasTimer, timerParams;
if (this.gameCreationStepManager.hasTimer(hours, minutes)) {
hasTimer = true;
timerParams = {
hours: hours,
minutes: minutes
};
} else {
hasTimer = false;
timerParams = null;
}
document.querySelector('#mid-game-timer-editor')?.remove();
document.querySelector('#timer-edit-container-background')?.remove();
document.getElementById('game-content').style.display = 'flex';
this.socket.emit(
SOCKET_EVENTS.IN_GAME_MESSAGE,
EVENT_IDS.UPDATE_GAME_TIMER,
stateBucket.currentGameState.accessCode,
{ hasTimer: hasTimer, timerParams: timerParams },
() => {
toast('Timer updated successfully!', 'success');
}
);
} else {
toast('Invalid timer options. Hours can be a max of 5, Minutes a max of 59.', 'error', true);
}
});
timerEditPrompt.querySelector('#cancel-timer-changes-button').addEventListener('click', () => {
document.querySelector('#mid-game-timer-editor')?.remove();
document.querySelector('#timer-edit-container-background')?.remove();
document.getElementById('game-content').style.display = 'flex';
});
timerEditContainer.appendChild(timerEditPrompt);
}
this.editRolesHandler = (e) => {
e.preventDefault();
document.querySelector('#mid-game-role-editor')?.remove();

View File

@@ -20,6 +20,17 @@ import { Ended } from '../game_state/states/Ended.js';
export const gameHandler = (socket, window, gameDOM) => {
document.body.innerHTML = gameDOM + document.body.innerHTML;
injectNavbar();
const connectionHandler = () => {
if (stateBucket.timerWorker) {
stateBucket.timerWorker.terminate();
stateBucket.timerWorker = null;
}
syncWithGame(
socket,
UserUtility.validateAnonUserSignature(stateBucket.environment),
window
);
}
return new Promise((resolve, reject) => {
window.fetch(
'/api/games/environment',
@@ -30,22 +41,18 @@ export const gameHandler = (socket, window, gameDOM) => {
).catch(() => {
reject(new Error('There was a problem connecting to the room.'));
}).then((response) => {
if (!response.ok) {
reject(new Error('HTTP ' + response.status + ': Could not connect to the room'));
if (!response.ok && !(response.status === 304)) {
console.log('too many requests! returning...');
reject(new Error('Could not connect to the room: HTTP ' + response.status + ': ' + response.statusText));
return;
}
response.text().then((text) => {
stateBucket.environment = text;
if (socket.connected) {
connectionHandler();
}
socket.on('connect', () => {
if (stateBucket.timerWorker) {
stateBucket.timerWorker.terminate();
stateBucket.timerWorker = null;
}
syncWithGame(
socket,
UserUtility.validateAnonUserSignature(stateBucket.environment),
window
);
connectionHandler();
});
socket.on('connect_error', (err) => {
toast(err, 'error', true, false);
@@ -72,6 +79,7 @@ function syncWithGame (socket, cookie, window) {
{ personId: cookie },
(err, gameState) => {
if (err) {
console.log(err);
retrySync(accessCode, socket, cookie);
} else {
handleGameState(gameState, cookie, socket);

View File

@@ -31,7 +31,7 @@ function attemptToJoinGame (event) {
mode: 'cors'
}
).then((res) => {
if (!res.ok) {
if (!res.ok && !(res.status === 304)) {
switch (res.status) {
case 404:
toast('Game not found', 'error', true);

View File

@@ -28,7 +28,7 @@ const joinHandler = (e) => {
if (validateName(name)) {
sendJoinRequest(e, name, accessCode)
.then((res) => {
if (!res.ok) {
if (!res.ok && !(res.status === 304)) {
switch (res.status) {
case 404:
toast('Game not found', 'error', true);

View File

@@ -136,7 +136,8 @@
#end-of-game-buttons #return-to-lobby-button,
#mod-transfer-button,
#edit-roles-button,
#save-role-changes-button {
#save-role-changes-button,
#edit-timer-button {
background-color: #045ea6;
border: 2px solid #024070;
}
@@ -145,7 +146,8 @@
#end-of-game-buttons #return-to-lobby-button:hover,
#mod-transfer-button:hover,
#edit-roles-button:hover,
#save-role-changes-button:hover {
#save-role-changes-button:hover,
#edit-timer-button:hover {
background-color: rgba(0, 120, 215, 0.45);
border: 2px solid #045EA6;
}
@@ -678,16 +680,21 @@ label[for='moderator'] {
box-shadow: 0 -6px 40px black;
}
#start-game-button, #end-game-button, #return-to-lobby-button, #edit-roles-button, #leave-game-button {
#start-game-button,
#end-game-button,
#return-to-lobby-button,
#edit-roles-button,
#leave-game-button,
#edit-timer-button {
font-family: 'signika-negative', sans-serif !important;
padding: 10px;
padding: 7px;
border-radius: 5px;
color: #e7e7e7;
cursor: pointer;
border: 2px solid transparent;
transition: background-color, border 0.3s ease-out;
text-shadow: 0 3px 4px rgb(0 0 0 / 85%);
font-size: 25px;
font-size: 22px;
user-select: none;
-ms-user-select: none;
-webkit-user-select: none;
@@ -997,6 +1004,10 @@ canvas {
}
@media(max-width: 500px) {
#game-control-prompt button, #start-game-prompt button, #leave-game-prompt button {
margin: 0 10px;
}
#client-container button img {
width: 18px;
pointer-events: none;
@@ -1068,7 +1079,12 @@ canvas {
height: 65px;
}
#start-game-button, #end-game-button, #return-to-lobby-button, #edit-roles-button, #leave-game-button {
#start-game-button,
#end-game-button,
#return-to-lobby-button,
#edit-roles-button,
#leave-game-button,
#edit-timer-button {
font-size: 20px;
padding: 5px;
}

View File

@@ -18,7 +18,7 @@ const template =
<div></div>
<div></div>
</div>
<p>Connecting to the Room...</p>
<p>Waiting for Connection to Room...</p>
</div>
<div id="mobile-menu-background-overlay"></div>
<div id="navbar"></div>