1
0

Lots of tweaks and fixes

Signed-off-by: James Ketrenos <james_eikona@ketrenos.com>
This commit is contained in:
James Ketrenos 2022-02-21 15:29:53 -08:00
parent 1fcad2f21f
commit e865133cc1
4 changed files with 161 additions and 45 deletions

View File

@ -545,7 +545,6 @@ class Table extends React.Component {
this.setPlayerName = this.setPlayerName.bind(this); this.setPlayerName = this.setPlayerName.bind(this);
this.setSelected = this.setSelected.bind(this); this.setSelected = this.setSelected.bind(this);
this.updateMessage = this.updateMessage.bind(this); this.updateMessage = this.updateMessage.bind(this);
this.gameSignature = this.gameSignature.bind(this);
this.sendAction = this.sendAction.bind(this); this.sendAction = this.sendAction.bind(this);
this.buildClicked = this.buildClicked.bind(this); this.buildClicked = this.buildClicked.bind(this);
this.closeCard = this.closeCard.bind(this); this.closeCard = this.closeCard.bind(this);
@ -821,21 +820,9 @@ class Table extends React.Component {
} }
gameSignature(game) {
if (!game) {
return "";
}
const signature =
game.borderOrder.map(border => Number(border).toString(16)).join('') + '-' +
game.pipOrder.map(pip => Number(pip).toString(16)).join('') + '-' +
game.tileOrder.map(tile => Number(tile).toString(16)).join('');
return signature;
};
updateGame(game) { updateGame(game) {
if (this.state.signature !== this.gameSignature(game)) { if (this.state.signature !== game.signature) {
game.signature = this.gameSignature(game); game.signature = game.signature;
} }
// console.log("Update Game", game); // console.log("Update Game", game);
this.setState( { game: game }); this.setState( { game: game });
@ -854,7 +841,7 @@ class Table extends React.Component {
case 'lobby': case 'lobby':
message = <>{message}You are in the lobby as&nbsp;<b>{name}</b>.</>; message = <>{message}You are in the lobby as&nbsp;<b>{name}</b>.</>;
if (!this.game.color) { if (!this.game.color) {
message = <>{message}You need to pick your color.</>; message = <>{message}You select one of the <b>Available</b> colors below.</>;
} else { } else {
message = <>{message}You have selected <PlayerColor color={this.game.color}/>.</>; message = <>{message}You have selected <PlayerColor color={this.game.color}/>.</>;
} }

View File

@ -35,3 +35,11 @@
width: 10em; /* 5x7 aspect ratio */ width: 10em; /* 5x7 aspect ratio */
height: 14em; height: 14em;
} }
.Winner .PlayerColor {
display: inline-flex;
width: 0.8em;
height: 0.8em;
padding: 0;
margin: 0;
}

View File

@ -4,6 +4,7 @@ import Paper from '@material-ui/core/Paper';
import Button from '@material-ui/core/Button'; import Button from '@material-ui/core/Button';
import Resource from './Resource.js'; import Resource from './Resource.js';
import { getPlayerName } from './Common.js'; import { getPlayerName } from './Common.js';
import PlayerColor from './PlayerColor.js';
const Winner = ({table, color}) => { const Winner = ({table, color}) => {
const quitClicked = (event) => { const quitClicked = (event) => {
@ -24,8 +25,8 @@ const Winner = ({table, color}) => {
} }
let description = <>Congratulations, <b>{name}</b>! let description = <>Congratulations, <b>{name}</b>!
They have won the game! The game played <p><PlayerColor color={color}/> {name} won the game after {Math.floor(table.game.turns / playerCount)} turns. They
for {Math.floor(table.game.turns / playerCount)} turns. had <b>{player.potential}</b> unplayed Victory Point card(s).</p>
</>; </>;
for (let key in table.game.players) { for (let key in table.game.players) {
if (key === color) { if (key === color) {
@ -35,7 +36,8 @@ const Winner = ({table, color}) => {
if (tmp.status === 'Not active') { if (tmp.status === 'Not active') {
continue; continue;
} }
let line = <>{getPlayerName(table.game.sessions, key)} finished with {tmp.points} victory points.</> let line = <><PlayerColor color={key}/> {getPlayerName(table.game.sessions, key)} finished with {tmp.points} victory points.
They had <b>{player.potential}</b> unplayed Victory Point card(s).</>
description = <>{description}<p>{line}</p></>; description = <>{description}<p>{line}</p></>;
} }

View File

@ -7,8 +7,6 @@ const express = require("express"),
accessSync = fs.accessSync, accessSync = fs.accessSync,
randomWords = require("random-words"); randomWords = require("random-words");
const { clear } = require("console");
const { corners } = require("./layout.js");
const layout = require('./layout.js'); const layout = require('./layout.js');
const MAX_SETTLEMENTS = 5; const MAX_SETTLEMENTS = 5;
@ -552,6 +550,14 @@ const adminActions = (game, action, value) => {
let color, player, parts, session; let color, player, parts, session;
switch (action) { switch (action) {
case "debug":
if (parseInt(value) === 0 || value === 'false') {
delete game.debug;
} else {
game.debug = true;
}
break;
case "state": case "state":
switch (value) { switch (value) {
case 'game-order': case 'game-order':
@ -988,7 +994,7 @@ const calculateRoadLengths = (game, session) => {
/* Clear out player longest road counts */ /* Clear out player longest road counts */
for (let key in game.players) { for (let key in game.players) {
game.players[key].length = 0; game.players[key].longestRoad = 0;
} }
/* Build a set of connected road graphs. Once all graphs are /* Build a set of connected road graphs. Once all graphs are
@ -1070,7 +1076,7 @@ const calculateRoadLengths = (game, session) => {
if (game.players[key].longestRoad > longestRoad) { if (game.players[key].longestRoad > longestRoad) {
longestPlayers = [ key ]; longestPlayers = [ key ];
longestRoad = game.players[key].longestRoad; longestRoad = game.players[key].longestRoad;
} else if (game.players[key].longestRoad == longestRoad && checkForTies) { } else if (game.players[key].longestRoad === longestRoad) {
longestPlayers.push(key); longestPlayers.push(key);
} }
} }
@ -1314,6 +1320,46 @@ const checkOffer = (player, offer) => {
return error; return error;
}; };
const gameSignature = (game) => {
if (!game) {
return "";
}
const salt = 251;
const signature =
game.borderOrder.map(border => `00${(Number(border)^salt).toString(16)}`.slice(-2)).join('') + '-' +
game.pipOrder.map((pip, index) => `00${(Number(pip)^salt^(salt*index)).toString(16)}`.slice(-2)).join('') + '-' +
game.tileOrder.map((tile, index) => `00${(Number(tile)^salt^(salt*index)).toString(16)}`.slice(-2)).join('');
return signature;
};
const setGameFromSignature = (game, border, pip, tile) => {
const salt = 251;
const borders = [], pips = [], tiles = [];
for (let i = 0; i < 6; i++) {
borders[i] = parseInt(border.slice(i * 2, (i * 2) + 2), 16)^salt;
if (borders[i] > 6) {
return false;
}
}
for (let i = 0; i < 19; i++) {
pips[i] = parseInt(pip.slice(i * 2, (i * 2) + 2), 16)^salt^(salt*i) % 256;
if (pips[i] > 18) {
return false;
}
}
for (let i = 0; i < 19; i++) {
tiles[i] = parseInt(tile.slice(i * 2, (i * 2) + 2), 16)^salt^(salt*i) % 256;
if (tiles[i] > 18) {
return false;
}
}
game.borderOrder = borders;
game.pipOrder = pips;
game.tileOrder = tiles;
return true;
}
const offerToString = (offer) => { const offerToString = (offer) => {
return offer.gives.map(item => `${item.count} ${item.type}`).join(', ') + return offer.gives.map(item => `${item.count} ${item.type}`).join(', ') +
' in exchange for ' + ' in exchange for ' +
@ -1354,6 +1400,28 @@ router.put("/:id/:action/:value?", async (req, res) => {
case 'chat': case 'chat':
const chat = req.body; const chat = req.body;
addChatMessage(game, session, chat.message); addChatMessage(game, session, chat.message);
/* Chat messages can set game flags and fields */
const parts = chat.message.match(/^set +([^ ]*) +(.*)$/i);
if (parts && parts.length === 3) {
switch (parts[1].toLowerCase()) {
case 'game':
if (parts[2].trim().match(/^beginner('?s)?( +layout)?/i)) {
setBeginnerGame(game);
addChatMessage(game, session, `${session.name} set game board to the Beginner's Layout.`);
break;
}
const signature = parts[2].match(/^([0-9a-f]{12})-([0-9a-f]{38})-([0-9a-f]{38})/i);
if (signature) {
if (setGameFromSignature(game, signature[1], signature[2], signature[3])) {
game.signature = parts[2];
addChatMessage(game, session, `${session.name} set game board to ${parts[2]}.`);
} else {
addChatMessage(game, session, `${session.name} requested an invalid game board.`);
}
}
break;
}
}
return sendGame(req, res, game); return sendGame(req, res, game);
} }
@ -1540,7 +1608,7 @@ router.put("/:id/:action/:value?", async (req, res) => {
} }
if (!error) { if (!error) {
shuffleBoard(game); shuffleBoard(game);
const message = `${name} requested a new board.`; const message = `${name} requested a new board. New board signature: ${game.signature}.`;
addChatMessage(game, null, message); addChatMessage(game, null, message);
console.log(message); console.log(message);
} }
@ -2328,7 +2396,11 @@ const debugChat = (game, preamble) => {
playerInventory += `nothing, `; playerInventory += `nothing, `;
} }
} }
addChatMessage(game, null, playerInventory.replace(/, $/, '').trim()); if (game.debug) {
addChatMessage(game, null, playerInventory.replace(/, $/, '').trim());
} else {
console.log(playerInventory.replace(/, $/, '').trim());
}
} }
const getActiveCount = (game) => { const getActiveCount = (game) => {
@ -2413,9 +2485,13 @@ const sendGame = async (req, res, game, error) => {
player.points += 2 * (MAX_CITIES - player.cities); player.points += 2 * (MAX_CITIES - player.cities);
player.unplayed = 0; player.unplayed = 0;
player.potential = 0;
player.development.forEach(card => { player.development.forEach(card => {
if (card.type === 'vp' && card.played) { if (card.type === 'vp') {
player.points++; player.potential++;
if (card.played) {
player.points++;
}
} }
if (!card.played) { if (!card.played) {
player.unplayed++; player.unplayed++;
@ -2428,8 +2504,18 @@ const sendGame = async (req, res, game, error) => {
game.state = 'winner'; game.state = 'winner';
delete game.turn.roll; delete game.turn.roll;
} }
}
/* If the game isn't in a win state, do not share development card information
* with other players */
if (game.state !== 'winner') {
for (let key in game.players) {
const player = game.players[key];
if (player.status === 'Not active') {
continue;
}
delete player.potential;
}
} }
/* Shallow copy game, filling its sessions with a shallow copy of sessions so we can then /* Shallow copy game, filling its sessions with a shallow copy of sessions so we can then
@ -2482,7 +2568,6 @@ const sendGame = async (req, res, game, error) => {
sessions: reducedSessions, sessions: reducedSessions,
layout: layout layout: layout
}); });
return res.status(200).send(playerGame); return res.status(200).send(playerGame);
} }
@ -2518,8 +2603,21 @@ const resetGame = (game) => {
cities: MAX_CITIES, cities: MAX_CITIES,
settlements: MAX_SETTLEMENTS, settlements: MAX_SETTLEMENTS,
points: 0, points: 0,
development: [] development: [],
banks: [],
maritime: [],
army: 0,
playedCard: 0,
haveResources: false,
unplayed: 0,
longestRoad: 0,
mustDiscard: 0,
gives: [],
gets: []
}); });
game.players[key].order = 0;
delete game.players[key].orderRoll;
delete game.players[key].orderStatus;
} }
shuffle(game.developmentCards); shuffle(game.developmentCards);
@ -2538,19 +2636,13 @@ const resetGame = (game) => {
}; };
} }
for (let key in game.players) {
game.players[key].order = 0;
delete game.players[key].orderRoll;
delete game.players[key].orderStatus;
}
delete game.turn; delete game.turn;
} }
const createGame = (id) => { const createGame = (id) => {
/* Look for a new game with random words that does not already exist */ /* Look for a new game with random words that does not already exist */
while (!id) { while (!id) {
id = randomWords(4).join('_'); id = randomWords(4).join('-');
console.log(`Looking for ${id}`); console.log(`Looking for ${id}`);
try { try {
/* If file can be read, it already exists so look for a new name */ /* If file can be read, it already exists so look for a new name */
@ -2586,7 +2678,9 @@ const createGame = (id) => {
id: id id: id
}; };
addChatMessage(game, null, `New game started for ${id}`); console.log(`New game created with Beginner's Layout: ${game.id}`);
addChatMessage(game, null,
`New game created with Beginner's Layout: ${game.id}`);
[ "pips", "borders", "tiles" ].forEach((field) => { [ "pips", "borders", "tiles" ].forEach((field) => {
game[field] = assetData[field] game[field] = assetData[field]
@ -2595,8 +2689,7 @@ const createGame = (id) => {
resetGame(game); resetGame(game);
games[game.id] = game; games[game.id] = game;
shuffleBoard(game); setBeginnerGame(game);
console.log(`New game created: ${game.id}`);
return game; return game;
}; };
@ -2614,16 +2707,40 @@ router.post("/:id?", (req, res/*, next*/) => {
return sendGame(req, res, game); return sendGame(req, res, game);
}); });
const shuffleBoard = (game) => { const setBeginnerGame = (game) => {
game.gender = Math.random() > 0.5 ? 'male' : 'female';
shuffle(game.developmentCards);
game.borderOrder = [];
for (let i = 0; i < 6; i++) {
game.borderOrder.push(i);
}
game.tileOrder = [
9, 12, 1,
5, 16, 13, 17,
6, 2, 0, 3, 10,
4, 11, 7, 14,
18, 8, 15
];
game.pipOrder = [
5, 1, 6,
7, 2, 9, 11,
12, 8, 18, 3, 4,
10, 16, 13, 0,
14, 15, 17
];
game.signature = gameSignature(game);
}
const shuffleBoard = (game, beginnersGame) => {
game.gender = Math.random() > 0.5 ? 'male' : 'female';
const seq = []; const seq = [];
for (let i = 0; i < 6; i++) { for (let i = 0; i < 6; i++) {
seq.push(i); seq.push(i);
} }
shuffle(seq); shuffle(seq);
game.gender = Math.random() > 0.5 ? 'male' : 'female';
game.borderOrder = seq.slice(); game.borderOrder = seq.slice();
for (let i = 6; i < 19; i++) { for (let i = 6; i < 19; i++) {
seq.push(i); seq.push(i);
} }
@ -2665,6 +2782,8 @@ const shuffleBoard = (game) => {
} }
shuffle(game.developmentCards); shuffle(game.developmentCards);
game.signature = gameSignature(game);
} }
/* /*