From a50086aedf6036bcfc94c8e9c9f96bd34672eca7 Mon Sep 17 00:00:00 2001 From: Andrio Celos Date: Thu, 31 Aug 2023 15:16:46 +1000 Subject: [PATCH] Allow the host to set the turn time limit in the lobby page Suggested by Ljovynn. It can be set only before the first battle. --- TableturfBattleClient/index.html | 6 +++- TableturfBattleClient/src/Pages/LobbyPage.ts | 15 ++++++++ TableturfBattleClient/src/app.ts | 16 +++++++-- TableturfBattleServer/Program.cs | 37 ++++++++++++++++++++ 4 files changed, 71 insertions(+), 3 deletions(-) diff --git a/TableturfBattleClient/index.html b/TableturfBattleClient/index.html index 3ef2097..03c3c1b 100644 --- a/TableturfBattleClient/index.html +++ b/TableturfBattleClient/index.html @@ -73,7 +73,11 @@

Other players can join using a link to this page.

- + diff --git a/TableturfBattleClient/src/Pages/LobbyPage.ts b/TableturfBattleClient/src/Pages/LobbyPage.ts index 6f235f8..7105c6c 100644 --- a/TableturfBattleClient/src/Pages/LobbyPage.ts +++ b/TableturfBattleClient/src/Pages/LobbyPage.ts @@ -101,6 +101,12 @@ function lobbyResetSlots() { playerListItems.push(el); playerList.appendChild(el); } + + lobbyLockSettings(currentGame.me?.playerIndex != 0); +} + +function lobbyLockSettings(lock: boolean) { + lobbyTimeLimitBox.readOnly = lock; } function clearReady() { @@ -169,6 +175,15 @@ function initDeckSelection() { } } +lobbyTimeLimitBox.addEventListener('change', () => { + let req = new XMLHttpRequest(); + req.open('POST', `${config.apiBaseUrl}/games/${currentGame!.id}/setTurnTimeLimit`); + let data = new URLSearchParams(); + data.append('clientToken', clientToken); + data.append('turnTimeLimit', lobbyTimeLimitBox.value || ''); + req.send(data.toString()); +}); + deckSelectionForm.addEventListener('submit', e => { e.preventDefault(); if (selectedDeck == null) return; diff --git a/TableturfBattleClient/src/app.ts b/TableturfBattleClient/src/app.ts index 7ce42b3..daaa4e8 100644 --- a/TableturfBattleClient/src/app.ts +++ b/TableturfBattleClient/src/app.ts @@ -95,6 +95,12 @@ function clearUrlFromGame() { location.hash = ''; } +function onGameSettingsChange() { + if (currentGame == null) return; + if (lobbyTimeLimitBox.value != currentGame.turnTimeLimit?.toString() ?? '') + lobbyTimeLimitBox.value = currentGame.turnTimeLimit?.toString() ?? ''; +} + function onGameStateChange(game: any, playerData: PlayerData | null) { if (currentGame == null) throw new Error('currentGame is null'); @@ -113,6 +119,9 @@ function onGameStateChange(game: any, playerData: PlayerData | null) { gamePage.dataset.myPlayerIndex = playerData ? playerData.playerIndex.toString() : ''; gamePage.dataset.uiBaseColourIsSpecialColour = playerData && game.players[playerData.playerIndex].uiBaseColourIsSpecialColour ? 'true' : 'false'; + if (game.stage != GameState.WaitingForPlayers) + lobbyLockSettings(true); + redrawModal.hidden = true; gamePage.classList.remove('gameEnded'); switch (game.state) { @@ -252,8 +261,7 @@ function setupWebSocket(gameID: string) { lobbyResetSlots(); for (let i = 0; i < currentGame.players.length; i++) lobbyAddPlayer(i); - lobbyTimeLimitBox.value = currentGame.turnTimeLimit?.toString() ?? ''; - lobbyTimeLimitUnit.hidden = currentGame.turnTimeLimit == null; + onGameSettingsChange(); for (let i = 0; i < playerBars.length; i++) { playerBars[i].visible = i < currentGame.maxPlayers; @@ -298,6 +306,10 @@ function setupWebSocket(gameID: string) { return; } switch (payload.event) { + case 'settingsChange': + currentGame.turnTimeLimit = payload.data.turnTimeLimit; + onGameSettingsChange(); + break; case 'join': if (payload.data.playerIndex == currentGame.players.length) { currentGame.players.push(payload.data.player); diff --git a/TableturfBattleServer/Program.cs b/TableturfBattleServer/Program.cs index 8bddffd..d0774ae 100644 --- a/TableturfBattleServer/Program.cs +++ b/TableturfBattleServer/Program.cs @@ -264,6 +264,43 @@ internal class Program { } break; } + case "setTurnTimeLimit": { + if (e.Request.HttpMethod != "POST") { + e.Response.AddHeader("Allow", "POST"); + SetErrorResponse(e.Response, new(HttpStatusCode.MethodNotAllowed, "MethodNotAllowed", "Invalid request method for this endpoint.")); + } else if (e.Request.ContentLength64 >= 65536) { + e.Response.StatusCode = (int) HttpStatusCode.RequestEntityTooLarge; + } else { + var d = DecodeFormData(e.Request.InputStream); + if (!d.TryGetValue("clientToken", out var tokenString) || !Guid.TryParse(tokenString, out var clientToken)) { + SetErrorResponse(e.Response, new(HttpStatusCode.BadRequest, "InvalidClientToken", "Invalid client token.")); + return; + } + if (game.State != GameState.WaitingForPlayers) { + SetErrorResponse(e.Response, new(HttpStatusCode.Gone, "GameAlreadyStarted", "The game has already started.")); + return; + } + if (!game.GetPlayer(clientToken, out var playerIndex, out var player) || playerIndex != 0) { + SetErrorResponse(e.Response, new(HttpStatusCode.Forbidden, "AccessDenied", "Only the host can do that.")); + return; + } + if (d.TryGetValue("turnTimeLimit", out var turnTimeLimitString)) { + if (turnTimeLimitString == "") + game.TurnTimeLimit = null; + else if (!int.TryParse(turnTimeLimitString, out var turnTimeLimit2) || turnTimeLimit2 < 10) { + SetErrorResponse(e.Response, new(HttpStatusCode.UnprocessableEntity, "InvalidTurnTimeLimit", "Invalid turn time limit.")); + return; + } else + game.TurnTimeLimit = turnTimeLimit2; + } else { + SetErrorResponse(e.Response, new(HttpStatusCode.UnprocessableEntity, "InvalidTurnTimeLimit", "Invalid turn time limit.")); + return; + } + + game.SendEvent("settingsChange", game, false); + } + break; + } case "chooseStage": { if (e.Request.HttpMethod != "POST") { e.Response.AddHeader("Allow", "POST");