Lots of tweaks and fixes
Signed-off-by: James Ketrenos <james_eikona@ketrenos.com>
This commit is contained in:
parent
1fcad2f21f
commit
e865133cc1
@ -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 <b>{name}</b>.</>;
|
message = <>{message}You are in the lobby as <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}/>.</>;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
@ -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></>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,10 +2603,23 @@ 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);
|
||||||
|
|
||||||
for (let i = 0; i < layout.corners.length; i++) {
|
for (let i = 0; i < layout.corners.length; i++) {
|
||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user