From 6a7902c32fe10881c1c9ee0a155a68c9cdb94af0 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 29 Jun 2022 09:06:57 -0700 Subject: [PATCH] Add clearGame if only one player in game Signed-off-by: James Ketrenos --- client/src/Actions.js | 8 ++ client/src/Board.js | 26 ++++-- server/ai/app.js | 49 ++++++++++- server/routes/games.js | 183 +++++++++++++++++++++++------------------ server/rules | 5 +- 5 files changed, 182 insertions(+), 89 deletions(-) diff --git a/client/src/Actions.js b/client/src/Actions.js index 30f2746..82fb2b4 100644 --- a/client/src/Actions.js +++ b/client/src/Actions.js @@ -148,6 +148,13 @@ const Actions = ({ if (buildActive) setBuildActive(false); }; + const resetGame = () => { + sendMessage({ + type: 'goto-lobby' + }); + if (buildActive) setBuildActive(false); + }; + if (!gameId) { return (); } @@ -200,6 +207,7 @@ const Actions = ({ { edit === "" && }
+ { name && active === 1 && } { name && inLobby && <> diff --git a/client/src/Board.js b/client/src/Board.js index ab4458a..8e72a00 100644 --- a/client/src/Board.js +++ b/client/src/Board.js @@ -25,6 +25,15 @@ const borderImageWidth = (2 + 2/3) * tileImageWidth, /* 2.667 * .Tile.width */ borderImageHeight = borderImageWidth * 0.29; /* 0.29 * .Border.height */ + +const showTooltip = () => { + document.querySelector('.Board .Tooltip').style.display = 'flex'; +}; + +const clearTooltip = () => { + document.querySelector('.Board .Tooltip').style.display = 'none'; +}; + const Board = () => { const { ws } = useContext(GlobalContext); const board = useRef(); @@ -237,6 +246,13 @@ const Board = () => { const Corner = ({corner}) => { return
{ + if (e.shiftPressed) { + const tooltip = document.querySelector('.Board .Tooltip'); + tooltip.innerHTML = `
${corner}
`; + showTooltip(); + } + }} onClick={(event) => { onCornerClicked(event, corner) }} data-index={corner.index} style={{ @@ -538,7 +554,7 @@ const Board = () => { if (tile.type === 'wheat') { div =
- { }); }; - const showTooltip = () => { - document.querySelector('.Board .Tooltip').style.display = 'flex'; - } - - const clearTooltip = () => { - document.querySelector('.Board .Tooltip').style.display = 'none'; - } - const calculateBorderSlot = (side, e) => { const borderBox = document.querySelector('.Borders').getBoundingClientRect(); let angle = (360 + Math.floor(90 + Math.atan2(e.pageY - borderBox.top, e.pageX - borderBox.left) * 180 / Math.PI)) % 360 - (side * 60); diff --git a/server/ai/app.js b/server/ai/app.js index ea911fc..3322536 100644 --- a/server/ai/app.js +++ b/server/ai/app.js @@ -5,6 +5,7 @@ const calculateLongestRoad = require('./longest-road.js'); const { getValidRoads, getValidCorners } = require('../util/validLocations.js'); const { layout, staticData } = require('../util/layout.js'); +const { turn } = require('core-js/core/array'); const version = '0.0.1'; @@ -461,6 +462,17 @@ const processWaitingFor = (waitingFor) => { received = {}; } + +const selectResources = async (received) => { + if (!game.turn) { + return { turn: anyValue }; + } + + if (!game.turn.actions || game.turn.actions.indexOf('select-resources') === -1) { + return; + } +} + const processDiscard = async (received) => { if (!game.players) { waitingFor = { @@ -612,6 +624,29 @@ const processTrade = async (received) => { }; } +const processVolcano = async (received) => { + if (!game.turn || !game.private) { + return { + turn: anyValue, + private: anyValue + } + }; + + if (game.turn.actions + && game.turn.actions.indexOf('select-resources') !== -1) { + console.log(`${name} - TODO - select resources -`, game.turn.select); + return; + } + + send({ + type: 'roll' + }); + + return { + turn: anyValue + }; +}; + const processNormal = async (received) => { let waitingFor = undefined; @@ -628,6 +663,11 @@ const processNormal = async (received) => { return waitingFor; } + waitingFor = await selectResources(received); + if (waitingFor) { + return waitingFor; + } + /* From here on it is only actions that occur on the player's turn */ if (!received.turn || received.turn.color !== game.color) { console.log(`${name} - waiting for turn... ${game.players[game.turn.color].name} is active.`); @@ -858,7 +898,14 @@ const message = async (data) => { processWaitingFor(waitingFor); } return; - + + case 'volcano': + waitingFor = await processVolcano(received); + if (waitingFor) { + processWaitingFor(waitingFor); + } + return; + case 'normal': waitingFor = await processNormal(received); if (waitingFor) { diff --git a/server/routes/games.js b/server/routes/games.js index 61657d9..a638969 100755 --- a/server/routes/games.js +++ b/server/routes/games.js @@ -415,7 +415,7 @@ const processRoll = (game, session, dice) => { } if (isRuleEnabled(game, 'volcano')) { - if (sum === game.rules['volcano'].number + if (sum === parseInt(game.rules['volcano'].number) || (synonym && (game.rules['volcano'].number === 2 || game.rules['volcano'].number === 12))) { @@ -709,6 +709,17 @@ const adminCommands = (game, action, value, query) => { switch (action) { case 'rules': const rule = value.replace(/=.*$/, ''); + if (rule === 'list') { + const rules = {}; + for (let key in supportedRules) { + if (game.rules[key]) { + rules[key] = game.rules[key]; + } else { + rules[key] = { enabled: false }; + } + } + return JSON.stringify(rules, null, 2); + } let values = value.replace(/^.*=/, '').split(','); const rules = {}; rules[rule] = {}; @@ -2768,6 +2779,79 @@ const getVictoryPointRule = (game) => { return game.rules['victory-points'].points; } +const supportedRules = { + 'victory-points': (game, session, rules) => { + if (!('points' in rules[rule])) { + return `No points specified for victory-points`; + } + if (!rules[rule].enabled) { + addChatMessage(game, null, + `${getName(session)} has disabled the Victory Point ` + + `house rule.`); + } else { + addChatMessage(game, null, + `${getName(session)} set the minimum Victory Points to ` + + `${rules[rule].points}`); + } + }, + 'roll-double-roll-again': (game, session, rules) => { + addChatMessage(game, null, + `${getName(session)} has ${rules[rule].enabled ? 'en' : 'dis'}abled the Roll Double, Roll Again house rule.`); + }, + 'volcano': (game, session, rules) => { + if (!rules[rule].enabled) { + addChatMessage(game, null, + `${getName(session)} has disabled the Volcano ` + + `house rule.`); + } else { + if (!(rule in game.rules) || !game.rules[rule].enabled) { + addChatMessage(game, null, + `${getName(session)} enabled the Volcano ` + + `house rule with roll set to ` + + `${rules[rule].number} and 'Volanoes have gold' mode ` + + `${rules[rule].gold ? 'en' : 'dis'}abled.`); + } else { + if (game.rules[rule].number !== rules[rule].number) { + addChatMessage(game, null, + `${getName(session)} set the Volcano roll to ` + + `${rules[rule].number}`); + } + + if (game.rules[rule].gold !== rules[rule].gold) { + addChatMessage(game, null, + `${getName(session)} has ` + + `${rules[rule].gold ? 'en' : 'dis'}abled the ` + + `'Volcanoes have gold' mode.`); + } + } + } + }, + 'twelve-and-two-are-synonyms': (game, session, rules) => { + addChatMessage(game, null, + `${getName(session)} has ${rules[rule].enabled ? 'en' : 'dis'}abled the Twelve and Two are Synonyms house rule.`); + game.rules[rule] = rules[rule]; + }, + 'most-developed': (game, session, rules) => { + addChatMessage(game, null, + `${getName(session)} has ${rules[rule].enabled ? 'en' : 'dis'}abled the Most Developed house rule.`); + }, + 'port-of-call': (game, session, rules) => { + addChatMessage(game, null, + `${getName(session)} has ${rules[rule].enabled ? 'en' : 'dis'}abled the Another Round of Port house rule.`); + }, + 'tiles-start-facing-down': (game, session, rules) => { + addChatMessage(game, null, + `${getName(session)} has ${rules[rule].enabled ? 'en' : 'dis'}abled the Tiles Start Facing Down house rule.`); + if (rules[rule].enabled) { + shuffle(game, session); + } + }, + 'robin-hood-robber': (game, session, rules) => { + addChatMessage(game, null, + `${getName(session)} has ${rules[rule].enabled ? 'en' : 'dis'}abled the Robin Hood Robber house rule.`); + } +}; + const setRules = (game, session, rules) => { if (game.state !== 'lobby') { return `You can not modify House Rules once the game has started.`; @@ -2778,85 +2862,13 @@ const setRules = (game, session, rules) => { continue; } - switch (rule) { - case 'victory-points': - if (!('points' in rules[rule])) { - return `No points specified for victory-points`; - } - if (!rules[rule].enabled) { - addChatMessage(game, null, - `${getName(session)} has disabled the Victory Point ` + - `house rule.`); - } else { - addChatMessage(game, null, - `${getName(session)} set the minimum Victory Points to ` + - `${rules[rule].points}`); + if (rule in supportedRules) { + const warning = supportedRules[rule](game, session, rules); + if (warning) { + return warning; } game.rules[rule] = rules[rule]; - break; - case 'roll-double-roll-again': - addChatMessage(game, null, - `${getName(session)} has ${rules[rule].enabled ? 'en' : 'dis'}abled the Roll Double, Roll Again house rule.`); - game.rules[rule] = rules[rule]; - break; - case 'volcano': - if (!rules[rule].enabled) { - addChatMessage(game, null, - `${getName(session)} has disabled the Volcano ` + - `house rule.`); - } else { - if (!(rule in game.rules) || !game.rules[rule].enabled) { - addChatMessage(game, null, - `${getName(session)} enabled the Volcano ` + - `house rule with roll set to ` + - `${rules[rule].number} and 'Volanoes have gold' mode ` + - `${rules[rule].gold ? 'en' : 'dis'}abled.`); - } else { - if (game.rules[rule].number !== rules[rule].number) { - addChatMessage(game, null, - `${getName(session)} set the Volcano roll to ` + - `${rules[rule].number}`); - } - - if (game.rules[rule].gold !== rules[rule].gold) { - addChatMessage(game, null, - `${getName(session)} has ` + - `${rules[rule].gold ? 'en' : 'dis'}abled the ` + - `'Volcanoes have gold' mode.`); - } - } - } - game.rules[rule] = rules[rule]; - break; - case 'twelve-and-two-are-synonyms': - addChatMessage(game, null, - `${getName(session)} has ${rules[rule].enabled ? 'en' : 'dis'}abled the Twelve and Two are Synonyms house rule.`); - game.rules[rule] = rules[rule]; - break; - case 'most-developed': - addChatMessage(game, null, - `${getName(session)} has ${rules[rule].enabled ? 'en' : 'dis'}abled the Most Developed house rule.`); - game.rules[rule] = rules[rule]; - break; - case 'port-of-call': - addChatMessage(game, null, - `${getName(session)} has ${rules[rule].enabled ? 'en' : 'dis'}abled the Another Round of Port house rule.`); - game.rules[rule] = rules[rule]; - break; - case 'tiles-start-facing-down': - addChatMessage(game, null, - `${getName(session)} has ${rules[rule].enabled ? 'en' : 'dis'}abled the Tiles Start Facing Down house rule.`); - if (rules[rule].enabled) { - shuffle(game, session); - } - game.rules[rule] = rules[rule]; - break; - case 'robin-hood-robber': - addChatMessage(game, null, - `${getName(session)} has ${rules[rule].enabled ? 'en' : 'dis'}abled the Robin Hood Robber house rule.`); - game.rules[rule] = rules[rule]; - break; - default: + } else { return `Rule ${rule} not recognized.`; } } @@ -3762,6 +3774,14 @@ const calculatePoints = (game, update) => { } } +const clearGame = (game, session) => { + resetGame(game); + addChatMessage(game, null, + `The game has been reset. You can play again with this board, or ` + + `click 'New board' to mix things up a bit.`); + sendGameToPlayers(game); +}; + const gotoLobby = (game, session) => { if (!game.waiting) { game.waiting = []; @@ -4261,6 +4281,13 @@ router.ws("/ws/:id", async (ws, req) => { sendWarning(session, warning); } break; + case 'clear-game': + console.log(`${short}: <- clear-game:${getName(session)}`); + warning = clearGame(game, session); + if (warning) { + sendWarning(session, warning); + } + break; case 'goto-lobby': console.log(`${short}: <- goto-lobby:${getName(session)}`); warning = gotoLobby(game, session); diff --git a/server/rules b/server/rules index 98e1ab1..48ada23 100755 --- a/server/rules +++ b/server/rules @@ -12,9 +12,12 @@ shift params="${*}" params="${params// /,}" +if [[ "${rule}" == "list" ]]; then + params=" " +fi if [[ "${id}" == "" ]] || [[ "${rule}" == "" ]] || [[ "${params}" == "" ]]; then cat << EOF -Usage: rules GAME-ID RULE KEY:VALUE [KEY:VALUE] +Usage: rules GAME-ID [(list)|(RULE KEY:VALUE [KEY:VALUE])] Examples: