From 54e1a51c0477497573493f568e5b70815a70a766 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Sat, 26 Feb 2022 02:57:08 -0800 Subject: [PATCH] Added Velocirobber Fixed several robber and admin related commands Signed-off-by: James Ketrenos --- client/src/Board.css | 42 +++++--- client/src/Board.js | 9 +- client/src/assets/raptor-robber.png | Bin 0 -> 30035 bytes server/routes/games.js | 145 +++++++++++++++++----------- 4 files changed, 124 insertions(+), 72 deletions(-) create mode 100755 client/src/assets/raptor-robber.png diff --git a/client/src/Board.css b/client/src/Board.css index a179c32..7392a19 100644 --- a/client/src/Board.css +++ b/client/src/Board.css @@ -43,14 +43,30 @@ transform: translate(-50%, -50%); } +.Pip.Option { + filter: brightness(150%); +} + .Pip.Active { filter: drop-shadow(0px 0px 10px rgba(255, 0, 255, 1)); } + +.Pip.Option:hover, +.Pip:hover { + filter: brightness(100%); +} + +.Pip.Active:hover { + filter: drop-shadow(0px 0px 10px rgba(255, 0, 255, 1)); +} + + .Pip.Active.Option { filter: brightness(150%) drop-shadow(0px 0px 10px rgba(255, 0, 255, 1)); } + .Pips[disabled], .Tiles[disabled], .Roads[disabled], @@ -121,6 +137,7 @@ top: 0px; bottom: 0px; clip-path: circle(50%); + pointer-events: none; } .Tile-Shape { @@ -139,37 +156,38 @@ filter: brightness(115%); } -.Option .Pip-Shape, .Option .Tile-Shape, .Option .Corner-Shape, .Option .Road-Shape { background-color: rgba(255, 255, 255, 0.5); } -.Robber .Pip-Shape, -.Pip-Shape:hover { - clip-path: circle(45%); /* show through the border */ +.Robber .Pip-Shape { + top: -2em; + left: -2em; + clip-path: circle(50%); + transform: scale(0.45); background-color:#e7c099; background-size: contain; background-position: center; + border: 0.2em solid #8c471f; + border-radius: 50%; } +.Roberta .Pip-Shape:hover, .Roberta .Pip-Shape { - top: -2em; - left: -2em; - clip-path: circle(50%); - transform: scale(0.45); background-image:url("./assets/woman-robber.png"); } +.Robert .Pip-Shape:hover, .Robert .Pip-Shape { - top: -2em; - left: -2em; - clip-path: circle(50%); - transform: scale(0.45); background-image:url("./assets/man-robber.png"); } +.Velocirobber .Pip-Shape { + background-image:url("./assets/raptor-robber.png"); +} + .Tile-Shape:hover, .Corner-Shape:hover, .Road-Shape:hover { diff --git a/client/src/Board.js b/client/src/Board.js index a4957bc..a1dc7c2 100644 --- a/client/src/Board.js +++ b/client/src/Board.js @@ -481,18 +481,19 @@ const Board = ({ table, game }) => { } if (game) { - let robberClass = game.gender === 'female' ? 'Roberta' : 'Robert'; let nodes = document.querySelectorAll(`.Pip.Robber`); for (let i = 0; i < nodes.length; i++) { nodes[i].classList.remove('Robber'); - nodes[i].classList.remove(robberClass); + [ 'Robert', 'Roberta', 'Velocirobber' ].forEach(robberName => + nodes[i].classList.remove(robberName) + ); } - if (game.robber) { + if (game.robber !== undefined) { const el = document.querySelector(`.Pip[data-index="${game.robber}"]`); if (el) { el.classList.add('Robber'); - el.classList.add(robberClass); + el.classList.add(game.robberName); } } } diff --git a/client/src/assets/raptor-robber.png b/client/src/assets/raptor-robber.png new file mode 100755 index 0000000000000000000000000000000000000000..bb8fad8c5562a4737b4e852fde38a62a2a60abf5 GIT binary patch literal 30035 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 literal 0 HcmV?d00001 diff --git a/server/routes/games.js b/server/routes/games.js index dff6a1f..acea515 100755 --- a/server/routes/games.js +++ b/server/routes/games.js @@ -304,7 +304,7 @@ const distributeResources = (game, roll) => { let index = game.pipOrder[i]; if (assetData.pips[index].roll === roll) { if (game.robber === i) { - addChatMessage(game, null, `That pesky Robber stole resources!`); + addChatMessage(game, null, `That pesky ${game.robberName} Roberson stole resources!`); } else { tiles.push(i); } @@ -350,6 +350,21 @@ const distributeResources = (game, roll) => { } } +const pickRobber = (game) => { + const selection = Math.floor(Math.random() * 3); + switch (selection) { + case 0: + game.robberName = 'Robert'; + break; + case 1: + game.robberName = 'Roberta'; + break; + case 2: + game.robberName = 'Velocirobber'; + break; + } +} + const processRoll = (game, dice) => { let session; for (let id in game.sessions) { @@ -365,38 +380,40 @@ const processRoll = (game, dice) => { addChatMessage(game, session, `${session.name} rolled ${game.dice[0]}, ${game.dice[1]}.`); game.turn.roll = game.dice[0] + game.dice[1]; if (game.turn.roll === 7) { - addChatMessage(game, null, `ROBBER! ${game.gender === 'female' ? 'Roberta' : 'Robert'} Robber Roberson!`); game.turn.robberInAction = true; delete game.turn.placedRobber; + const mustDiscard = []; + for (let id in game.sessions) { const player = game.sessions[id].player; if (player) { let discard = player.stone + player.wheat + player.brick + player.wood + player.sheep; if (discard > 7) { discard = Math.floor(discard / 2); - player.mustDiscard = discard; - addChatMessage(game, null, `${game.sessions[id].name} must discard ${discard} resource cards.`); + mustDiscard.push(player); } else { delete player.mustDiscard; } } } - /* - if you roll a 7, no one receives any resource cards. - instead, every player who has more than 7 resource cards must select - half (rounded down) of their - resource cards and return them to the bank. - then you muyst move the robber: - 1. you must move the robber immediately to the number token of any other - terrain ohex or to the desert hex, - 2. you then steal 1 (random) resourcde card from an opponent who has a settlement or city - adjacent to the target terrain hex. the player who is robbed holds their resource cards - face down. you then take 1 card at random. if the target hex is adjacent to 2 or - more player's settlements or cities, you choose which one you want to steal from. - If the production number for the hex containing the robber is rolled, the owners of - adjacent settlements and citieis do not receive resourcres. The robber prevents it. - */ + + if (mustDiscard.length === 0) { + addChatMessage(game, null, `ROBBER! ${game.robberName} Robber Roberson has fled, and no one had to discard!`); + addChatMessage(game, null, `But drat! A new robber has arrived and must be placed by ${game.turn.name}.`); + game.turn.actions = [ 'place-robber' ]; + game.turn.limits = { pips: [] }; + for (let i = 0; i < 19; i++) { + if (i === game.robber) { + continue; + } + game.turn.limits.pips.push(i); + } + } else { + mustDiscard.forEach(player => + addChatMessage(game, null, `${getPlayerName(game, player)} must discard ${player.mustDiscard} resource cards the robber steals while fleeing!`) + ); + } } else { distributeResources(game, game.turn.roll); } @@ -582,20 +599,22 @@ const adminActions = (game, action, value) => { if (!session) { return `Unable to determine current player turn to give resources.`; } - if (type in session.player) { + + if ([ 'wheat', 'sheep', 'wood', 'stone', 'brick' ].indexOf(type) !== -1) { const count = parseInt(card); - session.player[card] += count; + session.player[type] += count; addChatMessage(game, null, `Admin gave ${count} ${type} to ${game.turn.name}.`); break; } const index = game.developmentCards.findIndex(item => - item.card === card && item.type === type); + item.card.toString() === card && item.type === type); if (index === -1) { console.log({ card, type}, game.developmentCards); return `Unable to find ${type}-${card} in the current deck of development cards.`; } + let tmp = game.developmentCards.splice(index, 1)[0]; tmp.turn = game.turns ? game.turns - 1 : 0; session.player.development.push(tmp); @@ -1203,7 +1222,7 @@ const getValidRoads = (game, color) => { return limits; } -const isCompatibleOffer = (player, offer) => { +const isCompatibleOffer = (game, player, offer) => { const isBank = offer.name === 'The bank'; let valid = player.gets.length === offer.gives.length && player.gives.length === offer.gets.length; @@ -1214,7 +1233,7 @@ const isCompatibleOffer = (player, offer) => { } console.log({ - player: getPlayerName(player), + player: getPlayerName(game, player), gets: player.gets, gives: player.gives }, { @@ -1274,11 +1293,11 @@ const isSameOffer = (player, offer) => { return same; }; -const checkOffer = (player, offer) => { +const checkOffer = (game, player, offer) => { let error = undefined; console.log({ - player: getPlayerName(player), + player: getPlayerName(game, player), gets: player.gets, gives: player.gives }, { @@ -1476,7 +1495,7 @@ router.put("/:id/:action/:value?", async (req, res) => { if (value === 'offer') { const offer = req.body; - error = checkOffer(session.player, offer); + error = checkOffer(game, session.player, offer); if (error) { break; } @@ -1519,7 +1538,7 @@ router.put("/:id/:action/:value?", async (req, res) => { const offer = req.body; let target; - error = checkOffer(session.player, offer); + error = checkOffer(game, session.player, offer); if (error) { break; } @@ -1553,7 +1572,7 @@ router.put("/:id/:action/:value?", async (req, res) => { /* Verify the requesting offer wasn't jacked --\ * make sure the target.gives === player.gets and target.gives === player.gets */ - if (!isCompatibleOffer(player, target)) { + if (!isCompatibleOffer(game, player, target)) { error = `The requested offer does not match the negotiated terms!`; break; } @@ -1662,7 +1681,9 @@ router.put("/:id/:action/:value?", async (req, res) => { } game.robber = robber; game.turn.placedRobber = true; - addChatMessage(game, session, `Robber has been moved!`); + + pickRobber(game); + addChatMessage(game, session, `${game.robberName} Robber Robinson entered the scene as the nefarious robber!`); let colors = []; layout.tiles[robber].corners.forEach(cornerIndex => { @@ -1680,7 +1701,8 @@ router.put("/:id/:action/:value?", async (req, res) => { game.turn.actions = []; game.turn.robberInAction = false; delete game.turn.limits; - addChatMessage(game, session, `The Robber was moved to a terrain with no other players.`); + addChatMessage(game, session, `The dread robber ${game.robberName} was placed on a terrain with no other players, ` + + `so ${game.turn.name} does not steal resources from anyone.`); } break; @@ -1855,7 +1877,16 @@ router.put("/:id/:action/:value?", async (req, res) => { game.turn.robberInAction = true; delete game.turn.placedRobber; - addChatMessage(game, session, `${session.name} must now move the robber.`); + addChatMessage(game, session, `The robber ${game.robberName} has fled before the power of the Knight, ` + + `but a new robber has returned and ${session.name} must now place them.`); + game.turn.actions = [ 'place-robber' ]; + game.turn.limits = { pips: [] }; + for (let i = 0; i < 19; i++) { + if (i === game.robber) { + continue; + } + game.turn.limits.pips.push(i); + } } break; @@ -2323,7 +2354,29 @@ router.put("/:id/:action/:value?", async (req, res) => { addChatMessage(game, null, `${session.name} discarded ${sum} resource cards.`); if (player.mustDiscard) { addChatMessage(game, null, `${session.name} must discard ${player.mustDiscard} more cards.`); + break; } + + let move = true; + for (let color in game.players) { + const discard = game.players[color].mustDiscard; + if (discard) { + move = false; + } + } + + if (move) { + addChatMessage(game, null, `Drat! A new robber has arrived and must be placed by ${game.turn.name}!`); + game.turn.actions = [ 'place-robber' ]; + game.turn.limits = { pips: [] }; + for (let i = 0; i < 19; i++) { + if (i === game.robber) { + continue; + } + game.turn.limits.pips.push(i); + } + } + break; case "state": @@ -2423,28 +2476,6 @@ const sendGame = async (req, res, game, error) => { } game.active = active; - /* If the current turn is a robber placement, and everyone has - * discarded, set the limits for where the robber can be placed */ - if (game.turn && game.turn.robberInAction) { - let move = true; - for (let color in game.players) { - const discard = game.players[color].mustDiscard; - if (discard) { - move = false; - } - } - if (move && !game.turn.placedRobber) { - game.turn.actions = [ 'place-robber' ]; - game.turn.limits = { pips: [] }; - for (let i = 0; i < 19; i++) { - if (i === game.robber) { - continue; - } - game.turn.limits.pips.push(i); - } - } - } - /* Update the session lastActive clock */ let session; if (req.session) { @@ -2708,7 +2739,7 @@ router.post("/:id?", (req, res/*, next*/) => { }); const setBeginnerGame = (game) => { - game.gender = Math.random() > 0.5 ? 'male' : 'female'; + pickRobber(game); shuffle(game.developmentCards); game.borderOrder = []; for (let i = 0; i < 6; i++) { @@ -2721,6 +2752,8 @@ const setBeginnerGame = (game) => { 4, 11, 7, 14, 18, 8, 15 ]; + game.robber = 9; + game.pipOrder = [ 5, 1, 6, 7, 2, 9, 11, @@ -2732,7 +2765,7 @@ const setBeginnerGame = (game) => { } const shuffleBoard = (game, beginnersGame) => { - game.gender = Math.random() > 0.5 ? 'male' : 'female'; + pickRobber(game); const seq = []; for (let i = 0; i < 6; i++) {