From 0df51604280656af421f0c138258b773bc504a8b Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Sat, 5 Feb 2022 16:43:18 -0800 Subject: [PATCH] Implementing initial-placement Signed-off-by: James Ketrenos --- client/src/Board.js | 11 +- client/src/Table.js | 9 +- server/routes/games.js | 386 ++++++++++++----------------------------- 3 files changed, 121 insertions(+), 285 deletions(-) diff --git a/client/src/Board.js b/client/src/Board.js index 3702447..341c856 100644 --- a/client/src/Board.js +++ b/client/src/Board.js @@ -88,7 +88,7 @@ const Board = ({ game }) => { backgroundImage: `url(${assetsPath}/gfx/tiles-${tile.type}.png)`, backgroundPositionY: `-${tile.card*tileHeight}px` }} - >{tile.index}; + >; }; const Road = ({road}) => { @@ -438,6 +438,11 @@ const Board = ({ game }) => { } } + const canAction = (action) => { + console.log(game.turn); + return (game && game.turn && Array.isArray(game.turn.actions) && game.turn.actions.indexOf(action) !== -1); + }; + return (
@@ -445,10 +450,10 @@ const Board = ({ game }) => { { tiles } { pips } { game && <> -
+
{ corners }
-
+
{ roads }
} diff --git a/client/src/Table.js b/client/src/Table.js index 01cb15e..5fec9ff 100755 --- a/client/src/Table.js +++ b/client/src/Table.js @@ -281,8 +281,8 @@ const StartButton = ({ table }) => { const WaitingForPlayer = ({table}) => { return (
- { table.game && -
Waiting for {table.game.turn} to complete their turn.
+ { table.game && table.game.turn && +
Waiting for {table.game.turn.name} to complete their turn.
}
); @@ -376,7 +376,7 @@ const Action = ({ table }) => { } { table.game.state === 'active' && <> - + } { !inLobby && @@ -1069,7 +1069,8 @@ class Table extends React.Component { } - { game && game.turn && game.turn !== game.name && + { game && game.turn && game.turn.color !== game.color && + (game.state === 'initial-placement' || game.state === 'normal') && } diff --git a/server/routes/games.js b/server/routes/games.js index 8ba59aa..5624fba 100755 --- a/server/routes/games.js +++ b/server/routes/games.js @@ -6,6 +6,8 @@ const express = require("express"), fs = require("fs"), accessSync = fs.accessSync, randomWords = require("random-words"); + +const layout = require('./layout.js'); let gameDB; @@ -34,267 +36,6 @@ function shuffle(array) { return array; } -/* Board Tiles: - * 0 1 2 - * 3 4 5 6 - * 7 8 9 10 11 - * 12 13 14 15 - * 16 17 18 - */ - -/* - * c0 - * /\ - * r0 / \r1 - * c6 / \ c1 - * | | - * r6| p,a | r2 - * c5| | c3 - * \ / - * r5 \ / r3 - * \/ - * c4 -*/ - -/* | -* 1 2 | -* 0 1| 3| 5| -* \. / \ / \ / \ 3 -* \. 0/ 1\ 3/ 4\ 6/ 7\ -* \./ \ / \ / \ -* 0| 2| 4| |6 -* 17 2| 0 5| 1 8| 2 |9 4 -* 8| 10| 12| |14 -* / \ / \ / \ / \ -* 10/ 11\ 13/ 14\ 16/ 17\ 19/ 20\ -* / \ / \ / \ / \ -* 7| 9| 11| 13| |15 -* 16 12| 3 15| 4 18| 5 21| 6 |22 -* 17| 19| 21| 23| |25 5 -* / \ / \ / \ / \ / \ ,/ -* 23/ 24\ 26/ 27\ 29/ 30\ 32/ 33\ 35/ 36\ ,/ -* / \ / \ / \ / \ / \ ,/ -* 16| 18| 20| 22| 24| |26 -* 15 25| 7 28| 8 31| 9 34| 10 37| 11 |38 6 -* 27| 29| 31| 33| 35| |37 -* /' \ / \ / \ / \ / \ / -* /' 39\ 40/ 41\ 43/ 44\ 46/ 47\ 49/ 50\ /53 -* /' \ / \ / \ / \ / \ / 7 -* 28| 30| 32| 34| |36 -* 14 42| 12 45| 13 48| 14 51| 15 |52 -* 38| 40| 42| 44| |46 -* \ / \ / \ / \ / -* 54\ 55/ 56\ 58/ 59\ 61/ 62\ /65 -* \ / \ / \ / \ / 8 -* 39| 41| 43| |45 -* 13 57| 16 60| 17 63| 18 |64 -* 47| 49| 51| |53 -* \ / \ / \ / `\ -* 66\ 67/ 68\ 69/ 70\ /71 `\ -* \ / \ / \ / `\ -* 48| 50| 52| 9 -* | -* 12 | 11 10 -*/ -const Tile = (corners, roads) => { - return { - corners: corners, /* 6 */ - pip: -1, - roads: roads, - asset: -1 - }; -}; - -/* Borders have three sections each, so they are numbered - * 0-17 clockwise. Some corners share two borders. */ - -const Corner = (roads, banks) => { - return { - roads: roads, /* max of 3 */ - banks: banks, /* max of 2 */ - data: undefined - }; -}; - -const Road = (corners) => { - return { - corners: corners, /* 2 */ - data: undefined - } -}; - -const layout = { - tiles: [ - Tile([ 0, 1, 2, 10, 9, 8], [ 0, 1, 5, 13, 11, 2]), - Tile([ 2, 3, 4, 12, 11, 10], [ 3, 4, 8, 16, 14, 5]), - Tile([ 4, 5, 6, 14, 13, 12], [ 6, 7, 9, 19, 17, 8]), - - Tile([ 7, 8, 9, 19, 18, 17], [ 10, 11, 15, 26, 24, 12]), - Tile([ 9, 10, 11, 21, 20, 19], [ 13, 14, 18, 29, 27, 15]), - Tile([ 11, 12, 13, 23, 22, 21], [ 16, 17, 21, 32, 30, 18]), - Tile([ 13, 14, 15, 25, 24, 23], [ 19, 20, 22, 35, 33, 21]), - - Tile([ 16, 17, 18, 29, 28, 27], [ 23, 24, 28, 40, 39, 25]), - Tile([ 18, 19, 20, 31, 30, 29], [ 26, 27, 31, 43, 41, 28]), - Tile([ 20, 21, 22, 33, 32, 31], [ 29, 30, 34, 46, 44, 31]), - Tile([ 22, 23, 24, 35, 34, 33], [ 32, 33, 37, 49, 47, 34]), - Tile([ 24, 25, 26, 37, 36, 35], [ 35, 36, 38, 53, 50, 37]), - - Tile([ 28, 29, 30, 40, 39, 38], [ 40, 41, 45, 55, 54, 42]), - Tile([ 30, 31, 32, 42, 41, 40], [ 43, 44, 48, 58, 56, 45]), - Tile([ 32, 33, 34, 44, 43, 42], [ 46, 47, 51, 61, 59, 48]), - Tile([ 34, 35, 36, 46, 45, 44], [ 49, 50, 52, 65, 62, 51]), - - Tile([ 39, 40, 41, 49, 48, 47], [ 55, 56, 60, 67, 66, 57]), - Tile([ 41, 42, 43, 51, 50, 49], [ 58, 59, 63, 69, 68, 60]), - Tile([ 43, 44, 45, 53, 52, 51], [ 61, 62, 64, 71, 70, 63]) - ], - roads: [ - /* 0 */ - Road([0, 1]), - Road([1, 2]), - Road([0, 8]), - Road([2, 3]), - Road([3, 4]), - Road([2, 10]), - Road([4, 5]), - Road([5, 6]), - Road([4, 12]), - Road([6, 14]), - /* 10 */ - Road([8, 7]), - Road([8, 9]), - Road([7, 17]), - Road([9, 10]), - Road([10, 11]), - Road([9, 19]), - Road([12, 11]), - Road([12, 13]), - Road([11, 21]), - Road([14, 13]), - /* 20 */ - Road([14, 15]), - Road([13,23 ]), - Road([15, 25]), - Road([17, 16]), - Road([17, 18]), - Road([16, 27]), - Road([19, 18]), - Road([19, 20]), - Road([18, 29]), - Road([21, 20]), - /* 30 */ - Road([21, 22]), - Road([20, 31]), - Road([23, 22]), - Road([23, 24]), - Road([22,33]), - Road([25,24]), - Road([25,26]), - Road([24, 35]), - Road([26,37]), - Road([27,28]), - /* 40 */ - Road([29,28]), - Road([29,30]), - Road([28,38]), - Road([31,30]), - Road([31,32]), - Road([30,40]), - Road([33,32]), - Road([33,34]), - Road([32,42]), - Road([35,34]), - /* 50 */ - Road([35,36]), - Road([34,44]), - Road([36,46]), - Road([37,36]), - Road([38,39]), - Road([40,39]), - Road([40,41]), - Road([39,47]), - Road([41,42]), - Road([42,43]), - /* 60 */ - Road([41,49]), - Road([44,43]), - Road([44,45]), - Road([43,51]), - Road([45,53]), - Road([46,45]), - Road([47,48]), - Road([49,48]), - Road([49,50]), - Road([51,50]), - /* 70 */ - Road([51,52]), - Road([53,52]), - ], - corners: [ - /* 0 */ - /* 0 */ Corner([2, 0],[17,0]), - /* 1 */ Corner([0, 1],[0,1]), - /* 2 */ Corner([1,3,5],[1]), - /* 3 */ Corner([3,4],[1,2]), - /* 4 */ Corner([8,4,6],[2]), - /* 5 */ Corner([6,7],[2,3]), - /* 6 */ Corner([7,9],[3,4]), - /* 7 */ Corner([12,10],[16,17]), - /* 8 */ Corner([2,10,11],[17]), - /* 9 */ Corner([11,13,15],[]), - /* 10 */ - /* 10 */ Corner([5,13,14],[]), - /* 11 */ Corner([14,16,18],[]), - /* 12 */ Corner([8,16,17],[]), - /* 13 */ Corner([17,19,21],[]), - /* 14 */ Corner([9,19,20],[4]), - /* 15 */ Corner([20,22],[4,5]), - /* 16 */ Corner([23,25],[16,15]), - /* 17 */ Corner([12,23,24],[16]), - /* 18 */ Corner([24,26,28],[]), - /* 19 */ Corner([15,26,27],[]), - /* 20 */ - /* 20 */ Corner([27,29,31],[]), - /* 21 */ Corner([18,29,30],[]), - /* 22 */ Corner([30,32,34],[]), - /* 23 */ Corner([21,32,33],[]), - /* 24 */ Corner([33,35,37],[]), - /* 25 */ Corner([22,35,36],[5]), - /* 26 */ Corner([36,38],[5,6]), - /* 27 */ Corner([25,39],[15,14]), - /* 28 */ Corner([39,40,42],[14]), - /* 29 */ Corner([28,40,41],[]), - /* 30 */ - /* 30 */ Corner([41,43,45],[]), - /* 31 */ Corner([31,43,44],[]), - /* 32 */ Corner([44,46,48],[]), - /* 33 */ Corner([34,46,47],[]), - /* 34 */ Corner([47,49,51],[]), - /* 35 */ Corner([37,49,50],[]), - /* 36 */ Corner([50,53,52],[7]), - /* 37 */ Corner([38,53],[6,7]), - /* 38 */ Corner([42,54],[14,13]), - /* 39 */ Corner([54,55,57],[13]), - /* 40 */ - /* 40 */ Corner([45,55,56],[]), - /* 41 */ Corner([56,58,60],[]), - /* 42 */ Corner([48,58,59],[]), - /* 43 */ Corner([59,61,63],[]), - /* 44 */ Corner([51,61,62],[]), - /* 45 */ Corner([62,65,64],[8]), - /* 46 */ Corner([52,65],[7,8]), - /* 47 */ Corner([57,66],[13,12]), - /* 48 */ Corner([67,66],[12,11]), - /* 49 */ Corner([60,67,68],[11]), - /* 50 */ - /* 50 */ Corner([68,69],[11,10]), - /* 51 */ Corner([69,70,63],[10]), - /* 52 */ Corner([70,71],[10,9]), - /* 53 */ Corner([64,71],[8,9]), - ] -} - const assetData = { tiles: [ { type: "desert", card: 0 }, @@ -453,11 +194,15 @@ const processGameOrder = (game, player, dice) => { }).join(', ')}.`; addChatMessage(game, null, message); game.playerOrder = players.map(player => getPlayerColor(game, player)); - game.state = 'active' - message = `Game has started!`; - game.turn = getPlayerName(game, players[0]); + game.state = 'initial-placement'; + message = `Initial settlement placement has started!`; + game.turn = { + actions: ['place-settlement'], + name: getPlayerName(game, players[0]), + color: getPlayerColor(game, players[0]) + }; addChatMessage(game, null, message); - message = `It is ${game.turn}'s turn.`; + message = `It is ${game.turn.name}'s turn.`; } else { message = `There are still ties for player order!`; } @@ -588,6 +333,18 @@ const loadGame = async (id) => { }); } + if (game.state === 'active') { + game.state = 'initial-placement'; + } + + if (typeof game.turn !== 'object') { + delete game.turn; + } + + if (!game.status) { + resetGame(game); + } + /* Reconnect session player colors to the player objects */ for (let id in game.sessions) { const session = game.sessions[id]; @@ -618,12 +375,7 @@ const adminActions = (game, action, value) => { case "state": switch (value) { case 'game-order': - for (let key in game.players) { - game.players[key].order = 0; - delete game.players[key].orderRoll; - delete game.players[key].orderStatus; - } - delete game.turn; + resetGame(game); game.state = 'game-order'; break; } @@ -792,6 +544,15 @@ const addChatMessage = (game, session, message) => { }); }; +const getColorFromName = (game, name) => { + for (let id in game.sessions) { + if (game.sessions[id].name === name) { + return color; + } + } + return ''; +}; + const getNextPlayer = (game, name) => { let color; for (let id in game.sessions) { @@ -881,10 +642,48 @@ router.put("/:id/:action/:value?", async (req, res) => { error = `You cannot pass when it isn't your turn.` } if (!error) { - game.turn = getNextPlayer(game, name); + const next = getNextPlayer(game, name); + game.turn = { + actions: game.turn.actions, + name: next, + color: getColorFromName(game, next) + }; addChatMessage(game, session, `${name} passed their turn.`); - addChatMessage(game, null, `It is ${game.turn}'s turn.`); + addChatMessage(game, null, `It is ${next}'s turn.`); } + case 'place-settlement': + if (game.state !== 'initial-placement' || game.state !== 'normal') { + error = `You cannot place an item unless the game is active.`; + break; + } + if (session.color !== game.turn) { + error = `It is not your turn!`; + break; + } + const index = value; + if (game.corners[index] === undefined) { + error = `You have requested to place a settlement illegally!`; + break; + } + const corner = game.corners[index]; + if (corner.color) { + error = `This location already has a settlement belonging to ${playerNameFromColor(game, corner.color)}!`; + break; + } + corner.color = game.color; + corner.type = 'settlement'; + if (game.state === 'initial-placement') { + game.turn.actions = ['place-road']; + game.turn.limits = { corner: index }; /* road placement is limited to be near this corner index */ + addChatMessage(game, session, `Placed a settlement. Next, they need to place a road.`); + } + break; + case 'place-road': + error = `Road placement not yet implemented!`; + break; + case 'place-city': + error = `City placement not yet implemented!`; + break; case "state": const state = value; if (!state) { @@ -903,11 +702,7 @@ router.put("/:id/:action/:value?", async (req, res) => { break; } - for (let key in game.players) { - game.players[key].order = 0; - delete game.players[key].orderRoll; - delete game.players[key].orderStatus; - } + resetGame(game); message = `${name} requested to start the game.`; addChatMessage(game, null, message); @@ -1016,6 +811,39 @@ const sendGame = async (req, res, game, error) => { return res.status(200).send(playerGame); } +const resetGame = (game) => { + delete game.turn; + + game.state = 'lobby'; + + game.status = { + corners: [], + roads: [] + }; + + for (let i = 0; i < layout.corners.length; i++) { + game.status.corners[i] = { + color: undefined, + type: undefined + }; + } + + for (let i = 0; i < layout.roads.length; i++) { + game.status.roads[i] = { + color: undefined, + type: undefined + }; + } + + for (let key in game.players) { + game.players[key].order = 0; + delete game.players[key].orderRoll; + delete game.players[key].orderStatus; + } + + delete game.turn; +} + const createGame = (id) => { /* Look for a new game with random words that does not already exist */ while (!id) { @@ -1061,6 +889,8 @@ const createGame = (id) => { game[field] = assetData[field] }); + resetGame(game); + games[game.id] = game; shuffleBoard(game); console.log(`New game created: ${game.id}`);