From 9633e48f21f2cbaadd239d0ac2e37c78936c1dc5 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Sat, 12 Mar 2022 16:06:38 -0800 Subject: [PATCH] place-road and place-settlement are working Signed-off-by: James Ketrenos --- client/src/Board.css | 2 +- client/src/Board.js | 2 + server/routes/games.js | 366 ++++++++++++++++++++++------------------- 3 files changed, 201 insertions(+), 169 deletions(-) diff --git a/client/src/Board.css b/client/src/Board.css index 1097b98..03b1c21 100644 --- a/client/src/Board.css +++ b/client/src/Board.css @@ -148,7 +148,7 @@ clip-path: polygon(25% 0%,75% 0%,100% 50%,75% 100%,25% 100%,0% 50%); } -div[disabled] .Option { +.Board div[disabled] .Option { cursor: pointer; pointer-events: none; } diff --git a/client/src/Board.js b/client/src/Board.js index 65734cd..a84d95b 100644 --- a/client/src/Board.js +++ b/client/src/Board.js @@ -528,6 +528,7 @@ const Board = () => { borderOrder, borders, pipOrder, pips, tileOrder, tiles ]); + console.log(`board - todo - look into debouncing the direct DOM update`); if (turn) { let nodes = document.querySelectorAll('.Active'); for (let i = 0; i < nodes.length; i++) { @@ -584,6 +585,7 @@ const Board = () => { el.setAttribute('data-color', road.color); } }); + /* Clear all 'Option' targets */ let nodes = document.querySelectorAll(`.Option`); for (let i = 0; i < nodes.length; i++) { diff --git a/server/routes/games.js b/server/routes/games.js index 85346fa..25c6fac 100755 --- a/server/routes/games.js +++ b/server/routes/games.js @@ -202,7 +202,7 @@ const processGameOrder = (game, player, dice) => { name: players[0].name, color: players[0].color }; - getValidSettlementPlacements(game, getValidCorners(game)); + setForSettlementPlacement(game, getValidCorners(game)); addActivity(game, null, `${game.robberName} Robber Robinson entered the scene as the nefarious robber!`); addChatMessage(game, null, `Initial settlement placement has started!`); addChatMessage(game, null, `It is ${game.turn.name}'s turn to place a settlement.`);4 @@ -619,7 +619,7 @@ const adminActions = (game, action, value) => { return `There are no valid locations for ${game.turn.name} to place a road.`; } game.turn.free = true; - placeRoad(game, roads); + setForRoadPlacement(game, roads); addChatMessage(game, null, `Admin gave a road to ${game.turn.name}.` + `They must now place the road.`); break; @@ -638,7 +638,7 @@ const adminActions = (game, action, value) => { } corners = getValidCorners(game, session.color, 'settlement'); game.turn.free = true; - placeCity(game, corners); + setForCityPlacement(game, corners); addChatMessage(game, null, `Admin gave a city to ${game.turn.name}. ` + `They must now place the city.`); break; @@ -656,7 +656,7 @@ const adminActions = (game, action, value) => { return `There are no valid locations for ${game.turn.name} to place a settlement.`; } game.turn.free = true; - getValidSettlementPlacements(game, corners); + setForSettlementPlacement(game, corners); addChatMessage(game, null, `Admin gave a settlment to ${game.turn.name}. ` + `They must now place the settlement.`); break; @@ -1620,17 +1620,17 @@ const offerToString = (offer) => { offer.gets.map(item => `${item.count} ${item.type}`).join(', '); } -const placeRoad = (game, limits) => { +const setForRoadPlacement = (game, limits) => { game.turn.actions = [ 'place-road' ]; game.turn.limits = { roads: limits }; } -const placeCity = (game, limits) => { +const setForCityPlacement = (game, limits) => { game.turn.actions = [ 'place-city' ]; game.turn.limits = { corners: limits }; } -const getValidSettlementPlacements = (game, limits) => { +const setForSettlementPlacement = (game, limits) => { game.turn.actions = [ 'place-settlement' ]; game.turn.limits = { corners: limits }; } @@ -2069,7 +2069,7 @@ const playCard = (game, session, { card }) => { game.turn.free = true; game.turn.freeRoads = allowed; addChatMessage(game, session, `${session.name} played a Road Building card. They now place ${allowed} roads for free.`); - placeRoad(game, roads); + setForRoadPlacement(game, roads); break; case 'monopoly': game.turn.actions = [ 'select-resources' ]; @@ -2117,15 +2117,16 @@ const playCard = (game, session, { card }) => { } } -const placeSettlement = (game, session, value) => { +const placeSettlement = (game, session, index) => { const player = session.player; + index = parseInt(index); if (game.state !== 'initial-placement' && game.state !== 'normal') { return `You cannot place an item unless the game is active.`; } if (session.color !== game.turn.color) { return `It is not your turn! It is ${game.turn.name}'s turn.`; } - index = parseInt(value); + if (game.placements.corners[index] === undefined) { return `You have requested to place a settlement illegally!`; } @@ -2133,7 +2134,7 @@ const placeSettlement = (game, session, value) => { if (game.turn && game.turn.limits && game.turn.limits.corners && game.turn.limits.corners.indexOf(index) === -1) { return `You tried to cheat! You should not try to break the rules.`; } - corner = game.placements.corners[index]; + const corner = game.placements.corners[index]; if (corner.color) { return `This location already has a settlement belonging to ${game.players[corner.color].name}!`; } @@ -2227,15 +2228,174 @@ const placeSettlement = (game, session, value) => { `${session.name} placed a settlement by a maritime bank that trades ${bankType}. ` + `Next, they need to place a road.`); } else { - addActivity(game, session, `${name} placed a settlement. ` + + addActivity(game, session, `${session.name} placed a settlement. ` + `Next, they need to place a road.`); } - placeRoad(game, layout.corners[index].roads); + setForRoadPlacement(game, layout.corners[index].roads); } sendUpdateToPlayers(game, { placements: game.placements, turn: game.turn, + chat: game.chat + }); + sendUpdateToPlayer(session, { + private: game.player + }); +} + +const placeRoad = (game, session, index) => { + const player = session.player; + index = parseInt(index); + if (game.state !== 'initial-placement' && game.state !== 'normal') { + return `You cannot place an item unless the game is active.`; + } + if (session.color !== game.turn.color) { + return `It is not your turn! It is ${game.turn.name}'s turn.`; + } + + if (game.placements.roads[index] === undefined) { + return `You have requested to place a road illegally!`; + } + /* If this is not a valid road in the turn limits, discard it */ + if (game.turn && game.turn.limits && game.turn.limits.roads && game.turn.limits.roads.indexOf(index) === -1) { + return `You tried to cheat! You should not try to break the rules.`; + } + const road = game.placements.roads[index]; + if (road.color) { + return `This location already has a road belonging to ${game.players[road.color].name}!`; + } + + if (game.state === 'normal') { + if (!game.turn.free) { + if (player.brick < 1 || player.wood < 1) { + return `You have insufficient resources to build a road.`; + } + } + if (player.roads < 1) { + return `You have already built all of your roads.`; + } + + debugChat(game, 'Before road purchase'); + + player.roads--; + if (!game.turn.free) { + addChatMessage(game, session, `${session.name} spent 1 brick, 1 wood to purchase a road.`) + player.brick--; + player.wood--; + player.resources = 0; + [ 'wheat', 'brick', 'sheep', 'stone', 'wood' ].forEach(resource => { + player.resources += player[resource]; + }); + } + + debugChat(game, 'After road purchase'); + + road.color = session.color; + addActivity(game, session, `${session.name} placed a road.`); + calculateRoadLengths(game, session); + + let resetLimits = true; + if (game.turn.active === 'road-building') { + game.turn.freeRoads--; + if (game.turn.freeRoads === 0) { + delete game.turn.free; + delete game.turn.active; + delete game.turn.freeRaods; + } + + let roads = getValidRoads(game, session.color); + if (roads.length === 0) { + delete game.turn.active; + delete game.turn.freeRaods; + addActivity(game, session, `${session.name} has another road to play, but there are no more valid locations.`); + } else if (game.turn.freeRoads !== 0) { + game.turn.free = true; + setForRoadPlacement(game, roads); + resetLimits = false; + } + } + + if (resetLimits) { + delete game.turn.free; + game.turn.actions = []; + game.turn.limits = {}; + } + } else if (game.state === 'initial-placement') { + road.color = session.color; + addActivity(game, session, `${session.name} placed a road.`); + calculateRoadLengths(game, session); + + let next; + if (game.direction === 'forward' && getLastPlayerName(game) === session.name) { + game.direction = 'backward'; + next = session.name; + } else if (game.direction === 'backward' && getFirstPlayerName(game) === session.name) { + /* Done! */ + delete game.direction; + } else { + if (game.direction === 'forward') { + next = getNextPlayer(game, session.name); + } else { + next = getPrevPlayer(game, session.name); + } + } + if (next) { + game.turn = { + name: next, + color: getColorFromName(game, next) + }; + setForSettlementPlacement(game, getValidCorners(game)); + calculateRoadLengths(game, session); + addChatMessage(game, null, `It is ${next}'s turn to place a settlement.`); + } else { + game.turn = { + actions: [], + limits: { }, + name: session.name, + color: getColorFromName(game, session.name) + }; + + addChatMessage(game, null, `Everyone has placed their two settlements!`); + + /* Figure out which players received which resources */ + for (let id in game.sessions) { + const session = game.sessions[id], player = session.player, + receives = {}; + if (!player) { + continue; + } + if (session.initialSettlement) { + layout.tiles.forEach((tile, index) => { + if (tile.corners.indexOf(session.initialSettlement) !== -1) { + const resource = staticData.tiles[game.tileOrder[index]].type; + if (!(resource in receives)) { + receives[resource] = 0; + } + receives[resource]++; + } + }); + let message = []; + for (let type in receives) { + player[type] += receives[type]; + player.resources += receives[type]; + message.push(`${receives[type]} ${type}`); + } + addChatMessage(game, session, `${session.name} receives ${message.join(', ')}.`); + } + } + addChatMessage(game, null, `It is ${session.name}'s turn.`); + game.state = 'normal'; + } + } + + sendUpdateToPlayers(game, { + placements: game.placements, + turn: game.turn, + chat: game.chat, + state: game.state, + longestRoad: game.longestRoad, + longestRoadLength: game.longestRoadLength }); sendUpdateToPlayer(session, { private: game.player @@ -2248,13 +2408,13 @@ const asdf = () => { case 'select-resources': if (!game || !game.turn || !game.turn.actions || game.turn.actions.indexOf('select-resources') === -1) { - error = `Please, let's not cheat. Ok?`; + return `Please, let's not cheat. Ok?`; console.log(game); break; } if (session.color !== game.turn.color) { - error = `It is not your turn! It is ${game.turn.name}'s turn.`; + return `It is not your turn! It is ${game.turn.name}'s turn.`; break; } @@ -2263,7 +2423,7 @@ const asdf = () => { cards = req.body; if (!cards || cards.length > count || cards.length === 0) { - error = `You have chosen the wrong number of cards!`; + return `You have chosen the wrong number of cards!`; break; } @@ -2376,7 +2536,7 @@ const asdf = () => { error = `There are no valid locations for you to place a settlement.`; break; } - getValidSettlementPlacements(game, corners); + setForSettlementPlacement(game, corners); addActivity(game, session, `${game.turn.name} is considering placing a settlement.`); break; @@ -2412,7 +2572,7 @@ const asdf = () => { error = `There are no valid locations for you to place a city.`; break; } - placeCity(game, corners); + setForCityPlacement(game, corners); addActivity(game, session, `${game.turn.name} is considering upgrading a settlement to a city.`); break; @@ -2510,155 +2670,10 @@ const asdf = () => { error = `There are no valid locations for you to place a road.`; break; } - placeRoad(game, roads); + setForRoadPlacement(game, roads); addActivity(game, session, `${game.turn.name} is considering building a road.`); break; - case 'place-road': - 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.color) { - error = `It is not your turn! It is ${game.turn.name}'s turn.`; - break; - } - index = parseInt(value); - if (game.placements.roads[index] === undefined) { - error = `You have requested to place a road illegally!`; - break; - } - /* If this is not a valid road in the turn limits, discard it */ - if (game.turn && game.turn.limits && game.turn.limits.roads && game.turn.limits.roads.indexOf(index) === -1) { - error = `You tried to cheat! You should not try to break the rules.`; - break; - } - const road = game.placements.roads[index]; - if (road.color) { - error = `This location already has a road belonging to ${game.players[road.color].name}!`; - break; - } - - if (game.state === 'normal') { - if (!game.turn.free) { - if (player.brick < 1 || player.wood < 1) { - error = `You have insufficient resources to build a road.`; - break; - } - } - if (player.roads < 1) { - error = `You have already built all of your roads.`; - break; - } - - debugChat(game, 'Before road purchase'); - - player.roads--; - if (!game.turn.free) { - addChatMessage(game, session, `${name} spent 1 brick, 1 wood to purchase a road.`) - player.brick--; - player.wood--; - player.resources = 0; - [ 'wheat', 'brick', 'sheep', 'stone', 'wood' ].forEach(resource => { - player.resources += player[resource]; - }); - } - - debugChat(game, 'After road purchase'); - - road.color = session.color; - addActivity(game, session, `${name} placed a road.`); - calculateRoadLengths(game, session); - - if (game.turn.active === 'road-building') { - game.turn.freeRoads--; - if (game.turn.freeRoads === 0) { - delete game.turn.free; - delete game.turn.active; - delete game.turn.freeRaods; - } - - let roads = getValidRoads(game, session.color); - if (roads.length === 0) { - delete game.turn.active; - delete game.turn.freeRaods; - addActivity(game, session, `${name} has another road to play, but there are no more valid locations.`); - } else if (game.turn.freeRoads !== 0) { - game.turn.free = true; - placeRoad(game, roads); - break; /* do not reset actions or limits -- player has another road to place! */ - } - } - delete game.turn.free; - game.turn.actions = []; - game.turn.limits = {}; - } else if (game.state === 'initial-placement') { - road.color = session.color; - addActivity(game, session, `${name} placed a road.`); - calculateRoadLengths(game, session); - - let next; - if (game.direction === 'forward' && getLastPlayerName(game) === name) { - game.direction = 'backward'; - next = name; - } else if (game.direction === 'backward' && getFirstPlayerName(game) === name) { - /* Done! */ - delete game.direction; - } else { - if (game.direction === 'forward') { - next = getNextPlayer(game, name); - } else { - next = getPrevPlayer(game, name); - } - } - if (next) { - game.turn = { - name: next, - color: getColorFromName(game, next) - }; - getValidSettlementPlacements(game, getValidCorners(game)); - calculateRoadLengths(game, session); - addChatMessage(game, null, `It is ${next}'s turn to place a settlement.`); - } else { - game.turn = { - actions: [], - limits: { }, - name: name, - color: getColorFromName(game, name) - }; - - addChatMessage(game, null, `Everyone has placed their two settlements!`); - - /* Figure out which players received which resources */ - for (let id in game.sessions) { - const session = game.sessions[id], player = session.player, - receives = {}; - if (!player) { - continue; - } - if (session.initialSettlement) { - layout.tiles.forEach((tile, index) => { - if (tile.corners.indexOf(session.initialSettlement) !== -1) { - const resource = staticData.tiles[game.tileOrder[index]].type; - if (!(resource in receives)) { - receives[resource] = 0; - } - receives[resource]++; - } - }); - let message = []; - for (let type in receives) { - player[type] += receives[type]; - player.resources += receives[type]; - message.push(`${receives[type]} ${type}`); - } - addChatMessage(game, session, `${session.name} receives ${message.join(', ')}.`); - } - } - addChatMessage(game, null, `It is ${name}'s turn.`); - game.state = 'normal'; - } - } break; case 'discard': @@ -3281,6 +3296,7 @@ const wsConnect = async (ws, req) => { break; case 'roll': + console.log(`${short}: <- roll:${getName(session)}`); warning = roll(game, session); if (warning) { sendWarning(session, warning); @@ -3306,14 +3322,28 @@ const wsConnect = async (ws, req) => { switch (data.type) { case 'shuffle': - error = shuffle(game, session); + console.log(`${short}: <- shuffle:${getName(session)}`); + warning = shuffle(game, session); if (error) { - sendWarning(session, error); + warning(session, error); } else { - sendGameToPlayers(game); + warning(game); + } + break; + case 'place-settlement': + console.log(`${short}: <- place-settlement:${getName(session)} ${data.index}`); + warning = placeSettlement(game, session, data.index); + if (warning) { + sendWarning(session, warning); + } + break; + case 'place-road': + console.log(`${short}: <- place-road:${getName(session)} ${data.index}`); + warning = placeRoad(game, session, data.index); + if (warning) { + sendWarning(session, warning); } break; - default: console.warn(`Unsupported request: ${data.type}`); break;